networking progress
This commit is contained in:
parent
b363160103
commit
b73daaf1f1
@ -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; };
|
||||||
#define U128(_hi, _lo) ((u128) { .hi = (_hi), .lo = (_lo) })
|
Inline u128 U128(u64 hi, u64 lo) { u128 result; result.hi = hi; result.lo = lo; return result; }
|
||||||
#endif
|
Inline b32 MatchU128(u128 a, u128 b) { return a.lo == b.lo && a.hi == b.hi; }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Atomics
|
//~ Atomics
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
69
src/pp/pp.c
69
src/pp/pp.c
@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
181
src/pp/pp.h
181
src/pp/pp.h
@ -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);
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|
||||||
// FIXME: Only apply relevant cmds based on tick
|
|
||||||
|
|
||||||
|
P_MsgList in_msgs = Zi;
|
||||||
{
|
{
|
||||||
b32 should_save = 0;
|
LockTicketMutex(&P.u2s_msgs_mutex);
|
||||||
for (P_CmdNode *cmd_node = user_cmds.first; cmd_node; cmd_node = cmd_node->next)
|
|
||||||
{
|
{
|
||||||
P_Cmd *cmd = &cmd_node->cmd;
|
for (P_MsgNode *src_msg_node = P.u2s_msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
|
||||||
b32 allow = 0;
|
|
||||||
if (cmd->kind == P_CmdKind_SaveWorld)
|
|
||||||
{
|
{
|
||||||
// FIXME: Only accept save from local user
|
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
|
||||||
should_save = 1;
|
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;
|
||||||
}
|
}
|
||||||
if (cmd->kind == P_CmdKind_ResetWorld)
|
ResetArena(P.u2s_msgs_arena);
|
||||||
|
ZeroStruct(&P.u2s_msgs);
|
||||||
|
}
|
||||||
|
UnlockTicketMutex(&P.u2s_msgs_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Register users
|
||||||
|
|
||||||
{
|
{
|
||||||
// TODO: Real reset
|
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
|
||||||
|
{
|
||||||
|
P_Msg *msg = &msg_node->msg;
|
||||||
|
|
||||||
|
P_Key user_key = msg->src_user;
|
||||||
|
P_Ent *user = P_EntFromKey(world_frame, user_key);
|
||||||
|
if (P_EntIsNil(user))
|
||||||
|
{
|
||||||
|
P_EntList tmp_list = Zi;
|
||||||
|
user = P_PushTempEnt(frame_arena, &tmp_list);
|
||||||
|
user->key = user_key;
|
||||||
|
user->is_user = 1;
|
||||||
|
user->exists = 1;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
user_name = Lit("Player");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
String orig_user_name = user_name;
|
||||||
|
i64 duplicate_id = 0;
|
||||||
|
while (duplicate_id < 1000)
|
||||||
|
{
|
||||||
|
b32 is_duplicate = 0;
|
||||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||||
{
|
{
|
||||||
ent->exists = 0;
|
if (ent->is_user && MatchString(P_StringFromEnt(ent), user_name))
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd->kind == P_CmdKind_EntEdit)
|
|
||||||
{
|
{
|
||||||
P_EntList ents = Zi;
|
is_duplicate = 1;
|
||||||
P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
|
break;
|
||||||
*dst = cmd->ent;
|
|
||||||
P_SpawnEntsFromList(world_frame, ents);
|
|
||||||
}
|
}
|
||||||
if (cmd->kind == P_CmdKind_TileEdit)
|
}
|
||||||
|
if (is_duplicate)
|
||||||
{
|
{
|
||||||
P_TileKind tile = cmd->tile_kind;
|
duplicate_id += 1;
|
||||||
Rng2I32 range = cmd->tile_range;
|
user_name = StringF(frame_arena, "%F (%F)", FmtString(orig_user_name), FmtSint(duplicate_id));
|
||||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
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);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
Vec2 tile_pos = VEC2(tile_x, tile_y);
|
P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr);
|
||||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
msg->dst_user = user->key;
|
||||||
world->tiles[tile_idx] = (u8)tile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hash tiles
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- 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))
|
||||||
{
|
{
|
||||||
u64 old_tiles_hash = world->tiles_hash;
|
ent->fire_presses = 0;
|
||||||
world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles));
|
}
|
||||||
if (world->tiles_hash != old_tiles_hash)
|
|
||||||
|
for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user))
|
||||||
{
|
{
|
||||||
tiles_dirty = 1;
|
if (user->is_iser)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Save world
|
|
||||||
if (should_save)
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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")))
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user