The online racing simulator
Status graph help (more!!)
Hey all. Been fiddling about with things again and i am getting places.

Started using an old script and decided to look into editing the source like i was told to do by -ED- (original writer of script)

Now i have managed to get it working (yay!!) but it does not display on the graph the users who are on the server, but spectating.. (eg if there are 15 users in the server, and 4 of them are spectating, then the graph will only display 11) But from what i can tell (very very very limited knowledge here!!) it should all be working correctly.

The source is below:

If anybody could possibly take a quick look and see if anything jumps out at you, it would be appreciated. It reads from the host[port].txt and then creates its own file where it stores all the updates to generate an accurate graph. i can PM the entire source if anybody needs it who is willing and able to help me.

Thanks again all.

// HostHist.cpp
//
// 24Hour LFS Host status generator
// Reads ".\\host63392.txt" file from LFS dedicated host
// Generates:
// ".\\hourly_history.log" file with last 1440 server status entries
// ".\\hourly_history2.log" temp file of above - deleted on exit
// should be run 1/minute in the LFS Host directory
//
// Version 2.0
//
// Requires GD.DLL
//
// VC++ port by Ed Gibson of .pl original by the notorious Ian.H

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>

#include "gd.h"
#include "gdfontt.h"
#include "gdfonts.h"

#define STR_LEN 999 // max string line length
#define MAX_CONN 48 // max number of host connections
#define MINUTES_LOG 1440 // minutes to log 1440 = 24Hours

int CreateHoursFile(const char *FileName);
void create_small_driver_history_graph(const char* Hostname, int MaxGuests, const char* Filename, const char* LogFileName, struct tm *pCurrTime, int AlphaBack);
void create_large_driver_history_graph(const char* Hostname, int MaxGuests, const char* Filename, const char* LogFileName, struct tm *pCurrTime, int AlphaBack);
void StripColours(char* Strng);

int main(int argc, char* argv[])
{
FILE *InFile;
FILE *OutFile;
char LineData[STR_LEN];
char strHost[STR_LEN];
char strTrack[STR_LEN];
char strCars[STR_LEN];
char strConn[MAX_CONN][STR_LEN];
int MaxGuests;
int Guests;
int conn, conns = 0;
int Inch;
time_t CurrentTime;
struct tm *pCurrTime;
char* pString;
int AlphaBack = 0;

// messy but easy to follow...?
const char DefaultHostFile[] = "host53051.txt";
const char HourLogFile[] = "hourly_history.log";
char HourLogPathFile[256] = "";
const char NewHourLogFile[] = "hourly_history2.log";
char NewHourLogPathFile[256] = "";
const char SmallGraphFile[] = "driver_history_small.png";
char SmallGraphPathFile[256] = "";
const char LargeGraphFile[] = "driver_history_53051.png";
char LargeGraphPathFile[256] = "";

char ProgPath[256] = "";
char HostPathFile[256] = ""; // for source path & file
char DestPath[256] = "";

time(&CurrentTime); // grab timestamp
pCurrTime = localtime(&CurrentTime);

_cputs("HostHist v2.0\n");

// check given arguments
// argc, char* argv[]

strcpy(ProgPath, argv[0]); // get prog path & name
_strlwr(ProgPath); // lower cse it

pString = strstr(ProgPath, "hosthist.exe"); // find the name
if (pString == NULL)
pString = strstr(ProgPath, "hosthist"); // find the alternative name
if (pString == NULL)
{
_cputs("Filename Error\n"); // name not found - error
return -1;
} else {
*pString = '\0'; // terminate at name - path remains
}

if (argv[1] != NULL)
{
// check for 'help?'
if (strstr(argv[1], "/?") || strstr(argv[1], "/help")) // help!
{
_cputs("Reads [source] & generates:\n");
_cputs(" hourly_history.log\n");
_cputs(" driver_history_large.png\n");
_cputs(" driver_history_small.png\n");
_cputs("Should be run once per minute\n");
_cputs("\n");
_cputs("WinHostHist [dest] [source] [alpha]\n");
_cputs("\n");
_cputs(" dest path of folder for graph images\n");
_cputs(" and hourly_history.log file\n");
_cputs(" source path & name of host txt file\n");
_cputs(" (e.g. host63392.txt\n");
_cputs(" alpha 1 = use transparent background\n");
_cputs(" else(default) white background\n");
_cputs("\n");
_cputs("If no path(s) given folder of exe is used\n");
return 0;
}

strcpy(DestPath, argv[1]); // get dest path
_strlwr(DestPath); // lower cse it
pString = DestPath + strlen(DestPath) - 1;
if (*pString != '\\') // if \ not present
strcat(DestPath, "\\"); // add it

if (argv[2] != NULL)
{
strcpy(HostPathFile, argv[2]); // get source path & file
_strlwr(HostPathFile); // lower case it

if (argv[3] != NULL) // get Alpha Background
{
AlphaBack = atoi(argv[3]);
} else {
AlphaBack = 0;
}

} else {
strcpy(HostPathFile, ProgPath); // set to current path
strcat(HostPathFile, DefaultHostFile); // & default file
}

} else {
strcpy(DestPath, ProgPath); // set to current path
strcpy(HostPathFile, ProgPath); // set to current path
strcat(HostPathFile, DefaultHostFile); // & default file
}

strcpy(SmallGraphPathFile, DestPath);
strcat(SmallGraphPathFile, SmallGraphFile);
strcpy(LargeGraphPathFile, DestPath);
strcat(LargeGraphPathFile, LargeGraphFile);
// strcpy(HostPathFile, SourcePath);
// strcat(HostPathFile, HostFile);
strcpy(HourLogPathFile, DestPath);
strcat(HourLogPathFile, HourLogFile);
strcpy(NewHourLogPathFile, DestPath);
strcat(NewHourLogPathFile, NewHourLogFile);

if ((InFile = fopen(HostPathFile, "rt")) == NULL) // open HostFile
{
_cputs("Error opening\n");
_cputs(HostPathFile);
_cputs("\n");
return -1;
}

while (fgets(LineData, STR_LEN, InFile)) // read next line from file ?or EOL?
{
LineData[strlen(LineData)-1] = '\0'; // remove \n
if (strstr(LineData, "host=")) // is it "host="
strncpy(strHost, strchr(LineData, '=')+1, STR_LEN); // store string
else if (strstr(LineData, "maxguests=")) // is it "maxguests="
MaxGuests = atoi(strchr(LineData, '=')+1); // convert value to var
else if (strstr(LineData, "guests=")) // is it "maxguests="
Guests = atoi(strchr(LineData, '=')+1); // convert value to var
else if (strstr(LineData, "trackcfg=")) // is it "trackcfg="
strncpy(strTrack, strchr(LineData, '=')+1, STR_LEN); // store string
else if (strstr(LineData, "cars=")) // is it "cars="
strncpy(strCars, strchr(LineData, '=')+1, STR_LEN); // store string
else if (strstr(LineData, "conn=")) // is it "conn="
strncpy(&(strConn[conns++][0]), strchr(LineData, '=')+1, STR_LEN); // store string
}
fclose(InFile);

// HourLogFile
if ((OutFile = fopen(HourLogPathFile, "r")) == NULL) // if hourly file doesn't exist...
{
if (CreateHoursFile(HourLogPathFile)) // ...create a new one
{
_cputs("Error creating new\n");
_cputs(HourLogPathFile);
_cputs("\n");
return -1;
}
}
else
fclose(OutFile);

if ((OutFile = fopen(HourLogPathFile, "a")) == NULL) // open the hourly file for append
{
_cputs("Error opening\n");
_cputs(HourLogPathFile);
_cputs("\n");
return -1;
}
// log the data:
fprintf(OutFile, "%lu", CurrentTime); // time
fputc('\t', OutFile);
fputs(strTrack, OutFile); // tracks
fputc('\t', OutFile);
fputs(strCars, OutFile); // cars
for (conn=1; conn<conns; conn++) // (miss 'Host' conn)
{
fputc('\t', OutFile);
fputs(&(strConn[conn][0]), OutFile); // conns
}
fputc('\n', OutFile);

fclose(OutFile);

if ((InFile = fopen(HourLogPathFile, "r")) == NULL) // find the end of the first line
{
_cputs("Error opening\n");
_cputs(HourLogPathFile);
_cputs("\n");
return -1;
}
while (!feof(InFile) && fgetc(InFile) != '\n');
if (feof(InFile))
{
_cputs("Error reading\n");
_cputs(HourLogPathFile);
_cputs("\n");
return -1;
}

if ((OutFile = fopen(NewHourLogPathFile, "w")) == NULL) // write the entire new temp file
{
_cputs("Error opening\n");
_cputs(NewHourLogPathFile);
_cputs("\n");
return -1;
}
while ((Inch = fgetc(InFile)) != EOF)
fputc(Inch, OutFile);
fclose(OutFile);
fclose(InFile);

remove(HourLogPathFile); // delete the old file
rename(NewHourLogPathFile, HourLogPathFile); // rename the temp file

StripColours(strHost);
create_small_driver_history_graph(strHost, MaxGuests, SmallGraphPathFile, HourLogPathFile, pCurrTime, AlphaBack);
create_large_driver_history_graph(strHost, MaxGuests, LargeGraphPathFile, HourLogPathFile, pCurrTime, AlphaBack);

return 0;
}


