Reverts changes to component application and adds further client migration handling hookup

Signed-off-by: kberg-amzn <karlberg@amazon.com>
monroegm-disable-blank-issue-2
kberg-amzn 4 years ago
parent ca7de715fd
commit d28bcbe027

@ -121,9 +121,9 @@ namespace AZ
return environment ? environment->Get() : nullptr;
}
ComponentApplication::EventLoggerDeleter::EventLoggerDeleter() noexcept= default;
ComponentApplication::EventLoggerDeleter::EventLoggerDeleter() noexcept = default;
ComponentApplication::EventLoggerDeleter::EventLoggerDeleter(bool skipDelete) noexcept
: m_skipDelete{skipDelete}
: m_skipDelete{ skipDelete }
{}
void ComponentApplication::EventLoggerDeleter::operator()(AZ::Debug::LocalFileEventLogger* ptr)
{
@ -332,27 +332,27 @@ namespace AZ
->Value("Stack trace always", Debug::AllocationRecords::RECORD_FULL);
ec->Class<Descriptor>("System memory settings", "Settings for managing application memory usage")
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_grabAllMemory, "Allocate all memory at startup", "Allocate all system memory at startup if enabled, or allocate as needed if disabled")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_allocationRecords, "Record allocations", "Collect information on each allocation made for debugging purposes (ignored in Release builds)")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_allocationRecordsSaveNames, "Record allocations with name saving", "Saves names/filenames information on each allocation made, useful for tracking down leaks in dynamic modules (ignored in Release builds)")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_allocationRecordsAttemptDecodeImmediately, "Record allocations and attempt immediate decode", "Decode callstacks for each allocation when they occur, used for tracking allocations that fail decoding. Very expensive. (ignored in Release builds)")
->DataElement(Edit::UIHandlers::ComboBox, &Descriptor::m_recordingMode, "Stack recording mode", "Stack record mode. (Ignored in final builds)")
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_stackRecordLevels, "Stack entries to record", "Number of stack levels to record for each allocation (ignored in Release builds)")
->Attribute(Edit::Attributes::Step, 1)
->Attribute(Edit::Attributes::Max, 1024)
->Attribute(Edit::Attributes::Step, 1)
->Attribute(Edit::Attributes::Max, 1024)
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_autoIntegrityCheck, "Validate allocations", "Check allocations for integrity on each allocation/free (ignored in Release builds)")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_markUnallocatedMemory, "Mark freed memory", "Set memory to 0xcd when a block is freed for debugging (ignored in Release builds)")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_doNotUsePools, "Don't pool allocations", "Pipe pool allocations in system/tree heap (ignored in Release builds)")
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_pageSize, "Page size", "Memory page size in bytes (must be OS page size aligned)")
->Attribute(Edit::Attributes::Step, 1024)
->Attribute(Edit::Attributes::Step, 1024)
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_poolPageSize, "Pool page size", "Memory pool page size in bytes (must be a multiple of page size)")
->Attribute(Edit::Attributes::Max, &Descriptor::m_pageSize)
->Attribute(Edit::Attributes::Step, 1024)
->Attribute(Edit::Attributes::Max, &Descriptor::m_pageSize)
->Attribute(Edit::Attributes::Step, 1024)
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_memoryBlockAlignment, "Block alignment", "Memory block alignment in bytes (must be multiple of the page size)")
->Attribute(Edit::Attributes::Step, &Descriptor::m_pageSize)
->Attribute(Edit::Attributes::Step, &Descriptor::m_pageSize)
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_memoryBlocksByteSize, "Block size", "Memory block size in bytes (must be multiple of the page size)")
->Attribute(Edit::Attributes::Step, &Descriptor::m_pageSize)
->Attribute(Edit::Attributes::Step, &Descriptor::m_pageSize)
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_reservedOS, "OS reserved memory", "System memory reserved for OS (used only when 'Allocate all memory at startup' is true)")
->DataElement(Edit::UIHandlers::SpinBox, &Descriptor::m_reservedDebug, "Memory reserved for debugger", "System memory reserved for Debug allocator, like memory tracking (used only when 'Allocate all memory at startup' is true)")
->DataElement(Edit::UIHandlers::CheckBox, &Descriptor::m_enableDrilling, "Enable Driller", "Enable Drilling support for the application (ignored in Release builds)")
@ -419,11 +419,11 @@ namespace AZ
}
else
{
azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied");
azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied");
// use a "valid" value here. This is because Qt and potentially other third party libraries require
// that ArgC be 'at least 1' and that (*argV)[0] be a valid pointer to a real null terminated string.
m_argC = 1;
m_argV = &m_commandLineBufferAddress;
m_argC = 1;
m_argV = &m_commandLineBufferAddress;
}
// Create the Event logger if it doesn't exist, otherwise reuse the one registered
@ -557,8 +557,8 @@ namespace AZ
void ReportBadEngineRoot()
{
AZStd::string errorMessage = {"Unable to determine a valid path to the engine.\n"
"Check parameters such as --project-path and --engine-path and make sure they are valid.\n"};
AZStd::string errorMessage = { "Unable to determine a valid path to the engine.\n"
"Check parameters such as --project-path and --engine-path and make sure they are valid.\n" };
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
{
AZ::SettingsRegistryInterface::FixedValueString filePathErrorStr;
@ -614,7 +614,6 @@ namespace AZ
AZ_Assert(m_systemEntity, "SystemEntity failed to initialize!");
AddRequiredSystemComponents(m_systemEntity.get());
//m_currentTime = GetElapsedTimeUs();
m_isStarted = true;
return m_systemEntity.get();
}
@ -1372,38 +1371,44 @@ namespace AZ
void ComponentApplication::Tick(float deltaOverride /*= -1.f*/)
{
AZ_PROFILE_SCOPE(System, "Component application simulation tick");
AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
m_deltaTime = 0.0f;
if (now >= m_currentTime)
{
AZStd::chrono::duration<float> delta = now - m_currentTime;
m_deltaTime = deltaOverride >= 0.f ? deltaOverride : delta.count();
}
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:ExecuteQueuedEvents");
TickBus::ExecuteQueuedEvents();
}
m_currentTime = now;
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
AZ_PROFILE_SCOPE(System, "Component application simulation tick");
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
m_deltaTime = 0.0f;
if (timeUntilNextTick.count() > 0)
if (now >= m_currentTime)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
AZStd::chrono::duration<float> delta = now - m_currentTime;
m_deltaTime = deltaOverride >= 0.f ? deltaOverride : delta.count();
}
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:ExecuteQueuedEvents");
TickBus::ExecuteQueuedEvents();
}
m_currentTime = now;
{
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
if (timeUntilNextTick.count() > 0)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
}
}
}
}
@ -1555,5 +1560,4 @@ namespace AZ
AZ::SettingsRegistryScriptUtils::ReflectSettingsRegistryToBehaviorContext(*behaviorContext);
}
}
} // namespace AZ

