Implement the sending of input events to the websocket server.feature/data-structs
@@ -84,7 +84,7 @@ add_executable( | |||
src/packages/game/util/IZ_midi.h | |||
src/packages/game/net/core/IZ_websocket.h | |||
src/packages/game/net/core/IZ_websocket.c | |||
) | |||
src/packages/game/net/IZ_net.c src/packages/game/net/IZ_net.h) | |||
target_link_libraries( | |||
game | |||
@@ -1,77 +1,27 @@ | |||
#include "IZ_app.h" | |||
IZ_ProcedureResult IZ_AppWSClientInitialize(IZ_App* app) { | |||
if (IZ_WSClientInitialize(&app->client)) { | |||
printf("error\n"); | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_AppConnect(void* app_raw) { | |||
IZ_App* app = app_raw; | |||
if (IZ_AppWSClientInitialize(app)) { | |||
if (IZ_WSClientInitialize(&app->net_state.ws, app->net_state.params)) { | |||
return -1; | |||
} | |||
i32 result = 0; | |||
while (true) { | |||
if (IZ_WSClientHandle(&app->client)) { | |||
if (IZ_WSClientHandle(&app->net_state.ws)) { | |||
result = -1; | |||
break; | |||
} | |||
if (app->client.ws.interrupted) { | |||
if (app->net_state.ws.interrupted) { | |||
break; | |||
} | |||
} | |||
IZ_WSClientTeardown(&app->client); | |||
IZ_WSClientTeardown(&app->net_state.ws); | |||
return result; | |||
} | |||
void IZ_AppHandleNetworkingOutboundEvents(IZ_App* app) { | |||
struct lws* wsi = app->client.ws.connection; | |||
printf("%p\n", wsi); | |||
if (!wsi) { | |||
return; | |||
} | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
IZ_WebsocketMessage amsg; | |||
i32 result; | |||
result = IZ_WebsocketCreateTextMessage(wsi, &amsg, "hello", 5); | |||
if (result < 0) { | |||
return; | |||
} | |||
lws_ring_insert(vhd->ring, &amsg, 1); | |||
lws_callback_on_writable(wsi); | |||
} | |||
void IZ_AppEstablishConnection(IZ_App* app, IZ_WSClientInitializeParams params) { | |||
if (app->client.ws.context) { | |||
return; | |||
} | |||
app->client.params = params; | |||
app->client.userdata = app; | |||
app->client_thread = SDL_CreateThread(IZ_AppConnect, "networking", app); | |||
SDL_DetachThread(app->client_thread); | |||
} | |||
void IZ_AppCloseConnection(IZ_App* app) { | |||
if (!app->client.ws.context) { | |||
return; | |||
} | |||
app->client.ws.interrupted = true; | |||
IZ_WSClientCancelService(&app->client); | |||
} | |||
IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
memset(app, 0, sizeof(IZ_App)); | |||
u32 flags = ( | |||
@@ -102,6 +52,10 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
return IZ_APP_RUN_INPUT_INIT_ERROR; | |||
} | |||
if (IZ_NetInitialize(&app->net_state, app, IZ_AppConnect, config_path, argc, argv)) { | |||
return IZ_APP_RUN_NETWORKING_ERROR; | |||
} | |||
IZ_PoolInitialize(&app->pool, POOL_MAX_SIZE); | |||
// TODO put into its timer module | |||
@@ -110,7 +64,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
} | |||
void IZ_AppTeardown(IZ_App* app) { | |||
IZ_AppCloseConnection(app); | |||
IZ_NetDisconnect(&app->net_state); | |||
IZ_PoolTeardown(&app->pool); | |||
IZ_InputTeardown(&app->input_state); | |||
IZ_VideoTeardown(&app->video_state); | |||
@@ -126,15 +80,18 @@ IZ_ProcedureResult IZ_AppHandleSDLEvents(IZ_App* app) { | |||
if (e.type == SDL_KEYDOWN) { | |||
if (e.key.keysym.sym == SDLK_PAGEUP) { | |||
IZ_AppEstablishConnection(app, (IZ_WSClientInitializeParams){ | |||
.address = "127.0.0.1", | |||
.path = "/", | |||
.port = 42069, | |||
}); | |||
IZ_NetConnect( | |||
&app->net_state, | |||
(IZ_WSClientInitializeParams) { | |||
.host = "127.0.0.1", | |||
.path = "/", | |||
.port = 42069, | |||
} | |||
); | |||
} else if (e.key.keysym.sym == SDLK_PAGEDOWN) { | |||
IZ_AppCloseConnection(app); | |||
IZ_NetDisconnect(&app->net_state); | |||
} else if (e.key.keysym.sym == SDLK_INSERT) { | |||
IZ_AppHandleNetworkingOutboundEvents(app); | |||
IZ_NetSendTextMessage(&app->net_state, "hello", 5); | |||
} | |||
} | |||
@@ -178,7 +135,7 @@ void IZ_AppHandleNetworkingInboundBinaryEvents(IZ_App* app, void* binary_raw, si | |||
size_t i; | |||
printf("%llu: Binary", app->ticks); | |||
for (i = 0; i < len; i += 1) { | |||
printf("%c%x", i == 0 ? '(' : ' ', binary[i]); | |||
printf("%c%02x", i == 0 ? '(' : ' ', binary[i]); | |||
} | |||
printf(")\n"); | |||
} | |||
@@ -213,6 +170,18 @@ IZ_ProcedureResult IZ_AppRun(IZ_App* app, u8 argc, const char* argv[]) { | |||
break; | |||
} | |||
// TODO update this | |||
u8 player_index; | |||
for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { | |||
if (app->net_state.action[player_index] != app->input_state.action[player_index]) { | |||
IZ_NetSendBinaryMessage( | |||
&app->net_state, | |||
&(app->input_state.action[player_index]), | |||
sizeof app->input_state.action[player_index] | |||
); | |||
} | |||
app->net_state.action[player_index] = app->input_state.action[player_index]; | |||
} | |||
IZ_VideoUpdate(&app->video_state, app->ticks, &app->input_state); | |||
} | |||
@@ -311,7 +280,7 @@ void IZ_WSClientConnectionError(struct lws* wsi, void* in) { | |||
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); | |||
IZ_App* app = (IZ_App*) vhd->app; | |||
app->client.ws.connection = NULL; | |||
app->net_state.ws.connection = NULL; | |||
vhd->client_wsi = NULL; | |||
lws_sul_schedule( | |||
vhd->context, | |||
@@ -329,7 +298,7 @@ IZ_ProcedureResult IZ_WSClientOnOpen(struct lws* wsi, IZ_WSClientSessionData* ps | |||
); | |||
IZ_App* app = (IZ_App*) vhd->app; | |||
app->client.ws.connection = wsi; | |||
app->net_state.ws.connection = wsi; | |||
pss->ring = lws_ring_create(sizeof(IZ_WebsocketMessage), RING_COUNT,IZ_WebsocketDestroyMessage); | |||
if (!pss->ring) { | |||
return -1; | |||
@@ -345,7 +314,7 @@ void IZ_WSClientOnClose(struct lws* wsi) { | |||
); | |||
IZ_App* app = (IZ_App*) vhd->app; | |||
app->client.ws.connection = NULL; | |||
app->net_state.ws.connection = NULL; | |||
vhd->client_wsi = NULL; | |||
lws_sul_schedule( | |||
vhd->context, | |||
@@ -7,6 +7,7 @@ | |||
#include "output/IZ_video.h" | |||
#include "memory/IZ_pool.h" | |||
#include "net/svc/IZ_wsclient.h" | |||
#include "net/IZ_net.h" | |||
typedef enum { | |||
IZ_APP_RUN_RESULT_OK, | |||
@@ -22,9 +23,8 @@ typedef struct { | |||
IZ_VideoState video_state; | |||
IZ_Pool pool; | |||
IZ_WSClientState client; | |||
SDL_Thread* client_thread; | |||
u64 ticks; | |||
IZ_NetState net_state; | |||
} IZ_App; | |||
typedef struct { | |||
@@ -0,0 +1,134 @@ | |||
#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.interval = ini_getl("Network", "Interval", IZ_NET_DEFAULT_STATE.config.interval, config_path); | |||
} | |||
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", "Interval", state->config.interval, config_path)) { | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
void IZ_NetOverrideConfig(IZ_NetState* state, u8 argc, const char* argv[]) { | |||
const char* cmdline_buffer; | |||
if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, "-i"))) { | |||
state->config.interval = atoi(cmdline_buffer); | |||
} | |||
} | |||
IZ_ProcedureResult IZ_NetInitialize( | |||
IZ_NetState* state, | |||
void* user_data, | |||
void* callback, | |||
const char* config_path, | |||
u8 argc, | |||
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); | |||
if (!user_data) { | |||
return -2; | |||
} | |||
state->ws.user_data = user_data; | |||
state->callback = callback; | |||
u8 player_index; | |||
for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { | |||
state->action[player_index] = 0; | |||
} | |||
return 0; | |||
} | |||
void IZ_NetConnect(IZ_NetState* state, IZ_WSClientInitializeParams params) { | |||
if (IZ_NetIsConnected(state)) { | |||
return; | |||
} | |||
if (!state->callback) { | |||
return; | |||
} | |||
state->params = params; | |||
state->client_thread = SDL_CreateThread(state->callback, "networking", state->ws.user_data); | |||
SDL_DetachThread(state->client_thread); | |||
} | |||
void IZ_NetDisconnect(IZ_NetState* state) { | |||
if (!IZ_NetIsConnected(state)) { | |||
return; | |||
} | |||
IZ_WSClientCancelService(&state->ws); | |||
} | |||
bool IZ_NetIsConnected(IZ_NetState* state) { | |||
if (state->ws.interrupted) { | |||
return false; | |||
} | |||
if (!state->ws.context) { | |||
return false; | |||
} | |||
if (!state->ws.connection) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
void IZ_NetSendBinaryMessage(IZ_NetState* state, void* in, size_t len) { | |||
if (!IZ_NetIsConnected(state)) { | |||
return; | |||
} | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(state->ws.connection), | |||
lws_get_protocol(state->ws.connection) | |||
); | |||
IZ_WebsocketMessage amsg; | |||
i32 result; | |||
result = IZ_WebsocketCreateBinaryMessage(state->ws.connection, &amsg, in, len); | |||
if (result < 0) { | |||
return; | |||
} | |||
lws_ring_insert(vhd->ring, &amsg, 1); | |||
lws_callback_on_writable(state->ws.connection); | |||
} | |||
void IZ_NetSendTextMessage(IZ_NetState* state, char* in, size_t len) { | |||
if (!IZ_NetIsConnected(state)) { | |||
return; | |||
} | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(state->ws.connection), | |||
lws_get_protocol(state->ws.connection) | |||
); | |||
IZ_WebsocketMessage amsg; | |||
i32 result; | |||
result = IZ_WebsocketCreateTextMessage(state->ws.connection, &amsg, in, len); | |||
if (result < 0) { | |||
return; | |||
} | |||
lws_ring_insert(vhd->ring, &amsg, 1); | |||
lws_callback_on_writable(state->ws.connection); | |||
} |
@@ -0,0 +1,61 @@ | |||
#ifndef IZ_NET_H | |||
#define IZ_NET_H | |||
#include <minIni.h> | |||
#include <SDL_thread.h> | |||
#include "../IZ_common.h" | |||
#include "../IZ_config.h" | |||
#include "../input/IZ_action.h" | |||
#include "core/IZ_websocket.h" | |||
#include "svc/IZ_wsclient.h" | |||
typedef struct { | |||
u16 interval; | |||
char username[32]; | |||
} IZ_NetConfig; | |||
typedef struct { | |||
SDL_Thread* client_thread; | |||
IZ_NetConfig config; | |||
IZ_Websocket ws; | |||
IZ_WSClientInitializeParams params; | |||
void* callback; | |||
IZ_Action action[IZ_PLAYERS]; | |||
} IZ_NetState; | |||
static IZ_NetState IZ_NET_DEFAULT_STATE = { | |||
.client_thread = NULL, | |||
.config = { | |||
.interval = 200, | |||
.username = "Player", | |||
}, | |||
.ws = { | |||
.interrupted = false, | |||
.context = NULL, | |||
.connection = NULL, | |||
.user_data = NULL, | |||
}, | |||
.params = { | |||
.port = 42069, | |||
.path = "/", | |||
.host = "localhost", | |||
}, | |||
.callback = NULL, | |||
.action = {}, | |||
}; | |||
IZ_ProcedureResult IZ_NetInitialize(IZ_NetState*, void*, void*, const char*, u8, const char**); | |||
void IZ_NetConnect(IZ_NetState*, IZ_WSClientInitializeParams); | |||
void IZ_NetDisconnect(IZ_NetState*); | |||
IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState*, const char*); | |||
void IZ_NetSendBinaryMessage(IZ_NetState*, void*, size_t); | |||
void IZ_NetSendTextMessage(IZ_NetState*, char*, size_t); | |||
bool IZ_NetIsConnected(IZ_NetState*); | |||
#endif |
@@ -2,6 +2,7 @@ | |||
void IZ_WebsocketInitialize(IZ_Websocket* ws) { | |||
ws->context = NULL; | |||
ws->connection = NULL; | |||
ws->interrupted = false; | |||
} | |||
@@ -11,6 +12,7 @@ IZ_ProcedureResult IZ_WebsocketHandle(IZ_Websocket* ws) { | |||
void IZ_WebsocketCancelService(IZ_Websocket* ws) { | |||
ws->interrupted = true; | |||
ws->connection = NULL; | |||
lws_cancel_service(ws->context); | |||
} | |||
@@ -33,7 +33,7 @@ IZ_ProcedureResult IZ_WSClientCallback( | |||
return lws_callback_http_dummy(wsi, reason, user, in, len); | |||
} | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_Websocket* state, IZ_WSClientInitializeParams params) { | |||
struct lws_context_creation_info info; | |||
memset(&info, 0, sizeof info); | |||
info.port = CONTEXT_PORT_NO_LISTEN; | |||
@@ -58,7 +58,7 @@ IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
"address", /* pvo name */ | |||
"localhost" /* pvo value */ | |||
}; | |||
pvo_address.value = state->params.address; | |||
pvo_address.value = params.host; | |||
static struct lws_protocol_vhost_options pvo_path = { | |||
&pvo_address, | |||
@@ -66,7 +66,7 @@ IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
"path", /* pvo name */ | |||
"/" /* pvo value */ | |||
}; | |||
pvo_path.value = state->params.path; | |||
pvo_path.value = params.path; | |||
static struct lws_protocol_vhost_options pvo_port = { | |||
&pvo_path, | |||
@@ -74,7 +74,7 @@ IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
"port", /* pvo name */ | |||
NULL /* pvo value */ | |||
}; | |||
pvo_port.value = (void*) &state->params.port; | |||
pvo_port.value = (void*) ¶ms.port; | |||
static struct lws_protocol_vhost_options pvo_app = { | |||
&pvo_port, | |||
@@ -82,7 +82,7 @@ IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
"app", | |||
NULL, | |||
}; | |||
pvo_app.value = state->userdata; | |||
pvo_app.value = state->user_data; | |||
static const struct lws_protocol_vhost_options pvo = { | |||
NULL, /* "next" pvo linked-list */ | |||
@@ -93,22 +93,22 @@ IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state) { | |||
info.pvo = &pvo; | |||
info.fd_limit_per_thread = 1 + 1 + 1; | |||
IZ_WebsocketInitialize(&state->ws); | |||
state->ws.context = lws_create_context(&info); | |||
if (!state->ws.context) { | |||
IZ_WebsocketInitialize(state); | |||
state->context = lws_create_context(&info); | |||
if (!state->context) { | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClientState* state) { | |||
return IZ_WebsocketHandle(&state->ws); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_Websocket* state) { | |||
return IZ_WebsocketHandle(state); | |||
} | |||
void IZ_WSClientTeardown(IZ_WSClientState* state) { | |||
IZ_WebsocketTeardown(&state->ws); | |||
void IZ_WSClientTeardown(IZ_Websocket* state) { | |||
IZ_WebsocketTeardown(state); | |||
} | |||
void IZ_WSClientCancelService(IZ_WSClientState* state) { | |||
IZ_WebsocketCancelService(&state->ws); | |||
void IZ_WSClientCancelService(IZ_Websocket* state) { | |||
IZ_WebsocketCancelService(state); | |||
} |
@@ -1,7 +1,6 @@ | |||
#ifndef IZ_WSCLIENT_H | |||
#define IZ_WSCLIENT_H | |||
#include "libwebsockets.h" | |||
#include "../../IZ_common.h" | |||
#include "../core/IZ_websocket.h" | |||
@@ -31,24 +30,18 @@ typedef struct { | |||
} IZ_WSClientSessionData; | |||
typedef struct { | |||
const char* address; | |||
const char* host; | |||
const char* path; | |||
u16 port; | |||
} IZ_WSClientInitializeParams; | |||
typedef struct { | |||
IZ_Websocket ws; | |||
void* userdata; | |||
IZ_WSClientInitializeParams params; | |||
} IZ_WSClientState; | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState*); | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_Websocket*, IZ_WSClientInitializeParams); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClientState*); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_Websocket*); | |||
void IZ_WSClientTeardown(IZ_WSClientState*); | |||
void IZ_WSClientTeardown(IZ_Websocket*); | |||
void IZ_WSClientCancelService(IZ_WSClientState*); | |||
void IZ_WSClientCancelService(IZ_Websocket*); | |||
IZ_ProcedureResult IZ_WSClientProtocolInitialize(struct lws*, void*); | |||
@@ -3,10 +3,10 @@ | |||
void IZ_NetLoadConfig(IZ_NetState* state, const char* config_path) { | |||
char buffer[128]; | |||
ini_gets("Network", "Name", IZ_APP_NAME, buffer, 128, config_path); | |||
ini_gets("Network", "Name", IZ_NET_DEFAULT_STATE.config.name, buffer, 128, config_path); | |||
memcpy_s(state->config.name, 64, buffer, 64); | |||
ini_gets("Network", "Motd", "", buffer, 128, config_path); | |||
ini_gets("Network", "Motd", IZ_NET_DEFAULT_STATE.config.motd, buffer, 128, config_path); | |||
memcpy_s(state->config.motd, 128, buffer, 128); | |||
state->config.port = ini_getl("Network", "Port", IZ_NET_DEFAULT_STATE.config.port, config_path); | |||
@@ -62,3 +62,4 @@ IZ_ProcedureResult IZ_NetInitialize( | |||
state->ws.user_data = user_data; | |||
return 0; | |||
} | |||
@@ -6,6 +6,9 @@ | |||
#include "../IZ_config.h" | |||
#include "core/IZ_websocket.h" | |||
#define IZ_DEFAULT_MOTD "" | |||
typedef struct { | |||
u16 port; | |||
char name[64]; | |||
@@ -15,13 +18,14 @@ typedef struct { | |||
typedef struct { | |||
IZ_NetConfig config; | |||
IZ_Websocket ws; | |||
// TODO add message queue | |||
} IZ_NetState; | |||
static IZ_NetState IZ_NET_DEFAULT_STATE = { | |||
.config = { | |||
.port = 42069, | |||
.name = IZ_APP_NAME, | |||
.motd = "", | |||
.name = IZ_APP_NAME " Server", | |||
.motd = IZ_DEFAULT_MOTD, | |||
}, | |||
.ws = { | |||
.interrupted = false, | |||
@@ -2,10 +2,8 @@ | |||
#define IZ_WSSERVER_H | |||
#include <sys/stat.h> | |||
#include "libwebsockets.h" | |||
#include <string.h> | |||
#include "../../IZ_common.h" | |||
#include "../../IZ_config.h" | |||
#include "../core/IZ_websocket.h" | |||
#ifndef S_ISDIR | |||