diff --git a/README.md b/README.md index a906e71..d192753 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ This repository holds materials for the Open 3D Engine Foundation Special Interest Group for Networking (SIG-Network). ## Description of SIG Network + We manage communication components for O3DE, including foundational networking layers, transport, multiplayer, client/server interactions and Cloud connectivity pieces of O3DE. See the [SIG's charter](governance/SIG%20Network%20Charter.md) for full details. -## What the SIG does: +## What does the SIG do? * Reviews and contribute to O3DE's technology roadmap specifically around Networking features. * Reviews network related issues, RFCs and PRs. @@ -23,11 +24,13 @@ We manage communication components for O3DE, including foundational networking l * Subscribe to our [mailing list](https://lists.o3de.org/g/sig-network/join), which is occasionally used to convey information of interest to SIG members. ### Who can attend or participate? + O3DE cannot work without the help and input from as many of its community members as possible. You do not need anyone’s permission to get involved and contribute to the project. The #sig-network channel on O3DE Discord is a great place to begin getting involved. Many of our community members regularly share ideas, updates, and resources there. You can also find a number of topics under the GitHub Discussions area which need your input. ## Helpful information * SIG Chair: Pip Potter [Amazon, [@lmbr-pip](https://github.com/lmbr-pip)], Co-chair: Karl Berg [Amazon, [@kberg-amzn](https://github.com/kberg-amzn)] +* Accepted [RFCs](./rfcs/README.md) * [SIG-Network Charter](governance/SIG%20Network%20Charter.md) * [Upcoming meeting agendas](https://github.com/o3de/sig-network/issues?q=is%3Aopen+is%3Aissue+label%3Amtg-agenda) * [Archived meeting notes](meetings/readme.md) diff --git a/rfcs/readme.md b/rfcs/README.md similarity index 56% rename from rfcs/readme.md rename to rfcs/README.md index 1f53b1e..59915cb 100644 --- a/rfcs/readme.md +++ b/rfcs/README.md @@ -1,12 +1,14 @@ # Sig-Network RFCs -This is where RFCs that have been accepted by SIG-Network are kept. + +This is where Request for Change (RFC) documents that have been accepted by SIG-Network are kept. ## RFC Naming -RFC naming follows the pattern of: +RFC naming follows the pattern of: ```rfc-net-(YYYYMMDD)-(X)-(friendlyname)``` #### Notes + * RFC should be referred to as ```rfc-net-YYYYMMDD-X```, friendly name is just to aid discovery. * ```YYYYMMDD```: Replace with the date of the sig-network meeting that accepted the RFC. * ```X``` is a counter for the day, if there are multiple RFCs accepted in a single meeting. @@ -14,11 +16,14 @@ RFC naming follows the pattern of: ## Recent Accepted RFCS ### 2022 -| RFC | Month | Summary | -|-----------------------------------------------------------------------|---------|-----------------------------------------------------| -| [rfc-net-20220118-1-clientserver](rfc-net-20220118-1-clientserver.md) | January | Client/Server build separation | -| [rfc-net-20220719-1-awsgems](rfc-net-20220719-1-awsgems.md) | July | Migration of Amazon Gems from O3DE main repository. | -| [rfc-net-20220728-1-remotetools](rfc-net-20220728-1-remotetools.md) | July | Support for remote tools connections in O3DE | + +| RFC | Month | Summary | +|-----------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [rfc-net-20220118-1-clientserver](rfc-net-20220118-1-clientserver.md) | January | Client/Server build separation | +| [rfc-net-20220719-1-awsgems](rfc-net-20220719-1-awsgems.md) | July | Migration of Amazon Gems from O3DE main repository. | +| [rfc-net-20220728-1-remotetools](rfc-net-20220728-1-remotetools.md) | July | Support for remote tools connections in O3DE | +| [rfc-net-20221020-1-clientserver](rfc-net-20221020-1-clientserver.md) | October | Updates [rfc-net-20220118-1-clientserver](rfc-net-20220118-1-clientserver.md) to move from a Client and Server target with a CMake target to allow Client to include Server to a Client, Server and Unified target. | +| [rfc-net-20221020-2-netversion](rfc-net-20221020-2-netversion.md) | October | Mechanism to generate a version for network layer to detect client and server network mismatches. | ### 2021 | RFC | Month | Summary | diff --git a/rfcs/rfc-net-20220118-1-clientserver.md b/rfcs/rfc-net-20220118-1-clientserver.md index 8dd8d63..76b4470 100644 --- a/rfcs/rfc-net-20220118-1-clientserver.md +++ b/rfcs/rfc-net-20220118-1-clientserver.md @@ -1,6 +1,8 @@ # rfc-net-20220118-1 * https://github.com/o3de/sig-network/issues/32 +> This RFC is now replaced/amended by - [rfc-net-20221020-1-clientserver](./rfc-net-20221020-1-clientserver.md) + # RFC Feature: Client and server build target separation ### Summary: For some O3DE applications, like multiplayer and live service games, server code cannot be shipped to the clients. Doing so creates incremental security and cheating risks. Servers that include client code and resources can also bring unnecessary dependencies which causes long build and relocation times. This RFC proposes a hard client and server split by separating the client and server into different build targets when required. @@ -94,8 +96,8 @@ Macros would be enforced at the [auto-generated component](https://o3de.org/docs Add the same CMake flag/compile definitions as the proposed solution and also create the following three static libraries for the client hosted and dedicated server mode: * MultiplayerSample.Unified.static: Unified static library for the client target that can also behave as a server. -* MultiplayerSample.Server.static: Static library for the dedicated server target which doesn’t include any client code. -* MultiplayerSample.Client.static: Static library for the client target which doesn’t include any server code. +* MultiplayerSample.Server.static: Static library for the dedicated server target which doesn't include any client code. +* MultiplayerSample.Client.static: Static library for the client target which doesn't include any server code. Project/Gem CMake configuration will look like below: diff --git a/rfcs/rfc-net-20221020-1-clientserver.md b/rfcs/rfc-net-20221020-1-clientserver.md new file mode 100644 index 0000000..f31d92d --- /dev/null +++ b/rfcs/rfc-net-20221020-1-clientserver.md @@ -0,0 +1,164 @@ +# rfc-net-20221020-1 +https://github.com/o3de/sig-network/issues/77 + +> This proposes an updated version of an accepted RFC - [rfc-net-20220118-1-clientserver](./rfc-net-20220118-1-clientserver.md) + +# What is the delta produced by this Amendment? +### Feature Design Description +The amendment proposes moving from a Client and Server target with a CMake target to allow Client to include Server to a Client, Server and Unified target. This is largely what was described as the alternative solution in the original RFC. The prior solution is now listed as the alternative. + +### Technical Design Description +Example CMake was updated for accuracy and updated Feature Design Description. + +### Macros +Added further details on macro usage and expected user interactions. + +### Open Questions +Added a question around AutoGen usage in CMake for modules using Client/Server split + +# RFC Feature: Client and server build target separation +### Summary: +For some O3DE applications, like multiplayer and live service games, server code cannot be shipped to the clients. Doing so creates incremental security and cheating risks. Servers that include client code and resources can also bring unnecessary dependencies which causes long build and relocation times. That being said, customers may also require a unified build containing client and server logic. This RFC proposes a hard client and server split by separating the client and server into different build targets when required while maintaining the option of a unified build for customers that require it. + +### What is the relevance of this feature? +With the solution proposed by this RFC, O3DE will support the following two hosting modes for multiplayer applications: +1. (Headless Dedicated Server mode) One is for live service games, where headless dedicated servers can be packaged and distributed to on-prem/remote servers to provide reliable and stable hosting solutions. The dedicated server build omits the packages and modules that a headless server does not require and has a smaller compiled size. +2. (Client-As-Server mode) Supporting Single Purchase products which cannot rely on subscription revenue to cover the costs of dedicated server hosting. In this mode, one of the clients acts as a server to which other players connect. + +### Feature design description: +This solution proposes adding two compiler definitions to allow the separation of client and server behaviors: +- `AZ_TRAIT_SERVER_ENABLED`: Compile the server code for the current target. +- `AZ_TRAIT_CLIENT_ENABLED`: Compile the client code for the current target. + +O3DE developers can use these compiler definitions to separate the client and server targets, so that they can create a dedicated server for live service games, a client with no server logic or a client hosted server for console titles. These will be referred to as a Server build, Client build and Unified build going forward. + +### Technical design description: +#### CMake definitions +For any multiplayer O3DE project, as well as any dependent gems that contain multiplayer components, define separate static libraries for the Client, Server and Unified targets like below: + +``` +create target Multiplayer.Client.Static + COMPILE_DEFINITIONS + PUBLIC + AZ_TRAIT_CLIENT_ENABLED=1 + AZ_TRAIT_SERVER_ENABLED=0 + +create target MultiplayerSample.Client.Static + BUILD_DEPENDENCIES + PRIVATE + Gem::Multiplayer.Client.Static + +create target Multiplayer.Server.Static + COMPILE_DEFINITIONS + PUBLIC + AZ_TRAIT_CLIENT_ENABLED=0 + AZ_TRAIT_SERVER_ENABLED=1 + +create target MultiplayerSample.Servers.Static + BUILD_DEPENDENCIES + PRIVATE + Gem::Multiplayer.Server.Static + +create target Multiplayer.Unified.Static + COMPILE_DEFINITIONS + PUBLIC + AZ_TRAIT_CLIENT_ENABLED=1 + AZ_TRAIT_SERVER_ENABLED=1 + +create target MultiplayerSample.Unified.Static + BUILD_DEPENDENCIES + PRIVATE + Gem::Multiplayer.Unified.Static + +if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) + # If developers need to build a server launcher, then add the project name to the list of server launcher projects + set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS MultiplayerSample) +endif() +``` + +All the downstream targets should always refer to one of the Client, Server or Unified static libraries. + +Multiplayer gameplay components will live in both of the client and server targets to keep a simple cook and replication pipeline. Their behavior and accessors will be different because of the compile definitions and macros. + +If O3DE developers only need the client hosted solution and don’t want to generate a server launcher, they can just remove the following lines in the CMake configuration: + +``` +if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) + # If developers need to build a server launcher, then add the project name to the list of server launcher projects + set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS MultiplayerSample) +endif() +``` + +#### Macros +Macros would be enforced at the [auto-generated component](https://o3de.org/docs/user-guide/networking/autopackets/) level. We should be adding additional `#if AZ_TRAIT_SERVER_ENABLED` and `#if AZ_TRAIT_CLIENT_ENABLED` markup around authority, server, autonomous, client properties and remote procedure calls (RPC), which will force derived components to respect those same defines. + +Auto-generation provides a variety of logic overall. Some of this logic is declared and defined purely in AutoGen. Some however, is declared in AutoGen and defined by the user. RPC Handlers are an excellent example of this. In these cases, the declaration itself will be macro wrapped which will require users to macro wrap their definitions. + +How to handle logic the user declares and defines that can be separated using Client/Server macros is left to the user's discretion. + +### What are the advantages of the feature? +- Hard client and server separation can make O3DE multiplayer application more secure and compact. +- The hard split mode can be helpful to catch programmer errors. For example, when compiling the client only target, the compiler can catch errors where O3DE developers use server only network state on a client code path. + +### What are the disadvantages of the feature? +- Testing/validating all permutations would multiply the number of builds on Jenkins. AR will have to pick the primary mode as default and validate the non-default permutation (client hosted use case) periodically during Jenkins nightly builds. Some breaking changes might pass AR and won’t be detected by Jenkins jobs immediately. It is suggested to validate the non-default permutation on one platform and configuration instead of doing this on 3 platforms (mac/linux/windows) with 3 configurations (debug/profile/release) and 2*2 permutations (monolithic/unity/non-monolithic-unity/non-unity). + +### How will this be implemented or integrated into the O3DE environment? +* Identify the projects/gems that contain multiplayer components and split their client and server targets. Initial list this RFC targets on includes: + * MultiplayerSample project + * Multiplayer gem + * AWS GameLift gem +* Add project and gem templates to O3DE. Any new multiplayer-dependent projects or gems will follow the same configurations proposed by this RFC. + +### Are there any alternatives to this feature? +Using an extra CMake flag, remove the Unified solution and instead allow the Client configuration to function as the Client launcher or the Unified launcher based on said flag. + +Project/Gem CMake configuration will look like below: + +``` +create target Multiplayer.Client.Static + COMPILE_DEFINITIONS + PUBLIC + AZ_TRAIT_CLIENT_ENABLED=1 + AZ_TRAIT_SERVER_ENABLED=${LY_CLIENT_BEHAVES_AS_SERVER} + +create target MultiplayerSample.Client + BUILD_DEPENDENCIES + PRIVATE + Gem::Multiplayer.Client.Static + +create target Multiplayer.Server.Static + COMPILE_DEFINITIONS + PUBLIC + AZ_TRAIT_CLIENT_ENABLED=0 + AZ_TRAIT_SERVER_ENABLED=1 + +create target MultiplayerSample.Servers + BUILD_DEPENDENCIES + PRIVATE + Gem::Multiplayer.Server.Static + +if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) + # If developers need to build a server launcher, then add the project name to the list of server launcher projects + set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS MultiplayerSample) +endif() +``` + +This solution has the same advantages as the proposed solution. Disadvantages include: +- Toggling the CMake flag requires rebuilding the affected launcher +- Building all three types of launchers requires toggling the CMake flag at least once to update all builds +- Same compile definitions and testing/validating problems as the proposed solution. + +### How will users learn this feature? +- Existing O3DE project (MultiplayerSample) and any gems that contain multiplayer components can be referenced as examples for the hard client and server separation. +- Specific project/gem template can be provided with the client and server target predefined as references. +- Document usage of the new compile definitions. +- Certain Multiplayer AutoGen based features will require using the new compile definitions. + +### Are there any open questions? +- Lumberyard 1.x was WAF based and its [GridMate networking system](https://docs.aws.amazon.com/lumberyard/latest/userguide/network-intro.html) provided a macro solution for separating the client and server code. How could O3DE avoid messing up macros in most of the multiplayer-dependent classes as GridMate did? + - Enforce macros at the auto-generated component level which results in quick compile errors when macros are misused in derived classes. +- For sig-build and sig-testing, what optimizations can be made to reduce the build time and simplify testing/validating on Jenkins when switch between these two hosting modes? + - Create a common static library between server and client static targets that has the code shared between the two (that is not affected by the GENERATE_ defines) to reduce the amount of code that is compiled multiple times. +- How will AutoGen be affected by this feature? + - A module generally allows one target to define AutoGen rules. This has historically been the Static target. Splitting into multiple static targets removes that option. A solution would be to provide an AutoGen target with Client and Server compile definitions not defined that all other Static targets inherit from. diff --git a/rfcs/rfc-net-20221020-2-netversion.md b/rfcs/rfc-net-20221020-2-netversion.md new file mode 100644 index 0000000..619e96a --- /dev/null +++ b/rfcs/rfc-net-20221020-2-netversion.md @@ -0,0 +1,132 @@ +# rfc-net-20221020-2 +https://github.com/o3de/sig-network/issues/81 + +# Summary +This feature will provide a way to detect when a multiplayer server and client are using different versions of multiplayer components. + +This RFC was created as a proposed fix for [github.com/o3de/o3de/issues/9669](http://github.com/o3de/o3de/issues/9669) + +## What is the relevance of this feature? +As a developer I want to know if my server and client have a version mismatch. + +It's important for servers and clients to be running the same version of all the multiplayer components (components which communicate to each other over the network). Any mismatch will lead to unexpected behavior. This feature will warn users immediately upon connecting to the server if there is a mismatch. + +Example: +A developer wants to push a game update to players in the wild. One of the changes was made to a multiplayer auto-component, but the change was minimal; a developer reordered the auto-components RPCs inside the XML, so they were in alphabetical order (just because felt easier to read that way). Before pushing the update live, the developer tries testing the new build and starts a match by connecting to one of their production branch servers on the cloud. The game appears to be going smoothly, except the RPCs associated with this auto-component they reordered has seemed to have stopped working. Unbeknownst to the developer, this is because the server’s RPC index is different; although it felt minor at the time, reordering the RPCs inside the XML has broken the logic. The developer now needs to go and debug why the RPCs aren’t working as expected, which can take a long time if they don't realize the server and client are actually running different multiplayer auto-component versions. +After this feature is implemented, the developer would know right away that their client and server builds are different. Now upon connecting to the server, the client and server would share a hash-value representing the current snapshot of all their multiplayer components. If the hashes don’t match, an error message will be logged, and an error popup will be prominently displayed in the game's viewport. The developer will see the message, and know that he forgot to update the server. +Note: developers may want to add their own extensions to client/server "versioning" (ie region checks), this would instead be a feature for a custom game-specific handshake which is already supported. + +## Feature design description: +The multiplayer system will be updated so that it can detect when a server and client are using different multiplayer auto-components. The server and client machines will then be warned of a mismatch, at which point the user can go and update their server or client builds to the latest build version. The hash generation, error detection, and reporting will all happen automatically without adding any extra steps to the developer's normal build process. + + +## Common example workflows: + +1. *Local development*: There currently isn’t any client/server code split so accidentally mismatching game and server in this a local development environment is not really an issue. Whether building Editor, or GameLaunch, or ServerLauncher, the multiplayer auto-components are built as part of the game gem module and shared between all three apps. However, if client and server logic is split it may become more likely that a dev could forget to build the server after updating multiplayer components. Should this occur when developing locally, the dev will see a popup on their client app immediately upon trying to connect explaining that there’s a mismatch. “Warning: Server/Client Mismatch Detected!” The logs will include which exact components are mismatched: “Multiplayer Component mismatch includes NetPlayerController, NetCameraController, etc.”. At which point the dev will likely just rebuild both server and client to be sure. One question to ask is if there’s an opportunity to narrow down knowing whether it's the client or the server that needs rebuilding (ie which one is newer and which is older)? If Jinja also generated a timestamp during compilation, perhaps this build timestamp could be displayed along with the mismatch warning logs to provide better clues as to which build is older. +2. *Developer testing with remote server*: A developer might want to try testing their game using a remote server, or a server on other developer’s machines to play together. After receiving the mismatch warnings, each developer would need to check their code source control to double-check who has latest. The dev with the older code will need to sync latest and rebuild. There may be an opportunity to improve this workflow using generic engine versioning; if each pull request increments a minor version number this extra information could be shared between machines and give clues as to which machine is older. However, is unlikely to help in a dev-to-dev play session since developers don’t modify their engine versions between local builds. +3. *Play testing with real players*: If players in the wild have a client version mismatch with a live server, the game logic should connect to the mismatch notification bus in order to receive a callback on the client when a mismatch occurs. Game specific logic can then be deployed to assist the client upgrade to the latest client build. Although this is unlikely to be necessary as the game logic should already be using custom handshake logic to ensure the client is using the proper game version. + + +## Technical design description: +In order for this feature not to impact normal developer workflows, we'll aim to have the normal build process automatically generate all of the code required for comparing multiplayer components. For this, we'll rely on AzCodeGen. + +High-level overview: + +1. AzAutoGen creates a unique 64-bit hash value for each auto-component xml it digests. + 1. The 64-bit hash will be stored in the ComponentData class that’s passed to the global MultiplayerComponentRegistry +2. Connection packets will be updated so that the server and the player can exchange their current holistic version hash (see Hash Generation (Per-Application) below). +3. During application start up, as all the gems are registering their components with the MultiplayerComponentRegistry, the MultiplayerComponentRegistry will combine each component’s hash to create its own 64-bit version hash. +4. The MultiplayerComponentRegistry’s version hash is sent from the client to the server as part of the client’s connection packet. +5. Server will compare the client’s version-hash with its own to make sure it matches + 1. If the server finds a mismatch: + 1. Error logs will be reported + 2. An EBus notification is broadcast + 1. Test automation can receive the event + 2. MultiplayerViewportMessageSystemComponent can receive the mismatch event and display a warning on-screen + 3. The version hash of each individual auto-component will be exchanged (using a new packet type) in order that the server and client know exactly which components are out-of-date. + + +Auto-component XML To Multiplayer Component Registry +[Image: image.png]*## Hash Method Available to AzCodeGen/Jinja:* +Ultimately we want to compare the server and client auto-component XMLs. Instead of having to send and receive 100's of kilobytes of XML files over the network, we'll instead parse the XML and create a unique hash. Parsing the XML and creating a hash can be achieved by leveraging the same AzCodeGen that's used to parse and convert XML into game components and packets. For converting XML into a 64-bit hash, a new method will be added to \cmake\AzAutoGen.py called CreateHashValue64(string). It will return a AZ::HashValue64. Then in Jinja one can call the code as follows: + {{ SomeStringRepresentingTheAutoComponent | createHashValue64string}} + + +## Hash Generation (Per-Auto-Component): +Auto-components contain a name, namespace, RPCs, RPC parameters, network properties, network inputs, and archetypes. Each of these properties would need to be considered when generating a hash. The auto-component classes would have a new member variable "AZ::HashValue64 m_versionHash" and a public accessor method "GetVersionHash()". + +Creating the auto-component hash value will be done during AzCodeGen. The multiplayer auto-component Jinja will need to be updated to parse all the auto-component attributes (name, namespace, RPCs, RPC parameters, network properties, archetypes, and network inputs), store it in a string, pass it to the createHashValue64string method, and store it in m_versionHash. + +Relevant Files: +\Gems\Multiplayer\Code\Include\Multiplayer\AutoGen\AutoComponent_Header.jinja +\Gems\Multiplayer\Code\Include\Multiplayer\AutoGen\AutoComponent_Source.jinja + +## Hash Generation (Per-Application): +Instead of checking every auto-component on the server against every auto-component on the client, we will first compare a single holistic hash that’s generated per-application. +This hash, unlike the individual auto-component hash, will not be generated during AzCodeGen and instead will be produced at runtime. +Currently, at the start of the app, all of the auto-components register themselves with the global MultiplayerComponentRegistry. MultiplayerComponentRegistry will be updated so that as each component registers itself, the MultiplayerComponentRegistry will update its own AZ::HashValue64, by combining the component hashes together. (Note: A lazy init may be more appropriate here whereby the hash is generated once it’s asked for and then stored for future use) + +\Gems\Multiplayer\Code\Include\Multiplayer\Components\MultiplayerComponentRegistry.h +class MultiplayerComponentRegistry +{ +public: + + void RegisterMultiplayerComponent( ComponentData componentData ); +... +private: + AZ::HashValue64 m_versionHash; +} + +\Gems\Multiplayer\Code\Include\Multiplayer\Components\MultiplayerComponentRegistry.cpp +void MultiplayerComponentRegistry::RegisterMultiplayerComponent( ComponentData componentData ) +{ + ... + // update m_versionHash by adding in componentData.m_versionHash; +} + +## Sending and Receiving Hashes Between Client and Server + +1. Update MultiplayerPackets::Connect packet to contain a new 64-bit hash value called “MultiplayerComponentVersion”. This will contain the holistic hash generated per-application. +2. Upon receiving the MultiplayerPackets::Connect packet, the server will check the MultiplayerComponentVersion against his own version, and send back an updated MultiplayerPackets::Accept packet which contains a boolean specifying if the hashes match. + 1. If the hash doesn't match: + 1. The server and client will exchange a new type of packet that contains the per-component hashes. This information which allows each to map auto-components and their version hash; this will allow us to quickly identify which auto-components were added, removed, or modified. Trigger EBus notifications, log warnings, and display viewport messages. + 2. The client/server should disconnect from one another; no player should be spawned. + + +Relevant Files: +\Gems\Multiplayer\Code\Source\MultiplayerSystemComponent.cpp\h +\Gems\Multiplayer\Code\Source\AutoGen\Multiplayer.AutoPackets.xml + +## What are the advantages of the feature? +This feature will alert developers and players when their game doesn't match the server version. It's an important safeguard. By knowing which components don't match, developers can then check the code on either machine to see which is out-of-date. + +## What are the disadvantages of the feature? +This feature will add to build times, although probably not much considering the new Jinja logic will only be a fraction of what’s being generated per auto-component. To be safe, the GitHub pull-request should include a comment about before and after build times using Multiplayer Sample. If parsing each auto-component by hand is too slow, maybe it's faster to turn the entire XML into a string in order to hash; but be careful not to consider non-essential characters (such as newlines) which can be different depending on the operating system. + + +## How will this be implemented or integrated into the O3DE environment? +This will be added as default behavior in the MultiplayerGem connect logic. Users of the gem will get the behavior for free, when they update the gem. Users who require more control may utilize the IsHandshakeComplete method which already exists in the IMultiplayer interface; users can specify what constitutes a complete handshake specific to their game’s requirements. + + +## Are there any alternatives to this feature? +1. Alternative Hash Generation (Per-Auto-Component and Per-Auto-Packet): +There's a possibility to hash the entire auto-component XML file instead of having to parse its individual auto-component properties to create a hash. We'd want to be careful that the internal XML data-structure passed into Jinja ignores newlines as these could produce different results based on a machine's operating system. For instance, if a Windows machine using CR/LF line endings connects to a Linux server using CR line endings, the hash function could incorrectly produce a different hash. The upside is that using an XML "ToString()" method would be computationally faster, and also quicker to implement (fewer lines of code and easier to read). + +2. Leverage Existing Engine-Version API: +https://github.com/o3de/sig-core/issues/44 +Instead of automatically generating versions for multiplayer components specifically, we could simply leverage the upcoming O3DE engine versioning API to send the current engine/project/gem versions. The problem with this is it likely won't catch any multiplayer component mismatches unless developers specifically remember to update versions after every change. + +3. Instead of automatically generating versions, we could add a "version" field to the auto-component XML. The problem with this is it won't catch any multiplayer component mismatches unless developers specifically remembers to update versions after every change. + +## How will users learn this feature? +Users will not need to learn of this feature in order to enable it as it will be enabled automatically. +Should a version mismatch occur, debug logs, and an on-screen warning message will appear on the client machine tipping off users as to the version mismatch, however, a detailed networking troubleshooting doc should cover what to do in order to fix a version mismatch. + +## Out of Scope + +1. Auto-packet Versioning: Versioning based on auto-packets out of scope. it would be highly unusual for a customer to alter the actual packets since that would involve editing core engine code and gems. An overall engine version # check would probably be more than sufficient here. The auto-component network properties, types, and RPCs and param types are what customers will be implementing and editing in their game code, and are most important to capture in this version check. + + +## Are there any open questions? +- Can this be turned off with a cvar switch? For debugging purposes, etc.? +- Are there solutions to knowing which application is out-of-date? Right now mismatch is known, but not which is right or wrong. \ No newline at end of file