Cleanup server launch, misc. MP consts, and register Editor Spawnable assets server side

main
puvvadar 5 years ago
parent 74ea093f71
commit 1915b97c16

@ -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<class T>
Asset<T>::Asset(const AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior)
: m_assetId(id)
, m_assetType(azrtti_typeid<T>())
, m_loadBehavior(loadBehavior)
{
assetData->m_assetId = id;
SetData(assetData);
}
//=========================================================================
template<class T>
Asset<T>::Asset(const AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint)

@ -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<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() = 0;
virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;

@ -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 <AzCore/EBus/Event.h>
#include <AzCore/Name/Name.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/string/fixed_string.h>
#include <AzNetworking/Serialization/ISerializer.h>
#include <AzNetworking/ConnectionLayer/ConnectionEnums.h>
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;
}

@ -11,26 +11,22 @@
*/
#include <Include/IMultiplayer.h>
#include <Include/MultiplayerConstants.h>
#include <Source/Editor/MultiplayerEditorConnection.h>
#include <Source/AutoGen/AutoComponentTypes.h>
#include <AzNetworking/ConnectionLayer/IConnection.h>
#include <AzNetworking/Framework/INetworking.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <AzFramework/Spawnable/Spawnable.h>
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<uint8_t> buffer;
static AZ::IO::ByteContainerStream<AZStd::vector<uint8_t>> s_byteStream(&buffer);
@ -39,10 +35,16 @@ namespace Multiplayer
MultiplayerEditorConnection::MultiplayerEditorConnection()
{
m_networkEditorInterface = AZ::Interface<INetworking>::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<AZ::IConsole>::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<AZ::Data::Asset<AZ::Data::AssetData>> 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<void*>(&assetId));
s_byteStream.Read(sizeof(AZ::Data::AssetLoadBehavior), reinterpret_cast<void*>(&assetLoadBehavior));
s_byteStream.Read(sizeof(uint32_t), reinterpret_cast<void*>(&hintSize));
assetHint.resize(hintSize);
s_byteStream.Read(hintSize, assetHint.data());
size_t assetSize = s_byteStream.GetCurPos();
AZ::Data::AssetData* assetDatum = AZ::Utils::LoadObjectFromStream<AZ::Data::AssetData>(s_byteStream, nullptr);
assetSize = s_byteStream.GetCurPos() - assetSize;
AZ::Data::Asset<AZ::Data::AssetData> asset = AZ::Data::Asset<AZ::Data::AssetData>(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<AZ::Data::AssetData>(s_byteStream, nullptr);
AZ::Data::Asset<AZ::Data::AssetData> asset = AZ::Data::Asset<AZ::Data::AssetData>(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<AZ::IConsole>::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<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName));
networkInterface->Listen(DefaultServerPort);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
uint16_t serverPort = DefaultServerPort;
if (auto console = AZ::Interface<AZ::IConsole>::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<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName));
const IpAddress ipAddress(DefaultEditorIp.data(), DefaultServerEditorPort, networkInterface->GetType());
networkInterface->Connect(ipAddress);
if (auto console = AZ::Interface<AZ::IConsole>::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<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
INetworkInterface* networkInterface =
AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType());
networkInterface->Connect(ipAddress);
}
}
}
return true;
}

@ -12,6 +12,7 @@
#include <Include/IMultiplayer.h>
#include <Include/IMultiplayerTools.h>
#include <Include/MultiplayerConstants.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
#include <Source/MultiplayerSystemComponent.h>
#include <Source/Editor/MultiplayerEditorSystemComponent.h>
@ -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<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkEditorInterfaceName));
INetworkInterface* editorNetworkInterface = AZ::Interface<INetworking>::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<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::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<uint32_t>(assetHint.size());
byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast<void*>(&assetId));
byteStream.Write(sizeof(AZ::Data::AssetLoadBehavior), reinterpret_cast<void*>(&assetLoadBehavior));
byteStream.Write(sizeof(uint32_t), reinterpret_cast<void*>(&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<INetworking>::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<INetworking>::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);

@ -10,6 +10,7 @@
*
*/
#include <Include/MultiplayerConstants.h>
#include <Source/MultiplayerSystemComponent.h>
#include <Source/Components/MultiplayerComponent.h>
#include <Source/AutoGen/AutoComponentTypes.h>
@ -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<INetworking>::Get()->CreateNetworkInterface(AZ::Name(s_networkInterfaceName), sv_protocol, TrustZone::ExternalClientToServer, *this);
m_networkInterface = AZ::Interface<INetworking>::Get()->CreateNetworkInterface(AZ::Name(MPNetworkInterfaceName), sv_protocol, TrustZone::ExternalClientToServer, *this);
m_consoleCommandHandler.Connect(AZ::Interface<AZ::IConsole>::Get()->GetConsoleCommandInvokedEvent());
AZ::Interface<IMultiplayer>::Register(this);
@ -635,7 +631,7 @@ namespace Multiplayer
{
Multiplayer::MultiplayerAgentType serverType = sv_isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer;
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(serverType);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName));
INetworkInterface* networkInterface = AZ::Interface<INetworking>::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<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName));
INetworkInterface* networkInterface = AZ::Interface<INetworking>::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<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Uninitialized);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(s_networkInterfaceName));
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); };
networkInterface->GetConnectionSet().VisitConnections(visitor);
}

@ -31,11 +31,16 @@ namespace Multiplayer
void NetworkPrefabProcessor::Process(PrefabProcessorContext& context)
{
IMultiplayerTools* mpTools = AZ::Interface<IMultiplayerTools>::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);
}

@ -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

Loading…
Cancel
Save