networking progress

This commit is contained in:
jacob 2026-01-14 16:51:24 -06:00
parent b363160103
commit b73daaf1f1
8 changed files with 663 additions and 515 deletions

View File

@ -525,10 +525,9 @@
#define IsNan(x) isnan(x) #define IsNan(x) isnan(x)
//- u128 //- u128
#if IsLanguageC Struct(u128) { u64 lo; u64 hi; };
Struct(u128) { u64 lo; u64 hi; }; Inline u128 U128(u64 hi, u64 lo) { u128 result; result.hi = hi; result.lo = lo; return result; }
#define U128(_hi, _lo) ((u128) { .hi = (_hi), .lo = (_lo) }) Inline b32 MatchU128(u128 a, u128 b) { return a.lo == b.lo && a.hi == b.hi; }
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Atomics //~ Atomics

View File

@ -1006,8 +1006,10 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
DllQueueRemove(gpu_arena->reset_resources.first, gpu_arena->reset_resources.last, resource); DllQueueRemove(gpu_arena->reset_resources.first, gpu_arena->reset_resources.last, resource);
--gpu_arena->reset_resources.count; --gpu_arena->reset_resources.count;
D3D12_RESOURCE_DESC1 reset_d3d_desc = resource->d3d_desc; D3D12_RESOURCE_DESC1 reset_d3d_desc = Zi;
D3D12_RESOURCE_DESC1 compare_d3d_desc = reset_d3d_desc; D3D12_RESOURCE_DESC1 compare_d3d_desc = Zi;
CopyStruct(&reset_d3d_desc, &resource->d3d_desc);
CopyStruct(&compare_d3d_desc, &reset_d3d_desc);
// Buffers can be reused if size fits // Buffers can be reused if size fits
if (d3d_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && reset_d3d_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) if (d3d_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && reset_d3d_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)

View File

