diff --git a/src/base/base_bitbuff.c b/src/base/base_bitbuff.c index 49611a2d..b3271b4c 100644 --- a/src/base/base_bitbuff.c +++ b/src/base/base_bitbuff.c @@ -673,6 +673,20 @@ String BB_ReadString(Arena *arena, BB_Reader *bbr) return result; } +String BB_ReadStringRaw(BB_Reader *bbr) +{ + BB_ReadDebugMagic(bbr, BB_DebugMagicKind_String, 0); + String result = Zi; + u64 len = BB_ReadUV(bbr); + u8 *src = BB_ReadBytesRaw(bbr, len); + if (src != 0) + { + result.len = len; + result.text = src; + } + return result; +} + // Will fill dst with zeroes if bitbuff overflows void BB_ReadBytes(BB_Reader *bbr, String out) { diff --git a/src/base/base_bitbuff.h b/src/base/base_bitbuff.h index b476bef6..77e72a28 100644 --- a/src/base/base_bitbuff.h +++ b/src/base/base_bitbuff.h @@ -164,6 +164,7 @@ Uid BB_ReadUid(BB_Reader *bbr); //- Raw data String BB_ReadString(Arena *arena, BB_Reader *bbr); +String BB_ReadStringRaw(BB_Reader *bbr); void BB_ReadBytes(BB_Reader *bbr, String dst); u8 *BB_ReadBytesRaw(BB_Reader *bbr, u64 num_bytes); void BB_ReadSeekBytes(BB_Reader *bbr, u64 num_bytes); diff --git a/src/pp/pp.c b/src/pp/pp.c index bd37578e..c0a1b36d 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -120,7 +120,12 @@ String P_NameFromTileKind(P_TileKind kind) P_TilesXList(X) #undef X }; - return names[kind]; + String result = Zi; + if (kind >= 0 && kind < countof(names)) + { + result = names[kind]; + } + return result; } //////////////////////////////////////////////////////////// @@ -133,7 +138,12 @@ String P_NameFromPrefabKind(P_PrefabKind kind) P_PrefabsXList(X) #undef X }; - return names[kind]; + String result = Zi; + if (kind >= 0 && kind < countof(names)) + { + result = names[kind]; + } + return result; } //////////////////////////////////////////////////////////// @@ -1653,6 +1663,7 @@ P_Msg *P_PushMsg(P_MsgKind kind, String data) P_Msg *msg = &msg_node->msg; msg->kind = kind; msg->data = PushString(P_tl.out_msgs_arena, data); + msg->xf = XformIdentity; DllQueuePush(P_tl.out_msgs.first, P_tl.out_msgs.last, msg_node); ++P_tl.out_msgs.count; return msg; @@ -1981,6 +1992,7 @@ void P_StepFrame(P_Frame *frame) guy->is_guy = 1; guy->has_weapon = 1; guy->key = player->guy; + guy->player = player->key; //- Choose guy spawn point { @@ -2957,6 +2969,19 @@ void P_StepFrame(P_Frame *frame) // TODO: Remove this if (!P_IsEntNil(victim)) { + P_Ent *damager = bullet; + if (!damager->is_player) + { + damager = P_EntFromKey(frame, damager->bullet_firer); + } + if (!damager->is_player) + { + damager = P_EntFromKey(frame, damager->player); + } + if (damager->is_player) + { + victim->last_damaging_player = damager->key; + } victim->health -= 0.25; } @@ -2986,6 +3011,16 @@ void P_StepFrame(P_Frame *frame) P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key); if (old_guy->health > 0) { + P_Ent *player = P_EntFromKey(frame, guy->player); + P_Ent *killer = P_EntFromKey(frame, guy->last_damaging_player); + if (player->is_player) + { + player->deaths += 1; + } + if (killer->is_player && !P_MatchEntKey(player->key, killer->key)) + { + killer->kills += 1; + } guy->exists = 0; } } diff --git a/src/pp/pp.h b/src/pp/pp.h index e6bb8ee8..eeba5cac 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -152,9 +152,17 @@ Struct(P_Ent) P_EntKey guy; f32 ping; + f32 kills; + f32 deaths; + u8 string_len; u8 string_text[P_MaxPlayerNameLen + 8]; + //- Guy + + P_EntKey player; + P_EntKey last_damaging_player; + //- Spawn b32 is_guy_spawn; @@ -386,12 +394,15 @@ Enum(P_MsgKind) // Client -> Server P_MsgKind_SaveWorld, P_MsgKind_ResetWorld, + P_MsgKind_Teleport, P_MsgKind_TileEdit, P_MsgKind_Prefab, P_MsgKind_Delete, // Server -> Client P_MsgKind_Tiles, + + P_MsgKind_COUNT }; Struct(P_Msg) diff --git a/src/pp/pp_shared.cg b/src/pp/pp_shared.cg index 8b44a75f..761533a3 100644 --- a/src/pp/pp_shared.cg +++ b/src/pp/pp_shared.cg @@ -19,5 +19,10 @@ P_PrefabFlag P_FlagsFromPrefabKind(P_PrefabKind kind) P_PrefabsXList(X) #undef X }; - return flags[kind]; + P_PrefabFlag result = P_PrefabFlag_None; + if (kind >= 0 && kind < countof(flags)) + { + result = flags[kind]; + } + return result; } diff --git a/src/pp/pp_shared.cgh b/src/pp/pp_shared.cgh index 6443efaf..1355852e 100644 --- a/src/pp/pp_shared.cgh +++ b/src/pp/pp_shared.cgh @@ -44,7 +44,6 @@ Enum(P_TileKind) #define P_PrefabsXList(X) \ X(None, P_PrefabFlag_HideFromEditor) \ - X(Guy, P_PrefabFlag_None) \ X(Bot, P_PrefabFlag_None) \ X(GuySpawn, P_PrefabFlag_None) \ /* --------------------------------------------------- */ diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 438b4f95..47885185 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -557,6 +557,15 @@ void S_TickForever(WaveLaneCtx *lane) } } } break; + //- Teleport + case P_MsgKind_Teleport: + { + P_Ent *ent = P_EntFromKey(world_frame, msg->key); + if (!P_IsEntNil(ent)) + { + ent->xf = msg->xf; + } + } break; //- Prefab case P_MsgKind_Prefab: { @@ -565,15 +574,6 @@ void S_TickForever(WaveLaneCtx *lane) P_PrefabKind prefab = msg->prefab; switch (prefab) { - case P_PrefabKind_Guy: - { - P_Ent *guy = P_PushTempEnt(frame_arena, &ents); - guy->key = msg->key; - guy->xf = msg->xf; - guy->is_guy = 1; - guy->has_weapon = 1; - } break; - case P_PrefabKind_Bot: { P_Ent *bot = P_EntFromKey(world_frame, msg->key); @@ -592,6 +592,7 @@ void S_TickForever(WaveLaneCtx *lane) guy->key = P_RandEntKey(); guy->is_guy = 1; guy->has_weapon = 1; + guy->player = bot->key; bot->guy = guy->key; } guy->xf = msg->xf; diff --git a/src/pp/pp_transcode.c b/src/pp/pp_transcode.c index d8cb11d3..83babd44 100644 --- a/src/pp/pp_transcode.c +++ b/src/pp/pp_transcode.c @@ -70,6 +70,9 @@ String P_PackWorld(Arena *arena, P_World *src_world) result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len; result.len += StringF(arena, " health: \"%F\"\n", FmtFloat(ent->health)).len; result.len += StringF(arena, " guy: \"0x%F\"\n", FmtHex(ent->guy.v)).len; + result.len += StringF(arena, " player: \"0x%F\"\n", FmtHex(ent->player.v)).len; + result.len += StringF(arena, " kills: \"%F\"\n", FmtFloat(ent->kills)).len; + result.len += StringF(arena, " deaths: \"%F\"\n", FmtFloat(ent->deaths)).len; result.len += StringF(arena, " text: \"%F\"\n", FmtString(CR_SanitizeString(scratch.arena, STRING(ent->string_len, ent->string_text)))).len; } result.len += PushString(arena, Lit(" }\n")).len; @@ -211,6 +214,18 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed) { ent->guy.v = CR_IntFromString(attr->value); } + if (MatchString(attr->name, Lit("player"))) + { + ent->player.v = CR_IntFromString(attr->value); + } + if (MatchString(attr->name, Lit("kills"))) + { + ent->kills = CR_FloatFromString(attr->value); + } + if (MatchString(attr->name, Lit("deaths"))) + { + ent->deaths = CR_FloatFromString(attr->value); + } if (MatchString(attr->name, Lit("text"))) { P_SetEntString(ent, attr->value); @@ -275,37 +290,61 @@ P_MsgList P_UnpackMessages(Arena *arena, String packed, NET_Key sender) b32 done = 0; while (!done) { - b32 is_raw = BB_ReadBit(&bbr); - if (is_raw) + //- Read + P_Msg msg = Zi; { - P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode); - DllQueuePush(result.first, result.last, dst_msg_node); - result.count += 1; - dst_msg_node->msg.kind = P_MsgKind_Raw; - dst_msg_node->msg.src = sender; - dst_msg_node->msg.dst = NET_NilKey; - dst_msg_node->msg.data = PushString(arena, packed); - done = 1; - } - else - { - u8 *msg_src = BB_ReadBytesRaw(&bbr, sizeof(P_Msg)); - if (msg_src != 0) + b32 is_raw = BB_ReadBit(&bbr); + if (is_raw) { - // Read msg header - P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode); - CopyStruct(&dst_msg_node->msg, msg_src); - DllQueuePush(result.first, result.last, dst_msg_node); - result.count += 1; - // Read msg data string - String data_str = BB_ReadString(arena, &bbr); - dst_msg_node->msg.src = sender; - dst_msg_node->msg.dst = NET_NilKey; - dst_msg_node->msg.data = data_str; + msg.kind = P_MsgKind_Raw; + msg.data = packed; + done = 1; } else { - done = 1; + u8 *raw_src_msg = BB_ReadBytesRaw(&bbr, sizeof(P_Msg)); + if (raw_src_msg != 0) + { + CopyStruct(&msg, raw_src_msg); + String data_str = BB_ReadStringRaw(&bbr); + msg.data = data_str; + } + else + { + done = 1; + } + } + } + + //- Validate + b32 skip = 0; + { + if (msg.kind < P_MsgKind_None || msg.kind > P_MsgKind_COUNT) + { + skip = 1; + } + if (msg.prefab < P_PrefabKind_None || msg.prefab > P_PrefabKind_COUNT) + { + skip = 1; + } + } + + if (!skip) + { + //- Sanitize + { + msg.src = sender; + msg.dst = NET_NilKey; + msg.xf = NormXform(msg.xf); + msg.data = PushString(arena, msg.data); + } + + //- Collect + { + P_MsgNode *msg_node = PushStruct(arena, P_MsgNode); + DllQueuePush(result.first, result.last, msg_node); + result.count += 1; + msg_node->msg = msg; } } } diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 9bcd818e..f5d43595 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -4101,34 +4101,57 @@ void V_TickForever(WaveLaneCtx *lane) if (frame->held_buttons[Button_Tab]) { - UI_Size name_sz = UI_GROW(0.75, 0); - UI_Size ping_sz = UI_GROW(0.25, 0); + // UI_Size name_sz = UI_GROW(0.75, 0); + // UI_Size kills_sz = UI_GROW(0.25, 0); + // UI_Size deaths_sz = UI_GROW(0.25, 0); + // UI_Size ping_sz = UI_GROW(0.25, 0); + // UI_Size spacing_sz = UI_FNT(1, 0); + + UI_Size name_sz = UI_FNT(10, 0); + UI_Size kills_sz = UI_FNT(10, 0); + UI_Size deaths_sz = UI_FNT(10, 0); + UI_Size ping_sz = UI_FNT(5, 0); UI_Size spacing_sz = UI_FNT(1, 0); + Enum(BoardRowFlag) + { + BoardRowFlag_None = 0, + BoardRowFlag_Header = (1 << 0), + }; Struct(BoardRow) { BoardRow *next; + BoardRowFlag flags; String name; f32 ping; + f32 kills; + f32 deaths; }; i64 players_count = 0; i64 board_rows_count = 0; BoardRow *first_board_row = 0; BoardRow *last_board_row = 0; - for (P_Ent *player = P_FirstEnt(sim_world->last_frame); !P_IsEntNil(player); player = P_NextEnt(player)) + { + BoardRow *row = PushStruct(frame->arena, BoardRow); + SllQueuePush(first_board_row, last_board_row, row); + board_rows_count += 1; + row->flags |= BoardRowFlag_Header; + } + + for (P_Ent *player = P_FirstEnt(local_frame); !P_IsEntNil(player); player = P_NextEnt(player)) { if (player->is_player) { players_count += 1; BoardRow *row = PushStruct(frame->arena, BoardRow); - { - SllQueuePush(first_board_row, last_board_row, row); - board_rows_count += 1; - } + SllQueuePush(first_board_row, last_board_row, row); + board_rows_count += 1; String name = P_StringFromEnt(player); row->name = name; row->ping = player->ping; + row->kills = player->kills; + row->deaths = player->deaths; } } @@ -4137,9 +4160,8 @@ void V_TickForever(WaveLaneCtx *lane) Vec4 board_bg = VEC4(0, 0, 0, 1); f32 opacity = 0.75; - UI_Size board_width = UI_FNT(50, 0); - UI_Size board_height = UI_FNT(20, 0); - + UI_Size board_width = UI_SHRINK(0, 0); + UI_Size board_height = UI_SHRINK(0, 0); Vec2 pos = VEC2(frame->screen_dims.x / 2, 50); UI_PushCP(UI_NilKey); { @@ -4152,41 +4174,113 @@ void V_TickForever(WaveLaneCtx *lane) UI_SetNext(Flags, UI_BoxFlag_Floating); UI_PushCP(UI_BuildColumnEx(board_key)); { - UI_BuildSpacer(spacing_sz, Axis_Y); + // UI_BuildSpacer(spacing_sz, Axis_Y); for (BoardRow *board_row = first_board_row; board_row; board_row = board_row->next) { - UI_SetNext(Width, UI_GROW(1, 1)); - UI_SetNext(Height, UI_FNT(2.5, 0)); + b32 is_header = AnyBit(board_row->flags, BoardRowFlag_Header); + + UI_SetNext(Width, UI_SHRINK(0, 0)); + if (is_header) + { + UI_SetNext(Height, UI_FNT(3, 0)); + } + else + { + UI_SetNext(Height, UI_FNT(2, 0)); + } UI_SetNext(Tint, 0); UI_SetNext(ChildAlignment, UI_Region_Left); UI_PushCP(UI_BuildRow()); // Scoreboard row { + UI_Push(ChildAlignment, UI_Region_Left); + + if (is_header) + { + UI_Push(FontSize, UI_Top(FontSize) * theme.h2); + } + else + { + UI_Push(FontSize, UI_Top(FontSize) * theme.h3); + } + UI_BuildSpacer(spacing_sz, Axis_X); UI_SetNext(Width, name_sz); UI_PushCP(UI_BuildColumn()); // Player name column { - UI_SetNext(FontSize, UI_Top(FontSize) * theme.h2); - UI_BuildLabelF("Player: \"%F\"", FmtString(board_row->name)); + if (is_header) + { + UI_BuildLabelF("Name"); + } + else + { + UI_BuildLabelF("%F", FmtString(board_row->name)); + } } UI_PopCP(UI_TopCP()); + UI_BuildDivider(UI_PIX(1, 1), theme.col.divider, Axis_X); + + UI_BuildSpacer(spacing_sz, Axis_X); + UI_SetNext(Width, kills_sz); + UI_PushCP(UI_BuildColumn()); // Kills column + { + if (is_header) + { + UI_BuildLabelF("Kills"); + } + else + { + UI_BuildLabelF("%F", FmtFloat(board_row->kills, .p = 2)); + } + } + UI_PopCP(UI_TopCP()); + UI_BuildDivider(UI_PIX(1, 1), theme.col.divider, Axis_X); + + UI_BuildSpacer(spacing_sz, Axis_X); + UI_SetNext(Width, deaths_sz); + UI_PushCP(UI_BuildColumn()); // Deaths column + { + if (is_header) + { + UI_BuildLabelF("Deaths"); + } + else + { + UI_BuildLabelF("%F", FmtFloat(board_row->deaths, .p = 2)); + } + } + UI_PopCP(UI_TopCP()); + UI_BuildDivider(UI_PIX(1, 1), theme.col.divider, Axis_X); UI_BuildSpacer(spacing_sz, Axis_X); UI_SetNext(Width, ping_sz); UI_PushCP(UI_BuildColumn()); // Ping column { - UI_SetNext(FontSize, UI_Top(FontSize) * theme.h2); - UI_BuildLabelF("Ping: %F ", FmtFloat(board_row->ping, .p = 2)); + if (is_header) + { + UI_BuildLabelF("Ping"); + } + else + { + UI_BuildLabelF("%F", FmtFloat(board_row->ping, .p = 2)); + } } UI_PopCP(UI_TopCP()); } UI_PopCP(UI_TopCP()); - if (board_row->next) + if (is_header) { - UI_BuildDivider(UI_PIX(1, 1), theme.col.divider, Axis_Y); + UI_BuildDivider(UI_PIX(3, 1), theme.col.divider, Axis_Y); + } + else + { + if (board_row->next) + { + UI_BuildDivider(UI_PIX(1, 1), theme.col.divider, Axis_Y); + } } } - UI_BuildSpacer(spacing_sz, Axis_Y); + // UI_BuildSpacer(spacing_sz, Axis_Y); } UI_PopCP(UI_TopCP()); } @@ -4453,26 +4547,16 @@ void V_TickForever(WaveLaneCtx *lane) // } break; case V_CmdKind_reset_world: - case V_CmdKind_spawn_tp_player: { - // Reset world - Vec2 guy_pos = VEC2(5, 0); - if (kind == V_CmdKind_reset_world) - { - P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); - msg->affect_bots = 1; - } - else - { - guy_pos = frame->world_cursor; - } - // Spawn player guy - { - P_Msg *msg = P_PushMsg(P_MsgKind_Prefab, Zstr); - msg->prefab = P_PrefabKind_Guy; - msg->key = local_guy->key; - msg->xf.t = guy_pos; - } + P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); + msg->affect_bots = 1; + } break; + + case V_CmdKind_tp_player: + { + P_Msg *msg = P_PushMsg(P_MsgKind_Teleport, Zstr); + msg->key = local_guy->key; + msg->xf.t = frame->world_cursor; } break; case V_CmdKind_spawn_tp_bot: diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 42ad95b4..dc505345 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -13,7 +13,7 @@ X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ - X(spawn_tp_player, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \ + X(tp_player, Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \ X(spawn_tp_bot, Spawn/Teleport Bot, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \ X(spawn_bot, Spawn Bot, V_CmdDescFlag_None, V_HOTKEY( Button_T, .ctrl = 1 ), ) \ X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \ diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index be4a7ccb..f0d4875f 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -44,7 +44,12 @@ String SPR_NameFromRayKind(SPR_RayKind kind) SPR_RayKindXList(X) #undef X }; - return names[kind]; + String result = Zi; + if (kind >= 0 && kind < countof(names)) + { + result = names[kind]; + } + return result; } SPR_LayerKind SPR_LayerKindFromName(String name) diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 2f24a440..b6613400 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1350,7 +1350,8 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) f32 scaled_size = 0; if (box->solved_scale.v[axis] == 1) { - scaled_size = RoundF32(unscaled_size); + // scaled_size = RoundF32(unscaled_size); + scaled_size = unscaled_size; } else {