Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

bobtista
Copy link

@bobtista bobtista commented Oct 7, 2025

Created NetPacketStructs.h with packed struct definitions for network packets
Replaced 9 manual size calculation functions with sizeof(struct) calls

In the next PR we could use these structs for actual serialization, replacing manual memcpy calls

TODO:
Replicate in Generals

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot compile this branch. There are 700 linker errors.

@Mauller
Copy link

Mauller commented Oct 7, 2025

You can still do this for the messages that are variable in length, just make the fixed portion of the message a struct.
Then you just calculate the message size based on the size of the fixed portion and the variable data appended to it.

@bobtista bobtista force-pushed the bobtista/packedstructpackets branch 2 times, most recently from dbb01a8 to 9d9e804 Compare October 8, 2025 17:25
@bobtista bobtista force-pushed the bobtista/packedstructpackets branch from 9d9e804 to db5c043 Compare October 8, 2025 22:08

++msglen; // the NetPacketFieldTypes::Data
msglen += sizeof(UnsignedByte); // string msglength
UnsignedByte textmsglen = cmdMsg->getText().getLength();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: This truncates 4 bytes to 1 byte 👀

@xezon xezon added Major Severity: Minor < Major < Critical < Blocker Network Anything related to network, servers Refactor Edits the code with insignificant behavior changes, is never user facing labels Oct 13, 2025
@bobtista bobtista force-pushed the bobtista/packedstructpackets branch from 34ab595 to ba6335d Compare October 13, 2025 19:27
@bobtista bobtista force-pushed the bobtista/packedstructpackets branch 2 times, most recently from 960e7a4 to ad27a6c Compare October 14, 2025 03:29
*/
size_t NetDisconnectChatCommandMsg::getByteCount() const
{
return m_text.getByteCount();
Copy link

@xezon xezon Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the reader recognize the length of this text? Surely this must be either null terminated or bundled with a count? I wonder if this is an original bug.

Copy link
Author

@bobtista bobtista Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be addressed in another PR or here?
A potential fix:

{
    return sizeof(UnsignedByte) + m_text.getByteCount(); 
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be addressed separately, and it needs to consider retail compatibility.

I suspect it works in original game because message buffer is zero initialized and therefore string is zero terminated when nothing comes after it.

Copy link

@xezon xezon Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add a TheSuperHackers @todo ... comment here.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you did now:

struct NetPacketDisconnectChatCommandHeader {
	NetPacketCommandTypeField commandType;
	NetPacketRelayField relay;
	NetPacketPlayerIdField playerId;
	NetPacketDataFieldHeader dataHeader;
	UnsignedByte textLength;
};

You put the textLength into the header struct.

It is a bit confusing that it is detached from the string data.

Perhaps move it? Same in the other struct.

GeneralsMD/Code/GameEngine/Include/GameNetwork/NetPacket.h Outdated Show resolved Hide resolved
*/
size_t NetChatCommandMsg::getByteCount() const
{
return m_text.getByteCount() + sizeof(m_playerMask);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I think we need to make another pass on this.

NetChatCommandMsg inherits from NetCommandMsg. All these messages inherit from it.

So what we can do is add

size_t NetCommandMsg::getByteCount() const
{
  return sizeof(PackedNetCommandMsg);
}

It can then be combined with its descendent classes:

size_t NetChatCommandMsg::getByteCount() const
{
  return NetCommandMsg::getByteCount() + ...;
}

Alternatively the Packed structs can also inherit. Not sure what the best approach is because of the variable length data.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I went with packed structs inheritance, let me know what you think

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still is confusing. We have 25 messages that inherit the base message:

class NetGameCommandMsg : public NetCommandMsg
class NetAckBothCommandMsg : public NetCommandMsg
class NetAckStage1CommandMsg : public NetCommandMsg
class NetAckStage2CommandMsg : public NetCommandMsg
class NetFrameCommandMsg : public NetCommandMsg
class NetPlayerLeaveCommandMsg : public NetCommandMsg
class NetRunAheadMetricsCommandMsg : public NetCommandMsg
class NetRunAheadCommandMsg : public NetCommandMsg
class NetDestroyPlayerCommandMsg : public NetCommandMsg
class NetKeepAliveCommandMsg : public NetCommandMsg
class NetDisconnectKeepAliveCommandMsg : public NetCommandMsg
class NetDisconnectPlayerCommandMsg : public NetCommandMsg
class NetPacketRouterQueryCommandMsg : public NetCommandMsg
class NetPacketRouterAckCommandMsg : public NetCommandMsg
class NetDisconnectChatCommandMsg : public NetCommandMsg
class NetChatCommandMsg : public NetCommandMsg
class NetDisconnectVoteCommandMsg : public NetCommandMsg
class NetProgressCommandMsg: public NetCommandMsg
class NetWrapperCommandMsg : public NetCommandMsg
class NetFileCommandMsg : public NetCommandMsg
class NetFileAnnounceCommandMsg : public NetCommandMsg
class NetFileProgressCommandMsg : public NetCommandMsg
class NetDisconnectFrameCommandMsg : public NetCommandMsg
class NetDisconnectScreenOffCommandMsg : public NetCommandMsg
class NetFrameResendRequestCommandMsg : public NetCommandMsg

Are not all messages using all the fields of the base message? It would have been nice if this could be constructed with consistency. But maybe that is not the case. What deviation patterns do we have?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern is:
Variable data -> getByteCount() function
Fixed data -> sizeof(struct) directly

We've got 5 variable-length classes using getByteCount() with packed struct inheritance.
and 20 fixed-size classes using sizeof(struct) directly

The 5 that need custom size calculations are:
NetGameCommandMsg
NetChatCommandMsg
NetDisconnectChatCommandMsg
NetFileCommandMsg
NetFileAnnounceCommandMsg

These packets have dynamic content (text, file data, game arguments), so they use custom size calculations. They use a header + variable data pattern

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The confusion I see here is that the packed structs have different inheritance patterns than the non packed structs. It would be nice if these were consistent, but that seems not possible because the first few data fields are not always the same, for whatever reason.

I am inclined to say if we cannot make the packed ones use inheritance consistently, then make none inherited - for consistency.

But what we could do is add getByteCount() functions to all non packed structs, and then make them static where they simply return sizeof(PackedStructXYZ).

Also, I think we better name the functions getPackedByteCount().

And then in next changes we add functions toPackedStruct and fromPackedStruct to convert between packed and non-packed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I added getByteCount() functions to all of them, and used static where appropriate, and renamed the functions getPackedByteCount, in separate commits.

@bobtista bobtista force-pushed the bobtista/packedstructpackets branch from 586fafb to 07b592f Compare October 17, 2025 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Major Severity: Minor < Major < Critical < Blocker Network Anything related to network, servers Refactor Edits the code with insignificant behavior changes, is never user facing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.