@ -5,13 +5,13 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Time/ITime.h>
#include <AzCore/Memory/AllocationRecords.h>
#include <AzCore/Debug/BudgetTracker.h>
#include <AzCore/Memory/OSAllocator.h>
@ -377,14 +377,14 @@ namespace AZ
EntityRemovedEvent m_entityRemovedEvent;
EntityAddedEvent m_entityActivatedEvent;
EntityRemovedEvent m_entityDeactivatedEvent;
AZ::IConsole* m_console{};
AZ::IConsole* m_console{};
Descriptor m_descriptor;
bool m_isStarted{ false };
bool m_isSystemAllocatorOwner{ false };
bool m_isOSAllocatorOwner{ false };
bool m_ownsConsole{};
void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy.
IAllocatorAllocate* m_osAllocator{ nullptr };
void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy.
IAllocatorAllocate* m_osAllocator{ nullptr };
EntitySetType m_entities;
AZ::IO::FixedMaxPath m_exeDirectory;
AZ::IO::FixedMaxPath m_engineRoot;
@ -405,11 +405,11 @@ namespace AZ
// we create a buffer that can be written to (up to AZ_MAX_PATH_LEN) and then
// pack it with a single param.
char m_commandLineBuffer[AZ_MAX_PATH_LEN];
char* m_commandLineBufferAddress{ m_commandLineBuffer };
char* m_commandLineBufferAddress{ m_commandLineBuffer };
StartupParameters m_startupParameters;
char** m_argV{ nullptr };
char** m_argV{ nullptr };
int m_argC{ 0 };
AZ::CommandLine m_commandLine; // < Stores parsed command line supplied to the constructor

@ -45,6 +45,7 @@ namespace Multiplayer
using ClientMigrationStartEvent = AZ::Event<ClientInputId>;
using ClientMigrationEndEvent = AZ::Event<>;
using ClientDisconnectedEvent = AZ::Event<>;
using NotifyClientMigrationEvent = AZ::Event<HostId, uint64_t, ClientInputId>;
using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>;
using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using SessionShutdownEvent = AZ::Event<AzNetworking::INetworkInterface*>;
@ -80,34 +81,38 @@ namespace Multiplayer
//! @param state The state of this connection
virtual void InitializeMultiplayer(MultiplayerAgentType state) = 0;
//! Starts hosting a server
//! Starts hosting a server.
//! @param port The port to listen for connection on
//! @param isDedicated Whether the server is dedicated or client hosted
//! @return if the application successfully started hosting
virtual bool StartHosting(uint16_t port, bool isDedicated = true) = 0;
//! Connects to the specified IP as a Client
//! Connects to the specified IP as a Client.
//! @param remoteAddress The domain or IP to connect to
//! @param port The port to connect to
//! @result if a connection was successfully created
virtual bool Connect(AZStd::string remoteAddress, uint16_t port) = 0;
// Disconnects all multiplayer connections, stops listening on the server and invokes handlers appropriate to network context
// Disconnects all multiplayer connections, stops listening on the server and invokes handlers appropriate to network context.
//! @param reason The reason for terminating connections
virtual void Terminate(AzNetworking::DisconnectReason reason) = 0;
//! Adds a ClientMigrationStartEvent Handler which is invoked at the start of a client migration
//! Adds a ClientMigrationStartEvent Handler which is invoked at the start of a client migration.
//! @param handler The ClientMigrationStartEvent Handler to add
virtual void AddClientMigrationStartEventHandler(ClientMigrationStartEvent::Handler& handler) = 0;
//! Adds a ClientMigrationEndEvent Handler which is invoked when a client completes migration
//! Adds a ClientMigrationEndEvent Handler which is invoked when a client completes migration.
//! @param handler The ClientMigrationEndEvent Handler to add
virtual void AddClientMigrationEndEventHandler(ClientMigrationEndEvent::Handler& handler) = 0;
//! Adds a ClientDisconnectedEvent Handler which is invoked on the client when a disconnection occurs
//! Adds a ClientDisconnectedEvent Handler which is invoked on the client when a disconnection occurs.
//! @param handler The ClientDisconnectedEvent Handler to add
virtual void AddClientDisconnectedHandler(ClientDisconnectedEvent::Handler& handler) = 0;
//! Adds a NotifyClientMigrationEvent Handler which is invoked when a client migrates from one host to another.
//! @param handler The NotifyClientMigrationEvent Handler to add
virtual void AddNotifyClientMigrationHandler(NotifyClientMigrationEvent::Handler& handler) = 0;
//! Adds a ConnectionAcquiredEvent Handler which is invoked when a new endpoint connects to the session.
//! @param handler The ConnectionAcquiredEvent Handler to add
virtual void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) = 0;
@ -120,7 +125,13 @@ namespace Multiplayer
//! @param handler The SessionShutdownEvent handler to add
virtual void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) = 0;
//! Sends a packet telling if entity update messages can be sent
//! Signals a NotifyClientMigrationEvent with the provided parameters.
//! @param hostId the host id of the host the client is migrating to
//! @param userIdentifier the user identifier the client will provide the new host to validate identity
//! @param lastClientInputId the last processed clientInputId by the current host
virtual void SendNotifyClientMigrationEvent(HostId hostId, uint64_t userIdentifier, ClientInputId lastClientInputId);
//! Sends a packet telling if entity update messages can be sent.
//! @param readyForEntityUpdates Ready for entity updates or not
virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0;
@ -132,7 +143,7 @@ namespace Multiplayer
//! @return the current server time in milliseconds
virtual AZ::TimeMs GetCurrentHostTimeMs() const = 0;
//! Returns the current blend factor for client side interpolation
//! Returns the current blend factor for client side interpolation.
//! This value is only relevant on the client and is used to smooth between host frames
//! @return the current blend factor
virtual float GetCurrentBlendFactor() const = 0;

