Added NetworkBuffer

Allows for a command to be built before sending it off. Added wrapper functions for certain data types. Changed command from a number to a Name.
This commit is contained in:
Boondorl 2024-01-04 14:18:28 -05:00 committed by Christoph Oelckers
parent 9565c94cd2
commit 202d0d747f
6 changed files with 293 additions and 16 deletions

View file

@ -2708,13 +2708,16 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
case DEM_ZSC_CMD:
{
int cmd = ReadLong(stream);
FName cmd = ReadStringConst(stream);
unsigned int size = ReadWord(stream);
TArray<uint8_t> buffer = {};
buffer.Grow(size);
for (unsigned int i = 0u; i < size; ++i)
buffer.Push(ReadByte(stream));
if (size)
{
buffer.Grow(size);
for (unsigned int i = 0u; i < size; ++i)
buffer.Push(ReadByte(stream));
}
FNetworkCommand netCmd = { player, cmd, buffer };
primaryLevel->localEventManager->NetCommand(netCmd);
@ -2779,7 +2782,8 @@ void Net_SkipCommand (int type, uint8_t **stream)
break;
case DEM_ZSC_CMD:
skip = 6 + (((*stream)[4] << 8) | (*stream)[5]);
skip = strlen((char*)(*stream)) + 1;
skip += (((*stream)[skip] << 8) | (*stream)[skip + 1]) + 2;
break;
case DEM_SUMMON2:

View file

@ -163,7 +163,7 @@ enum EDemoCommand
DEM_MDK, // 71 String: Damage type
DEM_SETINV, // 72 SetInventory
DEM_ENDSCREENJOB,
DEM_ZSC_CMD, // 74 Long: Command id, Word: Byte size of command
DEM_ZSC_CMD, // 74 String: Command, Word: Byte size of command
};
// The following are implemented by cht_DoCheat in m_cheat.cpp

View file

@ -221,7 +221,7 @@ bool EventManager::SendNetworkEvent(FString name, int arg1, int arg2, int arg3,
return true;
}
bool EventManager::SendNetworkCommand(int cmd, VMVa_List args)
bool EventManager::SendNetworkCommand(const FName& cmd, VMVa_List& args)
{
if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL)
return false;
@ -247,11 +247,13 @@ bool EventManager::SendNetworkCommand(int cmd, VMVa_List args)
break;
case NET_STRING:
{
++bytes; // Strings will always consume at least one byte.
const FString* str = ListGetString(args);
if (str != nullptr)
bytes += str->Len();
break;
}
}
if (tag != NET_STRING)
@ -261,7 +263,7 @@ bool EventManager::SendNetworkCommand(int cmd, VMVa_List args)
}
Net_WriteByte(DEM_ZSC_CMD);
Net_WriteLong(cmd); // Using a full int here to allow better prevention of overlapping command ids.
Net_WriteString(cmd.GetChars());
Net_WriteWord(bytes);
constexpr char Default[] = "";
@ -293,12 +295,14 @@ bool EventManager::SendNetworkCommand(int cmd, VMVa_List args)
break;
case NET_STRING:
{
const FString* str = ListGetString(args);
if (str != nullptr)
Net_WriteString(str->GetChars());
else
Net_WriteString(Default); // Still have to send something here to be read correctly.
break;
}
}
tag = ListGetInt(args);
@ -307,6 +311,48 @@ bool EventManager::SendNetworkCommand(int cmd, VMVa_List args)
return true;
}
bool EventManager::SendNetworkBuffer(const FName& cmd, const FNetworkBuffer* buffer)
{
if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL)
return false;
Net_WriteByte(DEM_ZSC_CMD);
Net_WriteString(cmd.GetChars());
Net_WriteWord(buffer != nullptr ? buffer->GetBytes() : 0);
if (buffer != nullptr)
{
for (unsigned int i = 0u; i < buffer->GetBufferSize(); ++i)
{
const auto& pair = buffer->GetPair(i);
switch (pair.GetType())
{
case NET_BYTE:
Net_WriteByte(pair.GetInt());
break;
case NET_WORD:
Net_WriteWord(pair.GetInt());
break;
case NET_LONG:
Net_WriteLong(pair.GetInt());
break;
case NET_FLOAT:
Net_WriteFloat(pair.GetFloat());
break;
case NET_STRING:
Net_WriteString(pair.GetString());
break;
}
}
}
return true;
}
bool EventManager::CheckHandler(DStaticEventHandler* handler)
{
for (DStaticEventHandler* lhandler = FirstEventHandler; lhandler; lhandler = lhandler->next)
@ -855,6 +901,109 @@ DEFINE_ACTION_FUNCTION(FNetworkCommand, ReadString)
ACTION_RETURN_STRING(res);
}
DEFINE_ACTION_FUNCTION(FNetworkCommand, ReadName)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand);
FName res = NAME_None;
auto str = self->ReadString();
if (str != nullptr)
res = str;
ACTION_RETURN_INT(res.GetIndex());
}
DEFINE_ACTION_FUNCTION(FNetworkCommand, ReadVector2)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand);
DVector2 vec = {};
vec.X = self->ReadFloat();
vec.Y = self->ReadFloat();
ACTION_RETURN_VEC2(vec);
}
DEFINE_ACTION_FUNCTION(FNetworkCommand, ReadVector3)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkCommand);
DVector3 vec = {};
vec.X = self->ReadFloat();
vec.Y = self->ReadFloat();
vec.Z = self->ReadFloat();
ACTION_RETURN_VEC3(vec);
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddByte)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_INT(value);
self->AddByte(value);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddWord)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_INT(value);
self->AddWord(value);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddLong)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_INT(value);
self->AddLong(value);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddFloat)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_FLOAT(value);
self->AddFloat(value);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddString)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_STRING(value);
self->AddString(value);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddName)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_NAME(value);
self->AddString(value.GetChars());
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddVector2)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
self->AddFloat(x);
self->AddFloat(y);
return 0;
}
DEFINE_ACTION_FUNCTION(FNetworkBuffer, AddVector3)
{
PARAM_SELF_STRUCT_PROLOGUE(FNetworkBuffer);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
self->AddFloat(x);
self->AddFloat(y);
self->AddFloat(z);
return 0;
}
DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
{
PARAM_SELF_PROLOGUE(DStaticEventHandler);
@ -867,13 +1016,22 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkCommand)
{
PARAM_PROLOGUE;
PARAM_INT(cmd);
PARAM_NAME(cmd);
PARAM_VA_POINTER(va_reginfo);
VMVa_List args = { param + 1, 0, numparam - 2, va_reginfo + 1 };
ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkCommand(cmd, args));
}
DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkBuffer)
{
PARAM_PROLOGUE;
PARAM_NAME(cmd);
PARAM_POINTER(buffer, FNetworkBuffer);
ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkBuffer(cmd, buffer));
}
DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent)
{
PARAM_PROLOGUE;

View file

@ -5,6 +5,7 @@
#include "d_event.h"
#include "sbar.h"
#include "info.h"
#include "vm.h"
class DStaticEventHandler;
struct EventManager;
@ -31,7 +32,7 @@ struct FNetworkCommand
{
private:
size_t _index = 0;
TArray<uint8_t> _stream = {};
TArray<uint8_t> _stream;
inline bool IsValid() const
{
@ -39,10 +40,10 @@ private:
}
public:
int Player = 0;
int Command = 0;
int Player;
FName Command;
FNetworkCommand(const int player, const int command, TArray<uint8_t>& stream) : Player(player), Command(command)
FNetworkCommand(const int player, const FName& command, TArray<uint8_t>& stream) : Player(player), Command(command)
{
_stream.Swap(stream);
}
@ -131,6 +132,94 @@ public:
}
};
struct FNetworkBuffer
{
public:
struct BufferPair
{
private:
ENetCmd _type;
VMValue _message;
public:
BufferPair(const ENetCmd type, const int message) : _type(type), _message(message) {}
BufferPair(const ENetCmd type, const double message) : _type(type), _message(message) {}
BufferPair(const ENetCmd type, const FString* message) : _type(type), _message(message) {}
inline ENetCmd GetType() const
{
return _type;
}
inline int GetInt() const
{
return _message.i;
}
inline double GetFloat() const
{
return _message.f;
}
inline const char* GetString() const
{
return _message.s().GetChars();
}
};
private:
unsigned int _size;
TArray<BufferPair> _buffer;
TArray<FString> _strings; // Local copies of these need to be stored since VMValues store pointers to strings.
public:
inline unsigned int GetBytes() const
{
return _size;
}
inline unsigned int GetBufferSize() const
{
return _buffer.Size();
}
inline const BufferPair& GetPair(unsigned int i) const
{
return _buffer[i];
}
void AddByte(int byte)
{
++_size;
_buffer.Push({ NET_BYTE, byte });
}
void AddWord(int word)
{
_size += 2u;
_buffer.Push({ NET_WORD, word });
}
void AddLong(int msg)
{
_size += 4u;
_buffer.Push({ NET_LONG, msg });
}
void AddFloat(double msg)
{
_size += 4u;
_buffer.Push({ NET_FLOAT, msg });
}
void AddString(const FString& msg)
{
_size += msg.Len() + 1u;
unsigned int index = _strings.Push(msg);
_buffer.Push({ NET_STRING, &_strings[index] });
}
};
// ==============================================
//
// EventHandler - base class
@ -413,7 +502,9 @@ struct EventManager
// send networked event. unified function.
bool SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual);
// Send a custom network command from ZScript.
bool SendNetworkCommand(int cmd, VMVa_List args);
bool SendNetworkCommand(const FName& cmd, VMVa_List& args);
// Send a pre-built command buffer over.
bool SendNetworkBuffer(const FName& cmd, const FNetworkBuffer* buffer);
// check if there is anything that should receive GUI events
bool CheckUiProcessors();

