Dynamic screenshot display working in browser.

This commit is contained in:
Scott Duensing 2022-04-25 21:30:04 -05:00
parent 377e40f28f
commit f477ee15d0
23 changed files with 460 additions and 176 deletions

View file

@ -131,6 +131,7 @@ SOURCES = \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
$$SHARED/thirdparty/SHA256/sha256.c \
$$SHARED/memory.c \
../shared/game.c \
src/browser.c \
src/file.c \
src/gui/msgbox.c \

View file

@ -33,6 +33,8 @@
#include "db.h"
#include "network.h"
#include "util.h"
#include "game.h"
#include "file.h"
static WindowT *_winBrowser = NULL;
@ -50,17 +52,11 @@ static ListboxT *_lstDescription = NULL;
static ButtonT *_btnScreensTab = NULL;
static FrameT *_fraScreens = NULL;
static PictureT *_picThumb1 = NULL;
static PictureT *_picThumb2 = NULL;
static PictureT *_picThumb3 = NULL;
static PictureT *_picThumb4 = NULL;
static PictureT *_picThumb5 = NULL;
static PictureT *_picThumb6 = NULL;
static PictureT *_picThumb[6];
static ButtonT *_btnBoxTab = NULL;
static FrameT *_fraBox = NULL;
static PictureT *_picBox1 = NULL;
static PictureT *_picBox2 = NULL;
static PictureT *_picBox[2];
static ButtonT *_btnInfoTab = NULL;
static FrameT *_fraInfo = NULL;
@ -69,14 +65,22 @@ static ListboxT *_lstInfo = NULL;
static uint8_t _channel = 0;
static char *_lastSearchText = NULL;
static GameT _selectedGame = { 0 };
static void browserHide(void);
static void btnTabClick(WidgetT *widget);
static void fraBoxShow(void);
static void fraDescriptionShow(void);
static void fraInfoShow(void);
static void fraScreensShow(void);
static void fraScreensReady(char *file);
static void packetHandler(PacketDecodeDataT *packet);
static void tabsBusySet(uint8_t busy);
static void timSearchUpdate(WidgetT *widget);
static void updateSelectedGame(void);
static void browserHide(void) {
void browserHide(void) {
timerStop(_timSearchUpdate);
DEL(_lastSearchText);
netChannelRelease(_channel);
@ -106,7 +110,7 @@ void browserShow(void) {
T_TITLE, P("Search"),
T_TEXTBOX, O(_txtSearch),
T_TITLE, P("Game, Publisher, or Developer:"),
T_TITLE, P("Filter:"),
T_X, 5, T_Y, 3,
T_WIDTH, 490,
T_LENGTH, 255,
@ -155,35 +159,30 @@ void browserShow(void) {
T_TITLE, P("Screenshots"),
T_VISIBLE, T_FALSE,
T_PICTURE, O(_picThumb1), // Thumbs are 160x100
T_PICTURE, O(_picThumb[0]), // Thumbs are 160x100
T_X, 1, T_Y, 5,
T_CACHENAME, P("browser:no-screen.png"),
T_PICTURE, T_DONE,
T_PICTURE, O(_picThumb2),
T_PICTURE, O(_picThumb[1]),
T_X, 167, T_Y, 5,
T_CACHENAME, P("browser:no-screen.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picThumb3),
T_PICTURE, O(_picThumb[2]),
T_X, 333, T_Y, 5,
T_CACHENAME, P("browser:no-screen.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picThumb4),
T_PICTURE, O(_picThumb[3]),
T_X, 1, T_Y, 116,
T_CACHENAME, P("browser:no-screen.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picThumb5),
T_PICTURE, O(_picThumb[4]),
T_X, 167, T_Y, 116,
T_CACHENAME, P("browser:no-screen.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_PICTURE, O(_picThumb6),
T_PICTURE, O(_picThumb[5]),
T_X, 333, T_Y, 116,
T_CACHENAME, P("browser:no-screen.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_FRAME, T_DONE,
@ -201,14 +200,13 @@ void browserShow(void) {
T_TITLE, P("Packaging"),
T_VISIBLE, T_FALSE,
T_PICTURE, O(_picBox1), // Thumbs are 240x210
T_PICTURE, O(_picBox[0]), // Thumbs are 240x210
T_X, 1, T_Y, 5,
T_CACHENAME, P("browser:no-box.png"),
T_PICTURE, T_DONE,
T_PICTURE, O(_picBox2),
T_PICTURE, O(_picBox[1]),
T_X, 250, T_Y, 5,
T_CACHENAME, P("browser:no-box.png"),
T_VISIBLE, T_FALSE,
T_PICTURE, T_DONE,
T_FRAME, T_DONE,
@ -247,7 +245,7 @@ void browserShow(void) {
guiFocusSet(W(_txtSearch));
_channel = netChannelGet(packetHandler);
_lastSearchText = strdup("");
_lastSearchText = strdup("x");
/*
guiDebugAreaShow(W(_fraSearch));
@ -288,17 +286,101 @@ void browserShow(void) {
static void btnTabClick(WidgetT *widget) {
tabsBusySet(1);
// Hide everything.
widgetVisibleSet(W(_fraBox), 0);
widgetVisibleSet(W(_fraDescription), 0);
widgetVisibleSet(W(_fraInfo), 0);
widgetVisibleSet(W(_fraScreens), 0);
widgetVisibleSet(W(_fraSearch), 0);
if (widget == W(_btnBoxTab)) widgetVisibleSet(W(_fraBox), 1);
if (widget == W(_btnDescriptionTab)) widgetVisibleSet(W(_fraDescription), 1);
if (widget == W(_btnInfoTab)) widgetVisibleSet(W(_fraInfo), 1);
if (widget == W(_btnScreensTab)) widgetVisibleSet(W(_fraScreens), 1);
if (widget == W(_btnSearchTab)) widgetVisibleSet(W(_fraSearch), 1);
updateSelectedGame();
// Show selected frame.
if (widget == W(_btnBoxTab)) fraBoxShow();
if (widget == W(_btnDescriptionTab)) fraDescriptionShow();
if (widget == W(_btnInfoTab)) fraInfoShow();
if (widget == W(_btnScreensTab)) fraScreensShow();
if (widget == W(_btnSearchTab)) {
widgetVisibleSet(W(_fraSearch), 1);
tabsBusySet(0);
}
}
static void fraBoxShow(void) {
widgetVisibleSet(W(_fraBox), 1);
tabsBusySet(0);
}
static void fraDescriptionShow(void) {
widgetVisibleSet(W(_fraDescription), 1);
tabsBusySet(0);
}
static void fraInfoShow(void) {
widgetVisibleSet(W(_fraInfo), 1);
tabsBusySet(0);
}
static void fraScreensShow(void) {
char **fileList = NULL;
char *temp;
uint8_t i;
// Build list of screen filenames needed.
for (i=0; i<_selectedGame.screens; i++) {
temp = utilCreateString("games:%c:%s:screen%d.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
utilStringToLower(temp);
arrput(fileList, temp);
temp = utilCreateString("games:%c:%s:screen%d-thumb.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
utilStringToLower(temp);
arrput(fileList, temp);
}
if (fileList) {
fileCacheCheckArr(fraScreensReady, fileList);
} else {
fraScreensReady(NULL);
}
}
static void fraScreensReady(char *file) {
uint8_t i;
// Is this a file update notice? If so, exit.
if (file) return;
// Are there screenshots?
if (_selectedGame.screens == 0) {
// Nope.
pictureReplace(_picThumb[0], "browser:no-screen.png");
for (i=1; i<6; i++) {
widgetVisibleSet(W(_picThumb[i]), 0);
}
} else {
for (i=0; i<6; i++) {
if (i < _selectedGame.screens) {
snprintf(_scratch, SCRATCH_SIZE, "games:%c:%s:screen%d-thumb.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
utilStringToLower(_scratch);
logWrite("Loading screen: %s\n", _scratch);
pictureReplace(_picThumb[i], _scratch);
widgetVisibleSet(W(_picThumb[i]), 1);
} else {
widgetVisibleSet(W(_picThumb[i]), 0);
}
}
}
// Display us.
widgetVisibleSet(W(_fraScreens), 1);
tabsBusySet(0);
}
@ -307,16 +389,30 @@ static void packetHandler(PacketDecodeDataT *packet) {
}
static void tabsBusySet(uint8_t busy) {
uint8_t enabled = busy ? 0 : 1;
if (busy) {
guiMouseBusyPush();
} else {
guiMouseBusyPop();
}
widgetEnableSet(W(_btnSearchTab), enabled);
widgetEnableSet(W(_btnDescriptionTab), enabled);
widgetEnableSet(W(_btnScreensTab), enabled);
widgetEnableSet(W(_btnBoxTab), enabled);
widgetEnableSet(W(_btnInfoTab), enabled);
}
static void timSearchUpdate(WidgetT *widget) {
char ***records = NULL;
char **fields = NULL;
uint16_t count = 0;
char query[258]; // 255 search characters, two %'s, and the terminating null.
(void)widget;
// Are there more than two characters in the search field?
if (textboxValueGet(_txtSearch) && strlen(textboxValueGet(_txtSearch)) > 2) {
// Did the search contents change?
if (strcmp(_lastSearchText, textboxValueGet(_txtSearch))) {
// Remember what was in the search box.
@ -324,24 +420,84 @@ static void timSearchUpdate(WidgetT *widget) {
_lastSearchText = strdup(textboxValueGet(_txtSearch));
// Clear current search results.
listboxItemsClear(_lstResults);
// Execute search.
snprintf(query, 258, "%%%s%%", _lastSearchText);
// Is there something in the search field?
if (textboxValueGet(_txtSearch) && strlen(textboxValueGet(_txtSearch)) > 0) {
// Yes. Filter based on what is in the search field.
snprintf(_scratch, SCRATCH_SIZE, "%%%s%%", _lastSearchText);
dbQueryMultiple(&records,
"SELECT title FROM games WHERE "
"title LIKE ? OR developer LIKE ? OR publisher LIKE ? "
"SELECT ROWID, title FROM games WHERE "
"title LIKE ? "
"ORDER BY title",
"vvv",
query,
query,
query);
"v",
_scratch);
} else {
// No. Display ALL games.
dbQueryMultiple(&records,
"SELECT ROWID, title FROM games "
"ORDER BY title",
NULL);
}
// Did we get anything?
if (records) {
for (count = 0; count < arrlen(records); count++) {
fields = records[count];
listboxItemAdd(_lstResults, fields[0]);
listboxItemAddWithData(_lstResults, fields[1], atol(fields[0]));
}
dbResultRelease(&records);
}
// Ghost or enable tab buttons depending on if the listbox has an item highlighted or not.
count = listboxItemsCountGet(_lstResults) > 0; // Reusing count.
widgetEnableSet(W(_btnDescriptionTab), count);
widgetEnableSet(W(_btnScreensTab), count);
widgetEnableSet(W(_btnBoxTab), count);
widgetEnableSet(W(_btnInfoTab), count);
}
}
static void updateSelectedGame(void) {
char ***records = NULL;
char **fields = NULL;
// If a game is selected...
if (listboxItemsCountGet(_lstResults) > 0) {
// Is it a different game?
if (listboxDataGet(_lstResults) != _selectedGame.ROWID) {
// Clear last loadead game.
gameClear(&_selectedGame);
logWrite("Loading game details: %d = '%s'\n", listboxDataGet(_lstResults), listboxValueGet(_lstResults));
// Load the details from the SQL database.
dbQueryMultiple(&records,
"SELECT title, publisher, developer, description, "
"releaseDate, rating, series, origin, shortName, "
"worksWith, type, maxPlayers, joinable, screens, "
"boxes, ROWID "
"FROM games WHERE "
"ROWID=?",
"i",
listboxDataGet(_lstResults));
if (records) {
fields = records[0];
_selectedGame.title = strdup(fields[0]);
_selectedGame.publisher = strdup(fields[1]);
_selectedGame.developer = strdup(fields[2]);
_selectedGame.description = strdup(fields[3]);
_selectedGame.releaseDate = strdup(fields[4]);
_selectedGame.rating = strdup(fields[5]);
_selectedGame.series = strdup(fields[6]);
_selectedGame.origin = strdup(fields[7]);
_selectedGame.shortName = strdup(fields[8]);
_selectedGame.worksWith = strdup(fields[9]);
_selectedGame.type = atoi(fields[10]);
_selectedGame.maxPlayers = atoi(fields[11]);
_selectedGame.joinable = atoi(fields[12]);
_selectedGame.screens = atoi(fields[13]);
_selectedGame.boxes = atoi(fields[14]);
_selectedGame.ROWID = atol(fields[15]);
dbResultRelease(&records);
}
}
}
}

View file

@ -25,6 +25,7 @@
#include "os.h"
void browserHide(void);
void browserShow(void);

View file

@ -70,20 +70,46 @@ static void btnMsgBoxOkay(MsgBoxButtonT button) {
}
// List of character array.
void fileCacheCheck(fileCallback callback, char *vpaths[]) {
FileListT *newList = NULL;
uint16_t i = 0;
char **files = NULL;
// Used during development & debugging.
if (!netPacketHandlerIsRunning()) {
callback(NULL);
return;
}
BEGIN
while (vpaths[i] != NULL) {
arrput(files, strdup(vpaths[i]));
i++;
}
fileCacheCheckArr(callback, files);
END
}
// List of dynamic array.
void fileCacheCheckArr(fileCallback callback, char **vpathArr) {
FileListT *newList = NULL;
// Used during development & debugging.
if (!netPacketHandlerIsRunning()) {
callback(NULL);
return;
}
BEGIN
// Add new entries to anything already in the queue.
NEW(FileListT, newList);
newList->callback = callback;
newList->files = NULL;
while (vpaths[i] != NULL) {
arrput(newList->files, strdup(vpaths[i]));
i++;
}
newList->files = vpathArr;
arrput(_fileList, newList);
// New queue?

View file

@ -29,6 +29,7 @@ typedef void (*fileCallback)(char *updatedFile);
void fileCacheCheck(fileCallback callback, char *vpaths[]);
void fileCacheCheckArr(fileCallback callback, char **vpathArr);
#endif // FILE_H

View file

@ -218,6 +218,7 @@ void guiDelayedFree(void **pointer) {
// Delayed Free allows freeing of data that may be in use by the
// GUI system at a safe time. (After compositing.)
arrput(_guiPendingFrees, *pointer);
*pointer = NULL;
}
@ -230,6 +231,7 @@ void guiDelete(WidgetT **widget) {
// that is also handled in the paint event.
arrput(_guiDeleteList, widget);
*widget = NULL;
}

View file

@ -42,6 +42,11 @@ static void listboxScrollUp(ListboxT *listbox);
static void listboxSizesRecalculate(ListboxT *listbox);
uint32_t listboxDataGet(ListboxT *listbox) {
return listbox->values[listbox->selected]->data;
}
static void listboxDel(WidgetT **widget) {
ListboxT *l = (ListboxT *)*widget;
@ -83,7 +88,19 @@ WidgetT *listboxInit(WidgetT *widget, char *title) {
void listboxItemAdd(ListboxT *listbox, char *item) {
arrput(listbox->values, strdup(item));
listboxItemAddWithData(listbox, item, 0);
}
void listboxItemAddWithData(ListboxT *listbox, char *item, uint32_t data) {
ListboxItemT *i;
NEW(ListboxItemT, i);
i->text = strdup(item);
i->data = data;
arrput(listbox->values, i);
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
}
@ -94,7 +111,8 @@ void listboxItemRemove(ListboxT *listbox, char *item) {
if (len > 0) {
for (x=0; x<len; x++) {
if (strcmp(item, listbox->values[x]) == 0) {
if (strcmp(item, listbox->values[x]->text) == 0) {
DEL(listbox->values[x]->text);
DEL(listbox->values[x]);
arrdel(listbox->values, x);
if (listbox->selected > len || listbox->selected > 0) listbox->selected--;
@ -108,12 +126,20 @@ void listboxItemRemove(ListboxT *listbox, char *item) {
void listboxItemsClear(ListboxT *listbox) {
while (arrlen(listbox->values) > 0) {
DEL(listbox->values[0]->text);
DEL(listbox->values[0]);
arrdel(listbox->values, 0);
}
arrfree(listbox->values);
listbox->selected = 0;
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
}
uint16_t listboxItemsCountGet(ListboxT *listbox) {
return arrlen(listbox->values);
}
@ -278,9 +304,9 @@ static void listboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
for (i=0; i<items; i++) {
if (i == l->selected) {
surfaceRectangleFilledDraw(pos.x + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o, pos.x + _valueWidth - __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o + fontHeightGet(__guiFont) - 1, __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND]);
fontRender(__guiFont, l->values[l->offset + i], __guiColor[COLOR_LISTBOX_SELECTED_TEXT], __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
fontRender(__guiFont, l->values[l->offset + i]->text, __guiColor[COLOR_LISTBOX_SELECTED_TEXT], __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
} else {
fontRender(__guiFont, l->values[l->offset + i], __guiColor[COLOR_LISTBOX_TEXT], __guiColor[COLOR_LISTBOX_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
fontRender(__guiFont, l->values[l->offset + i]->text, __guiColor[COLOR_LISTBOX_TEXT], __guiColor[COLOR_LISTBOX_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
}
o += fontHeightGet(__guiFont);
}
@ -389,7 +415,7 @@ void listboxTitleSet(ListboxT *listbox, char *title) {
char *listboxValueGet(ListboxT *listbox) {
return listbox->values[listbox->selected];
return listbox->values[listbox->selected]->text;
}
@ -399,7 +425,7 @@ void listboxValueSet(ListboxT *listbox, char *value) {
if (len > 0) {
for (x=0; x<len; x++) {
if (strcmp(value, listbox->values[x]) == 0) {
if (strcmp(value, listbox->values[x]->text) == 0) {
listbox->selected = x;
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
break;

View file

@ -26,22 +26,30 @@
#include "widget.h"
typedef struct ListboxItemS {
char *text;
uint32_t data;
} ListboxItemT;
typedef struct ListboxS {
WidgetT base; // Must be first in every widget
char *title;
char **values;
ListboxItemT **values;
uint16_t selected; // values[offset + selected]
int32_t step;
int32_t offset;
} ListboxT;
uint32_t listboxDataGet(ListboxT *listbox);
uint16_t listboxIndexGet(ListboxT *listbox);
void listboxIndexSet(ListboxT *listbox, uint16_t index);
WidgetT *listboxInit(WidgetT *widget, char *title);
void listboxItemAdd(ListboxT *listbox, char *item);
void listboxItemAddWithData(ListboxT *listbox, char *item, uint32_t data);
void listboxItemRemove(ListboxT *listbox, char *item);
void listboxItemsClear(ListboxT *listbox);
uint16_t listboxItemsCountGet(ListboxT *listbox);
ListboxT *listboxNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
void listboxStepSet(ListboxT *listbox, int32_t step);
void listboxTitleSet(ListboxT *listbox, char *title);

View file

@ -117,6 +117,21 @@ static void picturePaint(WidgetT *widget, uint8_t enabled, RectT pos) {
}
void pictureReplace(PictureT *picture, char *filename) {
ImageT *newImage = NULL;
newImage = imageLoadCache(filename);
if (newImage) {
DEL(picture->filename);
picture->filename = strdup(filename);
imageUnload(&picture->image);
picture->image = newImage;
GUI_SET_FLAG(W(picture), WIDGET_FLAG_DIRTY);
}
}
void pictureZoomSet(PictureT *picture, PictureZoomT zoom) {
picture->zoom = zoom;
GUI_SET_FLAG(W(picture), WIDGET_FLAG_DIRTY);

View file

@ -45,6 +45,7 @@ typedef struct PictureS {
void pictureClickHandlerSet(PictureT *picture, widgetCallback callback);
WidgetT *pictureInit(WidgetT *widget, char *filename);
PictureT *pictureNew(uint16_t x, uint16_t y, char *filename);
void pictureReplace(PictureT *picture, char *filename);
void pictureZoomSet(PictureT *picture, PictureZoomT zoom);

View file

@ -145,6 +145,16 @@ static void menuFilesReady(char *updatedFile) {
}
void menuHide(void) {
guiDelete(D(_picChat));
guiDelete(D(_picEmail));
guiDelete(D(_picForums));
guiDelete(D(_picGames));
guiDelete(D(_picLogoff));
guiDelete(D(_picProfile));
}
void menuShow(void) {
char *fileList[] = {
"menu:48chat.png",
@ -154,6 +164,9 @@ void menuShow(void) {
"menu:48logoff.png",
"menu:48profile.png",
"generated:games.dat",
"browser:no-box.png",
"browser:no-screen.png",
// "browser:no-banner.png",
// LOAD THE WORLD! This is for debugging the browser.
"games:d:descent:banner.png",
@ -295,8 +308,6 @@ void menuShow(void) {
"games:s:sre:screen1.png",
"games:s:sre:screen1-thumb.png",
"games:s:sre:banner.png",
"browser:no-box.png",
"browser:no-screen.png",
NULL
};
@ -357,44 +368,6 @@ static void picProfileClick(WidgetT *widget) {
}
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result) {
unsigned char c;
// Get next byte.
c = fgetc(f);
// End of file?
if (feof(f)) return FAIL;
// Add to result.
*result = c;
return SUCCESS;
}
uint8_t utilFromFileReadString(FILE *f, char **result) {
unsigned char c;
char buffer[GAME_MAX_DESCRIPTION];
uint16_t x = 0;
// Something already in 'result'?
DEL(*result);
while (1) {
// Get next byte.
c = fgetc(f);
// End of file?
if (feof(f)) return FAIL;
// Add to result.
buffer[x++] = c;
buffer[x] = 0;
// End of string?
if (c == 0) {
*result = strdup(buffer);
return SUCCESS;
}
}
}
/* static */ void updateGameDatabase(void) {
FILE *f = NULL;
uint8_t result;
@ -491,16 +464,7 @@ uint8_t utilFromFileReadString(FILE *f, char **result) {
dbExecute("DELETE FROM games WHERE touched=0", NULL);
// Free 'game'.
DEL(game.title);
DEL(game.publisher);
DEL(game.developer);
DEL(game.description);
DEL(game.releaseDate);
DEL(game.rating);
DEL(game.series);
DEL(game.origin);
DEL(game.shortName);
DEL(game.worksWith);
gameClear(&game);
//***TODO*** Did we have problems updating the game database?
if (result == FAIL) {

View file

@ -25,6 +25,7 @@
#include "os.h"
void menuHide(void);
void menuShow(void);

View file

@ -55,51 +55,38 @@ void runtimeDataLoad(void) {
void runtimeDataUpdate(void) {
FILE *f;
uint8_t c;
char name[33];
char data[1025];
uint8_t which = 0; // 0 = Reading name, 1 = Reading data.
uint16_t x = 0;
char *name = NULL;
char *data = NULL;
uint8_t result = FAIL;
f = cacheFOpen("generated:client.dat", "rb");
if (f) {
while (1) {
// Get next byte.
c = fgetc(f);
// End of file?
if (feof(f)) break;
// End of string?
if (c == 0) {
if (which == 0) {
// Got the name, move on to data.
which++;
name[x] = 0;
x = 0;
} else {
// Got data. Write both to database and start over.
which = 0;
data[x] = 0;
x = 0;
// If this first read fails, we're out of data. Any other read fails, we have problems.
if (!utilFromFileReadString(f, &name)) {
result = SUCCESS;
break;
}
if (!utilFromFileReadString(f, &data)) break;
// Write this to the database.
dbExecute(
"REPLACE INTO data (name, data) VALUES (?, ?)",
"vv",
name, data
);
}
continue;
}
// Got byte.
if (which == 0) {
name[x++] = c;
} else {
data[x++] = c;
}
DEL(name);
DEL(data);
}
cacheFClose(f);
}
//***TODO*** Did we have problems updating the runtime data?
if (result == FAIL) {
// Do something here.
} else {
runtimeDataLoad();
}
}
void runtimeShutdown(void) {

View file

@ -206,7 +206,6 @@ static void settingsComShow(void) {
static void timSettingsProgress(WidgetT *widget) {
char buffer[1024];
int32_t rc;
uint32_t len;
@ -224,8 +223,8 @@ static void timSettingsProgress(WidgetT *widget) {
case S_OPEN_COM:
rc = comOpen(com, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
if (rc == SER_SUCCESS) {
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
comWrite(com, buffer, strlen(buffer));
snprintf(_scratch, SCRATCH_SIZE, "%s%c", "AT+SOCK1", 13);
comWrite(com, _scratch, strlen(_scratch));
timerQuarterSecondsSet((TimerT *)widget, 4);
_state = S_WAIT_FOR_INIT;
} else {
@ -243,16 +242,16 @@ static void timSettingsProgress(WidgetT *widget) {
break;
case S_WAIT_FOR_INIT:
len = comRead(com, buffer, 1023);
buffer[len] = 0;
if (strstr(buffer, "OK")) {
len = comRead(com, _scratch, SCRATCH_SIZE);
_scratch[len] = 0;
if (strstr(_scratch, "OK")) {
snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Modem Found!", com + 1);
_port[com].status = PORT_GOOD_MODEM;
_port[com].selected = selected;
_port[com].enabled = 1;
selected = 0;
} else {
if (strstr(buffer, "ERROR")) {
if (strstr(_scratch, "ERROR")) {
snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Incompatable Modem", com + 1);
_port[com].status = PORT_BAD_MODEM;
_port[com].selected = 0;

View file

@ -82,6 +82,11 @@ void netChannelSystemRelease(netPacketHandler handler) {
}
uint8_t netPacketHandlerIsRunning(void) {
return _netRunning;
}
void netPacketHandlerStart(void) {
_netRunning = 1;
}

View file

@ -32,6 +32,7 @@ uint8_t netChannelGet(netPacketHandler handler);
void netChannelRelease(uint8_t channel);
void netChannelSystemGet(netPacketHandler handler);
void netChannelSystemRelease(netPacketHandler handler);
uint8_t netPacketHandlerIsRunning(void);
void netPacketHandlerStart(void);
void netPacketHandlerStop(void);
void netProcess(void);

View file

@ -21,6 +21,9 @@
#include "os.h"
char _scratch[SCRATCH_SIZE];
uint8_t osFileExists(char *filename) {
FILE *f = fopen(filename, "rb");
if (f) {

View file

@ -43,6 +43,7 @@
#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
#define OS_PATH_MAX 256
#define SCRATCH_SIZE 4096
#ifdef __linux__
@ -79,11 +80,14 @@ void linuxOsStartup(void);
#include "packet.h"
#include "cache.h"
#ifndef PacketThreadDataT
typedef struct PacketThreadDataS PacketThreadDataT;
#endif
extern PacketThreadDataT *__packetThreadData; // Declared in main.c
extern char _scratch[SCRATCH_SIZE]; // Declared in os.c
uint8_t osFileExists(char *filename);

View file

@ -249,7 +249,6 @@ static void timWelcomeProgress(WidgetT *widget) {
TimerT *t = (TimerT *)widget;
int32_t r = 0;
uint32_t len = 0;
static char buffer[1024] = { 0 };
static uint16_t offset = 0;
BEGIN
@ -279,25 +278,25 @@ static void timWelcomeProgress(WidgetT *widget) {
break;
}
// Send a CR to clear anything in the modem.
snprintf(buffer, 1023, "%c", 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
snprintf(_scratch, SCRATCH_SIZE, "%c", 13);
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
timerQuarterSecondsSet(t, 4);
_state = S_INIT_MODEM;
break;
case S_INIT_MODEM:
// Just read anything to clear the buffer.
comRead(__configData.serialCom - 1, buffer, 1023);
comRead(__configData.serialCom - 1, _scratch, SCRATCH_SIZE);
// Send actual init
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
snprintf(_scratch, SCRATCH_SIZE, "%s%c", "AT+SOCK1", 13);
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
_state = S_INIT_RESULT;
break;
case S_INIT_RESULT:
len = comRead(__configData.serialCom - 1, buffer, 1023);
buffer[len] = 0;
if (strstr(buffer, "OK") == NULL) {
len = comRead(__configData.serialCom - 1, _scratch, SCRATCH_SIZE);
_scratch[len] = 0;
if (strstr(_scratch, "OK") == NULL) {
comClose(__configData.serialCom - 1);
timerStop(t);
// Restore mouse.
@ -312,8 +311,8 @@ static void timWelcomeProgress(WidgetT *widget) {
break;
case S_DIAL:
snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
snprintf(_scratch, SCRATCH_SIZE, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
timerQuarterSecondsSet(t, 0); // Run as fast as we can so we don't miss any data.
offset = 0;
_timeoutCounter = 7 * 4; // Seven seconds.
@ -322,11 +321,11 @@ static void timWelcomeProgress(WidgetT *widget) {
case S_WAIT_FOR_BANNER:
// Process incoming bytes one at a time so we don't accidentally eat the first packet after the banner.
len = comRead(__configData.serialCom - 1, &buffer[offset], 1);
len = comRead(__configData.serialCom - 1, &_scratch[offset], 1);
offset += len;
buffer[offset] = 0;
_scratch[offset] = 0;
// ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
if (strstr(buffer, "KPMPGSMKII\rOKAY\r") != NULL) {
if (strstr(_scratch, "KPMPGSMKII\rOKAY\r") != NULL) {
// Connect! Start packet handler and negotiate encryption.
netPacketHandlerStart();
packetEncryptionSetup(__packetThreadData);

41
shared/game.c Normal file
View file

@ -0,0 +1,41 @@
/*
* Kangaroo Punch MultiPlayer Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "game.h"
void gameClear(GameT *game) {
DEL(game->title);
DEL(game->publisher);
DEL(game->developer);
DEL(game->description);
DEL(game->releaseDate);
DEL(game->rating);
DEL(game->series);
DEL(game->origin);
DEL(game->shortName);
DEL(game->worksWith);
game->type = GAME_TYPE_UNKNOWN;
game->maxPlayers = 0;
game->joinable = 0;
game->screens = 0;
game->boxes = 0;
game->ROWID = 0;
}

View file

@ -53,7 +53,11 @@ typedef struct GameS { // Data type in DAT file sent to client.
uint8_t joinable; // 1
uint8_t screens; // 1
uint8_t boxes; // 1
uint64_t ROWID; // Provided by SQLite.
} GameT;
void gameClear(GameT *game);
#endif // GAME_H

View file

@ -119,6 +119,43 @@ uint8_t utilFileExists(char *filename) {
}
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result) {
unsigned char c;
// Get next byte.
c = fgetc(f);
// End of file?
if (feof(f)) return FAIL;
// Add to result.
*result = c;
return SUCCESS;
}
uint8_t utilFromFileReadString(FILE *f, char **result) {
unsigned char c;
uint16_t x = 0;
// Something already in 'result'?
DEL(*result);
while (1) {
// Get next byte.
c = fgetc(f);
// End of file?
if (feof(f)) return FAIL;
// Add to result.
_scratch[x++] = c;
_scratch[x] = 0;
// End of string?
if (c == 0) {
*result = strdup(_scratch);
return SUCCESS;
}
}
}
void utilStringToLower(char *string) {
uint16_t i;

View file

@ -31,6 +31,8 @@ char *utilCreateString(char *format, ...);
char *utilCreateStringVArgs(char *format, va_list args);
void utilDie(const char *why, ...);
uint8_t utilFileExists(char *filename);
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result);
uint8_t utilFromFileReadString(FILE *f, char **result);
void utilStringToLower(char *string);
char **utilWrapText(char *text, uint16_t width);