From 970dcea16ed6b5d5523eaca8dfd37684c38df01c Mon Sep 17 00:00:00 2001 From: pereslav Date: Wed, 23 Jun 2021 15:29:31 +0100 Subject: [PATCH 1/2] SPEC-7469 Fixed EditorServerInfo packet serialization --- .../TcpTransport/TcpConnection.cpp | 1 + .../Editor/MultiplayerEditorConnection.cpp | 8 +++++- .../MultiplayerEditorSystemComponent.cpp | 3 ++- .../Source/Editor/MultiplayerEditorUtils.h | 27 +++++++++++++++++++ Gems/Multiplayer/Code/multiplayer_files.cmake | 1 + 5 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp index 6278fb28d8..5048130190 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp @@ -205,6 +205,7 @@ namespace AzNetworking NetworkInputSerializer serializer(buffer.GetBuffer(), buffer.GetCapacity()); if (!const_cast(packet).Serialize(serializer)) { + AZ_Assert(false, "SendReliablePacket: Unable to serialize packet [Type: %d]", packet.GetPacketType()); return false; } buffer.Resize(serializer.GetSize()); diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 847d1caadf..601919ea7b 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -58,7 +59,7 @@ namespace Multiplayer if (!packet.GetLastUpdate()) { // More packets are expected, flush this to the buffer - m_byteStream.Write(TcpPacketEncodingBuffer::GetCapacity(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); + m_byteStream.Write(GetMaxEditorServerInitSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); } else { @@ -80,6 +81,11 @@ namespace Multiplayer size_t assetSize = m_byteStream.GetCurPos(); AZ::Data::AssetData* assetDatum = AZ::Utils::LoadObjectFromStream(m_byteStream, nullptr); + if (!assetDatum) + { + AZLOG_ERROR("EditorServerInit packet contains no asset data. Asset: %s", assetHint.c_str()); + return false; + } assetSize = m_byteStream.GetCurPos() - assetSize; AZ::Data::Asset asset = AZ::Data::Asset(assetId, assetDatum, AZ::Data::AssetLoadBehavior::NoLoad); asset.SetHint(assetHint); diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 3ac4e98d42..e1690d8ecc 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -214,7 +215,7 @@ namespace Multiplayer AzNetworking::TcpPacketEncodingBuffer& outBuffer = packet.ModifyAssetData(); // Size the packet's buffer appropriately - size_t readSize = TcpPacketEncodingBuffer::GetCapacity(); + size_t readSize = GetMaxEditorServerInitSize(); size_t byteStreamSize = byteStream.GetLength() - byteStream.GetCurPos(); if (byteStreamSize < readSize) { diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h new file mode 100644 index 0000000000..c5f01cdb5b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h @@ -0,0 +1,27 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include + + +namespace Multiplayer +{ + static constexpr size_t GetMaxEditorServerInitSize() + { + constexpr size_t totalCapacity = AzNetworking::TcpPacketEncodingBuffer::GetCapacity(); + constexpr size_t packetOverhead = sizeof(bool) + 2 * sizeof(uint16_t); // m_lastUpdate + m_assetBuffer + static_assert(totalCapacity > packetOverhead); + return totalCapacity - packetOverhead; + } +} diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 9f5ca8c805..b15fff4cfc 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -68,6 +68,7 @@ set(FILES Source/ConnectionData/ServerToClientConnectionData.inl Source/Editor/MultiplayerEditorConnection.cpp Source/Editor/MultiplayerEditorConnection.h + Source/Editor/MultiplayerEditorUtils.h Source/EntityDomains/FullOwnershipEntityDomain.cpp Source/EntityDomains/FullOwnershipEntityDomain.h Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp From 6b1d3d1f9ae105171184f71e80d20a6d4500cf63 Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 24 Jun 2021 01:12:19 +0100 Subject: [PATCH 2/2] SPEC-7469 Multiplayer Editor Ctrl+G fails due to EditorInfo packets reordering. SPEC-7471 Multiplayer Editor Ctrl+G asserts after CreateEntitiesImmediate --- .../AutoGen/MultiplayerEditor.AutoPackets.xml | 4 ++- .../Editor/MultiplayerEditorConnection.cpp | 19 +++++++------ .../MultiplayerEditorSystemComponent.cpp | 14 +++++++--- .../Editor/MultiplayerEditorSystemComponent.h | 3 ++- .../Source/Editor/MultiplayerEditorUtils.h | 27 ------------------- .../NetworkEntity/NetworkSpawnableLibrary.cpp | 3 +++ Gems/Multiplayer/Code/multiplayer_files.cmake | 1 - 7 files changed, 28 insertions(+), 43 deletions(-) delete mode 100644 Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h diff --git a/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml index 8f55ecd2b8..dd553a2413 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml @@ -7,7 +7,9 @@ - + + + diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 601919ea7b..18b128f05e 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -11,9 +11,9 @@ */ #include +#include #include #include -#include #include #include @@ -56,16 +56,12 @@ namespace Multiplayer ) { // Editor Server Init is intended for non-release targets - if (!packet.GetLastUpdate()) - { - // More packets are expected, flush this to the buffer - m_byteStream.Write(GetMaxEditorServerInitSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); - } - else - { - // This is the last expected packet, flush it to the buffer - m_byteStream.Write(packet.GetAssetData().GetSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); + m_byteStream.Write(packet.GetAssetData().GetSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); + // In case if this is the last update, process the byteStream buffer. Otherwise more packets are expected + if (packet.GetLastUpdate()) + { + // This is the last expected packet // Read all assets out of the buffer m_byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); AZStd::vector> assetData; @@ -107,6 +103,9 @@ namespace Multiplayer m_byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); m_byteStream.Truncate(); + // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets + AZ::Interface::Get()->BuildSpawnablesList(); + // Load the level via the root spawnable that was registered const AZ::CVarFixedString loadLevelString = "LoadLevel Root.spawnable"; AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index e1690d8ecc..7c2a7e4fd7 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -12,11 +12,11 @@ #include #include +#include #include #include #include -#include #include #include @@ -192,6 +192,9 @@ namespace Multiplayer m_serverProcess = LaunchEditorServer(); } + // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets + AZ::Interface::Get()->BuildSpawnablesList(); + // Now that the server has launched, attempt to connect the NetworkInterface INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPEditorInterfaceName)); AZ_Assert(editorNetworkInterface, "MP Editor Network Interface was unregistered before Editor could connect."); @@ -212,10 +215,10 @@ namespace Multiplayer while (byteStream.GetCurPos() < byteStream.GetLength()) { MultiplayerEditorPackets::EditorServerInit packet; - AzNetworking::TcpPacketEncodingBuffer& outBuffer = packet.ModifyAssetData(); + auto& outBuffer = packet.ModifyAssetData(); // Size the packet's buffer appropriately - size_t readSize = GetMaxEditorServerInitSize(); + size_t readSize = outBuffer.GetCapacity(); size_t byteStreamSize = byteStream.GetLength() - byteStream.GetCurPos(); if (byteStreamSize < readSize) { @@ -233,6 +236,11 @@ namespace Multiplayer editorNetworkInterface->SendReliablePacket(m_editorConnId, packet); } } + } + void MultiplayerEditorSystemComponent::OnGameEntitiesReset() + { + // Rebuild the library to clear temporary in-memory spawnable assets + AZ::Interface::Get()->BuildSpawnablesList(); } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index 81b138c675..b6b111ee2a 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -68,7 +68,8 @@ namespace Multiplayer //! GameEntityContextEventBus::Handler overrides //! @{ - void OnGameEntitiesStarted() override; + void OnGameEntitiesStarted() override; + void OnGameEntitiesReset() override; //! @} IEditor* m_editor = nullptr; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h deleted file mode 100644 index c5f01cdb5b..0000000000 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorUtils.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - - -namespace Multiplayer -{ - static constexpr size_t GetMaxEditorServerInitSize() - { - constexpr size_t totalCapacity = AzNetworking::TcpPacketEncodingBuffer::GetCapacity(); - constexpr size_t packetOverhead = sizeof(bool) + 2 * sizeof(uint16_t); // m_lastUpdate + m_assetBuffer - static_assert(totalCapacity > packetOverhead); - return totalCapacity - packetOverhead; - } -} diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp index 935744f807..ec5a804834 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -32,6 +32,9 @@ namespace Multiplayer void NetworkSpawnableLibrary::BuildSpawnablesList() { + m_spawnables.clear(); + m_spawnablesReverseLookup.clear(); + auto enumerateCallback = [this](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { if (info.m_assetType == AZ::AzTypeInfo::Uuid()) diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index b15fff4cfc..9f5ca8c805 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -68,7 +68,6 @@ set(FILES Source/ConnectionData/ServerToClientConnectionData.inl Source/Editor/MultiplayerEditorConnection.cpp Source/Editor/MultiplayerEditorConnection.h - Source/Editor/MultiplayerEditorUtils.h Source/EntityDomains/FullOwnershipEntityDomain.cpp Source/EntityDomains/FullOwnershipEntityDomain.h Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp