New configuration system working. Game database import started.
This commit is contained in:
parent
61ab16512f
commit
794bd96d3f
17 changed files with 461 additions and 256 deletions
|
@ -21,9 +21,8 @@
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
CONFIG -= qt
|
CONFIG -= qt
|
||||||
CONFIG += \
|
CONFIG += c99
|
||||||
ASAN \
|
CONFIG += ASAN
|
||||||
c99
|
|
||||||
|
|
||||||
DESTDIR = $$OUT_PWD/bin
|
DESTDIR = $$OUT_PWD/bin
|
||||||
SHARED = $$PWD/../shared
|
SHARED = $$PWD/../shared
|
||||||
|
@ -136,6 +135,7 @@ SOURCES = \
|
||||||
src/gui/msgbox.c \
|
src/gui/msgbox.c \
|
||||||
src/gui/timer.c \
|
src/gui/timer.c \
|
||||||
src/hangup.c \
|
src/hangup.c \
|
||||||
|
src/runtime.c \
|
||||||
src/system/cache.c \
|
src/system/cache.c \
|
||||||
src/system/comport.c \
|
src/system/comport.c \
|
||||||
src/system/db.c \
|
src/system/db.c \
|
||||||
|
|
|
@ -137,7 +137,8 @@ static void fileCheckNext(void) {
|
||||||
// End of list!
|
// End of list!
|
||||||
logWrite("End of file list.\n");
|
logWrite("End of file list.\n");
|
||||||
arrfree(_current->files);
|
arrfree(_current->files);
|
||||||
_current->callback();
|
// Call with NULL to signify end of transfers.
|
||||||
|
_current->callback(NULL);
|
||||||
DEL(_current);
|
DEL(_current);
|
||||||
// See if there's more.
|
// See if there's more.
|
||||||
doRecheck = 1;
|
doRecheck = 1;
|
||||||
|
@ -253,6 +254,8 @@ static void packetHandler(PacketDecodeDataT *packet) {
|
||||||
cacheEntryAdd(_currentSha256, cacheEntryNameGet(_file), _file);
|
cacheEntryAdd(_currentSha256, cacheEntryNameGet(_file), _file);
|
||||||
imageCacheIfNeeded(_file, _currentSha256); // If this was an image, decompress it now.
|
imageCacheIfNeeded(_file, _currentSha256); // If this was an image, decompress it now.
|
||||||
DEL(_currentSha256);
|
DEL(_currentSha256);
|
||||||
|
// Call with filename to signify this file was updated.
|
||||||
|
_current->callback(_file);
|
||||||
// Next file!
|
// Next file!
|
||||||
fileCheckNext();
|
fileCheckNext();
|
||||||
} else {
|
} else {
|
||||||
|
@ -299,7 +302,7 @@ static void timTimerTimeout(WidgetT *widget) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we're good so far, call the callback.
|
// If we're good so far, call the callback.
|
||||||
if (!missing) _fileList[0]->callback();
|
if (!missing) _fileList[0]->callback(NULL);
|
||||||
arrfree(_fileList[0]->files);
|
arrfree(_fileList[0]->files);
|
||||||
arrdel(_fileList, 0);
|
arrdel(_fileList, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
typedef void (*fileCallback)(void);
|
typedef void (*fileCallback)(char *updatedFile);
|
||||||
|
|
||||||
|
|
||||||
void fileCacheCheck(fileCallback callback, char *vpaths[]);
|
void fileCacheCheck(fileCallback callback, char *vpaths[]);
|
||||||
|
|
|
@ -626,7 +626,7 @@ uint8_t vbeStartup(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
|
||||||
|
|
||||||
_windowScale = 3;
|
_windowScale = 3;
|
||||||
|
|
||||||
_window = SDL_CreateWindow("GUI Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xRes, yRes, SDL_WINDOW_ALLOW_HIGHDPI);
|
_window = SDL_CreateWindow("KangaWorld Debug Client", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xRes, yRes, SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
_surface = SDL_GetWindowSurface(_window);
|
_surface = SDL_GetWindowSurface(_window);
|
||||||
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
|
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
_texture = SDL_CreateTexture(_renderer, _pixelFormat, SDL_TEXTUREACCESS_STREAMING, xRes, yRes);
|
_texture = SDL_CreateTexture(_renderer, _pixelFormat, SDL_TEXTUREACCESS_STREAMING, xRes, yRes);
|
||||||
|
|
|
@ -43,8 +43,6 @@ typedef enum LoginStateE {
|
||||||
} LoginStateT;
|
} LoginStateT;
|
||||||
|
|
||||||
|
|
||||||
static char *_shaClientDat = NULL;
|
|
||||||
|
|
||||||
static WindowT *_winLogin = NULL;
|
static WindowT *_winLogin = NULL;
|
||||||
static TextboxT *_txtUser = NULL;
|
static TextboxT *_txtUser = NULL;
|
||||||
static TextboxT *_txtPass = NULL;
|
static TextboxT *_txtPass = NULL;
|
||||||
|
@ -61,7 +59,7 @@ static void btnLoginClick(WidgetT *widget);
|
||||||
static void btnSignUpClick(WidgetT *widget);
|
static void btnSignUpClick(WidgetT *widget);
|
||||||
static void btnMsgBoxCancel(MsgBoxButtonT button);
|
static void btnMsgBoxCancel(MsgBoxButtonT button);
|
||||||
static void btnMsgBoxContinue(MsgBoxButtonT button);
|
static void btnMsgBoxContinue(MsgBoxButtonT button);
|
||||||
static void loginFilesReady(void);
|
static void loginFilesReady(char *updatedFile);
|
||||||
static void packetHandler(PacketDecodeDataT *packet);
|
static void packetHandler(PacketDecodeDataT *packet);
|
||||||
static void setButtons(uint8_t enabled);
|
static void setButtons(uint8_t enabled);
|
||||||
static void timLoginProgress(WidgetT *widget);
|
static void timLoginProgress(WidgetT *widget);
|
||||||
|
@ -114,74 +112,78 @@ static void btnMsgBoxContinue(MsgBoxButtonT button) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void loginFilesReady(void) {
|
static void loginFilesReady(char *updatedFile) {
|
||||||
char *p;
|
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
//***TODO*** Load into database if changed.
|
// Is this an updated file or the end of the transfer list?
|
||||||
p = cacheSha256Get("generated:client.dat");
|
if (updatedFile) {
|
||||||
|
// client.dat was updated - read it into DB.
|
||||||
|
runtimeDataUpdate();
|
||||||
|
} else {
|
||||||
|
// End of cache update. Display UI.
|
||||||
|
runtimeDataLoad();
|
||||||
|
|
||||||
// ***TODO*** We used to have a FORGOT PASSWORD link here, too.
|
// ***TODO*** We used to have a FORGOT PASSWORD link here, too.
|
||||||
|
|
||||||
TagItemT uiLogin[] = {
|
TagItemT uiLogin[] = {
|
||||||
T_START,
|
T_START,
|
||||||
T_WINDOW, O(_winLogin),
|
T_WINDOW, O(_winLogin),
|
||||||
T_TITLE, P("Login"),
|
|
||||||
T_WIDTH, 300, T_HEIGHT, 155,
|
|
||||||
|
|
||||||
T_TEXTBOX, O(_txtUser),
|
|
||||||
T_TITLE, P("User Name:"),
|
|
||||||
T_X, 42, T_Y, 10,
|
|
||||||
T_WIDTH, 200,
|
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxUser"),
|
|
||||||
T_TEXTBOX, T_DONE,
|
|
||||||
|
|
||||||
T_TEXTBOX, O(_txtPass),
|
|
||||||
T_TITLE, P(" Password:"),
|
|
||||||
T_X, 42, T_Y, 40,
|
|
||||||
T_WIDTH, 200,
|
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxPass"),
|
|
||||||
T_MASK, '*',
|
|
||||||
T_TEXTBOX, T_DONE,
|
|
||||||
|
|
||||||
T_BUTTON, O(_btnCancel),
|
|
||||||
T_TITLE, P("Cancel"),
|
|
||||||
T_X, 25, T_Y, 85,
|
|
||||||
T_CLICK, P(btnCancelClick),
|
|
||||||
T_BUTTON, T_DONE,
|
|
||||||
T_BUTTON, O(_btnSignUp),
|
|
||||||
T_TITLE, P("Sign Up"),
|
|
||||||
T_X, 110, T_Y, 85,
|
|
||||||
T_CLICK, P(btnSignUpClick),
|
|
||||||
T_BUTTON, T_DONE,
|
|
||||||
T_BUTTON, O(_btnLogin),
|
|
||||||
T_TITLE, P("Login"),
|
T_TITLE, P("Login"),
|
||||||
T_X, 199, T_Y, 85,
|
T_WIDTH, 300, T_HEIGHT, 155,
|
||||||
T_CLICK, P(btnLoginClick),
|
|
||||||
T_BUTTON, T_DONE,
|
|
||||||
T_TIMER, O(_timProgress),
|
|
||||||
T_EVENT, P(timLoginProgress),
|
|
||||||
T_VALUE, 0,
|
|
||||||
T_ENABLED, 0,
|
|
||||||
T_TIMER, T_DONE,
|
|
||||||
|
|
||||||
T_WINDOW, T_DONE,
|
T_TEXTBOX, O(_txtUser),
|
||||||
T_END
|
T_TITLE, P("User Name:"),
|
||||||
};
|
T_X, 42, T_Y, 10,
|
||||||
|
T_WIDTH, 200,
|
||||||
|
T_LENGTH, RUNTIME_INT("maxUser"),
|
||||||
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
tagListRun(uiLogin);
|
T_TEXTBOX, O(_txtPass),
|
||||||
_channel = netChannelGet(packetHandler);
|
T_TITLE, P(" Password:"),
|
||||||
|
T_X, 42, T_Y, 40,
|
||||||
|
T_WIDTH, 200,
|
||||||
|
T_LENGTH, RUNTIME_INT("maxPass"),
|
||||||
|
T_MASK, '*',
|
||||||
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
textboxValueSet(_txtUser, "test");
|
T_BUTTON, O(_btnCancel),
|
||||||
textboxValueSet(_txtPass, "test");
|
T_TITLE, P("Cancel"),
|
||||||
|
T_X, 25, T_Y, 85,
|
||||||
|
T_CLICK, P(btnCancelClick),
|
||||||
|
T_BUTTON, T_DONE,
|
||||||
|
T_BUTTON, O(_btnSignUp),
|
||||||
|
T_TITLE, P("Sign Up"),
|
||||||
|
T_X, 110, T_Y, 85,
|
||||||
|
T_CLICK, P(btnSignUpClick),
|
||||||
|
T_BUTTON, T_DONE,
|
||||||
|
T_BUTTON, O(_btnLogin),
|
||||||
|
T_TITLE, P("Login"),
|
||||||
|
T_X, 199, T_Y, 85,
|
||||||
|
T_CLICK, P(btnLoginClick),
|
||||||
|
T_BUTTON, T_DONE,
|
||||||
|
T_TIMER, O(_timProgress),
|
||||||
|
T_EVENT, P(timLoginProgress),
|
||||||
|
T_VALUE, 0,
|
||||||
|
T_ENABLED, 0,
|
||||||
|
T_TIMER, T_DONE,
|
||||||
|
|
||||||
|
T_WINDOW, T_DONE,
|
||||||
|
T_END
|
||||||
|
};
|
||||||
|
|
||||||
|
tagListRun(uiLogin);
|
||||||
|
_channel = netChannelGet(packetHandler);
|
||||||
|
|
||||||
|
textboxValueSet(_txtUser, "test");
|
||||||
|
textboxValueSet(_txtPass, "test");
|
||||||
|
}
|
||||||
|
|
||||||
END
|
END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loginShow() {
|
void loginShow() {
|
||||||
char *p;
|
|
||||||
char *fileList[] = {
|
char *fileList[] = {
|
||||||
"generated:client.dat",
|
"generated:client.dat",
|
||||||
NULL
|
NULL
|
||||||
|
@ -189,14 +191,6 @@ void loginShow() {
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
// Keep old SHA to know if we need to reload after updating.
|
|
||||||
p = cacheSha256Get("generated:client.dat");
|
|
||||||
if (p) {
|
|
||||||
_shaClientDat = strdup(p);
|
|
||||||
} else {
|
|
||||||
_shaClientDat = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileCacheCheck(loginFilesReady, fileList);
|
fileCacheCheck(loginFilesReady, fileList);
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
/*
|
/*
|
||||||
* To Do:
|
* To Do:
|
||||||
*
|
*
|
||||||
|
* - In-app video settings configuration with sensible auto-detected defaults
|
||||||
* - Replace any direct data manipulation from outside a class with methods to handle it
|
* - Replace any direct data manipulation from outside a class with methods to handle it
|
||||||
* - More widget states: Ghosted (underway)
|
* - More widget states: Ghosted (underway)
|
||||||
* - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well
|
* - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well
|
||||||
|
@ -31,6 +32,8 @@
|
||||||
* - No thumb in listbox scrollbar
|
* - No thumb in listbox scrollbar
|
||||||
* - Layout container widgets!
|
* - Layout container widgets!
|
||||||
* - Fix variable names. something = local; _something = file global; __something = project global
|
* - Fix variable names. something = local; _something = file global; __something = project global
|
||||||
|
* - Use https://qoiformat.org/ instead of PNG for faster decoding
|
||||||
|
* - Store unpacked images on surfaces instead of inside an ImageT for faster blitting and less RAM usage
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +58,7 @@
|
||||||
|
|
||||||
|
|
||||||
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
|
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
|
||||||
RuntimeDataT __runtimeData; // Exported in runtime.h
|
|
||||||
|
|
||||||
static MouseT *_mouse = NULL;
|
static MouseT *_mouse = NULL;
|
||||||
static ImageT *_pointer = NULL;
|
static ImageT *_pointer = NULL;
|
||||||
|
@ -71,8 +74,6 @@ static void eventLoop(void);
|
||||||
static uint8_t hasValidSettings(void);
|
static uint8_t hasValidSettings(void);
|
||||||
static void shutdown(void);
|
static void shutdown(void);
|
||||||
static uint8_t startup(int argc, char *argv[]);
|
static uint8_t startup(int argc, char *argv[]);
|
||||||
static void tableLoad(void);
|
|
||||||
static void tableSave(void);
|
|
||||||
|
|
||||||
|
|
||||||
static void checkSettings(void) {
|
static void checkSettings(void) {
|
||||||
|
@ -124,13 +125,12 @@ static void shutdown(void) {
|
||||||
|
|
||||||
imageUnload(&_pointer);
|
imageUnload(&_pointer);
|
||||||
|
|
||||||
tableSave();
|
|
||||||
|
|
||||||
netShutdown();
|
netShutdown();
|
||||||
guiShutdown();
|
guiShutdown();
|
||||||
mouseShutdown();
|
mouseShutdown();
|
||||||
surfaceShutdown();
|
surfaceShutdown();
|
||||||
vbeShutdown();
|
vbeShutdown();
|
||||||
|
runtimeShutdown();
|
||||||
cacheShutdown();
|
cacheShutdown();
|
||||||
dbShutdown();
|
dbShutdown();
|
||||||
configShutdown();
|
configShutdown();
|
||||||
|
@ -190,6 +190,7 @@ static uint8_t startup(int argc, char *argv[]) {
|
||||||
|
|
||||||
dbStartup();
|
dbStartup();
|
||||||
cacheStartup(argv[0]);
|
cacheStartup(argv[0]);
|
||||||
|
runtimeStartup();
|
||||||
surfaceStartup();
|
surfaceStartup();
|
||||||
mouseStartup();
|
mouseStartup();
|
||||||
guiStartup();
|
guiStartup();
|
||||||
|
@ -198,102 +199,10 @@ static uint8_t startup(int argc, char *argv[]) {
|
||||||
_pointer = imageLoadCache("gui:mouse.png");
|
_pointer = imageLoadCache("gui:mouse.png");
|
||||||
_alpha = imagePixelGet(_pointer, 5, 0);
|
_alpha = imagePixelGet(_pointer, 5, 0);
|
||||||
|
|
||||||
tableLoad();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void tableLoad(void) {
|
|
||||||
FILE *cache = NULL;
|
|
||||||
char *line = NULL;
|
|
||||||
char *p = NULL;
|
|
||||||
char *temp = NULL;
|
|
||||||
|
|
||||||
__runtimeData.integers = NULL;
|
|
||||||
__runtimeData.strings = NULL;
|
|
||||||
__runtimeData.protocolVersion = 0;
|
|
||||||
|
|
||||||
sh_new_strdup(__runtimeData.integers);
|
|
||||||
sh_new_strdup(__runtimeData.strings);
|
|
||||||
|
|
||||||
// ***TODO*** Default initial tables
|
|
||||||
|
|
||||||
line = (char *)malloc(4096);
|
|
||||||
if (line) {
|
|
||||||
// Load string cache.
|
|
||||||
cache = cacheFOpen("data:strings.dat", "rt");
|
|
||||||
if (cache) {
|
|
||||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
|
||||||
p = strstr(line, "=");
|
|
||||||
if (p) {
|
|
||||||
*p = 0;
|
|
||||||
p++;
|
|
||||||
// Do we have this string already?
|
|
||||||
temp = shget(__runtimeData.strings, line);
|
|
||||||
if (temp) {
|
|
||||||
DEL(temp);
|
|
||||||
shdel(__runtimeData.strings, line);
|
|
||||||
}
|
|
||||||
shput(__runtimeData.strings, line, strdup(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cacheFClose(cache);
|
|
||||||
}
|
|
||||||
// Load integer cache.
|
|
||||||
cache = cacheFOpen("data:integers.dat", "rt");
|
|
||||||
if (cache) {
|
|
||||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
|
||||||
p = strstr(line, "=");
|
|
||||||
if (p) {
|
|
||||||
*p = 0;
|
|
||||||
p++;
|
|
||||||
shput(__runtimeData.integers, line, atol(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cacheFClose(cache);
|
|
||||||
}
|
|
||||||
free(line);
|
|
||||||
line = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void tableSave(void) {
|
|
||||||
FILE *cache = NULL;
|
|
||||||
|
|
||||||
// Save & free integer table.
|
|
||||||
cache = cacheFOpen("data:integers.dat", "wt");
|
|
||||||
if (cache) {
|
|
||||||
if (__runtimeData.integers) {
|
|
||||||
while (shlen(__runtimeData.integers) > 0) {
|
|
||||||
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
|
|
||||||
fprintf(cache, "%s=%ld\n", __runtimeData.integers[0].key, (long)__runtimeData.integers[0].value);
|
|
||||||
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
|
|
||||||
}
|
|
||||||
shfree(__runtimeData.integers);
|
|
||||||
}
|
|
||||||
cacheFClose(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save & free string table.
|
|
||||||
cache = cacheFOpen("data:strings.dat", "wt");
|
|
||||||
if (cache) {
|
|
||||||
if (__runtimeData.strings) {
|
|
||||||
while (shlen(__runtimeData.strings) > 0) {
|
|
||||||
//logWrite("[%s]=[%s]\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
|
||||||
fprintf(cache, "%s=%s\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
|
||||||
DEL(__runtimeData.strings[0].value);
|
|
||||||
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
|
|
||||||
}
|
|
||||||
shfree(__runtimeData.strings);
|
|
||||||
}
|
|
||||||
cacheFClose(cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern void browserShow(void);
|
extern void browserShow(void);
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||||
* Copyright (C) 2020-2021 Scott Duensing
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
*
|
*
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "vesa.h"
|
#include "vesa.h"
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
#include "taglist.h"
|
#include "taglist.h"
|
||||||
#include "msgbox.h"
|
#include "msgbox.h"
|
||||||
|
@ -36,17 +37,16 @@
|
||||||
static void btnMsgBoxLogoff(MsgBoxButtonT button);
|
static void btnMsgBoxLogoff(MsgBoxButtonT button);
|
||||||
static void btnMsgBoxOkay(MsgBoxButtonT button);
|
static void btnMsgBoxOkay(MsgBoxButtonT button);
|
||||||
static void menuEnable(uint8_t enable);
|
static void menuEnable(uint8_t enable);
|
||||||
static void menuFilesReady(void);
|
static void menuFilesReady(char *updatedFile);
|
||||||
static void picChatClick(WidgetT *widget);
|
static void picChatClick(WidgetT *widget);
|
||||||
static void picEmailClick(WidgetT *widget);
|
static void picEmailClick(WidgetT *widget);
|
||||||
static void picForumsClick(WidgetT *widget);
|
static void picForumsClick(WidgetT *widget);
|
||||||
static void picGamesClick(WidgetT *widget);
|
static void picGamesClick(WidgetT *widget);
|
||||||
static void picLogoffClick(WidgetT *widget);
|
static void picLogoffClick(WidgetT *widget);
|
||||||
static void picProfileClick(WidgetT *widget);
|
static void picProfileClick(WidgetT *widget);
|
||||||
|
static void updateGameDatabase(void);
|
||||||
|
|
||||||
|
|
||||||
static char *_shaGamesDat = NULL;
|
|
||||||
|
|
||||||
static PictureT *_picChat = NULL;
|
static PictureT *_picChat = NULL;
|
||||||
static PictureT *_picEmail = NULL;
|
static PictureT *_picEmail = NULL;
|
||||||
static PictureT *_picForums = NULL;
|
static PictureT *_picForums = NULL;
|
||||||
|
@ -91,51 +91,59 @@ static void menuEnable(uint8_t enable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void menuFilesReady(void) {
|
static void menuFilesReady(char *updatedFile) {
|
||||||
uint16_t x = vbeDisplayWidthGet() - 49;
|
uint16_t x;
|
||||||
uint16_t y = vbeDisplayHeightGet() - 49;
|
uint16_t y;
|
||||||
char *p;
|
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
//***TODO*** Load into database if changed.
|
// Did a file get updated or are we done?
|
||||||
p = cacheSha256Get("generated:games.dat");
|
if (updatedFile) {
|
||||||
|
// Was this the game database?
|
||||||
|
if (strcmp(updatedFile, "generated:games.dat") == 0) {
|
||||||
|
// Load changes into database.
|
||||||
|
updateGameDatabase();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show UI
|
||||||
|
x = vbeDisplayWidthGet() - 49;
|
||||||
|
y = vbeDisplayHeightGet() - 49;
|
||||||
|
|
||||||
_picLogoff = pictureNew(x, y, "menu:48logoff.png");
|
_picLogoff = pictureNew(x, y, "menu:48logoff.png");
|
||||||
pictureClickHandlerSet(_picLogoff, picLogoffClick);
|
pictureClickHandlerSet(_picLogoff, picLogoffClick);
|
||||||
guiAttach(guiRootGet(), W(_picLogoff));
|
guiAttach(guiRootGet(), W(_picLogoff));
|
||||||
x -= 49;
|
x -= 49;
|
||||||
|
|
||||||
_picForums = pictureNew(x, y, "menu:48forums.png");
|
_picForums = pictureNew(x, y, "menu:48forums.png");
|
||||||
pictureClickHandlerSet(_picForums, picForumsClick);
|
pictureClickHandlerSet(_picForums, picForumsClick);
|
||||||
guiAttach(guiRootGet(), W(_picForums));
|
guiAttach(guiRootGet(), W(_picForums));
|
||||||
x -= 49;
|
x -= 49;
|
||||||
|
|
||||||
_picEmail = pictureNew(x, y, "menu:48email.png");
|
_picEmail = pictureNew(x, y, "menu:48email.png");
|
||||||
pictureClickHandlerSet(_picEmail, picEmailClick);
|
pictureClickHandlerSet(_picEmail, picEmailClick);
|
||||||
guiAttach(guiRootGet(), W(_picEmail));
|
guiAttach(guiRootGet(), W(_picEmail));
|
||||||
x -= 49;
|
x -= 49;
|
||||||
|
|
||||||
_picGames = pictureNew(x, y, "menu:48games.png");
|
_picGames = pictureNew(x, y, "menu:48games.png");
|
||||||
pictureClickHandlerSet(_picGames, picGamesClick);
|
pictureClickHandlerSet(_picGames, picGamesClick);
|
||||||
guiAttach(guiRootGet(), W(_picGames));
|
guiAttach(guiRootGet(), W(_picGames));
|
||||||
x -= 49;
|
x -= 49;
|
||||||
|
|
||||||
_picChat = pictureNew(x, y, "menu:48chat.png");
|
_picChat = pictureNew(x, y, "menu:48chat.png");
|
||||||
pictureClickHandlerSet(_picChat, picChatClick);
|
pictureClickHandlerSet(_picChat, picChatClick);
|
||||||
guiAttach(guiRootGet(), W(_picChat));
|
guiAttach(guiRootGet(), W(_picChat));
|
||||||
x -= 49;
|
x -= 49;
|
||||||
|
|
||||||
_picProfile = pictureNew(x, y, "menu:48profile.png");
|
_picProfile = pictureNew(x, y, "menu:48profile.png");
|
||||||
pictureClickHandlerSet(_picProfile, picProfileClick);
|
pictureClickHandlerSet(_picProfile, picProfileClick);
|
||||||
guiAttach(guiRootGet(), W(_picProfile));
|
guiAttach(guiRootGet(), W(_picProfile));
|
||||||
|
}
|
||||||
|
|
||||||
END
|
END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void menuShow(void) {
|
void menuShow(void) {
|
||||||
char *p;
|
|
||||||
char *fileList[] = {
|
char *fileList[] = {
|
||||||
"menu:48chat.png",
|
"menu:48chat.png",
|
||||||
"menu:48email.png",
|
"menu:48email.png",
|
||||||
|
@ -149,14 +157,6 @@ void menuShow(void) {
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
// Keep old SHA to know if we need to reload after updating.
|
|
||||||
p = cacheSha256Get("generated:games.dat");
|
|
||||||
if (p) {
|
|
||||||
_shaGamesDat = strdup(p);
|
|
||||||
} else {
|
|
||||||
_shaGamesDat = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileCacheCheck(menuFilesReady, fileList);
|
fileCacheCheck(menuFilesReady, fileList);
|
||||||
|
|
||||||
END
|
END
|
||||||
|
@ -208,3 +208,49 @@ static void picProfileClick(WidgetT *widget) {
|
||||||
menuEnable(0);
|
menuEnable(0);
|
||||||
msgBoxOne("Options", MSGBOX_ICON_MESSAGE, "Yeah, this doesn't do anything yet.", "Okay", btnMsgBoxOkay);
|
msgBoxOne("Options", MSGBOX_ICON_MESSAGE, "Yeah, this doesn't do anything yet.", "Okay", btnMsgBoxOkay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void updateGameDatabase(void) {
|
||||||
|
FILE *f = NULL;
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
// Do we need to create the game database?
|
||||||
|
dbExecute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS games ("
|
||||||
|
"title VARCHAR(255), "
|
||||||
|
"publisher VARCHAR(255), "
|
||||||
|
"developer VARCHAR(255), "
|
||||||
|
"description TEXT, "
|
||||||
|
"releaseDate VARCHAR(255), "
|
||||||
|
"rating VARCHAR(255), "
|
||||||
|
"series VARCHAR(255), "
|
||||||
|
"origin VARCHAR(255), "
|
||||||
|
"shortName VARCHAR(8) PRIMARY KEY, "
|
||||||
|
"worksWith VARCHAR(255), "
|
||||||
|
"type VARCHAR(8), "
|
||||||
|
"maxPlayers INTEGER, "
|
||||||
|
"joinable BOOLEAN, "
|
||||||
|
"screens INTEGER, "
|
||||||
|
"boxes INTEGER, "
|
||||||
|
"touched BOOLEAN "
|
||||||
|
")",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
// Mark everything untouched.
|
||||||
|
dbExecute("UPDATE games SET touced=0", NULL);
|
||||||
|
|
||||||
|
// Process latest downloaded game list.
|
||||||
|
f = cacheFOpen("generated:games.dat", "rb");
|
||||||
|
if (f) {
|
||||||
|
while (1) {
|
||||||
|
// Get next byte.
|
||||||
|
c = fgetc(f);
|
||||||
|
// End of file?
|
||||||
|
if (feof(f)) break;
|
||||||
|
|
||||||
|
}
|
||||||
|
cacheFClose(f);
|
||||||
|
// Delete anything untouched.
|
||||||
|
dbExecute("DELETE FROM games WHERE touced=0", NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
130
client/src/runtime.c
Normal file
130
client/src/runtime.c
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* 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 "db.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
|
||||||
|
RuntimeDataT __runtimeData;
|
||||||
|
|
||||||
|
|
||||||
|
void runtimeDataLoad(void) {
|
||||||
|
uint16_t count = 0;
|
||||||
|
char ***records = NULL;
|
||||||
|
char **fields = NULL;
|
||||||
|
|
||||||
|
dbQueryMultiple(&records, "SELECT name, data FROM data", NULL);
|
||||||
|
if (records) {
|
||||||
|
for (count = 0; count < arrlen(records); count++) {
|
||||||
|
fields = records[count];
|
||||||
|
if (fields) {
|
||||||
|
shput(__runtimeData.strings, fields[0], strdup(fields[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbResultRelease(&records);
|
||||||
|
|
||||||
|
/*
|
||||||
|
logWrite("\n\n");
|
||||||
|
for (int r = 0; r < shlen(__runtimeData.strings); r++) {
|
||||||
|
logWrite("%s = %s\n", __runtimeData.strings[r].key, __runtimeData.strings[r].value);
|
||||||
|
}
|
||||||
|
logWrite("\n\n");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
dbExecute(
|
||||||
|
"REPLACE INTO data (name, data) VALUES (?, ?)",
|
||||||
|
"vv",
|
||||||
|
name, data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Got byte.
|
||||||
|
if (which == 0) {
|
||||||
|
name[x++] = c;
|
||||||
|
} else {
|
||||||
|
data[x++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheFClose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
runtimeDataLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void runtimeShutdown(void) {
|
||||||
|
// Free string table.
|
||||||
|
while (shlen(__runtimeData.strings) > 0) {
|
||||||
|
DEL(__runtimeData.strings[0].value);
|
||||||
|
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
|
||||||
|
}
|
||||||
|
shfree(__runtimeData.strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void runtimeStartup(void) {
|
||||||
|
|
||||||
|
__runtimeData.strings = NULL;
|
||||||
|
__runtimeData.protocolVersion = 0;
|
||||||
|
|
||||||
|
sh_new_strdup(__runtimeData.strings);
|
||||||
|
|
||||||
|
// Do we need to create the client runtime config database?
|
||||||
|
dbExecute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS data ("
|
||||||
|
"name VARCHAR(32) PRIMARY KEY, "
|
||||||
|
"data VARCHAR(1024) "
|
||||||
|
")",
|
||||||
|
NULL);
|
||||||
|
}
|
|
@ -25,25 +25,28 @@
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define RUNTIME_INT(k) (atoi(shget(__runtimeData.strings, (k))))
|
||||||
|
#define RUNTIME_STR(k) (shget(__runtimeData.strings, (k)))
|
||||||
|
|
||||||
|
|
||||||
typedef struct StringMapS {
|
typedef struct StringMapS {
|
||||||
char *key;
|
char *key;
|
||||||
char *value;
|
char *value;
|
||||||
} StringMapT;
|
} StringMapT;
|
||||||
|
|
||||||
typedef struct IntegerMapS {
|
|
||||||
char *key;
|
|
||||||
int32_t value;
|
|
||||||
} IntegerMapT;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct RuntimeDataS {
|
typedef struct RuntimeDataS {
|
||||||
uint32_t protocolVersion;
|
uint32_t protocolVersion;
|
||||||
StringMapT *strings;
|
StringMapT *strings;
|
||||||
IntegerMapT *integers;
|
|
||||||
} RuntimeDataT;
|
} RuntimeDataT;
|
||||||
|
|
||||||
|
|
||||||
extern RuntimeDataT __runtimeData;
|
extern RuntimeDataT __runtimeData;
|
||||||
|
|
||||||
|
|
||||||
|
void runtimeDataLoad(void);
|
||||||
|
void runtimeDataUpdate(void);
|
||||||
|
void runtimeShutdown(void);
|
||||||
|
void runtimeStartup(void);
|
||||||
|
|
||||||
|
|
||||||
#endif // RUNTIME_H
|
#endif // RUNTIME_H
|
||||||
|
|
|
@ -188,7 +188,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" User Name:"),
|
T_TITLE, P(" User Name:"),
|
||||||
T_X, 40, T_Y, 64,
|
T_X, 40, T_Y, 64,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxUser"),
|
T_LENGTH, RUNTIME_INT("maxUser"),
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
T_TEXTBOX, O(_txtPass1),
|
T_TEXTBOX, O(_txtPass1),
|
||||||
|
@ -196,7 +196,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" Password:"),
|
T_TITLE, P(" Password:"),
|
||||||
T_X, 40, T_Y, 94,
|
T_X, 40, T_Y, 94,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxPass"),
|
T_LENGTH, RUNTIME_INT("maxPass"),
|
||||||
T_MASK, '*',
|
T_MASK, '*',
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" Password (again):"),
|
T_TITLE, P(" Password (again):"),
|
||||||
T_X, 40, T_Y, 124,
|
T_X, 40, T_Y, 124,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxPass"),
|
T_LENGTH, RUNTIME_INT("maxPass"),
|
||||||
T_MASK, '*',
|
T_MASK, '*',
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" REAL First Name:"),
|
T_TITLE, P(" REAL First Name:"),
|
||||||
T_X, 40, T_Y, 154,
|
T_X, 40, T_Y, 154,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxName"),
|
T_LENGTH, RUNTIME_INT("maxName"),
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
T_TEXTBOX, O(_txtLast),
|
T_TEXTBOX, O(_txtLast),
|
||||||
|
@ -222,7 +222,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" REAL Last Name:"),
|
T_TITLE, P(" REAL Last Name:"),
|
||||||
T_X, 40, T_Y, 184,
|
T_X, 40, T_Y, 184,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxName"),
|
T_LENGTH, RUNTIME_INT("maxName"),
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
T_TEXTBOX, O(_txtEmail),
|
T_TEXTBOX, O(_txtEmail),
|
||||||
|
@ -230,7 +230,7 @@ void signupShow(void) {
|
||||||
T_TITLE, P(" VALID E-Mail:"),
|
T_TITLE, P(" VALID E-Mail:"),
|
||||||
T_X, 40, T_Y, 214,
|
T_X, 40, T_Y, 214,
|
||||||
T_WIDTH, 300,
|
T_WIDTH, 300,
|
||||||
T_LENGTH, shget(__runtimeData.integers, "maxEmail"),
|
T_LENGTH, RUNTIME_INT("maxEmail"),
|
||||||
T_TEXTBOX, T_DONE,
|
T_TEXTBOX, T_DONE,
|
||||||
|
|
||||||
T_BUTTON, O(_btnCancel),
|
T_BUTTON, O(_btnCancel),
|
||||||
|
@ -363,8 +363,8 @@ static uint8_t validateName(char *username) {
|
||||||
char *allowed;
|
char *allowed;
|
||||||
char needle[2];
|
char needle[2];
|
||||||
|
|
||||||
if ((int32_t)strlen(username) < shget(__runtimeData.integers, "minName")) return 0;
|
if ((int32_t)strlen(username) < RUNTIME_INT("minName")) return 0;
|
||||||
if ((int32_t)strlen(username) > shget(__runtimeData.integers, "maxName")) return 0;
|
if ((int32_t)strlen(username) > RUNTIME_INT("maxName")) return 0;
|
||||||
|
|
||||||
allowed = shget(__runtimeData.strings, "nameAllowed");
|
allowed = shget(__runtimeData.strings, "nameAllowed");
|
||||||
needle[1] = 0;
|
needle[1] = 0;
|
||||||
|
@ -389,13 +389,13 @@ static uint8_t validatePassword(char *password) {
|
||||||
char *passNumeric;
|
char *passNumeric;
|
||||||
char needle[2];
|
char needle[2];
|
||||||
|
|
||||||
if ((int32_t)strlen(password) < shget(__runtimeData.integers, "minPass")) return 0;
|
if ((int32_t)strlen(password) < RUNTIME_INT("minPass")) return 0;
|
||||||
if ((int32_t)strlen(password) > shget(__runtimeData.integers, "maxPass")) return 0;
|
if ((int32_t)strlen(password) > RUNTIME_INT("maxPass")) return 0;
|
||||||
|
|
||||||
passLower = shget(__runtimeData.strings, "passLower");
|
passLower = RUNTIME_STR("passLower");
|
||||||
passUpper = shget(__runtimeData.strings, "passUpper");
|
passUpper = RUNTIME_STR("passUpper");
|
||||||
passSpecial = shget(__runtimeData.strings, "passSpecial");
|
passSpecial = RUNTIME_STR("passSpecial");
|
||||||
passNumeric = shget(__runtimeData.strings, "passNumeric");
|
passNumeric = RUNTIME_STR("passNumeric");
|
||||||
needle[1] = 0;
|
needle[1] = 0;
|
||||||
for (x=0; x<strlen(password); x++) {
|
for (x=0; x<strlen(password); x++) {
|
||||||
needle[0] = password[x];
|
needle[0] = password[x];
|
||||||
|
@ -405,10 +405,10 @@ static uint8_t validatePassword(char *password) {
|
||||||
if (strstr(passNumeric, needle)) numericCount++;
|
if (strstr(passNumeric, needle)) numericCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowerCount < shget(__runtimeData.integers, "minPassLower")) return 0;
|
if (lowerCount < RUNTIME_INT("minPassLower")) return 0;
|
||||||
if (upperCount < shget(__runtimeData.integers, "minPassUpper")) return 0;
|
if (upperCount < RUNTIME_INT("minPassUpper")) return 0;
|
||||||
if (specialCount < shget(__runtimeData.integers, "minPassSpecial")) return 0;
|
if (specialCount < RUNTIME_INT("minPassSpecial")) return 0;
|
||||||
if (numericCount < shget(__runtimeData.integers, "minPassNumeric")) return 0;
|
if (numericCount < RUNTIME_INT("minPassNumeric")) return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -419,10 +419,10 @@ static uint8_t validateUser(char *username) {
|
||||||
char *allowed;
|
char *allowed;
|
||||||
char needle[2];
|
char needle[2];
|
||||||
|
|
||||||
if ((int32_t)strlen(username) < shget(__runtimeData.integers, "minUser")) return 0;
|
if ((int32_t)strlen(username) < RUNTIME_INT("minUser")) return 0;
|
||||||
if ((int32_t)strlen(username) > shget(__runtimeData.integers, "maxUser")) return 0;
|
if ((int32_t)strlen(username) > RUNTIME_INT("maxUser")) return 0;
|
||||||
|
|
||||||
allowed = shget(__runtimeData.strings, "userAllowed");
|
allowed = RUNTIME_STR("userAllowed");
|
||||||
needle[1] = 0;
|
needle[1] = 0;
|
||||||
for (x=0; x<strlen(username); x++) {
|
for (x=0; x<strlen(username); x++) {
|
||||||
needle[0] = username[x];
|
needle[0] = username[x];
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
@ -91,16 +92,72 @@ uint8_t dbExecute(char *sql, char *format, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t dbQueryMultiple(char ****result, char *sql, char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
sqlite3_stmt *stmt = NULL;
|
||||||
|
int32_t r;
|
||||||
|
uint8_t cols;
|
||||||
|
uint8_t x;
|
||||||
|
char ***records = NULL;
|
||||||
|
char **fields = NULL;
|
||||||
|
|
||||||
|
if (format == NULL) {
|
||||||
|
// No parameters, just run it.
|
||||||
|
r = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
|
||||||
|
} else {
|
||||||
|
va_start(args, format);
|
||||||
|
stmt = dbSqlBind(sql, format, args);
|
||||||
|
va_end(args);
|
||||||
|
r = SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (r == SQLITE_OK || r == SQLITE_ROW) {
|
||||||
|
r = sqlite3_step(stmt);
|
||||||
|
if (r == SQLITE_ROW) {
|
||||||
|
cols = sqlite3_data_count(stmt);
|
||||||
|
x = 0;
|
||||||
|
while (cols-- > 0) {
|
||||||
|
arrput(fields, strdup((char *)sqlite3_column_text(stmt, x++)));
|
||||||
|
}
|
||||||
|
arrput(records, fields);
|
||||||
|
fields = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
logWrite("\n\n");
|
||||||
|
for (int r = 0; r < arrlen(records); r++) {
|
||||||
|
fields = records[r];
|
||||||
|
for (int f = 0; f < arrlen(fields); f++) {
|
||||||
|
logWrite("%s\t", fields[f]);
|
||||||
|
}
|
||||||
|
logWrite("\n");
|
||||||
|
}
|
||||||
|
logWrite("\n\n");
|
||||||
|
*/
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
|
*result = records;
|
||||||
|
|
||||||
|
return (r == SQLITE_OK || r == SQLITE_DONE) ? SUCCESS : FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) {
|
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
sqlite3_stmt *stmt = NULL;
|
sqlite3_stmt *stmt = NULL;
|
||||||
int32_t r;
|
int32_t r = 0;
|
||||||
static double d;
|
static double d = 0;
|
||||||
static int32_t i;
|
static int32_t i = 0;
|
||||||
static char *v = NULL;
|
static char *v = NULL;
|
||||||
|
|
||||||
if (v) DEL(v);
|
if (v) DEL(v);
|
||||||
|
|
||||||
|
// If everything is NULL, we're cleaning up internal variables (which we do before this). Just exit.
|
||||||
|
if (rformat == 0 && result == NULL && sql == NULL && format == NULL) return SUCCESS;
|
||||||
|
|
||||||
if (format == NULL) {
|
if (format == NULL) {
|
||||||
// No parameters, just run it.
|
// No parameters, just run it.
|
||||||
r = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
|
r = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
|
||||||
|
@ -140,11 +197,32 @@ uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...)
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
return r == SQLITE_OK ? SUCCESS : FAIL;
|
return (r == SQLITE_OK || r == SQLITE_DONE || r == SQLITE_ROW) ? SUCCESS : FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dbResultRelease(char ****result) {
|
||||||
|
char ***records = *result;
|
||||||
|
char **fields = NULL;
|
||||||
|
char *value = NULL;
|
||||||
|
|
||||||
|
while (arrlen(records) > 0) {
|
||||||
|
fields = records[0];
|
||||||
|
while (arrlen(fields) > 0) {
|
||||||
|
value = fields[0];
|
||||||
|
DEL(value);
|
||||||
|
arrdel(fields, 0);
|
||||||
|
}
|
||||||
|
arrdel(records, 0);
|
||||||
|
}
|
||||||
|
arrfree(records);
|
||||||
|
|
||||||
|
result = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dbShutdown(void) {
|
void dbShutdown(void) {
|
||||||
|
dbQuerySingle(0, NULL, NULL, NULL); // Release memory held by dbQuerySingle.
|
||||||
sqlite3_close(_db);
|
sqlite3_close(_db);
|
||||||
_db = NULL;
|
_db = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbExecute(char *sql, char *format, ...);
|
uint8_t dbExecute(char *sql, char *format, ...);
|
||||||
|
uint8_t dbQueryMultiple(char ****result, char *sql, char *format, ...);
|
||||||
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...);
|
uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...);
|
||||||
|
void dbResultRelease(char ****result);
|
||||||
void dbShutdown(void);
|
void dbShutdown(void);
|
||||||
void dbStartup(void);
|
void dbStartup(void);
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ void dbGameRelease(DbGameT **game) {
|
||||||
DEL(g->series);
|
DEL(g->series);
|
||||||
DEL(g->origin);
|
DEL(g->origin);
|
||||||
DEL(g->shortName);
|
DEL(g->shortName);
|
||||||
|
DEL(g->worksWith);
|
||||||
DEL(g);
|
DEL(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,6 +313,8 @@ DbGameT **dbGamesGet(void) {
|
||||||
int32_t i = 0;
|
int32_t i = 0;
|
||||||
DbGameT **gameList = NULL;
|
DbGameT **gameList = NULL;
|
||||||
DbGameT *game = NULL;
|
DbGameT *game = NULL;
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
int32_t x = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&_mutex);
|
pthread_mutex_lock(&_mutex);
|
||||||
|
|
||||||
|
@ -321,8 +324,8 @@ DbGameT **dbGamesGet(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p += sprintf(p,
|
p += sprintf(p,
|
||||||
"SELECT title, publisher, developer, description, releaseDate, "
|
"SELECT title, publisher, developer, description, releaseDate, rating, series, "
|
||||||
"rating, series, origin, shortName, type, maxPlayers, joinable "
|
"origin, shortName, worksWith, type, maxPlayers, joinable "
|
||||||
"FROM games WHERE active=1");
|
"FROM games WHERE active=1");
|
||||||
if (mysql_real_query(_sql, statement, p - statement) != 0) {
|
if (mysql_real_query(_sql, statement, p - statement) != 0) {
|
||||||
logWrite("dbGamesGet: %s\n", mysql_error(_sql));
|
logWrite("dbGamesGet: %s\n", mysql_error(_sql));
|
||||||
|
@ -357,13 +360,31 @@ DbGameT **dbGamesGet(void) {
|
||||||
game->series = strdup(row[6]);
|
game->series = strdup(row[6]);
|
||||||
game->origin = strdup(row[7]);
|
game->origin = strdup(row[7]);
|
||||||
game->shortName = strdup(row[8]);
|
game->shortName = strdup(row[8]);
|
||||||
|
game->worksWith = strdup(row[9]);
|
||||||
game->type = GAME_TYPE_UNKNOWN;
|
game->type = GAME_TYPE_UNKNOWN;
|
||||||
game->maxPlayers = atoi(row[10]);
|
if (!strcasecmp(row[10], "DOOR")) game->type = GAME_TYPE_DOOR;
|
||||||
game->joinable = atoi(row[11]);
|
if (!strcasecmp(row[10], "SERIAL")) game->type = GAME_TYPE_SERIAL;
|
||||||
if (!strcasecmp(row[9], "DOOR")) game->type = GAME_TYPE_DOOR;
|
if (!strcasecmp(row[10], "IPX")) game->type = GAME_TYPE_IPX;
|
||||||
if (!strcasecmp(row[9], "SERIAL")) game->type = GAME_TYPE_SERIAL;
|
if (!strcasecmp(row[10], "FICTION")) game->type = GAME_TYPE_FICTION;
|
||||||
if (!strcasecmp(row[9], "IPX")) game->type = GAME_TYPE_IPX;
|
game->maxPlayers = atoi(row[11]);
|
||||||
if (!strcasecmp(row[9], "FICTION")) game->type = GAME_TYPE_FICTION;
|
game->joinable = atoi(row[12]);
|
||||||
|
|
||||||
|
// Find screenshot and box image count from filesystem.
|
||||||
|
x = 0;
|
||||||
|
while (1) {
|
||||||
|
snprintf(filename, MAX_PATH, "%s/games/%c/%s/screen%d.png", __settingsFile, game->shortName[0], game->shortName, x + 1);
|
||||||
|
if (!utilFileExists(filename)) break;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
game->screens = x;
|
||||||
|
x = 0;
|
||||||
|
while (1) {
|
||||||
|
snprintf(filename, MAX_PATH, "%s/games/%c/%s/box%d.png", __settingsFile, game->shortName[0], game->shortName, x + 1);
|
||||||
|
if (!utilFileExists(filename)) break;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
game->boxes = x;
|
||||||
|
|
||||||
arrput(gameList, game);
|
arrput(gameList, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,9 +62,12 @@ typedef struct DbGameS {
|
||||||
char *series;
|
char *series;
|
||||||
char *origin;
|
char *origin;
|
||||||
char *shortName;
|
char *shortName;
|
||||||
|
char *worksWith;
|
||||||
DbGameTypeT type;
|
DbGameTypeT type;
|
||||||
uint8_t maxPlayers;
|
uint8_t maxPlayers;
|
||||||
uint8_t joinable;
|
uint8_t joinable;
|
||||||
|
uint8_t screens;
|
||||||
|
uint8_t boxes;
|
||||||
} DbGameT;
|
} DbGameT;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -233,9 +233,12 @@ static void updateGames(void) {
|
||||||
fwrite(game->series, strlen(game->series) + 1, 1, f);
|
fwrite(game->series, strlen(game->series) + 1, 1, f);
|
||||||
fwrite(game->origin, strlen(game->origin) + 1, 1, f);
|
fwrite(game->origin, strlen(game->origin) + 1, 1, f);
|
||||||
fwrite(game->shortName, strlen(game->shortName) + 1, 1, f);
|
fwrite(game->shortName, strlen(game->shortName) + 1, 1, f);
|
||||||
|
fwrite(game->worksWith, strlen(game->worksWith) + 1, 1, f);
|
||||||
c = game->type; fputc(c, f);
|
c = game->type; fputc(c, f);
|
||||||
c = game->maxPlayers; fputc(c, f);
|
c = game->maxPlayers; fputc(c, f);
|
||||||
c = game->joinable; fputc(c, f);
|
c = game->joinable; fputc(c, f);
|
||||||
|
c = game->screens; fputc(c, f);
|
||||||
|
c = game->boxes; fputc(c, f);
|
||||||
|
|
||||||
dbGameRelease(&game);
|
dbGameRelease(&game);
|
||||||
arrdel(gameList, 0);
|
arrdel(gameList, 0);
|
||||||
|
|
|
@ -105,6 +105,18 @@ void utilDie(const char *why, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t utilFileExists(char *filename) {
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char **utilWrapText(char *text, uint16_t width) {
|
char **utilWrapText(char *text, uint16_t width) {
|
||||||
char **lines = NULL;
|
char **lines = NULL;
|
||||||
char *head = text;
|
char *head = text;
|
||||||
|
|
|
@ -25,12 +25,13 @@
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
char *utilAppNameWithNewExtensionGet(char *appName, char *extension);
|
char *utilAppNameWithNewExtensionGet(char *appName, char *extension);
|
||||||
void utilBitsPrint(uint8_t byte);
|
void utilBitsPrint(uint8_t byte);
|
||||||
char *utilCreateString(char *format, ...);
|
char *utilCreateString(char *format, ...);
|
||||||
char *utilCreateStringVArgs(char *format, va_list args);
|
char *utilCreateStringVArgs(char *format, va_list args);
|
||||||
void utilDie(const char *why, ...);
|
void utilDie(const char *why, ...);
|
||||||
char **utilWrapText(char *text, uint16_t width);
|
uint8_t utilFileExists(char *filename);
|
||||||
|
char **utilWrapText(char *text, uint16_t width);
|
||||||
|
|
||||||
|
|
||||||
#endif // UTIL_H
|
#endif // UTIL_H
|
||||||
|
|
Loading…
Add table
Reference in a new issue