Explorar el Código

Refactor project

Split the network events to the net directory to keep the app code
implementation clean.
feature/data-structs
TheoryOfNekomata hace 2 años
padre
commit
fec7105c03
Se han modificado 7 ficheros con 484 adiciones y 380 borrados
  1. +1
    -1
      CMakeLists.txt
  2. +128
    -260
      src/packages/game/IZ_app.c
  3. +4
    -43
      src/packages/game/IZ_app.h
  4. +284
    -0
      src/packages/game/net/IZ_app.c
  5. +60
    -0
      src/packages/game/net/IZ_app.h
  6. +2
    -74
      src/packages/game/output/IZ_video.c
  7. +5
    -2
      src/packages/game/output/IZ_video.h

+ 1
- 1
CMakeLists.txt Ver fichero

@@ -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)
src/packages/game/net/IZ_net.c src/packages/game/net/IZ_net.h src/packages/game/net/IZ_app.c src/packages/game/net/IZ_app.h)

target_link_libraries(
game


+ 128
- 260
src/packages/game/IZ_app.c Ver fichero

@@ -1,29 +1,23 @@
#include "IZ_app.h"

IZ_ProcedureResult IZ_AppConnect(void* app_raw) {
IZ_App* app = app_raw;
if (IZ_WSClientInitialize(&app->net_state.ws, app->net_state.params)) {
return -1;
}
u64 IZ_AppGetTicks(struct IZ_App* app) {
return app->ticks;
}

i32 result = 0;
while (true) {
if (IZ_WSClientHandle(&app->net_state.ws)) {
result = -1;
break;
}
void IZ_AppBindConnection(struct IZ_App* app, struct lws* wsi) {
app->net_state.ws.connection = wsi;
}

if (app->net_state.ws.interrupted) {
break;
}
}
IZ_NetState* IZ_AppGetNetState(struct IZ_App* app) {
return &app->net_state;
}

IZ_WSClientTeardown(&app->net_state.ws);
return result;
IZ_InputState* IZ_AppGetInputState(struct IZ_App* app) {
return &app->input_state;
}

IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) {
memset(app, 0, sizeof(IZ_App));
IZ_ProcedureResult IZ_AppInitialize(struct IZ_App* app, u8 argc, const char* argv[]) {
memset(app, 0, sizeof(struct IZ_App));
u32 flags = (
SDL_INIT_VIDEO
| SDL_INIT_GAMECONTROLLER
@@ -44,7 +38,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) {
IZ_ConfigGetDefaultPath(config_path, 128);
}

if (IZ_VideoInitialize(&app->video_state, config_path, argc, argv)) {
if (IZ_VideoInitialize(&app->video_state, app, config_path, argc, argv)) {
return IZ_APP_RUN_VIDEO_INIT_ERROR;
}

@@ -63,7 +57,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) {
return IZ_APP_RUN_RESULT_OK;
}

void IZ_AppTeardown(IZ_App* app) {
void IZ_AppTeardown(struct IZ_App* app) {
IZ_NetDisconnect(&app->net_state);
IZ_PoolTeardown(&app->pool);
IZ_InputTeardown(&app->input_state);
@@ -71,7 +65,7 @@ void IZ_AppTeardown(IZ_App* app) {
SDL_Quit();
}

IZ_ProcedureResult IZ_AppHandleSDLEvents(IZ_App* app) {
IZ_ProcedureResult IZ_AppHandleSDLEvents(struct IZ_App* app) {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
@@ -100,7 +94,7 @@ IZ_ProcedureResult IZ_AppHandleSDLEvents(IZ_App* app) {
return 0;
}

void IZ_AppHandlePortMIDIEvents(IZ_App* app) {
void IZ_AppHandlePortMIDIEvents(struct IZ_App* app) {
u8 player_index;
i32* midi_events_count;
u32 midi_event_index;
@@ -130,21 +124,7 @@ void IZ_AppHandlePortMIDIEvents(IZ_App* app) {
}
}

void IZ_AppHandleNetworkingInboundBinaryEvents(IZ_App* app, void* binary_raw, size_t len) {
u8* binary = binary_raw;
size_t i;
printf("%llu: Binary", app->ticks);
for (i = 0; i < len; i += 1) {
printf("%c%02x", i == 0 ? '(' : ' ', binary[i]);
}
printf(")\n");
}

void IZ_AppHandleNetworkingInboundTextEvents(IZ_App* app, const char* text, size_t len) {
printf("%llu: String(%s)\n", app->ticks, text);
}

IZ_ProcedureResult IZ_AppHandleInputEvents(IZ_App* app) {
IZ_ProcedureResult IZ_AppHandleInputEvents(struct IZ_App* app) {
i32 sdl_events_result = IZ_AppHandleSDLEvents(app);
if (sdl_events_result) {
return sdl_events_result;
@@ -154,252 +134,140 @@ IZ_ProcedureResult IZ_AppHandleInputEvents(IZ_App* app) {
return 0;
}

IZ_ProcedureResult IZ_AppRun(IZ_App* app, u8 argc, const char* argv[]) {
IZ_ProcedureResult init_result = IZ_AppInitialize(app, argc, argv);
if (init_result) {
return init_result;
}

while (true) {
app->ticks = SDL_GetTicks64();

// TODO do audio processing
// TODO do networking

if (IZ_AppHandleInputEvents(app)) {
break;
void IZ_VideoUpdateForDebugTicks(IZ_VideoState* video_state, uint64_t ticks) {
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0xff, 0xff, 0xff);
u64 the_ticks = ticks;
u8 column;
u8 row;
const u8 size = 4;

u8 i;
for (i = 0; i < 64; i += 1) {
column = i % 32;
row = i / 32;

if (the_ticks & 0x1) {
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
(f32) (video_state->config.width - ((column + 1) * size)),
(f32) (video_state->config.height - ((row + 1) * size)),
size,
size
});
}
the_ticks >>= 1;
}
}

// 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]
);
void IZ_VideoUpdateForDebugInput(IZ_VideoState* video_state, IZ_InputState* input_state) {
SDL_SetRenderDrawColor(video_state->renderer, 0xff, 0xff, 0x00, 0xff);
const u8 size = 4;

u8 column;
u8 row;

u8 p;
u8 i;
for (p = 0; p < IZ_PLAYERS; p += 1) {
IZ_Action the_action = input_state->action[p];
for (i = 0; i < CONTROLS; i += 1) {
column = (i % 4) + (p * 4);
row = i / 4;

if (the_action & 0x1) {
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
(f32) (column * size),
(f32) (row * size),
size,
size
});
}
app->net_state.action[player_index] = app->input_state.action[player_index];
the_action >>= 1;
}

IZ_VideoUpdate(&app->video_state, app->ticks, &app->input_state);
}

IZ_AppTeardown(app);
return IZ_APP_RUN_RESULT_OK;
}

void IZ_WSClientAttemptConnect(struct lws_sorted_usec_list *sul) {
IZ_WSClientVHostData* vhd = lws_container_of(sul, IZ_WSClientVHostData, sul);

vhd->i.context = vhd->context;
vhd->i.port = *vhd->port;
vhd->i.address = vhd->address;
vhd->i.path = vhd->path;
vhd->i.host = vhd->i.address;
vhd->i.origin = vhd->i.address;
vhd->i.ssl_connection = 0;

vhd->i.protocol = NETWORK_PROTOCOL;
vhd->i.pwsi = &vhd->client_wsi;

if (lws_client_connect_via_info(&vhd->i)) {
void IZ_VideoUpdateForDebugNet(IZ_VideoState* video_state, IZ_NetState* net_state) {
if (!net_state->ws.connection) {
return;
}
const u8 size = 4;

lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
10 * LWS_US_PER_SEC
);
}

IZ_ProcedureResult IZ_WSClientProtocolInitialize(struct lws* wsi, void* in) {
const struct lws_protocols* protocols = lws_get_protocol(wsi);
struct lws_vhost* vhost = lws_get_vhost(wsi);
IZ_WSClientVHostData* vhd_instance = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(vhost,protocols);
IZ_WSClientVHostData** vhd = &vhd_instance;
*vhd = lws_protocol_vh_priv_zalloc(vhost, protocols, sizeof(IZ_WSClientVHostData));
(*vhd)->ring = lws_ring_create(
sizeof(IZ_WebsocketMessage),
RING_COUNT,
IZ_WebsocketDestroyMessage
);
if (!(*vhd)->ring) {
return -1;
}
(*vhd)->context = lws_get_context(wsi);
(*vhd)->protocol = protocols;
(*vhd)->vhost = vhost;
(*vhd)->port = (u16*) lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"port"
)->value;
(*vhd)->address = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"address"
)->value;
(*vhd)->path = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"path"
)->value;
(*vhd)->app = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"app"
)->value;
IZ_WSClientAttemptConnect(&(*vhd)->sul);
return 0;
}

void IZ_WSClientProtocolTeardown(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);

if (vhd->ring) {
lws_ring_destroy(vhd->ring);
}

lws_sul_cancel(&vhd->sul);
}

void IZ_WSClientConnectionError(struct lws* wsi, void* in) {
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)");
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
IZ_App* app = (IZ_App*) vhd->app;
app->net_state.ws.connection = NULL;
vhd->client_wsi = NULL;
lws_sul_schedule(
vhd->context,
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0xff, 0x00, 0xff);
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
LWS_US_PER_SEC
);
}

IZ_ProcedureResult IZ_WSClientOnOpen(struct lws* wsi, IZ_WSClientSessionData* pss) {
pss->ring = lws_ring_create(sizeof(IZ_WebsocketMessage), RING_COUNT,IZ_WebsocketDestroyMessage);
if (!pss->ring) {
return -1;
(f32) (video_state->config.height - size),
size,
size,
});

u8 column;
u8 row;

u8 p;
u8 i;
for (p = 0; p < IZ_PLAYERS; p += 1) {
IZ_Action the_action = net_state->action[p];
for (i = 0; i < CONTROLS; i += 1) {
column = (i % 4) + (p * 4);
row = i / 4;

if (the_action & 0x1) {
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
(f32) (column * size),
(f32) ((row * size) + (video_state->config.height - (size * 5))),
size,
size
});
}
the_action >>= 1;
}
}

IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
IZ_App* app = (IZ_App*) vhd->app;
app->net_state.ws.connection = wsi;
pss->tail = 0;
return 0;
}

void IZ_WSClientOnClose(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
IZ_App* app = (IZ_App*) vhd->app;
app->net_state.ws.connection = NULL;
vhd->client_wsi = NULL;
lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
LWS_US_PER_SEC
);
void IZ_VideoUpdateForDebug(IZ_VideoState* video_state, u64 ticks, IZ_InputState* input_state, IZ_NetState* net_state) {
IZ_VideoUpdateForDebugTicks(video_state, ticks);
IZ_VideoUpdateForDebugInput(video_state, input_state);
IZ_VideoUpdateForDebugNet(video_state, net_state);
}

IZ_ProcedureResult IZ_WSClientWritable(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);

const IZ_WebsocketMessage* pmsg = lws_ring_get_element(vhd->ring, &vhd->tail);
if (!pmsg) {
return 0;
}

/* notice we allowed for LWS_PRE in the payload already */
i32 m = lws_write(
wsi,
((unsigned char*) pmsg->payload) + LWS_PRE,
pmsg->len,
pmsg->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT
);

if (m < (i32)pmsg->len) {
lwsl_err("ERROR %d writing to ws socket\n", m);
return -1;
}

