#include "IZ_net_client.h" bool IZ_NetClientIsValidPacketIntervalMs(long packet_interval_ms) { return (100 <= packet_interval_ms && packet_interval_ms <= 500); } bool IZ_NetClientIsValidMaxReconnectRetries(long max_reconnect_retries) { return (0 <= max_reconnect_retries && max_reconnect_retries <= 8); } bool IZ_NetClientIsValidReconnectIntervalSeconds(long reconnect_interval_secs) { return (3 <= reconnect_interval_secs && reconnect_interval_secs <= 10); } static IZ_ConfigItem net_config_items[] = { { IZ_CONFIG_TYPE_STRING, 32, "Network", "Username", NULL, &IZ_NET_CLIENT_DEFAULT_STATE.config.username, NULL }, { IZ_CONFIG_TYPE_U16, sizeof(u16), "Network", "PacketIntervalMs", "-i", &IZ_NET_CLIENT_DEFAULT_STATE.config.packet_interval_ms, IZ_NetClientIsValidPacketIntervalMs, }, { IZ_CONFIG_TYPE_U8, sizeof(u8), "Network", "MaxReconnectRetries", NULL, &IZ_NET_CLIENT_DEFAULT_STATE.config.max_reconnect_retries, IZ_NetClientIsValidMaxReconnectRetries, }, { IZ_CONFIG_TYPE_U8, sizeof(u8), "Network", "ReconnectIntervalSeconds", NULL, &IZ_NET_CLIENT_DEFAULT_STATE.config.reconnect_interval_secs, IZ_NetClientIsValidReconnectIntervalSeconds, }, }; void IZ_NetClientBindStateToConfig(IZ_NetClientState* state, IZ_ConfigItem config_items[]) { config_items[0].dest = &state->config.username; config_items[1].dest = &state->config.packet_interval_ms; config_items[2].dest = &state->config.max_reconnect_retries; config_items[3].dest = &state->config.reconnect_interval_secs; } IZ_ProcedureResult IZ_NetClientSaveConfig(IZ_NetClientState* state, const char* config_path) { IZ_NetClientBindStateToConfig(state, net_config_items); return IZ_ConfigSave(net_config_items, config_path); } IZ_ProcedureResult IZ_NetClientInitialize( IZ_NetClientState* state, void* user_data, void* callback, const char* config_path, u8 argc, const char* argv[] ) { memcpy_s(state, sizeof(IZ_NetClientState), &IZ_NET_CLIENT_DEFAULT_STATE, sizeof(IZ_NetClientState)); IZ_NetClientBindStateToConfig(state, net_config_items); IZ_ConfigInit(net_config_items, config_path, argc, argv); if (!user_data) { return -2; } state->binding.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; } return 0; } void IZ_NetClientConnect(IZ_NetClientState* state, IZ_WSClientInitializeParams params) { if (!state->callback) { return; } if (state->status == IZ_NET_CLIENT_STATUS_CONNECTED) { return; } if (state->status == IZ_NET_CLIENT_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->binding.user_data); SDL_DetachThread(state->client_thread); } void IZ_NetClientDisconnect(IZ_NetClientState* state) { if (state->status == IZ_NET_CLIENT_STATUS_PRISTINE) { return; } if (state->binding.connection) { IZ_WSClientVHostData *vhd = (IZ_WSClientVHostData *) lws_protocol_vh_priv_get( lws_get_vhost(state->binding.connection), lws_get_protocol(state->binding.connection) ); if (vhd) { lws_sul_cancel(&vhd->sul); } } state->retries = state->config.max_reconnect_retries; IZ_WSClientCancelService(&state->binding); } void IZ_NetClientSendBinaryMessage(IZ_NetClientState* state, void* in, size_t len) { if (state->status != IZ_NET_CLIENT_STATUS_CONNECTED) { return; } IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( lws_get_vhost(state->binding.connection), lws_get_protocol(state->binding.connection) ); IZ_WebsocketMessage amsg; i32 result; result = IZ_WebsocketCreateBinaryMessage(state->binding.connection, &amsg, in, len); if (result < 0) { return; } lws_ring_insert(vhd->ring, &amsg, 1); lws_callback_on_writable(state->binding.connection); } void IZ_NetClientSendTextMessage(IZ_NetClientState* state, char* in, size_t len) { if (state->status != IZ_NET_CLIENT_STATUS_CONNECTED) { return; } IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( lws_get_vhost(state->binding.connection), lws_get_protocol(state->binding.connection) ); IZ_WebsocketMessage amsg; i32 result; result = IZ_WebsocketCreateTextMessage(state->binding.connection, &amsg, in, len); if (result < 0) { return; } lws_ring_insert(vhd->ring, &amsg, 1); lws_callback_on_writable(state->binding.connection); }