Add libwebsockets client to game executable.feature/data-structs
@@ -70,13 +70,16 @@ add_executable( | |||||
src/packages/game/input/IZ_midi.h | src/packages/game/input/IZ_midi.h | ||||
src/packages/game/data/IZ_list.c | src/packages/game/data/IZ_list.c | ||||
src/packages/game/data/IZ_list.h | src/packages/game/data/IZ_list.h | ||||
) | |||||
src/packages/game/network/IZ_wsclient.c src/packages/game/network/IZ_wsclient.h) | |||||
target_link_libraries( | target_link_libraries( | ||||
game | game | ||||
SDL2main | SDL2main | ||||
SDL2 | SDL2 | ||||
portmidi | portmidi | ||||
libcrypto | |||||
libssl | |||||
websockets | |||||
) | ) | ||||
add_executable( | add_executable( | ||||
@@ -188,6 +191,21 @@ if (WIN32) | |||||
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/Release/portmidi.dll" # <--this is in-file | "${PROJECT_SOURCE_DIR}/dependencies/portmidi/Release/portmidi.dll" # <--this is in-file | ||||
$<TARGET_FILE_DIR:game>) # <--this is out-file path | $<TARGET_FILE_DIR:game>) # <--this is out-file path | ||||
add_custom_command(TARGET game POST_BUILD | |||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | |||||
"${PROJECT_SOURCE_DIR}/dependencies/libwebsockets/build/bin/Release/websockets.dll" # <--this is in-file | |||||
$<TARGET_FILE_DIR:game>) # <--this is out-file path | |||||
add_custom_command(TARGET game POST_BUILD | |||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | |||||
"${PROJECT_SOURCE_DIR}/dependencies/openssl/${PROJECT_ARCH}/bin/libssl-1_1-x64.dll" # <--this is in-file | |||||
$<TARGET_FILE_DIR:game>) # <--this is out-file path | |||||
add_custom_command(TARGET game POST_BUILD | |||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | |||||
"${PROJECT_SOURCE_DIR}/dependencies/openssl/${PROJECT_ARCH}/bin/libcrypto-1_1-x64.dll" # <--this is in-file | |||||
$<TARGET_FILE_DIR:game>) # <--this is out-file path | |||||
add_custom_command(TARGET server POST_BUILD | add_custom_command(TARGET server POST_BUILD | ||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | ||||
"${PROJECT_SOURCE_DIR}/dependencies/libwebsockets/build/bin/Release/websockets.dll" # <--this is in-file | "${PROJECT_SOURCE_DIR}/dependencies/libwebsockets/build/bin/Release/websockets.dll" # <--this is in-file | ||||
@@ -15,15 +15,16 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app) { | |||||
char config_path[128]; | char config_path[128]; | ||||
IZ_ConfigGetPath(config_path, 128); | IZ_ConfigGetPath(config_path, 128); | ||||
if (IZ_VideoInitialize(config_path, &app->video_state)) { | |||||
if (IZ_VideoInitialize(&app->video_state, config_path)) { | |||||
return 2; | return 2; | ||||
} | } | ||||
if (IZ_InputInitialize(config_path, &app->input_state)) { | |||||
if (IZ_InputInitialize(&app->input_state, config_path)) { | |||||
return 3; | return 3; | ||||
} | } | ||||
IZ_PoolInitialize(&app->pool, POOL_MAX_SIZE); | IZ_PoolInitialize(&app->pool, POOL_MAX_SIZE); | ||||
IZ_WSClientInitialize(&app->client, app); | |||||
// TODO put into its timer module | // TODO put into its timer module | ||||
app->ticks = 0; | app->ticks = 0; | ||||
@@ -31,6 +32,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app) { | |||||
} | } | ||||
void IZ_AppTeardown(IZ_App* app) { | void IZ_AppTeardown(IZ_App* app) { | ||||
IZ_WSClientTeardown(&app->client); | |||||
IZ_PoolTeardown(&app->pool); | IZ_PoolTeardown(&app->pool); | ||||
IZ_InputTeardown(&app->input_state); | IZ_InputTeardown(&app->input_state); | ||||
IZ_VideoTeardown(&app->video_state); | IZ_VideoTeardown(&app->video_state); | ||||
@@ -66,8 +68,8 @@ void IZ_AppHandlePortMIDIEvents(IZ_App* app) { | |||||
for (midi_event_index = 0; midi_event_index < *midi_events_count; midi_event_index += 1) { | for (midi_event_index = 0; midi_event_index < *midi_events_count; midi_event_index += 1) { | ||||
IZ_InputHandlePortMIDIEvents( | IZ_InputHandlePortMIDIEvents( | ||||
app->input_state.midi_input_state[player_index].event_buffer[midi_event_index], | |||||
&app->input_state | |||||
&app->input_state, | |||||
app->input_state.midi_input_state[player_index].event_buffer[midi_event_index] | |||||
); | ); | ||||
} | } | ||||
} | } | ||||
@@ -104,7 +106,7 @@ IZ_ProcedureResult IZ_AppRun(IZ_App* app, u8 arg_count, char* arg_values[]) { | |||||
break; | break; | ||||
} | } | ||||
IZ_VideoUpdate(&app->video_state, &app->input_state, app->ticks); | |||||
IZ_VideoUpdate(&app->video_state, app->ticks, &app->input_state); | |||||
} | } | ||||
IZ_AppTeardown(app); | IZ_AppTeardown(app); | ||||
@@ -10,12 +10,14 @@ | |||||
#include "input/IZ_input.h" | #include "input/IZ_input.h" | ||||
#include "output/IZ_video.h" | #include "output/IZ_video.h" | ||||
#include "memory/IZ_pool.h" | #include "memory/IZ_pool.h" | ||||
#include "network/IZ_wsclient.h" | |||||
typedef struct { | typedef struct { | ||||
IZ_InputState input_state; | IZ_InputState input_state; | ||||
IZ_VideoState video_state; | IZ_VideoState video_state; | ||||
IZ_Pool pool; | IZ_Pool pool; | ||||
IZ_WSClient client; | |||||
u64 ticks; | u64 ticks; | ||||
} IZ_App; | } IZ_App; | ||||
@@ -5,11 +5,11 @@ void IZ_InputHandleSDLEvents(IZ_InputState* state) { | |||||
IZ_KeyboardHandleEvents(state->sdl_event, &state->keyboard_state, &state->action); | IZ_KeyboardHandleEvents(state->sdl_event, &state->keyboard_state, &state->action); | ||||
} | } | ||||
void IZ_InputHandlePortMIDIEvents(PmEvent e, IZ_InputState* state) { | |||||
void IZ_InputHandlePortMIDIEvents(IZ_InputState* state, PmEvent e) { | |||||
IZ_MIDIInputHandleEvents(e, &state->midi_input_state, &state->action); | IZ_MIDIInputHandleEvents(e, &state->midi_input_state, &state->action); | ||||
} | } | ||||
IZ_ProcedureResult IZ_InputInitialize(const char* config_path, IZ_InputState* state) { | |||||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState* state, const char* config_path) { | |||||
*state = (IZ_InputState) { | *state = (IZ_InputState) { | ||||
.action = {}, | .action = {}, | ||||
.joystick_state = {}, | .joystick_state = {}, | ||||
@@ -16,9 +16,9 @@ typedef struct { | |||||
void IZ_InputHandleSDLEvents(IZ_InputState*); | void IZ_InputHandleSDLEvents(IZ_InputState*); | ||||
void IZ_InputHandlePortMIDIEvents(PmEvent, IZ_InputState*); | |||||
void IZ_InputHandlePortMIDIEvents(IZ_InputState*, PmEvent); | |||||
IZ_ProcedureResult IZ_InputInitialize(const char*, IZ_InputState*); | |||||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState*, const char*); | |||||
void IZ_InputTeardown(IZ_InputState*); | void IZ_InputTeardown(IZ_InputState*); | ||||
@@ -0,0 +1,90 @@ | |||||
#include "IZ_wsclient.h" | |||||
IZ_ProcedureResult IZ_WSClientCallback( | |||||
struct lws* wsi, | |||||
enum lws_callback_reasons reason, | |||||
void* user, | |||||
void* in, | |||||
size_t len | |||||
) { | |||||
switch (reason) { | |||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: | |||||
return 1; | |||||
case LWS_CALLBACK_CLIENT_CLOSED: | |||||
return 0; | |||||
case LWS_CALLBACK_CLIENT_RECEIVE: | |||||
case LWS_CALLBACK_CLIENT_ESTABLISHED: | |||||
default: | |||||
break; | |||||
} | |||||
return lws_callback_http_dummy(wsi, reason, user, in, len); | |||||
} | |||||
IZ_ProcedureResult IZ_WSClientConnect(IZ_WSClient* client, IZ_WSClientConnectParams params) { | |||||
static struct lws_client_connect_info info; | |||||
memset(&info, 0, sizeof info); | |||||
info.context = client->context; | |||||
info.port = params.port; | |||||
info.address = params.address; | |||||
info.host = params.address; | |||||
info.origin = params.address; | |||||
info.protocol = params.protocol; | |||||
info.path = params.path; | |||||
info.userdata = params.userdata; | |||||
// info.ssl_connection = ( | |||||
// LCCSCF_ALLOW_SELFSIGNED | |||||
// | LCCSCF_ALLOW_INSECURE | |||||
// | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | |||||
// | LCCSCF_ALLOW_EXPIRED | |||||
// ); | |||||
client->connection = lws_client_connect_via_info(&info); | |||||
if (!client->connection) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClient* client, void* app) { | |||||
static struct lws_protocols protocols[] = { | |||||
{ | |||||
.name = "lws-minimal-client", | |||||
.callback = IZ_WSClientCallback, | |||||
.per_session_data_size = 0, | |||||
.rx_buffer_size = 0, | |||||
.id = 0, | |||||
.user = NULL, | |||||
.tx_packet_size = 0, | |||||
}, | |||||
LWS_PROTOCOL_LIST_TERM, | |||||
}; | |||||
protocols[0].user = app; | |||||
static struct lws_context_creation_info info; | |||||
memset(&info, 0, sizeof info); | |||||
info.port = CONTEXT_PORT_NO_LISTEN, | |||||
info.protocols = protocols, | |||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT, | |||||
client->context = lws_create_context(&info); | |||||
if (!client->context) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClient* client) { | |||||
i32 response = lws_service(client->context, 0); | |||||
if (response < 0) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
void IZ_WSClientTeardown(IZ_WSClient* client) { | |||||
lws_context_destroy(client->context); | |||||
} |
@@ -0,0 +1,29 @@ | |||||
#ifndef IZ_WSCLIENT_H | |||||
#define IZ_WSCLIENT_H | |||||
#include <libwebsockets.h> | |||||
#include "../IZ_common.h" | |||||
typedef struct { | |||||
struct lws_context* context; | |||||
struct lws* connection; | |||||
i32 n; | |||||
} IZ_WSClient; | |||||
typedef struct { | |||||
u16 port; | |||||
const char* address; | |||||
const char* path; | |||||
const char* protocol; | |||||
void* userdata; | |||||
} IZ_WSClientConnectParams; | |||||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClient*, void*); | |||||
IZ_ProcedureResult IZ_WSClientConnect(IZ_WSClient*, IZ_WSClientConnectParams); | |||||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClient*); | |||||
void IZ_WSClientTeardown(IZ_WSClient*); | |||||
#endif |
@@ -1,6 +1,6 @@ | |||||
#include "IZ_video.h" | #include "IZ_video.h" | ||||
IZ_ProcedureResult IZ_VideoSaveConfig(const char* config_path, IZ_VideoConfig* config) { | |||||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoConfig* config, const char* config_path) { | |||||
if (!ini_putl("Video", "Width", config->width, config_path)) { | if (!ini_putl("Video", "Width", config->width, config_path)) { | ||||
return 1; | return 1; | ||||
} | } | ||||
@@ -14,17 +14,17 @@ IZ_ProcedureResult IZ_VideoSaveConfig(const char* config_path, IZ_VideoConfig* c | |||||
return 0; | return 0; | ||||
} | } | ||||
void IZ_VideoLoadConfig(const char* config_path, IZ_VideoConfig* config) { | |||||
void IZ_VideoLoadConfig(IZ_VideoConfig* config, const char* config_path) { | |||||
config->width = ini_getl("Video", "Width", IZ_DEFAULT_VIDEO_STATE.config.width, config_path); | config->width = ini_getl("Video", "Width", IZ_DEFAULT_VIDEO_STATE.config.width, config_path); | ||||
config->height = ini_getl("Video", "Height", IZ_DEFAULT_VIDEO_STATE.config.height, config_path); | config->height = ini_getl("Video", "Height", IZ_DEFAULT_VIDEO_STATE.config.height, config_path); | ||||
config->max_fps = ini_getl("Video", "MaxFps", IZ_DEFAULT_VIDEO_STATE.config.max_fps, config_path); | config->max_fps = ini_getl("Video", "MaxFps", IZ_DEFAULT_VIDEO_STATE.config.max_fps, config_path); | ||||
} | } | ||||
IZ_ProcedureResult IZ_VideoInitialize(const char* config_path, IZ_VideoState* state) { | |||||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_path) { | |||||
SDL_memcpy(state, &IZ_DEFAULT_VIDEO_STATE, sizeof(IZ_VideoState)); | SDL_memcpy(state, &IZ_DEFAULT_VIDEO_STATE, sizeof(IZ_VideoState)); | ||||
IZ_VideoLoadConfig(config_path, &state->config); | |||||
if (IZ_VideoSaveConfig(config_path, &state->config)) { | |||||
IZ_VideoLoadConfig(&state->config, config_path); | |||||
if (IZ_VideoSaveConfig(&state->config, config_path)) { | |||||
// fprintf_s(stderr, "Error committing video config.\n"); | // fprintf_s(stderr, "Error committing video config.\n"); | ||||
} | } | ||||
state->last_update_at = 0u; | state->last_update_at = 0u; | ||||
@@ -103,7 +103,7 @@ void IZ_VideoUpdateForDebug(IZ_VideoState* video_state, IZ_InputState* input_sta | |||||
IZ_VideoUpdateForDebugInput(video_state, input_state); | IZ_VideoUpdateForDebugInput(video_state, input_state); | ||||
} | } | ||||
void IZ_VideoUpdate(IZ_VideoState* video_state, IZ_InputState* input_state, u64 ticks) { | |||||
void IZ_VideoUpdate(IZ_VideoState* video_state, u64 ticks, IZ_InputState* input_state) { | |||||
if (ticks - video_state->last_update_at > 1000 / video_state->config.max_fps) { | if (ticks - video_state->last_update_at > 1000 / video_state->config.max_fps) { | ||||
// Update window | // Update window | ||||
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0x00, 0x00, 0xff); | SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0x00, 0x00, 0xff); | ||||
@@ -34,11 +34,11 @@ static const IZ_VideoState IZ_DEFAULT_VIDEO_STATE = { | |||||
.window = NULL, | .window = NULL, | ||||
}; | }; | ||||
IZ_ProcedureResult IZ_VideoInitialize(const char*, IZ_VideoState*); | |||||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, const char*); | |||||
IZ_ProcedureResult IZ_VideoSaveConfig(const char*, IZ_VideoConfig*); | |||||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoConfig*, const char*); | |||||
void IZ_VideoUpdate(IZ_VideoState*, IZ_InputState*, u64); | |||||
void IZ_VideoUpdate(IZ_VideoState*, u64, IZ_InputState*); | |||||
void IZ_VideoTeardown(IZ_VideoState*); | void IZ_VideoTeardown(IZ_VideoState*); | ||||
@@ -19,25 +19,30 @@ static const lws_retry_bo_t retry = { | |||||
static i32 interrupted; | static i32 interrupted; | ||||
static const struct lws_http_mount mount = { | static const struct lws_http_mount mount = { | ||||
/* .mount_next */ NULL, /* linked-list "next" */ | |||||
/* .mountpoint */ "/", /* mountpoint URL */ | |||||
/* .origin */ "./mount-origin", /* serve from dir */ | |||||
/* .def */ "index.html", /* default filename */ | |||||
/* .protocol */ NULL, | |||||
/* .cgienv */ NULL, | |||||
/* .extra_mimetypes */ NULL, | |||||
/* .interpret */ NULL, | |||||
/* .cgi_timeout */ 0, | |||||
/* .cache_max_age */ 0, | |||||
/* .auth_mask */ 0, | |||||
/* .cache_reusable */ 0, | |||||
/* .cache_revalidate */ 0, | |||||
/* .cache_intermediaries */ 0, | |||||
/* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ | |||||
/* .mountpoint_len */ 1, /* char count */ | |||||
/* .basic_auth_login_file */ NULL, | |||||
.mount_next = NULL, /* linked-list "next" */ | |||||
.mountpoint = "/", /* mountpoint URL */ | |||||
.origin = "./mount-origin", /* serve from dir */ | |||||
.def = "index.html", /* default filename */ | |||||
.protocol = NULL, | |||||
.cgienv = NULL, | |||||
.extra_mimetypes = NULL, | |||||
.interpret = NULL, | |||||
.cgi_timeout = 0, | |||||
.cache_max_age = 0, | |||||
.auth_mask = 0, | |||||
.cache_reusable = 0, | |||||
.cache_revalidate = 0, | |||||
.cache_intermediaries = 0, | |||||
.origin_protocol = LWSMPRO_FILE, /* files in a dir */ | |||||
.mountpoint_len = 1, /* char count */ | |||||
.basic_auth_login_file = NULL, | |||||
}; | }; | ||||
#if defined(LWS_WITH_PLUGINS) | |||||
/* if plugins enabled, only protocols explicitly named in pvo bind to vhost */ | |||||
static struct lws_protocol_vhost_options pvo = { NULL, NULL, "lws-minimal", "" }; | |||||
#endif | |||||
void sigint_handler(i32 sig) { | void sigint_handler(i32 sig) { | ||||
interrupted = 1; | interrupted = 1; | ||||
} | } | ||||