lws_ring_consume_single_tail(vhd->ring, &vhd->tail, 1);

/* more to do for us? */
if (lws_ring_get_element(vhd->ring, &vhd->tail)) {
/* come back as soon as we can write more */
lws_callback_on_writable(wsi);
void IZ_VideoUpdate(IZ_VideoState* video_state) {
struct IZ_App* app = video_state->user_data;
if (app->ticks - video_state->last_update_at > 1000 / video_state->config.max_fps) {
// Update window
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0x00, 0x00, 0xff);
SDL_RenderClear(video_state->renderer);
for (u8 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) {
if (!video_state->active_sprites[i]) {
continue;
}
// TODO draw sprites
}
IZ_VideoUpdateForDebug(video_state, app->ticks, &app->input_state, &app->net_state);
SDL_RenderPresent(video_state->renderer);
video_state->last_update_at = app->ticks;
}

return 0;
}

void IZ_WSClientOnReceive(struct lws* wsi, IZ_WSClientSessionData* pss, void* in, size_t len) {
i32 n = (i32) lws_ring_get_count_free_elements(pss->ring);
if (!n) {
lwsl_user("dropping!\n");
return;
IZ_ProcedureResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) {
IZ_ProcedureResult init_result = IZ_AppInitialize(app, argc, argv);
if (init_result) {
return init_result;
}

lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: %4d (rpp %5d, first %d, last %d, bin %d)\n",
(int)len, (int)lws_remaining_packet_payload(wsi),
lws_is_first_fragment(wsi),
lws_is_final_fragment(wsi),
lws_frame_is_binary(wsi));

// lwsl_hexdump_notice(in, len);

IZ_WebsocketMessage amsg;
i32 result = (
lws_frame_is_binary(wsi)
? IZ_WebsocketCreateBinaryMessage(wsi, &amsg, in, len)
: IZ_WebsocketCreateTextMessage(wsi, &amsg, in, len)
);
if (result < 0) {
lwsl_user("OOM: dropping\n");
return;
}
while (true) {
app->ticks = SDL_GetTicks64();

IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
// TODO do audio processing
// TODO do networking

IZ_App* app = (IZ_App*) vhd->app;
if (amsg.binary) {
IZ_AppHandleNetworkingInboundBinaryEvents(app, in, len);
} else {
IZ_AppHandleNetworkingInboundTextEvents(app, in, len);
}
if (IZ_AppHandleInputEvents(app)) {
break;
}

if (!lws_ring_insert(pss->ring, &amsg, 1)) {
IZ_WebsocketDestroyMessage(&amsg);
lwsl_user("dropping!\n");
return;
IZ_AppHandleOutboundNetworking(app);
IZ_VideoUpdate(&app->video_state);
}
lws_callback_on_writable(wsi);

if (!pss->flow_controlled && n < 3) {
pss->flow_controlled = true;
lws_rx_flow_control(wsi, 0);
}
IZ_AppTeardown(app);
return IZ_APP_RUN_RESULT_OK;
}

+ 4
- 43
src/packages/game/IZ_app.h Ver fichero

@@ -6,8 +6,7 @@
#include "input/IZ_input.h"
#include "output/IZ_video.h"
#include "memory/IZ_pool.h"
#include "net/svc/IZ_wsclient.h"
#include "net/IZ_net.h"
#include "net/IZ_app.h"

typedef enum {
IZ_APP_RUN_RESULT_OK,
@@ -18,7 +17,7 @@ typedef enum {
IZ_APP_RUN_NETWORKING_ERROR,
} IZ_AppRunResult;

typedef struct {
typedef struct IZ_App {
IZ_InputState input_state;
IZ_VideoState video_state;
IZ_Pool pool;
@@ -27,46 +26,8 @@ typedef struct {
IZ_NetState net_state;
} IZ_App;

typedef struct {
u8 player_index: 3;
u8 player_state: 5;
u16 action_set;
} IZ_AppPlayerActionSyncMessage;
IZ_ProcedureResult IZ_AppRun(struct IZ_App*, u8, const char**);

typedef struct {
u8 player_index: 3;
f32 x;
f32 y;
f32 right;
f32 up;
} IZ_AppPlayerState;

typedef enum {
IZ_MESSAGE_KIND_ACTION_SYNC = 0,
IZ_MESSAGE_KIND_STATE_SYNC = 1,
} IZ_MessageKind;

typedef struct {
u8 message_kind; // player
u64 client_elapsed_time; // for synchronization
} IZ_AppMessageHeader;

typedef struct {
u8 player_actions_count;
IZ_AppPlayerActionSyncMessage player_actions[];
} IZ_AppPlayerActionSection;

typedef struct {
IZ_AppMessageHeader header;
IZ_AppPlayerActionSection player_actions;
} IZ_AppActionSyncMessage;

typedef struct {
IZ_AppMessageHeader header;
IZ_AppPlayerState player_state[IZ_PLAYERS];
IZ_AppPlayerActionSection player_actions;
} IZ_AppStateSyncMessage;

IZ_ProcedureResult IZ_AppRun(IZ_App*, u8, const char**);
IZ_ProcedureResult IZ_AppConnect(void*);

#endif

+ 284
- 0
src/packages/game/net/IZ_app.c Ver fichero

@@ -0,0 +1,284 @@
#include "IZ_app.h"

void IZ_AppHandleNetworkingInboundBinaryEvents(struct IZ_App* app, void* binary_raw, size_t len) {
u8* binary = binary_raw;
size_t i;
printf("%llu: Binary", IZ_AppGetTicks(app));
for (i = 0; i < len; i += 1) {
printf("%c%02x", i == 0 ? '(' : ' ', binary[i]);
}
printf(")\n");
}

void IZ_AppHandleNetworkingInboundTextEvents(struct IZ_App* app, const char* text, size_t len) {
printf("%llu: String(%s)\n", IZ_AppGetTicks(app), text);
}

void IZ_AppHandleOutboundNetworking(struct IZ_App* app) {
// TODO implement queueing of messages
IZ_NetState* net_state = IZ_AppGetNetState(app);
IZ_InputState* input_state = IZ_AppGetInputState(app);

u8 player_index;
for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
if (net_state->action[player_index] != input_state->action[player_index]) {
u8 player_actions_count = 1;
IZ_AppActionSyncMessage* msg = SDL_malloc(
sizeof(IZ_AppMessageHeader)
+ sizeof(u8)
+ (sizeof(IZ_AppPlayerActionSyncMessage) * player_actions_count)
);
msg->header.client_elapsed_time = IZ_AppGetTicks(app);
msg->header.message_kind = IZ_MESSAGE_KIND_ACTION_SYNC;
msg->action.player_actions_count = player_actions_count;
msg->action.player[0].index = player_index;
msg->action.player[0].value = input_state->action[player_index];
msg->action.player[0].state = 0;
IZ_NetSendBinaryMessage(
net_state,
msg,
sizeof(*msg)
);
SDL_free(msg);
}
net_state->action[player_index] = input_state->action[player_index];
}
}

void IZ_WSClientAttemptConnect(struct lws_sorted_usec_list *sul) {
IZ_WSClientVHostData* vhd = lws_container_of(sul, IZ_WSClientVHostData, sul);

vhd->i.context = vhd->context;
vhd->i.port = *vhd->port;
vhd->i.address = vhd->address;
vhd->i.path = vhd->path;
vhd->i.host = vhd->i.address;
vhd->i.origin = vhd->i.address;
vhd->i.ssl_connection = 0;

vhd->i.protocol = NETWORK_PROTOCOL;
vhd->i.pwsi = &vhd->client_wsi;

if (lws_client_connect_via_info(&vhd->i)) {
return;
}

lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
10 * LWS_US_PER_SEC
);
}

IZ_ProcedureResult IZ_WSClientProtocolInitialize(struct lws* wsi, void* in) {
const struct lws_protocols* protocols = lws_get_protocol(wsi);
struct lws_vhost* vhost = lws_get_vhost(wsi);
IZ_WSClientVHostData* vhd_instance = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(vhost,protocols);
IZ_WSClientVHostData** vhd = &vhd_instance;
*vhd = lws_protocol_vh_priv_zalloc(vhost, protocols, sizeof(IZ_WSClientVHostData));
(*vhd)->ring = lws_ring_create(
sizeof(IZ_WebsocketMessage),
RING_COUNT,
IZ_WebsocketDestroyMessage
);
if (!(*vhd)->ring) {
return -1;
}
(*vhd)->context = lws_get_context(wsi);
(*vhd)->protocol = protocols;
(*vhd)->vhost = vhost;
(*vhd)->port = (u16*) lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"port"
)->value;
(*vhd)->address = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"address"
)->value;
(*vhd)->path = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"path"
)->value;
(*vhd)->app = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"app"
)->value;
IZ_WSClientAttemptConnect(&(*vhd)->sul);
return 0;
}

