server snapshot testing

This commit is contained in:
jacob 2026-01-18 00:59:49 -06:00
parent 3cdff3c4c5
commit 8e29fa447b
4 changed files with 226 additions and 117 deletions

View File

@ -308,20 +308,19 @@ Struct(P_UserSnapshot)
Enum(P_MsgKind) Enum(P_MsgKind)
{ {
P_MsgKind_None, P_MsgKind_None,
P_MsgKind_Raw,
// Server <-> Client // Server <-> Client
P_MsgKind_Chat, P_MsgKind_Chat,
P_MsgKind_Connect, P_MsgKind_Connect,
// Client -> Server // Client -> Server
// P_MsgKind_UserSnapshot,
P_MsgKind_SaveWorld, P_MsgKind_SaveWorld,
P_MsgKind_ResetWorld, P_MsgKind_ResetWorld,
P_MsgKind_TileEdit, P_MsgKind_TileEdit,
P_MsgKind_EntEdit, P_MsgKind_EntEdit,
// Server -> Client // Server -> Client
// P_MsgKind_SimSnapshot,
P_MsgKind_Tiles, P_MsgKind_Tiles,
}; };
@ -331,9 +330,6 @@ Struct(P_Msg)
NET_Key src; NET_Key src;
NET_Key dst; NET_Key dst;
// P_UserSnapshot user_snapshot;
// P_SimSnapshot sim_snapshot;
P_TileKind tile_kind; P_TileKind tile_kind;
Rng2I32 tile_range; Rng2I32 tile_range;
u64 tiles_hash; u64 tiles_hash;

View File

