queue user cmds from sim

This commit is contained in:
jacob 2026-01-13 11:58:37 -06:00
parent 25a8a3c39a
commit db7cbad4b3
6 changed files with 450 additions and 321 deletions

View File

@ -890,11 +890,13 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
G_D12_Resource *resource = 0; G_D12_Resource *resource = 0;
b32 is_buffer = desc.kind == G_ResourceKind_Buffer; b32 is_buffer = desc.kind == G_ResourceKind_Buffer;
b32 is_texture = desc.kind == G_ResourceKind_Texture1D || b32 is_texture=
desc.kind == G_ResourceKind_Texture1D ||
desc.kind == G_ResourceKind_Texture2D || desc.kind == G_ResourceKind_Texture2D ||
desc.kind == G_ResourceKind_Texture3D; desc.kind == G_ResourceKind_Texture3D;
b32 is_sampler = desc.kind == G_ResourceKind_Sampler; b32 is_sampler = desc.kind == G_ResourceKind_Sampler;
G_ResourceFlag flags = is_buffer ? desc.buffer.flags : G_ResourceFlag flags =
is_buffer ? desc.buffer.flags :
is_texture ? desc.texture.flags : is_texture ? desc.texture.flags :
desc.sampler.flags; desc.sampler.flags;

View File