void IZ_WSClientProtocolTeardown(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);

if (vhd->ring) {
lws_ring_destroy(vhd->ring);
}

lws_sul_cancel(&vhd->sul);
}

void IZ_WSClientConnectionError(struct lws* wsi, void* in) {
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)");
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_AppBindConnection(app, NULL);
vhd->client_wsi = NULL;
lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
LWS_US_PER_SEC
);
}

IZ_ProcedureResult IZ_WSClientOnOpen(struct lws* wsi, IZ_WSClientSessionData* pss) {
pss->ring = lws_ring_create(sizeof(IZ_WebsocketMessage), RING_COUNT,IZ_WebsocketDestroyMessage);
if (!pss->ring) {
return -1;
}

IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_AppBindConnection(app, wsi);
pss->tail = 0;
return 0;
}

void IZ_WSClientOnClose(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);
struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_AppBindConnection(app, NULL);
vhd->client_wsi = NULL;
lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
LWS_US_PER_SEC
);
}

IZ_ProcedureResult IZ_WSClientWritable(struct lws* wsi) {
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);

const IZ_WebsocketMessage* pmsg = lws_ring_get_element(vhd->ring, &vhd->tail);
if (!pmsg) {
return 0;
}

/* notice we allowed for LWS_PRE in the payload already */
i32 m = lws_write(
wsi,
((unsigned char*) pmsg->payload) + LWS_PRE,
pmsg->len,
pmsg->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT
);

