Prevent buffer overflows when using streams
This commit is contained in:
parent
13a8b0e5ba
commit
ab7b1642bc
18 changed files with 600 additions and 388 deletions
|
|
@ -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<FBaseCVar *> &cvars, uint32_t filter)
|
|||
}
|
||||
}
|
||||
|
||||
void C_WriteCVars (uint8_t **demo_p, uint32_t filter, bool compact)
|
||||
void C_WriteCVars (TArrayView<uint8_t>& 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<uint8_t>& 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
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& 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<uint8_t>& 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<uint8_t>& demo_p);
|
||||
|
||||
void C_InstallHandlers(ConsoleCallbacks* cb);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream);
|
||||
void Net_ReadUserInfo(int client, TArrayView<uint8_t>& stream);
|
||||
void Net_ReadGameInfo(TArrayView<uint8_t>& stream);
|
||||
void Net_SetGameInfo(TArrayView<uint8_t>& 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<int>(NetBuffer[2], 1, MAXTICDUP);
|
||||
memcpy(GameID, &NetBuffer[3], 8);
|
||||
uint8_t* stream = &NetBuffer[11];
|
||||
TArrayView<uint8_t> 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<uint8_t> 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<uint8_t> 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)
|
||||
|
|
|
|||
|
|
@ -265,6 +265,11 @@ FString &FString::operator = (const char *copyStr)
|
|||
return *this;
|
||||
}
|
||||
|
||||
TArrayView<uint8_t> FString::GetTArrayView()
|
||||
{
|
||||
return TArrayView((uint8_t*)Chars, Len() + 1);
|
||||
}
|
||||
|
||||
void FString::Format (const char *fmt, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ public:
|
|||
|
||||
const char *GetChars() const { return Chars; }
|
||||
|
||||
TArrayView<uint8_t> 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
|
||||
|
|
|
|||
190
src/d_net.cpp
190
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<uint8_t>& 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<uint8_t> 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<uint8_t*> data = {};
|
||||
TArray<TArrayView<uint8_t>> 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<uint8_t> skipper = TArrayView(&NetBuffer[curByte], MAX_MSGLEN - curByte);
|
||||
SkipUserCmdMessage(skipper);
|
||||
|
||||
TArrayView<uint8_t> 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<uint8_t> 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t> 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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.
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
void SetData(const uint8_t* data, int len);
|
||||
uint8_t* GetData(int* len = nullptr);
|
||||
TArrayView<uint8_t> 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<uint8_t>& stream, int player);
|
||||
void Net_SkipCommand(int cmd, TArrayView<uint8_t>& stream);
|
||||
|
||||
bool Net_CheckCutsceneReady();
|
||||
void Net_AdvanceCutscene();
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& 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<uint8_t>& stream, bool update);
|
||||
|
||||
struct FPlayerColorSet;
|
||||
void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **colorset);
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& 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<uint8_t>& 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<uint8_t>& stream, bool update)
|
||||
{
|
||||
userinfo_t *info = &players[pnum].userinfo;
|
||||
TArray<FName> 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)
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream, size_t bytes)
|
||||
{
|
||||
assert(bytes <= stream.Size());
|
||||
stream = TArrayView(stream.Data() + bytes, stream.Size() - bytes);
|
||||
}
|
||||
|
||||
// Checked stream functions
|
||||
|
||||
char* ReadString(TArrayView<uint8_t>& 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<uint8_t>& 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<uint8_t>& dst, TArrayView<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t i;
|
||||
float f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt32 (stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
double ReadDouble(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int64_t i;
|
||||
double f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt64(stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
void WriteString(const char *string, TArrayView<uint8_t>& 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<uint8_t>& source, TArrayView<uint8_t>& 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<uint8_t>& stream)
|
||||
{
|
||||
WriteBytes(string.GetTArrayView(), stream);
|
||||
}
|
||||
|
||||
void WriteInt8(uint8_t v, TArrayView<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& stream)
|
||||
{
|
||||
if (streamPos == nullptr)
|
||||
return;
|
||||
|
||||
int len = int(*stream - streamPos - 4);
|
||||
WriteInt32(len, &streamPos);
|
||||
int len = int(stream.Data() - streamPos - 4);
|
||||
auto streamPosView = TArrayView<uint8_t>(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<uint8_t>& stream)
|
||||
{
|
||||
int len = ReadInt32(stream);
|
||||
*stream += len + (len & 1);
|
||||
AdvanceStream(stream, len + (len & 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream);
|
||||
void FinishChunk (TArrayView<uint8_t>& stream);
|
||||
void SkipChunk (TArrayView<uint8_t>& 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<uint8_t>& stream);
|
||||
void PackUserCmd(const usercmd_t& ucmd, const usercmd_t* basis, TArrayView<uint8_t>& stream);
|
||||
void WriteUserCmdMessage(const usercmd_t& ucmd, const usercmd_t *basis, TArrayView<uint8_t>& stream);
|
||||
|
||||
int SkipUserCmdMessage(uint8_t*& stream);
|
||||
int ReadUserCmdMessage(uint8_t*& stream, int player, int tic);
|
||||
void SkipUserCmdMessage(TArrayView<uint8_t>& stream);
|
||||
void ReadUserCmdMessage(TArrayView<uint8_t>& 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<uint8_t>& stream, size_t bytes);
|
||||
|
||||
uint8_t ReadInt8(TArrayView<uint8_t>& stream);
|
||||
int16_t ReadInt16(TArrayView<uint8_t>& stream);
|
||||
int32_t ReadInt32(TArrayView<uint8_t>& stream);
|
||||
int64_t ReadInt64(TArrayView<uint8_t>& stream);
|
||||
float ReadFloat(TArrayView<uint8_t>& stream);
|
||||
double ReadDouble(TArrayView<uint8_t>& stream);
|
||||
char* ReadString(TArrayView<uint8_t>& stream);
|
||||
const char* ReadStringConst(TArrayView<uint8_t>& stream);
|
||||
void ReadBytes(TArrayView<uint8_t>& dst, TArrayView<uint8_t>& stream);
|
||||
void WriteInt8(uint8_t val, TArrayView<uint8_t>& stream);
|
||||
void WriteInt16(int16_t val, TArrayView<uint8_t>& stream);
|
||||
void WriteInt32(int32_t val, TArrayView<uint8_t>& stream);
|
||||
void WriteInt64(int64_t val, TArrayView<uint8_t>& stream);
|
||||
void WriteFloat(float val, TArrayView<uint8_t>& stream);
|
||||
void WriteDouble(double val, TArrayView<uint8_t>& stream);
|
||||
void WriteString(const char* string, TArrayView<uint8_t>& stream);
|
||||
void WriteBytes(const TArrayView<uint8_t>& source, TArrayView<uint8_t>& stream);
|
||||
void WriteFString(FString& string, TArrayView<uint8_t>& stream);
|
||||
|
||||
#endif //__D_PROTOCOL_H__
|
||||
|
|
|
|||
203
src/g_game.cpp
203
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<uint8_t> demobuffer;
|
||||
TArrayView<uint8_t> 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<uint8_t>(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<Byte> 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)
|
||||
|
|
|
|||
|
|
@ -855,7 +855,7 @@ static int ntoh_cmp(const void *a, const void *b)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void P_WriteDemoWeaponsChunk(uint8_t **demo)
|
||||
void P_WriteDemoWeaponsChunk(TArrayView<uint8_t>& 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<uint8_t>& 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<uint8_t>& stream)
|
||||
{
|
||||
int index;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream);
|
||||
|
||||
void P_SetupWeapons_ntohton();
|
||||
void P_WriteDemoWeaponsChunk(uint8_t **demo);
|
||||
void P_ReadDemoWeaponsChunk(uint8_t **demo);
|
||||
void P_WriteDemoWeaponsChunk(TArrayView<uint8_t>& demo);
|
||||
void P_ReadDemoWeaponsChunk(TArrayView<uint8_t>& demo);
|
||||
|
||||
|
||||
enum class EBobStyle
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream)
|
||||
{
|
||||
player_t *player = &players[pnum];
|
||||
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& stream);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& 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<uint8_t> info, botskill_t skill);
|
||||
|
||||
protected:
|
||||
bool ctf;
|
||||
|
|
|
|||
|
|
@ -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<uint8_t>& 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<uint8_t> 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<DBot>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue