diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h b/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h index c8a245af68..ff1cd13023 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h @@ -308,6 +308,8 @@ namespace AZ Asset(AssetLoadBehavior loadBehavior = AssetLoadBehavior::Default); /// Create an asset from a valid asset data (created asset), might not be loaded or currently loading. Asset(AssetData* assetData, AssetLoadBehavior loadBehavior); + /// Create an asset from a valid asset data (created asset) and set the asset id for both, might not be loaded or currently loading. + Asset(const AZ::Data::AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior); /// Initialize asset pointer with id, type, and hint. No data construction will occur until QueueLoad is called. Asset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint = AZStd::string()); @@ -788,6 +790,17 @@ namespace AZ SetData(assetData); } + //========================================================================= + template + Asset::Asset(const AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior) + : m_assetId(id) + , m_assetType(azrtti_typeid()) + , m_loadBehavior(loadBehavior) + { + assetData->m_assetId = id; + SetData(assetData); + } + //========================================================================= template Asset::Asset(const AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h index 4476876b59..2afabd16a9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h @@ -46,6 +46,8 @@ namespace AzToolsFramework virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0; + //! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G) + //! /return The vector of Assets generated by Prefab processing virtual const AZStd::vector>& GetPlayInEditorAssetData() = 0; virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0; diff --git a/Gems/Multiplayer/Code/Include/MultiplayerConstants.h b/Gems/Multiplayer/Code/Include/MultiplayerConstants.h new file mode 100644 index 0000000000..892691177a --- /dev/null +++ b/Gems/Multiplayer/Code/Include/MultiplayerConstants.h @@ -0,0 +1,32 @@ +/* +* 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 +#include +#include +#include +#include +#include + +namespace Multiplayer +{ + static constexpr AZStd::string_view MPNetworkInterfaceName("MultiplayerNetworkInterface"); + static constexpr AZStd::string_view MPEditorInterfaceName("MultiplayerEditorNetworkInterface"); + + static constexpr AZStd::string_view LocalHost("127.0.0.1"); + static constexpr uint16_t DefaultServerPort = 30090; + static constexpr uint16_t DefaultServerEditorPort = 30091; + +} + diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index dcf9c134da..c97c66544e 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -11,26 +11,22 @@ */ #include +#include #include #include #include #include -#include +#include #include #include #include #include +#include namespace Multiplayer { using namespace AzNetworking; - static const AZStd::string_view s_networkInterfaceName("MultiplayerNetworkInterface"); - static const AZStd::string_view s_networkEditorInterfaceName("MultiplayerEditorNetworkInterface"); - static constexpr AZStd::string_view DefaultEditorIp = "127.0.0.1"; - static constexpr uint16_t DefaultServerPort = 30090; - static constexpr uint16_t DefaultServerEditorPort = 30091; - static AZStd::vector buffer; static AZ::IO::ByteContainerStream> s_byteStream(&buffer); @@ -39,10 +35,16 @@ namespace Multiplayer MultiplayerEditorConnection::MultiplayerEditorConnection() { m_networkEditorInterface = AZ::Interface::Get()->CreateNetworkInterface( - AZ::Name(s_networkEditorInterfaceName), ProtocolType::Tcp, TrustZone::ExternalClientToServer, *this); + AZ::Name(MPEditorInterfaceName), ProtocolType::Tcp, TrustZone::ExternalClientToServer, *this); if (editorsv_isDedicated) { - m_networkEditorInterface->Listen(DefaultServerEditorPort); + uint16_t editorServerPort = DefaultServerEditorPort; + if (auto console = AZ::Interface::Get(); console) + { + console->GetCvarValue("editorsv_port", editorServerPort); + } + AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening."); + m_networkEditorInterface->Listen(editorServerPort); } } @@ -69,34 +71,56 @@ namespace Multiplayer AZStd::vector> assetData; while (s_byteStream.GetCurPos() < s_byteStream.GetLength()) { + AZ::Data::AssetId assetId; AZ::Data::AssetLoadBehavior assetLoadBehavior; + uint32_t hintSize; + AZStd::string assetHint; + s_byteStream.Read(sizeof(AZ::Data::AssetId), reinterpret_cast(&assetId)); s_byteStream.Read(sizeof(AZ::Data::AssetLoadBehavior), reinterpret_cast(&assetLoadBehavior)); + s_byteStream.Read(sizeof(uint32_t), reinterpret_cast(&hintSize)); + assetHint.resize(hintSize); + s_byteStream.Read(hintSize, assetHint.data()); + + size_t assetSize = s_byteStream.GetCurPos(); + AZ::Data::AssetData* assetDatum = AZ::Utils::LoadObjectFromStream(s_byteStream, nullptr); + assetSize = s_byteStream.GetCurPos() - assetSize; + AZ::Data::Asset asset = AZ::Data::Asset(assetId, assetDatum, assetLoadBehavior); + asset.SetHint(assetHint); + + AZ::Data::AssetInfo assetInfo; + assetInfo.m_assetId = asset.GetId(); + assetInfo.m_assetType = asset.GetType(); + assetInfo.m_relativePath = asset.GetHint(); + assetInfo.m_sizeBytes = assetSize; - AZ::Data::AssetData* assetDatum = AZ::Utils::LoadObjectFromStream(s_byteStream, nullptr); - AZ::Data::Asset asset = AZ::Data::Asset(assetDatum, assetLoadBehavior); - - /* // Register Asset to AssetManager - */ - - assetData.push_back(asset); + AZ::Data::AssetManager::Instance().AssignAssetData(asset); + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::RegisterAsset, asset.GetId(), assetInfo); + + assetData.push_back(asset); } // Now that we've deserialized, clear the byte stream s_byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); s_byteStream.Truncate(); - /* - // Hand-off our resultant assets - */ + // Load the level via the root spawnable tha was registered + AZ::CVarFixedString loadLevelString = "LoadLevel Root.spawnable"; + AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); AZLOG_INFO("Editor Server completed asset receive, responding to Editor..."); if (connection->SendReliablePacket(MultiplayerEditorPackets::EditorServerReady())) { // Setup the normal multiplayer connection AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); - INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName)); - networkInterface->Listen(DefaultServerPort); + INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); + + uint16_t serverPort = DefaultServerPort; + if (auto console = AZ::Interface::Get(); console) + { + console->GetCvarValue("sv_port", serverPort); + } + networkInterface->Listen(serverPort); return true; } @@ -121,11 +145,22 @@ namespace Multiplayer // Receiving this packet means Editor sync is done, disconnect connection->Disconnect(AzNetworking::DisconnectReason::TerminatedByClient, AzNetworking::TerminationEndpoint::Local); - // Connect the Editor to the local server for Multiplayer simulation - AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); - INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName)); - const IpAddress ipAddress(DefaultEditorIp.data(), DefaultServerEditorPort, networkInterface->GetType()); - networkInterface->Connect(ipAddress); + if (auto console = AZ::Interface::Get(); console) + { + AZ::CVarFixedString remoteAddress; + uint16_t remotePort; + if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && + console->GetCvarValue("editorsv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) + { + // Connect the Editor to the editor server for Multiplayer simulation + AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); + INetworkInterface* networkInterface = + AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); + + const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType()); + networkInterface->Connect(ipAddress); + } + } } return true; } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 4c3e8200a1..89cb816695 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -26,16 +27,16 @@ namespace Multiplayer { - static const AZStd::string_view s_networkEditorInterfaceName("MultiplayerEditorNetworkInterface"); - using namespace AzNetworking; AZ_CVAR(bool, editorsv_enabled, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether Editor launching a local server to connect to is supported"); + AZ_CVAR(bool, editorsv_launch, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "Whether Editor should launch a server when the server address is localhost"); AZ_CVAR(AZ::CVarFixedString, editorsv_process, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The server executable that should be run. Empty to use the current project's ServerLauncher"); - AZ_CVAR(AZ::CVarFixedString, editorsv_serveraddr, "127.0.0.1", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the server to connect to"); - AZ_CVAR(uint16_t, editorsv_port, 30091, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic"); + AZ_CVAR(AZ::CVarFixedString, editorsv_serveraddr, LocalHost.data(), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the server to connect to"); + AZ_CVAR(uint16_t, editorsv_port, DefaultServerEditorPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic"); void MultiplayerEditorSystemComponent::Reflect(AZ::ReflectContext* context) { @@ -105,7 +106,7 @@ namespace Multiplayer m_serverProcess->TerminateProcess(0); m_serverProcess = nullptr; } - INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkEditorInterfaceName)); + INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPEditorInterfaceName)); if (editorNetworkInterface) { editorNetworkInterface->Disconnect(m_editorConnId, AzNetworking::DisconnectReason::TerminatedByClient); @@ -114,6 +115,46 @@ namespace Multiplayer } } + void LaunchEditorServer(AzFramework::ProcessWatcher* outProcess) + { + // Assemble the server's path + AZ::CVarFixedString serverProcess = editorsv_process; + if (serverProcess.empty()) + { + // If enabled but no process name is supplied, try this project's ServerLauncher + serverProcess = AZ::Utils::GetProjectName() + ".ServerLauncher"; + } + + AZ::IO::FixedMaxPathString serverPath = AZ::Utils::GetExecutableDirectory(); + if (!serverProcess.contains(AZ_TRAIT_OS_PATH_SEPARATOR)) + { + // If only the process name is specified, append that as well + serverPath.append(AZ_TRAIT_OS_PATH_SEPARATOR + serverProcess); + } + else + { + // If any path was already specified, then simply assign + serverPath = serverProcess; + } + + if (!serverProcess.ends_with(AZ_TRAIT_OS_EXECUTABLE_EXTENSION)) + { + // Add this platform's exe extension if it's not specified + serverPath.append(AZ_TRAIT_OS_EXECUTABLE_EXTENSION); + } + + // Start the configured server if it's available + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" --editorsv_isDedicated true", serverPath.c_str()); + processLaunchInfo.m_showWindow = true; + processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; + + // Launch the Server and give it a few seconds to boot up + outProcess = AzFramework::ProcessWatcher::LaunchProcess( + processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE); + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(15000)); + } + void MultiplayerEditorSystemComponent::OnGameEntitiesStarted() { auto prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); @@ -134,55 +175,38 @@ namespace Multiplayer // Serialize Asset information and AssetData into a potentially large buffer for (auto asset : assetData) { + AZ::Data::AssetId assetId = asset.GetId(); AZ::Data::AssetLoadBehavior assetLoadBehavior = asset.GetAutoLoadBehavior(); + AZStd::string assetHint = asset.GetHint(); + uint32_t hintSize = aznumeric_cast(assetHint.size()); + + byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast(&assetId)); byteStream.Write(sizeof(AZ::Data::AssetLoadBehavior), reinterpret_cast(&assetLoadBehavior)); - + byteStream.Write(sizeof(uint32_t), reinterpret_cast(&hintSize)); + byteStream.Write(assetHint.size(), assetHint.data()); AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType()); } - // Assemble the server's path - AZ::CVarFixedString serverProcess = editorsv_process; - if (serverProcess.empty()) + const AZ::CVarFixedString remoteAddress = editorsv_serveraddr; + if (editorsv_launch && LocalHost.compare(remoteAddress.c_str()) == 0) { - // If enabled but no process name is supplied, try this project's ServerLauncher - serverProcess = AZ::Utils::GetProjectName() + ".ServerLauncher"; + LaunchEditorServer(m_serverProcess); } - AZ::IO::FixedMaxPathString serverPath = AZ::Utils::GetExecutableDirectory(); - if (!serverProcess.contains(AZ_TRAIT_OS_PATH_SEPARATOR)) - { - // If only the process name is specified, append that as well - serverPath.append(AZ_TRAIT_OS_PATH_SEPARATOR + serverProcess); - } - else - { - // If any path was already specified, then simply assign - serverPath = serverProcess; - } + // 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."); + m_editorConnId = editorNetworkInterface->Connect( + AzNetworking::IpAddress(remoteAddress.c_str(), editorsv_port, AzNetworking::ProtocolType::Tcp)); - if (!serverProcess.ends_with(AZ_TRAIT_OS_EXECUTABLE_EXTENSION)) + if (m_editorConnId == AzNetworking::InvalidConnectionId) { - // Add this platform's exe extension if it's not specified - serverPath.append(AZ_TRAIT_OS_EXECUTABLE_EXTENSION); + AZ_Warning( + "MultiplayerEditor", false, + "Could not connect to server targeted by Editor. If using a local server, check that it's built and editorsv_launch is true."); + return; } - // Start the configured server if it's available - AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; - processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" --editorsv_isDedicated true", serverPath.c_str()); - processLaunchInfo.m_showWindow = true; - processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; - - // Launch the Server and give it a few seconds to boot up - m_serverProcess = AzFramework::ProcessWatcher::LaunchProcess( - processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE); - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(15000)); - - // Now that the server has launched, attempt to connect the NetworkInterface - const AZ::CVarFixedString remoteAddress = editorsv_serveraddr; - INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkEditorInterfaceName)); - m_editorConnId = editorNetworkInterface->Connect( - AzNetworking::IpAddress(remoteAddress.c_str(), editorsv_port, AzNetworking::ProtocolType::Tcp)); - // Read the buffer into EditorServerInit packets until we've flushed the whole thing byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index f920e7ed74..a0a343f320 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -59,13 +60,8 @@ namespace Multiplayer { using namespace AzNetworking; - static const AZStd::string_view s_networkInterfaceName("MultiplayerNetworkInterface"); - static const AZStd::string_view s_networkEditorInterfaceName("MultiplayerEditorNetworkInterface"); - static constexpr uint16_t DefaultServerPort = 30090; - static constexpr uint16_t DefaultServerEditorPort = 30091; - AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port"); - AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, "127.0.0.1", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the remote server or host to connect to"); + AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, LocalHost.data(), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the remote server or host to connect to"); AZ_CVAR(AZ::CVarFixedString, cl_serverpassword, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Optional server password"); AZ_CVAR(uint16_t, cl_serverport, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port of the remote host to connect to for game traffic"); AZ_CVAR(uint16_t, sv_port, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that this multiplayer gem will bind to for game traffic"); @@ -116,7 +112,7 @@ namespace Multiplayer void MultiplayerSystemComponent::Activate() { AZ::TickBus::Handler::BusConnect(); - m_networkInterface = AZ::Interface::Get()->CreateNetworkInterface(AZ::Name(s_networkInterfaceName), sv_protocol, TrustZone::ExternalClientToServer, *this); + m_networkInterface = AZ::Interface::Get()->CreateNetworkInterface(AZ::Name(MPNetworkInterfaceName), sv_protocol, TrustZone::ExternalClientToServer, *this); m_consoleCommandHandler.Connect(AZ::Interface::Get()->GetConsoleCommandInvokedEvent()); AZ::Interface::Register(this); @@ -635,7 +631,7 @@ namespace Multiplayer { Multiplayer::MultiplayerAgentType serverType = sv_isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer; AZ::Interface::Get()->InitializeMultiplayer(serverType); - INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName)); + INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); networkInterface->Listen(sv_port); } AZ_CONSOLEFREEFUNC(host, AZ::ConsoleFunctorFlags::DontReplicate, "Opens a multiplayer connection as a host for other clients to connect to"); @@ -643,7 +639,7 @@ namespace Multiplayer void connect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); - INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName)); + INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); if (arguments.size() < 1) { @@ -673,7 +669,7 @@ namespace Multiplayer void disconnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Uninitialized); - INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName)); + INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); }; networkInterface->GetConnectionSet().VisitConnections(visitor); } diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index bc6e5710fc..137bd27794 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -31,11 +31,16 @@ namespace Multiplayer void NetworkPrefabProcessor::Process(PrefabProcessorContext& context) { IMultiplayerTools* mpTools = AZ::Interface::Get(); - mpTools->SetDidProcessNetworkPrefabs(false); + if (mpTools) + { + mpTools->SetDidProcessNetworkPrefabs(false); + } + context.ListPrefabs([&context](AZStd::string_view prefabName, PrefabDom& prefab) { ProcessPrefab(context, prefabName, prefab); }); - if (context.GetProcessedObjects().size() > 0) + + if (mpTools && context.GetProcessedObjects().size() > 0) { mpTools->SetDidProcessNetworkPrefabs(true); } diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index b8fd842426..ecde01e2d7 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -17,6 +17,7 @@ set(FILES Include/INetworkEntityManager.h Include/INetworkTime.h Include/IReplicationWindow.h + Include/MultiplayerConstants.h Include/MultiplayerStats.cpp Include/MultiplayerStats.h Include/MultiplayerTypes.h