if (m < (i32)pmsg->len) {
lwsl_err("ERROR %d writing to ws socket\n", m);
return -1;
}

lws_ring_consume_single_tail(vhd->ring, &vhd->tail, 1);

/* more to do for us? */
if (lws_ring_get_element(vhd->ring, &vhd->tail)) {
/* come back as soon as we can write more */
lws_callback_on_writable(wsi);
}

return 0;
}

void IZ_WSClientOnReceive(struct lws* wsi, IZ_WSClientSessionData* pss, void* in, size_t len) {
i32 n = (i32) lws_ring_get_count_free_elements(pss->ring);
if (!n) {
lwsl_user("dropping!\n");
return;
}

lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: %4d (rpp %5d, first %d, last %d, bin %d)\n",
(int)len, (int)lws_remaining_packet_payload(wsi),
lws_is_first_fragment(wsi),
lws_is_final_fragment(wsi),
lws_frame_is_binary(wsi));

// lwsl_hexdump_notice(in, len);

IZ_WebsocketMessage amsg;
i32 result = (
lws_frame_is_binary(wsi)
? IZ_WebsocketCreateBinaryMessage(wsi, &amsg, in, len)
: IZ_WebsocketCreateTextMessage(wsi, &amsg, in, len)
);
if (result < 0) {
lwsl_user("OOM: dropping\n");
return;
}

IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get(
lws_get_vhost(wsi),
lws_get_protocol(wsi)
);

struct IZ_App* app = (struct IZ_App*) vhd->app;
if (amsg.binary) {
IZ_AppHandleNetworkingInboundBinaryEvents(app, in, len);
} else {
IZ_AppHandleNetworkingInboundTextEvents(app, in, len);
}

if (!lws_ring_insert(pss->ring, &amsg, 1)) {
IZ_WebsocketDestroyMessage(&amsg);
lwsl_user("dropping!\n");
return;
}
lws_callback_on_writable(wsi);

if (!pss->flow_controlled && n < 3) {
pss->flow_controlled = true;
lws_rx_flow_control(wsi, 0);
}
}

IZ_ProcedureResult IZ_AppConnect(void* app_raw) {
struct IZ_App* app = app_raw;
IZ_NetState* net_state = IZ_AppGetNetState(app);

if (IZ_WSClientInitialize(&net_state->ws, net_state->params)) {
return -1;
}

i32 result = 0;
while (true) {
if (IZ_WSClientHandle(&net_state->ws)) {
result = -1;
break;
}

if (net_state->ws.interrupted) {
break;
}
}

IZ_WSClientTeardown(&net_state->ws);
return result;
}

+ 60
- 0
src/packages/game/net/IZ_app.h Ver fichero

@@ -0,0 +1,60 @@
#ifndef IZ_NET_APP_H
#define IZ_NET_APP_H

#include "../IZ_common.h"
#include "../input/IZ_input.h"
#include "IZ_net.h"

typedef enum {
IZ_MESSAGE_KIND_ACTION_SYNC = 0,
IZ_MESSAGE_KIND_STATE_SYNC = 1,
} IZ_MessageKind;

typedef struct {
u8 index: 3;
u8 state: 5;
u16 value;
} IZ_AppPlayerActionSyncMessage;

typedef struct {
u8 player_index: 3;
f32 x;
f32 y;
f32 right;
f32 up;
} IZ_AppPlayerState;

typedef struct {
u8 message_kind; // player
u64 client_elapsed_time; // for synchronization
} IZ_AppMessageHeader;

typedef struct {
u8 player_actions_count;
IZ_AppPlayerActionSyncMessage player[];
} IZ_AppPlayerActionSection;

typedef struct {
IZ_AppMessageHeader header;
IZ_AppPlayerActionSection action;
} IZ_AppActionSyncMessage;

typedef struct {
IZ_AppMessageHeader header;
IZ_AppPlayerState player_state[IZ_PLAYERS];
IZ_AppPlayerActionSection player_actions;
} IZ_AppStateSyncMessage;

struct IZ_App;

