From e2b31d00ac096472a1493273f682eba5f753434d Mon Sep 17 00:00:00 2001 From: BotoX Date: Mon, 10 May 2021 22:48:48 +0200 Subject: [PATCH] fixes and improvements :^) --- demboyz/game/gameevents.cpp | 2 +- demboyz/game/logic.cpp | 98 ++++++++++++++++++++++++++++++++-- demboyz/game/logic.h | 6 +++ demboyz/game/sourcecontext.cpp | 46 ++++++++++++++-- demboyz/game/sourcecontext.h | 2 + 5 files changed, 146 insertions(+), 8 deletions(-) diff --git a/demboyz/game/gameevents.cpp b/demboyz/game/gameevents.cpp index 3fca682..a12188c 100644 --- a/demboyz/game/gameevents.cpp +++ b/demboyz/game/gameevents.cpp @@ -83,7 +83,7 @@ namespace GameEvents } break; case GameEvents::EventValueType::Byte: { - std::cout << d.second.u8Value << "\n"; + std::cout << unsigned(d.second.u8Value) << "\n"; } break; case GameEvents::EventValueType::Bool: { diff --git a/demboyz/game/logic.cpp b/demboyz/game/logic.cpp index 9340967..3986749 100644 --- a/demboyz/game/logic.cpp +++ b/demboyz/game/logic.cpp @@ -14,6 +14,7 @@ Logic::Logic(SourceGameContext* context): {"header", {}}, {"serverinfo", {}}, {"players", {}}, + {"events", {}}, {"chat", {}}, {"voice", {}} }); @@ -117,13 +118,27 @@ void Logic::OnClientConnected(int client) player = json({ {"names", {}}, {"sprays", {}}, - {"disconnect_reasons", {}}, {"playtime", 0}, - {"voicetime", 0.0f} + {"voicetime", 0.0f}, + {"kills", 0}, + {"deaths", 0}, + {"chats", 0} }); } clients[client].connected = curTick; + clients[client].kills = 0; + clients[client].deaths = 0; + clients[client].chats = 0; + clients[client].voiceTime = 0.0f; + + json player_connect = { + {"event", "player_connect"}, + {"tick", curTick}, + {"steamid", info.guid}, + {"name", info.name} + }; + data["events"] += player_connect; OnClientSettingsChanged(client); } @@ -146,7 +161,28 @@ void Logic::OnClientDisconnected(int client, const char* reason) voicetime += player["voicetime"].get(); player["voicetime"] = voicetime; - player["disconnect_reasons"] += reason; + // cumulative kills + int kills = clients[client].kills; + kills += player["kills"].get(); + player["kills"] = kills; + + // cumulative deaths + int deaths = clients[client].deaths; + deaths += player["deaths"].get(); + player["deaths"] = deaths; + + // cumulative chats + int chats = clients[client].chats; + chats += player["chats"].get(); + player["chats"] = chats; + + json player_disconnect = { + {"event", "player_disconnect"}, + {"tick", curTick}, + {"steamid", info.guid}, + {"reason", reason} + }; + data["events"] += player_disconnect; clients[client].connected = -1; } @@ -173,11 +209,40 @@ void Logic::OnClientSettingsChanged(int client) } } +void Logic::OnClientDeath(int client, int attacker, bool headshot, const char* weapon) +{ + assert(client >= 0 && client < MAX_PLAYERS); + assert(clients[client].connected != -1); + + const char *victim_guid = context->players[client].info.guid; + const char *attacker_guid = ""; + + clients[client].deaths++; + if(attacker >= 0 && attacker < MAX_PLAYERS) + { + clients[attacker].kills++; + attacker_guid = context->players[attacker].info.guid; + } + + json player_death = { + {"tick", curTick}, + {"event", "player_death"}, + {"victim", victim_guid}, + {"attacker", attacker_guid}, + {"headshot", headshot}, + {"weapon", weapon} + }; + + data["events"] += player_death; +} + void Logic::OnClientChat(int client, bool bWantsToChat, const char* msgName, const char* msgSender, const char* msgText) { assert(client >= 0 && client < MAX_PLAYERS); assert(clients[client].connected != -1); + clients[client].chats++; + const auto& info = context->players[client].info; json chat = { {"tick", curTick}, @@ -193,7 +258,8 @@ void Logic::OnClientChat(int client, bool bWantsToChat, const char* msgName, con void Logic::OnClientVoiceChat(int client, float length) { assert(client >= 0 && client < MAX_PLAYERS); - assert(clients[client].connected != -1); + if (clients[client].connected == -1) + return; clients[client].voiceTime += length; voiceTotalTime += length; @@ -220,3 +286,27 @@ void Logic::OnVoiceCodec(const char* codec, int quality, int sampleRate) {"sampleRate", sampleRate} }); } + +void Logic::OnRoundStart(int timelimit) +{ + json round_start = { + {"event", "round_start"}, + {"tick", curTick}, + {"timelimit", timelimit}, + }; + + data["events"] += round_start; +} + +void Logic::OnRoundEnd(const char *message, int reason, int winner) +{ + json round_end = { + {"event", "round_end"}, + {"tick", curTick}, + {"message", message}, + {"reason", reason}, + {"winner", winner} + }; + + data["events"] += round_end; +} \ No newline at end of file diff --git a/demboyz/game/logic.h b/demboyz/game/logic.h index 8828249..7709e5e 100644 --- a/demboyz/game/logic.h +++ b/demboyz/game/logic.h @@ -22,6 +22,9 @@ struct Logic struct { int32_t connected = -1; + int kills = 0; + int deaths = 0; + int chats = 0; float voiceTime = 0.0f; } clients[MAX_PLAYERS]; @@ -29,9 +32,12 @@ struct Logic void OnClientConnected(int client); void OnClientDisconnected(int client, const char* reason); void OnClientSettingsChanged(int client); + void OnClientDeath(int client, int attacker, bool headshot, const char* weapon); void OnClientChat(int client, bool bWantsToChat, const char* msgName, const char* msgSender, const char* msgText); void OnClientVoiceChat(int client, float length); void OnVoiceCodec(const char* codec, int quality, int sampleRate); + void OnRoundStart(int timelimit); + void OnRoundEnd(const char *message, int reason, int winner); int32_t curTick = 0; float voiceTotalTime = 0.0f; diff --git a/demboyz/game/sourcecontext.cpp b/demboyz/game/sourcecontext.cpp index a860a4d..28ef384 100644 --- a/demboyz/game/sourcecontext.cpp +++ b/demboyz/game/sourcecontext.cpp @@ -10,6 +10,7 @@ #include "game/logic.h" #include "io/voicewriter/voicedatawriter.h" #include +#include #include "netmessages/svc_voiceinit.h" #include "netmessages/svc_voicedata.h" @@ -19,6 +20,8 @@ SourceGameContext::SourceGameContext(std::string outputDir, std::string outputDi outputDirVoice(outputDirVoice) { stringTables = new StringTableContainer(this); + userIdLookUp = new uint8_t[USHRT_MAX+1]; + memset(userIdLookUp, 0xFF, USHRT_MAX+1); } SourceGameContext::~SourceGameContext() @@ -33,6 +36,8 @@ SourceGameContext::~SourceGameContext() gameEventList = nullptr; delete stringTables; stringTables = nullptr; + delete userIdLookUp; + userIdLookUp = nullptr; fclose(outputFp); } @@ -130,16 +135,46 @@ void SourceGameContext::OnGameEvent(const char *name, GameEvents::EventDataMap & if (strcmp(name, "player_disconnect") == 0) { int userid = data["userid"].i16Value; - for (int client = 0; client < MAX_PLAYERS; client++) + int client = userIdLookUp[userid]; + + // player_disconnect can fire for clients which never connected + // (ESC during mapchange) + if(client != 0xFF) { auto& p = players[client]; - if (!p.connected || p.info.userID != userid) - continue; + assert(p.connected && p.info.userID == userid); p.connected = false; logic->OnClientDisconnected(client, data["reason"].strValue.c_str()); + userIdLookUp[userid] = 0xFF; } } + + else if (strcmp(name, "player_death") == 0) + { + int client = userIdLookUp[data["userid"].i16Value]; + assert(client >= 0 && client < MAX_PLAYERS); + + int attacker = data["attacker"].i16Value; + if(attacker > 0) + { + attacker = userIdLookUp[attacker]; + assert(attacker >= 0 && attacker < MAX_PLAYERS); + } + else + attacker = -1; + + logic->OnClientDeath(client, attacker, data["headshot"].bValue, data["weapon"].strValue.c_str()); + } + + else if (strcmp(name, "round_start") == 0) + { + logic->OnRoundStart(data["timelimit"].i32Value); + } + else if (strcmp(name, "round_end") == 0) + { + logic->OnRoundEnd(data["message"].strValue.c_str(), data["reason"].u8Value, data["winner"].u8Value); + } } void SourceGameContext::OnStringtable(StringTable* table) @@ -155,16 +190,21 @@ void SourceGameContext::UserInfoChanged(int tableIdx, int entryIdx) StringTableEntry &entry = stringTables->tables[tableIdx].entries[entryIdx]; int client = std::stoi(entry.string); + assert(client >= 0 && client < MAX_PLAYERS); player_info_t *info = (player_info_t *)entry.data.data(); if (entry.data.size() != sizeof(player_info_t)) { + if(players[client].connected) + userIdLookUp[players[client].info.userID] = 0xFF; + memset(&players[client].info, 0, sizeof(player_info_t)); players[client].connected = false; return; } memcpy(&players[client].info, info, sizeof(player_info_t)); + userIdLookUp[info->userID] = client; if (!players[client].connected) logic->OnClientConnected(client); diff --git a/demboyz/game/sourcecontext.h b/demboyz/game/sourcecontext.h index c0ade55..43985f2 100644 --- a/demboyz/game/sourcecontext.h +++ b/demboyz/game/sourcecontext.h @@ -108,4 +108,6 @@ struct SourceGameContext bool connected = false; player_info_t info; } players[MAX_PLAYERS]; + + uint8_t *userIdLookUp = nullptr; };