diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp index 8a083c6727..fc0847b5ab 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpConnection.cpp @@ -200,6 +200,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/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 bb4eabbe85..6cbe24927d 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -50,16 +51,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(TcpPacketEncodingBuffer::GetCapacity(), 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; @@ -75,6 +72,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); @@ -96,6 +98,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 5eac7e3e4b..a2841927d6 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -186,6 +187,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."); @@ -206,10 +210,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 = TcpPacketEncodingBuffer::GetCapacity(); + size_t readSize = outBuffer.GetCapacity(); size_t byteStreamSize = byteStream.GetLength() - byteStream.GetCurPos(); if (byteStreamSize < readSize) { @@ -227,6 +231,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 4035f40231..f1abd216e2 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -63,7 +63,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/NetworkEntity/NetworkSpawnableLibrary.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp index 334a57532a..93bccd5c81 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -27,6 +27,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())