Browse Source

Implement sending events

Implement the sending of input events to the websocket server.
feature/data-structs
TheoryOfNekomata 2 years ago
parent
commit
a345474f03
11 changed files with 263 additions and 101 deletions
  1. +1
    -1
      CMakeLists.txt
  2. +35
    -66
      src/packages/game/IZ_app.c
  3. +2
    -2
      src/packages/game/IZ_app.h
  4. +134
    -0
      src/packages/game/net/IZ_net.c
  5. +61
    -0
      src/packages/game/net/IZ_net.h
  6. +2
    -0
      src/packages/game/net/core/IZ_websocket.c
  7. +14
    -14
      src/packages/game/net/svc/IZ_wsclient.c
  8. +5
    -12
      src/packages/game/net/svc/IZ_wsclient.h
  9. +3
    -2
      src/packages/server/net/IZ_net.c
  10. +6
    -2
      src/packages/server/net/IZ_net.h
  11. +0
    -2
      src/packages/server/net/svc/IZ_wsserver.h

+ 1
- 1
CMakeLists.txt View File

@@ -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


+ 35
- 66
src/packages/game/IZ_app.c View File

@@ -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,


+ 2
- 2
src/packages/game/IZ_app.h View File

@@ -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 {


+ 134
- 0
src/packages/game/net/IZ_net.c View File

@@ -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);
}

+ 61
- 0
src/packages/game/net/IZ_net.h View File

@@ -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
- 0
src/packages/game/net/core/IZ_websocket.c View File

@@ -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);
}



+ 14
- 14
src/packages/game/net/svc/IZ_wsclient.c View File

@@ -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*) &params.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);
}

+ 5
- 12
src/packages/game/net/svc/IZ_wsclient.h View File

@@ -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
- 2
src/packages/server/net/IZ_net.c View File

@@ -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
- 2
src/packages/server/net/IZ_net.h View File

@@ -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,


+ 0
- 2
src/packages/server/net/svc/IZ_wsserver.h View File

@@ -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


Loading…
Cancel
Save