IN THIS ARTICLE
Network Serializers
Open 3D Engine (O3DE) supports a variety of serializers that visit an object hierarchy and perform operations upon that hierarchy. These operations typically include reading data from or writing data to the object hierarchy for the purpose of persistence or network transmission.
Both AzNetworking
and the Multiplayer Gem use serialization for performant network communication through packets and RPCs. Consequently, serialization directly relates to bandwidth utilization in network communication. For cases when a bespoke serializer is desirable, AzNetworking
and the Multiplayer Gem provide good examples of how to use a serializer.
This section describes the various serializer implementations that are included in AzNetworking
, and how to author a serialization function for an object model. It also describes serializers that function as wrappers that can be used to supplement other serializer types.
ISerializer
AzNetworking::ISerializer describes an interface that all AzNetworking
serializers implement. It describes methods for the serialization of base data types in addition to template machinery to handle serialization of object types.
Included serializers
AzNetworking
provides several implementations of ISerializer
.
NetworkInputSerializer
NetworkInputSerializer
writes object model data into a bytestream. It’s generally used to serialize data for transport using packets in AzNetworking
.
NetworkOutputSerializer
NetworkOutputSerializer
reads object model data from a bytestream. It’s generally used to deserialize data to an object that was received in a packet that was previously serialized by NetworkInputSerializer
.
DeltaSerializer
DeltaSerializer
encodes information used by DeltaSerializer
to create and apply serialization deltas. An example usage is serialization of network inputs. Network inputs are generally close in value so they are serialized relative to each other using the DeltaSerializer
.
HashSerializer
HashSerializer
generates a 32 bit integer hash for a serializable object. These hashes can be used to compare serialization results which can be useful to detect desyncs.
StringifySerializer
StringifySerializer
writes object model data into a map of string keys and string values. It can be used to generate a human readable map of an object model.
TrackChangedSerializer
TrackChangedSerializer is an output serializer that tracks if any delta is actually serialized. It can wrap other ISerializer
types to supplement the wrapped type serializer with its tracking functionality. The tracking it performs comes with a slight memory and performance cost.
TypeValidatingSerializer
TypeValidatingSerializer
is a debug serializer that wraps other ISerializer
types to supplement the wrapped type serializer with type and name information for serialized values. These values can then be checked to ensure data consistency. TypeValidatingSerializer
will assert when a mismatch is detected to help aid debugging. Its functionality is gated by the net_validateSerializedTypes
cvar as described in
Settings. TypeValidatingSerializer
adds a bandwidth cost when net_validateSerializedTypes
is enabled in order to serialize type and name information.
The Multiplayer Gem uses TypeValidatingSerializer
in non-release builds. To see the implementation, refer to
IMultiplayer.h .
Authoring a serialization for an object model
Because serializers implement the ISerializer
interface, you can use this interface when authoring new serialization functions so that they can accept any serializer of this type.
As an example, consider the following struct and its Serialize
method:
struct PlayerState
{
PlayerNameString m_playerName;
uint32_t m_score = 0; // coins collected
uint8_t m_remainingShield = 0; // % of shield left, max of ~200% allowed for buffs
bool operator!=(const PlayerState& rhs) const;
bool Serialize(AzNetworking::ISerializer& serializer);
};
inline bool PlayerState::Serialize(AzNetworking::ISerializer& serializer)
{
return serializer.Serialize(m_playerName, "playerName")
&& serializer.Serialize(m_score, "score")
&& serializer.Serialize(m_remainingShield, "remainingShield");
}
PlayerState's
Serialize
function can be used to both serialize data for network transport using NetworkInputSerializer
and deserialize data back into a PlayerState
using NetworkOutputSerializer
. In fact, any type implementing ISerializer
could be used as a parameter to PlayerState's
Serialize
method.