@ -7,7 +7,8 @@ Readonly P_Ent P_NilEnt = {
}; };
Readonly P_Frame P_NilFrame = { Readonly P_Frame P_NilFrame = {
0 .first_ent = &P_NilEnt,
.last_ent = &P_NilEnt,
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -1056,7 +1057,7 @@ P_Ent *P_EntFromKey(P_Frame *frame, P_Key key)
P_Ent *P_FirstEnt(P_Frame *frame) P_Ent *P_FirstEnt(P_Frame *frame)
{ {
P_Ent *result = &P_NilEnt; P_Ent *result = &P_NilEnt;
if (frame->first_ent) if (!P_IsEntNil(frame->first_ent))
{ {
result = frame->first_ent; result = frame->first_ent;
} }
@ -1066,7 +1067,7 @@ P_Ent *P_FirstEnt(P_Frame *frame)
P_Ent *P_NextEnt(P_Ent *e) P_Ent *P_NextEnt(P_Ent *e)
{ {
P_Ent *result = &P_NilEnt; P_Ent *result = &P_NilEnt;
if (e && e->next) if (!P_IsEntNil(e) && !P_IsEntNil(e->next))
{ {
result = e->next; result = e->next;
} }
@ -1164,7 +1165,7 @@ P_World *P_AcquireWorld(void)
world->first_frame = &P_NilFrame; world->first_frame = &P_NilFrame;
world->last_frame = &P_NilFrame; world->last_frame = &P_NilFrame;
world->frame_bins_count = Kibi(1); world->frame_bins_count = Kibi(16);
world->frame_bins = PushStructs(world->arena, P_FrameBin, world->frame_bins_count); world->frame_bins = PushStructs(world->arena, P_FrameBin, world->frame_bins_count);
// TODO // TODO
@ -1189,8 +1190,6 @@ void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots)
world->seed = snapshot->world_seed; world->seed = snapshot->world_seed;
frame->time_ns = snapshot->time_ns; frame->time_ns = snapshot->time_ns;
if (frame->ents_count == 0)
{
for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
{ {
P_Delta *delta = &dn->delta; P_Delta *delta = &dn->delta;
@ -1199,16 +1198,16 @@ void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots)
{ {
} }
//- Reset //- Reset
else if (delta->kind == P_DeltaKind_Reset) // else if (delta->kind == P_DeltaKind_Reset)
{ // {
// FIXME: Free list entities // // FIXME: Freelist entities
frame->ents_count = 0; // frame->ents_count = 0;
frame->first_ent = 0; // frame->first_ent = 0;
frame->last_ent = 0; // frame->last_ent = 0;
ZeroStructs(world->tiles, P_TilesCount); // ZeroStructs(world->tiles, P_TilesCount);
ZeroStructs(frame->ent_bins, frame->ent_bins_count); // ZeroStructs(frame->ent_bins, frame->ent_bins_count);
tiles_dirty = 1; // tiles_dirty = 1;
} // }
//- Raw ent //- Raw ent
else if (delta->kind == P_DeltaKind_RawEnt) else if (delta->kind == P_DeltaKind_RawEnt)
{ {
@ -1242,21 +1241,21 @@ void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots)
tiles_dirty = 1; tiles_dirty = 1;
} }
//- Tile range //- Tile range
else if (delta->kind == P_DeltaKind_Tile) // else if (delta->kind == P_DeltaKind_Tile)
{ // {
P_TileKind tile = delta->tile_kind; // P_TileKind tile = delta->tile_kind;
Rng2I32 range = delta->tile_range; // Rng2I32 range = delta->tiles_range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y) // 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) // for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{ // {
Vec2 tile_pos = VEC2(tile_x, tile_y); // Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos); // i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
world->tiles[tile_idx] = (u8)tile; // world->tiles[tile_idx] = (u8)tile;
} // }
} // }
tiles_dirty = 1; // tiles_dirty = 1;
} // }
} }
@ -1267,7 +1266,6 @@ void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots)
// } // }
} }
} }
}
// TODO: Rehash statics // TODO: Rehash statics
// if (tiles_dirty) // if (tiles_dirty)
@ -1295,9 +1293,16 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
} }
if (!dst) if (!dst)
{ {
// FIXME: Use free list dst = world->first_free_ent;
dst = PushStructNoZero(world->arena, P_Ent); if (dst)
DllQueuePush(frame->first_ent, frame->last_ent, dst); {
SllStackPop(world->first_free_ent);
}
else
{
dst = PushStructNoZero(world->frames_arena, P_Ent);
}
DllQueuePushNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, dst, next, prev);
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
} }
P_Ent *old_next = dst->next; P_Ent *old_next = dst->next;
@ -1345,14 +1350,18 @@ void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max)
P_Frame *next_frame = frame->next; P_Frame *next_frame = frame->next;
if (frame->tick >= tick_min && frame->tick <= tick_max) if (frame->tick >= tick_min && frame->tick <= tick_max)
{ {
// FIXME: Freelist ents if (!P_IsEntNil(frame->first_ent))
{
// FIXME: Freelist frame frame->last_ent->next = world->first_free_ent;
world->first_free_ent = frame->first_ent;
}
u64 hash = MixU64(frame->tick); u64 hash = MixU64(frame->tick);
P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count]; P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count];
DllQueueRemoveNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev); DllQueueRemoveNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev);
DllQueueRemoveNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin); DllQueueRemoveNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin);
SllStackPush(world->first_free_frame, frame);
} }
else else
{ {
@ -1367,16 +1376,34 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick)
Assert(!(src_frame->world == world && tick <= src_frame->tick)); // Can't read from tick that is being overwritten by new tick Assert(!(src_frame->world == world && tick <= src_frame->tick)); // Can't read from tick that is being overwritten by new tick
P_ClearFrames(world, tick, I64Max); P_ClearFrames(world, tick, I64Max);
P_Frame *frame = PushStruct(world->frames_arena, P_Frame); P_Frame *frame = world->first_free_frame;
if (frame)
{ {
// FIXME: Pull from freelist SllStackPop(world->first_free_frame);
i64 old_ent_bins_count = frame->ent_bins_count;
P_EntBin *old_ent_bins = frame->ent_bins;
ZeroStruct(frame);
frame->ent_bins_count = old_ent_bins_count;
frame->ent_bins = old_ent_bins;
ZeroStructs(frame->ent_bins, frame->ent_bins_count);
}
else
{
frame = PushStruct(world->frames_arena, P_Frame);
}
{
frame->world = world; frame->world = world;
frame->tick = tick; frame->tick = tick;
frame->time_ns = src_frame->time_ns; frame->time_ns = src_frame->time_ns;
frame->first_ent = &P_NilEnt;
frame->last_ent = &P_NilEnt;
if (frame->ent_bins_count == 0)
{
frame->ent_bins_count = Kibi(16); frame->ent_bins_count = Kibi(16);
frame->ent_bins = PushStructs(world->frames_arena, P_EntBin, frame->ent_bins_count); frame->ent_bins = PushStructs(world->frames_arena, P_EntBin, frame->ent_bins_count);
}
u64 hash = MixU64(tick); u64 hash = MixU64(tick);
P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count]; P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count];
@ -1388,10 +1415,18 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick)
for (P_Ent *src = P_FirstEnt(src_frame); !P_IsEntNil(src); src = P_NextEnt(src)) for (P_Ent *src = P_FirstEnt(src_frame); !P_IsEntNil(src); src = P_NextEnt(src))
{ {
// FIXME: Pull from freelist // FIXME: Pull from freelist
P_Ent *dst = PushStruct(world->frames_arena, P_Ent); P_Ent *dst = world->first_free_ent;
if (dst)
{
SllStackPop(world->first_free_ent);
}
else
{
dst = PushStructNoZero(world->frames_arena, P_Ent);
}
*dst = *src; *dst = *src;
P_EntBin *bin = &frame->ent_bins[src->key.v % frame->ent_bins_count]; P_EntBin *bin = &frame->ent_bins[src->key.v % frame->ent_bins_count];
DllQueuePush(frame->first_ent, frame->last_ent, dst); DllQueuePushNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, dst, next, prev);
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
++frame->ents_count; ++frame->ents_count;
} }

