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
|
|
@ -3,18 +3,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pxl8_hal.h"
|
||||
#include "pxl8_platform.h"
|
||||
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
#include <stdatomic.h>
|
||||
#include "pxl8_queue.h"
|
||||
#endif
|
||||
|
||||
#include "pxl8_bytes.h"
|
||||
#include "pxl8_log.h"
|
||||
#include "pxl8_mem.h"
|
||||
#include "pxl8_world.h"
|
||||
#include "pxl8_world_chunk_cache.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
|
@ -37,7 +34,6 @@
|
|||
#endif
|
||||
|
||||
#define PXL8_NET_DEFAULT_PORT 7777
|
||||
#define PXL8_NET_TICK_RATE 30.0f
|
||||
|
||||
struct pxl8_net {
|
||||
char address[256];
|
||||
|
|
@ -46,27 +42,6 @@ struct pxl8_net {
|
|||
struct sockaddr_in server_addr;
|
||||
socket_t sock;
|
||||
|
||||
pxl8_world_chunk_cache* chunk_cache;
|
||||
i32 chunk_cx;
|
||||
i32 chunk_cz;
|
||||
bool has_chunk;
|
||||
pxl8_world* world;
|
||||
|
||||
u64 highest_tick;
|
||||
f32 interp_time;
|
||||
|
||||
pxl8_entity_state entities[PXL8_MAX_SNAPSHOT_ENTITIES];
|
||||
pxl8_entity_state prev_entities[PXL8_MAX_SNAPSHOT_ENTITIES];
|
||||
pxl8_snapshot_header prev_snapshot;
|
||||
pxl8_snapshot_header snapshot;
|
||||
|
||||
u64 input_head;
|
||||
pxl8_input_msg input_history[PXL8_NET_INPUT_HISTORY_SIZE];
|
||||
u64 input_oldest_tick;
|
||||
|
||||
u8 predicted_state[PXL8_NET_USERDATA_SIZE];
|
||||
u64 predicted_tick;
|
||||
|
||||
u8 recv_buf[4096];
|
||||
u8 send_buf[4096];
|
||||
|
||||
|
|
@ -77,13 +52,6 @@ struct pxl8_net {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const pxl8_entity_state* find_entity(const pxl8_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;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_net_connect(pxl8_net* net) {
|
||||
if (!net) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
if (net->connected) return PXL8_OK;
|
||||
|
|
@ -161,154 +129,11 @@ void pxl8_net_disconnect(pxl8_net* net) {
|
|||
net->connected = false;
|
||||
}
|
||||
|
||||
const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net) {
|
||||
if (!net) return NULL;
|
||||
return net->entities;
|
||||
}
|
||||
|
||||
const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id) {
|
||||
if (!net) return NULL;
|
||||
const pxl8_entity_state* e = find_entity(net->prev_entities, net->prev_snapshot.entity_count, entity_id);
|
||||
return e ? e->userdata : NULL;
|
||||
}
|
||||
|
||||
const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id) {
|
||||
if (!net) return NULL;
|
||||
const pxl8_entity_state* e = find_entity(net->entities, net->snapshot.entity_count, entity_id);
|
||||
return e ? e->userdata : NULL;
|
||||
}
|
||||
|
||||
const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick) {
|
||||
if (!net) return NULL;
|
||||
for (u64 i = 0; i < PXL8_NET_INPUT_HISTORY_SIZE; i++) {
|
||||
if (net->input_history[i].tick == tick) {
|
||||
return &net->input_history[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 pxl8_net_input_oldest_tick(const pxl8_net* net) {
|
||||
if (!net) return 0;
|
||||
return net->input_oldest_tick;
|
||||
}
|
||||
|
||||
void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input) {
|
||||
if (!net || !input) return;
|
||||
u64 idx = net->input_head % PXL8_NET_INPUT_HISTORY_SIZE;
|
||||
net->input_history[idx] = *input;
|
||||
net->input_head++;
|
||||
if (net->input_oldest_tick == 0 || input->tick < net->input_oldest_tick) {
|
||||
net->input_oldest_tick = input->tick;
|
||||
}
|
||||
}
|
||||
|
||||
f32 pxl8_net_lerp_alpha(const pxl8_net* net) {
|
||||
if (!net) return 1.0f;
|
||||
f32 tick_duration = 1.0f / PXL8_NET_TICK_RATE;
|
||||
f32 alpha = net->interp_time / tick_duration;
|
||||
return alpha > 1.0f ? 1.0f : alpha;
|
||||
}
|
||||
|
||||
bool pxl8_net_needs_correction(const pxl8_net* net) {
|
||||
if (!net) return false;
|
||||
if (net->snapshot.tick == 0) return false;
|
||||
if (net->predicted_tick == 0) return false;
|
||||
if (net->snapshot.tick > net->predicted_tick) return true;
|
||||
const u8* server = pxl8_net_entity_userdata(net, net->snapshot.player_id);
|
||||
if (!server) return false;
|
||||
return memcmp(server, net->predicted_state, PXL8_NET_USERDATA_SIZE) != 0;
|
||||
}
|
||||
|
||||
u64 pxl8_net_player_id(const pxl8_net* net) {
|
||||
if (!net) return 0;
|
||||
return net->snapshot.player_id;
|
||||
}
|
||||
|
||||
static bool dispatch_message(pxl8_net* net, const u8* data, usize len) {
|
||||
if (len < sizeof(pxl8_msg_header)) return false;
|
||||
|
||||
pxl8_msg_header hdr;
|
||||
usize offset = pxl8_protocol_deserialize_header(data, len, &hdr);
|
||||
|
||||
if (hdr.type == PXL8_MSG_CHUNK) {
|
||||
if (!net->chunk_cache) return false;
|
||||
|
||||
pxl8_chunk_msg_header chunk_hdr;
|
||||
offset += pxl8_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;
|
||||
}
|
||||
|
||||
pxl8_world_chunk_cache_receive(net->chunk_cache, &chunk_hdr, payload, payload_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type == PXL8_MSG_CHUNK_ENTER) {
|
||||
pxl8_chunk_enter_msg chunk_msg;
|
||||
pxl8_protocol_deserialize_chunk_enter(data + offset, len - offset, &chunk_msg);
|
||||
net->chunk_cx = chunk_msg.cx;
|
||||
net->chunk_cz = chunk_msg.cz;
|
||||
net->has_chunk = true;
|
||||
pxl8_debug("[CLIENT] Received CHUNK_ENTER cx=%d cz=%d", chunk_msg.cx, chunk_msg.cz);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type == PXL8_MSG_CHUNK_EXIT) {
|
||||
net->has_chunk = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hdr.type != PXL8_MSG_SNAPSHOT) return false;
|
||||
|
||||
pxl8_snapshot_header snap;
|
||||
offset += pxl8_protocol_deserialize_snapshot_header(data + offset, len - offset, &snap);
|
||||
|
||||
if (snap.tick <= net->highest_tick) return false;
|
||||
|
||||
memcpy(net->prev_entities, net->entities, sizeof(net->entities));
|
||||
net->prev_snapshot = net->snapshot;
|
||||
|
||||
net->highest_tick = snap.tick;
|
||||
net->snapshot = snap;
|
||||
net->interp_time = 0.0f;
|
||||
|
||||
u16 count = snap.entity_count;
|
||||
if (count > PXL8_MAX_SNAPSHOT_ENTITIES) count = PXL8_MAX_SNAPSHOT_ENTITIES;
|
||||
|
||||
for (u16 i = 0; i < count; i++) {
|
||||
offset += pxl8_protocol_deserialize_entity_state(
|
||||
data + offset, len - offset, &net->entities[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pxl8_net_poll(pxl8_net* net) {
|
||||
if (!net || !net->connected) return false;
|
||||
|
||||
usize len = pxl8_net_recv(net, net->recv_buf, sizeof(net->recv_buf));
|
||||
u64 prev_tick = net->highest_tick;
|
||||
if (!dispatch_message(net, net->recv_buf, len)) return false;
|
||||
|
||||
if (net->highest_tick > prev_tick && net->world) {
|
||||
pxl8_world_reconcile(net->world, net, 1.0f / 30.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u8* pxl8_net_predicted_state(pxl8_net* net) {
|
||||
if (!net) return NULL;
|
||||
return net->predicted_state;
|
||||
}
|
||||
|
||||
void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick) {
|
||||
if (!net) return;
|
||||
net->predicted_tick = tick;
|
||||
return len > 0;
|
||||
}
|
||||
|
||||
usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len) {
|
||||
|
|
@ -330,103 +155,6 @@ pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len) {
|
|||
return (sent > 0) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd) {
|
||||
if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_command_msg)];
|
||||
pxl8_msg_header hdr = {
|
||||
.type = PXL8_MSG_COMMAND,
|
||||
.version = PXL8_PROTOCOL_VERSION,
|
||||
.size = sizeof(pxl8_command_msg),
|
||||
.sequence = 0
|
||||
};
|
||||
|
||||
usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||
offset += pxl8_protocol_serialize_command(cmd, buf + offset, sizeof(buf) - offset);
|
||||
|
||||
return pxl8_net_send(net, buf, offset);
|
||||
}
|
||||
|
||||
pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input) {
|
||||
if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
pxl8_net_input_push(net, input);
|
||||
|
||||
u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_input_msg)];
|
||||
pxl8_msg_header hdr = {
|
||||
.type = PXL8_MSG_INPUT,
|
||||
.version = PXL8_PROTOCOL_VERSION,
|
||||
.size = sizeof(pxl8_input_msg),
|
||||
.sequence = 0
|
||||
};
|
||||
|
||||
usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf));
|
||||
offset += pxl8_protocol_serialize_input(input, buf + offset, sizeof(buf) - offset);
|
||||
|
||||
return pxl8_net_send(net, buf, offset);
|
||||
}
|
||||
|
||||
const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net) {
|
||||
if (!net) return NULL;
|
||||
return &net->snapshot;
|
||||
}
|
||||
|
||||
u64 pxl8_net_tick(const pxl8_net* net) {
|
||||
if (!net) return 0;
|
||||
return net->snapshot.tick;
|
||||
}
|
||||
|
||||
void pxl8_net_update(pxl8_net* net, f32 dt) {
|
||||
if (!net) return;
|
||||
net->interp_time += dt;
|
||||
}
|
||||
|
||||
void pxl8_net_set_chunk_cache(pxl8_net* net, pxl8_world_chunk_cache* cache) {
|
||||
if (!net) return;
|
||||
net->chunk_cache = cache;
|
||||
}
|
||||
|
||||
pxl8_world_chunk_cache* pxl8_net_chunk_cache(pxl8_net* net) {
|
||||
if (!net) return NULL;
|
||||
return net->chunk_cache;
|
||||
}
|
||||
|
||||
void pxl8_net_set_world(pxl8_net* net, pxl8_world* world) {
|
||||
if (!net) return;
|
||||
net->world = world;
|
||||
}
|
||||
|
||||
i32 pxl8_net_chunk_cx(const pxl8_net* net) {
|
||||
if (!net) return 0;
|
||||
return net->chunk_cx;
|
||||
}
|
||||
|
||||
i32 pxl8_net_chunk_cz(const pxl8_net* net) {
|
||||
if (!net) return 0;
|
||||
return net->chunk_cz;
|
||||
}
|
||||
|
||||
bool pxl8_net_has_chunk(const pxl8_net* net) {
|
||||
if (!net) return false;
|
||||
return net->has_chunk;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_net_spawn(pxl8_net* net, f32 x, f32 y, f32 z, f32 yaw, f32 pitch) {
|
||||
if (!net) return PXL8_ERROR_NULL_POINTER;
|
||||
if (!net->connected) return PXL8_ERROR_NOT_CONNECTED;
|
||||
|
||||
pxl8_command_msg cmd = {0};
|
||||
cmd.cmd_type = PXL8_CMD_SPAWN_ENTITY;
|
||||
pxl8_pack_f32_be(cmd.payload, 0, x);
|
||||
pxl8_pack_f32_be(cmd.payload, 4, y);
|
||||
pxl8_pack_f32_be(cmd.payload, 8, z);
|
||||
pxl8_pack_f32_be(cmd.payload, 12, yaw);
|
||||
pxl8_pack_f32_be(cmd.payload, 16, pitch);
|
||||
cmd.payload_size = 20;
|
||||
|
||||
return pxl8_net_send_command(net, &cmd);
|
||||
}
|
||||
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
|
||||
static int pxl8_net_recv_thread(void* data) {
|
||||
|
|
@ -494,7 +222,9 @@ void pxl8_net_packet_free(pxl8_packet* pkt) {
|
|||
|
||||
bool pxl8_net_process_packet(pxl8_net* net, const pxl8_packet* pkt) {
|
||||
if (!net || !pkt) return false;
|
||||
return dispatch_message(net, pkt->data, pkt->len);
|
||||
(void)net;
|
||||
(void)pkt;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue