refactor(netpacket): Simplify NetPacket functions for packet buffer writes and size tests#2329
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/GameNetwork/NetPacketStructs.h | Major new file: introduces SmallNetPacketCommandBaseSelect bitfield, SmallNetPacketCommandBase with dynamic field selection, NetPacketCommandTemplate/SmallNetPacketCommandTemplate CRTP templates, network write helpers (writePrimitive, writeObject, etc.), and per-command Base/Data struct pairs. Represents the core abstraction of the refactor. No critical issues found; the write helpers are correctly placed before #pragma pack(push,1). |
| Core/GameEngine/Source/GameNetwork/NetPacketStructs.cpp | New implementation file: contains all copyBytes / getSize logic for every packet command type. Uses nullptr correctly, const-correctness is good. Each Base::copyBytes correctly mirrors its CommandBase struct's included/excluded fields. |
| Core/GameEngine/Include/GameNetwork/NetCommandMsg.h | Introduces NetCommandMsgT CRTP template, NetAckCommandMsg base class consolidating the three ack types, and replaces getPackedByteCount() with getSizeForNetPacket/SmallNetPacket virtual interface. The virtual overrides in NetCommandMsgT are implicitly private (access specifier omitted), which is functionally correct but unusual and potentially causes compiler warnings. |
| Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp | Replaces per-type getPackedByteCount() with getSmallNetPacketSelect() for every command type. Three implementations (NetDisconnectFrameCommandMsg, NetDisconnectScreenOffCommandMsg, NetFrameResendRequestCommandMsg) return useFrame=1 despite the corresponding fixed-base structs having frame commented out, which may silently change the wire format for those command types in the normal packet path. |
| Core/GameEngine/Source/GameNetwork/NetPacket.cpp | Core packet logic consolidated into a single addCommand() method. Size check now correctly precedes all state updates (m_last*), and updateLastCommandId captures the pre-masking useCommandId to ensure m_lastCommandID is always advanced for command types that use IDs. Atomic state update behavior is preserved. |
Class Diagram
%%{init: {'theme': 'neutral'}}%%
classDiagram
class NetCommandMsg {
+getSizeForNetPacket() size_t*
+copyBytesForNetPacket() size_t*
+getSizeForSmallNetPacket() size_t*
+copyBytesForSmallNetPacket() size_t*
+getSmallNetPacketSelect() Select*
}
class NetCommandMsgT~NetPacketType,SmallNetPacketType~ {
-getSizeForNetPacket() size_t
-copyBytesForNetPacket() size_t
-getSizeForSmallNetPacket() size_t
-copyBytesForSmallNetPacket() size_t
}
class NetAckCommandMsg {
+getSmallNetPacketSelect() Select
+getCommandID() UnsignedShort
+getOriginalPlayerID() UnsignedByte
}
class NetPacketCommandTemplate~Base,Data~ {
+getSize(msg) size_t
+copyBytes(buffer, ref) size_t
}
class SmallNetPacketCommandTemplate~Base,Data~ {
+getSize(msg, select) size_t
+copyBytes(buffer, ref, select) size_t
}
class SmallNetPacketCommandBase {
+getSize(select) size_t
+copyBytes(buffer, ref, select) size_t
}
class SmallNetPacketCommandBaseSelect {
+useCommandType : 1
+useRelay : 1
+useFrame : 1
+usePlayerId : 1
+useCommandId : 1
}
NetCommandMsg <|-- NetCommandMsgT
NetCommandMsgT <|-- NetAckCommandMsg
NetCommandMsgT <|-- NetGameCommandMsg
NetCommandMsgT <|-- NetFrameCommandMsg
NetAckCommandMsg <|-- NetAckBothCommandMsg
NetAckCommandMsg <|-- NetAckStage1CommandMsg
NetAckCommandMsg <|-- NetAckStage2CommandMsg
SmallNetPacketCommandTemplate --> SmallNetPacketCommandBase : Base
SmallNetPacketCommandTemplate --> SmallNetPacketCommandBaseSelect : uses
NetCommandMsgT ..> NetPacketCommandTemplate : getSizeForNetPacket
NetCommandMsgT ..> SmallNetPacketCommandTemplate : getSizeForSmallNetPacket
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameNetwork/NetCommandMsg.h
Line: 77-99
Comment:
**Private virtual overrides in `NetCommandMsgT`**
The virtual method overrides inside `NetCommandMsgT` are implicitly `private` (since `class` uses private-by-default access), even though the corresponding functions in `NetCommandMsg` are declared `public`. While this is valid C++ — polymorphic dispatch still works through a `NetCommandMsg*` — it creates an access mismatch that can confuse readers and may trigger compiler warnings (e.g., MSVC's diagnostic for accessibility narrowing in virtual overrides).
Consider adding an explicit `public:` access specifier before the four overrides:
```suggestion
template<typename NetPacketType, typename SmallNetPacketType>
class NetCommandMsgT : public NetCommandMsg
{
public:
virtual size_t getSizeForNetPacket() const
{
return NetPacketType::getSize(*this);
}
virtual size_t copyBytesForNetPacket(UnsignedByte* buffer, const NetCommandRef& ref) const
{
return NetPacketType::copyBytes(buffer, ref);
}
virtual size_t getSizeForSmallNetPacket(const Select* select = nullptr) const
{
return SmallNetPacketType::getSize(*this, select);
}
virtual size_t copyBytesForSmallNetPacket(UnsignedByte* buffer, const NetCommandRef& ref, const Select* select = nullptr) const
{
return SmallNetPacketType::copyBytes(buffer, ref, select);
}
};
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp
Line: 1159-1178
Comment:
**`useFrame=1` inconsistent with corresponding fixed-base struct for these command types**
`NetDisconnectFrameCommandMsg::getSmallNetPacketSelect()` returns `useFrame=1`, but `NetPacketDisconnectFrameCommandBase::CommandBase` (used by the non-small `getSizeForNetPacket`/`copyBytesForNetPacket` path) has the frame field commented out — indicating that the original protocol for this command type never wrote `executionFrame`.
With `useFrame=1` in the small-packet path, `executionFrame` **will** be written to the packet whenever the execution frame advances between commands (which happens on every new game frame). This is a behavioural deviation from the pre-refactor code. Because the generic receiver parser accepts frame tags anywhere, it won't crash, but the `executionFrame` now carried on wire for these messages was not there before.
The same issue applies to:
- `NetDisconnectScreenOffCommandMsg::getSmallNetPacketSelect()` at `Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp:1188`
- `NetFrameResendRequestCommandMsg::getSmallNetPacketSelect()` at `Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp:1217`
If these command types genuinely do not need `executionFrame` in the packet (as the fixed-base structs suggest), all three should use `select.useFrame = 0`:
```suggestion
NetCommandMsg::Select NetDisconnectFrameCommandMsg::getSmallNetPacketSelect() const {
Select select;
select.useCommandType = 1;
select.useRelay = 1;
select.useFrame = 0;
select.usePlayerId = 1;
select.useCommandId = 1;
return select;
}
```
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: 35fa72a
aea8b1a to
d8f9dc1
Compare
|
Would it make sense to use macros? For some of the repeating stuff like: |
|
Preferably a template. I will think about it. |
|
Replicated to Generals. |
d8f9dc1 to
9c9ffb9
Compare
Simplified in fixup commit with template. |
86faf0d to
4f72f27
Compare
…NetAckStage1CommandMsg, NetAckStage2CommandMsg (TheSuperHackers#2329)
…NetCommandMsg::getSizeForNetPacket (TheSuperHackers#2329)
…rites and size tests (TheSuperHackers#2329)
|
Goldfish:
|
|
This looks great. Much cleaner and more readable :) LGTM |
Mauller
left a comment
There was a problem hiding this comment.
Looks good and works without issue when fish tested it from what i heard
…NetAckStage1CommandMsg, NetAckStage2CommandMsg (#2329)
…NetCommandMsg::getSizeForNetPacket (#2329)
4f72f27 to
b124775
Compare
b124775 to
c257b01
Compare
c257b01 to
9e1122c
Compare
…rites and size tests (#2329)
9e1122c to
35fa72a
Compare
…NetAckStage1CommandMsg, NetAckStage2CommandMsg (#2329)
…NetCommandMsg::getSizeForNetPacket (#2329)
Merge with Rebase
This change has 5 commits with refactors/fixes to greatly simplify all Net Packet buffer writes and size tests. All original networking behavior should be correctly preserved.
The only thing left to refactor for a follow up change are the Net Packet read functions.
TODO