@ -403,6 +403,8 @@ namespace {{ Component.attrib['Namespace'] }}
: public Multiplayer::MultiplayerController
{
public:
using ComponentType = {{ ComponentName }};
{{ ControllerBaseName }}({{ ComponentName }}& owner);
~{{ ControllerBaseName }}() override = default;

@ -40,8 +40,8 @@
</Packet>
<Packet Name="ClientMigration" Desc="Tell a client to migrate to a new server">
<Member Type="uint64_t" Name="temporaryUserIdentifier" Init="0" />
<Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
<Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" />
<Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
<Member Type="uint64_t" Name="temporaryUserIdentifier" Init="0" />
<Member Type="Multiplayer::ClientInputId" Name="lastClientInputId" Init="Multiplayer::ClientInputId{ 0 }" />
</Packet>
</PacketGroup>

@ -7,7 +7,10 @@
*/
#include <Source/ConnectionData/ServerToClientConnectionData.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
#include <Multiplayer/Components/LocalPredictionPlayerInputComponent.h>
#include <Multiplayer/IMultiplayer.h>
#include <AzNetworking/Utilities/EncryptionCommon.h>
namespace Multiplayer
{
@ -95,36 +98,31 @@ namespace Multiplayer
[[maybe_unused]] AzNetworking::ConnectionId connectionId
)
{
//Multiplayer::ServerAddrInfo serverAddr;
//if (gNovaGame->GetMultiplayerworkAgent().GetServerToServerNetwork().GetServerAddrInfoFromConnectionId(newConnectionId, serverAddr) == false)
//{
// AZLOG_WARN("MigrateClient::Failed to find servershard address, userID:%d", static_cast<uint32_t>(GetUserId()));
// return;
//}
//
//Multiplayer::GameTimePoint migratedClientGameTimePoint;
//
//if (m_ControlledEntity != nullptr)
//{
// if (const PlayerNetworkInputComponent::Authority* pComponent = Multiplayer::FindController<PlayerNetworkInputComponent::Authority>(m_ControlledEntity))
// {
// migratedClientGameTimePoint = pComponent->GetLastInputId().GetServerGameTimePoint();
// }
//}
//
// generate crypto-rand user identifier, send to both server and client so they can negotiate the autonomous entity to assume predictive control over after migration
//const uint64_t randomUserIdentifier = 0;
//
//// Tell the server a new client is about to join
//MultiplayerPackets::NotifyClientMigration notifyClientMigration(randomUserIdentifier);
//gNovaGame->GetMultiplayerworkAgent().GetServerToServerNetwork().SendReliablePacket(newConnectionId, notifyClientMigration);
//
//// Tell the client who to join
//MultiplayerPackets::ClientMigration clientMigration(randomUserIdentifier, serverAddr, migratedClientGameTimePoint);
//GetConnection()->SendReliablePacket(clientMigration);
//
//m_controlledEntity = nullptr;
//m_canSendUpdates = false;
AzNetworking::IpAddress serverAddress;
// serverAddress = GetHost(remoteHostId).GetAddress();
ClientInputId migratedClientInputId = ClientInputId{ 0 };
if (m_controlledEntity != nullptr)
{
auto controller = m_controlledEntity.FindController<LocalPredictionPlayerInputComponentController>();
if (controller != nullptr)
{
migratedClientInputId = controller->GetLastInputId();
}
}
// Generate crypto-rand user identifier, send to both server and client so they can negotiate the autonomous entity to assume predictive control over after migration
const uint64_t randomUserIdentifier = AzNetworking::CryptoRand64();
// Tell the new host that a client is about to (re)join
GetMultiplayer()->SendNotifyClientMigrationEvent(remoteHostId, randomUserIdentifier, migratedClientInputId);
// Tell the client who to join
MultiplayerPackets::ClientMigration clientMigration(serverAddress, randomUserIdentifier, migratedClientInputId);
GetConnection()->SendReliablePacket(clientMigration);
m_controlledEntity = NetworkEntityHandle();
m_canSendUpdates = false;
}
void ServerToClientConnectionData::OnGameplayStarted()

@ -617,7 +617,7 @@ namespace Multiplayer
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::ClientMigrated, TerminationEndpoint::Local); };
m_networkInterface->GetConnectionSet().VisitConnections(visitor);
AZLOG_INFO("Migrating to new server shard");
//m_clientMigrateStartEvent(packet.GetLastInputGameTimeMs());
m_clientMigrationStartEvent.Signal(ClientInputId{ 0 });
m_networkInterface->Connect(packet.GetRemoteServerAddress());
return true;
}
@ -795,6 +795,11 @@ namespace Multiplayer
handler.Connect(m_clientDisconnectedEvent);
}
void MultiplayerSystemComponent::AddNotifyClientMigrationHandler(NotifyClientMigrationEvent::Handler& handler)
{
handler.Connect(m_notifyClientMigrationEvent);
}
void MultiplayerSystemComponent::AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler)
{
handler.Connect(m_connectionAcquiredEvent);
@ -810,6 +815,11 @@ namespace Multiplayer
handler.Connect(m_shutdownEvent);
}
void MultiplayerSystemComponent::SendNotifyClientMigrationEvent(HostId hostId, uint64_t userIdentifier, ClientInputId lastClientInputId)
{
m_notifyClientMigrationEvent.Signal(hostId, userIdentifier, lastClientInputId);
}
void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates)
{
IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet();

@ -111,9 +111,11 @@ namespace Multiplayer
void AddClientMigrationStartEventHandler(ClientMigrationStartEvent::Handler& handler) override;
void AddClientMigrationEndEventHandler(ClientMigrationEndEvent::Handler& handler) override;
void AddClientDisconnectedHandler(ClientDisconnectedEvent::Handler& handler) override;
void AddNotifyClientMigrationHandler(NotifyClientMigrationEvent::Handler& handler) override;
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
void SendNotifyClientMigrationEvent(HostId hostId, uint64_t userIdentifier, ClientInputId lastClientInputId) override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
AZ::TimeMs GetCurrentHostTimeMs() const override;
float GetCurrentBlendFactor() const override;
@ -154,6 +156,7 @@ namespace Multiplayer
ClientDisconnectedEvent m_clientDisconnectedEvent;
ClientMigrationStartEvent m_clientMigrationStartEvent;
ClientMigrationEndEvent m_clientMigrationEndEvent;
NotifyClientMigrationEvent m_notifyClientMigrationEvent;
AZStd::queue<AZStd::string> m_pendingConnectionTickets;

Loading…
Cancel
Save