Networking Auto-packets

Auto-packets provide a convenient way to define network packets used to communicate data between endpoints in a AzNetworking session. Using the AzAutoGen system, auto-packet files found inside of your project are processed during builds to create C++ classes and handlers for packets with defined payloads.

In order to enable auto-packet builds for your project, you must add AZ::AzNetworking as a build dependency of your project.

Auto-packet file structure

Auto-packets are defined in XML files, placed in the Code\Source\Autogen directory of the relevant project or Gem.

PacketGroup attributes

The top-level element of an auto-packet definition is a PacketGroup. Packet groups associate different types of individual packet definitions together. Packets defined as part of a packet group are placed into the same namespace.

PropertyDescriptionType
NameThe namespace for generated auto-packets.A valid C++ namespace identifier
PacketStartThe value to start sequencing packet type identifiers for this packet group at. To avoid conflicts with the core AzNetworking framework, use CorePackets::PacketType::Max.const int32

Packet attributes

The Packet tag defines a new packet.

PropertyDescriptionType
NameThe class name of the generated autopacket.A valid C++ class identifier.
DescThe description of the generated autopacket.string
HandshakePacketIf the packet is part of a connection handshake.bool
Note:
Packets with HandshakePacket set as true will only be processed if the user-implemented IsHandshakeComplete function for the packet returns false.

Member attributes

The Member tag defines data on the packet. This is the primary mechanism for defining a packet’s payload.

PropertyDescriptionType
NameThe name of the packet member.A valid C++ variable name.
TypeThe type of the packet member.A valid C++ type.
InitThe initial value of the packet member.<Type>
ContainerIf provided, the member is a container of <Type>.Vector, Array
Vector: A resizeable vector.
Array: A fixed size array.
CountIf Container is provided, the size of the container.uint

Include

The Include tag is used to generate the #includes of the C++ code. Use an Include tag for each header that your generated classes will use.

PropertyDescriptionType
FileThe path to a header to add as an #include of the generated source.string

Example

The following is an example of an auto-packet group used for the Multiplayer Gem .

<?xml version="1.0" encoding="utf-8"?>

<PacketGroup Name="MultiplayerPackets" PacketStart="CorePackets::PacketType::MAX">
    <Include File="AzNetworking/AutoGen/CorePackets.AutoPackets.h" />
    <Include File="Multiplayer/MultiplayerTypes.h" />
    <Include File="Multiplayer/NetworkTime/INetworkTime.h" />
    <Include File="Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h" />
    <Include File="Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h" />

    <Packet Name="Connect" HandshakePacket="true" Desc="Client connection packet, on success the server will reply with an Accept">
        <Member Type="uint16_t" Name="networkProtocolVersion" Init="0" />
        <Member Type="Multiplayer::LongNetworkString" Name="ticket" />
    </Packet>

    <Packet Name="Accept" HandshakePacket="true" Desc="Server accept packet">
        <Member Type="Multiplayer::HostId" Name="hostId" Init="Multiplayer::InvalidHostId" />
        <Member Type="Multiplayer::LongNetworkString" Name="map" />
    </Packet>
  
    <Packet Name="ReadyForEntityUpdates" Desc="Client confirming it is ready to receive entity updates">
      <Member Type="bool" Name="readyForEntityUpdates" />
    </Packet>

    <Packet Name="SyncConsole" Desc="Packet for synchornizing cvars between hosts">
        <Member Type="Multiplayer::LongNetworkString" Name="commandSet" Container="Vector" Count="32" />
    </Packet>

    <Packet Name="ConsoleCommand" Desc="Packet for executing a server command from the client">
        <Member Type="Multiplayer::LongNetworkString" Name="command" />
    </Packet>

    <Packet Name="EntityUpdates" Desc="A packet that contains multiple entity updates">
        <Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" />
        <Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" />
        <Member Type="Multiplayer::NetworkEntityUpdateMessage" Name="entityMessages" Container="Vector" Count="Multiplayer::MaxAggregateEntityMessages" />
    </Packet>

    <Packet Name="EntityRpcs" Desc="A packet that contains multiple entity rpcs">
        <Member Type="Multiplayer::NetworkEntityRpcMessage" Name="entityRpcs" Container="Vector" Count="Multiplayer::MaxAggregateRpcMessages" />
    </Packet>

    <Packet Name="ClientMigration" Desc="Tell a client to migrate to a new server">
        <Member Type="uint64_t" Name="temporaryUserIdentifier" Init="0" />
        <Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
        <Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" />
    </Packet>
</PacketGroup>

Packet Handling

With the exception of CorePackets defined in AzNetworking, packets are handled via the IConnectionListener interface. Implementers of this interface typically define the following:

    //! IConnectionListener interface
    //! @{
    AzNetworking::ConnectResult ValidateConnect(const AzNetworking::IpAddress& remoteAddress, const AzNetworking::IPacketHeader& packetHeader, AzNetworking::ISerializer& serializer) override;
    void OnConnect(AzNetworking::IConnection* connection) override;
    AzNetworking::PacketDispatchResult OnPacketReceived(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, AzNetworking::ISerializer& serializer) override;
    void OnPacketLost(AzNetworking::IConnection* connection, AzNetworking::PacketId packetId) override;
    void OnDisconnect(AzNetworking::IConnection* connection, AzNetworking::DisconnectReason reason, AzNetworking::TerminationEndpoint endpoint) override;
    //! @}

OnPacketReceived is of interest here as it will forward to your PacketGroup’s dispatcher in the fashion of:

    AzNetworking::PacketDispatchResult MultiplayerSystemComponent::OnPacketReceived(AzNetworking::IConnection* connection, const IPacketHeader& packetHeader, ISerializer& serializer)
    {
        return MultiplayerPackets::DispatchPacket(connection, packetHeader, serializer, *this);
    }

The dispatcher expects the IConnectionListener implementer to implement an IsHandshakeComplete function and for each packet, a HandleRequest function. The above example of MultiplayerPackets is handled in MultiplayerSystemComponent .

IsHandshakeComplete

This function checks if handshake logic for the IConnectionListener is complete. This is useful for specifying any additional handshake logic beyond that in AzNetworking. For example, Multiplayer uses this to check with ISessionProvider before beginning to process gameplay traffic. While IsHandshakeComplete returns false, only packets designated as HandshakePackets will process. All other packet types will be skipped.

HandleRequest

HandleRequest defines a callback for each packet type.

PropertyDescriptionType
connectionThe connection the packet was sent on.AzNetworking::IConnection*
packetHeaderThe header of the packet.const IPacketHeader&
packetThe packet itself as defined by AzCodeGen.<Type>: Must be a valid packet type of the related packet group.

Copyright © 2022 Open 3D Engine Contributors

Documentation Distributed under CC BY 4.0.
For our trademark, privacy and antitrust policies, code of conduct, and terms of use, please click the applicable link below or see https://www.lfprojects.org.


The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Policy page.