u64 IZ_AppGetTicks(struct IZ_App*);

void IZ_AppBindConnection(struct IZ_App*, struct lws*);

IZ_NetState* IZ_AppGetNetState(struct IZ_App*);

IZ_InputState* IZ_AppGetInputState(struct IZ_App*);

void IZ_AppHandleOutboundNetworking(struct IZ_App*);

#endif

+ 2
- 74
src/packages/game/output/IZ_video.c Ver fichero

@@ -27,7 +27,7 @@ void IZ_VideoOverrideConfig(IZ_VideoState* state, u8 argc, const char* argv[]) {
}
}

IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_path, u8 argc, const char* argv[]) {
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_VideoLoadConfig(state, config_path);
@@ -36,6 +36,7 @@ IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_p
}
IZ_VideoOverrideConfig(state, argc, argv);
state->last_update_at = 0u;
state->user_data = user_data;

SDL_Window* window = SDL_CreateWindow(
IZ_APP_NAME,
@@ -55,79 +56,6 @@ IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_p
return 0;
}

void IZ_VideoUpdateForDebugTicks(IZ_VideoState* video_state, uint64_t ticks) {
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0xff, 0xff, 0xff);
u64 the_ticks = ticks;
u8 column;
u8 row;
const u8 size = 4;

u8 i;
for (i = 0; i < 64; i += 1) {
column = i % 32;
row = i / 32;

if (the_ticks & 0x1) {
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
(f32) (video_state->config.width - ((column + 1) * size)),
(f32) (video_state->config.height - ((row + 1) * size)),
size,
size
});
}
the_ticks >>= 1;
}
}

void IZ_VideoUpdateForDebugInput(IZ_VideoState* video_state, IZ_InputState* input_state) {
SDL_SetRenderDrawColor(video_state->renderer, 0xff, 0xff, 0x00, 0xff);
u8 column;
u8 row;
const u8 size = 4;

u8 p;
u8 i;
for (p = 0; p < IZ_PLAYERS; p += 1) {
IZ_Action the_action = input_state->action[p];
for (i = 0; i < CONTROLS; i += 1) {
column = (i % 4) + (p * 4);
row = i / 4;

if (the_action & 0x1) {
SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
(f32) (column * size),
(f32) (row * size),
size,
size
});
}
the_action >>= 1;
}
}
}

void IZ_VideoUpdateForDebug(IZ_VideoState* video_state, IZ_InputState* input_state, u64 ticks) {
IZ_VideoUpdateForDebugTicks(video_state, ticks);
IZ_VideoUpdateForDebugInput(video_state, input_state);
}

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) {
// Update window
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0x00, 0x00, 0xff);
SDL_RenderClear(video_state->renderer);
for (u8 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) {
if (!video_state->active_sprites[i]) {
continue;
}
// TODO draw sprites
}
IZ_VideoUpdateForDebug(video_state, input_state, ticks);
SDL_RenderPresent(video_state->renderer);
video_state->last_update_at = ticks;
}
}

void IZ_VideoTeardown(IZ_VideoState* state) {
SDL_DestroyWindow(state->window);
}

+ 5
- 2
src/packages/game/output/IZ_video.h Ver fichero

@@ -6,6 +6,7 @@
#include <SDL_render.h>

#include "../input/IZ_input.h"
#include "../net/IZ_net.h"
#include "../IZ_common.h"
#include "../IZ_config.h"

@@ -21,6 +22,7 @@ typedef struct {
} IZ_VideoConfig;

typedef struct {
void* user_data;
IZ_VideoConfig config;
u64 last_update_at;
SDL_Window* window;
@@ -29,6 +31,7 @@ typedef struct {
} IZ_VideoState;

static const IZ_VideoState IZ_DEFAULT_VIDEO_STATE = {
.user_data = NULL,
.config = {
.width = 320u,
.height = 240u,
@@ -40,11 +43,11 @@ static const IZ_VideoState IZ_DEFAULT_VIDEO_STATE = {
.active_sprites = {},
};

IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, const char*, u8, const char**);
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, void*, const char*, u8, const char**);

IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState*, const char*);

void IZ_VideoUpdate(IZ_VideoState*, u64, IZ_InputState*);
void IZ_VideoUpdate(IZ_VideoState*);

void IZ_VideoTeardown(IZ_VideoState*);



Cargando…
Cancelar
Guardar