@ -167,76 +167,12 @@ void S_TickForever(WaveLaneCtx *lane)
{ {
NET_Key net_key = net_msg->sender; NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame_arena, net_key); // String address_str = NET_StringFromKey(frame_arena, net_key);
LogDebugF("Received message from client \"%F\"", FmtString(address_str)); // LogDebugF("Received message from client \"%F\"", FmtString(address_str));
// String test_address_str = NET_StringFromKey(frame_arena, net_key);
// LogDebugF("Sending test msg to client \"%F\"", FmtString(test_address_str));
// NET_Send(net_pipe, net_key, Lit("HIII"), NET_SendFlag_None);
String packed = net_msg->data; String packed = net_msg->data;
P_MsgList client_msgs = P_UnpackMessages(frame_arena, packed, net_key); P_MsgList client_msgs = P_UnpackMessages(frame_arena, packed, net_key);
// if (client_msgs.count > 0)
// {
// S_Client *client = S_ClientFromNetKey(net_key);
// // Create client
// if (S_IsClientNil(client))
// {
// P_Msg *msg = &client_msgs.first->msg;
// if (msg->kind == P_MsgKind_Connect)
// {
// u64 hash = NET_HashFromKey(net_key);
// S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
// String src_name = msg->data;
// src_name = TrimWhitespace(src_name);
// if (src_name.len < P_MinPlayerNameLen)
// {
// src_name = Lit("Player");
// }
// src_name.len = MinI64(src_name.len, P_MaxPlayerNameLen);
// // FIXME: Freelist client
// client = PushStruct(perm, S_Client);
// client->hash = hash;
// client->net_key = net_key;
// client->name_len = MinI64(countof(client->name_text), src_name.len);
// CopyBytes(client->name_text, src_name.text, client->name_len);
// DllQueuePushNPZ(&S_NilClient, S.first_client, S.last_client, client, next, prev);
// DllQueuePushNP(bin->first, bin->last, client, next_in_bin, prev_in_bin);
// {
// P_Msg *out_msg = P_PushMsg(P_MsgKind_Connect, Zstr);
// out_msg->dst = net_key;
// }
// {
// String name = STRING(client->name_len, client->name_text);
// if (MatchString(name, src_name))
// {
// LogDebugF("Client \"%F\" connecting with name \"%F\"", FmtString(address_str), FmtString(src_name));
// }
// else
// {
// LogDebugF("Client \"%F\" connecting with name \"%F\" (reassigned to \"%F\")", FmtString(address_str), FmtString(src_name), FmtString(name));
// }
// P_Msg *out_msg = P_PushMsg(
// P_MsgKind_Chat,
// StringF(
// frame_arena,
// "Player %F is connecting",
// FmtString(name)
// ));
// }
// }
// }
// }
if (client_msgs.first) if (client_msgs.first)
{ {
if (in_msgs.last) if (in_msgs.last)
@ -269,8 +205,8 @@ void S_TickForever(WaveLaneCtx *lane)
u64 hash = NET_HashFromKey(net_key); u64 hash = NET_HashFromKey(net_key);
S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count]; S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
String src_name = msg->data; String orig_src_name = msg->data;
src_name = TrimWhitespace(src_name); String src_name = TrimWhitespace(orig_src_name);
if (src_name.len < P_MinPlayerNameLen) if (src_name.len < P_MinPlayerNameLen)
{ {
src_name = Lit("Player"); src_name = Lit("Player");
@ -296,13 +232,13 @@ void S_TickForever(WaveLaneCtx *lane)
// Broadcast player connection notification // Broadcast player connection notification
{ {
String name = STRING(client->name_len, client->name_text); String name = STRING(client->name_len, client->name_text);
if (MatchString(name, src_name)) if (MatchString(name, orig_src_name))
{ {
LogDebugF("Client \"%F\" connecting with name \"%F\"", FmtString(address_str), FmtString(src_name)); LogInfoF("Client \"%F\" connecting with name \"%F\"", FmtString(address_str), FmtString(name));
} }
else else
{ {
LogDebugF("Client \"%F\" connecting with name \"%F\" (reassigned to \"%F\")", FmtString(address_str), FmtString(src_name), FmtString(name)); LogInfoF("Client \"%F\" connecting with name \"%F\" (reassigned to \"%F\")", FmtString(address_str), FmtString(orig_src_name), FmtString(name));
} }
P_Msg *out_msg = P_PushMsg( P_Msg *out_msg = P_PushMsg(
P_MsgKind_Chat, P_MsgKind_Chat,
@ -649,6 +585,113 @@ void S_TickForever(WaveLaneCtx *lane)
// } // }
// } // }
//////////////////////////////
//- Send snapshots
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{
Struct(PackedDeltaNode)
{
PackedDeltaNode *next;
String packed;
};
i64 total_delta_bytes = 0;
PackedDeltaNode *first_delta_node = 0;
PackedDeltaNode *last_delta_node = 0;
//- Pack entity deltas
P_Frame *src_frame = &P_NilFrame;
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
b32 should_transmit = 0;
BB_ResetWriter(&packer_bbw);
u64 delta_start = BB_GetNumBytesWritten(&packer_bbw);
{
// TODO: Compress
should_transmit = 1;
BB_WriteBytes(&packer_bbw, StringFromStruct(ent));
}
u64 delta_end = BB_GetNumBytesWritten(&packer_bbw);
if (should_transmit)
{
String packed = Zi;
packed.text = BB_GetWrittenRaw(&packer_bbw) + delta_start;
packed.len = delta_end - delta_start;
{
PackedDeltaNode *delta_node = PushStruct(frame_arena, PackedDeltaNode);
delta_node->packed = PushString(frame_arena, packed);
SllQueuePush(first_delta_node, last_delta_node, delta_node);
total_delta_bytes += packed.len;
}
}
}
// Collect deltas into snapshots
{
u64 max_snapshot_size = NET_PacketSize / 2;
PackedDeltaNode *delta_node = first_delta_node;
u64 snapshot_start = 0;
b32 new_snapshot = 1;
b32 done = 0;
while (!done)
{
PackedDeltaNode *next_delta_node = delta_node ? delta_node->next : 0;
{
//- Init snapshot
if (new_snapshot)
{
new_snapshot = 0;
BB_ResetWriter(&packer_bbw);
snapshot_start = BB_GetNumBytesWritten(&packer_bbw);
BB_WriteBit(&packer_bbw, 1); // Raw
BB_WriteIV(&packer_bbw, src_frame->tick);
BB_WriteIV(&packer_bbw, world_frame->tick);
BB_WriteIV(&packer_bbw, world_frame->time_ns);
}
//- Append packed delta
BB_WriteAlignToNextByte(&packer_bbw);
if (delta_node)
{
BB_WriteBytes(&packer_bbw, delta_node->packed);
}
//- Submit snapshot
{
if (!delta_node || !next_delta_node)
{
new_snapshot = 1;
done = 1;
}
u64 next_len = 0;
if (next_delta_node)
{
next_len = next_delta_node->packed.len;
}
u64 cur_snapshot_len = BB_GetNumBytesWritten(&packer_bbw);
if ((cur_snapshot_len - snapshot_start) + next_len >= max_snapshot_size)
{
new_snapshot = 1;
}
}
if (new_snapshot)
{
u64 snapshot_end = BB_GetNumBytesWritten(&packer_bbw);
String snapshot = Zi;
snapshot.text = BB_GetWrittenRaw(&packer_bbw) + snapshot_start;
snapshot.len = snapshot_end - snapshot_start;
// FIXME: Send raw snapshots
// NET_Send(net_pipe, client->net_key, snapshot, NET_SendFlag_Raw);
NET_Send(net_pipe, client->net_key, snapshot, NET_SendFlag_None);
}
}
delta_node = next_delta_node;
}
}
}
////////////////////////////// //////////////////////////////
//- Send messages //- Send messages
@ -688,11 +731,11 @@ void S_TickForever(WaveLaneCtx *lane)
P_MsgList msgs = client->out_msgs; P_MsgList msgs = client->out_msgs;
if (msgs.count > 0) if (msgs.count > 0)
{ {
BB_ResetWriter(&packer_bbw);
String packed = P_PackMessages(&packer_bbw, msgs); String packed = P_PackMessages(&packer_bbw, msgs);
// String address_str = NET_StringFromKey(frame_arena, client->net_key);
String address_str = NET_StringFromKey(frame_arena, client->net_key); // LogDebugF("Sending message to client \"%F\"", FmtString(address_str));
LogDebugF("Sending message to client \"%F\"", FmtString(address_str));
NET_Send(net_pipe, client->net_key, packed, NET_SendFlag_None); NET_Send(net_pipe, client->net_key, packed, NET_SendFlag_None);
ZeroStruct(&client->out_msgs); ZeroStruct(&client->out_msgs);

View File

@ -206,6 +206,7 @@ String P_PackMessages(BB_Writer *bbw, P_MsgList msgs)
{ {
// TODO: Compress // TODO: Compress
P_Msg *msg = &msg_node->msg; P_Msg *msg = &msg_node->msg;
BB_WriteBit(bbw, 0); // Not raw
BB_WriteBytes(bbw, StringFromStruct(msg)); BB_WriteBytes(bbw, StringFromStruct(msg));
BB_WriteString(bbw, msg->data); BB_WriteString(bbw, msg->data);
} }
@ -225,23 +226,38 @@ P_MsgList P_UnpackMessages(Arena *arena, String packed, NET_Key sender)
b32 done = 0; b32 done = 0;
while (!done) while (!done)
{ {
u8 *msg_raw = BB_ReadBytesRaw(&bbr, sizeof(P_Msg)); b32 is_raw = BB_ReadBit(&bbr);
if (msg_raw != 0) if (is_raw)
{ {
// Read msg header
P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode); P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode);
CopyStruct(&dst_msg_node->msg, msg_raw);
DllQueuePush(result.first, result.last, dst_msg_node); DllQueuePush(result.first, result.last, dst_msg_node);
result.count += 1; result.count += 1;
// Read msg data string dst_msg_node->msg.kind = P_MsgKind_Raw;
String data_str = BB_ReadString(arena, &bbr);
dst_msg_node->msg.src = sender; dst_msg_node->msg.src = sender;
dst_msg_node->msg.dst = NET_NilKey; dst_msg_node->msg.dst = NET_NilKey;
dst_msg_node->msg.data = data_str; dst_msg_node->msg.data = PushString(arena, packed);
done = 1;
} }
else else
{ {
done = 1; u8 *msg_src = BB_ReadBytesRaw(&bbr, sizeof(P_Msg));
if (msg_src != 0)
{
// Read msg header
P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode);
CopyStruct(&dst_msg_node->msg, msg_src);
DllQueuePush(result.first, result.last, dst_msg_node);
result.count += 1;
// Read msg data string
String data_str = BB_ReadString(arena, &bbr);
dst_msg_node->msg.src = sender;
dst_msg_node->msg.dst = NET_NilKey;
dst_msg_node->msg.data = data_str;
}
else
{
done = 1;
}
} }
} }
return result; return result;

View File

@ -2629,29 +2629,29 @@ void V_TickForever(WaveLaneCtx *lane)
// } // }
// } break; // } break;
// case V_CmdKind_spawn_dummy: case V_CmdKind_spawn_dummy:
// { {
// P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr); P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr);
// P_Ent *ent = &cmd->ent; P_Ent *ent = &msg->ent;
// *ent = P_NilEnt; *ent = P_NilEnt;
// ent->key = P_RandKey(); ent->key = P_RandKey();
// ent->xf = XformFromPos(frame->world_cursor); ent->xf = XformFromPos(frame->world_cursor);
// ent->is_player = 1; ent->is_player = 1;
// ent->is_dummy = 1; ent->is_dummy = 1;
// ent->has_weapon = 1; ent->has_weapon = 1;
// ent->exists = 1; ent->exists = 1;
// } break; } break;
// case V_CmdKind_delete: case V_CmdKind_delete:
// { {
// if (!P_IsEntNil(hovered_ent)) if (!P_IsEntNil(hovered_ent))
// { {
// P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr); P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr);
// P_Ent *ent = &cmd->ent; P_Ent *ent = &msg->ent;
// ent->key = hovered_ent->key; ent->key = hovered_ent->key;
// ent->exists = 0; ent->exists = 0;
// } }
// } break; } break;
// case V_CmdKind_save_level: // case V_CmdKind_save_level:
// { // {
@ -2670,8 +2670,6 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
// V_PushNotif(Lit("Hello!!!")); // V_PushNotif(Lit("Hello!!!"));
P_Msg *chat_msg = P_PushMsg(P_MsgKind_Chat, Lit("Hello!!!")); P_Msg *chat_msg = P_PushMsg(P_MsgKind_Chat, Lit("Hello!!!"));
} break; } break;
} }
} }
@ -2701,7 +2699,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
P_MsgNode tmp_msg_node = Zi; P_MsgNode tmp_msg_node = Zi;
tmp_msg_node.msg.kind = P_MsgKind_Connect; tmp_msg_node.msg.kind = P_MsgKind_Connect;
tmp_msg_node.msg.data = Lit("Guy"); tmp_msg_node.msg.data = Lit("Bro");
P_MsgList tmp_msglist = Zi; P_MsgList tmp_msglist = Zi;
tmp_msglist.count = 1; tmp_msglist.count = 1;
@ -2734,8 +2732,8 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
NET_Key net_key = net_msg->sender; NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame->arena, net_key); // String address_str = NET_StringFromKey(frame->arena, net_key);
LogDebugF("Received message from server \"%F\"", FmtString(address_str)); // LogDebugF("Received message from server \"%F\"", FmtString(address_str));
if (NET_MatchKey(net_key, frame->desired_sim_key)) if (NET_MatchKey(net_key, frame->desired_sim_key))
{ {
@ -2845,10 +2843,67 @@ void V_TickForever(WaveLaneCtx *lane)
// UnlockTicketMutex(&P.s2v_snapshot_mutex); // UnlockTicketMutex(&P.s2v_snapshot_mutex);
// } // }
//////////////////////////////
//- Apply sim snapshots
{
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
//- Snapshot
if (msg->kind == P_MsgKind_Raw)
{
BB_Buff bb = BB_BuffFromString(msg->data);
BB_Reader bbr = BB_ReaderFromBuff(&bb);
//- Read header
BB_ReadBit(&bbr); // Raw
i64 src_tick = BB_ReadIV(&bbr);
i64 dst_tick = BB_ReadIV(&bbr);
i64 time_ns = BB_ReadIV(&bbr);
P_Frame *src_frame = P_FrameFromTick(sim_world, src_tick);
if (src_frame->tick == src_tick)
{
P_Frame *dst_frame = P_FrameFromTick(sim_world, dst_tick);
if (P_IsFrameNil(dst_frame))
{
dst_frame = P_PushFrame(sim_world, src_frame, dst_tick);
}
dst_frame->time_ns = time_ns;
//- Read deltas
BB_ReadAlignToNextByte(&bbr);
b32 done = 0;
while (!done && BB_NumBitsRemaining(&bbr) > 0)
{
P_Ent *src_ent = (P_Ent *)BB_ReadBytesRaw(&bbr, sizeof(P_Ent));
if (src_ent)
{
P_EntListNode tmp_ent_node = Zi;
CopyStruct(&tmp_ent_node.ent, src_ent);
P_EntList ent_list = Zi;
ent_list.first = &tmp_ent_node;
ent_list.last = &tmp_ent_node;
++ent_list.count;
P_SpawnEntsFromList(dst_frame, ent_list);
}
else
{
done = 1;
}
}
}
}
}
}
////////////////////////////// //////////////////////////////
//- Apply sim msgs //- Apply sim msgs
P_Msg *newest_snapshot_msg = 0;
{ {
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next) for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{ {
@ -3086,7 +3141,6 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Update blended world //- Update blended world
b32 tiles_dirty = 0; b32 tiles_dirty = 0;
b32 should_clear_particles = 0; b32 should_clear_particles = 0;
@ -3744,7 +3798,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Upload tiles // Upload tiles
if (tiles_dirty) if (tiles_dirty)
{ {
LogDebugF("Uploading tiles to gpu"); // LogDebugF("Uploading tiles to gpu");
G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_CopyWrite); G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_CopyWrite);
G_CopyCpuToTexture( G_CopyCpuToTexture(
frame->cl, frame->cl,