int CreateHoursFile(const char *FileName) // create a fresh HourLogFile
{
FILE* OutFile;
char Contents[MINUTES_LOG+1], *pContents = Contents;
int lp;

if ((OutFile = fopen(FileName, "w")) != NULL)
{ // open the file
for (lp=0; lp<MINUTES_LOG; lp++)
*pContents++ = '\n'; // create the data
*pContents = '\0';

fputs(Contents, OutFile); // write it to the file
fclose(OutFile); // & close the file
return 0;
} else {
_cputs("Error opening\n");
_cputs(FileName);
_cputs("\n");
return -1;
}
}



void create_small_driver_history_graph(const char* Hostname, int MaxGuests, const char* Filename, const char* LogFileName, struct tm *pCurrTime, int AlphaBack)
{
int width = 1440;
int height = 80;
int out_width = 170;
int out_height = 95;
int s, i;
char MinData[MINUTES_LOG];
int MinIndex = 0;
int Inch;
char Buf[10];

FILE *InFile;
FILE *OutFile;
int pngBufSize;
char *pngBufData;
gdImagePtr graph = gdImageCreate(width, height);
gdImagePtr out_graph = gdImageCreate(out_width, out_height);
gdFontPtr gdTinyFont = gdFontGetTiny();

// Colours
int background, black, light_blue, int_lines, int_lines_light;
int out_background, out_black;

// Allocate colours
background = gdImageColorAllocate(graph, 214, 224, 235);
black = gdImageColorAllocate(graph, 0, 0, 0);
light_blue = gdImageColorAllocate(graph, 134, 155, 191);
int_lines = gdImageColorAllocate(graph, 184, 194, 205);
int_lines_light = gdImageColorAllocate(graph, 204, 214, 225);

if (AlphaBack)
out_background = gdImageColorAllocateAlpha(out_graph, 255, 255, 255, 127);
else
out_background = gdImageColorAllocate(out_graph, 255, 255, 255);

out_black = gdImageColorAllocate(out_graph, 0, 0, 0);

// read log file
if ((InFile = fopen(LogFileName, "rt")) == NULL)
return;

MinIndex = 0;
for (i=0; i<MINUTES_LOG; i++)
{
MinData[MinIndex] = 0; // initialise
do
{
Inch = fgetc(InFile);
if (Inch == '\t')
MinData[MinIndex]++;
} while ((Inch != EOF) && (Inch != '\n'));
MinData[MinIndex] -= 2; // fiddle to remove \t for other data in log
MinIndex++;
}

fclose(InFile);

// generate image
gdImageFilledRectangle(out_graph, 0, 0, width, height, out_background);
sprintf(Buf, "%02d:%02d>", pCurrTime->tm_hour, pCurrTime->tm_min);
gdImageString(out_graph, gdTinyFont, 123, 82, (unsigned char*)Buf, out_black);
gdImageString(out_graph, gdTinyFont, 1, 82, (unsigned char*)Hostname, out_black);
gdImageFilledRectangle(graph, 0, 0, width, height, background);

s = 0;
for (i = MaxGuests; i > 0; i--)
{
if ((i % 2) == 0)
{
if (s) gdImageLine(graph, 0, s, width, s, int_lines);
} else {
if (s) gdImageLine(graph, 0, s, width, s, int_lines_light);
}
s += (height / MaxGuests);
}

for (i=0; i<MINUTES_LOG; i++)
{
if (MinData[i] > 0)
gdImageLine(graph, i, height - (MinData[i] * (height / MaxGuests)), i, height, light_blue);
}

s = 0;
for (i=MaxGuests; i>0; i--)
{
if ((i % 2) == 0)
{
sprintf(Buf, "%d", i);
gdImageString(out_graph, gdTinyFont, 157, s, (unsigned char*)Buf, out_black);
}
s += (height / MaxGuests);
}

gdImageCopyResized(out_graph, graph, 0, 0, 0, 0, 155, 80, width, height);
gdImageInterlace(out_graph, 1);

if ((OutFile = fopen(Filename, "wb")) == NULL)
return;

// gdImagePng(out_graph, OutFile);
pngBufData = (char *)gdImagePngPtr(out_graph, &pngBufSize); // use buffer as recommended
if (pngBufData != NULL)
{
fwrite(pngBufData, 1, pngBufSize, OutFile);
gdFree(pngBufData);
}
fclose(OutFile);

gdImageDestroy(out_graph);
gdImageDestroy(graph);
}

void create_large_driver_history_graph(const char* Hostname, int MaxGuests, const char* Filename, const char* LogFileName, struct tm *pCurrTime, int AlphaBack)
{
int width = 1440;
int height = 160;
int out_width = 360;
int out_height = 200;
int s, i;
char MinData[MINUTES_LOG];
int MinIndex = 0;
int Inch;
char Buf[10];

FILE *InFile;
FILE *OutFile;
int pngBufSize;
char *pngBufData;
gdImagePtr graph = gdImageCreate(width, height);
gdImagePtr out_graph = gdImageCreate(out_width, out_height);
gdFontPtr gdTinyFont = gdFontGetTiny();
gdFontPtr gdSmallFont = gdFontGetSmall();

// Colours
int background, black, light_blue, int_lines, int_lines_light;
int out_background, out_black;

// Allocate colours
background = gdImageColorAllocate(graph, 214, 224, 235);
black = gdImageColorAllocate(graph, 0, 0, 0);
light_blue = gdImageColorAllocate(graph, 134, 155, 191);
int_lines = gdImageColorAllocate(graph, 184, 194, 205);
int_lines_light = gdImageColorAllocate(graph, 204, 214, 225);

if (AlphaBack)
out_background = gdImageColorAllocateAlpha(out_graph, 255, 255, 255, 127);
else
out_background = gdImageColorAllocate(out_graph, 255, 255, 255);

out_black = gdImageColorAllocate(out_graph, 0, 0, 0);

// read log file
if ((InFile = fopen(LogFileName, "rt")) == NULL)
return;

MinIndex = 0;
for (i=0; i<MINUTES_LOG; i++)
{
MinData[MinIndex] = 0; // initialise
do
{
Inch = fgetc(InFile);
if (Inch == '\t')
MinData[MinIndex]++;
} while ((Inch != EOF) && (Inch != '\n'));
MinData[MinIndex] -= 2; // fiddle to remove \t for other data in log
MinIndex++;
}

fclose(InFile);

// generate image
gdImageFilledRectangle(out_graph, 0, 0, width, height, out_background);
gdImageString(out_graph, gdSmallFont, 1, 5, (unsigned char*)"Server activity over the past 24 hours", out_black);
sprintf(Buf, "%02d:%02d>", pCurrTime->tm_hour, pCurrTime->tm_min);
gdImageString(out_graph, gdSmallFont, 300, 182, (unsigned char*)Buf, out_black);
gdImageString(out_graph, gdSmallFont, 1, 182, (unsigned char*)Hostname, out_black);
gdImageFilledRectangle(graph, 0, 0, width, height, background);

s = 0;
for (i = MaxGuests; i > 0; i--)
{
if ((i % 2) == 0)
{
if (s) gdImageLine(graph, 0, s, width, s, int_lines);
} else {
if (s) gdImageLine(graph, 0, s, width, s, int_lines_light);
}
s += (height / MaxGuests);
}

for (i=0; i<MINUTES_LOG; i++)
{
if (MinData[i] > 0)
gdImageLine(graph, i, height - (MinData[i] * (height / MaxGuests)), i, height, light_blue);
}

s = 20;
for (i=MaxGuests; i>0; i--)
{
if ((i % 2) == 0)
{
sprintf(Buf, "%d", i);
gdImageString(out_graph, gdTinyFont, 342, s, (unsigned char*)Buf, out_black);
}
s += (height / MaxGuests);
}

gdImageCopyResized(out_graph, graph, 0, 20, 0, 0, 340, 160, width, height);
gdImageInterlace(out_graph, 1);

if ((OutFile = fopen(Filename, "wb")) == NULL)
return;

// gdImagePng(out_graph, OutFile);
pngBufData = (char *)gdImagePngPtr(out_graph, &pngBufSize); // use buffer as recommended
if (pngBufData != NULL)
{
fwrite(pngBufData, 1, pngBufSize, OutFile);
gdFree(pngBufData);
}
fclose(OutFile);

gdImageDestroy(out_graph);
gdImageDestroy(graph);
}


void StripColours(char* Strng)
{
char* pSource = Strng;
char* pDest = Strng;

while (*pSource)
{
if ((*pSource == '^') && (strchr("0123456789",*(pSource+1))))
pSource += 2; // skip colour assignment
else
*pDest++ = *pSource++; // else copy as is
}
*pDest = '\0'; // terminate
}

Quote from franky500 :
[...] it does not display on the graph the users who are on the server, but spectating.. (eg if there are 15 users in the server, and 4 of them are spectating, then the graph will only display 11)

Are you sure this is exactly its behaviour? I opened an host[port].txt and didn't find a way to tell if someone is spectating or not...so it would be surprising if this program would be able to do so by parsing that file
I'm not a C/C++ expert but the reading/parsing of host[port].txt seemed ok.. you might want to put in some debug lines to print intermediate results and see what's going wrong.
Checking .log files would be handy too, so that you can check which drivers are missing.
If the .log files are ok, then you can focus on checking the draw image part

FGED GREDG RDFGDR GSFDG