Browse Source

Update config file parsing

Unify config loading in net and video subsystems.
feature/data-structs
TheoryOfNekomata 2 years ago
parent
commit
3094b571d5
7 changed files with 441 additions and 129 deletions
  1. +36
    -21
      src/packages/game/IZ_app.c
  2. +235
    -0
      src/packages/game/IZ_config.c
  3. +24
    -1
      src/packages/game/IZ_config.h
  4. +57
    -51
      src/packages/game/net/IZ_net.c
  5. +51
    -32
      src/packages/game/output/video/IZ_video.c
  6. +1
    -1
      src/packages/game/output/video/IZ_video.h
  7. +37
    -23
      src/packages/server/IZ_app.c

+ 36
- 21
src/packages/game/IZ_app.c View File

@@ -65,29 +65,44 @@ void IZ_AppTeardown(struct IZ_App* app) {
SDL_Quit();
}

void IZ_AppPrintHelpOptions() {
printf("\n");
printf("Options:\n");
printf("\n");
printf(
"\n"
"Options:\n"
"\n"
" -c <path> Specifies the path to the config file. (default: \"./config-game.ini\")\n"
" -f <value> Specifies the frames per second. (default: 30)\n"
" -h Displays this help screen.\n"
" -i <value> Specifies the interval of sending packets (default: 200)\n"
" in milliseconds.\n"

);
}

void IZ_AppPrintHelpUsage() {
printf("\n");
printf("Usage:");
printf(" %s [options]\n", "game.exe");
}

void IZ_AppPrintHelpHeader() {
printf("\n");
printf("%s - %s\n", IZ_APP_NAME, IZ_APP_DESCRIPTION);
}

void IZ_AppPrintHelp() {
IZ_AppPrintHelpHeader();
IZ_AppPrintHelpUsage();
IZ_AppPrintHelpOptions();
}

IZ_ProcedureResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) {
// TODO have a config subsystem that handles these.
if (IZ_ConfigGetCommandlineOption(argc, argv, "-h")) {
printf(
(
"\n"
"%s - %s\n"
"\n"
"Usage:\n"
"\n"
" %s [options]\n"
"\n"
"Options:\n"
"\n"
" -c <path> Specifies the path to the config file. (default: \"./config-game.ini\")\n"
" -f <value> Specifies the frames per second. (default: 30)\n"
" -h Displays this help file.\n"
" -i <value> Specifies the interval of sending packets (default: 200)\n"
" in milliseconds.\n"
),
IZ_APP_NAME,
IZ_APP_DESCRIPTION,
"game.exe"
);
IZ_AppPrintHelp();
return IZ_APP_RUN_RESULT_OK;
}



+ 235
- 0
src/packages/game/IZ_config.c View File

@@ -33,3 +33,238 @@ const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const cha

return NULL;
}

typedef bool IZ_ConfigLoadParamsStringValidator(const char*);

typedef bool IZ_ConfigLoadParamsU16Validator(u16);

typedef bool IZ_ConfigLoadParamsU8Validator(u8);

void IZ_ConfigEnsureValidString(IZ_ConfigItem item, char* buffer) {
char dest[item.dest_size];
if (item.validator) {
IZ_ConfigLoadParamsStringValidator* validator = item.validator;
if (validator(buffer)) {
memcpy_s(dest, item.dest_size, buffer, item.dest_size);
item.dest = &dest;
return;
}
memcpy_s(dest, item.dest_size, item.default_value, item.dest_size);
item.dest = &dest;
return;
}
memcpy_s(dest, item.dest_size, buffer, item.dest_size);
item.dest = &dest;
}

void IZ_ConfigLoadString(IZ_ConfigItem item, const char* config_path) {
char buffer[item.dest_size];
ini_gets(item.section, item.key, item.default_value, buffer, item.dest_size, config_path);
IZ_ConfigEnsureValidString(item, buffer);
}

void IZ_ConfigEnsureValidU8(IZ_ConfigItem item, u8 raw_value, u8 default_value) {
if (item.validator) {
IZ_ConfigLoadParamsU8Validator* validator = item.validator;
if (validator(raw_value)) {
item.dest = &raw_value;
return;
}
item.dest = &default_value;
return;
}
item.dest = &raw_value;
}

void IZ_ConfigLoadU8(IZ_ConfigItem item, const char* config_path) {
static u8 raw_value;
static u8 default_value;
default_value = *((u8*) item.default_value);
raw_value = ini_getl(item.section, item.key, default_value, config_path);
IZ_ConfigEnsureValidU8(item, raw_value, default_value);
}

void IZ_ConfigEnsureValidU16(IZ_ConfigItem item, u16 raw_value, u16 default_value) {
if (item.validator) {
IZ_ConfigLoadParamsU16Validator* validator = item.validator;
if (validator(raw_value)) {
item.dest = &raw_value;
return;
}
item.dest = &default_value;
return;
}
item.dest = &raw_value;
}

void IZ_ConfigLoadU16(IZ_ConfigItem item, const char* config_path) {
static u16 raw_value;
static u16 default_value;
default_value = *((u16*) item.default_value);
raw_value = ini_getl(item.section, item.key, default_value, config_path);
IZ_ConfigEnsureValidU16(item, raw_value, default_value);
}

void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) {
u8 i;
for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) {
switch (item[i].type) {
case IZ_CONFIG_TYPE_STRING:
IZ_ConfigLoadString(item[i], config_path);
break;
case IZ_CONFIG_TYPE_U8:
IZ_ConfigLoadU8(item[i], config_path);
break;
case IZ_CONFIG_TYPE_U16:
IZ_ConfigLoadU16(item[i], config_path);
break;
default:
break;
}
}
}

IZ_ProcedureResult IZ_ConfigSaveU8(IZ_ConfigItem item, const char* config_path) {
u8 dest = *((u8*) item.dest);
if (item.validator) {
IZ_ConfigLoadParamsU8Validator* validator = item.validator;
if (!validator(dest)) {
dest = *((const u8*) item.default_value);
}
}

if (!ini_putl(item.section, item.key, dest, config_path)) {
return -1;
}

return 0;
}

IZ_ProcedureResult IZ_ConfigSaveU16(IZ_ConfigItem item, const char* config_path) {
u16 dest = *((u16*) item.dest);
if (item.validator) {
IZ_ConfigLoadParamsU8Validator* validator = item.validator;
if (!validator(dest)) {
dest = *((const u16*) item.default_value);
}
}

if (!ini_putl(item.section, item.key, dest, config_path)) {
return -1;
}

return 0;
}

IZ_ProcedureResult IZ_ConfigSaveString(IZ_ConfigItem item, const char* config_path) {
const char* dest = (const char*) item.dest;
if (item.validator) {
IZ_ConfigLoadParamsStringValidator* validator = item.validator;
if (!validator(dest)) {
dest = (const char*) item.default_value;
}
}

if (!ini_puts(item.section, item.key, dest, config_path)) {
return -1;
}

return 0;
}

IZ_ProcedureResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) {
u8 i;
u16 problems = 0;
for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) {
switch (item[i].type) {
case IZ_CONFIG_TYPE_STRING:
IZ_ConfigSaveString(item[i], config_path);
break;
case IZ_CONFIG_TYPE_U8:
IZ_ConfigSaveU8(item[i], config_path);
break;
case IZ_CONFIG_TYPE_U16:
IZ_ConfigSaveU16(item[i], config_path);
break;
default:
break;
}
}

return -problems;
}

void IZ_ConfigOverrideU8(IZ_ConfigItem item, u8 argc, const char* argv[]) {
if (!item.cmdline_option) {
return;
}
const char* cmdline_buffer;
char* rest_of_string;
static u8 dest;
static u8 default_value;
default_value = *((u16*) item.default_value);
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) {
dest = strtol(cmdline_buffer, &rest_of_string, 10);
if (strcmp(cmdline_buffer, rest_of_string) != 0) {
IZ_ConfigEnsureValidU8(item, dest, default_value);
return;
}
item.dest = &default_value;
}
}

void IZ_ConfigOverrideU16(IZ_ConfigItem item, u8 argc, const char* argv[]) {
if (!item.cmdline_option) {
return;
}
const char* cmdline_buffer;
char* rest_of_string;
static u16 dest;
static u16 default_value;
default_value = *((u16*) item.default_value);
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) {
dest = strtol(cmdline_buffer, &rest_of_string, 10);
if (strcmp(cmdline_buffer, rest_of_string) != 0) {
IZ_ConfigEnsureValidU16(item, dest, default_value);
return;
}
item.dest = &default_value;
}
}

void IZ_ConfigOverrideString(IZ_ConfigItem item, u8 argc, const char* argv[]) {
if (!item.cmdline_option) {
return;
}
const char* cmdline_buffer;
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) {
IZ_ConfigEnsureValidString(item, cmdline_buffer);
}
}

void IZ_ConfigOverride(IZ_ConfigItem item[], u8 argc, const char* argv[]) {
u8 i;
for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) {
switch (item[i].type) {
case IZ_CONFIG_TYPE_U8:
IZ_ConfigOverrideU8(item[i], argc, argv);
break;
case IZ_CONFIG_TYPE_U16:
IZ_ConfigOverrideU16(item[i], argc, argv);
break;
case IZ_CONFIG_TYPE_STRING:
IZ_ConfigOverrideString(item[i], argc, argv);
break;
default:
break;
}
}
}

void IZ_ConfigInit(IZ_ConfigItem item[], const char* config_path, u8 argc, const char* argv[]) {
IZ_ConfigLoad(item, config_path);
if (IZ_ConfigSave(item, config_path)) {
// TODO log errors in saving
}
IZ_ConfigOverride(item, argc, argv);
}

+ 24
- 1
src/packages/game/IZ_config.h View File

@@ -3,11 +3,34 @@

#include <SDL_filesystem.h>
#include <string.h>
#include <minIni.h>
#include <stdlib.h>
#include "IZ_common.h"

// TODO unify loading of config from cmdline and config file
typedef enum {
IZ_CONFIG_TYPE_VOID,
IZ_CONFIG_TYPE_STRING,
IZ_CONFIG_TYPE_U8,
IZ_CONFIG_TYPE_U16
} IZ_ConfigType;

typedef struct {
IZ_ConfigType type;
size_t dest_size;
const char* section;
const char* key;
const char* cmdline_option;
const void* default_value;
void* validator;
void* dest;
} IZ_ConfigItem;

void IZ_ConfigGetDefaultPath(const char*, size_t);

const char* IZ_ConfigGetCommandlineOption(u8, const char**, const char*);

void IZ_ConfigInit(IZ_ConfigItem[], const char*, u8, const char**);

IZ_ProcedureResult IZ_ConfigSave(IZ_ConfigItem[], const char*);

#endif

+ 57
- 51
src/packages/game/net/IZ_net.c View File

@@ -1,57 +1,66 @@
#include "IZ_net.h"

void IZ_NetLoadConfig(IZ_NetState* state, const char* config_path) {
char buffer[32];

ini_gets("Network", "Username", IZ_NET_DEFAULT_STATE.config.username, buffer, 32, config_path);
memcpy_s(state->config.username, 32, buffer, 32);

state->config.packet_interval_ms = ini_getl("Network", "PacketIntervalMs", IZ_NET_DEFAULT_STATE.config.packet_interval_ms, config_path);
if (!(100 <= state->config.packet_interval_ms && state->config.packet_interval_ms <= 500)) {
state->config.packet_interval_ms = IZ_NET_DEFAULT_STATE.config.packet_interval_ms;
}

state->config.max_reconnect_retries = ini_getl("Network", "MaxReconnectRetries", IZ_NET_DEFAULT_STATE.config.max_reconnect_retries, config_path);
if (!(0 <= state->config.max_reconnect_retries && state->config.max_reconnect_retries <= 8)) {
state->config.max_reconnect_retries = IZ_NET_DEFAULT_STATE.config.max_reconnect_retries;
}

state->config.reconnect_interval_secs = ini_getl("Network", "ReconnectIntervalSeconds", IZ_NET_DEFAULT_STATE.config.reconnect_interval_secs, config_path);
if (!(3 <= state->config.reconnect_interval_secs && state->config.reconnect_interval_secs <= 10)) {
state->config.reconnect_interval_secs = IZ_NET_DEFAULT_STATE.config.reconnect_interval_secs;
}
bool IZ_NetIsValidPacketIntervalMs(long packet_interval_ms) {
return (100 <= packet_interval_ms && packet_interval_ms <= 500);
}

IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState* state, const char* config_path) {
if (!ini_puts("Network", "Username", state->config.username, config_path)) {
return -1;
}

if (!ini_putl("Network", "PacketIntervalMs", state->config.packet_interval_ms, config_path)) {
return -1;
}

if (!ini_putl("Network", "MaxReconnectRetries", state->config.max_reconnect_retries, config_path)) {
return -1;
}
bool IZ_NetIsValidMaxReconnectRetries(long max_reconnect_retries) {
return (0 <= max_reconnect_retries && max_reconnect_retries <= 8);
}

if (!ini_putl("Network", "ReconnectIntervalSeconds", state->config.reconnect_interval_secs, config_path)) {
return -1;
}
bool IZ_NetIsValidReconnectIntervalSeconds(long reconnect_interval_secs) {
return (3 <= reconnect_interval_secs && reconnect_interval_secs <= 10);
}

return 0;
static IZ_ConfigItem net_config_items[] = {
{
IZ_CONFIG_TYPE_STRING,
32,
"Network",
"Username",
NULL,
&IZ_NET_DEFAULT_STATE.config.username,
NULL
},
{
IZ_CONFIG_TYPE_U16,
sizeof(u16),
"Network",
"PacketIntervalMs",
"-i",
&IZ_NET_DEFAULT_STATE.config.packet_interval_ms,
IZ_NetIsValidPacketIntervalMs,
},
{
IZ_CONFIG_TYPE_U8,
sizeof(u8),
"Network",
"MaxReconnectRetries",
NULL,
&IZ_NET_DEFAULT_STATE.config.max_reconnect_retries,
IZ_NetIsValidMaxReconnectRetries,
},
{
IZ_CONFIG_TYPE_U8,
sizeof(u8),
"Network",
"ReconnectIntervalSeconds",
NULL,
&IZ_NET_DEFAULT_STATE.config.reconnect_interval_secs,
IZ_NetIsValidReconnectIntervalSeconds,
},
};

void IZ_NetBindStateToConfig(IZ_NetState* state, IZ_ConfigItem config_items[]) {
config_items[0].dest = &state->config.username;
config_items[1].dest = &state->config.packet_interval_ms;
config_items[2].dest = &state->config.max_reconnect_retries;
config_items[3].dest = &state->config.reconnect_interval_secs;
}

void IZ_NetOverrideConfig(IZ_NetState* state, u8 argc, const char* argv[]) {
const char* cmdline_buffer;
char* rest_of_string;
u16 packet_interval_ms;
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, "-i"))) {
packet_interval_ms = strtol(cmdline_buffer, &rest_of_string, 10);
if (strcmp(cmdline_buffer, rest_of_string) != 0) {
state->config.packet_interval_ms = packet_interval_ms;
}
}
IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState* state, const char* config_path) {
IZ_NetBindStateToConfig(state, net_config_items);
return IZ_ConfigSave(net_config_items, config_path);
}