View file

@ -812,6 +812,10 @@ void InitThingdef()
netcmdstruct->Size = sizeof(FNetworkCommand);
netcmdstruct->Align = alignof(FNetworkCommand);
auto netbuffstruct = NewStruct("NetworkBuffer", nullptr);
netbuffstruct->Size = sizeof(FNetworkBuffer);
netbuffstruct->Align = alignof(FNetworkBuffer);
auto fltd = NewStruct("FLineTraceData", nullptr);
fltd->Size = sizeof(FLineTraceData);
fltd->Align = alignof(FLineTraceData);

View file

@ -10,13 +10,32 @@ enum ENetCmd
struct NetworkCommand native play version("4.12")
{
native readonly int Player;
native readonly int Command;
native readonly Name Command;
native int ReadByte();
native int ReadWord();
native int ReadLong();
native double ReadFloat();
native string ReadString();
// Wrappers
native Name ReadName();
native Vector2 ReadVector2();
native Vector3 ReadVector3();
}
struct NetworkBuffer native version("4.12")
{
native void AddByte(int value);
native void AddWord(int value);
native void AddLong(int value);
native void AddFloat(double value);
native void AddString(string value);
// Wrappers
native void AddName(Name value);
native void AddVector2(Vector2 value);
native void AddVector3(Vector3 value);
}
struct RenderEvent native ui version("2.4")
@ -171,6 +190,7 @@ class EventHandler : StaticEventHandler native version("2.4")
{
clearscope static native StaticEventHandler Find(class<StaticEventHandler> type);
clearscope static native void SendNetworkEvent(String name, int arg1 = 0, int arg2 = 0, int arg3 = 0);
version("4.12") clearscope static native vararg bool SendNetworkCommand(int cmd, ...);
version("4.12") clearscope static native vararg bool SendNetworkCommand(Name cmd, ...);
version("4.12") clearscope static native bool SendNetworkBuffer(Name cmd, NetworkBuffer buffer);
clearscope static native void SendInterfaceEvent(int playerNum, string name, int arg1 = 0, int arg2 = 0, int arg3 = 0);
}