浏览代码

Implement retries behavior and config

Provide the facility for the player to retry a failed connection a
certain number of times.
feature/data-structs
父节点
当前提交
1a2f4ff726
共有 6 个文件被更改,包括 120 次插入37 次删除
  1. +34
    -7
      src/packages/game/net/IZ_app.c
  2. +49
    -21
      src/packages/game/net/IZ_net.c
  3. +17
    -2
      src/packages/game/net/IZ_net.h
  4. +1
    -2
      src/packages/game/net/svc/IZ_wsclient.c
  5. +1
    -1
      src/packages/game/net/svc/IZ_wsclient.h
  6. +18
    -4
      src/packages/game/output/video/IZ_app.c

+ 34
- 7
src/packages/game/net/IZ_app.c 查看文件

@@ -59,6 +59,9 @@ void IZ_WSClientAttemptConnect(struct lws_sorted_usec_list *sul) {
vhd->i.protocol = NETWORK_PROTOCOL;
vhd->i.pwsi = &vhd->client_wsi;

struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_NetState* net_state = IZ_AppGetNetState(app);
net_state->status = IZ_NET_STATUS_CONNECTING;
if (lws_client_connect_via_info(&vhd->i)) {
return;
}
@@ -120,38 +123,60 @@ void IZ_WSClientProtocolTeardown(struct lws* wsi) {
}

lws_sul_cancel(&vhd->sul);
struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_NetState* net_state = IZ_AppGetNetState(app);
net_state->status = IZ_NET_STATUS_PRISTINE;
}

void IZ_WSClientConnectionError(struct lws* wsi, void* in) {
IZ_ProcedureResult 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)
);

if (!vhd) {
return -1;
}

struct IZ_App* app = (struct IZ_App*) vhd->app;
IZ_AppBindConnection(app, NULL);
vhd->client_wsi = NULL;
IZ_NetState* net_state = IZ_AppGetNetState(app);
if (net_state->retries == net_state->config.max_reconnect_retries) {
lwsl_err("Max number of retries reached!\n");
net_state->status = IZ_NET_STATUS_PRISTINE;
return -1;
}
net_state->status = IZ_NET_STATUS_ERROR;
net_state->retries += 1;
lws_sul_schedule(
vhd->context,
0,
&vhd->sul,
IZ_WSClientAttemptConnect,
LWS_US_PER_SEC
net_state->config.reconnect_interval_secs * LWS_US_PER_SEC
);

return 0;
}

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_NetState* net_state = IZ_AppGetNetState(app);
pss->ring = lws_ring_create(sizeof(IZ_WebsocketMessage), RING_COUNT,IZ_WebsocketDestroyMessage);
if (!pss->ring) {
net_state->status = IZ_NET_STATUS_ERROR;
return -1;
}

IZ_AppBindConnection(app, wsi);
net_state->status = IZ_NET_STATUS_CONNECTED;
net_state->retries = 0;
pss->tail = 0;
return 0;
}
@@ -251,6 +276,8 @@ void IZ_WSClientOnReceive(struct lws* wsi, IZ_WSClientSessionData* pss, void* in
lwsl_user("dropping!\n");
return;
}

lws_ring_consume_single_tail(pss->ring, &pss->tail, 1);
lws_callback_on_writable(wsi);

if (!pss->flow_controlled && n < 3) {


+ 49
- 21
src/packages/game/net/IZ_net.c 查看文件

@@ -1,25 +1,25 @@
#include "IZ_net.h"

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

IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState* state, const char* config_path) {
@@ -27,7 +27,15 @@ IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState* state, const char* config_path)
return -1;
}

if (!ini_putl("Network", "Interval", state->config.interval, config_path)) {
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;
}

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

@@ -37,7 +45,7 @@ IZ_ProcedureResult IZ_NetSaveConfig(IZ_NetState* state, const char* config_path)
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);
state->config.packet_interval_ms = atoi(cmdline_buffer);
}
}

@@ -60,6 +68,7 @@ IZ_ProcedureResult IZ_NetInitialize(
}
state->ws.user_data = user_data;
state->callback = callback;
state->retries = state->config.max_reconnect_retries;
u8 player_index;
for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
state->action[player_index] = 0;
@@ -69,28 +78,47 @@ IZ_ProcedureResult IZ_NetInitialize(
}

void IZ_NetConnect(IZ_NetState* state, IZ_WSClientInitializeParams params) {
if (IZ_NetIsConnected(state)) {
if (!state->callback) {
return;
}

if (!state->callback) {
if (state->status == IZ_NET_STATUS_CONNECTED) {
return;
}

if (state->status == IZ_NET_STATUS_CONNECTING) {
return;
}

if (state->retries < state->config.max_reconnect_retries) {
return;
}

state->retries = 0;
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)) {
if (state->status == IZ_NET_STATUS_PRISTINE) {
return;
}
if (state->ws.connection) {
IZ_WSClientVHostData *vhd = (IZ_WSClientVHostData *) lws_protocol_vh_priv_get(
lws_get_vhost(state->ws.connection),
lws_get_protocol(state->ws.connection)
);
if (vhd) {
lws_sul_cancel(&vhd->sul);
}
}
state->retries = state->config.max_reconnect_retries;
IZ_WSClientCancelService(&state->ws);
}

void IZ_NetSendBinaryMessage(IZ_NetState* state, void* in, size_t len) {
if (!IZ_NetIsConnected(state)) {
if (state->status != IZ_NET_STATUS_CONNECTED) {
return;
}

@@ -112,7 +140,7 @@ void IZ_NetSendBinaryMessage(IZ_NetState* state, void* in, size_t len) {
}

void IZ_NetSendTextMessage(IZ_NetState* state, char* in, size_t len) {
if (!IZ_NetIsConnected(state)) {
if (state->status != IZ_NET_STATUS_CONNECTED) {
return;
}



+ 17
- 2
src/packages/game/net/IZ_net.h 查看文件

@@ -9,8 +9,17 @@
#include "core/IZ_websocket.h"
#include "svc/IZ_wsclient.h"

typedef enum {
IZ_NET_STATUS_PRISTINE,
IZ_NET_STATUS_CONNECTING,
IZ_NET_STATUS_ERROR,
IZ_NET_STATUS_CONNECTED,
} IZ_NetStatus;

typedef struct {
u16 interval;
u16 packet_interval_ms;
u8 max_reconnect_retries;
u8 reconnect_interval_secs;
char username[32];
} IZ_NetConfig;

@@ -21,13 +30,17 @@ typedef struct {
IZ_WSClientInitializeParams params;
void* callback;
IZ_Action action[IZ_PLAYERS];
u8 retries;
IZ_NetStatus status;
// TODO add message queue
} IZ_NetState;

static IZ_NetState IZ_NET_DEFAULT_STATE = {
.client_thread = NULL,
.config = {
.interval = 200,
.packet_interval_ms = 200,
.max_reconnect_retries = 3,
.reconnect_interval_secs = 3,
.username = "Player",
},
.ws = {
@@ -43,6 +56,8 @@ static IZ_NetState IZ_NET_DEFAULT_STATE = {
},
.callback = NULL,
.action = {},
.retries = 3,
.status = IZ_NET_STATUS_PRISTINE,
};

IZ_ProcedureResult IZ_NetInitialize(IZ_NetState*, void*, void*, const char*, u8, const char**);


+ 1
- 2
src/packages/game/net/svc/IZ_wsclient.c 查看文件

@@ -14,8 +14,7 @@ IZ_ProcedureResult IZ_WSClientCallback(
IZ_WSClientProtocolTeardown(wsi);
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
IZ_WSClientConnectionError(wsi, in);
break;
return IZ_WSClientConnectionError(wsi, in);
case LWS_CALLBACK_CLIENT_ESTABLISHED:
return IZ_WSClientOnOpen(wsi, user);
case LWS_CALLBACK_CLIENT_CLOSED:


+ 1
- 1
src/packages/game/net/svc/IZ_wsclient.h 查看文件

@@ -47,7 +47,7 @@ IZ_ProcedureResult IZ_WSClientProtocolInitialize(struct lws*, void*);

void IZ_WSClientProtocolTeardown(struct lws*);

void IZ_WSClientConnectionError(struct lws*, void*);
IZ_ProcedureResult IZ_WSClientConnectionError(struct lws*, void*);

IZ_ProcedureResult IZ_WSClientOnOpen(struct lws*, IZ_WSClientSessionData*);



+ 18
- 4
src/packages/game/output/video/IZ_app.c 查看文件

@@ -53,12 +53,22 @@ void IZ_VideoUpdateForDebugInput(IZ_VideoState* video_state, IZ_InputState* inpu
}

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

SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0xff, 0x00, 0xff);
switch (net_state->status) {
default:
return;
case IZ_NET_STATUS_ERROR:
SDL_SetRenderDrawColor(video_state->renderer, 0xff, 0x00, 0x00, 0xff);
break;
case IZ_NET_STATUS_CONNECTING:
SDL_SetRenderDrawColor(video_state->renderer, 0xff, 0xff, 0x00, 0xff);
break;
case IZ_NET_STATUS_CONNECTED:
SDL_SetRenderDrawColor(video_state->renderer, 0x00, 0xff, 0x00, 0xff);
break;
}

SDL_RenderFillRectF(video_state->renderer, &(SDL_FRect) {
0,
(f32) (video_state->config.height - size),
@@ -66,6 +76,10 @@ void IZ_VideoUpdateForDebugNet(IZ_VideoState* video_state, IZ_NetState* net_stat
size,
});

if (!net_state->ws.connection) {
return;
}

u8 column;
u8 row;



正在加载...
取消
保存