From ab7b1642bcd37fd56cff24b51a7da7a7d774ccbb Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 27 Jun 2025 19:27:22 -0700 Subject: [PATCH] Prevent buffer overflows when using streams --- src/common/console/c_cvars.cpp | 13 +- src/common/console/c_cvars.h | 10 +- src/common/engine/i_net.cpp | 29 +-- src/common/utility/zstring.cpp | 5 + src/common/utility/zstring.h | 2 + src/d_net.cpp | 190 +++++++-------- src/d_net.h | 5 +- src/d_netinf.h | 4 +- src/d_netinfo.cpp | 18 +- src/d_protocol.cpp | 413 +++++++++++++++++++++++++-------- src/d_protocol.h | 68 ++++-- src/g_game.cpp | 203 ++++++++-------- src/gamedata/a_weapons.cpp | 6 +- src/gamedata/a_weapons.h | 6 +- src/p_conversation.cpp | 2 +- src/p_conversation.h | 2 +- src/playsim/bots/b_bot.h | 4 +- src/playsim/bots/b_game.cpp | 8 +- 18 files changed, 600 insertions(+), 388 deletions(-) diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index fc8c715b3..eb76f136a 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -40,6 +40,7 @@ #include "c_console.h" #include "c_dispatch.h" #include "c_cvars.h" +#include "d_protocol.h" #include "engineerrors.h" #include "printf.h" #include "palutil.h" @@ -1265,12 +1266,10 @@ void FilterCompactCVars (TArray &cvars, uint32_t filter) } } -void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact) +void C_WriteCVars (TArrayView& demo_p, uint32_t filter, bool compact) { FString dump = C_GetMassCVarString(filter, compact); - size_t dumplen = dump.Len() + 1; // include terminating \0 - memcpy(*demo_p, dump.GetChars(), dumplen); - *demo_p += dumplen; + WriteFString(dump, demo_p); } FString C_GetMassCVarString (uint32_t filter, bool compact) @@ -1306,9 +1305,9 @@ FString C_GetMassCVarString (uint32_t filter, bool compact) return dump; } -void C_ReadCVars (uint8_t **demo_p) +void C_ReadCVars (TArrayView& demo_p) { - char *ptr = *((char **)demo_p); + char *ptr = (char *)demo_p.Data(); char *breakpt; if (*ptr++ != '\\') @@ -1371,7 +1370,7 @@ void C_ReadCVars (uint8_t **demo_p) } } } - *demo_p += strlen (*((char **)demo_p)) + 1; + AdvanceStream(demo_p, strlen((char*)demo_p.Data()) + 1); } struct FCVarBackup diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h index 27cf8aa38..48678bbdf 100644 --- a/src/common/console/c_cvars.h +++ b/src/common/console/c_cvars.h @@ -269,7 +269,7 @@ private: // These need to go away! friend FString C_GetMassCVarString (uint32_t filter, bool compact); friend void C_SerializeCVars(FSerializer& arc, const char* label, uint32_t filter); - friend void C_ReadCVars (uint8_t **demo_p); + friend void C_ReadCVars (TArrayView& demo_p); friend void C_BackupCVars (void); friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); friend FBaseCVar *FindCVarSub (const char *var_name, int namelen); @@ -288,12 +288,12 @@ private: // the cvar names are omitted to save space. FString C_GetMassCVarString (uint32_t filter, bool compact=false); -// Writes all cvars that could effect demo sync to *demo_p. These are +// Writes all cvars that could effect demo sync to demo_p. These are // cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set. -void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact=false); +void C_WriteCVars (TArrayView& demo_p, uint32_t filter, bool compact=false); -// Read all cvars from *demo_p and set them appropriately. -void C_ReadCVars (uint8_t **demo_p); +// Read all cvars from demo_p and set them appropriately. +void C_ReadCVars (TArrayView& demo_p); void C_InstallHandlers(ConsoleCallbacks* cb); diff --git a/src/common/engine/i_net.cpp b/src/common/engine/i_net.cpp index f665271ad..5ddd0f69f 100644 --- a/src/common/engine/i_net.cpp +++ b/src/common/engine/i_net.cpp @@ -191,10 +191,10 @@ size_t Net_SetEngineInfo(uint8_t*& stream); bool Net_VerifyEngine(uint8_t*& stream); void Net_SetupUserInfo(); const char* Net_GetClientName(int client, unsigned int charLimit); -size_t Net_SetUserInfo(int client, uint8_t*& stream); -size_t Net_ReadUserInfo(int client, uint8_t*& stream); -size_t Net_ReadGameInfo(uint8_t*& stream); -size_t Net_SetGameInfo(uint8_t*& stream); +void Net_SetUserInfo(int client, TArrayView& stream); +void Net_ReadUserInfo(int client, TArrayView& stream); +void Net_ReadGameInfo(TArrayView& stream); +void Net_SetGameInfo(TArrayView& stream); static SOCKET CreateUDPSocket() { @@ -833,7 +833,7 @@ static bool Host_CheckForConnections(void* connected) { if (Connected[RemoteClient].Status == CSTAT_CONNECTING) { - uint8_t* stream = &NetBuffer[2]; + TArrayView stream = TArrayView(&NetBuffer[2], MAX_MSGLEN-2); Net_ReadUserInfo(RemoteClient, stream); Connected[RemoteClient].Status = CSTAT_WAITING; I_NetClientConnected(RemoteClient, 16u); @@ -886,8 +886,9 @@ static bool Host_CheckForConnections(void* connected) memcpy(&NetBuffer[3], GameID, 8); NetBufferLength = 11u; - uint8_t* stream = &NetBuffer[NetBufferLength]; - NetBufferLength += Net_SetGameInfo(stream); + TArrayView stream = TArrayView(&NetBuffer[NetBufferLength], MAX_MSGLEN - NetBufferLength); + Net_SetGameInfo(stream); + NetBufferLength += stream.Data() - &NetBuffer[NetBufferLength]; SendPacket(con.Address); clientReady = false; } @@ -911,8 +912,9 @@ static bool Host_CheckForConnections(void* connected) NetBufferLength += addrSize; } - uint8_t* stream = &NetBuffer[NetBufferLength]; - NetBufferLength += Net_SetUserInfo(i, stream); + TArrayView stream = TArrayView(&NetBuffer[NetBufferLength], MAX_MSGLEN - NetBufferLength); + Net_SetUserInfo(i, stream); + NetBufferLength += stream.Data() - &NetBuffer[NetBufferLength]; SendPacket(con.Address); } clientReady = false; @@ -1131,7 +1133,7 @@ static bool Guest_ContactHost(void* unused) { TicDup = clamp(NetBuffer[2], 1, MAXTICDUP); memcpy(GameID, &NetBuffer[3], 8); - uint8_t* stream = &NetBuffer[11]; + TArrayView stream = TArrayView(&NetBuffer[11], MAX_MSGLEN - 11); Net_ReadGameInfo(stream); Connected[consoleplayer].bHasGameInfo = true; } @@ -1158,7 +1160,7 @@ static bool Guest_ContactHost(void* unused) { Connected[c].Status = CSTAT_READY; } - uint8_t* stream = &NetBuffer[byte]; + TArrayView stream = TArrayView(&NetBuffer[byte], MAX_MSGLEN - byte); Net_ReadUserInfo(c, stream); SetClientAck(consoleplayer, c, true); @@ -1199,8 +1201,9 @@ static bool Guest_ContactHost(void* unused) NetBuffer[1] = PRE_USER_INFO; NetBufferLength = 2u; - uint8_t* stream = &NetBuffer[NetBufferLength]; - NetBufferLength += Net_SetUserInfo(consoleplayer, stream); + TArrayView stream = TArrayView(&NetBuffer[NetBufferLength], MAX_MSGLEN - NetBufferLength); + Net_SetUserInfo(consoleplayer, stream); + NetBufferLength += stream.Data() - &NetBuffer[NetBufferLength]; SendPacket(Connected[0].Address); } else if (con.Status == CSTAT_WAITING) diff --git a/src/common/utility/zstring.cpp b/src/common/utility/zstring.cpp index 0a5405e43..47bfd15fe 100644 --- a/src/common/utility/zstring.cpp +++ b/src/common/utility/zstring.cpp @@ -265,6 +265,11 @@ FString &FString::operator = (const char *copyStr) return *this; } +TArrayView FString::GetTArrayView() +{ + return TArrayView((uint8_t*)Chars, Len() + 1); +} + void FString::Format (const char *fmt, ...) { va_list arglist; diff --git a/src/common/utility/zstring.h b/src/common/utility/zstring.h index 2bc27d7b3..e51950a47 100644 --- a/src/common/utility/zstring.h +++ b/src/common/utility/zstring.h @@ -166,6 +166,8 @@ public: const char *GetChars() const { return Chars; } + TArrayView GetTArrayView(); + const char &operator[] (int index) const { return Chars[index]; } #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // Compiling 32-bit Windows source with MSVC: size_t is typedefed to an diff --git a/src/d_net.cpp b/src/d_net.cpp index 5a1f64c1c..9e89a5966 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -158,7 +158,7 @@ void D_ProcessEvents(void); void G_BuildTiccmd(usercmd_t *cmd); void D_DoAdvanceDemo(void); -static void RunScript(uint8_t **stream, AActor *pawn, int snum, int argn, int always); +static void RunScript(TArrayView& stream, AActor *pawn, int snum, int argn, int always); extern bool advancedemo; @@ -297,7 +297,7 @@ public: if (CurrentStream != nullptr) { AddBytes(1); - WriteInt8(it, &CurrentStream); + UncheckedWriteInt8(it, &CurrentStream); } return *this; } @@ -307,7 +307,7 @@ public: if (CurrentStream != nullptr) { AddBytes(2); - WriteInt16(it, &CurrentStream); + UncheckedWriteInt16(it, &CurrentStream); } return *this; } @@ -317,7 +317,7 @@ public: if (CurrentStream != nullptr) { AddBytes(4); - WriteInt32(it, &CurrentStream); + UncheckedWriteInt32(it, &CurrentStream); } return *this; } @@ -327,7 +327,7 @@ public: if (CurrentStream != nullptr) { AddBytes(8); - WriteInt64(it, &CurrentStream); + UncheckedWriteInt64(it, &CurrentStream); } return *this; } @@ -337,7 +337,7 @@ public: if (CurrentStream != nullptr) { AddBytes(4); - WriteFloat(it, &CurrentStream); + UncheckedWriteFloat(it, &CurrentStream); } return *this; } @@ -347,7 +347,7 @@ public: if (CurrentStream != nullptr) { AddBytes(8); - WriteDouble(it, &CurrentStream); + UncheckedWriteDouble(it, &CurrentStream); } return *this; } @@ -357,7 +357,7 @@ public: if (CurrentStream != nullptr) { AddBytes(strlen(it) + 1); - WriteString(it, &CurrentStream); + UncheckedWriteString(it, &CurrentStream); } return *this; } @@ -603,24 +603,24 @@ static size_t GetNetBufferSize() if (NetBufferLength < totalBytes + playerCount * padding) return totalBytes + playerCount * padding; - uint8_t* skipper = &NetBuffer[totalBytes]; + TArrayView skipper = TArrayView(&NetBuffer[totalBytes], MAX_MSGLEN - totalBytes); for (int p = 0; p < playerCount; ++p) { - ++skipper; + AdvanceStream(skipper, 1); if (NetMode == NET_PacketServer && RemoteClient == Net_Arbitrator) - skipper += 2; + AdvanceStream(skipper, 2); for (int i = 0; i < ranTics; ++i) - skipper += 3; + AdvanceStream(skipper, 3); for (int i = 0; i < numTics; ++i) { - ++skipper; + AdvanceStream(skipper, 1); SkipUserCmdMessage(skipper); } } - return int(skipper - NetBuffer); + return int(skipper.Data() - NetBuffer); } // @@ -992,14 +992,19 @@ static void GetPackets() // Each tic within a given packet is given a sequence number to ensure that things were put // back together correctly. Normally this wouldn't matter as much but since we need to keep // clients in lock step a misordered packet will instantly cause a desync. - TArray data = {}; + TArray> data = {}; // each contained TArrayView represents a packet. for (int t = 0; t < totalTics; ++t) { // Try and reorder the tics if they're all there but end up out of order. const int ofs = NetBuffer[curByte++]; - data.Insert(ofs, &NetBuffer[curByte]); - uint8_t* skipper = &NetBuffer[curByte]; - curByte += SkipUserCmdMessage(skipper); + + TArrayView skipper = TArrayView(&NetBuffer[curByte], MAX_MSGLEN - curByte); + SkipUserCmdMessage(skipper); + + TArrayView packet = TArrayView(&NetBuffer[curByte], skipper.Data() - &NetBuffer[curByte]); + data.Insert(ofs, packet); + + curByte += skipper.Data() - &NetBuffer[curByte]; } // If it's from a previous waiting period, the commands are no longer relevant. @@ -1722,38 +1727,29 @@ void NetUpdate(int tics) // Client commands. - uint8_t* cmd = &NetBuffer[size]; + TArrayView cmd = TArrayView(&NetBuffer[size], MAX_MSGLEN - size); for (int i = 0; i < playerCount; ++i) { - cmd[0] = playerNums[i]; - ++cmd; + WriteInt8(playerNums[i], cmd); auto& clientState = ClientStates[playerNums[i]]; // Time used to track latency since in packet server mode we want each // client's latency to the server itself. if (NetMode == NET_PacketServer && consoleplayer == Net_Arbitrator) { - cmd[0] = (clientState.AverageLatency >> 8); - ++cmd; - cmd[0] = clientState.AverageLatency; - ++cmd; + WriteInt16(clientState.AverageLatency, cmd); } for (int r = 0; r < sendCon; ++r) { - cmd[0] = r; - ++cmd; + WriteInt8(r, cmd); const int tic = (baseConsistency + curTicOfs + r) % BACKUPTICS; - cmd[0] = (clientState.LocalConsistency[tic] >> 8); - ++cmd; - cmd[0] = clientState.LocalConsistency[tic]; - ++cmd; + WriteInt16(clientState.LocalConsistency[tic], cmd); } for (int t = 0; t < sendTics; ++t) { - cmd[0] = t; - ++cmd; + WriteInt8(t, cmd); int curTic = sequenceNum + curTicOfs + t, lastTic = curTic - 1; if (playerNums[i] == consoleplayer) @@ -1763,11 +1759,7 @@ void NetUpdate(int tics) // Write out the net events before the user commands so inputs can // be used as a marker for when the given command ends. auto& stream = NetEvents.Streams[curTic % BACKUPTICS]; - if (stream.Used) - { - memcpy(cmd, stream.Stream, stream.Used); - cmd += stream.Used; - } + WriteBytes(TArrayView(stream.Stream, stream.Used), cmd); WriteUserCmdMessage(LocalCmds[realTic], realLastTic >= 0 ? &LocalCmds[realLastTic] : nullptr, cmd); @@ -1776,13 +1768,8 @@ void NetUpdate(int tics) { auto& netTic = clientState.Tics[curTic % BACKUPTICS]; - int len; - uint8_t* data = netTic.Data.GetData(&len); - if (data != nullptr) - { - memcpy(cmd, data, len); - cmd += len; - } + auto data = netTic.Data.GetTArrayView(); + WriteBytes(data, cmd); WriteUserCmdMessage(netTic.Command, lastTic >= 0 ? &clientState.Tics[lastTic % BACKUPTICS].Command : nullptr, cmd); @@ -1790,9 +1777,9 @@ void NetUpdate(int tics) } } - HSendPacket(client, int(cmd - NetBuffer)); + HSendPacket(client, int(cmd.Data() - NetBuffer)); if (net_extratic && !isSelf) - HSendPacket(client, int(cmd - NetBuffer)); + HSendPacket(client, int(cmd.Data() - NetBuffer)); } } } @@ -1834,70 +1821,52 @@ const char* Net_GetClientName(int client, unsigned int charLimit = 0u) return players[client].userinfo.GetName(charLimit); } -size_t Net_SetUserInfo(int client, uint8_t*& stream) +void Net_SetUserInfo(int client, TArrayView& stream) { auto str = D_GetUserInfoStrings(client, true); - const size_t userSize = str.Len() + 1; - memcpy(stream, str.GetChars(), userSize); - return userSize; + WriteFString(str, stream); } -size_t Net_ReadUserInfo(int client, uint8_t*& stream) +void Net_ReadUserInfo(int client, TArrayView& stream) { - const uint8_t* start = stream; - D_ReadUserInfoStrings(client, &stream, false); - return stream - start; + D_ReadUserInfoStrings(client, stream, false); } -size_t Net_SetGameInfo(uint8_t*& stream) +void Net_SetGameInfo(TArrayView& stream) { - const uint8_t* start = stream; - WriteString(startmap.GetChars(), &stream); - WriteInt32(rngseed, &stream); - C_WriteCVars(&stream, CVAR_SERVERINFO, true); + WriteFString(startmap, stream); + WriteInt32(rngseed, stream); + C_WriteCVars(stream, CVAR_SERVERINFO, true); auto load = Args->CheckValue("-loadgame"); if (load != nullptr) { - stream[0] = true; - const size_t len = strlen(load) + 1; - memcpy(&stream[1], load, len); - stream += len; + WriteInt8(1, stream); + WriteString(load, stream); } else { - stream[0] = false; + WriteInt8(0, stream); } - - return (stream + 1) - start; } -size_t Net_ReadGameInfo(uint8_t*& stream) +void Net_ReadGameInfo(TArrayView& stream) { - const uint8_t* start = stream; - startmap = ReadStringConst(&stream); - rngseed = ReadInt32(&stream); - C_ReadCVars(&stream); + startmap = ReadStringConst(stream); + rngseed = ReadInt32(stream); + C_ReadCVars(stream); - if (stream[0]) + if (ReadInt8(stream)) { - ++stream; - const size_t len = strlen((char*)stream) + 1; + auto load = ReadString(stream); // Don't override the existing argument in case they need to use // a custom savefile name. if (!Args->CheckParm("-loadgame")) { Args->AppendArg("-loadgame"); - Args->AppendArg((char*)stream); + Args->AppendArg(load); } - stream += len; } - else - { - ++stream; - } - - return stream - start; } // Connects players to each other if needed. @@ -2412,6 +2381,11 @@ uint8_t *FDynamicBuffer::GetData(int *len) return m_Len ? m_Data : nullptr; } +TArrayView FDynamicBuffer::GetTArrayView() +{ + return TArrayView(m_Data, m_Len); +} + static int RemoveClass(FLevelLocals *Level, const PClass *cls) { AActor *actor; @@ -2447,7 +2421,7 @@ static int RemoveClass(FLevelLocals *Level, const PClass *cls) // [RH] Execute a special "ticcmd". The type byte should // have already been read, and the stream is positioned // at the beginning of the command's actual data. -void Net_DoCommand(int cmd, uint8_t **stream, int player) +void Net_DoCommand(int cmd, TArrayView& stream, int player) { uint8_t pos = 0; const char* s = nullptr; @@ -3040,7 +3014,7 @@ void Net_DoCommand(int cmd, uint8_t **stream, int player) } // Used by DEM_RUNSCRIPT, DEM_RUNSCRIPT2, and DEM_RUNNAMEDSCRIPT -static void RunScript(uint8_t **stream, AActor *pawn, int snum, int argn, int always) +static void RunScript(TArrayView& stream, AActor *pawn, int snum, int argn, int always) { // Scripts can be invoked without a level loaded, e.g. via puke(name) CCMD in fullscreen console if (pawn == nullptr) @@ -3061,44 +3035,44 @@ static void RunScript(uint8_t **stream, AActor *pawn, int snum, int argn, int al // not to execute them. Right now this is making setting up net commands a nightmare. // Reads through the network stream but doesn't actually execute any command. Used for getting the size of a stream. // The skip amount is the number of bytes the command possesses. This should mirror the bytes in Net_DoCommand(). -void Net_SkipCommand(int cmd, uint8_t **stream) +void Net_SkipCommand(int cmd, TArrayView& stream) { size_t skip = 0; switch (cmd) { case DEM_SAY: - skip = strlen((char *)(*stream + 1)) + 2; + skip = strlen((char *)(stream.Data() + 1)) + 2; break; case DEM_ADDBOT: - skip = strlen((char *)(*stream + 1)) + 6; + skip = strlen((char *)(stream.Data() + 1)) + 6; break; case DEM_GIVECHEAT: case DEM_TAKECHEAT: - skip = strlen((char *)(*stream)) + 5; + skip = strlen((char *)(stream.Data())) + 5; break; case DEM_SETINV: - skip = strlen((char *)(*stream)) + 6; + skip = strlen((char *)(stream.Data())) + 6; break; case DEM_NETEVENT: - skip = strlen((char *)(*stream)) + 15; + skip = strlen((char *)(stream.Data())) + 15; break; case DEM_ZSC_CMD: - skip = strlen((char*)(*stream)) + 1; - skip += (((*stream)[skip] << 8) | (*stream)[skip + 1]) + 2; + skip = strlen((char*)(stream.Data())) + 1; + skip += (stream[skip] << 8) | (stream[skip + 1]) + 2; break; case DEM_SUMMON2: case DEM_SUMMONFRIEND2: case DEM_SUMMONFOE2: - skip = strlen((char *)(*stream)) + 26; + skip = strlen((char *)(stream.Data())) + 26; break; case DEM_CHANGEMAP2: - skip = strlen((char *)(*stream + 1)) + 2; + skip = strlen((char *)(stream.Data() + 1)) + 2; break; case DEM_MUSICCHANGE: case DEM_PRINT: @@ -3114,7 +3088,7 @@ void Net_SkipCommand(int cmd, uint8_t **stream) case DEM_MORPHEX: case DEM_KILLCLASSCHEAT: case DEM_MDK: - skip = strlen((char *)(*stream)) + 1; + skip = strlen((char *)(stream.Data())) + 1; break; case DEM_WARPCHEAT: @@ -3141,14 +3115,14 @@ void Net_SkipCommand(int cmd, uint8_t **stream) break; case DEM_SAVEGAME: - skip = strlen((char *)(*stream)) + 1; - skip += strlen((char *)(*stream) + skip) + 1; + skip = strlen((char *)(stream.Data())) + 1; + skip += strlen((char *)(stream.Data()) + skip) + 1; break; case DEM_SINFCHANGEDXOR: case DEM_SINFCHANGED: { - uint8_t t = **stream; + uint8_t t = stream[0]; skip = 1 + (t & 63); if (cmd == DEM_SINFCHANGED) { @@ -3162,7 +3136,7 @@ void Net_SkipCommand(int cmd, uint8_t **stream) skip += 4; break; case CVAR_String: - skip += strlen((char*)(*stream + skip)) + 1; + skip += strlen((char*)(stream.Data() + skip)) + 1; break; } } @@ -3175,16 +3149,16 @@ void Net_SkipCommand(int cmd, uint8_t **stream) case DEM_RUNSCRIPT: case DEM_RUNSCRIPT2: - skip = 3 + *(*stream + 2) * 4; + skip = 3 + *(stream.Data() + 2) * 4; break; case DEM_RUNNAMEDSCRIPT: - skip = strlen((char *)(*stream)) + 2; - skip += ((*(*stream + skip - 1)) & 127) * 4; + skip = strlen((char *)(stream.Data())) + 2; + skip += ((*(stream.Data() + skip - 1)) & 127) * 4; break; case DEM_RUNSPECIAL: - skip = 3 + *(*stream + 2) * 4; + skip = 3 + *(stream.Data() + 2) * 4; break; case DEM_CONVREPLY: @@ -3195,14 +3169,14 @@ void Net_SkipCommand(int cmd, uint8_t **stream) case DEM_SETSLOTPNUM: { skip = 2 + (cmd == DEM_SETSLOTPNUM); - for (int numweapons = (*stream)[skip-1]; numweapons > 0; --numweapons) - skip += 1 + ((*stream)[skip] >> 7); + for (int numweapons = stream[skip-1]; numweapons > 0; --numweapons) + skip += 1 + (stream[skip] >> 7); } break; case DEM_ADDSLOT: case DEM_ADDSLOTDEFAULT: - skip = 2 + ((*stream)[1] >> 7); + skip = 2 + (stream[1] >> 7); break; case DEM_SETPITCHLIMIT: @@ -3210,7 +3184,7 @@ void Net_SkipCommand(int cmd, uint8_t **stream) break; } - *stream += skip; + AdvanceStream(stream, skip); } // This was taken out of shared_hud, because UI code shouldn't do low level calculations that may change if the backing implementation changes. diff --git a/src/d_net.h b/src/d_net.h index 8938f0c42..11e847bd9 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -65,6 +65,7 @@ public: void SetData(const uint8_t* data, int len); uint8_t* GetData(int* len = nullptr); + TArrayView GetTArrayView(); private: uint8_t* m_Data; @@ -149,8 +150,8 @@ void Net_WriteDouble(double); void Net_WriteString(const char *); void Net_WriteBytes(const uint8_t *, int len); -void Net_DoCommand(int cmd, uint8_t **stream, int player); -void Net_SkipCommand(int cmd, uint8_t **stream); +void Net_DoCommand(int cmd, TArrayView& stream, int player); +void Net_SkipCommand(int cmd, TArrayView& stream); bool Net_CheckCutsceneReady(); void Net_AdvanceCutscene(); diff --git a/src/d_netinf.h b/src/d_netinf.h index 56f955e06..92b9f1d21 100644 --- a/src/d_netinf.h +++ b/src/d_netinf.h @@ -56,10 +56,10 @@ void D_UserInfoChanged (FBaseCVar *info); bool D_SendServerInfoChange (FBaseCVar *cvar, UCVarValue value, ECVarType type); bool D_SendServerFlagChange (FBaseCVar *cvar, int bitnum, bool set, bool silent); -void D_DoServerInfoChange (uint8_t **stream, bool singlebit); +void D_DoServerInfoChange (TArrayView& stream, bool singlebit); FString D_GetUserInfoStrings(int pnum, bool compact = false); -void D_ReadUserInfoStrings (int player, uint8_t **stream, bool update); +void D_ReadUserInfoStrings (int player, TArrayView& stream, bool update); struct FPlayerColorSet; void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **colorset); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index e319f9234..c4973a6e7 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -249,9 +249,9 @@ void D_PickRandomTeam (int player) { static char teamline[8] = "\\team\\X"; - uint8_t *foo = (uint8_t *)teamline; + auto foo = TArrayView((uint8_t *)teamline, sizeof(teamline)); teamline[6] = (char)D_PickRandomTeam() + '0'; - D_ReadUserInfoStrings (player, &foo, teamplay); + D_ReadUserInfoStrings (player, foo, teamplay); } int D_PickRandomTeam () @@ -581,7 +581,7 @@ void D_UserInfoChanged (FBaseCVar *cvar) Net_WriteString (foo); } -static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, bool singlebit) +static const char *SetServerVar (char *name, ECVarType type, TArrayView& stream, bool singlebit) { FBaseCVar *var = FindCVar (name, NULL); UCVarValue value; @@ -711,7 +711,7 @@ bool D_SendServerFlagChange (FBaseCVar *cvar, int bitnum, bool set, bool silent) return false; } -void D_DoServerInfoChange (uint8_t **stream, bool singlebit) +void D_DoServerInfoChange (TArrayView& stream, bool singlebit) { const char *value; char name[64]; @@ -723,8 +723,8 @@ void D_DoServerInfoChange (uint8_t **stream, bool singlebit) len &= 0x3f; if (len == 0) return; - memcpy (name, *stream, len); - *stream += len; + auto dst = TArrayView((uint8_t*)name, len); + ReadBytes(dst, stream); name[len] = 0; if ( (value = SetServerVar (name, (ECVarType)type, stream, singlebit)) && netgame) @@ -808,12 +808,12 @@ FString D_GetUserInfoStrings(int pnum, bool compact) return result; } -void D_ReadUserInfoStrings (int pnum, uint8_t **stream, bool update) +void D_ReadUserInfoStrings (int pnum, TArrayView& stream, bool update) { userinfo_t *info = &players[pnum].userinfo; TArray compact_names(info->CountUsed()); FBaseCVar **cvar_ptr; - const char *ptr = *((const char **)stream); + const char *ptr = (const char *)stream.Data(); const char *breakpt; FString value; bool compact; @@ -944,7 +944,7 @@ void D_ReadUserInfoStrings (int pnum, uint8_t **stream, bool update) } } } - *stream += strlen (*((char **)stream)) + 1; + AdvanceStream(stream, strlen((char*)stream.Data()) + 1); } void WriteUserInfo(FSerializer &arc, userinfo_t &info) diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 2ecc713bc..de56e2ba3 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -38,7 +38,10 @@ #include "cmdlib.h" #include "serializer.h" -char* ReadString(uint8_t **stream) +// Unchecked stream functions. +// Use the checked versions instead unless you're checking the stream size yourself! + +char* UncheckedReadString(uint8_t **stream) { char *string = *((char **)stream); @@ -46,65 +49,65 @@ char* ReadString(uint8_t **stream) return copystring(string); } -const char* ReadStringConst(uint8_t **stream) +const char* UncheckedReadStringConst(uint8_t **stream) { const char *string = *((const char **)stream); *stream += strlen(string) + 1; return string; } -uint8_t ReadInt8(uint8_t **stream) +uint8_t UncheckedReadInt8(uint8_t **stream) { uint8_t v = **stream; *stream += 1; return v; } -int16_t ReadInt16(uint8_t **stream) +int16_t UncheckedReadInt16(uint8_t **stream) { int16_t v = (((*stream)[0]) << 8) | (((*stream)[1])); *stream += 2; return v; } -int32_t ReadInt32(uint8_t **stream) +int32_t UncheckedReadInt32(uint8_t **stream) { int32_t v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3])); *stream += 4; return v; } -int64_t ReadInt64(uint8_t** stream) +int64_t UncheckedReadInt64(uint8_t **stream) { int64_t v = (int64_t((*stream)[0]) << 56) | (int64_t((*stream)[1]) << 48) | (int64_t((*stream)[2]) << 40) | (int64_t((*stream)[3]) << 32) - | (int64_t((*stream)[4]) << 24) | (int64_t((*stream)[5]) << 16) | (int64_t((*stream)[6]) << 8) | (int64_t((*stream)[7])); + | (int64_t((*stream)[4]) << 24) | (int64_t((*stream)[5]) << 16) | (int64_t((*stream)[6]) << 8) | (int64_t((*stream)[7])); *stream += 8; return v; } -float ReadFloat(uint8_t **stream) +float UncheckedReadFloat(uint8_t **stream) { union { int32_t i; float f; } fakeint; - fakeint.i = ReadInt32 (stream); + fakeint.i = UncheckedReadInt32(stream); return fakeint.f; } -double ReadDouble(uint8_t** stream) +double UncheckedReadDouble(uint8_t **stream) { union { int64_t i; double f; } fakeint; - fakeint.i = ReadInt64(stream); + fakeint.i = UncheckedReadInt64(stream); return fakeint.f; } -void WriteString(const char *string, uint8_t **stream) +void UncheckedWriteString(const char *string, uint8_t **stream) { char *p = *((char **)stream); @@ -116,20 +119,20 @@ void WriteString(const char *string, uint8_t **stream) *stream = (uint8_t *)p; } -void WriteInt8(uint8_t v, uint8_t **stream) +void UncheckedWriteInt8(uint8_t v, uint8_t **stream) { **stream = v; *stream += 1; } -void WriteInt16(int16_t v, uint8_t **stream) +void UncheckedWriteInt16(int16_t v, uint8_t **stream) { (*stream)[0] = v >> 8; (*stream)[1] = v & 255; *stream += 2; } -void WriteInt32(int32_t v, uint8_t **stream) +void UncheckedWriteInt32(int32_t v, uint8_t **stream) { (*stream)[0] = v >> 24; (*stream)[1] = (v >> 16) & 255; @@ -138,7 +141,7 @@ void WriteInt32(int32_t v, uint8_t **stream) *stream += 4; } -void WriteInt64(int64_t v, uint8_t** stream) +void UncheckedWriteInt64(int64_t v, uint8_t **stream) { (*stream)[0] = v >> 56; (*stream)[1] = (v >> 48) & 255; @@ -151,7 +154,231 @@ void WriteInt64(int64_t v, uint8_t** stream) *stream += 8; } -void WriteFloat(float v, uint8_t **stream) +void UncheckedWriteFloat(float v, uint8_t **stream) +{ + union + { + int32_t i; + float f; + } fakeint; + fakeint.f = v; + UncheckedWriteInt32(fakeint.i, stream); +} + +void UncheckedWriteDouble(double v, uint8_t **stream) +{ + union + { + int64_t i; + double f; + } fakeint; + fakeint.f = v; + UncheckedWriteInt64(fakeint.i, stream); +} + +void AdvanceStream(TArrayView& stream, size_t bytes) +{ + assert(bytes <= stream.Size()); + stream = TArrayView(stream.Data() + bytes, stream.Size() - bytes); +} + +// Checked stream functions + +char* ReadString(TArrayView& stream) +{ + char *string = (char*)stream.Data(); + size_t len = strnlen(string, stream.Size()); + if (len == stream.Size()) + { + I_Error("Attempted to read past end of stream"); + } + AdvanceStream(stream, len + 1); + return copystring(string); +} + +const char* ReadStringConst(TArrayView& stream) +{ + const char* string = (const char*)stream.Data(); + size_t len = strnlen(string, stream.Size()); + if (len == stream.Size()) + { + I_Error("Attempted to read past end of stream"); + } + AdvanceStream(stream, len + 1); + return string; +} + +void ReadBytes(TArrayView& dst, TArrayView& stream) +{ + if (dst.Size() > stream.Size()) + { + I_Error("Attempted to read past end of stream"); + } + if (dst.Size()) + { + memcpy(dst.Data(), stream.Data(), dst.Size()); + AdvanceStream(stream, dst.Size()); + } +} + +uint8_t ReadInt8(TArrayView& stream) +{ + if (stream.Size() < 1) + { + I_Error("Attempted to read past end of stream"); + } + uint8_t v = stream[0]; + AdvanceStream(stream, 1); + return v; +} + +int16_t ReadInt16(TArrayView& stream) +{ + if (stream.Size() < 2) + { + I_Error("Attempted to read past end of stream"); + } + int16_t v = ((stream[0]) << 8) | stream[1]; + AdvanceStream(stream, 2); + return v; +} + +int32_t ReadInt32(TArrayView& stream) +{ + if (stream.Size() < 4) + { + I_Error("Attempted to read past end of stream"); + } + int32_t v = (stream[0] << 24) | (stream[1] << 16) | (stream[2] << 8) | stream[3]; + AdvanceStream(stream, 4); + return v; +} + +int64_t ReadInt64(TArrayView& stream) +{ + if (stream.Size() < 8) + { + I_Error("Attempted to read past end of stream"); + } + int64_t v = (int64_t(stream[0]) << 56) | (int64_t(stream[1]) << 48) | (int64_t(stream[2]) << 40) | (int64_t(stream[3]) << 32) + | (int64_t(stream[4]) << 24) | (int64_t(stream[5]) << 16) | (int64_t(stream[6]) << 8) | int64_t(stream[7]); + AdvanceStream(stream, 8); + return v; +} + +float ReadFloat(TArrayView& stream) +{ + union + { + int32_t i; + float f; + } fakeint; + fakeint.i = ReadInt32 (stream); + return fakeint.f; +} + +double ReadDouble(TArrayView& stream) +{ + union + { + int64_t i; + double f; + } fakeint; + fakeint.i = ReadInt64(stream); + return fakeint.f; +} + +void WriteString(const char *string, TArrayView& stream) +{ + char *p = (char *)stream.Data(); + unsigned int remaining = stream.Size(); + + while (*string) { + if (remaining-- == 0) + { + I_Error("Attempted to write past end of stream"); + } + *p++ = *string++; + } + + if (remaining == 0) + { + I_Error("Attempted to write past end of stream"); + } + *p++ = 0; + AdvanceStream(stream, p - (char*)stream.Data()); +} + +void WriteBytes(const TArrayView& source, TArrayView& stream) +{ + if (source.Size() > stream.Size()) + { + I_Error("Attempted to write past end of stream"); + } + if (source.Size()) + { + memcpy(stream.Data(), source.Data(), source.Size()); + AdvanceStream(stream, source.Size()); + } +} + +void WriteFString(FString& string, TArrayView& stream) +{ + WriteBytes(string.GetTArrayView(), stream); +} + +void WriteInt8(uint8_t v, TArrayView& stream) +{ + if (stream.Size() < 1) + { + I_Error("Attempted to write past end of stream"); + } + stream[0] = v; + AdvanceStream(stream, 1); +} + +void WriteInt16(int16_t v, TArrayView& stream) +{ + if (stream.Size() < 2) + { + I_Error("Attempted to write past end of stream"); + } + stream[0] = v >> 8; + stream[1] = v & 255; + AdvanceStream(stream, 2); +} + +void WriteInt32(int32_t v, TArrayView& stream) +{ + if (stream.Size() < 4) + { + I_Error("Attempted to write past end of stream"); + } + stream[0] = v >> 24; + stream[1] = (v >> 16) & 255; + stream[2] = (v >> 8) & 255; + stream[3] = v & 255; + AdvanceStream(stream, 4); +} + +void WriteInt64(int64_t v, TArrayView& stream) +{ + if (stream.Size() < 8) + { + I_Error("Attempted to write past end of stream"); + } + stream[0] = v >> 56; + stream[1] = (v >> 48) & 255; + stream[2] = (v >> 40) & 255; + stream[3] = (v >> 32) & 255; + stream[4] = (v >> 24) & 255; + stream[5] = (v >> 16) & 255; + stream[6] = (v >> 8) & 255; + stream[7] = v & 255; + AdvanceStream(stream, 8); +} + +void WriteFloat(float v, TArrayView& stream) { union { @@ -162,7 +389,7 @@ void WriteFloat(float v, uint8_t **stream) WriteInt32 (fakeint.i, stream); } -void WriteDouble(double v, uint8_t** stream) +void WriteDouble(double v, TArrayView& stream) { union { @@ -193,11 +420,8 @@ FSerializer& Serialize(FSerializer& arc, const char* key, usercmd_t& cmd, usercm return arc; } -// Returns the number of bytes read -int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) +void UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, TArrayView& stream) { - const uint8_t* start = stream; - if (basis != nullptr) { if (basis != &cmd) @@ -208,7 +432,7 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) memset(&cmd, 0, sizeof(usercmd_t)); } - uint8_t flags = ReadInt8(&stream); + uint8_t flags = ReadInt8(stream); if (flags) { // We can support up to 29 buttons using 1 to 4 bytes to store them. The most @@ -216,19 +440,19 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) // should be read in excluding the last one which supports all 8 bits. if (flags & UCMDF_BUTTONS) { - uint8_t in = ReadInt8(&stream); + uint8_t in = ReadInt8(stream); uint32_t buttons = (cmd.buttons & ~0x7F) | (in & 0x7F); if (in & MoreButtons) { - in = ReadInt8(&stream); + in = ReadInt8(stream); buttons = (buttons & ~(0x7F << 7)) | ((in & 0x7F) << 7); if (in & MoreButtons) { - in = ReadInt8(&stream); + in = ReadInt8(stream); buttons = (buttons & ~(0x7F << 14)) | ((in & 0x7F) << 14); if (in & MoreButtons) { - in = ReadInt8(&stream); + in = ReadInt8(stream); buttons = (buttons & ~(0xFF << 21)) | (in << 21); } } @@ -236,26 +460,24 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) cmd.buttons = buttons; } if (flags & UCMDF_PITCH) - cmd.pitch = ReadInt16(&stream); + cmd.pitch = ReadInt16(stream); if (flags & UCMDF_YAW) - cmd.yaw = ReadInt16(&stream); + cmd.yaw = ReadInt16(stream); if (flags & UCMDF_FORWARDMOVE) - cmd.forwardmove = ReadInt16(&stream); + cmd.forwardmove = ReadInt16(stream); if (flags & UCMDF_SIDEMOVE) - cmd.sidemove = ReadInt16(&stream); + cmd.sidemove = ReadInt16(stream); if (flags & UCMDF_UPMOVE) - cmd.upmove = ReadInt16(&stream); + cmd.upmove = ReadInt16(stream); if (flags & UCMDF_ROLL) - cmd.roll = ReadInt16(&stream); + cmd.roll = ReadInt16(stream); } - - return int(stream - start); } -int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) +void PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, TArrayView& stream) { uint8_t flags = 0; - uint8_t* start = stream; + auto flagsPosition = TArrayView(stream.Data(), 1); usercmd_t blank; if (basis == nullptr) @@ -264,7 +486,7 @@ int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) basis = ␣ } - ++stream; // Make room for the flags. + AdvanceStream(stream, 1); // Make room for the flags. uint32_t buttons_changed = cmd.buttons ^ basis->buttons; if (buttons_changed != 0) { @@ -284,56 +506,54 @@ int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) bytes[2] |= MoreButtons; } } - WriteInt8(bytes[0], &stream); + WriteInt8(bytes[0], stream); if (bytes[0] & MoreButtons) { - WriteInt8(bytes[1], &stream); + WriteInt8(bytes[1], stream); if (bytes[1] & MoreButtons) { - WriteInt8(bytes[2], &stream); + WriteInt8(bytes[2], stream); if (bytes[2] & MoreButtons) - WriteInt8(bytes[3], &stream); + WriteInt8(bytes[3], stream); } } } if (cmd.pitch != basis->pitch) { flags |= UCMDF_PITCH; - WriteInt16(cmd.pitch, &stream); + WriteInt16(cmd.pitch, stream); } if (cmd.yaw != basis->yaw) { flags |= UCMDF_YAW; - WriteInt16 (cmd.yaw, &stream); + WriteInt16 (cmd.yaw, stream); } if (cmd.forwardmove != basis->forwardmove) { flags |= UCMDF_FORWARDMOVE; - WriteInt16 (cmd.forwardmove, &stream); + WriteInt16 (cmd.forwardmove, stream); } if (cmd.sidemove != basis->sidemove) { flags |= UCMDF_SIDEMOVE; - WriteInt16(cmd.sidemove, &stream); + WriteInt16(cmd.sidemove, stream); } if (cmd.upmove != basis->upmove) { flags |= UCMDF_UPMOVE; - WriteInt16(cmd.upmove, &stream); + WriteInt16(cmd.upmove, stream); } if (cmd.roll != basis->roll) { flags |= UCMDF_ROLL; - WriteInt16(cmd.roll, &stream); + WriteInt16(cmd.roll, stream); } // Write the packing bits - WriteInt8(flags, &start); - - return int(stream - start); + WriteInt8(flags, flagsPosition); } -int WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream) +void WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, TArrayView& stream) { if (basis == nullptr) { @@ -341,58 +561,60 @@ int WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& || cmd.pitch || cmd.yaw || cmd.roll || cmd.forwardmove || cmd.sidemove || cmd.upmove) { - WriteInt8(DEM_USERCMD, &stream); - return PackUserCmd(cmd, basis, stream) + 1; + WriteInt8(DEM_USERCMD, stream); + PackUserCmd(cmd, basis, stream); + return; } } else if (cmd.buttons != basis->buttons || cmd.yaw != basis->yaw || cmd.pitch != basis->pitch || cmd.roll != basis->roll || cmd.forwardmove != basis->forwardmove || cmd.sidemove != basis->sidemove || cmd.upmove != basis->upmove) { - WriteInt8(DEM_USERCMD, &stream); - return PackUserCmd(cmd, basis, stream) + 1; + WriteInt8(DEM_USERCMD, stream); + PackUserCmd(cmd, basis, stream); + return; } - WriteInt8(DEM_EMPTYUSERCMD, &stream); - return 1; + WriteInt8(DEM_EMPTYUSERCMD, stream); } // Reads through the user command without actually setting any of its info. Used to get the size // of the command when getting the length of the stream. -int SkipUserCmdMessage(uint8_t*& stream) +void SkipUserCmdMessage(TArrayView& stream) { - const uint8_t* start = stream; - while (true) { - const uint8_t type = *stream++; + const uint8_t type = ReadInt8(stream); if (type == DEM_USERCMD) { int skip = 1; - if (*stream & UCMDF_PITCH) + if (stream[0] & UCMDF_PITCH) skip += 2; - if (*stream & UCMDF_YAW) + if (stream[0] & UCMDF_YAW) skip += 2; - if (*stream & UCMDF_FORWARDMOVE) + if (stream[0] & UCMDF_FORWARDMOVE) skip += 2; - if (*stream & UCMDF_SIDEMOVE) + if (stream[0] & UCMDF_SIDEMOVE) skip += 2; - if (*stream & UCMDF_UPMOVE) + if (stream[0] & UCMDF_UPMOVE) skip += 2; - if (*stream & UCMDF_ROLL) + if (stream[0] & UCMDF_ROLL) skip += 2; - if (*stream & UCMDF_BUTTONS) + if (stream[0] & UCMDF_BUTTONS) { - if (*++stream & MoreButtons) + AdvanceStream(stream, 1); + if (stream[0] & MoreButtons) { - if (*++stream & MoreButtons) + AdvanceStream(stream, 1); + if (stream[0] & MoreButtons) { - if (*++stream & MoreButtons) - ++stream; + AdvanceStream(stream, 1); + if (stream[0] & MoreButtons) + AdvanceStream(stream, 1); } } } - stream += skip; + AdvanceStream(stream, skip); break; } else if (type == DEM_EMPTYUSERCMD) @@ -401,31 +623,29 @@ int SkipUserCmdMessage(uint8_t*& stream) } else { - Net_SkipCommand(type, &stream); + Net_SkipCommand(type, stream); } } - - return int(stream - start); } -int ReadUserCmdMessage(uint8_t*& stream, int player, int tic) +void ReadUserCmdMessage(TArrayView& stream, int player, int tic) { const int ticMod = tic % BACKUPTICS; auto& curTic = ClientStates[player].Tics[ticMod]; usercmd_t& ticCmd = curTic.Command; - const uint8_t* start = stream; + const uint8_t* start = stream.Data(); // Skip until we reach the player command. Event data will get read off once the // tick is actually executed. int type; - while ((type = ReadInt8(&stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) - Net_SkipCommand(type, &stream); + while ((type = ReadInt8(stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) + Net_SkipCommand(type, stream); // Subtract a byte to account for the fact the stream head is now sitting on the // user command. - curTic.Data.SetData(start, int(stream - start - 1)); + curTic.Data.SetData(start, int(stream.Data() - start - 1)); if (type == DEM_USERCMD) { @@ -439,8 +659,6 @@ int ReadUserCmdMessage(uint8_t*& stream, int player, int tic) else memset(&ticCmd, 0, sizeof(ticCmd)); } - - return int(stream - start); } void RunPlayerCommands(int player, int tic) @@ -449,14 +667,12 @@ void RunPlayerCommands(int player, int tic) if (gametic % TicDup) return; - int len; auto& data = ClientStates[player].Tics[tic % BACKUPTICS].Data; - uint8_t* stream = data.GetData(&len); - if (stream != nullptr) + auto stream = data.GetTArrayView(); + if (stream.Size()) { - uint8_t* end = stream + len; - while (stream < end) - Net_DoCommand(ReadInt8(&stream), &stream, player); + while (stream.Size() > 0) + Net_DoCommand(ReadInt8(stream), stream, player); if (!demorecording) data.SetData(nullptr, 0); @@ -469,22 +685,23 @@ uint8_t* streamPos = nullptr; // Write the header of an IFF chunk and leave space // for the length field. -void StartChunk(int id, uint8_t **stream) +void StartChunk(int id, TArrayView& stream) { WriteInt32(id, stream); - streamPos = *stream; - *stream += 4; + streamPos = stream.Data(); + AdvanceStream(stream, 4); } // Write the length field for the chunk and insert // pad byte if the chunk is odd-sized. -void FinishChunk(uint8_t **stream) +void FinishChunk(TArrayView& stream) { if (streamPos == nullptr) return; - int len = int(*stream - streamPos - 4); - WriteInt32(len, &streamPos); + int len = int(stream.Data() - streamPos - 4); + auto streamPosView = TArrayView(streamPos, 4); + WriteInt32(len, streamPosView); if (len & 1) WriteInt8(0, stream); @@ -493,8 +710,8 @@ void FinishChunk(uint8_t **stream) // Skip past an unknown chunk. *stream should be // pointing to the chunk's length field. -void SkipChunk(uint8_t **stream) +void SkipChunk(TArrayView& stream) { int len = ReadInt32(stream); - *stream += len + (len & 1); + AdvanceStream(stream, len + (len & 1)); } diff --git a/src/d_protocol.h b/src/d_protocol.h index f4388d3bf..6a9717043 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -229,33 +229,53 @@ enum ECheatCommand CHT_MASSACRE2 }; -void StartChunk (int id, uint8_t **stream); -void FinishChunk (uint8_t **stream); -void SkipChunk (uint8_t **stream); +void StartChunk (int id, TArrayView& stream); +void FinishChunk (TArrayView& stream); +void SkipChunk (TArrayView& stream); -// Returns the number of bytes written to the stream -int UnpackUserCmd(usercmd_t& ucmd, const usercmd_t* basis, uint8_t*& stream); -int PackUserCmd(const usercmd_t& ucmd, const usercmd_t* basis, uint8_t*& stream); -int WriteUserCmdMessage(const usercmd_t& ucmd, const usercmd_t *basis, uint8_t*& stream); +void UnpackUserCmd(usercmd_t& ucmd, const usercmd_t* basis, TArrayView& stream); +void PackUserCmd(const usercmd_t& ucmd, const usercmd_t* basis, TArrayView& stream); +void WriteUserCmdMessage(const usercmd_t& ucmd, const usercmd_t *basis, TArrayView& stream); -int SkipUserCmdMessage(uint8_t*& stream); -int ReadUserCmdMessage(uint8_t*& stream, int player, int tic); +void SkipUserCmdMessage(TArrayView& stream); +void ReadUserCmdMessage(TArrayView& stream, int player, int tic); void RunPlayerCommands(int player, int tic); -uint8_t ReadInt8 (uint8_t **stream); -int16_t ReadInt16 (uint8_t **stream); -int32_t ReadInt32 (uint8_t **stream); -int64_t ReadInt64(uint8_t** stream); -float ReadFloat (uint8_t **stream); -double ReadDouble(uint8_t** stream); -char *ReadString (uint8_t **stream); -const char *ReadStringConst(uint8_t **stream); -void WriteInt8 (uint8_t val, uint8_t **stream); -void WriteInt16 (int16_t val, uint8_t **stream); -void WriteInt32 (int32_t val, uint8_t **stream); -void WriteInt64(int64_t val, uint8_t** stream); -void WriteFloat (float val, uint8_t **stream); -void WriteDouble(double val, uint8_t** stream); -void WriteString (const char *string, uint8_t **stream); +uint8_t UncheckedReadInt8(uint8_t** stream); +int16_t UncheckedReadInt16(uint8_t** stream); +int32_t UncheckedReadInt32(uint8_t** stream); +int64_t UncheckedReadInt64(uint8_t** stream); +float UncheckedReadFloat(uint8_t** stream); +double UncheckedReadDouble(uint8_t** stream); +char* UncheckedReadString(uint8_t** stream); +const char* UncheckedReadStringConst(uint8_t** stream); +void UncheckedWriteInt8(uint8_t val, uint8_t** stream); +void UncheckedWriteInt16(int16_t val, uint8_t** stream); +void UncheckedWriteInt32(int32_t val, uint8_t** stream); +void UncheckedWriteInt64(int64_t val, uint8_t** stream); +void UncheckedWriteFloat(float val, uint8_t** stream); +void UncheckedWriteDouble(double val, uint8_t** stream); +void UncheckedWriteString(const char* string, uint8_t** stream); + +void AdvanceStream(TArrayView& stream, size_t bytes); + +uint8_t ReadInt8(TArrayView& stream); +int16_t ReadInt16(TArrayView& stream); +int32_t ReadInt32(TArrayView& stream); +int64_t ReadInt64(TArrayView& stream); +float ReadFloat(TArrayView& stream); +double ReadDouble(TArrayView& stream); +char* ReadString(TArrayView& stream); +const char* ReadStringConst(TArrayView& stream); +void ReadBytes(TArrayView& dst, TArrayView& stream); +void WriteInt8(uint8_t val, TArrayView& stream); +void WriteInt16(int16_t val, TArrayView& stream); +void WriteInt32(int32_t val, TArrayView& stream); +void WriteInt64(int64_t val, TArrayView& stream); +void WriteFloat(float val, TArrayView& stream); +void WriteDouble(double val, TArrayView& stream); +void WriteString(const char* string, TArrayView& stream); +void WriteBytes(const TArrayView& source, TArrayView& stream); +void WriteFString(FString& string, TArrayView& stream); #endif //__D_PROTOCOL_H__ diff --git a/src/g_game.cpp b/src/g_game.cpp index 963437552..1d236328c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -178,8 +178,8 @@ bool demorecording; bool demoplayback; bool demonew; // [RH] Only used around G_InitNew for demos int demover; -uint8_t* demobuffer; -uint8_t* demo_p; +TArray demobuffer; +TArrayView demo_p; uint8_t* democompspot; uint8_t* demobodyspot; size_t maxdemosize; @@ -2089,8 +2089,8 @@ void G_DoLoadGame () arc("importantcvars", cvar); if (!cvar.IsEmpty()) { - uint8_t *vars_p = (uint8_t *)cvar.GetChars(); - C_ReadCVars(&vars_p); + auto vars_p = cvar.GetTArrayView(); + C_ReadCVars(vars_p); } else { @@ -2488,14 +2488,14 @@ void G_ReadDemoTiccmd (usercmd_t *cmd, int player) while (id != DEM_USERCMD && id != DEM_EMPTYUSERCMD) { - if (!demorecording && demo_p >= zdembodyend) + if (!demorecording && demo_p.Data() >= zdembodyend) { // nothing left in the BODY chunk, so end playback. G_CheckDemoStatus (); break; } - id = ReadInt8 (&demo_p); + id = ReadInt8 (demo_p); switch (id) { @@ -2514,7 +2514,7 @@ void G_ReadDemoTiccmd (usercmd_t *cmd, int player) case DEM_DROPPLAYER: { - uint8_t i = ReadInt8 (&demo_p); + uint8_t i = ReadInt8 (demo_p); if (i < MAXPLAYERS) { playeringame[i] = false; @@ -2523,7 +2523,7 @@ void G_ReadDemoTiccmd (usercmd_t *cmd, int player) break; default: - Net_DoCommand (id, &demo_p, player); + Net_DoCommand (id, demo_p, player); break; } } @@ -2556,8 +2556,7 @@ void G_WriteDemoTiccmd (usercmd_t *cmd, int player, int buf) // [RH] Write any special "ticcmds" for this player to the demo if ((specdata = ClientStates[player].Tics[buf % BACKUPTICS].Data.GetData (&speclen)) && !(gametic % TicDup)) { - memcpy (demo_p, specdata, speclen); - demo_p += speclen; + WriteBytes(TArrayView(specdata, speclen), demo_p); ClientStates[player].Tics[buf % BACKUPTICS].Data.SetData(nullptr, 0); } @@ -2566,19 +2565,19 @@ void G_WriteDemoTiccmd (usercmd_t *cmd, int player, int buf) WriteUserCmdMessage (*cmd, &players[player].cmd, demo_p); // [RH] Bigger safety margin - if (demo_p > demobuffer + maxdemosize - 64) + if (demo_p.Data() > demobuffer.Data() + demobuffer.Size() - 64) { - ptrdiff_t pos = demo_p - demobuffer; - ptrdiff_t spot = streamPos - demobuffer; - ptrdiff_t comp = democompspot - demobuffer; - ptrdiff_t body = demobodyspot - demobuffer; + ptrdiff_t pos = demo_p.Data() - demobuffer.Data(); + ptrdiff_t spot = streamPos - demobuffer.Data(); + ptrdiff_t comp = democompspot - demobuffer.Data(); + ptrdiff_t body = demobodyspot - demobuffer.Data(); // [RH] Allocate more space for the demo maxdemosize += 0x20000; - demobuffer = (uint8_t *)M_Realloc (demobuffer, maxdemosize); - demo_p = demobuffer + pos; - streamPos = demobuffer + spot; - democompspot = demobuffer + comp; - demobodyspot = demobuffer + body; + demobuffer.Resize(maxdemosize); + demo_p = TArrayView(demobuffer.Data() + pos, demobuffer.Size() - pos); + streamPos = demobuffer.Data() + spot; + democompspot = demobuffer.Data() + comp; + demobodyspot = demobuffer.Data() + body; } } @@ -2594,7 +2593,7 @@ void G_RecordDemo (const char* name) FixPathSeperator (demoname); DefaultExtension (demoname, ".lmp"); maxdemosize = 0x20000; - demobuffer = (uint8_t *)M_Malloc (maxdemosize); + demobuffer.Resize(maxdemosize); demorecording = true; } @@ -2611,35 +2610,33 @@ void G_BeginRecording (const char *startmap) { startmap = primaryLevel->MapName.GetChars(); } - demo_p = demobuffer; + demo_p = TArrayView(demobuffer.Data(), demobuffer.Size()); - WriteInt32 (FORM_ID, &demo_p); // Write FORM ID - demo_p += 4; // Leave space for len - WriteInt32 (ZDEM_ID, &demo_p); // Write ZDEM ID + WriteInt32 (FORM_ID, demo_p); // Write FORM ID + AdvanceStream(demo_p, 4); // Leave space for len + WriteInt32 (ZDEM_ID, demo_p); // Write ZDEM ID // Write header chunk - StartChunk (ZDHD_ID, &demo_p); - WriteInt16 (DEMOGAMEVERSION, &demo_p); // Write ZDoom version - *demo_p++ = 2; // Write minimum version needed to use this demo. - *demo_p++ = 3; // (Useful?) + StartChunk (ZDHD_ID, demo_p); + WriteInt16 (DEMOGAMEVERSION, demo_p); // Write ZDoom version + WriteInt8(2, demo_p); // Write minimum version needed to use this demo. + WriteInt8(3, demo_p); // (Useful?) - strcpy((char*)demo_p, startmap); // Write name of map demo was recorded on. - demo_p += strlen(startmap) + 1; - WriteInt32(rngseed, &demo_p); // Write RNG seed - *demo_p++ = consoleplayer; - FinishChunk (&demo_p); + WriteString(startmap, demo_p); // Write name of map demo was recorded on. + WriteInt32(rngseed, demo_p); // Write RNG seed + WriteInt8(consoleplayer, demo_p); + FinishChunk (demo_p); // Write player info chunks for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { - StartChunk(UINF_ID, &demo_p); - WriteInt8((uint8_t)i, &demo_p); + StartChunk(UINF_ID, demo_p); + WriteInt8((uint8_t)i, demo_p); auto str = D_GetUserInfoStrings(i); - memcpy(demo_p, str.GetChars(), str.Len() + 1); - demo_p += str.Len() + 1; - FinishChunk(&demo_p); + WriteFString(str, demo_p); + FinishChunk(demo_p); } } @@ -2648,29 +2645,29 @@ void G_BeginRecording (const char *startmap) // enough. if (multiplayer) { - StartChunk (NETD_ID, &demo_p); - FinishChunk (&demo_p); + StartChunk (NETD_ID, demo_p); + FinishChunk (demo_p); } // Write cvars chunk - StartChunk (VARS_ID, &demo_p); - C_WriteCVars (&demo_p, CVAR_SERVERINFO|CVAR_DEMOSAVE); - FinishChunk (&demo_p); + StartChunk (VARS_ID, demo_p); + C_WriteCVars (demo_p, CVAR_SERVERINFO|CVAR_DEMOSAVE); + FinishChunk (demo_p); // Write weapon ordering chunk - StartChunk (WEAP_ID, &demo_p); - P_WriteDemoWeaponsChunk(&demo_p); - FinishChunk (&demo_p); + StartChunk (WEAP_ID, demo_p); + P_WriteDemoWeaponsChunk(demo_p); + FinishChunk (demo_p); // Indicate body is compressed - StartChunk (COMP_ID, &demo_p); - democompspot = demo_p; - WriteInt32 (0, &demo_p); - FinishChunk (&demo_p); + StartChunk (COMP_ID, demo_p); + democompspot = demo_p.Data(); + WriteInt32 (0, demo_p); + FinishChunk (demo_p); // Begin BODY chunk - StartChunk (BODY_ID, &demo_p); - demobodyspot = demo_p; + StartChunk (BODY_ID, demo_p); + demobodyspot = demo_p.Data(); } @@ -2730,13 +2727,13 @@ bool G_ProcessIFFDemo (FString &mapname) for (i = 0; i < MAXPLAYERS; i++) playeringame[i] = 0; - len = ReadInt32 (&demo_p); - zdemformend = demo_p + len + (len & 1); + len = ReadInt32 (demo_p); + zdemformend = demo_p.Data() + len + (len & 1); // Check to make sure this is a ZDEM chunk file. // TODO: Support multiple FORM ZDEMs in a CAT. Might be useful. - id = ReadInt32 (&demo_p); + id = ReadInt32 (demo_p); if (id != ZDEM_ID) { Printf ("Not a " GAMENAME " demo file!\n"); @@ -2745,11 +2742,11 @@ bool G_ProcessIFFDemo (FString &mapname) // Process all chunks until a BODY chunk is encountered. - while (demo_p < zdemformend && !bodyHit) + while (demo_p.Data() < zdemformend && !bodyHit) { - id = ReadInt32 (&demo_p); - len = ReadInt32 (&demo_p); - nextchunk = demo_p + len + (len & 1); + id = ReadInt32 (demo_p); + len = ReadInt32 (demo_p); + nextchunk = demo_p.Data() + len + (len & 1); if (nextchunk > zdemformend) { Printf ("Demo is mangled!\n"); @@ -2761,48 +2758,47 @@ bool G_ProcessIFFDemo (FString &mapname) case ZDHD_ID: headerHit = true; - demover = ReadInt16 (&demo_p); // ZDoom version demo was created with + demover = ReadInt16 (demo_p); // ZDoom version demo was created with if (demover < MINDEMOVERSION) { Printf ("Demo requires an older version of " GAMENAME "!\n"); //return true; } - if (ReadInt16 (&demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version + if (ReadInt16 (demo_p) > DEMOGAMEVERSION) // Minimum ZDoom version { Printf ("Demo requires a newer version of " GAMENAME "!\n"); return true; } if (demover >= 0x21a) { - mapname = (char*)demo_p; - demo_p += mapname.Len() + 1; + mapname = ReadStringConst(demo_p); } else { - mapname = FString((char*)demo_p, 8); - demo_p += 8; + mapname = FString((char*)demo_p.Data(), 8); + AdvanceStream(demo_p, 8); } - rngseed = ReadInt32 (&demo_p); + rngseed = ReadInt32 (demo_p); // Only reset the RNG if this demo is not in conjunction with a savegame. if (mapname[0] != 0) { FRandom::StaticClearRandom (); } - consoleplayer = *demo_p++; + consoleplayer = ReadInt8(demo_p); break; case VARS_ID: - C_ReadCVars (&demo_p); + C_ReadCVars (demo_p); break; case UINF_ID: - i = ReadInt8 (&demo_p); + i = ReadInt8 (demo_p); if (!playeringame[i]) { playeringame[i] = 1; numPlayers++; } - D_ReadUserInfoStrings (i, &demo_p, false); + D_ReadUserInfoStrings (i, demo_p, false); break; case NETD_ID: @@ -2810,21 +2806,21 @@ bool G_ProcessIFFDemo (FString &mapname) break; case WEAP_ID: - P_ReadDemoWeaponsChunk(&demo_p); + P_ReadDemoWeaponsChunk(demo_p); break; case BODY_ID: bodyHit = true; - zdembodyend = demo_p + len; + zdembodyend = demo_p.Data() + len; break; case COMP_ID: - uncompSize = ReadInt32 (&demo_p); + uncompSize = ReadInt32 (demo_p); break; } if (!bodyHit) - demo_p = nextchunk; + demo_p = TArrayView(nextchunk, demo_p.Size() + demo_p.Data() - nextchunk); } if (!headerHit) @@ -2851,17 +2847,16 @@ bool G_ProcessIFFDemo (FString &mapname) if (uncompSize > 0) { - uint8_t *uncompressed = (uint8_t*)M_Malloc(uncompSize); - int r = uncompress (uncompressed, &uncompSize, demo_p, uLong(zdembodyend - demo_p)); + auto uncompressed = TArray(uncompSize, true); + int r = uncompress (uncompressed.Data(), &uncompSize, demo_p.Data(), uLong(zdembodyend - demo_p.Data())); if (r != Z_OK) { Printf ("Could not decompress demo! %s\n", M_ZLibError(r).GetChars()); - M_Free(uncompressed); return true; } - M_Free (demobuffer); - zdembodyend = uncompressed + uncompSize; - demobuffer = demo_p = uncompressed; + zdembodyend = uncompressed.Data() + uncompSize; + demobuffer = std::move(uncompressed); + demo_p = TArrayView(demobuffer.Data(), uncompSize); } return false; @@ -2878,9 +2873,9 @@ void G_DoPlayDemo (void) demolump = fileSystem.CheckNumForFullName (defdemoname.GetChars(), true); if (demolump >= 0) { - int demolen = fileSystem.FileLength (demolump); - demobuffer = (uint8_t *)M_Malloc(demolen); - fileSystem.ReadFile (demolump, demobuffer); + size_t demolen = fileSystem.FileLength (demolump); + demobuffer.Resize(demolen); + fileSystem.ReadFile (demolump, demobuffer.Data()); } else { @@ -2891,26 +2886,26 @@ void G_DoPlayDemo (void) { I_Error("Unable to open demo '%s'", defdemoname.GetChars()); } - auto len = fr.GetLength(); - demobuffer = (uint8_t*)M_Malloc(len); - if (fr.Read(demobuffer, len) != len) + size_t demolen = fr.GetLength(); + demobuffer.Resize(demolen); + if (fr.Read(demobuffer.Data(), demolen) != demolen) { I_Error("Unable to read demo '%s'", defdemoname.GetChars()); } } - demo_p = demobuffer; + demo_p = TArrayView(demobuffer.Data(), demobuffer.Size()); if (singledemo) Printf ("Playing demo %s\n", defdemoname.GetChars()); C_BackupCVars (); // [RH] Save cvars that might be affected by demo - if (ReadInt32 (&demo_p) != FORM_ID) + if (ReadInt32 (demo_p) != FORM_ID) { const char *eek = "Cannot play non-" GAMENAME " demos.\n"; C_ForgetCVars(); - M_Free(demobuffer); - demo_p = demobuffer = NULL; + demobuffer.Reset(); + demo_p = NULL; if (singledemo) { I_Error ("%s", eek); @@ -2990,8 +2985,7 @@ bool G_CheckDemoStatus (void) endtime = I_GetTime () - starttime; C_RestoreCVars (); // [RH] Restore cvars demo might have changed - M_Free (demobuffer); - demobuffer = NULL; + demobuffer.Reset(); P_SetupWeapons_ntohton(); demoplayback = false; @@ -3034,9 +3028,7 @@ bool G_CheckDemoStatus (void) if (demorecording) { - uint8_t *formlen; - - WriteInt8 (DEM_STOP, &demo_p); + WriteInt8 (DEM_STOP, demo_p); if (demo_compress) { @@ -3044,32 +3036,31 @@ bool G_CheckDemoStatus (void) // a compressed version. If the BODY successfully compresses, the // contents of the COMP chunk will be changed to indicate the // uncompressed size of the BODY. - uLong len = uLong(demo_p - demobodyspot); + uLong len = uLong(demo_p.Data() - demobodyspot); uLong outlen = (len + len/100 + 12); TArray compressed(outlen, true); int r = compress2 (compressed.Data(), &outlen, demobodyspot, len, 9); if (r == Z_OK && outlen < len) { - formlen = democompspot; - WriteInt32 (len, &democompspot); + UncheckedWriteInt32 (len, &democompspot); memcpy (demobodyspot, compressed.Data(), outlen); - demo_p = demobodyspot + outlen; + demo_p = TArrayView(demobodyspot + outlen, demo_p.Size() + len - outlen); } } - FinishChunk (&demo_p); - formlen = demobuffer + 4; - WriteInt32 (int(demo_p - demobuffer - 8), &formlen); + FinishChunk (demo_p); + uint8_t* formlen = demobuffer.Data() + 4; + UncheckedWriteInt32 (int(demo_p.Data() - demobuffer.Data() - 8), &formlen); auto fw = FileWriter::Open(demoname.GetChars()); bool saved = false; if (fw != nullptr) { - const size_t size = demo_p - demobuffer; - saved = fw->Write(demobuffer, size) == size; + const size_t size = demo_p.Data() - demobuffer.Data(); + saved = fw->Write(demobuffer.Data(), size) == size; delete fw; if (!saved) RemoveFile(demoname.GetChars()); } - M_Free (demobuffer); + demobuffer.Reset(); demorecording = false; stoprecording = false; if (saved) diff --git a/src/gamedata/a_weapons.cpp b/src/gamedata/a_weapons.cpp index 93768fd54..be8c01df5 100644 --- a/src/gamedata/a_weapons.cpp +++ b/src/gamedata/a_weapons.cpp @@ -855,7 +855,7 @@ static int ntoh_cmp(const void *a, const void *b) // //=========================================================================== -void P_WriteDemoWeaponsChunk(uint8_t **demo) +void P_WriteDemoWeaponsChunk(TArrayView& demo) { WriteInt16(Weapons_ntoh.Size(), demo); for (unsigned int i = 1; i < Weapons_ntoh.Size(); ++i) @@ -873,7 +873,7 @@ void P_WriteDemoWeaponsChunk(uint8_t **demo) // //=========================================================================== -void P_ReadDemoWeaponsChunk(uint8_t **demo) +void P_ReadDemoWeaponsChunk(TArrayView& demo) { int count, i; PClassActor *type; @@ -938,7 +938,7 @@ void Net_WriteWeapon(PClassActor *type) // //=========================================================================== -PClassActor *Net_ReadWeapon(uint8_t **stream) +PClassActor *Net_ReadWeapon(TArrayView& stream) { int index; diff --git a/src/gamedata/a_weapons.h b/src/gamedata/a_weapons.h index a626959d8..610e2502f 100644 --- a/src/gamedata/a_weapons.h +++ b/src/gamedata/a_weapons.h @@ -120,11 +120,11 @@ public: void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); void Net_WriteWeapon(PClassActor *type); -PClassActor *Net_ReadWeapon(uint8_t **stream); +PClassActor *Net_ReadWeapon(TArrayView& stream); void P_SetupWeapons_ntohton(); -void P_WriteDemoWeaponsChunk(uint8_t **demo); -void P_ReadDemoWeaponsChunk(uint8_t **demo); +void P_WriteDemoWeaponsChunk(TArrayView& demo); +void P_ReadDemoWeaponsChunk(TArrayView& demo); enum class EBobStyle diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 417b0e49f..a43204e64 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -667,7 +667,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply // //============================================================================ -void P_ConversationCommand (int netcode, int pnum, uint8_t **stream) +void P_ConversationCommand (int netcode, int pnum, TArrayView& stream) { player_t *player = &players[pnum]; diff --git a/src/p_conversation.h b/src/p_conversation.h index d674b3d53..8f55da7b4 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -70,7 +70,7 @@ void P_FreeStrifeConversations (); void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle); void P_ResumeConversation (); -void P_ConversationCommand (int netcode, int player, uint8_t **stream); +void P_ConversationCommand (int netcode, int player, TArrayView& stream); #endif diff --git a/src/playsim/bots/b_bot.h b/src/playsim/bots/b_bot.h index 9e9cadeb8..bbcd4f2b0 100644 --- a/src/playsim/bots/b_bot.h +++ b/src/playsim/bots/b_bot.h @@ -120,7 +120,7 @@ public: void Init (); void End(); bool SpawnBot (const char *name, int color = NOCOLOR); - void TryAddBot (FLevelLocals *Level, uint8_t **stream, int player); + void TryAddBot (FLevelLocals *Level, TArrayView& stream, int player); void RemoveAllBots (FLevelLocals *Level, bool fromlist); bool LoadBots (); void ForgetBots (); @@ -154,7 +154,7 @@ public: private: //(b_game.cpp) - bool DoAddBot (FLevelLocals *Level, uint8_t *info, botskill_t skill); + bool DoAddBot (FLevelLocals *Level, TArrayView info, botskill_t skill); protected: bool ctf; diff --git a/src/playsim/bots/b_game.cpp b/src/playsim/bots/b_game.cpp index 19f212a61..ba35b580d 100644 --- a/src/playsim/bots/b_game.cpp +++ b/src/playsim/bots/b_game.cpp @@ -319,7 +319,7 @@ bool FCajunMaster::SpawnBot (const char *name, int color) return true; } -void FCajunMaster::TryAddBot (FLevelLocals *Level, uint8_t **stream, int player) +void FCajunMaster::TryAddBot (FLevelLocals *Level, TArrayView& stream, int player) { int botshift = ReadInt8 (stream); char *info = ReadString (stream); @@ -342,7 +342,7 @@ void FCajunMaster::TryAddBot (FLevelLocals *Level, uint8_t **stream, int player) } } - if (DoAddBot (Level,(uint8_t *)info, skill)) + if (DoAddBot (Level, TArrayView((uint8_t*)info, strlen(info)+1), skill)) { //Increment this. botnum++; @@ -363,7 +363,7 @@ void FCajunMaster::TryAddBot (FLevelLocals *Level, uint8_t **stream, int player) delete[] info; } -bool FCajunMaster::DoAddBot (FLevelLocals *Level, uint8_t *info, botskill_t skill) +bool FCajunMaster::DoAddBot (FLevelLocals *Level, TArrayView info, botskill_t skill) { int bnum; @@ -381,7 +381,7 @@ bool FCajunMaster::DoAddBot (FLevelLocals *Level, uint8_t *info, botskill_t skil return false; } - D_ReadUserInfoStrings (bnum, &info, false); + D_ReadUserInfoStrings (bnum, info, false); multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost). players[bnum].Bot = Level->CreateThinker();