From 4391fa7b33179fbbceffd04581035c4d373ff596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Mon, 21 Aug 2023 12:32:46 +0200 Subject: [PATCH] netsync improvements --- demos/99-dung.c | 176 +++++++++++++++++++++++++++++++++++++ demos/99-syncdemo.c | 4 +- engine/joint/v4k.h | 79 +++++++++++------ engine/split/v4k_netsync.c | 70 ++++++++++----- engine/split/v4k_netsync.h | 9 +- engine/v4k.c | 70 ++++++++++----- engine/v4k.h | 9 +- 7 files changed, 338 insertions(+), 79 deletions(-) create mode 100644 demos/99-dung.c diff --git a/demos/99-dung.c b/demos/99-dung.c new file mode 100644 index 0000000..b07e7e8 --- /dev/null +++ b/demos/99-dung.c @@ -0,0 +1,176 @@ +#include "v4k.h" + +#define WS 32 + +enum { + WALL=2, DOOR=4 +}; + +typedef struct { + int16_t id:8; + int16_t flags:8; +} cell_t; + +#define cell_t(...) C_CAST(cell_t, __VA_ARGS__) + +typedef struct { + cell_t grid[WS*WS]; + mesh_t level; +} world_t; + +static world_t world; + +void world_init() { + int i, j; + for (i = 0; i < WS; ++i) { + for (j = 0; j < WS; ++j) { + if (i == 0 || i == WS-1 || j == 0 || j == WS-1) { + // Border cells + world.grid[i*WS + j] = cell_t(0, WALL); + } else { + // Interior cells + world.grid[i*WS + j] = cell_t(rand()%3, 0); + } + } + } + + world.level = mesh(); + + + const int cube_vertices = 24; + const int cube_triangles = 12; + const int vertex_count = WS * WS * cube_vertices; + const int index_count = WS * WS * cube_triangles * 3; + + struct vert { + vec3 pos; + vec3 normal; + }; + + struct vert verts[vertex_count]; + + unsigned index_data[index_count]; + + int vertex_index = 0; + int index_index = 0; + + static vec3 normals[6] = { + {1, 0, 0}, {-1, 0, 0}, + {0, 1, 0}, {0, -1, 0}, + {0, 0, 1}, {0, 0, -1} + }; + + for(int z = 0; z < WS; ++z) { + for(int x = 0; x < WS; ++x) { + if(world.grid[z*WS + x].id >= 0) { + for(int face = 0; face < 6; ++face) { + for(int i = 0; i < 4; ++i) { + + vertex_index++; + } + } + + // Create 12 triangles for the cube + static unsigned indices[12][3] = { + {0, 1, 2}, {2, 1, 3}, {4, 5, 6}, {6, 5, 7}, + {0, 4, 1}, {1, 4, 5}, {2, 6, 3}, {3, 6, 7}, + {0, 2, 4}, {4, 2, 6}, {1, 3, 5}, {5, 3, 7} + }; + for(int i = 0; i < 12; ++i) { + for(int j = 0; j < 3; ++j) { + index_data[index_index++] = vertex_index - 24 + indices[i][j]; + } + } + } + } + } + + mesh_update(&world.level, "p3 n3", sizeof(struct vert), vertex_count, verts, index_count, index_data, 0); +} + +void draw_world() { + static mat44 M; do_once id44(M); + static mat44 VP; multiply44x2(VP, camera_get_active()->proj, camera_get_active()->view); + + static const char *vs = + "#version 130\n" + "//" FILELINE "\n" + "uniform mat4 M,VP;\n" + "in vec3 att_position;\n" + "in vec3 att_normal;\n" + "out vec3 v_normal;\n" + "void main() {\n" + " v_normal = normalize(att_position);\n" + " gl_Position = M * VP * vec4( att_position, 1.0 );\n" + "}\n"; + static const char *fs = + "#version 130\n" + "//" FILELINE "\n" + "in vec3 v_normal;\n" + "out vec4 fragcolor;\n" + "void main() {\n" + "fragcolor = vec4(v_normal, 1.0);\n" // diffuse + "}"; + + static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor"); + shader_bind(program); + shader_mat44("VP", VP); + shader_mat44("M", M); + + mesh_render(&world.level); +} + + +int main() { + window_create(80, WINDOW_MSAA8); + window_title(__FILE__); + + // init world + world_init(); + + // load all fx files + fx_load("fx**.fs"); + + // load skybox + skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0); // --mie for rayleigh/mie scattering + + // camera + camera_t cam = camera(); + cam.speed = 0.2f; + + // audio (both clips & streams) + // audio_t SFX1 = audio_clip( "coin.wav" ); + // audio_t SFX2 = audio_clip( "pew.sfxr" ); + // audio_t BGM1 = audio_stream( "waterworld-map.fur"); // wrath_of_the_djinn.xm" ); + // audio_t BGM2 = audio_stream( "larry.mid" ); + // audio_t BGM3 = audio_stream( "monkey1.mid" ), BGM = BGM1; + // audio_play(SFX1, 0); + // audio_play(BGM1, 0); + + while (window_swap()) { + // input + if( input_down(KEY_ESC) ) break; + if( input_down(KEY_F5) ) window_reload(); + if( input_down(KEY_W) && input_held(KEY_LCTRL) ) break; + if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 ); + if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png"); + if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4"); + + // fps camera + bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); + if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f); + vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); + vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed); + camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z); + camera_fps(&cam, mouse.x,mouse.y); + window_cursor( !active ); + + fx_begin(); + skybox_render(&sky, cam.proj, cam.view); + + draw_world(); + fx_end(); + } + + return 0; +} diff --git a/demos/99-syncdemo.c b/demos/99-syncdemo.c index 57d8781..b48cf09 100644 --- a/demos/99-syncdemo.c +++ b/demos/99-syncdemo.c @@ -34,7 +34,7 @@ void bind_netbuffers(int64_t self_id) { for (int64_t i=0; iclient rpc @@ -56,6 +56,8 @@ int main() { window_create( 0.35f, WINDOW_MSAA8|WINDOW_SQUARE ); struct player_t *self = &world.player[self_id]; + network_put(NETWORK_SEND_MS, 33); // 0.033 s + // game loop while( window_swap() && !input(KEY_ESC) ) { // network sync diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 4997003..2a981f5 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -15921,17 +15921,18 @@ enum { MAX_CLIENTS = 32 }; API void network_create(const char *ip, const char *port, unsigned flags); // both ip and port can be null //enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes -//enum { NETWORK_UNRELIABLE, NETWORK_UNORDERED, NETWORK_PRIORITY }; // how //enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when //enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much //enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; -API void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank); // configures a shared/networked buffer +enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ }; +API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY }; enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE }; +enum { NETWORK_SEND_MS = 4 }; //enum { NETWORK_USERID, NETWORK_SALT, NETWORK_COUNT/*N users*/ /*...*/, API int64_t network_get(uint64_t key); API int64_t network_put(uint64_t key, int64_t value); @@ -15945,7 +15946,9 @@ API void network_rpc_send(unsigned id, const char *cmdline); API bool server_bind(int max_clients, int port); API void server_poll(); +API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags); API void server_broadcast_bin(const void *ptr, int len); +API void server_broadcast_flags(const char *msg, uint64_t flags); API void server_broadcast(const char *msg); API void server_terminate(); API void server_send(int64_t handle, const char *msg); @@ -15953,7 +15956,9 @@ API void server_send_bin(int64_t handle, const void *ptr, int len); API void server_drop(int64_t handle); API int64_t client_join(const char *ip, int port); +#define client_send_flags(msg,flags) server_broadcast(msg, flags) #define client_send(msg) server_broadcast(msg) +#define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags) #define client_send_bin(ptr,len) server_broadcast_bin(ptr, len) #define client_terminate() server_terminate() @@ -338447,10 +338452,12 @@ typedef struct rpc_call { uint64_t function_hash; } rpc_call; -#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) // printf("%llx\n, HASH_STR("int(int,int,int)")); -#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) // printf("%llx\n, HASH_STR("int(int,int)")); -#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) // printf("%llx\n, HASH_STR("char*(char*)")); -#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) // printf("%llx\n, HASH_STR("char*(void)")); +#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) +#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) +#define RPC_SIGNATURE_i_s UINT64_C(0xf7b73162829ed667) +#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) +#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) +#define RPC_SIGNATURE_v_s UINT64_C(0xc1746990ab73ed24) static rpc_call rpc_new_call(const char *signature, rpc_function function) { @@ -338497,10 +338504,12 @@ char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]) rpc_call *found = map_find(rpc_calls, (char*)method); if( found ) { switch(found->function_hash) { - case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); - case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); + case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_s: return va("%d %d", id, (int)(intptr_t)found->function(args[0]) ); case RPC_SIGNATURE_s_s: return va("%d %s", id, (char*)found->function(args[0]) ); case RPC_SIGNATURE_s_v: return va("%d %s", id, (char*)found->function() ); + case RPC_SIGNATURE_v_s: return va("%d", id), found->function(args[0]); default: break; } } @@ -338718,11 +338727,19 @@ void client_poll() { } } +void server_broadcast_bin_flags(const void *msg, int len, uint64_t flags) { + ENetPacket *packet = enet_packet_create(msg, len, flags&NETWORK_UNRELIABLE ? ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT : ENET_PACKET_FLAG_RELIABLE | flags&(NETWORK_UNRELIABLE|NETWORK_UNORDERED) ? ENET_PACKET_FLAG_UNSEQUENCED : 0); + enet_host_broadcast(Server, 0, packet); +} + void server_broadcast_bin(const void *msg, int len) { ENetPacket *packet = enet_packet_create(msg, len, ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(Server, 0, packet); //enet_host_flush(Server); // flush if needed } +void server_broadcast_flags(const char *msg, uint64_t flags) { + server_broadcast_bin_flags(msg, strlen(msg)+1, flags); +} void server_broadcast(const char *msg) { server_broadcast_bin(msg, strlen(msg)+1); } @@ -338820,12 +338837,15 @@ typedef struct netbuffer_t { int64_t owner; void *ptr; unsigned sz; - unsigned flags; + uint64_t flags; } netbuffer_t; static array(char*) events; // @todo: make event 128 bytes max? static array(int64_t) values; // @todo: map instead? static map( int64_t, array(netbuffer_t) ) buffers; // map> +static double msg_send_cooldown = 0.0; +static double network_dt = 0.0; +static double last_netsync = 0.0; void network_create(const char *ip, const char *port_, unsigned flags) { if (buffers) map_clear(buffers); @@ -338895,7 +338915,7 @@ int64_t network_get(uint64_t key) { return found ? *found : 0; } -void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank) { +void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank) { assert(flags); array(netbuffer_t) *found = map_find_or_add(buffers, rank, NULL); @@ -338916,26 +338936,33 @@ char** network_sync(unsigned timeout_ms) { bool is_server = whoami == 0; bool is_client = !is_server; if(timeout_ms < 2) timeout_ms = 2; - // sleep_ms(timeout_ms); // @fixme. server only? + + network_dt = time_ss() - last_netsync; + last_netsync = time_ss(); // Split buffers into clients @todo // clients need to do this before network polling; servers should do this after polling. - map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { - for(int i = 0, end = array_count(list); i < end; ++i) { - netbuffer_t *nb = &list[i]; - if (!is_server && !(nb->flags & NETWORK_SEND)) - continue; - static array(char) encapsulate; - array_resize(encapsulate, nb->sz + 28); - uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; - uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; - uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; - uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; - uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; - // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); - memcpy(&encapsulate[28], nb->ptr, nb->sz); - server_broadcast_bin(&encapsulate[0], nb->sz + 28); + if (msg_send_cooldown <= 0.0) { + map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { + for(int i = 0, end = array_count(list); i < end; ++i) { + netbuffer_t *nb = &list[i]; + if (!is_server && !(nb->flags & NETWORK_SEND)) + continue; + static array(char) encapsulate; + array_resize(encapsulate, nb->sz + 28); + uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; + uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; + uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; + uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; + uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; + // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); + memcpy(&encapsulate[28], nb->ptr, nb->sz); + server_broadcast_bin(&encapsulate[0], nb->sz + 28); + } } + msg_send_cooldown = (double)network_get(NETWORK_SEND_MS)/1000.0; + } else { + msg_send_cooldown -= network_dt; } // network poll diff --git a/engine/split/v4k_netsync.c b/engine/split/v4k_netsync.c index fc40cd7..913ef28 100644 --- a/engine/split/v4k_netsync.c +++ b/engine/split/v4k_netsync.c @@ -6,10 +6,12 @@ typedef struct rpc_call { uint64_t function_hash; } rpc_call; -#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) // printf("%llx\n, HASH_STR("int(int,int,int)")); -#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) // printf("%llx\n, HASH_STR("int(int,int)")); -#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) // printf("%llx\n, HASH_STR("char*(char*)")); -#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) // printf("%llx\n, HASH_STR("char*(void)")); +#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) +#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) +#define RPC_SIGNATURE_i_s UINT64_C(0xf7b73162829ed667) +#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) +#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) +#define RPC_SIGNATURE_v_s UINT64_C(0xc1746990ab73ed24) static rpc_call rpc_new_call(const char *signature, rpc_function function) { @@ -56,10 +58,12 @@ char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]) rpc_call *found = map_find(rpc_calls, (char*)method); if( found ) { switch(found->function_hash) { - case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); - case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); + case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_s: return va("%d %d", id, (int)(intptr_t)found->function(args[0]) ); case RPC_SIGNATURE_s_s: return va("%d %s", id, (char*)found->function(args[0]) ); case RPC_SIGNATURE_s_v: return va("%d %s", id, (char*)found->function() ); + case RPC_SIGNATURE_v_s: return va("%d", id), found->function(args[0]); default: break; } } @@ -277,11 +281,19 @@ void client_poll() { } } +void server_broadcast_bin_flags(const void *msg, int len, uint64_t flags) { + ENetPacket *packet = enet_packet_create(msg, len, flags&NETWORK_UNRELIABLE ? ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT : ENET_PACKET_FLAG_RELIABLE | flags&(NETWORK_UNRELIABLE|NETWORK_UNORDERED) ? ENET_PACKET_FLAG_UNSEQUENCED : 0); + enet_host_broadcast(Server, 0, packet); +} + void server_broadcast_bin(const void *msg, int len) { ENetPacket *packet = enet_packet_create(msg, len, ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(Server, 0, packet); //enet_host_flush(Server); // flush if needed } +void server_broadcast_flags(const char *msg, uint64_t flags) { + server_broadcast_bin_flags(msg, strlen(msg)+1, flags); +} void server_broadcast(const char *msg) { server_broadcast_bin(msg, strlen(msg)+1); } @@ -379,12 +391,15 @@ typedef struct netbuffer_t { int64_t owner; void *ptr; unsigned sz; - unsigned flags; + uint64_t flags; } netbuffer_t; static array(char*) events; // @todo: make event 128 bytes max? static array(int64_t) values; // @todo: map instead? static map( int64_t, array(netbuffer_t) ) buffers; // map> +static double msg_send_cooldown = 0.0; +static double network_dt = 0.0; +static double last_netsync = 0.0; void network_create(const char *ip, const char *port_, unsigned flags) { if (buffers) map_clear(buffers); @@ -454,7 +469,7 @@ int64_t network_get(uint64_t key) { return found ? *found : 0; } -void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank) { +void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank) { assert(flags); array(netbuffer_t) *found = map_find_or_add(buffers, rank, NULL); @@ -475,26 +490,33 @@ char** network_sync(unsigned timeout_ms) { bool is_server = whoami == 0; bool is_client = !is_server; if(timeout_ms < 2) timeout_ms = 2; - // sleep_ms(timeout_ms); // @fixme. server only? + + network_dt = time_ss() - last_netsync; + last_netsync = time_ss(); // Split buffers into clients @todo // clients need to do this before network polling; servers should do this after polling. - map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { - for(int i = 0, end = array_count(list); i < end; ++i) { - netbuffer_t *nb = &list[i]; - if (!is_server && !(nb->flags & NETWORK_SEND)) - continue; - static array(char) encapsulate; - array_resize(encapsulate, nb->sz + 28); - uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; - uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; - uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; - uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; - uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; - // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); - memcpy(&encapsulate[28], nb->ptr, nb->sz); - server_broadcast_bin(&encapsulate[0], nb->sz + 28); + if (msg_send_cooldown <= 0.0) { + map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { + for(int i = 0, end = array_count(list); i < end; ++i) { + netbuffer_t *nb = &list[i]; + if (!is_server && !(nb->flags & NETWORK_SEND)) + continue; + static array(char) encapsulate; + array_resize(encapsulate, nb->sz + 28); + uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; + uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; + uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; + uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; + uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; + // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); + memcpy(&encapsulate[28], nb->ptr, nb->sz); + server_broadcast_bin(&encapsulate[0], nb->sz + 28); + } } + msg_send_cooldown = (double)network_get(NETWORK_SEND_MS)/1000.0; + } else { + msg_send_cooldown -= network_dt; } // network poll diff --git a/engine/split/v4k_netsync.h b/engine/split/v4k_netsync.h index 44d5e9c..95beb0f 100644 --- a/engine/split/v4k_netsync.h +++ b/engine/split/v4k_netsync.h @@ -18,17 +18,18 @@ enum { MAX_CLIENTS = 32 }; API void network_create(const char *ip, const char *port, unsigned flags); // both ip and port can be null //enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes -//enum { NETWORK_UNRELIABLE, NETWORK_UNORDERED, NETWORK_PRIORITY }; // how //enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when //enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much //enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; -API void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank); // configures a shared/networked buffer +enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ }; +API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY }; enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE }; +enum { NETWORK_SEND_MS = 4 }; //enum { NETWORK_USERID, NETWORK_SALT, NETWORK_COUNT/*N users*/ /*...*/, API int64_t network_get(uint64_t key); API int64_t network_put(uint64_t key, int64_t value); @@ -42,7 +43,9 @@ API void network_rpc_send(unsigned id, const char *cmdline); API bool server_bind(int max_clients, int port); API void server_poll(); +API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags); API void server_broadcast_bin(const void *ptr, int len); +API void server_broadcast_flags(const char *msg, uint64_t flags); API void server_broadcast(const char *msg); API void server_terminate(); API void server_send(int64_t handle, const char *msg); @@ -50,7 +53,9 @@ API void server_send_bin(int64_t handle, const void *ptr, int len); API void server_drop(int64_t handle); API int64_t client_join(const char *ip, int port); +#define client_send_flags(msg,flags) server_broadcast(msg, flags) #define client_send(msg) server_broadcast(msg) +#define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags) #define client_send_bin(ptr,len) server_broadcast_bin(ptr, len) #define client_terminate() server_terminate() diff --git a/engine/v4k.c b/engine/v4k.c index a88dab6..b9685dc 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -9483,10 +9483,12 @@ typedef struct rpc_call { uint64_t function_hash; } rpc_call; -#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) // printf("%llx\n, HASH_STR("int(int,int,int)")); -#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) // printf("%llx\n, HASH_STR("int(int,int)")); -#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) // printf("%llx\n, HASH_STR("char*(char*)")); -#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) // printf("%llx\n, HASH_STR("char*(void)")); +#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) +#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) +#define RPC_SIGNATURE_i_s UINT64_C(0xf7b73162829ed667) +#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) +#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) +#define RPC_SIGNATURE_v_s UINT64_C(0xc1746990ab73ed24) static rpc_call rpc_new_call(const char *signature, rpc_function function) { @@ -9533,10 +9535,12 @@ char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]) rpc_call *found = map_find(rpc_calls, (char*)method); if( found ) { switch(found->function_hash) { - case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); - case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) ); + case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(intptr_t)found->function(atoi(args[0]), atoi(args[1])) ); + case RPC_SIGNATURE_i_s: return va("%d %d", id, (int)(intptr_t)found->function(args[0]) ); case RPC_SIGNATURE_s_s: return va("%d %s", id, (char*)found->function(args[0]) ); case RPC_SIGNATURE_s_v: return va("%d %s", id, (char*)found->function() ); + case RPC_SIGNATURE_v_s: return va("%d", id), found->function(args[0]); default: break; } } @@ -9754,11 +9758,19 @@ void client_poll() { } } +void server_broadcast_bin_flags(const void *msg, int len, uint64_t flags) { + ENetPacket *packet = enet_packet_create(msg, len, flags&NETWORK_UNRELIABLE ? ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT : ENET_PACKET_FLAG_RELIABLE | flags&(NETWORK_UNRELIABLE|NETWORK_UNORDERED) ? ENET_PACKET_FLAG_UNSEQUENCED : 0); + enet_host_broadcast(Server, 0, packet); +} + void server_broadcast_bin(const void *msg, int len) { ENetPacket *packet = enet_packet_create(msg, len, ENET_PACKET_FLAG_RELIABLE); enet_host_broadcast(Server, 0, packet); //enet_host_flush(Server); // flush if needed } +void server_broadcast_flags(const char *msg, uint64_t flags) { + server_broadcast_bin_flags(msg, strlen(msg)+1, flags); +} void server_broadcast(const char *msg) { server_broadcast_bin(msg, strlen(msg)+1); } @@ -9856,12 +9868,15 @@ typedef struct netbuffer_t { int64_t owner; void *ptr; unsigned sz; - unsigned flags; + uint64_t flags; } netbuffer_t; static array(char*) events; // @todo: make event 128 bytes max? static array(int64_t) values; // @todo: map instead? static map( int64_t, array(netbuffer_t) ) buffers; // map> +static double msg_send_cooldown = 0.0; +static double network_dt = 0.0; +static double last_netsync = 0.0; void network_create(const char *ip, const char *port_, unsigned flags) { if (buffers) map_clear(buffers); @@ -9931,7 +9946,7 @@ int64_t network_get(uint64_t key) { return found ? *found : 0; } -void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank) { +void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank) { assert(flags); array(netbuffer_t) *found = map_find_or_add(buffers, rank, NULL); @@ -9952,26 +9967,33 @@ char** network_sync(unsigned timeout_ms) { bool is_server = whoami == 0; bool is_client = !is_server; if(timeout_ms < 2) timeout_ms = 2; - // sleep_ms(timeout_ms); // @fixme. server only? + + network_dt = time_ss() - last_netsync; + last_netsync = time_ss(); // Split buffers into clients @todo // clients need to do this before network polling; servers should do this after polling. - map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { - for(int i = 0, end = array_count(list); i < end; ++i) { - netbuffer_t *nb = &list[i]; - if (!is_server && !(nb->flags & NETWORK_SEND)) - continue; - static array(char) encapsulate; - array_resize(encapsulate, nb->sz + 28); - uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; - uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; - uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; - uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; - uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; - // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); - memcpy(&encapsulate[28], nb->ptr, nb->sz); - server_broadcast_bin(&encapsulate[0], nb->sz + 28); + if (msg_send_cooldown <= 0.0) { + map_foreach(buffers, int64_t, rank, array(netbuffer_t), list) { + for(int i = 0, end = array_count(list); i < end; ++i) { + netbuffer_t *nb = &list[i]; + if (!is_server && !(nb->flags & NETWORK_SEND)) + continue; + static array(char) encapsulate; + array_resize(encapsulate, nb->sz + 28); + uint32_t *mid = (uint32_t*)&encapsulate[0]; *mid = MSG_BUF; + uint64_t *st = (uint64_t*)&encapsulate[4]; *st = nb->flags; + uint32_t *idx = (uint32_t*)&encapsulate[12]; *idx = i; + uint32_t *len = (uint32_t*)&encapsulate[16]; *len = nb->sz; + uint64_t *who = (uint64_t*)&encapsulate[20]; *who = nb->owner; + // PRINTF("sending %llx %u %lld %u\n", *st, *idx, *who, *len); + memcpy(&encapsulate[28], nb->ptr, nb->sz); + server_broadcast_bin(&encapsulate[0], nb->sz + 28); + } } + msg_send_cooldown = (double)network_get(NETWORK_SEND_MS)/1000.0; + } else { + msg_send_cooldown -= network_dt; } // network poll diff --git a/engine/v4k.h b/engine/v4k.h index 51615d2..c63443b 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -2004,17 +2004,18 @@ enum { MAX_CLIENTS = 32 }; API void network_create(const char *ip, const char *port, unsigned flags); // both ip and port can be null //enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes -//enum { NETWORK_UNRELIABLE, NETWORK_UNORDERED, NETWORK_PRIORITY }; // how //enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when //enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much //enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; -API void* network_buffer(void *ptr, unsigned sz, unsigned flags, int64_t rank); // configures a shared/networked buffer +enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ }; +API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY }; enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE }; +enum { NETWORK_SEND_MS = 4 }; //enum { NETWORK_USERID, NETWORK_SALT, NETWORK_COUNT/*N users*/ /*...*/, API int64_t network_get(uint64_t key); API int64_t network_put(uint64_t key, int64_t value); @@ -2028,7 +2029,9 @@ API void network_rpc_send(unsigned id, const char *cmdline); API bool server_bind(int max_clients, int port); API void server_poll(); +API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags); API void server_broadcast_bin(const void *ptr, int len); +API void server_broadcast_flags(const char *msg, uint64_t flags); API void server_broadcast(const char *msg); API void server_terminate(); API void server_send(int64_t handle, const char *msg); @@ -2036,7 +2039,9 @@ API void server_send_bin(int64_t handle, const void *ptr, int len); API void server_drop(int64_t handle); API int64_t client_join(const char *ip, int port); +#define client_send_flags(msg,flags) server_broadcast(msg, flags) #define client_send(msg) server_broadcast(msg) +#define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags) #define client_send_bin(ptr,len) server_broadcast_bin(ptr, len) #define client_terminate() server_terminate()