IZ_ProcedureResult IZ_NetInitialize(
@@ -63,11 +72,8 @@ IZ_ProcedureResult IZ_NetInitialize(
const char* argv[]
) {
memcpy_s(state, sizeof(IZ_NetState), &IZ_NET_DEFAULT_STATE, sizeof(IZ_NetState));
IZ_NetLoadConfig(state, config_path);
if (IZ_NetSaveConfig(state, config_path) < 0) {
return -1;
}
IZ_NetOverrideConfig(state, argc, argv);
IZ_NetBindStateToConfig(state, net_config_items);
IZ_ConfigInit(net_config_items, config_path, argc, argv);
if (!user_data) {
return -2;
}


+ 51
- 32
src/packages/game/output/video/IZ_video.c View File

@@ -1,45 +1,64 @@
#include "IZ_video.h"

IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState* state, const char* config_path) {
if (!ini_putl("Video", "Width", state->config.width, config_path)) {
return -1;
}
if (!ini_putl("Video", "Height", state->config.height, config_path)) {
return -1;
}
if (!ini_putl("Video", "MaxFps", state->config.max_fps, config_path)) {
return -1;
}
bool IZ_VideoIsValidWidth(u16 width) {
// TODO check screen size
return (320 <= width && width <= 16384);
}

return 0;
bool IZ_VideoIsValidHeight(u16 height) {
// TODO check screen size
return (240 <= height && height <= 8192);
}

void IZ_VideoLoadConfig(IZ_VideoState* state, const char* config_path) {
state->config.width = ini_getl("Video", "Width", IZ_DEFAULT_VIDEO_STATE.config.width, config_path);
state->config.height = ini_getl("Video", "Height", IZ_DEFAULT_VIDEO_STATE.config.height, config_path);
state->config.max_fps = ini_getl("Video", "MaxFps", IZ_DEFAULT_VIDEO_STATE.config.max_fps, config_path);
bool IZ_VideoIsValidMaxFPS(u8 max_fps) {
return (10 <= max_fps && max_fps <= 200);
}

void IZ_VideoOverrideConfig(IZ_VideoState* state, u8 argc, const char* argv[]) {
const char* cmdline_buffer;
char* rest_of_string;
u8 max_fps;
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, "-f"))) {
max_fps = strtol(cmdline_buffer, &rest_of_string, 10);
if (strcmp(cmdline_buffer, rest_of_string) != 0) {
state->config.max_fps = max_fps;
}
}
static IZ_ConfigItem video_config_items[] = {
{
IZ_CONFIG_TYPE_U16,
sizeof(u16),
"Video",
"Width",
NULL,
&IZ_VIDEO_DEFAULT_STATE.config.width,
IZ_VideoIsValidWidth,
},
{
IZ_CONFIG_TYPE_U16,
sizeof(u16),
"Video",
"Height",
NULL,
&IZ_VIDEO_DEFAULT_STATE.config.height,
IZ_VideoIsValidHeight,
},
{
IZ_CONFIG_TYPE_U8,
sizeof(u8),
"Video",
"MaxFps",
"-f",
&IZ_VIDEO_DEFAULT_STATE.config.max_fps,
IZ_VideoIsValidMaxFPS,
},
};

void IZ_VideoBindStateToConfig(IZ_VideoState* state, IZ_ConfigItem config_items[]) {
config_items[0].dest = &state->config.width;
config_items[1].dest = &state->config.height;
config_items[2].dest = &state->config.max_fps;
}

IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, const char* config_path, u8 argc, const char* argv[]) {
SDL_memcpy(state, &IZ_DEFAULT_VIDEO_STATE, sizeof(IZ_VideoState));
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState* state, const char* config_path) {
IZ_VideoBindStateToConfig(state, video_config_items);
return IZ_ConfigSave(video_config_items, config_path);
}