@ -16,17 +16,8 @@ Readonly P_Frame P_NilFrame = {
void P_Bootstrap(void) void P_Bootstrap(void)
{ {
// Initialize shared state P.u2s_msgs_arena = AcquireArena(Gibi(64));
for (u64 i = 0; i < countof(P.sim_input_states); ++i) P.s2u_msgs_arena = AcquireArena(Gibi(64));
{
P_InputState *input = &P.sim_input_states[i];
input->arena = AcquireArena(Gibi(64));
}
for (u64 i = 0; i < countof(P.sim_output_states); ++i)
{
P_OutputState *output = &P.sim_output_states[i];
output->arena = AcquireArena(Gibi(64));
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -73,6 +64,24 @@ u64 P_RandU64FromEnt(P_Ent *ent)
return result; return result;
} }
////////////////////////////////////////////////////////////
//~ String helpers
String P_StringFromEnt(P_Ent *ent)
{
String result = Zi;
result.len = ent->string_len;
result.text = ent->string_text;
return result;
}
void P_SetEntString(P_Ent *ent, String str)
{
i64 len = MinI64(countof(ent->string_text), str.len);
CopyBytes(ent->string_text, str.text, len);
ent->string_len = len;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Tile helpers //~ Tile helpers
@ -1158,6 +1167,14 @@ void P_DebugDrawShape(P_Shape shape, Vec4 srgb)
} }
} }
////////////////////////////////////////////////////////////
//~ Msg
P_Msg *P_PushMsg(P_MsgKind kind, String data)
{
// TODO
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ World //~ World
@ -1362,7 +1379,7 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Step //~ Step
void P_StepFrame(P_Frame *frame, P_CmdList cmds) void P_StepFrame(P_Frame *frame)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
P_World *world = frame->world; P_World *world = frame->world;
@ -1379,32 +1396,6 @@ void P_StepFrame(P_Frame *frame, P_CmdList cmds)
ent->prev_xf = ent->xf; ent->prev_xf = ent->xf;
} }
//////////////////////////////
//- Update ent controls
// FIXME: Only apply relevant cmds based on tick
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
ent->fire_presses = 0;
}
for (P_CmdNode *cmd_node = cmds.first; cmd_node; cmd_node = cmd_node->next)
{
P_Cmd cmd = cmd_node->cmd;
if (cmd.kind == P_CmdKind_Control)
{
P_Ent *target = P_EntFromKey(frame, cmd.target);
if (!P_IsEntNil(target))
{
target->move = ClampVec2Len(cmd.move, 1);
target->look = cmd.look;
target->fire_held = cmd.fire_held;
target->fire_presses += cmd.fire_presses;
}
}
}
////////////////////////////// //////////////////////////////
//- Spawn entities //- Spawn entities
@ -1797,7 +1788,7 @@ void P_StepFrame(P_Frame *frame, P_CmdList cmds)
f32 mass_scale = 1.0; f32 mass_scale = 1.0;
f32 impulse_scale = 0.0; f32 impulse_scale = 0.0;
// TDOO: Do a relaxation pass without bias // TODO: Do a relaxation pass without bias
b32 apply_bias = 1; b32 apply_bias = 1;
if (separation > 0.0) if (separation > 0.0)
{ {

View File

@ -71,7 +71,6 @@ Struct(P_DebugDrawNode)
Struct(P_Ent) Struct(P_Ent)
{ {
//////////////////////////////
//- Internal world state //- Internal world state
P_Ent *next; P_Ent *next;
@ -80,18 +79,17 @@ Struct(P_Ent)
P_Ent *next_in_bin; P_Ent *next_in_bin;
P_Ent *prev_in_bin; P_Ent *prev_in_bin;
//////////////////////////////
//- Persistent data //- Persistent data
P_Key key; P_Key key;
u64 rand_seq; u64 rand_seq;
//////////////////////////////
//- Build data //- Build data
f32 exists; f32 exists;
b32 is_player; b32 is_player;
b32 is_dummy;
f32 health; f32 health;
Xform prev_xf; Xform prev_xf;
@ -115,8 +113,16 @@ Struct(P_Ent)
Vec2 hit_entry; Vec2 hit_entry;
Vec2 hit_entry_normal; Vec2 hit_entry_normal;
////////////////////////////// //- User
//- Solver data
b32 is_user;
P_Key player;
u8 string_len;
u8 string_text[32];
//- Solver
Vec2 solved_v; Vec2 solved_v;
f32 solved_w; f32 solved_w;
@ -231,36 +237,36 @@ Struct(P_World)
P_Frame *first_frame; P_Frame *first_frame;
P_Frame *last_frame; P_Frame *last_frame;
P_Frame *first_free_frame;
i64 frame_bins_count; i64 frame_bins_count;
P_FrameBin *frame_bins; P_FrameBin *frame_bins;
P_Frame *first_free_frame;
u64 tiles_hash; u64 tiles_hash;
u8 *tiles; u8 *tiles;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Snapshot types //~ Sim snapshot types
Enum(P_DeltaKind) Enum(P_SimDeltaKind)
{ {
P_DeltaKind_None, P_SimDeltaKind_None,
P_DeltaKind_RawEnt, P_SimDeltaKind_RawEnt,
}; };
Struct(P_Delta) Struct(P_SimDelta)
{ {
P_DeltaKind kind; P_SimDeltaKind kind;
P_Ent ent; P_Ent ent;
}; };
Struct(P_DeltaNode) Struct(P_SimDeltaNode)
{ {
P_DeltaNode *next; P_SimDeltaNode *next;
P_Delta delta; P_SimDelta delta;
}; };
Struct(P_Snapshot) Struct(P_SimSnapshot)
{ {
u64 world_seed; u64 world_seed;
i64 src_tick; i64 src_tick;
@ -268,12 +274,27 @@ Struct(P_Snapshot)
i64 time_ns; i64 time_ns;
i64 deltas_count; i64 deltas_count;
P_DeltaNode *first_delta_node; P_SimDeltaNode *first_delta_node;
P_DeltaNode *last_delta_node; P_SimDeltaNode *last_delta_node;
i64 debug_draw_nodes_count;
P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *first_debug_draw_node;
P_DebugDrawNode *last_debug_draw_node; P_DebugDrawNode *last_debug_draw_node;
i64 debug_draw_nodes_count; };
////////////////////////////////////////////////////////////
//~ User snapshot types
Struct(P_UserSnapshot)
{
P_Key user;
i64 src_tick;
i64 tick;
Vec2 move;
Vec2 look;
b32 fire_held;
i32 fire_presses;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -282,16 +303,30 @@ Struct(P_Snapshot)
Enum(P_MsgKind) Enum(P_MsgKind)
{ {
P_MsgKind_None, P_MsgKind_None,
// User -> sim
P_MsgKind_SaveWorld,
P_MsgKind_ResetWorld,
P_MsgKind_TileEdit,
P_MsgKind_EntEdit,
// Sim -> user
P_MsgKind_Tiles, P_MsgKind_Tiles,
}; };
Struct(P_Msg) Struct(P_Msg)
{ {
P_MsgKind kind; P_MsgKind kind;
P_Key src_user;
P_Key dst_user; // If dst is 0, then cmd is meant to be broadcast
u64 tiles_hash; P_TileKind tile_kind;
Rng2I32 tile_range; Rng2I32 tile_range;
u8 *raw_tiles; u64 tiles_hash;
P_Ent ent;
String data;
}; };
Struct(P_MsgNode) Struct(P_MsgNode)
@ -361,94 +396,39 @@ Struct(P_RaycastResult)
Vec2 p; Vec2 p;
Vec2 normal; Vec2 normal;
}; };
////////////////////////////////////////////////////////////
//~ Command types
Enum(P_CmdKind)
{
P_CmdKind_Nop,
P_CmdKind_SaveWorld,
P_CmdKind_ResetWorld,
P_CmdKind_TileEdit,
P_CmdKind_EntEdit,
P_CmdKind_Control,
};
Struct(P_Cmd)
{
i64 tick;
b32 predicted;
P_CmdKind kind;
// Tile edit
P_TileKind tile_kind;
Rng2I32 tile_range;
// Ent edit
P_Ent ent;
// Control
P_Key target;
Vec2 move;
Vec2 look;
b32 fire_held;
i32 fire_presses;
};
Struct(P_CmdNode)
{
P_CmdNode *next;
P_CmdNode *prev;
P_Cmd cmd;
};
Struct(P_CmdList)
{
i64 count;
P_CmdNode *first;
P_CmdNode *last;
};
Struct(P_InputState)
{
Arena *arena;
P_CmdList cmds;
};
Struct(P_OutputState)
{
Arena *arena;
P_Snapshot snapshot;
P_MsgList msgs;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
Struct(P_Ctx) Struct(P_Ctx)
{ {
//- Sim input //- User -> sim messages
TicketMutex sim_input_back_tm; Arena *u2s_msgs_arena;
i32 sim_input_back_idx; TicketMutex u2s_msgs_mutex;
P_InputState sim_input_states[2]; P_MsgList u2s_msgs;
//- Sim output //- Sim -> user messages
TicketMutex sim_output_back_tm; Arena *s2u_msgs_arena;
i32 sim_output_back_idx; TicketMutex s2u_msgs_mutex;
P_OutputState sim_output_states[2]; P_MsgList s2u_msgs;
//- Sim -> user snapshot
Arena *s2u_snapshot_arena;
TicketMutex s2u_snapshot_mutex;
P_SimSnapshot s2u_snapshot;
}; };
Struct(P_ThreadLocalCtx) Struct(P_ThreadLocalCtx)
{ {
// TODO: Move this to world frame //- Per-thread debug info
Arena *debug_arena; Arena *debug_arena;
b32 debug_draw_enabled; b32 debug_draw_enabled;
P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *first_debug_draw_node;
P_DebugDrawNode *last_debug_draw_node; P_DebugDrawNode *last_debug_draw_node;
i64 debug_draw_nodes_count; i64 debug_draw_nodes_count;
//- Per-thread outbound messages
Arena *out_msgs_arena;
P_MsgList out_msgs;
}; };
extern P_Ctx P; extern P_Ctx P;
@ -478,6 +458,12 @@ u64 P_RandU64FromEnt(P_Ent *ent);
#define P_FmtKey(key) FmtHandle((key).v) #define P_FmtKey(key) FmtHandle((key).v)
////////////////////////////////////////////////////////////
//~ String helpers
String P_StringFromEnt(P_Ent *ent);
void P_SetEntString(P_Ent *ent, String str);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Tile helpers //~ Tile helpers
@ -533,6 +519,11 @@ void P_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
void P_DebugDrawRect(Rng2 rect, Vec4 srgb); void P_DebugDrawRect(Rng2 rect, Vec4 srgb);
void P_DebugDrawShape(P_Shape shape, Vec4 srgb); void P_DebugDrawShape(P_Shape shape, Vec4 srgb);
////////////////////////////////////////////////////////////
//~ Msg
P_Msg *P_PushMsg(P_MsgKind kind, String data);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ World //~ World
@ -546,4 +537,4 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Step //~ Step
void P_StepFrame(P_Frame *frame, P_CmdList queued_cmds); void P_StepFrame(P_Frame *frame);

View File

@ -23,6 +23,7 @@ void S_TickForever(WaveLaneCtx *lane)
Arena *perm = PermArena(); Arena *perm = PermArena();
Arena *frame_arena = AcquireArena(Gibi(64)); Arena *frame_arena = AcquireArena(Gibi(64));
P_tl.debug_arena = AcquireArena(Gibi(64)); P_tl.debug_arena = AcquireArena(Gibi(64));
P_tl.out_msgs_arena = AcquireArena(Gibi(64));
P_World *world = P_AcquireWorld(); P_World *world = P_AcquireWorld();
@ -36,9 +37,9 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Header // FIXME: Header
Rng user_cmd_tick_range = RNG(SIM_TICKS_PER_SECOND * -SIM_MAX_PING, SIM_TICKS_PER_SECOND * SIM_MAX_PING); Rng user_msg_tick_range = RNG(SIM_TICKS_PER_SECOND * -SIM_MAX_PING, SIM_TICKS_PER_SECOND * SIM_MAX_PING);
P_CmdList queued_user_cmds = Zi; P_MsgList queued_user_msgs = Zi;
P_CmdNode *first_free_user_cmd_node = 0; P_MsgNode *first_free_user_msg_node = 0;
@ -67,95 +68,12 @@ void S_TickForever(WaveLaneCtx *lane)
P_Frame *world_frame = P_PushFrame(world, prev_world_frame, prev_world_frame->tick + 1); P_Frame *world_frame = P_PushFrame(world, prev_world_frame, prev_world_frame->tick + 1);
b32 tiles_dirty = 0; b32 tiles_dirty = 0;
// TDOO: Remove this // TODO: Remove this
// TODO: Keep old frames around for user snapshot deltas
P_ClearFrames(world, I64Min, prev_world_frame->tick - 1); P_ClearFrames(world, I64Min, prev_world_frame->tick - 1);
i64 frame_begin_ns = TimeNs(); i64 frame_begin_ns = TimeNs();
//////////////////////////////
//- Pop commands
P_InputState *input = 0;
LockTicketMutex(&P.sim_input_back_tm);
{
input = &P.sim_input_states[P.sim_input_back_idx];
++P.sim_input_back_idx;
if (P.sim_input_back_idx >= countof(P.sim_input_states))
{
P.sim_input_back_idx = 0;
}
}
UnlockTicketMutex(&P.sim_input_back_tm);
P_CmdList user_cmds = Zi;
{
i64 user_cmds_min_tick = world_frame->tick + user_cmd_tick_range.min;
i64 user_cmds_max_tick = world_frame->tick + user_cmd_tick_range.max;
// Prune queued user cmds
{
for (P_CmdNode *cmd_node = queued_user_cmds.first; cmd_node;)
{
P_CmdNode *next = cmd_node->next;
b32 prune = 0;
if (cmd_node->cmd.predicted && (cmd_node->cmd.tick < user_cmds_min_tick || cmd_node->cmd.tick > user_cmds_max_tick))
{
prune = 1;
}
if (prune)
{
DllQueueRemove(queued_user_cmds.first, queued_user_cmds.last, cmd_node);
SllStackPush(first_free_user_cmd_node, cmd_node);
--queued_user_cmds.count;
}
cmd_node = next;
}
}
// Push user cmds to queue
{
for (P_CmdNode *src_cmd_node = input->cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next)
{
if (!src_cmd_node->cmd.predicted || (src_cmd_node->cmd.tick >= user_cmds_min_tick && src_cmd_node->cmd.tick <= user_cmds_max_tick))
{
P_CmdNode *dst_cmd_node = first_free_user_cmd_node;
if (dst_cmd_node)
{
SllStackPop(first_free_user_cmd_node);
ZeroStruct(dst_cmd_node);
}
else
{
dst_cmd_node = PushStruct(perm, P_CmdNode);
}
dst_cmd_node->cmd = src_cmd_node->cmd;
DllQueuePush(queued_user_cmds.first, queued_user_cmds.last, dst_cmd_node);
++queued_user_cmds.count;
}
}
}
// Pop frame user cmds from queue
{
for (P_CmdNode *src_cmd_node = queued_user_cmds.first; src_cmd_node;)
{
P_CmdNode *next = src_cmd_node->next;
if (!src_cmd_node->cmd.predicted || src_cmd_node->cmd.tick == world_frame->tick)
{
{
P_CmdNode *dst_cmd_node = PushStruct(frame_arena, P_CmdNode);
dst_cmd_node->cmd = src_cmd_node->cmd;
DllQueuePush(user_cmds.first, user_cmds.last, dst_cmd_node);
++user_cmds.count;
}
{
DllQueueRemove(queued_user_cmds.first, queued_user_cmds.last, src_cmd_node);
SllStackPush(first_free_user_cmd_node, src_cmd_node);
--queued_user_cmds.count;
}
}
src_cmd_node = next;
}
}
}
////////////////////////////// //////////////////////////////
//- Swap //- Swap
@ -208,67 +126,257 @@ void S_TickForever(WaveLaneCtx *lane)
} }
////////////////////////////// //////////////////////////////
//- Process user edit commands //- Pop messages from user
// FIXME: Only accept world deltas from users that can edit P_MsgList in_msgs = Zi;
{
LockTicketMutex(&P.u2s_msgs_mutex);
{
for (P_MsgNode *src_msg_node = P.u2s_msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
{
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
P_Msg *src_msg = &src_msg_node->msg;
P_Msg *dst_msg = &dst_msg_node->msg;
*dst_msg = *src_msg;
dst_msg->data = PushString(frame_arena, src_msg->data);
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
++in_msgs.count;
}
ResetArena(P.u2s_msgs_arena);
ZeroStruct(&P.u2s_msgs);
}
UnlockTicketMutex(&P.u2s_msgs_mutex);
}
// FIXME: Only apply relevant cmds based on tick //////////////////////////////
//- Register users
{ {
b32 should_save = 0; for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
for (P_CmdNode *cmd_node = user_cmds.first; cmd_node; cmd_node = cmd_node->next)
{ {
P_Cmd *cmd = &cmd_node->cmd; P_Msg *msg = &msg_node->msg;
b32 allow = 0;
if (cmd->kind == P_CmdKind_SaveWorld) P_Key user_key = msg->src_user;
P_Ent *user = P_EntFromKey(world_frame, user_key);
if (P_EntIsNil(user))
{ {
// FIXME: Only accept save from local user P_EntList tmp_list = Zi;
should_save = 1; user = P_PushTempEnt(frame_arena, &tmp_list);
} user->key = user_key;
if (cmd->kind == P_CmdKind_ResetWorld) user->is_user = 1;
{ user->exists = 1;
// TODO: Real reset
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) i32 min_name_len = 3;
i32 max_name_len = countof(user->string_text) - 8;
// De-duplicate user name
String user_name = msg->data;
user_name = TrimWhitespace(user_name);
user_name.len = MinI64(user_name.len, max_name_len);
user_name = TrimWhitespace(user_name);
if (user_name.len < min_name_len)
{ {
ent->exists = 0; user_name = Lit("Player");
} }
}
if (cmd->kind == P_CmdKind_EntEdit)
{
P_EntList ents = Zi;
P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
*dst = cmd->ent;
P_SpawnEntsFromList(world_frame, ents);
}
if (cmd->kind == P_CmdKind_TileEdit)
{
P_TileKind tile = cmd->tile_kind;
Rng2I32 range = cmd->tile_range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{ {
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x) String orig_user_name = user_name;
i64 duplicate_id = 0;
while (duplicate_id < 1000)
{ {
Vec2 tile_pos = VEC2(tile_x, tile_y); b32 is_duplicate = 0;
i32 tile_idx = P_TileIdxFromTilePos(tile_pos); for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
world->tiles[tile_idx] = (u8)tile; {
} if (ent->is_user && MatchString(P_StringFromEnt(ent), user_name))
} {
// Hash tiles is_duplicate = 1;
{ break;
u64 old_tiles_hash = world->tiles_hash; }
world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles)); }
if (world->tiles_hash != old_tiles_hash) if (is_duplicate)
{ {
tiles_dirty = 1; duplicate_id += 1;
user_name = StringF(frame_arena, "%F (%F)", FmtString(orig_user_name), FmtSint(duplicate_id));
}
else
{
break;
}
} }
} }
P_SetEntString(user, user_name);
P_Msg *msg = P_PushMsg(
P_MsgKind_Chat,
StringF(
frame_arena,
"Player %F connected",
FmtString(user_name)
));
)
P_SpawnEntsFromList(world_frame, tmp_list);
}
{
P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr);
msg->dst_user = user->key;
} }
} }
// Save world }
if (should_save)
//////////////////////////////
//- Apply user snapshots
// P_MsgList user_msgs = Zi;
// {
// i64 user_msgs_min_tick = world_frame->tick + user_msg_tick_range.min;
// i64 user_msgs_max_tick = world_frame->tick + user_msg_tick_range.max;
// // Prune queued user msgs
// {
// for (P_MsgNode *msg_node = queued_user_msgs.first; msg_node;)
// {
// P_MsgNode *next = msg_node->next;
// b32 prune = 0;
// if (msg_node->msg.predicted && (msg_node->msg.tick < user_msgs_min_tick || msg_node->msg.tick > user_msgs_max_tick))
// {
// prune = 1;
// }
// if (prune)
// {
// DllQueueRemove(queued_user_msgs.first, queued_user_msgs.last, msg_node);
// SllStackPush(first_free_user_msg_node, msg_node);
// --queued_user_msgs.count;
// }
// msg_node = next;
// }
// }
// // Push user msgs to queue
// {
// for (P_MsgNode *src_msg_node = input->msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
// {
// if (!src_msg_node->msg.predicted || (src_msg_node->msg.tick >= user_msgs_min_tick && src_msg_node->msg.tick <= user_msgs_max_tick))
// {
// P_MsgNode *dst_msg_node = first_free_user_msg_node;
// if (dst_msg_node)
// {
// SllStackPop(first_free_user_msg_node);
// ZeroStruct(dst_msg_node);
// }
// else
// {
// dst_msg_node = PushStruct(perm, P_MsgNode);
// }
// dst_msg_node->msg = src_msg_node->msg;
// DllQueuePush(queued_user_msgs.first, queued_user_msgs.last, dst_msg_node);
// ++queued_user_msgs.count;
// }
// }
// }
// // Pop frame user msgs from queue
// {
// for (P_MsgNode *src_msg_node = queued_user_msgs.first; src_msg_node;)
// {
// P_MsgNode *next = src_msg_node->next;
// if (!src_msg_node->msg.predicted || src_msg_node->msg.tick == world_frame->tick)
// {
// {
// P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
// dst_msg_node->msg = src_msg_node->msg;
// DllQueuePush(user_msgs.first, user_msgs.last, dst_msg_node);
// ++user_msgs.count;
// }
// {
// DllQueueRemove(queued_user_msgs.first, queued_user_msgs.last, src_msg_node);
// SllStackPush(first_free_user_msg_node, src_msg_node);
// --queued_user_msgs.count;
// }
// }
// src_msg_node = next;
// }
// }
// }
//////////////////////////////
//- Process user edit messages
// FIXME: Only accept edits from privileged users
// {
// b32 should_save = 0;
// for (P_MsgNode *msg_node = user_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// b32 allow = 0;
// if (msg->kind == P_MsgKind_SaveWorld)
// {
// // FIXME: Only accept save from local user
// should_save = 1;
// }
// if (msg->kind == P_MsgKind_ResetWorld)
// {
// // TODO: Real reset
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// {
// ent->exists = 0;
// }
// }
// if (msg->kind == P_MsgKind_EntEdit)
// {
// P_EntList ents = Zi;
// P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
// *dst = msg->ent;
// P_SpawnEntsFromList(world_frame, ents);
// }
// if (msg->kind == P_MsgKind_TileEdit)
// {
// P_TileKind tile = msg->tile_kind;
// Rng2I32 range = msg->tile_range;
// for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
// {
// for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
// {
// Vec2 tile_pos = VEC2(tile_x, tile_y);
// i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
// world->tiles[tile_idx] = (u8)tile;
// }
// }
// // Hash tiles
// {
// u64 old_tiles_hash = world->tiles_hash;
// world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles));
// if (world->tiles_hash != old_tiles_hash)
// {
// tiles_dirty = 1;
// }
// }
// }
// }
// // Save world
// if (should_save)
// {
// String path = Lit("...");
// LogInfoF("Saving world to %F", FmtString(path));
// }
// }
//////////////////////////////
//- Update ent controls
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
ent->fire_presses = 0;
}
for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user))
{
if (user->is_iser)
{ {
String path = Lit("..."); P_Ent *target = P_EntFromKey(user->player);
LogInfoF("Saving world to %F", FmtString(path)); if (!P_IsEntNil(target))
{
target->move = ClampVec2Len(user->move, 1);
target->look = user->look;
target->fire_held = user->fire_held;
target->fire_presses += user->fire_presses;
}
} }
} }
@ -276,12 +384,23 @@ void S_TickForever(WaveLaneCtx *lane)
//- Step frame //- Step frame
{ {
P_StepFrame(world_frame, user_cmds); P_StepFrame(world_frame, user_msgs);
} }
////////////////////////////// //////////////////////////////
//- Publish sim state //- Publish sim state
for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
{
if (user->is_user)
{
P_Frame *src_frame = P_FrameFromTick(world, user->acked_tick);
if (user->is_local)
{
}
}
}
// TODO: Only copy active entities // TODO: Only copy active entities
LockTicketMutex(&P.sim_output_back_tm); LockTicketMutex(&P.sim_output_back_tm);
{ {

View File

@ -33,6 +33,14 @@ String P_PackWorld(Arena *arena, P_World *src_world)
{ {
result.len += PushString(arena, Lit(" player\n")).len; result.len += PushString(arena, Lit(" player\n")).len;
} }
if (ent->is_dummy)
{
result.len += PushString(arena, Lit(" dummy\n")).len;
}
if (ent->has_weapon)
{
result.len += PushString(arena, Lit(" has_weapon\n")).len;
}
if (ent->is_bullet) if (ent->is_bullet)
{ {
result.len += PushString(arena, Lit(" bullet\n")).len; result.len += PushString(arena, Lit(" bullet\n")).len;
@ -120,6 +128,13 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
if (MatchString(prop->value, Lit("player"))) if (MatchString(prop->value, Lit("player")))
{ {
ent->is_player = 1; ent->is_player = 1;
}
if (MatchString(prop->value, Lit("dummy")))
{
ent->is_dummy = 1;
}
if (MatchString(prop->value, Lit("has_weapon")))
{
ent->has_weapon = 1; ent->has_weapon = 1;
} }
if (MatchString(prop->value, Lit("bullet"))) if (MatchString(prop->value, Lit("bullet")))

View File

@ -41,25 +41,6 @@ V_Cmd *V_PushVisCmd(String name)
return cmd; return cmd;
} }
P_Cmd *V_PushSimCmd(P_CmdKind kind)
{
Arena *perm = PermArena();
P_CmdNode *n = V.first_free_sim_cmd_node;
if (n)
{
SllStackPop(V.first_free_sim_cmd_node);
ZeroStruct(n);
}
else
{
n = PushStruct(perm, P_CmdNode);
}
n->cmd.kind = kind;
DllQueuePush(V.sim_cmds.first, V.sim_cmds.last, n);
++V.sim_cmds.count;
return &n->cmd;
}
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey) String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
@ -345,7 +326,7 @@ void V_PushNotif(String msg)
notif->seq = V.first_notif->seq + 1; notif->seq = V.first_notif->seq + 1;
} }
SllQueuePushFront(V.first_notif, V.last_notif, notif); SllQueuePushFront(V.first_notif, V.last_notif, notif);
LogInfoF("Notif: %F", FmtString(notif->msg)); LogInfoF("[Notif] %F", FmtString(notif->msg));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -356,6 +337,7 @@ void V_TickForever(WaveLaneCtx *lane)
Arena *perm = PermArena(); Arena *perm = PermArena();
G_ArenaHandle gpu_perm = G_PermArena(); G_ArenaHandle gpu_perm = G_PermArena();
P_tl.debug_arena = AcquireArena(Gibi(64)); P_tl.debug_arena = AcquireArena(Gibi(64));
P_tl.out_msgs_arena = AcquireArena(Gibi(64));
const i32 world_pitch = P_WorldPitch; const i32 world_pitch = P_WorldPitch;
const f32 zoom_rate = 1.50; const f32 zoom_rate = 1.50;
@ -366,9 +348,8 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Init vis state //- Init vis state
Arena *sim_debug_arena = AcquireArena(Gibi(64)); Arena *sim_snapshot_arena = AcquireArena(Gibi(64));
P_DebugDrawNode *first_sim_debug_draw_node = 0; P_SimSnapshot sim_snapshot = Zi;
P_DebugDrawNode *last_sim_debug_draw_node = 0;
P_World *sim_world = P_AcquireWorld(); P_World *sim_world = P_AcquireWorld();
P_World *predict_world = P_AcquireWorld(); P_World *predict_world = P_AcquireWorld();
@ -562,9 +543,9 @@ void V_TickForever(WaveLaneCtx *lane)
frame->dt = SecondsFromNs(frame->dt_ns); frame->dt = SecondsFromNs(frame->dt_ns);
frame->rand = prev_frame->rand; frame->rand = prev_frame->rand;
if (P_IsKeyNil(V.player_key)) if (P_IsKeyNil(V.user_key))
{ {
V.player_key = P_RandKey(); TrueRand(StringFromStruct(&V.user_key));
} }
////////////////////////////// //////////////////////////////
@ -596,7 +577,7 @@ void V_TickForever(WaveLaneCtx *lane)
//- Transcode swap state //- Transcode swap state
if (swapout) if (swapout)
{ {
BB_WriteUBits(&bw, V.player_key.v, 64); BB_WriteUBits(&bw, V.user_key.v, 64);
BB_WriteBit(&bw, prev_frame->is_editing); BB_WriteBit(&bw, prev_frame->is_editing);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.x); BB_WriteF32(&bw, prev_frame->edit_camera_pos.x);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.y); BB_WriteF32(&bw, prev_frame->edit_camera_pos.y);
@ -605,7 +586,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
else else
{ {
V.player_key.v = BB_ReadUBits(&br, 64); V.user_key.v = BB_ReadUBits(&br, 64);
frame->is_editing = BB_ReadBit(&br); frame->is_editing = BB_ReadBit(&br);
frame->edit_camera_pos.x = BB_ReadF32(&br); frame->edit_camera_pos.x = BB_ReadF32(&br);
frame->edit_camera_pos.y = BB_ReadF32(&br); frame->edit_camera_pos.y = BB_ReadF32(&br);
@ -788,7 +769,8 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 look_ratio = Zi; Vec2 look_ratio = Zi;
look_ratio.y = 0.5; look_ratio.y = 0.5;
look_ratio.x = look_ratio.y / (16.0 / 9.0); look_ratio.x = look_ratio.y / (16.0 / 9.0);
P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key); P_Ent *user = P_EntFromKey(blend_world->last_frame, V.user_key);
P_Ent *player = P_EntFromKey(blend_world->last_frame, user->player);
Vec2 player_center = P_WorldShapeFromEnt(player).centroid; Vec2 player_center = P_WorldShapeFromEnt(player).centroid;
Vec2 ui_center = MulVec2(frame->ui_dims, 0.5); Vec2 ui_center = MulVec2(frame->ui_dims, 0.5);
Vec2 look = MulXformBasisV2(prev_frame->xf.ui_to_world, SubVec2(ui_frame->cursor_pos, ui_center)); Vec2 look = MulXformBasisV2(prev_frame->xf.ui_to_world, SubVec2(ui_frame->cursor_pos, ui_center));
@ -934,16 +916,17 @@ void V_TickForever(WaveLaneCtx *lane)
tile_range.p0 = Vec2I32FromVec(FloorVec2(MulXformV2(frame->xf.world_to_tile, prev_frame->world_selection.p0))); tile_range.p0 = Vec2I32FromVec(FloorVec2(MulXformV2(frame->xf.world_to_tile, prev_frame->world_selection.p0)));
tile_range.p1 = Vec2I32FromVec(CeilVec2(MulXformV2(frame->xf.world_to_tile, prev_frame->world_selection.p1))); tile_range.p1 = Vec2I32FromVec(CeilVec2(MulXformV2(frame->xf.world_to_tile, prev_frame->world_selection.p1)));
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_TileEdit); P_Msg *msg = P_PushMsg(P_MsgKind_TileEdit, Zstr);
cmd->tile_kind = prev_frame->equipped_tile; msg->tile_kind = prev_frame->equipped_tile;
cmd->tile_range = tile_range; msg->tile_range = tile_range;
} }
} }
////////////////////////////// //////////////////////////////
//- Query entities //- Query entities
P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key); P_Ent *user = P_EntFromKey(blend_world->last_frame, V.user_key);
P_Ent *player = P_EntFromKey(blend_world->last_frame, user->player);
P_Ent *hovered_ent = &P_NilEnt; P_Ent *hovered_ent = &P_NilEnt;
{ {
// TODO: Real world query // TODO: Real world query
@ -2566,62 +2549,63 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} break; } break;
case V_CmdKind_reset_world: // case V_CmdKind_reset_world:
case V_CmdKind_spawn: // case V_CmdKind_spawn:
{ // {
// Reset world // // Reset world
Vec2 player_pos = VEC2(5, 0); // Vec2 player_pos = VEC2(5, 0);
if (kind == V_CmdKind_reset_world) // if (kind == V_CmdKind_reset_world)
{ // {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_ResetWorld); // P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr);
} // }
else // else
{ // {
player_pos = frame->world_cursor; // player_pos = frame->world_cursor;
} // }
// Spawn player // // Spawn player
{ // {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit); // P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr);
P_Ent *ent = &cmd->ent; // P_Ent *ent = &cmd->ent;
*ent = P_NilEnt; // *ent = P_NilEnt;
ent->key = V.player_key; // ent->key = V.player_key;
ent->xf = XformFromPos(player_pos); // ent->xf = XformFromPos(player_pos);
ent->is_player = 1; // ent->is_player = 1;
ent->has_weapon = 1; // ent->has_weapon = 1;
ent->exists = 1; // ent->exists = 1;
} // }
} break; // } break;
case V_CmdKind_spawn_dummy: // case V_CmdKind_spawn_dummy:
{ // {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit); // P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr);
P_Ent *ent = &cmd->ent; // P_Ent *ent = &cmd->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->has_weapon = 1; // ent->is_dummy = 1;
ent->exists = 1; // ent->has_weapon = 1;
} break; // ent->exists = 1;
// } break;
case V_CmdKind_delete: // case V_CmdKind_delete:
{ // {
if (!P_IsEntNil(hovered_ent)) // if (!P_IsEntNil(hovered_ent))
{ // {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit); // P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr);
P_Ent *ent = &cmd->ent; // P_Ent *ent = &cmd->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:
{ // {
if (frame->is_editing) // if (frame->is_editing)
{ // {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_SaveWorld); // P_Msg *msg = P_PushMsg(P_MsgKind_SaveWorld, Zstr);
} // }
} break; // } break;
// case V_CmdKind_clear_particles: // case V_CmdKind_clear_particles:
// { // {
@ -2635,9 +2619,169 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
//////////////////////////////
//- Pop messages from sim
P_MsgList in_msgs = Zi;
{
LockTicketMutex(&P.s2u_msgs_mutex);
{
for (P_MsgNode *src_msg_node = P.s2u_msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
{
P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
P_Msg *src_msg = &src_msg_node->msg;
P_Msg *dst_msg = &dst_msg_node->msg;
*dst_msg = *src_msg;
dst_msg->data = PushString(frame->arena, src_msg->data);
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
++in_msgs.count;
}
ResetArena(P.s2u_msgs_arena);
ZeroStruct(&P.s2u_msgs);
}
UnlockTicketMutex(&P.s2u_msgs_mutex);
}
//////////////////////////////
//- Pop snapshot from sim
{
LockTicketMutex(&P.s2u_snapshot_mutex);
P_SimSnapshot *src_snapshot = &P.s2u_snapshot;
if (src_snapshot->tick > sim_snapshot.tick)
{
ResetArena(sim_snapshot_arena);
ZeroStruct(&sim_snapshot);
sim_snapshot.world_seed = src_snapshot->world_seed;
sim_snapshot.src_tick = src_snapshot->src_tick;
sim_snapshot.tick = src_snapshot->tick;
sim_snapshot.time_ns = src_snapshot->time_ns;
{
//- Copy deltas
{
P_SimDeltaNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_SimDeltaNode, src_snapshot->deltas_count);
for (P_SimDeltaNode *src_delta_node = src_snapshot->first_delta_node; src_delta_node; src_delta_node = src_delta_node->next)
{
P_SimDeltaNode *dst_delta_node = &dst_nodes[sim_snapshot.deltas_count];
*dst_delta_node = *src_delta_node;
SllQueuePush(sim_snapshot.first_delta_node, sim_snapshot.last_delta_node, dst_delta_node);
sim_snapshot.deltas_count += 1;
}
}
//- Copy debug info
{
P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_DebugDrawNode, src_snapshot->debug_draw_nodes_count);
for (P_DebugDrawNode *src = src_snapshot->first_debug_draw_node; src; src = src->next)
{
P_DebugDrawNode *dst = &dst_nodes[sim_snapshot.debug_draw_nodes_count];
*dst = *src;
SllQueuePush(sim_snapshot.first_debug_draw_node, sim_snapshot.last_debug_draw_node, dst);
sim_snapshot.debug_draw_nodes_count += 1;
}
}
}
ResetArena(P.s2u_snapshot_arena);
ZeroStruct(&P.s2u_snapshot);
}
UnlockTicketMutex(&P.s2u_snapshot_mutex);
}
//////////////////////////////
//- Apply sim msgs
{
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
//- Chat
// if (msg->kind == P_MsgKind_Chat)
// {
// }
//- Tiles
if (msg->kind == P_MsgKind_Tiles && sim_world->tiles_hash != msg->tiles_hash)
{
// TODO: Remove this check. Allow non-whole-map tile ranges.
Rng2I32 range = msg->tile_range;
if (msg->data.len == P_TilesCount)
{
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{
i32 src_tile_y = tile_y - range.p0.y;
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{
i32 src_tile_x = tile_x - range.p0.x;
Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y);
i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos);
u8 src_tile = msg->data.text[src_tile_idx];
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
sim_world->tiles_hash = msg->tiles_hash;
sim_world->tiles[tile_idx] = src_tile;
}
}
}
}
}
}
//////////////////////////////
//- Apply sim snapshots
// if (sim_snapshot.tick > sim_world->last_frame->tick)
// {
// P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
// P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
// sim_world->seed = snapshot->world_seed;
// dst_frame->time_ns = snapshot->time_ns;
// //- Apply deltas
// for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
// {
// P_SimDelta *delta = &dn->delta;
// //- Raw ent
// if (delta->kind == P_SimDeltaKind_RawEnt)
// {
// P_Ent tmp_ent = delta->ent;
// P_EntListNode tmp_ent_node = Zi;
// tmp_ent_node.ent = tmp_ent;
// P_EntList ent_list = Zi;
// ent_list.first = &tmp_ent_node;
// ent_list.last = &tmp_ent_node;
// P_SpawnEntsFromList(dst_frame, ent_list);
// }
// }
// //- Update sim debug info
// {
// ResetArena(sim_debug_arena);
// first_sim_debug_draw_node = 0;
// last_sim_debug_draw_node = 0;
// {
// i64 dst_idx = 0;
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
// for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
// {
// P_DebugDrawNode *dst = &dst_nodes[dst_idx];
// *dst = *src;
// dst_idx += 1;
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
// }
// }
// }
// }
// TODO: Remove this
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
P_Frame *sim_frame = sim_world->last_frame;
////////////////////////////// //////////////////////////////
//- Compute movement & look //- Compute movement & look
if (frame->predict_to != prev_frame->predict_to)
{ {
Vec2 move = Zi; Vec2 move = Zi;
{ {
@ -2671,122 +2815,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
////////////////////////////// //////////////////////////////
//- Pop sim output //- Push user snapshot
P_OutputState *sim_output = 0;
LockTicketMutex(&P.sim_output_back_tm);
{
sim_output = &P.sim_output_states[P.sim_output_back_idx];
++P.sim_output_back_idx;
if (P.sim_output_back_idx >= countof(P.sim_output_states))
{
P.sim_output_back_idx = 0;
}
}
UnlockTicketMutex(&P.sim_output_back_tm);
//////////////////////////////
//- Apply sim msgs
// Apply msgs
{
for (P_MsgNode *msg_node = sim_output->msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
//- Chat
// if (msg->kind == P_MsgKind_Chat)
// {
// }
//- Tiles
if (msg->kind == P_MsgKind_Tiles && sim_world->tiles_hash != msg->tiles_hash)
{
Rng2I32 range = msg->tile_range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{
i32 src_tile_y = tile_y - range.p0.y;
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{
i32 src_tile_x = tile_x - range.p0.x;
Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y);
i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos);
u8 src_tile = msg->raw_tiles[src_tile_idx];
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
sim_world->tiles_hash = msg->tiles_hash;
sim_world->tiles[tile_idx] = src_tile;
}
}
}
}
}
//////////////////////////////
//- Apply sim snapshots
{
P_Snapshot *snapshot = &sim_output->snapshot;
b32 skip_snapshot = 0;
skip_snapshot = snapshot->tick < sim_world->last_frame->tick;
if (!skip_snapshot)
{
P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
sim_world->seed = snapshot->world_seed;
dst_frame->time_ns = snapshot->time_ns;
//- Apply deltas
for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
{
P_Delta *delta = &dn->delta;
//- Raw ent
if (delta->kind == P_DeltaKind_RawEnt)
{
P_Ent tmp_ent = delta->ent;
P_EntListNode tmp_ent_node = Zi;
tmp_ent_node.ent = tmp_ent;
P_EntList ent_list = Zi;
ent_list.first = &tmp_ent_node;
ent_list.last = &tmp_ent_node;
P_SpawnEntsFromList(dst_frame, ent_list);
}
}
//- Update sim debug info
{
ResetArena(sim_debug_arena);
first_sim_debug_draw_node = 0;
last_sim_debug_draw_node = 0;
{
i64 dst_idx = 0;
P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
{
P_DebugDrawNode *dst = &dst_nodes[dst_idx];
*dst = *src;
dst_idx += 1;
SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
}
}
}
}
}
// TODO: Remove this
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
P_Frame *sim_frame = sim_world->last_frame;
//////////////////////////////
//- Submit sim commands
// FIXME: Real ping // FIXME: Real ping
// f64 ping = 0.250; // f64 ping = 0.250;
@ -2794,27 +2823,31 @@ void V_TickForever(WaveLaneCtx *lane)
i64 ping_ns = NsFromSeconds(ping); i64 ping_ns = NsFromSeconds(ping);
frame->predict_to = sim_world->last_frame->tick + MaxF64(CeilF64(ping * SIM_TICKS_PER_SECOND), 1.0); frame->predict_to = sim_world->last_frame->tick + MaxF64(CeilF64(ping * SIM_TICKS_PER_SECOND), 1.0);
if (frame->predict_to != prev_frame->predict_to)
b32 should_send_sim_cmds = frame->predict_to != prev_frame->predict_to;
if (should_send_sim_cmds)
{ {
// Push control cmd
{ {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Control); P_UserSnapshot snapshot = Zi;
cmd->predicted = 1; snapshot->user = V.user_user;
cmd->target = V.player_key; snapshot->src_tick = 0;
cmd->move = frame->move; // FIXME: Generate snapshots for all new frames, not just last
cmd->look = frame->look; snapshot->tick = frame->predict_to;
cmd->fire_held = frame->fire_held; snapshot->move = frame->move;
cmd->fire_presses = frame->fire_presses; snapshot->look = frame->look;
snapshot->fire_held = frame->fire_held;
snapshot->fire_presses = frame->fire_presses;
} }
}
//////////////////////////////
//- Submit sim commands
{
LockTicketMutex(&P.sim_input_back_tm); LockTicketMutex(&P.sim_input_back_tm);
{ {
P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx]; P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx];
for (P_CmdNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next) for (P_MsgNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next)
{ {
P_CmdNode *dst_cmd_node = PushStruct(v2s->arena, P_CmdNode); P_MsgNode *dst_cmd_node = PushStruct(v2s->arena, P_MsgNode);
dst_cmd_node->cmd = src_cmd_node->cmd; dst_cmd_node->cmd = src_cmd_node->cmd;
dst_cmd_node->cmd.tick = frame->predict_to; dst_cmd_node->cmd.tick = frame->predict_to;
DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node); DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node);
@ -2855,12 +2888,12 @@ void V_TickForever(WaveLaneCtx *lane)
// P_Frame *step_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_world->last_frame->tick + 1); // P_Frame *step_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_world->last_frame->tick + 1);
// // FIXME: Cmds // // FIXME: Cmds
// P_CmdList step_cmds = Zi; // P_MsgList step_cmds = Zi;
// for (P_CmdNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next) // for (P_MsgNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next)
// { // {
// if (src_cmd_node->cmd.predicted && src_cmd_node->cmd.tick == step_frame->tick) // if (src_cmd_node->cmd.predicted && src_cmd_node->cmd.tick == step_frame->tick)
// { // {
// P_CmdNode *dst_cmd_node = PushStruct(frame->arena, P_CmdNode); // P_MsgNode *dst_cmd_node = PushStruct(frame->arena, P_MsgNode);
// DllQueuePush(step_cmds.first, step_cmds.last, dst_cmd_node); // DllQueuePush(step_cmds.first, step_cmds.last, dst_cmd_node);
// ++step_cmds.count; // ++step_cmds.count;
// } // }
@ -2921,22 +2954,6 @@ void V_TickForever(WaveLaneCtx *lane)
// } // }
//////////////////////////////
//- Reset queued sim cmds
if (should_send_sim_cmds)
{
if (V.sim_cmds.first)
{
V.sim_cmds.last->next = V.first_free_sim_cmd_node;
V.first_free_sim_cmd_node = V.sim_cmds.first;
}
V.sim_cmds.first = 0;
V.sim_cmds.last = 0;
V.sim_cmds.count = 0;
}
@ -3670,7 +3687,26 @@ void V_TickForever(WaveLaneCtx *lane)
} }
////////////////////////////// //////////////////////////////
//- Prune ents //- Prune sim cmds
{
for (P_MsgNode *msg_node = V.sim_cmds.first; cmd_node;)
{
P_MsgNode *next = cmd_node->next;
{
if (!cmd_node->cmd.predicted || cmd_node->cmd.tick <= sim_world->last_frame->tick)
{
DllQueueRemove(V.sim_cmds.first, V.sim_cmds.last, cmd_node);
SllStackPush(V.first_free_sim_cmd_node, cmd_node);
--V.sim_cmds.count;
}
}
cmd_node = next;
}
}
//////////////////////////////
//- Prune sim ents
{ {
i64 ents_to_prune_count = 0; i64 ents_to_prune_count = 0;

View File

@ -298,7 +298,7 @@ Struct(V_Frame)
Struct(V_Ctx) Struct(V_Ctx)
{ {
P_Key player_key; P_Key user_key;
i64 panels_count; i64 panels_count;
i64 windows_count; i64 windows_count;
@ -309,10 +309,6 @@ Struct(V_Ctx)
V_Notif *first_notif; V_Notif *first_notif;
V_Notif *last_notif; V_Notif *last_notif;
// Sim commands
P_CmdList sim_cmds;
P_CmdNode *first_free_sim_cmd_node;
// Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer // Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer
u32 particle_seq; u32 particle_seq;
@ -337,7 +333,6 @@ void V_Shutdown(void);
V_Frame *V_CurrentFrame(void); V_Frame *V_CurrentFrame(void);
V_Frame *V_PrevFrame(void); V_Frame *V_PrevFrame(void);
V_Cmd *V_PushVisCmd(String name); V_Cmd *V_PushVisCmd(String name);
P_Cmd *V_PushSimCmd(P_CmdKind kind);
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey); String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
void V_PushParticles(V_Emitter src); void V_PushParticles(V_Emitter src);