refactor separate framework from game code, add demo3d
This commit is contained in:
parent
19ae869769
commit
40f5cdcaa5
92 changed files with 2665 additions and 6547 deletions
297
demo3d/client/net/demo3d_net.c
Normal file
297
demo3d/client/net/demo3d_net.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
#include "pxl8_platform.h"
|
||||
#include "demo3d_net.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pxl8_bytes.h"
|
||||
#include "pxl8_log.h"
|
||||
#include "pxl8_mem.h"
|
||||
#include "demo3d_world.h"
|
||||
#include "demo3d_chunk_cache.h"
|
||||
|
||||
static const demo3d_entity_state* find_entity(const demo3d_entity_state* entities, u16 count, u64 id) {
|
||||
for (u16 i = 0; i < count; i++) {
|
||||
if (entities[i].entity_id == id) return &entities[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool dispatch_message(demo3d_net* ng, const u8* data, usize len) {
|
||||
if (len < sizeof(demo3d_msg_header)) return false;
|
||||
|
||||
demo3d_msg_header hdr;
|
||||
usize offset = demo3d_protocol_deserialize_header(data, len, &hdr);
|
||||
|
||||
if (hdr.type == DEMO3D_MSG_CHUNK) {
|
||||
if (!ng->chunk_cache) return false;
|
||||
demo3d_chunk_msg_header chunk_hdr;
|
||||
offset += demo3d_protocol_deserialize_chunk_msg_header(data + offset, len - offset, &chunk_hdr);
|
||||
const u8* payload = data + offset;
|
||||
usize payload_len = chunk_hdr.payload_size;
|
||||
if (payload_len > len - offset) payload_len = len - offset;
|
||||
demo3d_chunk_cache_receive(ng->chunk_cache, &chunk_hdr, payload, payload_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type == DEMO3D_MSG_CHUNK_ENTER) {
|
||||
demo3d_chunk_enter_msg chunk_msg;
|
||||
demo3d_protocol_deserialize_chunk_enter(data + offset, len - offset, &chunk_msg);
|
||||
ng->chunk_cx = chunk_msg.cx;
|
||||
ng->chunk_cz = chunk_msg.cz;
|
||||
ng->has_chunk = true;
|
||||
pxl8_debug("Received CHUNK_ENTER cx=%d cz=%d", chunk_msg.cx, chunk_msg.cz);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type == DEMO3D_MSG_CHUNK_EXIT) {
|
||||
ng->has_chunk = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type != DEMO3D_MSG_SNAPSHOT) return false;
|
||||
|
||||
demo3d_snapshot_header snap;
|
||||
offset += demo3d_protocol_deserialize_snapshot_header(data + offset, len - offset, &snap);
|
||||
if (snap.tick <= ng->highest_tick) return false;
|
||||
|
||||
memcpy(ng->prev_entities, ng->entities, sizeof(ng->entities));
|
||||
ng->prev_snapshot = ng->snapshot;
|
||||
ng->highest_tick = snap.tick;
|
||||
ng->snapshot = snap;
|
||||
ng->interp_time = 0.0f;
|
||||
|
||||
u16 count = snap.entity_count;
|
||||
if (count > DEMO3D_MAX_SNAPSHOT_ENTITIES) count = DEMO3D_MAX_SNAPSHOT_ENTITIES;
|
||||
|
||||
for (u16 i = 0; i < count; i++) {
|
||||
offset += demo3d_protocol_deserialize_entity_state(data + offset, len - offset, &ng->entities[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
demo3d_net* demo3d_net_create(const pxl8_net_config* config) {
|
||||
demo3d_net* ng = pxl8_calloc(1, sizeof(demo3d_net));
|
||||
if (!ng) return NULL;
|
||||
ng->transport = pxl8_net_create(config);
|
||||
if (!ng->transport) {
|
||||
pxl8_free(ng);
|
||||
return NULL;
|
||||
}
|
||||
return ng;
|
||||
}
|
||||
|
||||
void demo3d_net_destroy(demo3d_net* ng) {
|
||||
if (!ng) return;
|
||||
pxl8_net_destroy(ng->transport);
|
||||
pxl8_free(ng);
|
||||
}
|
||||
|
||||
pxl8_result demo3d_net_connect(demo3d_net* ng) {
|
||||
if (!ng) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
return pxl8_net_connect(ng->transport);
|
||||
}
|
||||
|
||||
bool demo3d_net_connected(const demo3d_net* ng) {
|
||||
return ng && pxl8_net_connected(ng->transport);
|
||||
}
|
||||
|
||||
void demo3d_net_disconnect(demo3d_net* ng) {
|
||||
if (!ng) return;
|
||||
pxl8_net_disconnect(ng->transport);
|
||||
}
|
||||
|
||||
const demo3d_entity_state* demo3d_net_entities(const demo3d_net* ng) {
|
||||
if (!ng) return NULL;
|
||||
return ng->entities;
|
||||
}
|
||||
|
||||
const u8* demo3d_net_entity_prev_userdata(const demo3d_net* ng, u64 entity_id) {
|
||||
if (!ng) return NULL;
|
||||
const demo3d_entity_state* e = find_entity(ng->prev_entities, ng->prev_snapshot.entity_count, entity_id);
|
||||
return e ? e->userdata : NULL;
|
||||
}
|
||||
|
||||
const u8* demo3d_net_entity_userdata(const demo3d_net* ng, u64 entity_id) {
|
||||
if (!ng) return NULL;
|
||||
const demo3d_entity_state* e = find_entity(ng->entities, ng->snapshot.entity_count, entity_id);
|
||||
return e ? e->userdata : NULL;
|
||||
}
|
||||
|
||||
const demo3d_input_msg* demo3d_net_input_at(const demo3d_net* ng, u64 tick) {
|
||||
if (!ng) return NULL;
|
||||
if (tick < ng->input_oldest_tick) return NULL;
|
||||
u64 age = tick - ng->input_oldest_tick;
|
||||
if (age >= DEMO3D_NET_INPUT_HISTORY_SIZE) return NULL;
|
||||
u64 idx = tick % DEMO3D_NET_INPUT_HISTORY_SIZE;
|
||||
const demo3d_input_msg* msg = &ng->input_history[idx];
|
||||
if (msg->tick != tick) return NULL;
|
||||
return msg;
|
||||
}
|
||||
|
||||
u64 demo3d_net_input_oldest_tick(const demo3d_net* ng) {
|
||||
if (!ng) return 0;
|
||||
return ng->input_oldest_tick;
|
||||
}
|
||||
|
||||
void demo3d_net_input_push(demo3d_net* ng, const demo3d_input_msg* input) {
|
||||
if (!ng || !input) return;
|
||||
u64 idx = input->tick % DEMO3D_NET_INPUT_HISTORY_SIZE;
|
||||
ng->input_history[idx] = *input;
|
||||
ng->input_head = input->tick;
|
||||
if (input->tick >= DEMO3D_NET_INPUT_HISTORY_SIZE) {
|
||||
ng->input_oldest_tick = input->tick - DEMO3D_NET_INPUT_HISTORY_SIZE + 1;
|
||||
}
|
||||
}
|
||||
|
||||
f32 demo3d_net_lerp_alpha(const demo3d_net* ng) {
|
||||
if (!ng) return 1.0f;
|
||||
return ng->interp_time / (1.0f / DEMO3D_NET_TICK_RATE);
|
||||
}
|
||||
|
||||
bool demo3d_net_needs_correction(const demo3d_net* ng) {
|
||||
if (!ng) return false;
|
||||
if (ng->snapshot.tick == 0) return false;
|
||||
if (ng->predicted_tick == 0) return false;
|
||||
|
||||
u64 player_id = ng->snapshot.player_id;
|
||||
const demo3d_entity_state* server = find_entity(ng->entities, ng->snapshot.entity_count, player_id);
|
||||
if (!server) return false;
|
||||
|
||||
return memcmp(server->userdata, ng->predicted_state, DEMO3D_NET_USERDATA_SIZE) != 0;
|
||||
}
|
||||
|
||||
u64 demo3d_net_player_id(const demo3d_net* ng) {
|
||||
if (!ng) return 0;
|
||||
return ng->snapshot.player_id;
|
||||
}
|
||||
|
||||
bool demo3d_net_poll(demo3d_net* ng) {
|
||||
if (!ng || !pxl8_net_connected(ng->transport)) return false;
|
||||
|
||||
u8 recv_buf[4096];
|
||||
usize len = pxl8_net_recv(ng->transport, recv_buf, sizeof(recv_buf));
|
||||
u64 prev_tick = ng->highest_tick;
|
||||
if (!dispatch_message(ng, recv_buf, len)) return false;
|
||||
|
||||
if (ng->highest_tick > prev_tick && ng->world) {
|
||||
demo3d_world_reconcile(ng->world, ng, 1.0f / 30.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u8* demo3d_net_predicted_state(demo3d_net* ng) {
|
||||
if (!ng) return NULL;
|
||||
return ng->predicted_state;
|
||||
}
|
||||
|
||||
void demo3d_net_predicted_tick_set(demo3d_net* ng, u64 tick) {
|
||||
if (!ng) return;
|
||||
ng->predicted_tick = tick;
|
||||
}
|
||||
|
||||
pxl8_result demo3d_net_send_command(demo3d_net* ng, const demo3d_command_msg* cmd) {
|
||||
if (!ng || !cmd) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
if (!pxl8_net_connected(ng->transport)) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
u8 buf[512];
|
||||
demo3d_msg_header hdr = {.type = DEMO3D_MSG_COMMAND, .version = DEMO3D_PROTOCOL_VERSION};
|
||||
usize offset = demo3d_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||
offset += demo3d_protocol_serialize_command(cmd, buf + offset, sizeof(buf) - offset);
|
||||
|
||||
return pxl8_net_send(ng->transport, buf, offset);
|
||||
}
|
||||
|
||||
pxl8_result demo3d_net_send_input(demo3d_net* ng, const demo3d_input_msg* input) {
|
||||
if (!ng || !input) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
if (!pxl8_net_connected(ng->transport)) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
demo3d_net_input_push(ng, input);
|
||||
|
||||
u8 buf[512];
|
||||
demo3d_msg_header hdr = {.type = DEMO3D_MSG_INPUT, .version = DEMO3D_PROTOCOL_VERSION};
|
||||
usize offset = demo3d_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||
offset += demo3d_protocol_serialize_input(input, buf + offset, sizeof(buf) - offset);
|
||||
|
||||
return pxl8_net_send(ng->transport, buf, offset);
|
||||
}
|
||||
|
||||
const demo3d_snapshot_header* demo3d_net_snapshot(const demo3d_net* ng) {
|
||||
if (!ng) return NULL;
|
||||
return &ng->snapshot;
|
||||
}
|
||||
|
||||
u64 demo3d_net_tick(const demo3d_net* ng) {
|
||||
if (!ng) return 0;
|
||||
return ng->snapshot.tick;
|
||||
}
|
||||
|
||||
void demo3d_net_update(demo3d_net* ng, f32 dt) {
|
||||
if (!ng) return;
|
||||
ng->interp_time += dt;
|
||||
}
|
||||
|
||||
void demo3d_net_set_chunk_cache(demo3d_net* ng, demo3d_chunk_cache* cache) {
|
||||
if (!ng) return;
|
||||
ng->chunk_cache = cache;
|
||||
}
|
||||
|
||||
demo3d_chunk_cache* demo3d_net_chunk_cache(demo3d_net* ng) {
|
||||
if (!ng) return NULL;
|
||||
return ng->chunk_cache;
|
||||
}
|
||||
|
||||
void demo3d_net_set_world(demo3d_net* ng, demo3d_world* world) {
|
||||
if (!ng) return;
|
||||
ng->world = world;
|
||||
}
|
||||
|
||||
i32 demo3d_net_chunk_cx(const demo3d_net* ng) {
|
||||
if (!ng) return 0;
|
||||
return ng->chunk_cx;
|
||||
}
|
||||
|
||||
i32 demo3d_net_chunk_cz(const demo3d_net* ng) {
|
||||
if (!ng) return 0;
|
||||
return ng->chunk_cz;
|
||||
}
|
||||
|
||||
bool demo3d_net_has_chunk(const demo3d_net* ng) {
|
||||
if (!ng) return false;
|
||||
return ng->has_chunk;
|
||||
}
|
||||
|
||||
pxl8_result demo3d_net_spawn(demo3d_net* ng, f32 x, f32 y, f32 z, f32 yaw, f32 pitch) {
|
||||
if (!ng) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
demo3d_command_msg cmd = {0};
|
||||
cmd.cmd_type = DEMO3D_CMD_SPAWN_ENTITY;
|
||||
|
||||
u8* p = cmd.payload;
|
||||
memcpy(p, &x, 4); p += 4;
|
||||
memcpy(p, &y, 4); p += 4;
|
||||
memcpy(p, &z, 4); p += 4;
|
||||
memcpy(p, &yaw, 4); p += 4;
|
||||
memcpy(p, &pitch, 4);
|
||||
cmd.payload_size = 20;
|
||||
|
||||
return demo3d_net_send_command(ng, &cmd);
|
||||
}
|
||||
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
void demo3d_net_start_thread(demo3d_net* ng) {
|
||||
if (!ng) return;
|
||||
pxl8_net_start_thread(ng->transport);
|
||||
}
|
||||
|
||||
void demo3d_net_stop_thread(demo3d_net* ng) {
|
||||
if (!ng) return;
|
||||
pxl8_net_stop_thread(ng->transport);
|
||||
}
|
||||
|
||||
bool demo3d_net_dispatch_packet(demo3d_net* ng, const pxl8_packet* pkt) {
|
||||
if (!ng || !pkt) return false;
|
||||
return dispatch_message(ng, pkt->data, pkt->len);
|
||||
}
|
||||
#endif
|
||||
74
demo3d/client/net/demo3d_net.h
Normal file
74
demo3d/client/net/demo3d_net.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "pxl8_net.h"
|
||||
#include "demo3d_protocol.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
#define DEMO3D_NET_INPUT_HISTORY_SIZE 64
|
||||
#define DEMO3D_NET_USERDATA_SIZE 56
|
||||
#define DEMO3D_NET_TICK_RATE 30.0f
|
||||
|
||||
typedef struct demo3d_world demo3d_world;
|
||||
typedef struct demo3d_chunk_cache demo3d_chunk_cache;
|
||||
|
||||
typedef struct demo3d_net {
|
||||
pxl8_net* transport;
|
||||
|
||||
demo3d_chunk_cache* chunk_cache;
|
||||
i32 chunk_cx;
|
||||
i32 chunk_cz;
|
||||
bool has_chunk;
|
||||
demo3d_world* world;
|
||||
|
||||
u64 highest_tick;
|
||||
f32 interp_time;
|
||||
|
||||
demo3d_entity_state entities[DEMO3D_MAX_SNAPSHOT_ENTITIES];
|
||||
demo3d_entity_state prev_entities[DEMO3D_MAX_SNAPSHOT_ENTITIES];
|
||||
demo3d_snapshot_header prev_snapshot;
|
||||
demo3d_snapshot_header snapshot;
|
||||
|
||||
u64 input_head;
|
||||
demo3d_input_msg input_history[DEMO3D_NET_INPUT_HISTORY_SIZE];
|
||||
u64 input_oldest_tick;
|
||||
|
||||
u8 predicted_state[DEMO3D_NET_USERDATA_SIZE];
|
||||
u64 predicted_tick;
|
||||
} demo3d_net;
|
||||
|
||||
demo3d_net* demo3d_net_create(const pxl8_net_config* config);
|
||||
void demo3d_net_destroy(demo3d_net* ng);
|
||||
pxl8_result demo3d_net_connect(demo3d_net* ng);
|
||||
bool demo3d_net_connected(const demo3d_net* ng);
|
||||
void demo3d_net_disconnect(demo3d_net* ng);
|
||||
|
||||
const demo3d_entity_state* demo3d_net_entities(const demo3d_net* ng);
|
||||
const u8* demo3d_net_entity_prev_userdata(const demo3d_net* ng, u64 entity_id);
|
||||
const u8* demo3d_net_entity_userdata(const demo3d_net* ng, u64 entity_id);
|
||||
const demo3d_input_msg* demo3d_net_input_at(const demo3d_net* ng, u64 tick);
|
||||
u64 demo3d_net_input_oldest_tick(const demo3d_net* ng);
|
||||
void demo3d_net_input_push(demo3d_net* ng, const demo3d_input_msg* input);
|
||||
f32 demo3d_net_lerp_alpha(const demo3d_net* ng);
|
||||
bool demo3d_net_needs_correction(const demo3d_net* ng);
|
||||
u64 demo3d_net_player_id(const demo3d_net* ng);
|
||||
bool demo3d_net_poll(demo3d_net* ng);
|
||||
u8* demo3d_net_predicted_state(demo3d_net* ng);
|
||||
void demo3d_net_predicted_tick_set(demo3d_net* ng, u64 tick);
|
||||
pxl8_result demo3d_net_send_command(demo3d_net* ng, const demo3d_command_msg* cmd);
|
||||
pxl8_result demo3d_net_send_input(demo3d_net* ng, const demo3d_input_msg* input);
|
||||
const demo3d_snapshot_header* demo3d_net_snapshot(const demo3d_net* ng);
|
||||
u64 demo3d_net_tick(const demo3d_net* ng);
|
||||
void demo3d_net_update(demo3d_net* ng, f32 dt);
|
||||
void demo3d_net_set_chunk_cache(demo3d_net* ng, demo3d_chunk_cache* cache);
|
||||
demo3d_chunk_cache* demo3d_net_chunk_cache(demo3d_net* ng);
|
||||
void demo3d_net_set_world(demo3d_net* ng, demo3d_world* world);
|
||||
i32 demo3d_net_chunk_cx(const demo3d_net* ng);
|
||||
i32 demo3d_net_chunk_cz(const demo3d_net* ng);
|
||||
bool demo3d_net_has_chunk(const demo3d_net* ng);
|
||||
pxl8_result demo3d_net_spawn(demo3d_net* ng, f32 x, f32 y, f32 z, f32 yaw, f32 pitch);
|
||||
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
void demo3d_net_start_thread(demo3d_net* ng);
|
||||
void demo3d_net_stop_thread(demo3d_net* ng);
|
||||
bool demo3d_net_dispatch_packet(demo3d_net* ng, const pxl8_packet* pkt);
|
||||
#endif
|
||||
197
demo3d/client/net/demo3d_protocol.c
Normal file
197
demo3d/client/net/demo3d_protocol.c
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
#include "demo3d_protocol.h"
|
||||
#include "pxl8_bytes.h"
|
||||
|
||||
usize demo3d_protocol_serialize_header(const demo3d_msg_header* msg, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_msg_header)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u32_be(&s, msg->sequence);
|
||||
pxl8_write_u16_be(&s, msg->size);
|
||||
pxl8_write_u8(&s, msg->type);
|
||||
pxl8_write_u8(&s, msg->version);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_header(const u8* buf, usize len, demo3d_msg_header* msg) {
|
||||
if (len < sizeof(demo3d_msg_header)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
msg->sequence = pxl8_read_u32_be(&s);
|
||||
msg->size = pxl8_read_u16_be(&s);
|
||||
msg->type = pxl8_read_u8(&s);
|
||||
msg->version = pxl8_read_u8(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_input(const demo3d_input_msg* msg, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_input_msg)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u32_be(&s, msg->buttons);
|
||||
pxl8_write_f32_be(&s, msg->look_dx);
|
||||
pxl8_write_f32_be(&s, msg->look_dy);
|
||||
pxl8_write_f32_be(&s, msg->move_x);
|
||||
pxl8_write_f32_be(&s, msg->move_y);
|
||||
pxl8_write_f32_be(&s, msg->yaw);
|
||||
pxl8_write_u64_be(&s, msg->tick);
|
||||
pxl8_write_u64_be(&s, msg->timestamp);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_input(const u8* buf, usize len, demo3d_input_msg* msg) {
|
||||
if (len < sizeof(demo3d_input_msg)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
msg->buttons = pxl8_read_u32_be(&s);
|
||||
msg->look_dx = pxl8_read_f32_be(&s);
|
||||
msg->look_dy = pxl8_read_f32_be(&s);
|
||||
msg->move_x = pxl8_read_f32_be(&s);
|
||||
msg->move_y = pxl8_read_f32_be(&s);
|
||||
msg->yaw = pxl8_read_f32_be(&s);
|
||||
msg->tick = pxl8_read_u64_be(&s);
|
||||
msg->timestamp = pxl8_read_u64_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_command(const demo3d_command_msg* msg, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_command_msg)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u16_be(&s, msg->cmd_type);
|
||||
pxl8_write_bytes(&s, msg->payload, DEMO3D_COMMAND_PAYLOAD_SIZE);
|
||||
pxl8_write_u16_be(&s, msg->payload_size);
|
||||
pxl8_write_u64_be(&s, msg->tick);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_command(const u8* buf, usize len, demo3d_command_msg* msg) {
|
||||
if (len < sizeof(demo3d_command_msg)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
msg->cmd_type = pxl8_read_u16_be(&s);
|
||||
pxl8_read_bytes(&s, msg->payload, DEMO3D_COMMAND_PAYLOAD_SIZE);
|
||||
msg->payload_size = pxl8_read_u16_be(&s);
|
||||
msg->tick = pxl8_read_u64_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_entity_state(const demo3d_entity_state* state, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_entity_state)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u64_be(&s, state->entity_id);
|
||||
pxl8_write_bytes(&s, state->userdata, 56);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_entity_state(const u8* buf, usize len, demo3d_entity_state* state) {
|
||||
if (len < sizeof(demo3d_entity_state)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
state->entity_id = pxl8_read_u64_be(&s);
|
||||
pxl8_read_bytes(&s, state->userdata, 56);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_event(const demo3d_event_msg* msg, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_event_msg)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u8(&s, msg->event_type);
|
||||
pxl8_write_bytes(&s, msg->payload, DEMO3D_EVENT_PAYLOAD_SIZE);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_event(const u8* buf, usize len, demo3d_event_msg* msg) {
|
||||
if (len < sizeof(demo3d_event_msg)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
msg->event_type = pxl8_read_u8(&s);
|
||||
pxl8_read_bytes(&s, msg->payload, DEMO3D_EVENT_PAYLOAD_SIZE);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_snapshot_header(const demo3d_snapshot_header* hdr, u8* buf, usize len) {
|
||||
if (len < sizeof(demo3d_snapshot_header)) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u16_be(&s, hdr->entity_count);
|
||||
pxl8_write_u16_be(&s, hdr->event_count);
|
||||
pxl8_write_u64_be(&s, hdr->player_id);
|
||||
pxl8_write_u64_be(&s, hdr->tick);
|
||||
pxl8_write_f32_be(&s, hdr->time);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_snapshot_header(const u8* buf, usize len, demo3d_snapshot_header* hdr) {
|
||||
if (len < sizeof(demo3d_snapshot_header)) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
hdr->entity_count = pxl8_read_u16_be(&s);
|
||||
hdr->event_count = pxl8_read_u16_be(&s);
|
||||
hdr->player_id = pxl8_read_u64_be(&s);
|
||||
hdr->tick = pxl8_read_u64_be(&s);
|
||||
hdr->time = pxl8_read_f32_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_chunk_msg_header(const demo3d_chunk_msg_header* hdr, u8* buf, usize len) {
|
||||
if (len < 24) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u8(&s, hdr->chunk_type);
|
||||
pxl8_write_u8(&s, hdr->flags);
|
||||
pxl8_write_u8(&s, hdr->fragment_idx);
|
||||
pxl8_write_u8(&s, hdr->fragment_count);
|
||||
pxl8_write_u32_be(&s, hdr->id);
|
||||
pxl8_write_u32_be(&s, (u32)hdr->cx);
|
||||
pxl8_write_u32_be(&s, (u32)hdr->cy);
|
||||
pxl8_write_u32_be(&s, (u32)hdr->cz);
|
||||
pxl8_write_u32_be(&s, hdr->version);
|
||||
pxl8_write_u16_be(&s, hdr->payload_size);
|
||||
pxl8_write_u16_be(&s, hdr->reserved);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, demo3d_chunk_msg_header* hdr) {
|
||||
if (len < 24) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
hdr->chunk_type = pxl8_read_u8(&s);
|
||||
hdr->flags = pxl8_read_u8(&s);
|
||||
hdr->fragment_idx = pxl8_read_u8(&s);
|
||||
hdr->fragment_count = pxl8_read_u8(&s);
|
||||
hdr->id = pxl8_read_u32_be(&s);
|
||||
hdr->cx = (i32)pxl8_read_u32_be(&s);
|
||||
hdr->cy = (i32)pxl8_read_u32_be(&s);
|
||||
hdr->cz = (i32)pxl8_read_u32_be(&s);
|
||||
hdr->version = pxl8_read_u32_be(&s);
|
||||
hdr->payload_size = pxl8_read_u16_be(&s);
|
||||
hdr->reserved = pxl8_read_u16_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, demo3d_bsp_wire_header* hdr) {
|
||||
if (len < 48) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
hdr->num_vertices = pxl8_read_u32_be(&s);
|
||||
hdr->num_edges = pxl8_read_u32_be(&s);
|
||||
hdr->num_faces = pxl8_read_u32_be(&s);
|
||||
hdr->num_planes = pxl8_read_u32_be(&s);
|
||||
hdr->num_nodes = pxl8_read_u32_be(&s);
|
||||
hdr->num_leafs = pxl8_read_u32_be(&s);
|
||||
hdr->num_surfedges = pxl8_read_u32_be(&s);
|
||||
hdr->num_marksurfaces = pxl8_read_u32_be(&s);
|
||||
hdr->num_cell_portals = pxl8_read_u32_be(&s);
|
||||
hdr->visdata_size = pxl8_read_u32_be(&s);
|
||||
hdr->num_vertex_lights = pxl8_read_u32_be(&s);
|
||||
hdr->num_heightfield = pxl8_read_u32_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_serialize_chunk_enter(const demo3d_chunk_enter_msg* msg, u8* buf, usize len) {
|
||||
if (len < 8) return 0;
|
||||
pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len);
|
||||
pxl8_write_u32_be(&s, (u32)msg->cx);
|
||||
pxl8_write_u32_be(&s, (u32)msg->cz);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
usize demo3d_protocol_deserialize_chunk_enter(const u8* buf, usize len, demo3d_chunk_enter_msg* msg) {
|
||||
if (len < 8) return 0;
|
||||
pxl8_stream s = pxl8_stream_create(buf, (u32)len);
|
||||
msg->cx = (i32)pxl8_read_u32_be(&s);
|
||||
msg->cz = (i32)pxl8_read_u32_be(&s);
|
||||
return s.offset;
|
||||
}
|
||||
|
||||
u32 demo3d_chunk_hash(i32 cx, i32 cz) {
|
||||
u32 h = (u32)cx * 374761393u + (u32)cz * 668265263u;
|
||||
return h ^ (h >> 16);
|
||||
}
|
||||
143
demo3d/client/net/demo3d_protocol.h
Normal file
143
demo3d/client/net/demo3d_protocol.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#pragma once
|
||||
|
||||
#include "pxl8_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEMO3D_PROTOCOL_VERSION 1
|
||||
#define DEMO3D_MAX_SNAPSHOT_ENTITIES 256
|
||||
#define DEMO3D_MAX_SNAPSHOT_EVENTS 32
|
||||
#define DEMO3D_COMMAND_PAYLOAD_SIZE 64
|
||||
#define DEMO3D_EVENT_PAYLOAD_SIZE 15
|
||||
|
||||
typedef enum demo3d_msg_type {
|
||||
DEMO3D_MSG_NONE = 0,
|
||||
DEMO3D_MSG_CHUNK,
|
||||
DEMO3D_MSG_CHUNK_ENTER,
|
||||
DEMO3D_MSG_CHUNK_EXIT,
|
||||
DEMO3D_MSG_COMMAND,
|
||||
DEMO3D_MSG_CONNECT,
|
||||
DEMO3D_MSG_DISCONNECT,
|
||||
DEMO3D_MSG_EVENT,
|
||||
DEMO3D_MSG_INPUT,
|
||||
DEMO3D_MSG_SNAPSHOT
|
||||
} demo3d_msg_type;
|
||||
|
||||
typedef struct demo3d_msg_header {
|
||||
u32 sequence;
|
||||
u16 size;
|
||||
u8 type;
|
||||
u8 version;
|
||||
} demo3d_msg_header;
|
||||
|
||||
typedef enum demo3d_cmd_type {
|
||||
DEMO3D_CMD_NONE = 0,
|
||||
DEMO3D_CMD_SPAWN_ENTITY,
|
||||
} demo3d_cmd_type;
|
||||
|
||||
typedef struct demo3d_input_msg {
|
||||
u32 buttons;
|
||||
f32 look_dx;
|
||||
f32 look_dy;
|
||||
f32 move_x;
|
||||
f32 move_y;
|
||||
f32 yaw;
|
||||
u64 tick;
|
||||
u64 timestamp;
|
||||
} demo3d_input_msg;
|
||||
|
||||
typedef struct demo3d_command_msg {
|
||||
u16 cmd_type;
|
||||
u8 payload[DEMO3D_COMMAND_PAYLOAD_SIZE];
|
||||
u16 payload_size;
|
||||
u64 tick;
|
||||
} demo3d_command_msg;
|
||||
|
||||
typedef struct demo3d_entity_state {
|
||||
u64 entity_id;
|
||||
u8 userdata[56];
|
||||
} demo3d_entity_state;
|
||||
|
||||
typedef struct demo3d_event_msg {
|
||||
u8 event_type;
|
||||
u8 payload[DEMO3D_EVENT_PAYLOAD_SIZE];
|
||||
} demo3d_event_msg;
|
||||
|
||||
typedef struct demo3d_snapshot_header {
|
||||
u16 entity_count;
|
||||
u16 event_count;
|
||||
u64 player_id;
|
||||
u64 tick;
|
||||
f32 time;
|
||||
} demo3d_snapshot_header;
|
||||
|
||||
#define DEMO3D_CHUNK_TYPE_BSP 1
|
||||
|
||||
#define DEMO3D_CHUNK_FLAG_FINAL 0x04
|
||||
#define DEMO3D_CHUNK_MAX_PAYLOAD 1400
|
||||
|
||||
typedef struct demo3d_chunk_msg_header {
|
||||
u8 chunk_type;
|
||||
u8 flags;
|
||||
u8 fragment_idx;
|
||||
u8 fragment_count;
|
||||
u32 id;
|
||||
i32 cx, cy, cz;
|
||||
u32 version;
|
||||
u16 payload_size;
|
||||
u16 reserved;
|
||||
} demo3d_chunk_msg_header;
|
||||
|
||||
typedef struct demo3d_bsp_wire_header {
|
||||
u32 num_vertices;
|
||||
u32 num_edges;
|
||||
u32 num_faces;
|
||||
u32 num_planes;
|
||||
u32 num_nodes;
|
||||
u32 num_leafs;
|
||||
u32 num_surfedges;
|
||||
u32 num_marksurfaces;
|
||||
u32 num_cell_portals;
|
||||
u32 visdata_size;
|
||||
u32 num_vertex_lights;
|
||||
u32 num_heightfield;
|
||||
} demo3d_bsp_wire_header;
|
||||
|
||||
usize demo3d_protocol_serialize_header(const demo3d_msg_header* msg, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_header(const u8* buf, usize len, demo3d_msg_header* msg);
|
||||
|
||||
usize demo3d_protocol_serialize_input(const demo3d_input_msg* msg, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_input(const u8* buf, usize len, demo3d_input_msg* msg);
|
||||
|
||||
usize demo3d_protocol_serialize_command(const demo3d_command_msg* msg, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_command(const u8* buf, usize len, demo3d_command_msg* msg);
|
||||
|
||||
usize demo3d_protocol_serialize_entity_state(const demo3d_entity_state* state, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_entity_state(const u8* buf, usize len, demo3d_entity_state* state);
|
||||
|
||||
usize demo3d_protocol_serialize_event(const demo3d_event_msg* msg, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_event(const u8* buf, usize len, demo3d_event_msg* msg);
|
||||
|
||||
usize demo3d_protocol_serialize_snapshot_header(const demo3d_snapshot_header* hdr, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_snapshot_header(const u8* buf, usize len, demo3d_snapshot_header* hdr);
|
||||
|
||||
usize demo3d_protocol_serialize_chunk_msg_header(const demo3d_chunk_msg_header* hdr, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_chunk_msg_header(const u8* buf, usize len, demo3d_chunk_msg_header* hdr);
|
||||
|
||||
usize demo3d_protocol_deserialize_bsp_wire_header(const u8* buf, usize len, demo3d_bsp_wire_header* hdr);
|
||||
|
||||
typedef struct demo3d_chunk_enter_msg {
|
||||
i32 cx;
|
||||
i32 cz;
|
||||
} demo3d_chunk_enter_msg;
|
||||
|
||||
usize demo3d_protocol_serialize_chunk_enter(const demo3d_chunk_enter_msg* msg, u8* buf, usize len);
|
||||
usize demo3d_protocol_deserialize_chunk_enter(const u8* buf, usize len, demo3d_chunk_enter_msg* msg);
|
||||
|
||||
u32 demo3d_chunk_hash(i32 cx, i32 cz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue