From 202d0d747f491899ef296ac659cd6d68239173ae Mon Sep 17 00:00:00 2001 From: Boondorl Date: Thu, 4 Jan 2024 14:18:28 -0500 Subject: [PATCH] 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. --- src/d_net.cpp | 14 ++- src/d_protocol.h | 2 +- src/events.cpp | 164 +++++++++++++++++++++++++++++++- src/events.h | 101 +++++++++++++++++++- src/scripting/thingdef_data.cpp | 4 + wadsrc/static/zscript/events.zs | 24 ++++- 6 files changed, 293 insertions(+), 16 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 0e9473d59f..6400ea0583 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -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 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: diff --git a/src/d_protocol.h b/src/d_protocol.h index 5899dd8ac7..86ecce1279 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -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 diff --git a/src/events.cpp b/src/events.cpp index 5ce46fc05c..04bc39bc8b 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -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; diff --git a/src/events.h b/src/events.h index b5d5026384..ca72076840 100755 --- a/src/events.h +++ b/src/events.h @@ -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 _stream = {}; + TArray _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& stream) : Player(player), Command(command) + FNetworkCommand(const int player, const FName& command, TArray& 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 _buffer; + TArray _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(); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 49fc9bc5ef..bc85a7b284 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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); diff --git a/wadsrc/static/zscript/events.zs b/wadsrc/static/zscript/events.zs index f848148891..6d4115210c 100644 --- a/wadsrc/static/zscript/events.zs +++ b/wadsrc/static/zscript/events.zs @@ -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 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); }