diff --git a/src/net/net.h b/src/net/net.h index 8e449538..4c1f9b8f 100644 --- a/src/net/net.h +++ b/src/net/net.h @@ -74,7 +74,7 @@ u64 NET_HashFromKey(NET_Key key); NET_PipeHandle NET_AcquirePipe(void); -void NET_Bind(NET_PipeHandle pipe_handle, u64 port); +void NET_Listen(NET_PipeHandle pipe_handle, u64 port); NET_MsgList NET_Swap(Arena *arena, NET_PipeHandle pipe_handle); void NET_Send(NET_PipeHandle pipe_handle, NET_Key dst, String data, NET_SendFlag flags); diff --git a/src/net/net_win32/net_win32.c b/src/net/net_win32/net_win32.c index 6029bb69..1e5f5574 100644 --- a/src/net/net_win32/net_win32.c +++ b/src/net/net_win32/net_win32.c @@ -281,7 +281,7 @@ NET_PipeHandle NET_AcquirePipe(void) return (NET_PipeHandle) { .v = (u64) pipe }; } -void NET_Bind(NET_PipeHandle pipe_handle, u64 port) +void NET_Listen(NET_PipeHandle pipe_handle, u64 port) { NET_W32_Pipe *pipe = NET_W32_PipeFromHandle(pipe_handle); u64 prev_desired_port = Atomic64FetchSet(&pipe->desired_port, port); diff --git a/src/pp/pp.c b/src/pp/pp.c index 635b7e8e..342eab7f 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -1293,6 +1293,7 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents) dst->prev = old_prev; dst->next_in_bin = old_next_in_bin; dst->prev_in_bin = old_prev_in_bin; + dst->created_at_ns = frame->time_ns; ++frame->ents_count; } } @@ -1436,6 +1437,33 @@ void P_StepFrame(P_Frame *frame) i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; f64 sim_dt = SecondsFromNs(sim_dt_ns); + ////////////////////////////// + //- Prune ents + + { + i64 ents_to_prune_count = 0; + P_Ent **ents_to_prune = PushStructsNoZero(scratch.arena, P_Ent *, frame->ents_count); + for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + { + if (ent->exists <= 0) + { + ents_to_prune[ents_to_prune_count] = ent; + ents_to_prune_count += 1; + } + } + + for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) + { + // FIXME: Ensure sure prunes are received by player + P_Ent *ent = ents_to_prune[prune_idx]; + P_EntBin *bin = &frame->ent_bins[ent->key.v % frame->ent_bins_count]; + DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); + DllQueueRemoveNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, ent, next, prev); + frame->ents_count -= 1; + SllStackPush(world->first_free_ent, ent); + } + } + ////////////////////////////// //- Update double-buffered entity data @@ -1544,7 +1572,7 @@ void P_StepFrame(P_Frame *frame) ////////////////////////////// - //- Generate guy wall constraints + //- Generate guy-on-guy constraints diff --git a/src/pp/pp.h b/src/pp/pp.h index 475fc95c..fb4a6a09 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -97,6 +97,7 @@ Struct(P_Ent) P_Key key; u64 rand_seq; + i64 created_at_ns; //- Build data @@ -287,6 +288,8 @@ Struct(P_Msg) NET_Key src; NET_Key dst; + b32 affect_dummies; + P_TileKind tile_kind; Rng2I32 tile_range; u64 tiles_hash; diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index bba909fc..addf1a66 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -57,7 +57,7 @@ void S_TickForever(WaveLaneCtx *lane) Arena *perm = PermArena(); Arena *frame_arena = AcquireArena(Gibi(64)); P_tl.debug_arena = AcquireArena(Gibi(64)); - P_tl.debug_tint = VEC4(0.2, 0.4, 0.2, 0.75); + P_tl.debug_tint = VEC4(0.2, 0.8, 0.2, 0.75); P_tl.out_msgs_arena = AcquireArena(Gibi(64)); P_World *world = P_AcquireWorld(); @@ -102,7 +102,7 @@ void S_TickForever(WaveLaneCtx *lane) // TODO: Keep old frames around for player snapshot deltas P_ClearFrames(world, I64Min, prev_world_frame->tick - 1); - i64 frame_begin_ns = TimeNs(); + i64 time_ns = TimeNs(); ////////////////////////////// //- Swap @@ -159,7 +159,7 @@ void S_TickForever(WaveLaneCtx *lane) //- Pop messages u64 port = 22121; - NET_Bind(net_pipe, port); + NET_Listen(net_pipe, port); P_MsgList in_msgs = Zi; { @@ -352,31 +352,16 @@ void S_TickForever(WaveLaneCtx *lane) //- Propagate control // - // In case future snapshots aren't received, the last-received control should be used, so we copy this control forward here + // In case previous snapshots weren't received, backfill with newest snapshot // // TODO: Not like this i64 max_propagate_count = SIM_TICKS_PER_SECOND / 4; { - // Propagate forwards - for (i64 prop_tick = control_tick; prop_tick < prop_tick + max_propagate_count; ++prop_tick) - { - P_Control *prop_control = &client->controls[prop_tick % client->max_controls]; - if (prop_tick > prop_control->orig_tick) - { - *prop_control = *control; - prop_control->tick = prop_tick; - prop_control->orig_tick = control_tick; - } - else - { - break; - } - } // Propagate backwards - for (i64 prop_tick = control_tick - 1; prop_tick > MaxI64(prop_tick - max_propagate_count, 0); --prop_tick) + for (i64 prop_tick = control_tick - 1; prop_tick >= MaxI64(prop_tick - max_propagate_count, world_frame->tick); --prop_tick) { P_Control *prop_control = &client->controls[prop_tick % client->max_controls]; - if (prop_tick > prop_control->orig_tick) + if (prop_control->orig_tick != prop_control->tick && control_tick < prop_control->orig_tick) { *prop_control = *control; prop_control->tick = prop_tick; @@ -433,11 +418,27 @@ void S_TickForever(WaveLaneCtx *lane) for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next) { P_Control *control = &client->controls[world_frame->tick % client->max_controls]; - - P_Ent *player = P_EntFromKey(world_frame, client->player); - if (!P_IsEntNil(player)) + if (control->tick == world_frame->tick) { - player->control = *control; + P_Ent *player = P_EntFromKey(world_frame, client->player); + if (!P_IsEntNil(player)) + { + player->control = *control; + } + } + } + + ////////////////////////////// + //- Apply dummy controls + + for (P_Ent *dummy = P_FirstEnt(world_frame); !P_IsEntNil(dummy); dummy = P_NextEnt(dummy)) + { + if (dummy->is_dummy) + { + i64 alive_time_ns = time_ns - dummy->created_at_ns; + i64 frequency_ns = NsFromSeconds(0.1); + + dummy->control.move.x = SinF32((f64)alive_time_ns / (f64)frequency_ns); } } @@ -625,7 +626,7 @@ void S_TickForever(WaveLaneCtx *lane) // TODO: Real reset for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { - if (!ent->is_player) + if (!ent->is_player || (msg->affect_dummies && ent->is_dummy)) { ent->exists = 0; } @@ -642,24 +643,41 @@ void S_TickForever(WaveLaneCtx *lane) } else if (MatchString(name, Lit("guy"))) { - P_Ent *ent = P_PushTempEnt(frame_arena, &ents); - *ent = P_NilEnt; - ent->key = msg->key; - ent->xf = XformFromPos(msg->pos); - ent->is_guy = 1; - ent->has_weapon = 1; - ent->exists = 1; + P_Ent *guy = P_PushTempEnt(frame_arena, &ents); + *guy = P_NilEnt; + guy->key = msg->key; + guy->xf = XformFromPos(msg->pos); + guy->is_guy = 1; + guy->has_weapon = 1; + guy->exists = 1; } else if (MatchString(name, Lit("dummy"))) { - P_Ent *ent = P_PushTempEnt(frame_arena, &ents); - *ent = P_NilEnt; - ent->key = msg->key; - ent->xf = XformFromPos(msg->pos); - ent->is_guy = 1; - ent->is_dummy = 1; - ent->has_weapon = 1; - ent->exists = 1; + P_Ent *guy = P_PushTempEnt(frame_arena, &ents); + *guy = P_NilEnt; + guy->key = P_RandKey(); + guy->xf = XformFromPos(msg->pos); + guy->is_guy = 1; + guy->has_weapon = 1; + guy->exists = 1; + + P_Ent *dummy = P_PushTempEnt(frame_arena, &ents); + *dummy = P_NilEnt; + dummy->key = msg->key; + dummy->is_player = 1; + dummy->is_dummy = 1; + dummy->exists = 1; + dummy->guy = guy->key; + P_SetEntString(dummy, Lit("Dummy")); + + // P_Ent *ent = P_PushTempEnt(frame_arena, &ents); + // *ent = P_NilEnt; + // ent->key = msg->key; + // ent->xf = XformFromPos(msg->pos); + // ent->is_guy = 1; + // ent->is_dummy = 1; + // ent->has_weapon = 1; + // ent->exists = 1; } P_SpawnEntsFromList(world_frame, ents); } break; @@ -1165,29 +1183,29 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Prune ents - { - i64 ents_to_prune_count = 0; - P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world_frame->ents_count); - for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - { - if (ent->exists <= 0) - { - ents_to_prune[ents_to_prune_count] = ent; - ents_to_prune_count += 1; - } - } + // { + // i64 ents_to_prune_count = 0; + // P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world_frame->ents_count); + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // if (ent->exists <= 0) + // { + // ents_to_prune[ents_to_prune_count] = ent; + // ents_to_prune_count += 1; + // } + // } - for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) - { - // FIXME: Ensure sure prunes are received by player - P_Ent *ent = ents_to_prune[prune_idx]; - 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); - DllQueueRemoveNPZ(&P_NilEnt, world_frame->first_ent, world_frame->last_ent, ent, next, prev); - world_frame->ents_count -= 1; - SllStackPush(world->first_free_ent, ent); - } - } + // for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) + // { + // // FIXME: Ensure sure prunes are received by player + // P_Ent *ent = ents_to_prune[prune_idx]; + // 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); + // DllQueueRemoveNPZ(&P_NilEnt, world_frame->first_ent, world_frame->last_ent, ent, next, prev); + // world_frame->ents_count -= 1; + // SllStackPush(world->first_free_ent, ent); + // } + // } ////////////////////////////// //- Publish Sim -> User data @@ -1247,7 +1265,7 @@ void S_TickForever(WaveLaneCtx *lane) if (!shutdown) { i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; - PLT_SleepFrame(frame_begin_ns, step_dt_ns); + PLT_SleepFrame(time_ns, step_dt_ns); } } diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index b6cd9160..a45b12a1 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -2430,7 +2430,10 @@ void V_TickForever(WaveLaneCtx *lane) { String name = board_row->name; + UI_SetNext(Width, UI_GROW(1, 0)); + UI_SetNext(Height, UI_FNT(2.5, 0)); UI_SetNext(Tint, 0); + UI_SetNext(ChildAlignment, UI_Region_Left); UI_PushCP(UI_BuildRow()); { UI_SetNext(FontSize, UI_Top(FontSize) * theme.h2); @@ -2714,6 +2717,7 @@ void V_TickForever(WaveLaneCtx *lane) if (kind == V_CmdKind_reset_world) { P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); + msg->affect_dummies = 1; } else { @@ -2964,7 +2968,9 @@ void V_TickForever(WaveLaneCtx *lane) } // TODO: Remove this - P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); + // TODO: Delete all frames except for prediction base & remote ack + P_ClearFrames(sim_world, I64Min, known_sim_tick - SIM_TICKS_PER_SECOND); + // P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); P_Frame *sim_frame = sim_world->last_frame; ////////////////////////////// @@ -3021,7 +3027,9 @@ void V_TickForever(WaveLaneCtx *lane) // frame->predict_to = sim_world->last_frame->tick + MaxF64(CeilF64(ping * SIM_TICKS_PER_SECOND), 1.0); - frame->predict_to = known_sim_tick + 10; + // frame->predict_to = known_sim_tick + 10; + + frame->predict_to = known_sim_tick + 20; ////////////////////////////// //- Create player control @@ -3209,6 +3217,13 @@ void V_TickForever(WaveLaneCtx *lane) + + + + + + + // Predict P_Frame *predict_frame = &P_NilFrame; { @@ -3221,20 +3236,15 @@ void V_TickForever(WaveLaneCtx *lane) - // P_ClearFrames(predict_world, I64Min, I64Max); - // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); - - - // FIXME: Not like this i64 max_predict_ticks = SIM_TICKS_PER_SECOND; i64 last_predict_tick = frame->predict_to; - i64 first_predict_tick = sim_world->last_frame->tick; + i64 first_predict_tick = known_sim_tick - 2; first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks); P_ClearFrames(predict_world, I64Min, first_predict_tick - 1); - predict_frame = P_PushFrame(predict_world, sim_world->last_frame, first_predict_tick); + predict_frame = P_PushFrame(predict_world, P_FrameFromTick(sim_world, first_predict_tick), first_predict_tick); for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick) { @@ -3250,35 +3260,11 @@ void V_TickForever(WaveLaneCtx *lane) } } + P_tl.debug_draw_enabled = 0; P_StepFrame(predict_frame); + P_tl.debug_draw_enabled = 1; } - - - // // We want to keep previously predicted ticks to preserve constraints - // P_ClearFrames(predict_world, I64Min, sim_world->last_frame->tick - 2); - - // i64 step_count = frame->predict_to - sim_world->last_frame->tick; - // P_Frame *base_predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); - // for (i64 step_idx = 0; step_idx < step_count; ++step_idx) - // { - // P_Frame *step_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_world->last_frame->tick + 1); - - // // FIXME: Cmds - // P_MsgList step_cmds = Zi; - // 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) - // { - // P_MsgNode *dst_cmd_node = PushStruct(frame->arena, P_MsgNode); - // DllQueuePush(step_cmds.first, step_cmds.last, dst_cmd_node); - // ++step_cmds.count; - // } - // } - - // P_StepFrame(step_frame, step_cmds); - // } - predict_frame = predict_world->last_frame; P_DebugDrawFrame(predict_frame); @@ -3289,6 +3275,64 @@ void V_TickForever(WaveLaneCtx *lane) + + + + + + + // // Predict + // P_Frame *predict_frame = &P_NilFrame; + // { + // if (predict_world->tiles_hash != sim_world->tiles_hash) + // { + // predict_world->tiles_hash = sim_world->tiles_hash; + // CopyStructs(predict_world->tiles, sim_world->tiles, P_TilesCount); + // } + // predict_world->seed = sim_world->seed; + + + + // // P_ClearFrames(predict_world, I64Min, I64Max); + // // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); + + // // FIXME: Not like this + // i64 max_predict_ticks = SIM_TICKS_PER_SECOND; + + // i64 last_predict_tick = frame->predict_to; + // i64 first_predict_tick = sim_world->last_frame->tick; + // first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks); + + // P_ClearFrames(predict_world, I64Min, first_predict_tick - 1); + // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, first_predict_tick); + + // for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick) + // { + // predict_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_tick); + + // P_Ent *predict_player = P_EntFromKey(predict_frame, local_player->key); + // if (!P_IsEntNil(predict_player)) + // { + // P_Control *predict_control = &local_controls[predict_tick % max_local_controls]; + // if (predict_control->tick == predict_tick) + // { + // predict_player->control = *predict_control; + // } + // } + + // P_StepFrame(predict_frame); + // } + + // predict_frame = predict_world->last_frame; + // P_DebugDrawFrame(predict_frame); + + // // TODO: Extract information that occurred between first & last prediction, like bullet hits etc? + // } + + + + + ////////////////////////////// //- Update local world @@ -4010,28 +4054,28 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Prune sim ents - { - i64 ents_to_prune_count = 0; - P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, sim_frame->ents_count); - for (P_Ent *ent = P_FirstEnt(sim_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - { - if (ent->exists <= 0) - { - ents_to_prune[ents_to_prune_count] = ent; - ents_to_prune_count += 1; - } - } + // { + // i64 ents_to_prune_count = 0; + // P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, sim_frame->ents_count); + // for (P_Ent *ent = P_FirstEnt(sim_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // if (ent->exists <= 0) + // { + // ents_to_prune[ents_to_prune_count] = ent; + // ents_to_prune_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); - } - } + // 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); + // } + // } ////////////////////////////// //- Send messages