IZ_VideoLoadConfig(state, config_path);
if (IZ_VideoSaveConfig(state, config_path)) {
// fprintf_s(stderr, "Error committing video config.\n");
}
IZ_VideoOverrideConfig(state, argc, argv);
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, const char* config_path, u8 argc, const char* argv[]) {
SDL_memcpy(state, &IZ_VIDEO_DEFAULT_STATE, sizeof(IZ_VideoState));
IZ_VideoBindStateToConfig(state, video_config_items);
IZ_ConfigInit(video_config_items, config_path, argc, argv);
state->last_update_at = 0u;
state->user_data = user_data;



+ 1
- 1
src/packages/game/output/video/IZ_video.h View File

@@ -30,7 +30,7 @@ typedef struct {
IZ_Sprite active_sprites[MAX_ACTIVE_SPRITES];
} IZ_VideoState;

static const IZ_VideoState IZ_DEFAULT_VIDEO_STATE = {
static const IZ_VideoState IZ_VIDEO_DEFAULT_STATE = {
.user_data = NULL,
.config = {
.width = 320u,


+ 37
- 23
src/packages/server/IZ_app.c View File

@@ -41,31 +41,45 @@ void IZ_AppTeardown(IZ_App* app) {
lwsl_user("Server closed. Bye!\n");
}

void IZ_AppPrintHelpOptions() {
printf("\n");
printf("Options:\n");
printf("\n");
printf(
"\n"
"Options:\n"
"\n"
" -c <path> Specifies the path to the config file. (default: \"./config-server.ini\")\n"
" -d <path> Specifies the path to the database. (default: \"./db.sqlite\")\n"
" -h Displays this help screen.\n"
" -m <value> Specifies the message of the day. (default: \"\")\n"
" -n <value> Specifies the name of the server. (default: \"%s\")\n"
" -p <value> Specifies the port where the server runs. (default: 42069)\n",
IZ_APP_NAME
);
}

void IZ_AppPrintHelpUsage() {
printf("\n");
printf("Usage:");
printf(" %s [options]\n", "server.exe");
}

void IZ_AppPrintHelpHeader() {
printf("\n");
printf("%s - %s\n", IZ_APP_NAME, IZ_APP_SERVER_DESCRIPTION);
}

void IZ_AppPrintHelp() {
IZ_AppPrintHelpHeader();
IZ_AppPrintHelpUsage();
IZ_AppPrintHelpOptions();
}

IZ_ProcedureResult IZ_AppRun(IZ_App *app, u8 argc, const char **argv) {
// TODO have a config subsystem that handles these.
if (IZ_ConfigGetCommandlineOption(argc, argv, "-h")) {
printf(
(
"\n"
"%s - %s\n"
"\n"
"Usage:\n"
"\n"
" %s [options]\n"
"\n"
"Options:\n"
"\n"
" -c <path> Specifies the path to the config file. (default: \"./config-server.ini\")\n"
" -d <path> Specifies the path to the database. (default: \"./db.sqlite\")\n"
" -h Displays this help file.\n"
" -m <value> Specifies the message of the day. (default: \"\")\n"
" -n <value> Specifies the name of the server. (default: \"%s\")\n"
" -p <value> Specifies the port where the server runs. (default: 42069)\n"
),
IZ_APP_NAME,
IZ_APP_SERVER_DESCRIPTION,
"server.exe",
IZ_APP_NAME
);
IZ_AppPrintHelp();
return 0;
}



Loading…
Cancel
Save