View File

@ -151,13 +151,14 @@ Struct(P_World)
Arena *statics_arena; Arena *statics_arena;
u64 seed; u64 seed;
// P_Ent *first_free_ent;
P_Ent *first_free_ent;
P_Frame *first_frame; P_Frame *first_frame;
P_Frame *last_frame; P_Frame *last_frame;
i64 frame_bins_count; i64 frame_bins_count;
P_FrameBin *frame_bins; P_FrameBin *frame_bins;
// P_Frame *first_free_frame; P_Frame *first_free_frame;
u8 *tiles; u8 *tiles;
}; };
@ -167,18 +168,14 @@ Enum(P_DeltaKind)
P_DeltaKind_Reset, P_DeltaKind_Reset,
P_DeltaKind_RawEnt, P_DeltaKind_RawEnt,
P_DeltaKind_RawTiles, P_DeltaKind_RawTiles,
P_DeltaKind_Tile,
}; };
Struct(P_Delta) Struct(P_Delta)
{ {
P_DeltaKind kind; P_DeltaKind kind;
P_Ent ent; P_Ent ent;
u8 *raw_tiles;
P_TileKind tile_kind;
Rng2I32 tile_range; Rng2I32 tile_range;
u8 *raw_tiles;
}; };
Struct(P_DeltaNode) Struct(P_DeltaNode)
@ -342,8 +339,10 @@ Struct(P_DebugDrawNode)
Enum(P_CmdKind) Enum(P_CmdKind)
{ {
P_CmdKind_Nop, P_CmdKind_Nop,
P_CmdKind_Save, P_CmdKind_SaveWorld,
P_CmdKind_Delta, P_CmdKind_ResetWorld,
P_CmdKind_TileEdit,
P_CmdKind_EntEdit,
P_CmdKind_Control, P_CmdKind_Control,
}; };
@ -352,8 +351,12 @@ Struct(P_Cmd)
i64 tick; i64 tick;
P_CmdKind kind; P_CmdKind kind;
// Delta // Tile edit
P_Delta delta; P_TileKind tile_kind;
Rng2I32 tile_range;
// Ent edit
P_Ent ent;
// Control // Control
P_Key target; P_Key target;
@ -366,6 +369,7 @@ Struct(P_Cmd)
Struct(P_CmdNode) Struct(P_CmdNode)
{ {
P_CmdNode *next; P_CmdNode *next;
P_CmdNode *prev;
P_Cmd cmd; P_Cmd cmd;
}; };

View File

@ -29,6 +29,27 @@ void S_TickForever(WaveLaneCtx *lane)
// TODO: Real per-client deltas // TODO: Real per-client deltas
b32 has_sent_initial_tick = 0; b32 has_sent_initial_tick = 0;
// FIXME: Header
Rng user_cmd_tick_range = RNG(0, SIM_TICKS_PER_SECOND * 0.5);
P_CmdList queued_user_cmds = Zi;
P_CmdNode *first_free_user_cmd_node = 0;
////////////////////////////// //////////////////////////////
//- Sim loop //- Sim loop
@ -91,7 +112,8 @@ void S_TickForever(WaveLaneCtx *lane)
P_Frame *prev_world_frame = world->last_frame; P_Frame *prev_world_frame = world->last_frame;
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);
// FIXME: Copy frame // TDOO: Remove this
P_ClearFrames(world, I64Min, prev_world_frame->tick - 1);
i64 frame_begin_ns = TimeNs(); i64 frame_begin_ns = TimeNs();
@ -113,6 +135,66 @@ void S_TickForever(WaveLaneCtx *lane)
} }
UnlockTicketMutex(&P.sim_input_back_tm); 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 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.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.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;
}
}
}
// Copy queued commands for current tick
{
for (P_CmdNode *src_cmd_node = queued_user_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next)
{
if (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;
}
}
}
}
////////////////////////////// //////////////////////////////
//- Update double-buffered entity data //- Update double-buffered entity data
@ -126,21 +208,21 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Only accept save command from local user // FIXME: Only accept save command from local user
b32 should_save = 0; // b32 should_save = 0;
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) // for (P_CmdNode *cmd_node = user_cmds.first; cmd_node; cmd_node = cmd_node->next)
{ // {
P_Cmd *cmd = &cmd_node->cmd; // P_Cmd *cmd = &cmd_node->cmd;
if (cmd->kind == P_CmdKind_Save) // if (cmd->kind == P_CmdKind_SaveWorld)
{ // {
should_save = 1; // should_save = 1;
break; // break;
} // }
} // }
if (should_save) // if (should_save)
{ // {
String path = Lit("HAH"); // String path = Lit("...");
LogInfoF("Saving world to %F", FmtString(path)); // LogInfoF("Saving world to %F", FmtString(path));
} // }
////////////////////////////// //////////////////////////////
//- Process user world delta commands //- Process user world delta commands
@ -149,53 +231,44 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Only apply relevant cmds based on tick // FIXME: Only apply relevant cmds based on tick
i64 applied_user_deltas_count = 0;
P_Delta **applied_user_deltas = PushStructsNoZero(frame_arena, P_Delta *, input->cmds.count); {
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) b32 tiles_dirty = 0;
for (P_CmdNode *cmd_node = user_cmds.first; cmd_node; cmd_node = cmd_node->next)
{ {
P_Cmd *cmd = &cmd_node->cmd; P_Cmd *cmd = &cmd_node->cmd;
if (cmd->kind == P_CmdKind_Delta)
{
P_Delta *delta = &cmd->delta;
b32 allow = 0; b32 allow = 0;
b32 forward = 0; if (cmd->kind == P_CmdKind_ResetWorld)
if (delta->kind == P_DeltaKind_Reset)
{ {
allow = 1; // TODO
forward = 1;
} }
if (delta->kind == P_DeltaKind_RawEnt) if (cmd->kind == P_CmdKind_EntEdit)
{ {
allow = 1; P_EntList ents = Zi;
P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
*dst = cmd->ent;
P_SpawnEntsFromList(world_frame, ents);
} }
if (delta->kind == P_DeltaKind_Tile) if (cmd->kind == P_CmdKind_TileEdit)
{ {
allow = 1; P_TileKind tile = cmd->tile_kind;
forward = 1; 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)
{
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
world->tiles[tile_idx] = (u8)tile;
}
}
} }
if (forward)
{
applied_user_deltas[applied_user_deltas_count] = delta;
applied_user_deltas_count += 1;
} }
if (allow)
{
P_DeltaNode tmp_delta_node = Zi;
tmp_delta_node.delta = *delta;
P_SnapshotNode tmp_snapshot_node = Zi; // TODO: Hash tiles here
tmp_snapshot_node.snapshot.deltas_count = 1; // if (tiles_dirty)
tmp_snapshot_node.snapshot.first_delta_node = &tmp_delta_node; // {
tmp_snapshot_node.snapshot.last_delta_node = &tmp_delta_node; // }
P_SnapshotList tmp_snapshot_list = Zi;
tmp_snapshot_list.count = 1;
tmp_snapshot_list.first = &tmp_snapshot_node;
tmp_snapshot_list.last = &tmp_snapshot_node;
P_UpdateWorldFromSnapshots(world, tmp_snapshot_list);
}
}
} }
////////////////////////////// //////////////////////////////
@ -208,7 +281,7 @@ void S_TickForever(WaveLaneCtx *lane)
ent->fire_presses = 0; ent->fire_presses = 0;
} }
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) for (P_CmdNode *cmd_node = user_cmds.first; cmd_node; cmd_node = cmd_node->next)
{ {
P_Cmd cmd = cmd_node->cmd; P_Cmd cmd = cmd_node->cmd;
if (cmd.kind == P_CmdKind_Control) if (cmd.kind == P_CmdKind_Control)
@ -1237,20 +1310,6 @@ void S_TickForever(WaveLaneCtx *lane)
snapshot->tick = world_frame->tick; snapshot->tick = world_frame->tick;
snapshot->time_ns = world_frame->time_ns; snapshot->time_ns = world_frame->time_ns;
// Forward user edit deltas
for (i64 applied_user_delta_idx = 0; applied_user_delta_idx < applied_user_deltas_count; ++applied_user_delta_idx)
{
P_Delta *delta = 0;
{
P_DeltaNode *dn = PushStruct(output->arena, P_DeltaNode);
snapshot->deltas_count += 1;
SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn);
delta = &dn->delta;
}
P_Delta *src = applied_user_deltas[applied_user_delta_idx];
*delta = *src;
}
// Push full tile delta // Push full tile delta
if (!has_sent_initial_tick) if (!has_sent_initial_tick)
{ {
@ -1320,13 +1379,13 @@ void S_TickForever(WaveLaneCtx *lane)
for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
{ {
// FIXME: Add to freelist
// FIXME: Ensure sure prunes are received by user // FIXME: Ensure sure prunes are received by user
P_Ent *ent = ents_to_prune[prune_idx]; P_Ent *ent = ents_to_prune[prune_idx];
P_EntBin *bin = &world_frame->ent_bins[ent->key.v % world_frame->ent_bins_count]; P_EntBin *bin = &world_frame->ent_bins[ent->key.v % world_frame->ent_bins_count];
DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
DllQueueRemove(world_frame->first_ent, world_frame->last_ent, ent); DllQueueRemoveNPZ(&P_NilEnt, world_frame->first_ent, world_frame->last_ent, ent, next, prev);
world_frame->ents_count -= 1; world_frame->ents_count -= 1;
SllStackPush(world->first_free_ent, ent);
} }
} }

View File

@ -37,17 +37,25 @@ V_Cmd *V_PushVisCmd(String name)
cmd->name = name; cmd->name = name;
} }
++frame->cmds_count; ++frame->cmds_count;
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, cmd_node); DllQueuePush(frame->first_cmd_node, frame->last_cmd_node, cmd_node);
return cmd; return cmd;
} }
P_Cmd *V_PushSimCmd(P_CmdKind kind) P_Cmd *V_PushSimCmd(P_CmdKind kind)
{ {
// FIXME: Free list
Arena *perm = PermArena(); Arena *perm = PermArena();
P_CmdNode *n = PushStruct(perm, P_CmdNode); 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; n->cmd.kind = kind;
SllQueuePush(V.sim_cmds.first, V.sim_cmds.last, n); DllQueuePush(V.sim_cmds.first, V.sim_cmds.last, n);
++V.sim_cmds.count; ++V.sim_cmds.count;
return &n->cmd; return &n->cmd;
} }
@ -1002,7 +1010,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Place tiles //- Place tiles
// TODO: Push vis cmd // TODO: Push vis cmd instead
if (frame->is_editing && prev_frame->is_selecting && !frame->is_selecting) if (frame->is_editing && prev_frame->is_selecting && !frame->is_selecting)
{ {
@ -1013,10 +1021,9 @@ 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_Delta); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_TileEdit);
cmd->delta.kind = P_DeltaKind_Tile; cmd->tile_kind = prev_frame->equipped_tile;
cmd->delta.tile_kind = prev_frame->equipped_tile; cmd->tile_range = tile_range;
cmd->delta.tile_range = tile_range;
} }
} }
@ -2234,12 +2241,20 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{ {
UI_BuildLabelF("World seed: 0x%F", FmtHex(blend_world->seed)); UI_BuildLabelF("Sim world seed: 0x%F", FmtHex(sim_world->seed));
UI_BuildLabelF("Entities count: %F", FmtSint(blend_world->last_frame->ents_count)); UI_BuildLabelF("Sim world tick: %F", FmtSint(sim_world->last_frame->tick));
UI_BuildLabelF("Sim world entities: %F", FmtSint(sim_world->last_frame->ents_count));
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
UI_BuildLabelF("Predict world seed: 0x%F", FmtHex(predict_world->seed));
UI_BuildLabelF("Predict world tick: %F", FmtSint(predict_world->last_frame->tick));
UI_BuildLabelF("Predict world entities: %F", FmtSint(predict_world->last_frame->ents_count));
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
UI_BuildLabelF("Blend world seed: 0x%F", FmtHex(blend_world->seed));
UI_BuildLabelF("Blend world tick: %F", FmtSint(blend_world->last_frame->tick));
UI_BuildLabelF("Blend world entities: %F", FmtSint(blend_world->last_frame->ents_count));
} }
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{ {
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
Vec2 tile_pos = MulXformV2(frame->xf.world_to_tile, frame->world_cursor); Vec2 tile_pos = MulXformV2(frame->xf.world_to_tile, frame->world_cursor);
Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor); Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos); i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
@ -2521,8 +2536,7 @@ void V_TickForever(WaveLaneCtx *lane)
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_Delta); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_ResetWorld);
cmd->delta.kind = P_DeltaKind_Reset;
} }
else else
{ {
@ -2530,9 +2544,8 @@ void V_TickForever(WaveLaneCtx *lane)
} }
// Spawn player // Spawn player
{ {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit);
cmd->delta.kind = P_DeltaKind_RawEnt; P_Ent *ent = &cmd->ent;
P_Ent *ent = &cmd->delta.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);
@ -2544,9 +2557,8 @@ void V_TickForever(WaveLaneCtx *lane)
case V_CmdKind_spawn_dummy: case V_CmdKind_spawn_dummy:
{ {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit);
cmd->delta.kind = P_DeltaKind_RawEnt; P_Ent *ent = &cmd->ent;
P_Ent *ent = &cmd->delta.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);
@ -2559,9 +2571,8 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
if (!P_IsEntNil(hovered_ent)) if (!P_IsEntNil(hovered_ent))
{ {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_EntEdit);
cmd->delta.kind = P_DeltaKind_RawEnt; P_Ent *ent = &cmd->ent;
P_Ent *ent = &cmd->delta.ent;
ent->key = hovered_ent->key; ent->key = hovered_ent->key;
ent->exists = 0; ent->exists = 0;
} }
@ -2571,7 +2582,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
if (frame->is_editing) if (frame->is_editing)
{ {
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Save); P_Cmd *cmd = V_PushSimCmd(P_CmdKind_SaveWorld);
} }
} break; } break;
@ -2617,16 +2628,6 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
// Push control cmd
{
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Control);
cmd->target = V.player_key;
cmd->move = frame->move;
cmd->look = frame->look;
cmd->fire_held = frame->fire_held;
cmd->fire_presses = frame->fire_presses;
}
@ -2646,9 +2647,6 @@ void V_TickForever(WaveLaneCtx *lane)
} }
UnlockTicketMutex(&P.sim_output_back_tm); UnlockTicketMutex(&P.sim_output_back_tm);
////////////////////////////// //////////////////////////////
//- Apply sim snapshots //- Apply sim snapshots
@ -2699,6 +2697,10 @@ void V_TickForever(WaveLaneCtx *lane)
P_UpdateWorldFromSnapshots(sim_world, sim_snapshots); P_UpdateWorldFromSnapshots(sim_world, sim_snapshots);
} }
// TODO: Remove this
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
P_Frame *sim_frame = sim_world->last_frame;
@ -2708,21 +2710,46 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Submit sim commands //- Submit sim commands
i64 predict_to = sim_world->last_frame->tick + 10; frame->predict_to = sim_world->last_frame->tick + 1;
if (frame->predict_to != prev_frame->predict_to)
{
// Push control cmd
{
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Control);
cmd->target = V.player_key;
cmd->move = frame->move;
cmd->look = frame->look;
cmd->fire_held = frame->fire_held;
cmd->fire_presses = frame->fire_presses;
}
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 = V.sim_cmds.first; src; src = src->next) for (P_CmdNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next)
{ {
P_CmdNode *cmd_node = PushStruct(v2s->arena, P_CmdNode); if (src_cmd_node->cmd.kind == P_CmdKind_EntEdit)
cmd_node->cmd = src->cmd; {
cmd_node->cmd.tick = predict_to; DEBUGBREAKABLE;
SllQueuePush(v2s->cmds.first, v2s->cmds.last, cmd_node); }
P_CmdNode *dst_cmd_node = PushStruct(v2s->arena, P_CmdNode);
dst_cmd_node->cmd = src_cmd_node->cmd;
dst_cmd_node->cmd.tick = frame->predict_to;
DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node);
++v2s->cmds.count; ++v2s->cmds.count;
} }
} }
UnlockTicketMutex(&P.sim_input_back_tm); UnlockTicketMutex(&P.sim_input_back_tm);
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;
}
////////////////////////////// //////////////////////////////
@ -2750,7 +2777,7 @@ void V_TickForever(WaveLaneCtx *lane)
// { // {
// P_CmdNode *n = PushStructNoZero(frame->arena, P_CmdNode); // P_CmdNode *n = PushStructNoZero(frame->arena, P_CmdNode);
// *n = *src; // *n = *src;
// SllQueuePush(step_cmds.first, step_cmds.last, n); // DllQueuePush(step_cmds.first, step_cmds.last, n);
// ++step_cmds.count; // ++step_cmds.count;
// } // }
@ -2775,9 +2802,8 @@ void V_TickForever(WaveLaneCtx *lane)
// TODO: Remove this // TODO: Remove this
P_Frame *blend_frame = 0; P_Frame *blend_frame = 0;
{ {
// P_ResetWorldFromFrame(blended_world, predict_world->last_frame); P_ClearFrames(blend_world, I64Min, I64Max);
// P_Frame *blend_frame = blended_world->last_frame; blend_frame = P_PushFrame(blend_world, sim_world->last_frame, sim_world->last_frame->tick);
blend_frame = predict_frame;
} }
@ -3206,85 +3232,85 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Debug draw //- Debug draw
// { {
// // Copy debug draw data from sim // Copy debug draw data from sim
// if (received_unseen_tick) // if (received_unseen_tick)
// { {
// ResetArena(sim_debug_arena); ResetArena(sim_debug_arena);
// first_sim_debug_draw_node = 0; first_sim_debug_draw_node = 0;
// last_sim_debug_draw_node = 0; last_sim_debug_draw_node = 0;
// { {
// i64 dst_idx = 0; i64 dst_idx = 0;
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count); P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count);
// for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next) for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next)
// { {
// P_DebugDrawNode *dst = &dst_nodes[dst_idx]; P_DebugDrawNode *dst = &dst_nodes[dst_idx];
// *dst = *src; *dst = *src;
// dst_idx += 1; dst_idx += 1;
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst); SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
// } }
// } }
// } }
// // Merge vis debug draws with sim debug draws // Merge vis debug draws with sim debug draws
// P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node; P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
// P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node; P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
// if (P_tl.first_debug_draw_node) if (P_tl.first_debug_draw_node)
// { {
// if (last_debug_draw_node) if (last_debug_draw_node)
// { {
// last_debug_draw_node->next = P_tl.first_debug_draw_node; last_debug_draw_node->next = P_tl.first_debug_draw_node;
// } }
// else else
// { {
// first_debug_draw_node = P_tl.first_debug_draw_node; first_debug_draw_node = P_tl.first_debug_draw_node;
// } }
// last_debug_draw_node = P_tl.last_debug_draw_node; last_debug_draw_node = P_tl.last_debug_draw_node;
// } }
// // Push draws // Push draws
// for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next) for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
// { {
// Vec4 color = Vec4FromU32(n->srgb32); Vec4 color = Vec4FromU32(n->srgb32);
// i32 detail = 24; i32 detail = 24;
// f32 radius = 5; f32 radius = 5;
// switch(n->kind) switch(n->kind)
// { {
// case P_DebugDrawKind_Point: case P_DebugDrawKind_Point:
// { {
// Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p); Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
// V_DrawPoint(ui_p, color); V_DrawPoint(ui_p, color);
// } break; } break;
// case P_DebugDrawKind_Line: case P_DebugDrawKind_Line:
// { {
// Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0); Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
// Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1); Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
// V_DrawLine(ui_p0, ui_p1, color); V_DrawLine(ui_p0, ui_p1, color);
// } break; } break;
// case P_DebugDrawKind_Rect: case P_DebugDrawKind_Rect:
// { {
// Rng2 ui_rect = Zi; Rng2 ui_rect = Zi;
// ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0); ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
// ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1); ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
// V_DrawRect(ui_rect, color, V_DrawFlag_Line); V_DrawRect(ui_rect, color, V_DrawFlag_Line);
// } break; } break;
// case P_DebugDrawKind_Shape: case P_DebugDrawKind_Shape:
// { {
// P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape); P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
// } break; } break;
// } }
// } }
// // Reset vis debug draws // Reset vis debug draws
// ResetArena(P_tl.debug_arena); ResetArena(P_tl.debug_arena);
// P_tl.first_debug_draw_node = 0; P_tl.first_debug_draw_node = 0;
// P_tl.last_debug_draw_node = 0; P_tl.last_debug_draw_node = 0;
// P_tl.debug_draw_nodes_count = 0; P_tl.debug_draw_nodes_count = 0;
// } }
////////////////////////////// //////////////////////////////
@ -3560,29 +3586,28 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Prune ents //- Prune ents
// { {
// i64 ents_to_prune_count = 0; i64 ents_to_prune_count = 0;
// P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count); P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, sim_frame->ents_count);
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(sim_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// { {
// if (ent->exists <= 0) if (ent->exists <= 0)
// { {
// ents_to_prune[ents_to_prune_count] = ent; ents_to_prune[ents_to_prune_count] = ent;
// ents_to_prune_count += 1; ents_to_prune_count += 1;
// } }
// } }
// for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
// {
// // FIXME: Add to free list
// P_Ent *ent = ents_to_prune[prune_idx];
// P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
// DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
// DllQueueRemove(world->first_ent, world->last_ent, ent);
// world->ents_count -= 1;
// }
// }
for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
{
P_Ent *ent = ents_to_prune[prune_idx];
P_EntBin *bin = &sim_frame->ent_bins[ent->key.v % sim_frame->ent_bins_count];
DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
DllQueueRemoveNPZ(&P_NilEnt, sim_frame->first_ent, sim_frame->last_ent, ent, next, prev);
sim_frame->ents_count -= 1;
SllStackPush(sim_world->first_free_ent, ent);
}
}
////////////////////////////// //////////////////////////////
//- End frame //- End frame

View File

@ -123,6 +123,7 @@ Struct(V_Cmd)
Struct(V_CmdNode) Struct(V_CmdNode)
{ {
V_CmdNode *next; V_CmdNode *next;
V_CmdNode *prev;
V_Cmd cmd; V_Cmd cmd;
}; };
@ -265,6 +266,8 @@ Struct(V_Frame)
V_CmdNode *first_cmd_node; V_CmdNode *first_cmd_node;
V_CmdNode *last_cmd_node; V_CmdNode *last_cmd_node;
i64 predict_to;
// Control // Control
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;
@ -288,6 +291,7 @@ Struct(V_Ctx)
// Sim commands // Sim commands
P_CmdList sim_cmds; 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;