From 822368ef01db626bd3718c69fbe1be4ae43becf9 Mon Sep 17 00:00:00 2001 From: karlberg Date: Mon, 3 May 2021 16:26:11 -0700 Subject: [PATCH 01/18] Changes to get visibility system working again in-game --- .../AzCore/Component/ComponentApplication.cpp | 20 +++ .../AzCore/Component/ComponentApplication.h | 6 + .../Component/ComponentApplicationBus.h | 18 +++ .../AzCore/AzCore/Component/Entity.cpp | 2 + .../AzCore/Console/LoggerSystemComponent.cpp | 2 +- .../UnitTest/MockComponentApplication.h | 4 + .../AzCore/Tests/BehaviorContextFixture.h | 6 +- Code/Framework/AzCore/Tests/Serialization.cpp | 6 + .../Entity/GameEntityContextComponent.cpp | 4 + .../Entity/GameEntityContextComponent.h | 4 + .../AzFramework/Render/Intersector.cpp | 3 +- .../AzFramework/Visibility/BoundsBus.h | 19 +-- .../Visibility/EntityBoundsUnionBus.h | 16 ++- .../EntityVisibilityBoundsUnionSystem.cpp | 117 +++++++++--------- .../EntityVisibilityBoundsUnionSystem.h | 28 ++--- .../Visibility/EntityVisibilityQuery.cpp | 5 +- .../Entity/EditorEntityContextComponent.cpp | 4 +- .../Entity/EditorEntityContextComponent.h | 2 +- .../ToolsComponents/TransformComponent.cpp | 3 +- .../ViewportSelection/EditorHelpers.cpp | 8 +- .../ViewportSelection/EditorSelectionUtil.cpp | 5 +- .../Visibility/EditorVisibilityTests.cpp | 30 ++--- Code/Framework/Tests/ComponentAddRemove.cpp | 6 + Code/Framework/Tests/NetBindingMocks.h | 4 + .../Tests/Containers/SceneBehaviorTests.cpp | 4 + .../Code/Tests/AWSClientAuthGemMock.h | 4 + .../Code/Tests/ImageProcessing_Test.cpp | 6 + .../Tests.Builders/BuilderTestFixture.cpp | 2 + .../Code/Tests.Builders/BuilderTestFixture.h | 4 + .../Tests/Common/AssetManagerTestFixture.h | 4 + .../Source/Mesh/MeshComponentController.cpp | 3 +- .../ReflectionProbeComponentController.cpp | 3 +- .../Code/Source/AtomActorInstance.cpp | 3 +- .../Integration/Components/ActorComponent.cpp | 3 +- .../External/ImGui/v1.82/imgui/imgui.cpp | 8 +- .../Code/Tests/ImageProcessing_Test.cpp | 4 + .../Code/Source/Rendering/MeshComponent.cpp | 6 +- .../Source/Shape/EditorBaseShapeComponent.cpp | 5 +- .../Source/Shape/EditorSplineComponent.cpp | 4 +- .../Code/Tests/Builders/SliceBuilderTests.cpp | 6 + .../ServerToClientReplicationWindow.cpp | 12 +- .../Code/Tests/ScriptCanvasBuilderTests.cpp | 4 + .../Source/EditorOccluderAreaComponent.cpp | 3 +- .../Code/Source/EditorPortalComponent.cpp | 3 +- .../Code/Source/EditorVisAreaComponent.cpp | 3 +- .../Code/Source/EditorWhiteBoxComponent.cpp | 3 +- 46 files changed, 269 insertions(+), 150 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index c55f565615..d71358088e 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -986,6 +986,26 @@ namespace AZ handler.Connect(m_entityRemovedEvent); } + void ComponentApplication::RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) + { + handler.Connect(m_entityActivatedEvent); + } + + void ComponentApplication::RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) + { + handler.Connect(m_entityDeactivatedEvent); + } + + void ComponentApplication::SignalEntityActivated(AZ::Entity* entity) + { + m_entityActivatedEvent.Signal(entity); + } + + void ComponentApplication::SignalEntityDeactivated(AZ::Entity* entity) + { + m_entityDeactivatedEvent.Signal(entity); + } + //========================================================================= // AddEntity // [5/30/2012] diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index 3ebcf39d95..0d9aad0f0f 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -204,6 +204,10 @@ namespace AZ void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) override final; void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) override final; void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final; + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final; + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final; + void SignalEntityActivated(AZ::Entity* entity) override final; + void SignalEntityDeactivated(AZ::Entity* entity) override final; bool AddEntity(Entity* entity) override; bool RemoveEntity(Entity* entity) override; bool DeleteEntity(const EntityId& id) override; @@ -385,6 +389,8 @@ namespace AZ AZStd::unique_ptr m_settingsRegistry; EntityAddedEvent m_entityAddedEvent; EntityRemovedEvent m_entityRemovedEvent; + EntityAddedEvent m_entityActivatedEvent; + EntityRemovedEvent m_entityDeactivatedEvent; AZ::IConsole* m_console{}; Descriptor m_descriptor; bool m_isStarted{ false }; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h index 3582e6ebb8..c93f07f347 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h @@ -72,6 +72,8 @@ namespace AZ using EntityAddedEvent = AZ::Event; using EntityRemovedEvent = AZ::Event; + using EntityActivatedEvent = AZ::Event; + using EntityDeactivatedEvent = AZ::Event; //! Interface that components can use to make requests of the main application. class ComponentApplicationRequests @@ -102,6 +104,22 @@ namespace AZ //! @param handler the event handler to signal. virtual void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) = 0; + //! Registers an event handler that will be signalled whenever an entity is added. + //! @param handler the event handler to signal. + virtual void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) = 0; + + //! Registers an event handler that will be signalled whenever an entity is removed. + //! @param handler the event handler to signal. + virtual void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) = 0; + + //! Signals that the provided entity has been activated. + //! @param entity the entity being activated. + virtual void SignalEntityActivated(AZ::Entity* entity) = 0; + + //! Signals that the provided entity has been deactivated. + //! @param entity the entity being deactivated. + virtual void SignalEntityDeactivated(AZ::Entity* entity) = 0; + //! Adds an entity to the application's registry. //! Calling Init() on an entity automatically performs this operation. //! @param entity A pointer to the entity to add to the application's registry. diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index b18474e428..656fc5938f 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -216,12 +216,14 @@ namespace AZ EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityActivated, m_id); + AZ::Interface::Get()->SignalEntityActivated(this); } void Entity::Deactivate() { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore); + AZ::Interface::Get()->SignalEntityDeactivated(this); EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id); diff --git a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp index 6c142975e0..b19d4c7071 100644 --- a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp @@ -126,7 +126,7 @@ namespace AZ char buffer[MaxLogBufferSize]; const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args); - buffer[AZStd::min(length, MaxLogBufferSize - 2)] = '\n'; + //buffer[AZStd::min(length, MaxLogBufferSize - 2)] = '\n'; buffer[AZStd::min(length + 1, MaxLogBufferSize - 1)] = '\0'; switch (level) diff --git a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h index e15071f56c..873bb5ad22 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h @@ -33,6 +33,10 @@ namespace UnitTest MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&)); diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 687aee8aa4..0e2b67addd 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -49,9 +49,13 @@ namespace UnitTest // ComponentApplicationBus AZ::ComponentApplication* GetApplication() override { return nullptr; } void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} + void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override {} void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override {} - void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {} + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {} + void SignalEntityActivated(AZ::Entity* entity) override {} + void SignalEntityDeactivated(AZ::Entity* entity) override {} bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index 35cf17c2e0..c1ce9f3d03 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1232,6 +1232,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(Entity*) override { return false; } bool RemoveEntity(Entity*) override { return false; } bool DeleteEntity(const EntityId&) override { return false; } @@ -1252,6 +1256,7 @@ namespace UnitTest m_serializeContext.reset(aznew AZ::SerializeContext()); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); @@ -1270,6 +1275,7 @@ namespace UnitTest AZ::AllocatorInstance::Destroy(); AZ::AllocatorInstance::Destroy(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); } diff --git a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp index 999013fdf8..461d578e28 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.cpp @@ -93,6 +93,8 @@ namespace AzFramework InitContext(); GameEntityContextRequestBus::Handler::BusConnect(); + + m_entityVisibilityBoundsUnionSystem.Connect(); } //========================================================================= @@ -100,6 +102,8 @@ namespace AzFramework //========================================================================= void GameEntityContextComponent::Deactivate() { + m_entityVisibilityBoundsUnionSystem.Disconnect(); + GameEntityContextRequestBus::Handler::BusDisconnect(); DestroyContext(); diff --git a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h index 3f15027ac7..7e75ffffa6 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/GameEntityContextComponent.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "EntityContext.h" @@ -90,6 +91,9 @@ namespace AzFramework { required.push_back(AZ_CRC("SliceSystemService", 0x1a5b7aad)); } + + private: + AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp b/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp index 1d55ec9711..c9d43b5446 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp +++ b/Code/Framework/AzFramework/AzFramework/Render/Intersector.cpp @@ -138,7 +138,8 @@ namespace AzFramework "Implementers of IntersectionRequestBus must also implement BoundsRequestBus to ensure valid " "bounds are returned"); - m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entityId) }); + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entity) }); } m_dirtyEntities.clear(); diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h index 65c62c7e64..3ffe9990df 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include @@ -27,7 +28,8 @@ namespace AZ namespace AzFramework { //! Implemented by components that provide bounds for use with various systems. - class BoundsRequests : public AZ::ComponentBus + class BoundsRequests + : public AZ::ComponentBus { public: static void Reflect(AZ::ReflectContext* context); @@ -37,6 +39,7 @@ namespace AzFramework //! more than one component may be providing a bound. It isn't guaranteed which bound //! will be returned by a single call to GetWorldBounds. virtual AZ::Aabb GetWorldBounds() = 0; + //! Returns an axis aligned bounding box in local space. //! @note It is preferred to use CalculateEntityLocalBoundsUnion in the general case as //! more than one component may be providing a bound. It isn't guaranteed which bound @@ -46,17 +49,15 @@ namespace AzFramework protected: ~BoundsRequests() = default; }; - using BoundsRequestBus = AZ::EBus; //! Returns a union of all local Aabbs provided by components implementing the BoundsRequestBus. //! @note It is preferred to call this function as opposed to GetLocalBounds directly as more than one //! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned. - inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::EntityId entityId) + inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::Entity* entity) { AZ::EBusReduceResult aabbResult(AZ::Aabb::CreateNull()); - BoundsRequestBus::EventResult( - aabbResult, entityId, &BoundsRequestBus::Events::GetLocalBounds); + BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetLocalBounds); if (aabbResult.value.IsValid()) { @@ -69,18 +70,18 @@ namespace AzFramework //! Returns a union of all world Aabbs provided by components implementing the BoundsRequestBus. //! @note It is preferred to call this function as opposed to GetWorldBounds directly as more than one //! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned. - inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::EntityId entityId) + inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::Entity* entity) { AZ::EBusReduceResult aabbResult(AZ::Aabb::CreateNull()); - BoundsRequestBus::EventResult(aabbResult, entityId, &BoundsRequestBus::Events::GetWorldBounds); + BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetWorldBounds); if (aabbResult.value.IsValid()) { return aabbResult.value; } - AZ::Vector3 worldTranslation = AZ::Vector3::CreateZero(); - AZ::TransformBus::EventResult(worldTranslation, entityId, &AZ::TransformBus::Events::GetWorldTranslation); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Vector3 worldTranslation = transformInterface->GetWorldTranslation(); return AZ::Aabb::CreateCenterHalfExtents(worldTranslation, AZ::Vector3(0.5f)); } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h index 4424cbcf60..99c575e3c9 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h @@ -23,9 +23,11 @@ namespace AzFramework { //! Provides an interface to retrieve and update the union of all Aabbs on a single Entity. //! @note This will be the combination/union of all individual Component Aabbs. - class EntityBoundsUnionRequests : public AZ::EBusTraits + class IEntityBoundsUnion { public: + AZ_RTTI(IEntityBoundsUnion, "{106968DD-43C0-478E-8045-523E0BF5D0F5}"); + //! Requests the cached union of component Aabbs to be recalculated as one may have changed. //! @note This is used to drive event driven updates to the visibility system. virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0; @@ -39,8 +41,16 @@ namespace AzFramework virtual void ProcessEntityBoundsUnionRequests() = 0; protected: - ~EntityBoundsUnionRequests() = default; + virtual ~IEntityBoundsUnion() = default; }; - using EntityBoundsUnionRequestBus = AZ::EBus; + // EBus wrapper for ScriptCanvas + class IEntityBoundsUnionTraits + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + }; + using IEntityBoundsUnionRequestBus = AZ::EBus; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp index e9b0d4609e..c03ab8b78d 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp @@ -17,69 +17,69 @@ namespace AzFramework { + EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem() + : m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); }) + , m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); }) + { + ; + } + void EntityVisibilityBoundsUnionSystem::Connect() { - EntityBoundsUnionRequestBus::Handler::BusConnect(); + AZ::Interface::Register(this); + IEntityBoundsUnionRequestBus::Handler::BusConnect(); AZ::TransformNotificationBus::Router::BusRouterConnect(); - AZ::EntitySystemBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); + + AZ::Interface::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler); + AZ::Interface::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler); } void EntityVisibilityBoundsUnionSystem::Disconnect() { AZ::TickBus::Handler::BusDisconnect(); - AZ::EntitySystemBus::Handler::BusDisconnect(); + IEntityBoundsUnionRequestBus::Handler::BusDisconnect(); AZ::TransformNotificationBus::Router::BusRouterDisconnect(); - EntityBoundsUnionRequestBus::Handler::BusDisconnect(); + AZ::Interface::Unregister(this); } - static void SetUserDataEntityId(VisibilityEntry& visibilityEntry, const AZ::EntityId entityId) - { - static_assert( - sizeof(AZ::EntityId) <= sizeof(visibilityEntry.m_userData), "Ensure EntityId fits into m_userData"); - - visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity; - - std::memcpy(&visibilityEntry.m_userData, &entityId, sizeof(AZ::EntityId)); - } - - void EntityVisibilityBoundsUnionSystem::OnEntityActivated(const AZ::EntityId& entityId) + void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); // ignore any entity that might activate which does not have a TransformComponent - if (!AZ::TransformBus::HasHandlers(entityId)) + if (entity->GetTransform() == nullptr) { return; } - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it == m_entityVisibilityBoundsUnionInstanceMapping.end()) { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Vector3 entityPosition = transformInterface->GetWorldTranslation(); EntityVisibilityBoundsUnionInstance instance; - instance.m_worldTransform = worldFromLocal; - instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId); - SetUserDataEntityId(instance.m_visibilityEntry, entityId); + instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity); + instance.m_visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity; + instance.m_visibilityEntry.m_userData = static_cast(entity); - auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({entityId, instance}); - UpdateVisibilitySystem(next_it.first->second); + auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({ entity, instance }); + UpdateVisibilitySystem(entity, next_it.first->second); } } - void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(const AZ::EntityId& entityId) + void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); - // ignore any entity that might deactivate which does not have a TransformComponent - if (!AZ::TransformBus::HasHandlers(entityId)) + // ignore any entity that might activate which does not have a TransformComponent + if (entity->GetTransform() == nullptr) { return; } - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { if (IVisibilitySystem* visibilitySystem = AZ::Interface::Get()) @@ -90,7 +90,7 @@ namespace AzFramework } } - void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance) + void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); @@ -98,8 +98,8 @@ namespace AzFramework { // note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb // there will be some wasted space but it should be sufficient for the visibility system - const AZ::Aabb worldEntityBoundsUnion = - localEntityBoundsUnions.GetTransformedAabb(instance.m_worldTransform); + AZ::TransformInterface* transformInterface = entity->GetTransform(); + const AZ::Aabb worldEntityBoundsUnion = localEntityBoundsUnions.GetTransformedAabb(transformInterface->GetWorldTM()); IVisibilitySystem* visibilitySystem = AZ::Interface::Get(); if (visibilitySystem && !worldEntityBoundsUnion.IsClose(instance.m_visibilityEntry.m_boundingVolume)) { @@ -111,19 +111,27 @@ namespace AzFramework void EntityVisibilityBoundsUnionSystem::RefreshEntityLocalBoundsUnion(const AZ::EntityId entityId) { - // track entities that need their bounds union to be recalculated - m_entityIdsBoundsDirty.insert(entityId); + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (entity != nullptr) + { + // track entities that need their bounds union to be recalculated + m_entityBoundsDirty.insert(entity); + } } AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityLocalBoundsUnion(const AZ::EntityId entityId) const { - // if the EntityId is not found in the mapping then return a null Aabb, this is to mimic - // as closely as possible the behavior of an individual GetLocalBounds call to an Entity that - // had been deleted (there would be no response, leaving the default value assigned) - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); - instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (entity != nullptr) { - return instance_it->second.m_localEntityBoundsUnion; + // if the entity is not found in the mapping then return a null Aabb, this is to mimic + // as closely as possible the behavior of an individual GetLocalBounds call to an Entity that + // had been deleted (there would be no response, leaving the default value assigned) + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); + instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) + { + return instance_it->second.m_localEntityBoundsUnion; + } } return AZ::Aabb::CreateNull(); @@ -134,45 +142,32 @@ namespace AzFramework AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); // iterate over all entities whose bounds changed and recalculate them - for (const auto& entityId : m_entityIdsBoundsDirty) + for (const auto& entity : m_entityBoundsDirty) { - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { - instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId); - } - } - - auto allDirtyEntityIds = m_entityIdsTransformDirty; - allDirtyEntityIds.insert(m_entityIdsBoundsDirty.begin(), m_entityIdsBoundsDirty.end()); - - for (const auto& dirtyEntityId : allDirtyEntityIds) - { - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(dirtyEntityId); - instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) - { - UpdateVisibilitySystem(instance_it->second); + instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity); + UpdateVisibilitySystem(entity, instance_it->second); } } // clear dirty entities once the visibility system has been updated - m_entityIdsBoundsDirty.clear(); - m_entityIdsTransformDirty.clear(); + m_entityBoundsDirty.clear(); } - void EntityVisibilityBoundsUnionSystem::OnTransformChanged( - [[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) + void EntityVisibilityBoundsUnionSystem::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId(); - m_entityIdsTransformDirty.insert(entityId); + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); // update the world transform of the visibility bounds union - if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId); + if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) { - instance_it->second.m_worldTransform = world; + UpdateVisibilitySystem(entity, instance_it->second); } } diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h index 56d6ba9670..27304a57b1 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h @@ -23,12 +23,13 @@ namespace AzFramework { //! Provide a unified hook between entities and the visibility system. class EntityVisibilityBoundsUnionSystem - : public EntityBoundsUnionRequestBus::Handler - , private AZ::EntitySystemBus::Handler + : public IEntityBoundsUnionRequestBus::Handler , private AZ::TransformNotificationBus::Router , private AZ::TickBus::Handler { public: + EntityVisibilityBoundsUnionSystem(); + void Connect(); void Disconnect(); @@ -40,30 +41,29 @@ namespace AzFramework private: struct EntityVisibilityBoundsUnionInstance { - AZ::Transform m_worldTransform = AZ::Transform::CreateIdentity(); //!< The world transform of the Entity. - AZ::Aabb m_localEntityBoundsUnion = - AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space. + AZ::Aabb m_localEntityBoundsUnion = AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space. VisibilityEntry m_visibilityEntry; //!< Hook into the IVisibilitySystem interface. }; - using UniqueEntityIds = AZStd::unordered_set; + using UniqueEntities = AZStd::set; using EntityVisibilityBoundsUnionInstanceMapping = - AZStd::unordered_map; + AZStd::unordered_map; + + void OnEntityActivated(AZ::Entity* entity); + void OnEntityDeactivated(AZ::Entity* entity); // TickBus overrides ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - // EntitySystemBus overrides ... - void OnEntityActivated(const AZ::EntityId& entityId) override; - void OnEntityDeactivated(const AZ::EntityId& entityId) override; - // TransformNotificationBus overrides ... void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; - void UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance); + void UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance); EntityVisibilityBoundsUnionInstanceMapping m_entityVisibilityBoundsUnionInstanceMapping; - UniqueEntityIds m_entityIdsBoundsDirty; - UniqueEntityIds m_entityIdsTransformDirty; + UniqueEntities m_entityBoundsDirty; + + AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler; + AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp index fd119c8199..3d3d4bc65b 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityQuery.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,7 @@ namespace AzFramework octreeDebug.m_nodeBounds.push_back(nodeData.m_bounds); } + visibleEntityIdsOut.reserve(visibleEntityIdsOut.size() + nodeData.m_entries.size()); for (const auto* visibilityEntry : nodeData.m_entries) { if (ed_visibility_showDebug) @@ -88,8 +90,7 @@ namespace AzFramework octreeDebug.m_entryAabbsInFrustum.push_back(visibilityEntry->m_boundingVolume); } - AZ::EntityId entityId; - std::memcpy(&entityId, &visibilityEntry->m_userData, sizeof(AZ::EntityId)); + AZ::EntityId entityId = static_cast(visibilityEntry->m_userData)->GetId(); visibleEntityIdsOut.push_back(entityId); } }); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp index 44c8487272..5237e7adf6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp @@ -190,7 +190,7 @@ namespace AzToolsFramework EditorLegacyGameModeNotificationBus::Handler::BusConnect(); - m_entityVisibilityBoundsUnionSystem.Connect(); + //m_entityVisibilityBoundsUnionSystem.Connect(); } @@ -199,7 +199,7 @@ namespace AzToolsFramework //========================================================================= void EditorEntityContextComponent::Deactivate() { - m_entityVisibilityBoundsUnionSystem.Disconnect(); + //m_entityVisibilityBoundsUnionSystem.Disconnect(); EditorLegacyGameModeNotificationBus::Handler::BusDisconnect(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h index 9a9a2dcff0..fb3276b5ac 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h @@ -189,7 +189,7 @@ namespace AzToolsFramework AZ::ComponentTypeList m_requiredEditorComponentTypes; //! Edit time visibility management integrating entities with the IVisibilitySystem. - AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; + //AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; bool m_isLegacySliceService; UndoSystem::UndoCacheInterface* m_undoCacheInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 7ce11e5957..459d3022ad 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ - +#pragma optimize ("", off) #include "AzToolsFramework_precompiled.h" #include "TransformComponent.h" @@ -261,6 +261,7 @@ namespace AzToolsFramework AZ::TransformNotificationBus::Event( GetEntityId(), &TransformNotification::OnTransformChanged, localTM, worldTM); + m_transformChangedEvent.Signal(localTM, worldTM); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index f3abc70fba..5fd814367c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -68,6 +68,7 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); AzFramework::EntityDebugDisplayEventBus::Event( entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, viewportInfo, debugDisplay); @@ -84,10 +85,9 @@ namespace AzToolsFramework if (ed_visibility_showAggregateEntityTransformedLocalBounds) { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::Transform worldFromLocal = entity->GetTransform()->GetWorldTM(); - if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entityId); localAabb.IsValid()) + if (const AZ::Aabb localAabb = AzFramework::CalculateEntityLocalBoundsUnion(entity); localAabb.IsValid()) { const AZ::Aabb worldAabb = localAabb.GetTransformedAabb(worldFromLocal); debugDisplay.SetColor(AZ::Colors::Turquoise); @@ -97,7 +97,7 @@ namespace AzToolsFramework if (ed_visibility_showAggregateEntityWorldBounds) { - if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entityId); worldAabb.IsValid()) + if (const AZ::Aabb worldAabb = AzFramework::CalculateEntityWorldBoundsUnion(entity); worldAabb.IsValid()) { debugDisplay.SetColor(AZ::Colors::Magenta); debugDisplay.DrawWireBox(worldAabb.GetMin(), worldAabb.GetMax()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp index 95095bd3c8..f3eac5ad18 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp @@ -13,7 +13,9 @@ #include "EditorSelectionUtil.h" #include +#include #include +#include #include #include #include @@ -28,7 +30,8 @@ namespace AzToolsFramework { if (Centered(pivot)) { - if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entityId); + const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); + if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entity); localBound.IsValid()) { return localBound.GetCenter(); diff --git a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp index 0b059594be..39b2d069e6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ - +#pragma optimize("", off) #include #include #include @@ -62,8 +62,8 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative y-axis moved just back from the origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -101,8 +101,8 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative x-axis moved along the x-axis and tilted slightly down AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -143,15 +143,15 @@ namespace UnitTest SetupRowOfEntities(AZ::Vector3::CreateAxisX(-20.0f), AZ::Vector3::CreateAxisX(2.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); const AZ::EntityId entityIdToMove = m_editorEntityIds[10]; AZ::TransformBus::Event( entityIdToMove, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3::CreateAxisZ(100.0f)); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the negative y-axis moved just back from the origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -241,8 +241,8 @@ namespace UnitTest { m_localAabb = localAabb; - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); } TEST_F(EditorVisibilityFixture, UpdatedBoundsIntersectingFrustumAddsVisibleEntity) @@ -264,8 +264,8 @@ namespace UnitTest entityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(40.0f, -3.0f, 20.0f)); // request the entity union bounds system to update - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); // create default camera looking down the positive x-axis moved to position offset from world origin AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( @@ -288,8 +288,8 @@ namespace UnitTest testBoundComponent->ChangeBounds(AZ::Aabb::CreateFromMinMax(AZ::Vector3(-2.5f), AZ::Vector3(2.5f))); // perform an 'update' of the visibility system - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); + AzFramework::IEntityBoundsUnionRequestBus::Broadcast( + &AzFramework::IEntityBoundsUnionRequestBus::Events::ProcessEntityBoundsUnionRequests); entityVisibilityQuery.UpdateVisibility(cameraState); diff --git a/Code/Framework/Tests/ComponentAddRemove.cpp b/Code/Framework/Tests/ComponentAddRemove.cpp index e47b69c977..3815188269 100644 --- a/Code/Framework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/Tests/ComponentAddRemove.cpp @@ -1100,6 +1100,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const ComponentDescriptor*) override {} void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override {} void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {} + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {} + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {} + void SignalEntityActivated(AZ::Entity* entity) override {} + void SignalEntityDeactivated(AZ::Entity* entity) override {} bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const EntityId&) override { return true; } @@ -1125,6 +1129,7 @@ namespace UnitTest AllocatorsFixture::SetUp(); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); m_serializeContext.reset(aznew AZ::SerializeContext(true, true)); Entity::Reflect(m_serializeContext.get()); @@ -1139,6 +1144,7 @@ namespace UnitTest m_descriptors.set_capacity(0); m_serializeContext.reset(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); AllocatorsFixture::TearDown(); diff --git a/Code/Framework/Tests/NetBindingMocks.h b/Code/Framework/Tests/NetBindingMocks.h index 3f280383f5..2af748e29c 100644 --- a/Code/Framework/Tests/NetBindingMocks.h +++ b/Code/Framework/Tests/NetBindingMocks.h @@ -278,6 +278,10 @@ namespace UnitTest MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&)); diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp index cb23e73b0e..b658df7ffa 100644 --- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp @@ -363,6 +363,10 @@ namespace AZ MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*)); MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&)); MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&)); + MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&)); + MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*)); + MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*)); MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*)); MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&)); MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&)); diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index 51fe236171..dc746bae23 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -577,6 +577,10 @@ namespace AWSClientAuthUnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index c1795f7217..2a26c2a0ae 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -105,6 +105,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(Entity*) override { return false; } bool RemoveEntity(Entity*) override { return false; } bool DeleteEntity(const EntityId&) override { return false; } @@ -134,6 +138,7 @@ namespace UnitTest // Adding this handler to allow utility functions access the serialize context ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); AZ::AllocatorInstance::Create(); AZ::AllocatorInstance::Create(); @@ -212,6 +217,7 @@ namespace UnitTest AZ::AllocatorInstance::Destroy(); AZ::AllocatorInstance::Destroy(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); AllocatorsBase::TeardownAllocator(); } diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp index 657657d07d..36598fb29f 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.cpp @@ -75,6 +75,7 @@ namespace UnitTest // Adding this handler to allow utility functions access the serialize context ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); // Startup default local FileIO (hits OSAllocator) if not already setup. if (IO::FileIOBase::GetInstance() == nullptr) @@ -113,6 +114,7 @@ namespace UnitTest delete IO::FileIOBase::GetInstance(); IO::FileIOBase::SetInstance(nullptr); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); m_jsonRegistrationContext->EnableRemoveReflection(); diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index 51282642aa..fbc39f6a40 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -41,6 +41,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index f400a171c5..55a226956a 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -38,6 +38,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 9d2196de2b..ecd60be009 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -295,8 +295,7 @@ namespace AZ m_configuration.m_modelAsset = modelAsset; MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model); MaterialReceiverNotificationBus::Event(m_entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 005e9a6ff5..8edac1f109 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -231,8 +231,7 @@ namespace AZ m_configuration.m_outerLength = dimensions.GetY(); m_configuration.m_outerHeight = dimensions.GetZ(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); // clamp the inner extents to the outer extents m_configuration.m_innerWidth = AZStd::min(m_configuration.m_innerWidth, m_configuration.m_outerWidth); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index f8b638efaf..d0116452b7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -82,8 +82,7 @@ namespace AZ // Update RenderActorInstance local bounding box m_localAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetStaticBasedAABB().GetMin(), m_actorInstance->GetStaticBasedAABB().GetMax()); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, m_entityId); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } AZ::Aabb AtomActorInstance:: GetWorldBounds() diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index e3de713b3c..94feb36e80 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -513,8 +513,7 @@ namespace EMotionFX { m_renderActorInstance->OnTick(deltaTime); m_renderActorInstance->UpdateBounds(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); // Optimization: Set the actor instance invisible when character is out of camera view. This will stop the joint transforms update, except the root joint. // Calling it after the bounds on the render actor updated. diff --git a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp index 2555d1a6af..c386766eef 100644 --- a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp +++ b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp @@ -759,7 +759,7 @@ CODE //------------------------------------------------------------------------- // [SECTION] INCLUDES //------------------------------------------------------------------------- - +#pragma optimize("", off) #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif @@ -7117,9 +7117,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. - const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); - IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); - IM_UNUSED(key_mod_flags); + //const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); + //IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + //IM_UNUSED(key_mod_flags); // Recover from errors //ErrorCheckEndFrameRecover(); diff --git a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp b/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp index 1bef8e2fa3..d60dc20ef9 100644 --- a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp @@ -125,6 +125,10 @@ protected: void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/LmbrCentral/Code/Source/Rendering/MeshComponent.cpp b/Gems/LmbrCentral/Code/Source/Rendering/MeshComponent.cpp index 0ee72b62cf..4bef29fb52 100644 --- a/Gems/LmbrCentral/Code/Source/Rendering/MeshComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Rendering/MeshComponent.cpp @@ -319,8 +319,7 @@ namespace LmbrCentral UpdateWorldTransform(transformHandler->GetWorldTM()); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); m_modificationHelper.Connect(id); } @@ -536,8 +535,7 @@ namespace LmbrCentral m_localBoundingBox.Add(m_statObj->GetAABB()); } - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); UpdateWorldBoundingBox(); } diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp index df5c65e07c..cd21b1e855 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorBaseShapeComponent.cpp @@ -12,7 +12,7 @@ #include "LmbrCentral_precompiled.h" #include "EditorBaseShapeComponent.h" - +#include #include #include @@ -214,8 +214,7 @@ namespace LmbrCentral { if (changeReason == ShapeChangeReasons::ShapeChanged) { - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } } } // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp index 42c35b8cd9..71ed89a180 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorSplineComponent.cpp @@ -378,9 +378,7 @@ namespace LmbrCentral { SplineComponentNotificationBus::Event( GetEntityId(), &SplineComponentNotificationBus::Events::OnSplineChanged); - - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } AZ::SplinePtr EditorSplineComponent::GetSpline() diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 925f7512da..27cc326ff9 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -304,6 +304,10 @@ public: void UnregisterComponentDescriptor(const ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } @@ -329,6 +333,7 @@ public: m_serializeContext = aznew SerializeContext(true, true); ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); m_sliceDescriptor = SliceComponent::CreateDescriptor(); m_mockAssetDescriptor = MockAssetRefComponent::CreateDescriptor(); @@ -358,6 +363,7 @@ public: void TearDown() override { m_catalog->DisableCatalog(); + AZ::Interface::Unregister(this); ComponentApplicationBus::Handler::BusDisconnect(); Data::AssetManager::Destroy(); diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index f6aa6b2de9..22f777a149 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -146,11 +146,11 @@ namespace Multiplayer } ); + NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker(); + // Add all the neighbors for (AzFramework::VisibilityEntry* visEntry : gatheredEntries) { - // TODO: Discard entities that don't have a NetBindComponent - //if (mp_ControlledFilteredEntityComponent && mp_ControlledFilteredEntityComponent->IsEntityFiltered(iterator.Get())) //{ // continue; @@ -162,8 +162,12 @@ namespace Multiplayer const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition); const float priority = (gatherDistanceSquared > 0.0f) ? 1.0f / gatherDistanceSquared : 0.0f; AZ::Entity* entity = static_cast(visEntry->m_userData); - NetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); - AddEntityToReplicationSet(entityHandle, priority, gatherDistanceSquared); + NetBindComponent* entryNetBindComponent = entity->template FindComponent(); + if (entryNetBindComponent != nullptr) + { + NetworkEntityHandle entityHandle(entryNetBindComponent, networkEntityTracker); + AddEntityToReplicationSet(entityHandle, priority, gatherDistanceSquared); + } } // Add in Autonomous Entities diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index ca7e2a3583..8545424ca7 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -82,6 +82,10 @@ protected: void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } + void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity* entity) override { } + void SignalEntityDeactivated(AZ::Entity* entity) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/Visibility/Code/Source/EditorOccluderAreaComponent.cpp b/Gems/Visibility/Code/Source/EditorOccluderAreaComponent.cpp index 9a88799a31..0521836e48 100644 --- a/Gems/Visibility/Code/Source/EditorOccluderAreaComponent.cpp +++ b/Gems/Visibility/Code/Source/EditorOccluderAreaComponent.cpp @@ -245,8 +245,7 @@ namespace Visibility const AZStd::string name = AZStd::string("OcclArea_") + GetEntity()->GetName(); GetIEditor()->Get3DEngine()->UpdateVisArea(m_area, &verts[0], verts.size(), name.c_str(), info, false); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } } diff --git a/Gems/Visibility/Code/Source/EditorPortalComponent.cpp b/Gems/Visibility/Code/Source/EditorPortalComponent.cpp index 4e1b07991a..18f3f2fdb0 100644 --- a/Gems/Visibility/Code/Source/EditorPortalComponent.cpp +++ b/Gems/Visibility/Code/Source/EditorPortalComponent.cpp @@ -455,8 +455,7 @@ namespace Visibility GetIEditor()->Get3DEngine()->UpdateVisArea(m_area, &verts[0], verts.size(), name.c_str(), info, true); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } } diff --git a/Gems/Visibility/Code/Source/EditorVisAreaComponent.cpp b/Gems/Visibility/Code/Source/EditorVisAreaComponent.cpp index 48045d9023..ddd18e2da8 100644 --- a/Gems/Visibility/Code/Source/EditorVisAreaComponent.cpp +++ b/Gems/Visibility/Code/Source/EditorVisAreaComponent.cpp @@ -349,8 +349,7 @@ namespace Visibility GetIEditor()->Get3DEngine()->UpdateVisArea(m_area, &points[0], points.size(), name.c_str(), info, true); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); } } } diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index e88b4ce686..d4ab543404 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -414,8 +414,7 @@ namespace WhiteBox m_localAabb.reset(); m_faces.reset(); - AzFramework::EntityBoundsUnionRequestBus::Broadcast( - &AzFramework::EntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId()); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(GetEntityId()); // must have been created in Activate or have had the Entity made visible again if (m_renderMesh.has_value()) From d5ad5d95965266ecc1cca41d11537b7206afff81 Mon Sep 17 00:00:00 2001 From: karlberg Date: Mon, 3 May 2021 21:20:40 -0700 Subject: [PATCH 02/18] Removing some more ebus dependencies within the vis system --- .../AzCore/AzCore/Component/Component.cpp | 3 ++- Code/Framework/AzCore/AzCore/Component/Entity.cpp | 2 +- .../AzFramework/Components/TransformComponent.cpp | 10 ++++++---- .../AzFramework/Visibility/EntityBoundsUnionBus.h | 4 ++++ .../EntityVisibilityBoundsUnionSystem.cpp | 7 +------ .../Visibility/EntityVisibilityBoundsUnionSystem.h | 5 +---- .../ToolsComponents/TransformComponent.cpp | 14 ++++++++------ 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Component.cpp b/Code/Framework/AzCore/AzCore/Component/Component.cpp index f1e8aa1fb0..f336b9e1a1 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Component.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -173,7 +174,7 @@ namespace AZ //========================================================================= void ComponentDescriptor::ReleaseDescriptor() { - EBUS_EVENT(ComponentApplicationBus, UnregisterComponentDescriptor, this); + AZ::Interface::Get()->UnregisterComponentDescriptor(this); delete this; } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index 656fc5938f..6796bccb2b 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -112,7 +112,7 @@ namespace AZ { EBUS_EVENT(EntitySystemBus, OnEntityDestruction, m_id); EBUS_EVENT_ID(m_id, EntityBus, OnEntityDestruction, m_id); - EBUS_EVENT(ComponentApplicationBus, RemoveEntity, this); + AZ::Interface::Get()->RemoveEntity(this); m_stateEvent.Signal(State::Init, State::Destroying); } diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 910d6749af..866f0cc6d2 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -11,10 +11,12 @@ */ #include +#include #include #include #include #include +#include #include #include @@ -694,8 +696,7 @@ namespace AzFramework } #endif - AZ::Entity* parentEntity = nullptr; - EBUS_EVENT_RESULT(parentEntity, AZ::ComponentApplicationBus, FindEntity, parentEntityId); + AZ::Entity* parentEntity = AZ::Interface::Get()->FindEntity(parentEntityId); AZ_Assert(parentEntity, "We expect to have a parent entity associated with the provided parent's entity Id."); if (parentEntity) { @@ -744,8 +745,7 @@ namespace AzFramework m_parentId = parentId; if (m_parentId.IsValid()) { - AZ::Entity* parentEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId); + AZ::Entity* parentEntity = AZ::Interface::Get()->FindEntity(m_parentId); m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active); m_onNewParentKeepWorldTM = isKeepWorldTM; @@ -832,6 +832,8 @@ namespace AzFramework EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM); m_transformChangedEvent.Signal(m_localTM, m_worldTM); + + AZ::Interface::Get()->OnTransformUpdated(GetEntity()); } void TransformComponent::ComputeWorldTM() diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h index 99c575e3c9..b607759260 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h @@ -40,6 +40,10 @@ namespace AzFramework //! also be called explicitly (e.g. For testing purposes). virtual void ProcessEntityBoundsUnionRequests() = 0; + //! Notifies the EntityBoundsUnion system that an entities transform has been modified. + //! @param entity the entity whose transform has been modified. + virtual void OnTransformUpdated(AZ::Entity* entity) = 0; + protected: virtual ~IEntityBoundsUnion() = default; }; diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp index c03ab8b78d..f9c24b82db 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp @@ -28,7 +28,6 @@ namespace AzFramework { AZ::Interface::Register(this); IEntityBoundsUnionRequestBus::Handler::BusConnect(); - AZ::TransformNotificationBus::Router::BusRouterConnect(); AZ::TickBus::Handler::BusConnect(); AZ::Interface::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler); @@ -39,7 +38,6 @@ namespace AzFramework { AZ::TickBus::Handler::BusDisconnect(); IEntityBoundsUnionRequestBus::Handler::BusDisconnect(); - AZ::TransformNotificationBus::Router::BusRouterDisconnect(); AZ::Interface::Unregister(this); } @@ -156,13 +154,10 @@ namespace AzFramework m_entityBoundsDirty.clear(); } - void EntityVisibilityBoundsUnionSystem::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) + void EntityVisibilityBoundsUnionSystem::OnTransformUpdated(AZ::Entity* entity) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); - const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId(); - AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - // update the world transform of the visibility bounds union if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity); instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end()) diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h index 27304a57b1..808f834ebc 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h @@ -24,7 +24,6 @@ namespace AzFramework //! Provide a unified hook between entities and the visibility system. class EntityVisibilityBoundsUnionSystem : public IEntityBoundsUnionRequestBus::Handler - , private AZ::TransformNotificationBus::Router , private AZ::TickBus::Handler { public: @@ -37,6 +36,7 @@ namespace AzFramework void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override; AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override; void ProcessEntityBoundsUnionRequests() override; + void OnTransformUpdated(AZ::Entity* entity) override; private: struct EntityVisibilityBoundsUnionInstance @@ -55,9 +55,6 @@ namespace AzFramework // TickBus overrides ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - // TransformNotificationBus overrides ... - void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; - void UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance); EntityVisibilityBoundsUnionInstanceMapping m_entityVisibilityBoundsUnionInstanceMapping; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 459d3022ad..81c9ebaaec 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#pragma optimize ("", off) + #include "AzToolsFramework_precompiled.h" #include "TransformComponent.h" @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -262,6 +263,8 @@ namespace AzToolsFramework AZ::TransformNotificationBus::Event( GetEntityId(), &TransformNotification::OnTransformChanged, localTM, worldTM); m_transformChangedEvent.Signal(localTM, worldTM); + + AZ::Interface::Get()->OnTransformUpdated(GetEntity()); } } @@ -930,15 +933,14 @@ namespace AzToolsFramework { return nullptr; } - - AZ::Entity* pEntity = nullptr; - EBUS_EVENT_RESULT(pEntity, AZ::ComponentApplicationBus, FindEntity, otherEntityId); - if (!pEntity) + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(otherEntityId); + if (!entity) { return nullptr; } - return pEntity->FindComponent(); + return entity->FindComponent(); } AZ::TransformInterface* TransformComponent::GetParent() From bbe3fcfdd9416c52317879151464c793326f14cf Mon Sep 17 00:00:00 2001 From: karlberg Date: Tue, 4 May 2021 08:49:35 -0700 Subject: [PATCH 03/18] Cleans up some debug code --- .../AzCore/AzCore/Console/LoggerSystemComponent.cpp | 1 - .../Entity/EditorEntityContextComponent.cpp | 5 ----- .../Entity/EditorEntityContextComponent.h | 2 -- .../Tests/Visibility/EditorVisibilityTests.cpp | 2 +- Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp | 8 ++++---- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp index b19d4c7071..de29edc3b0 100644 --- a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp @@ -126,7 +126,6 @@ namespace AZ char buffer[MaxLogBufferSize]; const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args); - //buffer[AZStd::min(length, MaxLogBufferSize - 2)] = '\n'; buffer[AZStd::min(length + 1, MaxLogBufferSize - 1)] = '\0'; switch (level) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp index 5237e7adf6..041a0f4195 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp @@ -189,9 +189,6 @@ namespace AzToolsFramework SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect(); EditorLegacyGameModeNotificationBus::Handler::BusConnect(); - - //m_entityVisibilityBoundsUnionSystem.Connect(); - } //========================================================================= @@ -199,8 +196,6 @@ namespace AzToolsFramework //========================================================================= void EditorEntityContextComponent::Deactivate() { - //m_entityVisibilityBoundsUnionSystem.Disconnect(); - EditorLegacyGameModeNotificationBus::Handler::BusDisconnect(); SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h index d59792752b..92c7f84703 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h @@ -189,8 +189,6 @@ namespace AzToolsFramework //! EditorEntityContextRequestBus::Events::AddRequiredComponents() AZ::ComponentTypeList m_requiredEditorComponentTypes; - //! Edit time visibility management integrating entities with the IVisibilitySystem. - //AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem; bool m_isLegacySliceService; UndoSystem::UndoCacheInterface* m_undoCacheInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp index 39b2d069e6..a7aeee5660 100644 --- a/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Visibility/EditorVisibilityTests.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#pragma optimize("", off) + #include #include #include diff --git a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp index c386766eef..2555d1a6af 100644 --- a/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp +++ b/Gems/ImGui/External/ImGui/v1.82/imgui/imgui.cpp @@ -759,7 +759,7 @@ CODE //------------------------------------------------------------------------- // [SECTION] INCLUDES //------------------------------------------------------------------------- -#pragma optimize("", off) + #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif @@ -7117,9 +7117,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. - //const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); - //IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); - //IM_UNUSED(key_mod_flags); + const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); + IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mod_flags); // Recover from errors //ErrorCheckEndFrameRecover(); From a1fe8fe4193f343e08329e692b202050cd506478 Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 5 May 2021 20:07:16 -0700 Subject: [PATCH 04/18] Ported the local prediction player controller component --- .../Serialization/StringifySerializer.cpp | 162 +++++ .../Serialization/StringifySerializer.h | 80 +++ .../AzNetworking/aznetworking_files.cmake | 2 + .../IConnectionData.h | 10 +- .../EntityDomains => Include}/IEntityDomain.h | 2 +- Gems/Multiplayer/Code/Include/IMultiplayer.h | 11 +- .../IMultiplayerComponentInput.h | 0 .../INetworkEntityManager.h | 2 +- .../NetworkTime => Include}/INetworkTime.h | 66 +- .../IReplicationWindow.h | 2 +- .../Code/Include/MultiplayerTypes.h | 8 + .../NetworkEntityHandle.h | 2 +- .../NetworkEntityHandle.inl | 0 .../AutoGen/AutoComponentTypes_Source.jinja | 2 +- .../Source/AutoGen/AutoComponent_Common.jinja | 4 +- .../Source/AutoGen/AutoComponent_Header.jinja | 6 +- .../Source/AutoGen/AutoComponent_Source.jinja | 11 +- ...tionPlayerInputComponent.AutoComponent.xml | 4 +- .../AutoGen/Multiplayer.AutoPackets.xml | 2 + .../LocalPredictionPlayerInputComponent.cpp | 562 +++++++++++++++++- .../LocalPredictionPlayerInputComponent.h | 88 ++- .../Source/Components/MultiplayerComponent.h | 4 +- .../Source/Components/MultiplayerController.h | 2 +- .../Source/Components/NetBindComponent.cpp | 34 +- .../Code/Source/Components/NetBindComponent.h | 23 +- .../ClientToServerConnectionData.cpp | 2 +- .../ClientToServerConnectionData.h | 5 +- .../ServerToClientConnectionData.cpp | 6 +- .../ServerToClientConnectionData.h | 7 +- .../EntityDomains/FullOwnershipEntityDomain.h | 2 +- .../Source/MultiplayerSystemComponent.cpp | 20 +- .../Code/Source/MultiplayerSystemComponent.h | 6 +- .../EntityReplicationManager.cpp | 34 +- .../EntityReplicationManager.h | 30 +- .../EntityReplication/EntityReplicator.cpp | 6 +- .../EntityReplication/EntityReplicator.h | 4 +- .../NetworkEntity/INetworkEntityDomain.h | 41 -- .../NetworkEntityAuthorityTracker.cpp | 2 +- .../NetworkEntity/NetworkEntityHandle.cpp | 2 +- .../NetworkEntity/NetworkEntityManager.cpp | 2 +- .../NetworkEntity/NetworkEntityManager.h | 4 +- .../NetworkEntity/NetworkEntityTracker.cpp | 2 +- .../NetworkEntity/NetworkEntityTracker.h | 2 +- .../Code/Source/NetworkInput/NetworkInput.cpp | 37 +- .../Code/Source/NetworkInput/NetworkInput.h | 22 +- .../Source/NetworkInput/NetworkInputChild.cpp | 2 +- .../NetworkInput/NetworkInputVector.cpp | 2 +- .../Source/NetworkInput/NetworkInputVector.h | 2 +- .../Code/Source/NetworkTime/NetworkTime.cpp | 38 +- .../Code/Source/NetworkTime/NetworkTime.h | 22 +- .../Source/NetworkTime/RewindableObject.h | 10 +- .../Source/NetworkTime/RewindableObject.inl | 14 +- .../NullReplicationWindow.h | 2 +- .../ServerToClientReplicationWindow.h | 6 +- Gems/Multiplayer/Code/multiplayer_files.cmake | 16 +- 55 files changed, 1164 insertions(+), 275 deletions(-) create mode 100644 Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp create mode 100644 Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h rename Gems/Multiplayer/Code/{Source/ConnectionData => Include}/IConnectionData.h (87%) rename Gems/Multiplayer/Code/{Source/EntityDomains => Include}/IEntityDomain.h (97%) rename Gems/Multiplayer/Code/{Source/NetworkInput => Include}/IMultiplayerComponentInput.h (100%) rename Gems/Multiplayer/Code/{Source/NetworkEntity => Include}/INetworkEntityManager.h (99%) rename Gems/Multiplayer/Code/{Source/NetworkTime => Include}/INetworkTime.h (50%) rename Gems/Multiplayer/Code/{Source/ReplicationWindows => Include}/IReplicationWindow.h (96%) rename Gems/Multiplayer/Code/{Source/NetworkEntity => Include}/NetworkEntityHandle.h (99%) rename Gems/Multiplayer/Code/{Source/NetworkEntity => Include}/NetworkEntityHandle.inl (100%) delete mode 100644 Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp new file mode 100644 index 0000000000..bcd09f274c --- /dev/null +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp @@ -0,0 +1,162 @@ +/* +* 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. +* +*/ + +#include + +namespace AzNetworking +{ + StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator) + : m_delimeter(delimeter) + , m_outputFieldNames(outputFieldNames) + , m_separator(seperator) + { + ; + } + + const AZStd::string& StringifySerializer::GetString() const + { + return m_string; + } + + const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const + { + return m_map; + } + + SerializerMode StringifySerializer::GetSerializerMode() const + { + return SerializerMode::ReadFromObject; + } + + bool StringifySerializer::Serialize(bool& value, const char* name) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(char& value, const char* name, char, char) + { + const int val = value; // Print chars as integers + return ProcessData(name, val); + } + + bool StringifySerializer::Serialize(int8_t& value, const char* name, int8_t, int8_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int16_t& value, const char* name, int16_t, int16_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int32_t& value, const char* name, int32_t, int32_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(int64_t& value, const char* name, int64_t, int64_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint8_t& value, const char* name, uint8_t, uint8_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint16_t& value, const char* name, uint16_t, uint16_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint32_t& value, const char* name, uint32_t, uint32_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(uint64_t& value, const char* name, uint64_t, uint64_t) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(float& value, const char* name, float, float) + { + return ProcessData(name, value); + } + + bool StringifySerializer::Serialize(double& value, const char* name, double, double) + { + return ProcessData(name, value); + } + + bool StringifySerializer::SerializeBytes(uint8_t* buffer, uint32_t, bool isString, uint32_t&, const char* name) + { + if (isString) + { + AZ::CVarFixedString value = reinterpret_cast(buffer); + return ProcessData(name, value); + } + return false; + } + + bool StringifySerializer::BeginObject(const char* name, const char*) + { + m_prefixSizeStack.push_back(m_prefix.size()); + m_prefix += name; + m_prefix += "."; + return true; + } + + bool StringifySerializer::EndObject(const char*, const char*) + { + m_prefix.resize(m_prefixSizeStack.back()); + m_prefixSizeStack.pop_back(); + return true; + } + + const uint8_t* StringifySerializer::GetBuffer() const + { + return nullptr; + } + + uint32_t StringifySerializer::GetCapacity() const + { + return 0; + } + + uint32_t StringifySerializer::GetSize() const + { + return 0; + } + + template + bool StringifySerializer::ProcessData(const char* name, const T& value) + { + // Only add delimeters after we have processed at least one element + if (!m_string.empty()) + { + m_string += m_delimeter; + } + + if (m_outputFieldNames) + { + m_string += m_prefix; + m_string += name; + m_string += m_separator; + } + + AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value); + m_string += string.c_str(); + m_map[m_prefix + name] = string.c_str(); + return true; + } +} diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h new file mode 100644 index 0000000000..aa8c58ae60 --- /dev/null +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h @@ -0,0 +1,80 @@ +/* +* 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 + +namespace AzNetworking +{ + // StringifySerializer + // Generate a debug string of a serializable object + class StringifySerializer + : public ISerializer + { + public: + + using StringMap = AZStd::map; + + StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "="); + + // GetString + // After serializing objects, get the serialized values as a single string + const AZStd::string& GetString() const; + + // GetValueMap + // After serializing objects, get the serialized values as key value pairs + const StringMap& GetValueMap() const; + + // ISerializer interfaces + SerializerMode GetSerializerMode() const override; + bool Serialize(bool& value, const char* name) override; + bool Serialize(char& value, const char* name, char minValue, char maxValue) override; + bool Serialize(int8_t& value, const char* name, int8_t minValue, int8_t maxValue) override; + bool Serialize(int16_t& value, const char* name, int16_t minValue, int16_t maxValue) override; + bool Serialize(int32_t& value, const char* name, int32_t minValue, int32_t maxValue) override; + bool Serialize(int64_t& value, const char* name, int64_t minValue, int64_t maxValue) override; + bool Serialize(uint8_t& value, const char* name, uint8_t minValue, uint8_t maxValue) override; + bool Serialize(uint16_t& value, const char* name, uint16_t minValue, uint16_t maxValue) override; + bool Serialize(uint32_t& value, const char* name, uint32_t minValue, uint32_t maxValue) override; + bool Serialize(uint64_t& value, const char* name, uint64_t minValue, uint64_t maxValue) override; + bool Serialize(float& value, const char* name, float minValue, float maxValue) override; + bool Serialize(double& value, const char* name, double minValue, double maxValue) override; + bool SerializeBytes(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name) override; + bool BeginObject(const char* name, const char* typeName) override; + bool EndObject(const char* name, const char* typeName) override; + + const uint8_t* GetBuffer() const override; + uint32_t GetCapacity() const override; + uint32_t GetSize() const override; + void ClearTrackedChangesFlag() override {} + bool GetTrackedChangesFlag() const override { return false; } + // ISerializer interfaces + + private: + + template + bool ProcessData(const char* name, const T& value); + + private: + + char m_delimeter; + bool m_outputFieldNames = true; + + StringMap m_map; + AZStd::string m_string; + AZStd::string m_prefix; + AZStd::string m_separator; + AZStd::deque m_prefixSizeStack; + }; +} diff --git a/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake b/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake index ea84f3fdc9..b8d488a1e4 100644 --- a/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake +++ b/Code/Framework/AzNetworking/AzNetworking/aznetworking_files.cmake @@ -65,6 +65,8 @@ set(FILES Serialization/NetworkOutputSerializer.cpp Serialization/NetworkOutputSerializer.h Serialization/NetworkOutputSerializer.inl + Serialization/StringifySerializer.cpp + Serialization/StringifySerializer.h Serialization/TrackChangedSerializer.h Serialization/TrackChangedSerializer.inl TcpTransport/TcpConnection.cpp diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h b/Gems/Multiplayer/Code/Include/IConnectionData.h similarity index 87% rename from Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h rename to Gems/Multiplayer/Code/Include/IConnectionData.h index a7ceffd289..dcc2c940ef 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/IConnectionData.h +++ b/Gems/Multiplayer/Code/Include/IConnectionData.h @@ -12,11 +12,13 @@ #pragma once -#include -#include +#include +#include namespace Multiplayer { + class EntityReplicationManager; + enum class ConnectionDataType { ClientToServer, @@ -42,8 +44,8 @@ namespace Multiplayer virtual EntityReplicationManager& GetReplicationManager() = 0; //! Creates and manages sending updates to the remote endpoint. - //! @param serverGameTimeMs current server game time in milliseconds - virtual void Update(AZ::TimeMs serverGameTimeMs) = 0; + //! @param hostTimeMs current server game time in milliseconds + virtual void Update(AZ::TimeMs hostTimeMs) = 0; //! Returns whether update messages can be sent to the connection. //! @return true if update messages can be sent diff --git a/Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h b/Gems/Multiplayer/Code/Include/IEntityDomain.h similarity index 97% rename from Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h rename to Gems/Multiplayer/Code/Include/IEntityDomain.h index 56ec24618d..6571797d05 100644 --- a/Gems/Multiplayer/Code/Source/EntityDomains/IEntityDomain.h +++ b/Gems/Multiplayer/Code/Include/IEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Include/IMultiplayer.h b/Gems/Multiplayer/Code/Include/IMultiplayer.h index 47d0d5a05e..039b86b2a6 100644 --- a/Gems/Multiplayer/Code/Include/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/IMultiplayer.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AzNetworking @@ -56,7 +57,7 @@ namespace Multiplayer //! Gets the type of Agent this IMultiplayer impl represents //! @return The type of agents represented - virtual MultiplayerAgentType GetAgentType() = 0; + virtual MultiplayerAgentType GetAgentType() const = 0; //! Sets the type of this Multiplayer connection and calls any related callback //! @param state The state of this connection @@ -78,6 +79,14 @@ namespace Multiplayer //! @param readyForEntityUpdates Ready for entity updates or not virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0; + //! Returns the current server time in milliseconds. + //! This can be one of three possible values: + //! 1. On the host outside of rewind scope, this will return the latest application elapsed time in ms. + //! 2. On the host within rewind scope, this will return the rewound time in ms. + //! 3. On the client, this will return the most recently replicated server time in ms. + //! @return the current server time in milliseconds + virtual AZ::TimeMs GetCurrentHostTimeMs() const = 0; + //! Returns the gem name associated with the provided component index. //! @param netComponentId the componentId to return the gem name of //! @return the name of the gem that contains the requested component diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/IMultiplayerComponentInput.h b/Gems/Multiplayer/Code/Include/IMultiplayerComponentInput.h similarity index 100% rename from Gems/Multiplayer/Code/Source/NetworkInput/IMultiplayerComponentInput.h rename to Gems/Multiplayer/Code/Include/IMultiplayerComponentInput.h diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/INetworkEntityManager.h similarity index 99% rename from Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h rename to Gems/Multiplayer/Code/Include/INetworkEntityManager.h index 891a4606ea..d9b611ece0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/INetworkEntityManager.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/INetworkTime.h similarity index 50% rename from Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h rename to Gems/Multiplayer/Code/Include/INetworkTime.h index 703fba5fb5..5346a0e0d0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/INetworkTime.h +++ b/Gems/Multiplayer/Code/Include/INetworkTime.h @@ -14,13 +14,10 @@ #include #include +#include namespace Multiplayer { - //! This is a strong typedef for representing the number of application frames since application start. - AZ_TYPE_SAFE_INTEGRAL(ApplicationFrameId, uint32_t); - static constexpr ApplicationFrameId InvalidApplicationFrameId = ApplicationFrameId{0xFFFFFFFF}; - //! @class INetworkTime //! @brief This is an AZ::Interface<> for managing multiplayer specific time related operations. class INetworkTime @@ -31,30 +28,24 @@ namespace Multiplayer INetworkTime() = default; virtual ~INetworkTime() = default; - //! Converts from an ApplicationFrameId to a corresponding TimeMs. - //! @param frameId the ApplicationFrameId to convert to a TimeMs - //! @return the TimeMs that corresponds to the provided ApplicationFrameId - virtual AZ::TimeMs ConvertFrameIdToTimeMs(ApplicationFrameId frameId) const = 0; + //! Returns true if the host timeMs and frameId has been temporarily altered. + //! @return true if the host timeMs and frameId has been altered, false otherwise + virtual bool IsTimeRewound() const = 0; - //! Converts from a TimeMs to an ApplicationFrameId. - //! @param timeMs the TimeMs to convert to an ApplicationFrameId - //! @return the ApplicationFrameId that corresponds to the provided TimeMs - virtual ApplicationFrameId ConvertTimeMsToFrameId(AZ::TimeMs timeMs) const = 0; + //! Retrieves the hosts current frameId (may be rewound on the server during backward reconciliation). + //! @return the hosts current frameId + virtual HostFrameId GetHostFrameId() const = 0; - //! Returns true if the application frameId has been temporarily altered. - //! @return true if the application frameId has been altered, false otherwise - virtual bool IsApplicationFrameIdRewound() const = 0; + //! Retrieves the unaltered hosts current frameId. + //! @return the hosts current frameId, unaltered by any scoped time instance + virtual HostFrameId GetUnalteredHostFrameId() const = 0; - //! Retrieves the applications current frameId (may be rewound on the server during backward reconciliation). - //! @return the applications current frameId - virtual ApplicationFrameId GetApplicationFrameId() const = 0; + //! Increments the hosts current frameId. + virtual void IncrementHostFrameId() = 0; - //! Retrieves the unaltered applications current frameId. - //! @return the applications current frameId, unaltered by any scoped time instance - virtual ApplicationFrameId GetUnalteredApplicationFrameId() const = 0; - - //! Increments the applications current frameId. - virtual void IncrementApplicationFrameId() = 0; + //! Retrieves the hosts current timeMs (may be rewound on the server during backward reconciliation). + //! @return the hosts current timeMs + virtual AZ::TimeMs GetHostTimeMs() const = 0; //! Synchronizes rewindable entity state for the current application time. virtual void SyncRewindableEntityState() = 0; @@ -66,14 +57,15 @@ namespace Multiplayer //! Get the controlling connection that may be currently altering global game time. //! Note this abstraction is required at a relatively high level to allow for 'don't rewind the shooter' semantics - //! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered applicationFrameId - //! @return the ApplicationFrameId taking into account the provided rewinding connectionId - virtual ApplicationFrameId GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0; + //! @param rewindConnectionId if this parameter matches the current rewindConnectionId, it will return the unaltered hostFrameId + //! @return the HostFrameId taking into account the provided rewinding connectionId + virtual HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0; - //! Alters the current ApplicationFrameId and binds that alteration to the provided ConnectionId. - //! @param frameId the new ApplicationFrameId to use + //! Alters the current HostFrameId and binds that alteration to the provided ConnectionId. + //! @param frameId the new HostFrameId to use + //! @param timeMs the new HostTimeMs to use //! @param rewindConnectionId the rewinding ConnectionId - virtual void AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) = 0; + virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0; AZ_DISABLE_COPY_MOVE(INetworkTime); }; @@ -93,22 +85,22 @@ namespace Multiplayer class ScopedAlterTime final { public: - inline ScopedAlterTime(ApplicationFrameId frameId, AzNetworking::ConnectionId connectionId) + inline ScopedAlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId connectionId) { INetworkTime* time = AZ::Interface::Get(); - m_previousApplicationFrameId = time->GetApplicationFrameId(); + m_previousHostFrameId = time->GetHostFrameId(); + m_previousHostTimeMs = time->GetHostTimeMs(); m_previousRewindConnectionId = time->GetRewindingConnectionId(); - time->AlterApplicationFrameId(frameId, connectionId); + time->AlterTime(frameId, timeMs, connectionId); } inline ~ScopedAlterTime() { INetworkTime* time = AZ::Interface::Get(); - time->AlterApplicationFrameId(m_previousApplicationFrameId, m_previousRewindConnectionId); + time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId); } private: - ApplicationFrameId m_previousApplicationFrameId = InvalidApplicationFrameId; + HostFrameId m_previousHostFrameId = InvalidHostFrameId; + AZ::TimeMs m_previousHostTimeMs = AZ::TimeMs{ 0 }; AzNetworking::ConnectionId m_previousRewindConnectionId = AzNetworking::InvalidConnectionId; }; } - -AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ApplicationFrameId); diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h b/Gems/Multiplayer/Code/Include/IReplicationWindow.h similarity index 96% rename from Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h rename to Gems/Multiplayer/Code/Include/IReplicationWindow.h index 27c14f8049..eb34a2f87d 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/IReplicationWindow.h +++ b/Gems/Multiplayer/Code/Include/IReplicationWindow.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Include/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/MultiplayerTypes.h index 5c690958b5..1bee9867e3 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/MultiplayerTypes.h @@ -36,6 +36,12 @@ namespace Multiplayer AZ_TYPE_SAFE_INTEGRAL(PropertyIndex, uint16_t); AZ_TYPE_SAFE_INTEGRAL(RpcIndex, uint16_t); + AZ_TYPE_SAFE_INTEGRAL(ClientInputId, uint16_t); + + //! This is a strong typedef for representing the number of application frames since application start. + AZ_TYPE_SAFE_INTEGRAL(HostFrameId, uint32_t); + static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ 0xFFFFFFFF }; + using LongNetworkString = AZ::CVarFixedString; using ReliabilityType = AzNetworking::ReliabilityType; @@ -122,3 +128,5 @@ AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::NetEntityId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::NetComponentId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::PropertyIndex); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::RpcIndex); +AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ClientInputId); +AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostFrameId); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.h similarity index 99% rename from Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h rename to Gems/Multiplayer/Code/Include/NetworkEntityHandle.h index 0f84ed4477..9b8546ef2c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.h +++ b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.h @@ -138,4 +138,4 @@ namespace Multiplayer }; } -#include "Source/NetworkEntity/NetworkEntityHandle.inl" +#include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.inl b/Gems/Multiplayer/Code/Include/NetworkEntityHandle.inl similarity index 100% rename from Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.inl rename to Gems/Multiplayer/Code/Include/NetworkEntityHandle.inl diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja index 57375b39f2..2bae618d94 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja @@ -1,6 +1,6 @@ #include #include -#include +#include {% for Component in dataFiles %} {% set ComponentDerived = Component.attrib['OverrideComponent']|booleanTrue %} {% set ControllerDerived = Component.attrib['OverrideController']|booleanTrue %} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index fb7de56bb1..d211b933c5 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -170,12 +170,12 @@ AZ::Event<{{ Property.attrib['Type'] }}> {% set PropertyName = UpperFirst(Property.attrib['Name']) %} {{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} {% if IsOverride %} -void Handle{{ PropertyName }}({{ ', '.join(paramDefines) }}) override {} +void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) override {} {% else %} //! {{ PropertyName }} Handler //! {{ Property.attrib['Description'] }} //! HandleOn {{ HandleOn }} -virtual void Handle{{ PropertyName }}({{ ', '.join(paramDefines) }}) = 0; +virtual void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) = 0; {% endif %} {% endmacro %} {# diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 14a68cddf1..faaa009e34 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -221,11 +221,11 @@ AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] } #include #include #include -#include +#include +#include #include #include #include -#include #include #include {% call(Include) AutoComponentMacros.ParseIncludes(Component) %} @@ -435,7 +435,7 @@ namespace {{ Component.attrib['Namespace'] }} //! MultiplayerComponent interface //! @{ NetComponentId GetNetComponentId() const override; - bool HandleRpcMessage(Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override; + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override; bool SerializeStateDeltaMessage(Multiplayer::ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) override; void NotifyStateDeltaChanges(Multiplayer::ReplicationRecord& replicationRecord) override; bool HasController() const override; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index fb802541ce..6e54ec3d58 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -336,7 +336,7 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); } {% if Property.attrib['IsReliable']|booleanTrue %} {# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #} @@ -350,7 +350,7 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); } {% else %} Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); @@ -1251,7 +1251,12 @@ namespace {{ Component.attrib['Namespace'] }} #pragma warning(push) #pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels - bool {{ ComponentBaseName }}::HandleRpcMessage([[maybe_unused]] Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& message) + bool {{ ComponentBaseName }}::HandleRpcMessage + ( + [[maybe_unused]] AzNetworking::IConnection* invokingConnection, + [[maybe_unused]] Multiplayer::NetEntityRole remoteRole, + Multiplayer::NetworkEntityRpcMessage& message + ) { const {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure rpcType = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure>(message.GetRpcIndex()); switch (rpcType) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index 4eaf7ff0fb..45dfc43e49 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -16,11 +16,11 @@ - + - + diff --git a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml index 5de466899c..daf55c3d92 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml @@ -3,6 +3,7 @@ + @@ -35,6 +36,7 @@ + diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 24986148c4..56192c96d7 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -13,9 +13,41 @@ #include #include #include +#include +#include +#include +#include +#include namespace Multiplayer { + AZ_CVAR(AZ::TimeMs, cl_InputRateMs, AZ::TimeMs{ 33 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Rate at which to sample and process client inputs"); + AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay"); +#ifndef _RELEASE + AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat"); +#endif + + AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs"); + AZ_CVAR(double, sv_MaxBankTimeWindowSec, 0.2, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum bank time we allow before we start rejecting autonomous proxy move inputs due to anticheat kicking in"); + AZ_CVAR(double, sv_BankTimeDecay, 0.025, nullptr, AZ::ConsoleFunctorFlags::Null, "Amount to decay bank time by, in case of more permanent shifts in client latency"); + AZ_CVAR(AZ::TimeMs, sv_MinCorrectionTimeMs, AZ::TimeMs{ 100 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time to wait between sending out corrections in order to avoid flooding corrections on high-latency connections"); + AZ_CVAR(AZ::TimeMs, sv_InputUpdateTimeMs, AZ::TimeMs{ 5 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time between component updates"); + + // Debug helper functions + AZStd::string GetInputString(NetworkInput& input) + { + AzNetworking::StringifySerializer serializer(',', false); + input.Serialize(serializer); + return serializer.GetString(); + } + + AZStd::string GetCorrectionDataString(NetBindComponent* netBindComponent) + { + AzNetworking::StringifySerializer serializer(',', false); + netBindComponent->SerializeEntityCorrection(serializer); + return serializer.GetString(); + } + void LocalPredictionPlayerInputComponent::LocalPredictionPlayerInputComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -27,30 +59,544 @@ namespace Multiplayer LocalPredictionPlayerInputComponentBase::Reflect(context); } + void LocalPredictionPlayerInputComponent::OnInit() + { + ; + } + + void LocalPredictionPlayerInputComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + + void LocalPredictionPlayerInputComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + + LocalPredictionPlayerInputComponentController::LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent) + : LocalPredictionPlayerInputComponentControllerBase(parent) + , m_autonomousUpdateEvent([this]() { UpdateAutonomous(m_autonomousUpdateEvent.TimeInQueueMs()); }, AZ::Name("AutonomousUpdate Event")) + , m_updateBankedTimeEvent([this]() { UpdateBankedTime(m_updateBankedTimeEvent.TimeInQueueMs()); }, AZ::Name("BankTimeUpdate Event")) + , m_migrateStartHandler([this](ClientInputId migratedInputId) { OnMigrateStart(migratedInputId); }) + , m_migrateEndHandler([this]() { OnMigrateEnd(); }) + { + if (GetNetEntityRole() == NetEntityRole::Autonomous) + { + m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true); + parent.GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler); + parent.GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler); + } + } + + void LocalPredictionPlayerInputComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + if (entityIsMigrating == EntityIsMigrating::True) + { + m_allowMigrateClientInput = true; + m_serverMigrateFrameId = AZ::Interface::Get()->GetHostFrameId(); + } + } + + void LocalPredictionPlayerInputComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + ; + } + void LocalPredictionPlayerInputComponentController::HandleSendClientInput ( - [[maybe_unused]] const Multiplayer::NetworkInputVector& inputArray, - [[maybe_unused]] const uint32_t& stateHash, + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputVector& inputArray, + const AZ::HashValue64& stateHash, [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState ) { - ; + // After receiving the first input from the client, start the update event to check for slow hacking + if (!m_updateBankedTimeEvent.IsScheduled()) + { + m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true); + } + + if (invokingConnection == nullptr) + { + // Discard any input messages that were locally dispatched or sent by disconnected clients + return; + } + + const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs(); + const double clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + m_lastInputReceivedTimeMs = currentTimeMs; + + // Keep track of last inputs received, also allows us to update frame ids + m_lastInputReceived = inputArray; + + // Figure out which index from the input array we want + // we start at the oldest input that has not been processed + int32_t inputArrayIndex = -1; + for (int32_t i = NetworkInputVector::MaxElements - 1; i >= 0; --i) + { + // Find an input that is newer than the last one we processed + if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId()) + { + inputArrayIndex = i; + break; + } + } + + if (inputArrayIndex < 0) + { + AZLOG + ( + NET_Prediction, + "Discarding old or out of order move input (current: %u, received %u)", + aznumeric_cast(GetLastInputId()), + aznumeric_cast(m_lastInputReceived[0].GetClientInputId()) + ); + return; + } + + bool lostInput = false; + if (GetLastInputId() < inputArray.GetPreviousInputId()) + { + // last move id processed is older than the previous input id, we missed some input packets + lostInput = true; + } + + SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration + + while (inputArrayIndex >= 0) + { + NetworkInput& input = m_lastInputReceived[inputArrayIndex]; + + // Anticheat, if we're receiving too many inputs, and fall outside our variable latency input window + // Discard move input events, client may be speed hacking + if (m_clientBankedTime < sv_MaxBankTimeWindowSec) + { + m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary + + { + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec)); + } + if (lostInput) + { + AZLOG(NET_Prediction, "InputLost InputId=%u", input.GetClientInputId()); + } + else + { + AZLOG(NET_Prediction, "Processed InputId=%u", input.GetClientInputId()); + } + } + else + { + AZLOG(NET_Prediction, "Dropped InputId=%u", input.GetClientInputId()); + } + --inputArrayIndex; + } + + if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs)) + { + m_lastCorrectionSentTimeMs = currentTimeMs; + + AzNetworking::HashSerializer hashSerializer; + GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); + + const AZ::HashValue64 localAuthorityHash = hashSerializer.GetHash(); + + if (stateHash != localAuthorityHash) + { + // Produce correction for client + AzNetworking::PacketEncodingBuffer correction; + correction.Resize(correction.GetCapacity()); + AzNetworking::NetworkInputSerializer serializer(correction.GetBuffer(), correction.GetCapacity()); + + // only deserialize if we have data (for client/server profile/debug mismatches) + if (correction.GetSize() > 0) + { + GetNetBindComponent()->SerializeEntityCorrection(serializer); + } + + correction.Resize(serializer.GetSize()); + + // Send correction + SendClientInputCorrection(GetLastInputId(), correction); + +#ifdef _DEBUG + // In debug, show which states caused the correction + AZStd::string clientStateString; + AZStd::string serverStateString; + { + // Write in client state + AzNetworking::NetworkOutputSerializer clientStateSerializer(clientState.GetBuffer(), clientState.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(clientStateSerializer); + + // Read out state values + AzNetworking::StringifySerializer clientValues; + GetNetBindComponent()->SerializeEntityCorrection(clientValues); + + // Restore server state + AzNetworking::NetworkOutputSerializer serverStateSerializer(correction.GetBuffer(), correction.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(serverStateSerializer); + + // Read out state values + AzNetworking::StringifySerializer serverValues; + GetNetBindComponent()->SerializeEntityCorrection(serverValues); + + AZStd::map> mapComparison; + // put the server value in the first part of the pair + for (const auto& pair : serverValues.GetValueMap()) + { + mapComparison[pair.first].first = pair.second; + } + // put the client value in the second part of the pair + for (const auto& pair : clientValues.GetValueMap()) + { + mapComparison[pair.first].second = pair.second; + } + + bool firstIt = true; + for (const auto& mapPair : mapComparison) + { + if (mapPair.second.first != mapPair.second.second) + { + if (!firstIt) + { + clientStateString += ","; + serverStateString += ","; + } + firstIt = false; + + AZStd::string clientValue = mapPair.second.second.empty() ? "" : mapPair.second.second; + AZStd::string serverValue = mapPair.second.first.empty() ? "" : mapPair.second.first; + clientStateString += mapPair.first + "=" + clientValue; + serverStateString += mapPair.first + "=" + serverValue; + } + } + } +#else + const AZStd::string clientStateString = "available in debug only"; + const AZStd::string serverStateString = "available in debug only"; +#endif + + AZLOG_ERROR("** Autonomous proxy desync detected! ** clientState=[%s], serverState=[%s]", clientStateString.c_str(), serverStateString.c_str()); + } + } } void LocalPredictionPlayerInputComponentController::HandleSendMigrateClientInput ( - [[maybe_unused]] const Multiplayer::MigrateNetworkInputVector& inputArray + AzNetworking::IConnection* invokingConnection, + const Multiplayer::MigrateNetworkInputVector& inputArray ) { - ; + if (!m_allowMigrateClientInput) + { + AZLOG_ERROR("Client attempting to SendMigrateClientInput message when server was not expecting it. This may be an attempt to cheat"); + return; + } + + // We only allow the client to send this message exactly once, when the component has been migrated + // Any further processing of these messages from the client would be exploitable + m_allowMigrateClientInput = false; + + if (invokingConnection == nullptr) + { + // Discard any input migration messages that were locally dispatched or sent by disconnected clients + return; + } + + const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + + // Copy array so we can modify input ids + MigrateNetworkInputVector inputArrayCopy = inputArray; + + for (uint32_t i = 0; i < inputArrayCopy.GetSize(); ++i) + { + NetworkInput& input = inputArrayCopy[i]; + + ++ModifyLastInputId(); + input.SetClientInputId(GetLastInputId()); + + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); + + AZLOG + ( + NET_Prediction, + "Migrated InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + // Don't bother checking for corrections here, the next regular input will trigger any corrections if necessary + // Also don't bother with any cheat detection here, because the input array is limited in size and at most and can only be sent once + // So this highly constrains anything a malicious client can do + } } void LocalPredictionPlayerInputComponentController::HandleSendClientInputCorrection ( - [[maybe_unused]] const Multiplayer::ClientInputId& inputId, - [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& correction + AzNetworking::IConnection* invokingConnection, + const Multiplayer::ClientInputId& inputId, + const AzNetworking::PacketEncodingBuffer& correction ) { - ; + AZ_Assert(inputId <= m_clientInputId, "Invalid correction frame id, correction is for a move the client has not yet submitted to the server"); + if (inputId > m_clientInputId) + { + AZLOG_ERROR("Discarding correction for non-existent move, correction represents a move we haven't sent to the server yet"); + return; + } + + if (inputId <= m_lastCorrectionInputId) + { + AZLOG(NET_Prediction, "Discarding old correction for client frame %u", aznumeric_cast(inputId)); + return; + } + + m_lastCorrectionInputId = inputId; + + // Apply the correction + AzNetworking::TrackChangedSerializer serializer(correction.GetBuffer(), correction.GetSize()); + GetNetBindComponent()->SerializeEntityCorrection(serializer); + m_correctionEvent.Signal(); + + AZLOG + ( + NET_Prediction, + "Corrected InputId=%d - o=[%s]", + aznumeric_cast(m_lastCorrectionInputId), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + const uint32_t inputHistorySize = m_inputHistory.Size(); + const uint32_t historicalDelta = aznumeric_cast(m_clientInputId - inputId); // Do not replay the move we just corrected, that was already processed by the server + + // If this correction is for a move outside our input history window, just start replaying from the oldest move we have available + const uint32_t startReplayIndex = (inputHistorySize > historicalDelta) ? (inputHistorySize - historicalDelta) : 0; + + // Flag that we are replaying inputs + struct ScopedReplayingInput + { + ScopedReplayingInput(LocalPredictionPlayerInputComponentController* instance) + : m_instance(instance) + { + m_instance->m_replayingInput = true; + } + ~ScopedReplayingInput() + { + m_instance->m_replayingInput = false; + } + LocalPredictionPlayerInputComponentController* m_instance; + }; + ScopedReplayingInput markReplayingInput(this); + + const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + for (uint32_t replayIndex = startReplayIndex; replayIndex < inputHistorySize; ++replayIndex) + { + // Reprocess the input for this frame + NetworkInput& input = m_inputHistory[replayIndex]; + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); + + AZLOG + ( + NET_Prediction, + "Replayed InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + } + } + + bool LocalPredictionPlayerInputComponentController::IsReplayingInput() const + { + return m_replayingInput; + } + + bool LocalPredictionPlayerInputComponentController::IsMigrating() const + { + return m_lastMigratedInputId != ClientInputId{ 0 }; + } + + ClientInputId LocalPredictionPlayerInputComponentController::GetLastInputId() const + { + return m_clientInputId; + } + + HostFrameId LocalPredictionPlayerInputComponentController::GetInputFrameId(const NetworkInput& input) const + { + // If the client has sent us an invalid server frame id + // this is because they are in the process of migrating from one server to another + // In this situation, use whatever the server frame id was when this component was migrated + // This will match the closest state to what the client sees + return (input.GetHostFrameId() == InvalidHostFrameId) ? m_serverMigrateFrameId : input.GetHostFrameId(); + } + + void LocalPredictionPlayerInputComponentController::CorrectionEventAddHandle(CorrectionEvent::Handler& handler) + { + handler.Connect(m_correctionEvent); + } + + void LocalPredictionPlayerInputComponentController::OnMigrateStart(ClientInputId migratedInputId) + { + m_lastMigratedInputId = migratedInputId; + } + + void LocalPredictionPlayerInputComponentController::OnMigrateEnd() + { + MigrateNetworkInputVector inputArray; + + // Roll up all inputs that the new server doesn't have and send them now + for (AZStd::size_t i = 0; i < m_inputHistory.Size(); ++i) + { + NetworkInput& input = m_inputHistory[i]; + + // New server already has these inputs + if (input.GetClientInputId() <= m_lastMigratedInputId) + { + continue; + } + + // Clear out the old server frame id + // We don't know what server frame ids to use for the new server yet, but the new server will figure out how to deal with this + input.SetHostFrameId(InvalidHostFrameId); + + // New server doesn't have these inputs + if (!inputArray.PushBack(input)) + { + break; // Reached capacity + } + } + + // Send these inputs to the server + SendMigrateClientInput(inputArray); + + // Done migrating + m_lastMigratedInputId = ClientInputId{ 0 }; + } + + void LocalPredictionPlayerInputComponentController::UpdateAutonomous(AZ::TimeMs deltaTimeMs) + { + const double deltaTime = static_cast(deltaTimeMs) / 1000.0; + const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; + +#ifndef _RELEASE + m_moveAccumulator += deltaTime * cl_DebugHackTimeMultiplier; +#else + m_moveAccumulator += deltaTime; +#endif + + const uint32_t maxClientInputs = inputRate > 0.0 ? static_cast(maxRewindHistory / inputRate) : 0; + + INetworkTime* networkTime = AZ::Interface::Get(); + IMultiplayer* multiplayer = AZ::Interface::Get(); + while (m_moveAccumulator >= inputRate) + { + m_moveAccumulator -= inputRate; + ++m_clientInputId; + + NetworkInputVector inputArray(GetEntityHandle()); + NetworkInput& input = inputArray[0]; + + input.SetClientInputId(m_clientInputId); + input.SetHostFrameId(networkTime->GetHostFrameId()); + input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs()); + + // Allow components to form the input for this frame + GetNetBindComponent()->CreateInput(input, inputRate); + + // Process the input for this frame + GetNetBindComponent()->ProcessInput(input, inputRate); + + AZLOG + ( + NET_Prediction, + "Processed InutId=%d - i=[%s] o=[%s]", + aznumeric_cast(m_clientInputId), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + + // Generate a hash based on the current client predicted states + AzNetworking::HashSerializer hashSerializer; + GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); + + // In debug, send the entire client output state to the server to make it easier to debug desync issues + AzNetworking::PacketEncodingBuffer processInputResult; +#ifdef _DEBUG + AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); + GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); + processInputResult.Resize(processInputResultSerializer.GetSize()); +#endif + + // Save this input and discard move history outside our client rewind window + m_inputHistory.PushBack(input); + while (m_inputHistory.Size() > maxClientInputs) + { + m_inputHistory.PopFront(); + } + + const size_t inputHistorySize = m_inputHistory.Size(); + + // Form the rest of the input array using the n most recent elements in the history buffer + // NOTE: inputArray[0] has already been initialized hence start at i = 1 + for (uint32_t i = 1; i < NetworkInputVector::MaxElements; ++i) + { + if (i < inputHistorySize) + { + inputArray[i] = m_inputHistory[inputHistorySize - 1 - i]; + } + else // History is too small? + { + // Plug in the most recent input + inputArray[i] = input; + } + } + + // Send the input to server (only when we are not migrating) + if (!IsMigrating()) + { + SendClientInput(inputArray, hashSerializer.GetHash(), processInputResult); + } + } + } + + void LocalPredictionPlayerInputComponentController::UpdateBankedTime(AZ::TimeMs deltaTimeMs) + { + const double deltaTime = static_cast(deltaTimeMs) / 1000.0; + const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; + + // Update banked time accumulator + m_clientBankedTime -= deltaTime; + + // Forcibly tick any clients who are too far behind our variable latency window + // Client may be slow hacking + if (m_clientBankedTime < -sv_MaxBankTimeWindowSec) + { + m_clientBankedTime = -sv_MaxBankTimeWindowSec; // clamp to boundary + + NetworkInput& input = m_lastInputReceived[0]; + { + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), AzNetworking::InvalidConnectionId); + GetNetBindComponent()->ProcessInput(input, inputRate); + } + + AZLOG + ( + NET_Prediction, + "Forced InputId=%d - i=[%s] o=[%s]", + aznumeric_cast(input.GetClientInputId()), + GetInputString(input).c_str(), + GetCorrectionDataString(GetNetBindComponent()).c_str() + ); + } + + // Decay our bank time window, in case the remote endpoint has suffered a more persistent shift in latency, this should cause the client to eventually recover + m_clientBankedTime = m_clientBankedTime * (1.0 - sv_BankTimeDecay); } } diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h index b332315799..0a4e574d65 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h @@ -13,9 +13,12 @@ #pragma once #include +#include namespace Multiplayer { + using CorrectionEvent = AZ::Event<>; + class LocalPredictionPlayerInputComponent : public LocalPredictionPlayerInputComponentBase { @@ -24,24 +27,87 @@ namespace Multiplayer static void Reflect([[maybe_unused]] AZ::ReflectContext* context); - void OnInit() override {} - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - - + void OnInit() override; + void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; }; class LocalPredictionPlayerInputComponentController : public LocalPredictionPlayerInputComponentControllerBase { public: - LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent) : LocalPredictionPlayerInputComponentControllerBase(parent) {} + LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent); - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} + void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override; - void HandleSendClientInput(const Multiplayer::NetworkInputVector& inputArray, const uint32_t& stateHash, const AzNetworking::PacketEncodingBuffer& clientState) override; - void HandleSendMigrateClientInput(const Multiplayer::MigrateNetworkInputVector& inputArray) override; - void HandleSendClientInputCorrection(const Multiplayer::ClientInputId& inputId, const AzNetworking::PacketEncodingBuffer& correction) override; + void HandleSendClientInput + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::NetworkInputVector& inputArray, + const AZ::HashValue64& stateHash, + const AzNetworking::PacketEncodingBuffer& clientState + ) override; + + void HandleSendMigrateClientInput + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::MigrateNetworkInputVector& inputArray + ) override; + + void HandleSendClientInputCorrection + ( + AzNetworking::IConnection* invokingConnection, + const Multiplayer::ClientInputId& inputId, + const AzNetworking::PacketEncodingBuffer& correction + ) override; + + //! Return true if we're currently replaying inputs after a correction. + //! If this value returns true, effects, audio, and other cosmetic triggers should be suppressed + //! @return true if we're within correction scope and replaying inputs + bool IsReplayingInput() const; + + //! Return true if we're currently migrating from one host to another. + //! @return boolean true if we're currently migrating from one host to another + bool IsMigrating() const; + + ClientInputId GetLastInputId() const; + HostFrameId GetInputFrameId(const NetworkInput& input) const; + + void CorrectionEventAddHandle(CorrectionEvent::Handler& handler); + + private: + + void OnMigrateStart(ClientInputId migratedInputId); + void OnMigrateEnd(); + void UpdateAutonomous(AZ::TimeMs deltaTimeMs); + void UpdateBankedTime(AZ::TimeMs deltaTimeMs); + + // Implicitly sorted player input history, back() is the input that corresponds to the latest client input Id + NetworkInputHistory m_inputHistory; + + // Anti-cheat accumulator for clients who purposely mess with their clock rate + NetworkInputVector m_lastInputReceived; + + AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection + AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates + + CorrectionEvent m_correctionEvent; + EntityMigrationStartEvent::Handler m_migrateStartHandler; + EntityMigrationEndEvent::Handler m_migrateEndHandler; + + double m_moveAccumulator = 0.0; + double m_clientBankedTime = 0.0; + + AZ::TimeMs m_lastInputReceivedTimeMs = AZ::TimeMs{ 0 }; + AZ::TimeMs m_lastCorrectionSentTimeMs = AZ::TimeMs{ 0 }; + + ClientInputId m_clientInputId = ClientInputId{ 0 }; + ClientInputId m_lastCorrectionInputId = ClientInputId{ 0 }; + ClientInputId m_lastMigratedInputId = ClientInputId{ 0 }; // Used to resend inputs that were queued during a migration event + HostFrameId m_serverMigrateFrameId = InvalidHostFrameId; + + bool m_replayingInput = false; // True if we're replaying inputs under a correction event (use this to suppress effects or audio) + bool m_allowMigrateClientInput = false; // True if this component was migrated, we will allow the client to send us migrated inputs (one time only) }; } diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h index 3642a55476..0f64221dde 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -69,7 +69,7 @@ namespace Multiplayer virtual NetComponentId GetNetComponentId() const = 0; - virtual bool HandleRpcMessage(NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0; + virtual bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0; virtual bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) = 0; virtual void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord) = 0; virtual bool HasController() const = 0; diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h index 9e3c7d68ab..de07e39e66 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index bb1dac5a4e..eba09734a9 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -13,10 +13,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -192,12 +192,12 @@ namespace Multiplayer return bounds; } - bool NetBindComponent::HandleRpcMessage(NetEntityRole remoteRole, NetworkEntityRpcMessage& message) + bool NetBindComponent::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message) { auto findIt = m_multiplayerComponentMap.find(message.GetComponentId()); if (findIt != m_multiplayerComponentMap.end()) { - return findIt->second->HandleRpcMessage(remoteRole, message); + return findIt->second->HandleRpcMessage(invokingConnection, remoteRole, message); } return false; } @@ -274,9 +274,19 @@ namespace Multiplayer m_localNotificationRecord.Clear(); } - void NetBindComponent::NotifyMigration(HostId remoteHostId, AzNetworking::ConnectionId connectionId) + void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId) { - m_entityMigrationEvent.Signal(m_netEntityHandle, remoteHostId, connectionId); + m_entityMigrationStartEvent.Signal(migratedInputId); + } + + void NetBindComponent::NotifyMigrationEnd() + { + m_entityMigrationEndEvent.Signal(); + } + + void NetBindComponent::NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId) + { + m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId); } void NetBindComponent::AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler) @@ -289,9 +299,19 @@ namespace Multiplayer eventHandler.Connect(m_dirtiedEvent); } - void NetBindComponent::AddEntityMigrationEventHandler(EntityMigrationEvent::Handler& eventHandler) + void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler) { - eventHandler.Connect(m_entityMigrationEvent); + eventHandler.Connect(m_entityMigrationStartEvent); + } + + void NetBindComponent::AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityMigrationEndEvent); + } + + void NetBindComponent::AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityServerMigrationEvent); } bool NetBindComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer) diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h index e992dbfd72..4a4c4d0549 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h @@ -21,8 +21,9 @@ #include #include #include -#include -#include +#include +#include +#include #include #include @@ -34,7 +35,9 @@ namespace Multiplayer using EntityStopEvent = AZ::Event; using EntityDirtiedEvent = AZ::Event<>; - using EntityMigrationEvent = AZ::Event; + using EntityMigrationStartEvent = AZ::Event; + using EntityMigrationEndEvent = AZ::Event<>; + using EntityServerMigrationEvent = AZ::Event; //! @class NetBindComponent //! @brief Component that provides net-binding to a networked entity. @@ -72,7 +75,7 @@ namespace Multiplayer void ProcessInput(NetworkInput& networkInput, float deltaTime); AZ::Aabb GetRewindBoundsForInput(const NetworkInput& networkInput, float deltaTime) const; - bool HandleRpcMessage(NetEntityRole remoteRole, NetworkEntityRpcMessage& message); + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message); bool HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges = true); RpcSendEvent& GetSendAuthorityToClientRpcEvent(); @@ -84,11 +87,15 @@ namespace Multiplayer void MarkDirty(); void NotifyLocalChanges(); - void NotifyMigration(HostId remoteHostId, AzNetworking::ConnectionId connectionId); + void NotifyMigrationStart(ClientInputId migratedInputId); + void NotifyMigrationEnd(); + void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId); void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler); void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler); - void AddEntityMigrationEventHandler(EntityMigrationEvent::Handler& eventHandler); + void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler); + void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler); + void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler); bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer); @@ -133,7 +140,9 @@ namespace Multiplayer EntityStopEvent m_entityStopEvent; EntityDirtiedEvent m_dirtiedEvent; - EntityMigrationEvent m_entityMigrationEvent; + EntityMigrationStartEvent m_entityMigrationStartEvent; + EntityMigrationEndEvent m_entityMigrationEndEvent; + EntityServerMigrationEvent m_entityServerMigrationEvent; AZ::Event<> m_onRemove; RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle; AZ::Event<>::Handler m_handleMarkedDirty; diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp index 4420e0689c..3aeaac5103 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp @@ -50,7 +50,7 @@ namespace Multiplayer return m_entityReplicationManager; } - void ClientToServerConnectionData::Update([[maybe_unused]] AZ::TimeMs serverGameTimeMs) + void ClientToServerConnectionData::Update([[maybe_unused]] AZ::TimeMs hostTimeMs) { m_entityReplicationManager.ActivatePendingEntities(); } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h index 76a809b351..b72a6aad2b 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h @@ -12,7 +12,8 @@ #pragma once -#include +#include +#include namespace Multiplayer { @@ -32,7 +33,7 @@ namespace Multiplayer ConnectionDataType GetConnectionDataType() const override; AzNetworking::IConnection* GetConnection() const override; EntityReplicationManager& GetReplicationManager() override; - void Update(AZ::TimeMs serverGameTimeMs) override; + void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; //! @} diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp index 7a7e266a38..d2440d28f4 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp @@ -35,7 +35,7 @@ namespace Multiplayer if (netBindComponent != nullptr) { netBindComponent->AddEntityStopEventHandler(m_controlledEntityRemovedHandler); - netBindComponent->AddEntityMigrationEventHandler(m_controlledEntityMigrationHandler); + netBindComponent->AddEntityServerMigrationEventHandler(m_controlledEntityMigrationHandler); } m_entityReplicationManager.SetMaxRemoteEntitiesPendingCreationCount(sv_ClientMaxRemoteEntitiesPendingCreationCount); @@ -63,7 +63,7 @@ namespace Multiplayer return m_entityReplicationManager; } - void ServerToClientConnectionData::Update(AZ::TimeMs serverGameTimeMs) + void ServerToClientConnectionData::Update(AZ::TimeMs hostTimeMs) { m_entityReplicationManager.ActivatePendingEntities(); @@ -73,7 +73,7 @@ namespace Multiplayer // potentially false if we just migrated the player, if that is the case, don't send any more updates if (netBindComponent != nullptr && (netBindComponent->GetNetEntityRole() == NetEntityRole::Authority)) { - m_entityReplicationManager.SendUpdates(serverGameTimeMs); + m_entityReplicationManager.SendUpdates(hostTimeMs); } } } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h index 7ea62b15fd..b02e6de9aa 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h @@ -12,7 +12,8 @@ #pragma once -#include +#include +#include namespace Multiplayer { @@ -33,7 +34,7 @@ namespace Multiplayer ConnectionDataType GetConnectionDataType() const override; AzNetworking::IConnection* GetConnection() const override; EntityReplicationManager& GetReplicationManager() override; - void Update(AZ::TimeMs serverGameTimeMs) override; + void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; //! @} @@ -49,7 +50,7 @@ namespace Multiplayer EntityReplicationManager m_entityReplicationManager; NetworkEntityHandle m_controlledEntity; EntityStopEvent::Handler m_controlledEntityRemovedHandler; - EntityMigrationEvent::Handler m_controlledEntityMigrationHandler; + EntityServerMigrationEvent::Handler m_controlledEntityMigrationHandler; AzNetworking::IConnection* m_connection = nullptr; bool m_canSendUpdates = false; }; diff --git a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h index 95bfc211cf..c1abbe74cd 100644 --- a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h +++ b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 03c661ab03..90d55d8b26 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -127,7 +127,7 @@ namespace Multiplayer void MultiplayerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZ::TimeMs serverGameTimeMs = AZ::GetElapsedTimeMs(); + AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs(); // Handle deferred local rpc messages that were generated during the updates m_networkEntityManager.DispatchLocalDeferredRpcMessages(); @@ -143,12 +143,12 @@ namespace Multiplayer // Send out the game state update to all connections { - auto sendNetworkUpdates = [serverGameTimeMs, &stats](IConnection& connection) + auto sendNetworkUpdates = [hostTimeMs, &stats](IConnection& connection) { if (connection.GetUserData() != nullptr) { IConnectionData* connectionData = reinterpret_cast(connection.GetUserData()); - connectionData->Update(serverGameTimeMs); + connectionData->Update(hostTimeMs); if (connectionData->GetConnectionDataType() == ConnectionDataType::ServerToClient) { stats.m_clientConnectionCount++; @@ -481,7 +481,7 @@ namespace Multiplayer } } - MultiplayerAgentType MultiplayerSystemComponent::GetAgentType() + MultiplayerAgentType MultiplayerSystemComponent::GetAgentType() const { return m_agentType; } @@ -528,6 +528,18 @@ namespace Multiplayer }); } + AZ::TimeMs MultiplayerSystemComponent::GetCurrentHostTimeMs() const + { + if (GetAgentType() == MultiplayerAgentType::Client) + { + return m_lastReplicatedHostTimeMs; + } + else // ClientServer or DedicatedServer + { + return m_networkTime.GetHostTimeMs(); + } + } + const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const { return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index f25e530b61..477745e6b5 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -84,12 +84,13 @@ namespace Multiplayer //! IMultiplayer interface //! @{ - MultiplayerAgentType GetAgentType() override; + MultiplayerAgentType GetAgentType() const override; void InitializeMultiplayer(MultiplayerAgentType state) override; void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; void SendReadyForEntityUpdates(bool readyForEntityUpdates) override; + AZ::TimeMs GetCurrentHostTimeMs() const override; const char* GetComponentGemName(NetComponentId netComponentId) const override; const char* GetComponentName(NetComponentId netComponentId) const override; const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const override; @@ -119,5 +120,8 @@ namespace Multiplayer SessionInitEvent m_initEvent; SessionShutdownEvent m_shutdownEvent; ConnectionAcquiredEvent m_connAcquiredEvent; + + AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 }; + HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index 74bdcd5cf0..1e7649f561 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -14,14 +14,14 @@ #include #include #include -#include -#include #include #include -#include #include #include +#include #include +#include +#include #include #include #include @@ -93,10 +93,10 @@ namespace Multiplayer } } - void EntityReplicationManager::SendUpdates(AZ::TimeMs serverGameTimeMs) + void EntityReplicationManager::SendUpdates(AZ::TimeMs hostTimeMs) { m_frameTimeMs = AZ::GetElapsedTimeMs(); - SendEntityUpdates(serverGameTimeMs); + SendEntityUpdates(hostTimeMs); SendEntityRpcs(m_deferredRpcMessagesReliable, true); SendEntityRpcs(m_deferredRpcMessagesUnreliable, false); @@ -118,7 +118,7 @@ namespace Multiplayer void EntityReplicationManager::SendEntityUpdatesPacketHelper ( - AZ::TimeMs serverGameTimeMs, + AZ::TimeMs hostTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection @@ -127,7 +127,8 @@ namespace Multiplayer uint32_t pendingPacketSize = 0; EntityReplicatorList replicatorUpdatedList; MultiplayerPackets::EntityUpdates entityUpdatePacket; - entityUpdatePacket.SetHostTimeMs(serverGameTimeMs); + entityUpdatePacket.SetHostTimeMs(hostTimeMs); + entityUpdatePacket.SetHostFrameId(InvalidHostFrameId); // Serialize everything while (!toSendList.empty()) { @@ -249,7 +250,7 @@ namespace Multiplayer return toSendList; } - void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs serverGameTimeMs) + void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs hostTimeMs) { EntityReplicatorList toSendList = GenerateEntityUpdateList(); @@ -264,7 +265,7 @@ namespace Multiplayer // While our to send list is not empty, build up another packet to send do { - SendEntityUpdatesPacketHelper(serverGameTimeMs, toSendList, m_maxPayloadSize, m_connection); + SendEntityUpdatesPacketHelper(hostTimeMs, toSendList, m_maxPayloadSize, m_connection); } while (!toSendList.empty()); } @@ -747,7 +748,7 @@ namespace Multiplayer bool EntityReplicationManager::HandleEntityUpdateMessage ( - [[maybe_unused]] AzNetworking::IConnection* connection, + [[maybe_unused]] AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage ) @@ -803,7 +804,7 @@ namespace Multiplayer return handled; } - bool EntityReplicationManager::HandleEntityRpcMessage([[maybe_unused]] AzNetworking::IConnection* connection, NetworkEntityRpcMessage& message) + bool EntityReplicationManager::HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message) { EntityReplicator* entityReplicator = GetEntityReplicator(message.GetEntityId()); const bool isReplicatorValid = (entityReplicator != nullptr) && !entityReplicator->IsMarkedForRemoval(); @@ -815,7 +816,7 @@ namespace Multiplayer } else { - return entityReplicator->HandleRpcMessage(message); + return entityReplicator->HandleRpcMessage(invokingConnection, message); } } @@ -833,8 +834,7 @@ namespace Multiplayer ); return false; } - - return entityReplicator->HandleRpcMessage(message); + return entityReplicator->HandleRpcMessage(nullptr, message); } AZ::TimeMs EntityReplicationManager::GetResendTimeoutTimeMs() const @@ -877,7 +877,6 @@ namespace Multiplayer AzNetworking::TimeoutResult EntityReplicationManager::OrphanedEntityRpcs::HandleTimeout(AzNetworking::TimeoutQueue::TimeoutItem& item) { NetEntityId timedOutEntityId = aznumeric_cast(item.m_userData); - auto entityRpcsIter = m_entityRpcMap.find(timedOutEntityId); if (entityRpcsIter != m_entityRpcMap.end()) { @@ -887,7 +886,6 @@ namespace Multiplayer } m_entityRpcMap.erase(entityRpcsIter); } - return AzNetworking::TimeoutResult::Delete; } @@ -1089,7 +1087,7 @@ namespace Multiplayer if (m_updateMode == EntityReplicationManager::Mode::LocalServerToRemoteServer) { - netBindComponent->NotifyMigration(GetRemoteHostId(), GetConnection().GetConnectionId()); + netBindComponent->NotifyServerMigration(GetRemoteHostId(), GetConnection().GetConnectionId()); } bool didSucceed = true; @@ -1127,7 +1125,7 @@ namespace Multiplayer } } - bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* connection, MultiplayerPackets::EntityMigration& message) + bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message) { EntityReplicator* replicator = GetEntityReplicator(message.GetEntityId()); { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h index a6470e6c34..4fc14e210f 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h @@ -13,11 +13,11 @@ #pragma once #include -#include -#include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -59,7 +59,7 @@ namespace Multiplayer HostId GetRemoteHostId() const; void ActivatePendingEntities(); - void SendUpdates(AZ::TimeMs serverGameTimeMs); + void SendUpdates(AZ::TimeMs hostTimeMs); void Clear(bool forMigration); bool SetEntityRebasing(NetworkEntityHandle& entityHandle); @@ -82,10 +82,10 @@ namespace Multiplayer void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event::Handler& handler); - bool HandleMessage(AzNetworking::IConnection* connection, MultiplayerPackets::EntityMigration& message); + bool HandleMessage(AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message); bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); - bool HandleEntityUpdateMessage(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); - bool HandleEntityRpcMessage(AzNetworking::IConnection* connection, NetworkEntityRpcMessage& message); + bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); + bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message); AZ::TimeMs GetResendTimeoutTimeMs() const; @@ -118,9 +118,9 @@ namespace Multiplayer using EntityReplicatorList = AZStd::deque; EntityReplicatorList GenerateEntityUpdateList(); - void SendEntityUpdatesPacketHelper(AZ::TimeMs serverGameTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection); + void SendEntityUpdatesPacketHelper(AZ::TimeMs hostTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection); - void SendEntityUpdates(AZ::TimeMs serverGameTimeMs); + void SendEntityUpdates(AZ::TimeMs hostTimeMs); void SendEntityRpcs(RpcMessages& deferredRpcs, bool reliable); void MigrateEntityInternal(NetEntityId entityId); @@ -155,31 +155,27 @@ namespace Multiplayer OrphanedEntityRpcs(EntityReplicationManager& replicationManager); void Update(); bool DispatchOrphanedRpcs(EntityReplicator& entityReplicator); - void AddOrphanedRpc(NetEntityId entityId, NetworkEntityRpcMessage& entityPrcMessage); + void AddOrphanedRpc(NetEntityId entityId, NetworkEntityRpcMessage& entityRpcMessage); AZStd::size_t Size() const { return m_entityRpcMap.size(); } private: AzNetworking::TimeoutResult HandleTimeout(AzNetworking::TimeoutQueue::TimeoutItem& item) override; - struct OrphanedRpcs { OrphanedRpcs() = default; OrphanedRpcs(OrphanedRpcs&& rhs) { + m_rpcMessages.swap(rhs.m_rpcMessages); m_timeoutId = rhs.m_timeoutId; rhs.m_timeoutId = AzNetworking::TimeoutId{ 0 }; - m_rpcMessages.swap(rhs.m_rpcMessages); } - - AzNetworking::TimeoutId m_timeoutId = AzNetworking::TimeoutId{ 0 }; RpcMessages m_rpcMessages; + AzNetworking::TimeoutId m_timeoutId = AzNetworking::TimeoutId{ 0 }; }; - typedef AZStd::unordered_map EntityRpcMap; EntityRpcMap m_entityRpcMap; AzNetworking::TimeoutQueue m_timeoutQueue; EntityReplicationManager& m_replicationManager; }; - OrphanedEntityRpcs m_orphanedEntityRpcs; EntityReplicatorMap m_entityReplicatorMap; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index b645101677..7431b95a22 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -628,7 +628,7 @@ namespace Multiplayer return result; } - bool EntityReplicator::HandleRpcMessage(NetworkEntityRpcMessage& entityRpcMessage) + bool EntityReplicator::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage) { // Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics MultiplayerStats& stats = AZ::Interface::Get()->GetStats(); @@ -676,7 +676,7 @@ namespace Multiplayer switch (result) { case RpcValidationResult::HandleRpc: - return m_netBindComponent->HandleRpcMessage(GetRemoteNetworkRole(), entityRpcMessage); + return m_netBindComponent->HandleRpcMessage(invokingConnection, GetRemoteNetworkRole(), entityRpcMessage); case RpcValidationResult::DropRpc: return true; case RpcValidationResult::DropRpcAndDisconnect: @@ -703,7 +703,7 @@ namespace Multiplayer break; } - AZ_Assert(false, "Unhandled ERpcValidationResult %d", result); + AZ_Assert(false, "Unhandled RpcValidationResult %d", result); return false; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h index 66274f638e..93494ab07c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h @@ -75,8 +75,8 @@ namespace Multiplayer const PropertyPublisher* GetPropertyPublisher() const; PropertySubscriber* GetPropertySubscriber(); - // Handlers for messages - bool HandleRpcMessage(NetworkEntityRpcMessage& entityRpcMessage); + // Handlers for Rpc messages + bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage); //! AZ::EntityBus overrides //! @{ diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h b/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h deleted file mode 100644 index 24e43de66a..0000000000 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/INetworkEntityDomain.h +++ /dev/null @@ -1,41 +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 -{ - //! @class INetworkEntityDomain - //! @brief A class that determines if an entity should belong to a particular EntityManager. - class INetworkEntityDomain - { - public: - using EntitiesNotInDomain = AZStd::unordered_set; - - virtual ~INetworkEntityDomain() = default; - - //! Enable Entity Domain Exit Tracking for entities on the server. - //! @param ownedEntitySet - virtual void ActivateTracking(const INetworkEntityManager::OwnedEntitySet& ownedEntitySet) = 0; - - //! Return the set of entities not in this domain. - //! @param outEntitiesNotInDomain - virtual void RetrieveEntitiesNotInDomain(EntitiesNotInDomain& outEntitiesNotInDomain) const = 0; - - //! Returns whether or not an entity should be owned by an entity manager. - //! @param entityHandle the handle of the entity to check for inclusion in the domain - //! @return false if this entity should not belong to the entity manger, true if it could be owned by the entity manager - virtual bool IsInDomain(const ConstNetworkEntityHandle& entityHandle) const = 0; - }; -} diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp index a37d444046..797d67e3ef 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp index 650b113186..ca0275d20b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index d1701bbb89..dfe427bd88 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -212,7 +212,7 @@ namespace Multiplayer { NetBindComponent* netBindComponent = entity->FindComponent(); AZ_Assert(netBindComponent != nullptr, "Attempting to send an RPC to an entity with no NetBindComponent"); - netBindComponent->HandleRpcMessage(NetEntityRole::Server, rpcMessage); + netBindComponent->HandleRpcMessage(nullptr, NetEntityRole::Server, rpcMessage); } } m_localDeferredRpcMessages.clear(); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index 142730188b..436ae01f5a 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -15,11 +15,11 @@ #include #include #include -#include #include #include #include -#include +#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp index 4ced19f8d9..69f715317a 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h index ffc150e5cc..4cfb242154 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp index a02bc4209d..0ab1d5ffcc 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp @@ -48,19 +48,34 @@ namespace Multiplayer return m_inputId; } - void NetworkInput::SetServerTimeMs(AZ::TimeMs serverTimeMs) + void NetworkInput::SetHostFrameId(HostFrameId hostFrameId) { - m_serverTimeMs = serverTimeMs; + m_hostFrameId = hostFrameId; } - AZ::TimeMs NetworkInput::GetServerTimeMs() const + HostFrameId NetworkInput::GetHostFrameId() const { - return m_serverTimeMs; + return m_hostFrameId; } - AZ::TimeMs& NetworkInput::ModifyServerTimeMs() + HostFrameId& NetworkInput::ModifyHostFrameId() { - return m_serverTimeMs; + return m_hostFrameId; + } + + void NetworkInput::SetHostTimeMs(AZ::TimeMs hostTimeMs) + { + m_hostTimeMs = hostTimeMs; + } + + AZ::TimeMs NetworkInput::GetHostTimeMs() const + { + return m_hostTimeMs; + } + + AZ::TimeMs& NetworkInput::ModifyHostTimeMs() + { + return m_hostTimeMs; } void NetworkInput::AttachNetBindComponent(NetBindComponent* netBindComponent) @@ -76,17 +91,19 @@ namespace Multiplayer bool NetworkInput::Serialize(AzNetworking::ISerializer& serializer) { - if (!serializer.Serialize(m_inputId, "InputId")) + if (!serializer.Serialize(m_inputId, "InputId") + || !serializer.Serialize(m_hostTimeMs, "HostTimeMs") + || !serializer.Serialize(m_hostFrameId, "HostFrameId")) { return false; } - uint8_t componentInputCount = static_cast(m_componentInputs.size()); + uint16_t componentInputCount = static_cast(m_componentInputs.size()); serializer.Serialize(componentInputCount, "ComponentInputCount"); m_componentInputs.resize(componentInputCount); if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) { - for (uint8_t i = 0; i < componentInputCount; ++i) + for (uint16_t i = 0; i < componentInputCount; ++i) { // We need to do a little extra work here, the delta serializer won't actually write out values if they were the same as the parent. // We need to make sure we don't lose state that is intrinsic to the underlying type @@ -148,7 +165,7 @@ namespace Multiplayer void NetworkInput::CopyInternal(const NetworkInput& rhs) { m_inputId = rhs.m_inputId; - m_serverTimeMs = rhs.m_serverTimeMs; + m_hostTimeMs = rhs.m_hostTimeMs; m_componentInputs.resize(rhs.m_componentInputs.size()); for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i) { diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h index 43768c4196..2c33d1ccf0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h @@ -12,8 +12,9 @@ #pragma once -#include -#include +#include +#include +#include #include namespace Multiplayer @@ -21,8 +22,6 @@ namespace Multiplayer // Forwards class NetBindComponent; - AZ_TYPE_SAFE_INTEGRAL(ClientInputId, uint16_t); - //! @class NetworkInput //! @brief A single networked client input command. class NetworkInput final @@ -42,9 +41,13 @@ namespace Multiplayer ClientInputId GetClientInputId() const; ClientInputId& ModifyClientInputId(); - void SetServerTimeMs(AZ::TimeMs serverTimeMs); - AZ::TimeMs GetServerTimeMs() const; - AZ::TimeMs& ModifyServerTimeMs(); + void SetHostFrameId(HostFrameId hostFrameId); + HostFrameId GetHostFrameId() const; + HostFrameId& ModifyHostFrameId(); + + void SetHostTimeMs(AZ::TimeMs hostTimeMs); + AZ::TimeMs GetHostTimeMs() const; + AZ::TimeMs& ModifyHostTimeMs(); void AttachNetBindComponent(NetBindComponent* netBindComponent); @@ -72,10 +75,9 @@ namespace Multiplayer MultiplayerComponentInputVector m_componentInputs; ClientInputId m_inputId = ClientInputId{ 0 }; - AZ::TimeMs m_serverTimeMs = AZ::TimeMs{ 0 }; + HostFrameId m_hostFrameId = InvalidHostFrameId; + AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; ConstNetworkEntityHandle m_owner; bool m_wasAttached = false; }; } - -AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ClientInputId); diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp index bb5f9a488d..8f70f7e1fa 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp index 466a112e12..6d284a6835 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h index be41495577..91970040c5 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp index b062569dce..9a0e784d36 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp @@ -24,36 +24,31 @@ namespace Multiplayer AZ::Interface::Unregister(this); } - AZ::TimeMs NetworkTime::ConvertFrameIdToTimeMs([[maybe_unused]] ApplicationFrameId frameId) const - { - return AZ::TimeMs{0}; - } - - ApplicationFrameId NetworkTime::ConvertTimeMsToFrameId([[maybe_unused]] AZ::TimeMs timeMs) const - { - return ApplicationFrameId{0}; - } - - bool NetworkTime::IsApplicationFrameIdRewound() const + bool NetworkTime::IsTimeRewound() const { return m_rewindingConnectionId != AzNetworking::InvalidConnectionId; } - ApplicationFrameId NetworkTime::GetApplicationFrameId() const + HostFrameId NetworkTime::GetHostFrameId() const { - return m_applicationFrameId; + return m_hostFrameId; } - ApplicationFrameId NetworkTime::GetUnalteredApplicationFrameId() const + HostFrameId NetworkTime::GetUnalteredHostFrameId() const { return m_unalteredFrameId; } - void NetworkTime::IncrementApplicationFrameId() + void NetworkTime::IncrementHostFrameId() { - AZ_Assert(!IsApplicationFrameIdRewound(), "Incrementing the global application frameId is unsupported under a rewound time scope"); + AZ_Assert(!IsTimeRewound(), "Incrementing the global application frameId is unsupported under a rewound time scope"); ++m_unalteredFrameId; - m_applicationFrameId = m_unalteredFrameId; + m_hostFrameId = m_unalteredFrameId; + } + + AZ::TimeMs NetworkTime::GetHostTimeMs() const + { + return m_hostTimeMs; } void NetworkTime::SyncRewindableEntityState() @@ -66,14 +61,15 @@ namespace Multiplayer return m_rewindingConnectionId; } - ApplicationFrameId NetworkTime::GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const + HostFrameId NetworkTime::GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const { - return (IsApplicationFrameIdRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_applicationFrameId; + return (IsTimeRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_hostFrameId; } - void NetworkTime::AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) + void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) { - m_applicationFrameId = frameId; + m_hostFrameId = frameId; + m_hostTimeMs = timeMs; m_rewindingConnectionId = rewindConnectionId; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h index 55ccb45e69..06e758b349 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include @@ -28,22 +28,22 @@ namespace Multiplayer //! INetworkTime overrides. //! @{ - AZ::TimeMs ConvertFrameIdToTimeMs(ApplicationFrameId frameId) const override; - ApplicationFrameId ConvertTimeMsToFrameId(AZ::TimeMs timeMs) const override; - bool IsApplicationFrameIdRewound() const override; - ApplicationFrameId GetApplicationFrameId() const override; - ApplicationFrameId GetUnalteredApplicationFrameId() const override; - void IncrementApplicationFrameId() override; + bool IsTimeRewound() const override; + HostFrameId GetHostFrameId() const override; + HostFrameId GetUnalteredHostFrameId() const override; + void IncrementHostFrameId() override; + AZ::TimeMs GetHostTimeMs() const override; void SyncRewindableEntityState() override; AzNetworking::ConnectionId GetRewindingConnectionId() const override; - ApplicationFrameId GetApplicationFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; - void AlterApplicationFrameId(ApplicationFrameId frameId, AzNetworking::ConnectionId rewindConnectionId) override; + HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; + void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override; //! @} private: - ApplicationFrameId m_applicationFrameId = ApplicationFrameId{0}; - ApplicationFrameId m_unalteredFrameId = ApplicationFrameId{0}; + HostFrameId m_hostFrameId = HostFrameId{ 0 }; + HostFrameId m_unalteredFrameId = HostFrameId{ 0 }; + AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; AzNetworking::ConnectionId m_rewindingConnectionId = AzNetworking::InvalidConnectionId; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h index cdea98dc07..4e830d4480 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include #include @@ -87,25 +87,25 @@ namespace Multiplayer //! Returns what the appropriate current time is for this rewindable property. //! @return the appropriate current time is for this rewindable property - ApplicationFrameId GetCurrentTimeForProperty() const; + HostFrameId GetCurrentTimeForProperty() const; //! Updates the latest value for this object instance, if frameTime represents a current or future time. //! Any attempts to set old values on the object will fail //! @param value the new value to set in the object history //! @param frameTime the time to set the value for - void SetValueForTime(const BASE_TYPE& value, ApplicationFrameId frameTime); + void SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime); //! Const value accessor, returns the correct value for the provided input time. //! @param frameTime the frame time to return the associated value for //! @return value given the current input time - const BASE_TYPE& GetValueForTime(ApplicationFrameId frameTime) const; + const BASE_TYPE& GetValueForTime(HostFrameId frameTime) const; //! Helper method to compute clamped array index values accounting for the offset head index. AZStd::size_t GetOffsetIndex(AZStd::size_t absoluteIndex) const; AZStd::array m_history; AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId; - ApplicationFrameId m_headTime = ApplicationFrameId{0}; + HostFrameId m_headTime = HostFrameId{0}; uint32_t m_headIndex = 0; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl index 69752210bb..0835421ebd 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl +++ b/Gems/Multiplayer/Code/Source/NetworkTime/RewindableObject.inl @@ -48,7 +48,7 @@ namespace Multiplayer inline RewindableObject &RewindableObject::operator =(const RewindableObject& rhs) { INetworkTime* networkTime = AZ::Interface::Get(); - SetValueForTime(rhs.GetValueForTime(networkTime->GetApplicationFrameId()), GetCurrentTimeForProperty()); + SetValueForTime(rhs.GetValueForTime(networkTime->GetHostFrameId()), GetCurrentTimeForProperty()); return *this; } @@ -73,7 +73,7 @@ namespace Multiplayer template inline BASE_TYPE& RewindableObject::Modify() { - const ApplicationFrameId frameTime = GetCurrentTimeForProperty(); + const HostFrameId frameTime = GetCurrentTimeForProperty(); if (frameTime < m_headTime) { AZ_Assert(false, "Trying to mutate a rewindable in the past"); @@ -103,7 +103,7 @@ namespace Multiplayer template inline bool RewindableObject::Serialize(AzNetworking::ISerializer& serializer) { - const ApplicationFrameId frameTime = GetCurrentTimeForProperty(); + const HostFrameId frameTime = GetCurrentTimeForProperty(); BASE_TYPE value = GetValueForTime(frameTime); if (serializer.Serialize(value, "Element") && (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject)) { @@ -113,14 +113,14 @@ namespace Multiplayer } template - inline ApplicationFrameId RewindableObject::GetCurrentTimeForProperty() const + inline HostFrameId RewindableObject::GetCurrentTimeForProperty() const { INetworkTime* networkTime = AZ::Interface::Get(); - return networkTime->GetApplicationFrameIdForRewindingConnection(m_owningConnectionId); + return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId); } template - inline void RewindableObject::SetValueForTime(const BASE_TYPE& value, ApplicationFrameId frameTime) + inline void RewindableObject::SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime) { if (frameTime < m_headTime) { @@ -155,7 +155,7 @@ namespace Multiplayer } template - inline const BASE_TYPE &RewindableObject::GetValueForTime(ApplicationFrameId frameTime) const + inline const BASE_TYPE &RewindableObject::GetValueForTime(HostFrameId frameTime) const { if (frameTime > m_headTime) { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h index 76562a34e2..1922e65941 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index 4dad4bd01f..423334476e 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -12,9 +12,9 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index f26e40355e..b340913e47 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -10,10 +10,18 @@ # set(FILES + Include/IConnectionData.h + Include/IEntityDomain.h Include/IMultiplayer.h + Include/IMultiplayerComponentInput.h + Include/INetworkEntityManager.h + Include/INetworkTime.h + Include/IReplicationWindow.h Include/MultiplayerStats.cpp Include/MultiplayerStats.h Include/MultiplayerTypes.h + Include/NetworkEntityHandle.h + Include/NetworkEntityHandle.inl Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/MultiplayerSystemComponent.cpp @@ -41,13 +49,11 @@ set(FILES Source/ConnectionData/ClientToServerConnectionData.cpp Source/ConnectionData/ClientToServerConnectionData.h Source/ConnectionData/ClientToServerConnectionData.inl - Source/ConnectionData/IConnectionData.h Source/ConnectionData/ServerToClientConnectionData.cpp Source/ConnectionData/ServerToClientConnectionData.h Source/ConnectionData/ServerToClientConnectionData.inl Source/EntityDomains/FullOwnershipEntityDomain.cpp Source/EntityDomains/FullOwnershipEntityDomain.h - Source/EntityDomains/IEntityDomain.h Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp Source/NetworkEntity/EntityReplication/EntityReplicationManager.h Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -59,12 +65,9 @@ set(FILES Source/NetworkEntity/EntityReplication/PropertySubscriber.h Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp Source/NetworkEntity/EntityReplication/ReplicationRecord.h - Source/NetworkEntity/INetworkEntityManager.h Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp Source/NetworkEntity/NetworkEntityAuthorityTracker.h Source/NetworkEntity/NetworkEntityHandle.cpp - Source/NetworkEntity/NetworkEntityHandle.h - Source/NetworkEntity/NetworkEntityHandle.inl Source/NetworkEntity/NetworkEntityManager.cpp Source/NetworkEntity/NetworkEntityManager.h Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -76,7 +79,6 @@ set(FILES Source/NetworkEntity/NetworkEntityTracker.inl Source/NetworkEntity/NetworkEntityUpdateMessage.cpp Source/NetworkEntity/NetworkEntityUpdateMessage.h - Source/NetworkInput/IMultiplayerComponentInput.h Source/NetworkInput/NetworkInput.cpp Source/NetworkInput/NetworkInput.h Source/NetworkInput/NetworkInputChild.cpp @@ -85,7 +87,6 @@ set(FILES Source/NetworkInput/NetworkInputHistory.h Source/NetworkInput/NetworkInputVector.cpp Source/NetworkInput/NetworkInputVector.h - Source/NetworkTime/INetworkTime.h Source/NetworkTime/NetworkTime.cpp Source/NetworkTime/NetworkTime.h Source/NetworkTime/RewindableObject.h @@ -96,7 +97,6 @@ set(FILES Source/Pipeline/NetworkSpawnableHolderComponent.h Source/ReplicationWindows/NullReplicationWindow.cpp Source/ReplicationWindows/NullReplicationWindow.h - Source/ReplicationWindows/IReplicationWindow.h Source/ReplicationWindows/ServerToClientReplicationWindow.cpp Source/ReplicationWindows/ServerToClientReplicationWindow.h ) From e7f0bc9ee2e58d25c6ed4ed408dd896751cec416 Mon Sep 17 00:00:00 2001 From: karlberg Date: Thu, 6 May 2021 17:23:03 -0700 Subject: [PATCH 05/18] Local prediction player controller is now functional --- ...tionPlayerInputComponent.AutoComponent.xml | 7 +- .../LocalPredictionPlayerInputComponent.cpp | 14 ++-- .../LocalPredictionPlayerInputComponent.h | 6 +- .../Code/Source/Components/NetBindComponent.h | 2 +- .../Debug/MultiplayerDebugSystemComponent.cpp | 4 +- .../Code/Source/NetworkInput/NetworkInput.h | 4 +- ...kInputVector.cpp => NetworkInputArray.cpp} | 79 ++---------------- .../Source/NetworkInput/NetworkInputArray.h | 54 +++++++++++++ .../NetworkInputMigrationVector.cpp | 80 +++++++++++++++++++ ...Vector.h => NetworkInputMigrationVector.h} | 44 ++-------- .../ServerToClientReplicationWindow.cpp | 9 ++- Gems/Multiplayer/Code/multiplayer_files.cmake | 6 +- 12 files changed, 176 insertions(+), 133 deletions(-) rename Gems/Multiplayer/Code/Source/NetworkInput/{NetworkInputVector.cpp => NetworkInputArray.cpp} (54%) create mode 100644 Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h create mode 100644 Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp rename Gems/Multiplayer/Code/Source/NetworkInput/{NetworkInputVector.h => NetworkInputMigrationVector.h} (54%) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index 45dfc43e49..65e2a8884e 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -12,14 +12,15 @@ + - + - + @@ -30,6 +31,6 @@ - + diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 56192c96d7..5a8fbfbe33 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -106,7 +106,7 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::HandleSendClientInput ( AzNetworking::IConnection* invokingConnection, - const Multiplayer::NetworkInputVector& inputArray, + const Multiplayer::NetworkInputArray& inputArray, const AZ::HashValue64& stateHash, [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState ) @@ -133,7 +133,7 @@ namespace Multiplayer // Figure out which index from the input array we want // we start at the oldest input that has not been processed int32_t inputArrayIndex = -1; - for (int32_t i = NetworkInputVector::MaxElements - 1; i >= 0; --i) + for (int32_t i = NetworkInputArray::MaxElements - 1; i >= 0; --i) { // Find an input that is newer than the last one we processed if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId()) @@ -286,7 +286,7 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::HandleSendMigrateClientInput ( AzNetworking::IConnection* invokingConnection, - const Multiplayer::MigrateNetworkInputVector& inputArray + const Multiplayer::NetworkInputMigrationVector& inputArray ) { if (!m_allowMigrateClientInput) @@ -308,7 +308,7 @@ namespace Multiplayer const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; // Copy array so we can modify input ids - MigrateNetworkInputVector inputArrayCopy = inputArray; + NetworkInputMigrationVector inputArrayCopy = inputArray; for (uint32_t i = 0; i < inputArrayCopy.GetSize(); ++i) { @@ -447,7 +447,7 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::OnMigrateEnd() { - MigrateNetworkInputVector inputArray; + NetworkInputMigrationVector inputArray; // Roll up all inputs that the new server doesn't have and send them now for (AZStd::size_t i = 0; i < m_inputHistory.Size(); ++i) @@ -499,7 +499,7 @@ namespace Multiplayer m_moveAccumulator -= inputRate; ++m_clientInputId; - NetworkInputVector inputArray(GetEntityHandle()); + NetworkInputArray inputArray(GetEntityHandle()); NetworkInput& input = inputArray[0]; input.SetClientInputId(m_clientInputId); @@ -544,7 +544,7 @@ namespace Multiplayer // Form the rest of the input array using the n most recent elements in the history buffer // NOTE: inputArray[0] has already been initialized hence start at i = 1 - for (uint32_t i = 1; i < NetworkInputVector::MaxElements; ++i) + for (uint32_t i = 1; i < NetworkInputArray::MaxElements; ++i) { if (i < inputHistorySize) { diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h index 0a4e574d65..feb79c0fa2 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h @@ -44,7 +44,7 @@ namespace Multiplayer void HandleSendClientInput ( AzNetworking::IConnection* invokingConnection, - const Multiplayer::NetworkInputVector& inputArray, + const Multiplayer::NetworkInputArray& inputArray, const AZ::HashValue64& stateHash, const AzNetworking::PacketEncodingBuffer& clientState ) override; @@ -52,7 +52,7 @@ namespace Multiplayer void HandleSendMigrateClientInput ( AzNetworking::IConnection* invokingConnection, - const Multiplayer::MigrateNetworkInputVector& inputArray + const Multiplayer::NetworkInputMigrationVector& inputArray ) override; void HandleSendClientInputCorrection @@ -87,7 +87,7 @@ namespace Multiplayer NetworkInputHistory m_inputHistory; // Anti-cheat accumulator for clients who purposely mess with their clock rate - NetworkInputVector m_lastInputReceived; + NetworkInputArray m_lastInputReceived; AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h index 4a4c4d0549..0885e44aa4 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.h @@ -126,7 +126,7 @@ namespace Multiplayer ReplicationRecord m_currentRecord = NetEntityRole::InvalidRole; ReplicationRecord m_totalRecord = NetEntityRole::InvalidRole; - ReplicationRecord m_predictableRecord = NetEntityRole::InvalidRole; + ReplicationRecord m_predictableRecord = NetEntityRole::Autonomous; ReplicationRecord m_localNotificationRecord = NetEntityRole::InvalidRole; PrefabEntityId m_prefabEntityId; AZStd::unordered_map m_multiplayerComponentMap; diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 506581b5e4..aec8d8520e 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -235,7 +235,7 @@ namespace Multiplayer if (m_displayMultiplayerStats) { - if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_HorizontalScrollbar)) + if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None)) { IMultiplayer* multiplayer = AZ::Interface::Get(); const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats(); @@ -254,7 +254,7 @@ namespace Multiplayer if (ImGui::BeginTable("", 5, flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide, TEXT_BASE_WIDTH * 36.0f); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Total Calls", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); ImGui::TableSetupColumn("Total Bytes", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); ImGui::TableSetupColumn("Calls/Sec", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h index 2c33d1ccf0..b2b0fa12c6 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.h @@ -29,8 +29,8 @@ namespace Multiplayer public: //! Intentionally restrict instancing of these objects to associated containers classes only //! This is a mechanism used to restrict calling autonomous client predicted setter functions to the ProcessInput call chain only - friend class NetworkInputVector; - friend class MigrateNetworkInputVector; + friend class NetworkInputArray; + friend class NetworkInputMigrationVector; friend class NetworkInputHistory; friend class NetworkInputChild; diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp similarity index 54% rename from Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp rename to Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp index 6d284a6835..0f5a0d7c0c 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp @@ -10,21 +10,21 @@ * */ -#include +#include #include #include #include namespace Multiplayer { - NetworkInputVector::NetworkInputVector() + NetworkInputArray::NetworkInputArray() : m_owner() , m_inputs() { ; } - NetworkInputVector::NetworkInputVector(const ConstNetworkEntityHandle& entityHandle) + NetworkInputArray::NetworkInputArray(const ConstNetworkEntityHandle& entityHandle) : m_owner(entityHandle) , m_inputs() { @@ -38,27 +38,27 @@ namespace Multiplayer } } - NetworkInput& NetworkInputVector::operator[](uint32_t index) + NetworkInput& NetworkInputArray::operator[](uint32_t index) { return m_inputs[index].m_networkInput; } - const NetworkInput& NetworkInputVector::operator[](uint32_t index) const + const NetworkInput& NetworkInputArray::operator[](uint32_t index) const { return m_inputs[index].m_networkInput; } - void NetworkInputVector::SetPreviousInputId(ClientInputId previousInputId) + void NetworkInputArray::SetPreviousInputId(ClientInputId previousInputId) { m_previousInputId = previousInputId; } - ClientInputId NetworkInputVector::GetPreviousInputId() const + ClientInputId NetworkInputArray::GetPreviousInputId() const { return m_previousInputId; } - bool NetworkInputVector::Serialize(AzNetworking::ISerializer& serializer) + bool NetworkInputArray::Serialize(AzNetworking::ISerializer& serializer) { // Always serialize the full first element if (!m_inputs[0].m_networkInput.Serialize(serializer)) @@ -105,67 +105,4 @@ namespace Multiplayer serializer.Serialize(m_previousInputId, "PreviousInputId"); return true; } - - - MigrateNetworkInputVector::MigrateNetworkInputVector() - : m_owner() - { - ; - } - - MigrateNetworkInputVector::MigrateNetworkInputVector(const ConstNetworkEntityHandle& entityHandle) - : m_owner(entityHandle) - { - ; - } - - uint32_t MigrateNetworkInputVector::GetSize() const - { - return aznumeric_cast(m_inputs.size()); - } - - NetworkInput& MigrateNetworkInputVector::operator[](uint32_t index) - { - return m_inputs[index].m_networkInput; - } - - const NetworkInput& MigrateNetworkInputVector::operator[](uint32_t index) const - { - return m_inputs[index].m_networkInput; - } - - bool MigrateNetworkInputVector::PushBack(const NetworkInput& networkInput) - { - if (m_inputs.size() < m_inputs.capacity()) - { - m_inputs.push_back(networkInput); - return true; - } - return false; - } - - bool MigrateNetworkInputVector::Serialize(AzNetworking::ISerializer& serializer) - { - NetEntityId ownerId = m_owner.GetNetEntityId(); - serializer.Serialize(ownerId, "OwnerId"); - - uint32_t inputCount = aznumeric_cast(m_inputs.size()); - serializer.Serialize(inputCount, "InputCount"); - - if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) - { - // make sure all the possible NetworkInputs get attached prior to serialization, this double sends the size, but this message is only sent on server migration - m_inputs.resize(inputCount); - m_owner = GetNetworkEntityManager()->GetEntity(ownerId); - NetBindComponent* netBindComponent = m_owner.GetNetBindComponent(); - if (netBindComponent) - { - for (uint32_t i = 0; i < m_inputs.size(); ++i) - { - m_inputs[i].m_networkInput.AttachNetBindComponent(netBindComponent); - } - } - } - return serializer.Serialize(m_inputs, "Inputs"); - } } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h new file mode 100644 index 0000000000..504992fecb --- /dev/null +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h @@ -0,0 +1,54 @@ +/* +* 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 + +namespace Multiplayer +{ + //! @class NetworkInputArray + //! @brief An array of network inputs. Used to mitigate loss of input packets on the server. Compresses subsequent elements. + class NetworkInputArray final + { + public: + static constexpr uint32_t MaxElements = 8; // Never try to replicate a list larger than this amount + + NetworkInputArray(); + NetworkInputArray(const ConstNetworkEntityHandle& entityHandle); + ~NetworkInputArray() = default; + + NetworkInput& operator[](uint32_t index); + const NetworkInput& operator[](uint32_t index) const; + + void SetPreviousInputId(ClientInputId previousInputId); + ClientInputId GetPreviousInputId() const; + + bool Serialize(AzNetworking::ISerializer& serializer); + + private: + + struct Wrapper // Strictly a workaround to deal with the private constructor of NetworkInput + { + Wrapper() : m_networkInput() {} + Wrapper(const NetworkInput& networkInput) : m_networkInput(networkInput) {} + NetworkInput m_networkInput; + }; + + ConstNetworkEntityHandle m_owner; + AZStd::array m_inputs; + ClientInputId m_previousInputId; + }; +} diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp new file mode 100644 index 0000000000..dee72156ed --- /dev/null +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.cpp @@ -0,0 +1,80 @@ +/* +* 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. +* +*/ + +#include +#include +#include + +namespace Multiplayer +{ + NetworkInputMigrationVector::NetworkInputMigrationVector() + : m_owner() + { + ; + } + + NetworkInputMigrationVector::NetworkInputMigrationVector(const ConstNetworkEntityHandle& entityHandle) + : m_owner(entityHandle) + { + ; + } + + uint32_t NetworkInputMigrationVector::GetSize() const + { + return aznumeric_cast(m_inputs.size()); + } + + NetworkInput& NetworkInputMigrationVector::operator[](uint32_t index) + { + return m_inputs[index].m_networkInput; + } + + const NetworkInput& NetworkInputMigrationVector::operator[](uint32_t index) const + { + return m_inputs[index].m_networkInput; + } + + bool NetworkInputMigrationVector::PushBack(const NetworkInput& networkInput) + { + if (m_inputs.size() < m_inputs.capacity()) + { + m_inputs.push_back(networkInput); + return true; + } + return false; + } + + bool NetworkInputMigrationVector::Serialize(AzNetworking::ISerializer& serializer) + { + NetEntityId ownerId = m_owner.GetNetEntityId(); + serializer.Serialize(ownerId, "OwnerId"); + + uint32_t inputCount = aznumeric_cast(m_inputs.size()); + serializer.Serialize(inputCount, "InputCount"); + + if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) + { + // make sure all the possible NetworkInputs get attached prior to serialization, this double sends the size, but this message is only sent on server migration + m_inputs.resize(inputCount); + m_owner = GetNetworkEntityManager()->GetEntity(ownerId); + NetBindComponent* netBindComponent = m_owner.GetNetBindComponent(); + if (netBindComponent) + { + for (uint32_t i = 0; i < m_inputs.size(); ++i) + { + m_inputs[i].m_networkInput.AttachNetBindComponent(netBindComponent); + } + } + } + return serializer.Serialize(m_inputs, "Inputs"); + } +} diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h similarity index 54% rename from Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h rename to Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h index 91970040c5..c6ea425fec 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputVector.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h @@ -14,53 +14,21 @@ #include #include +#include #include namespace Multiplayer { - //! @class NetworkInputVector - //! @brief An array of network inputs. Used to mitigate loss of input packets on the server. Compresses subsequent elements. - class NetworkInputVector final - { - public: - static constexpr uint32_t MaxElements = 8; // Never try to replicate a list larger than this amount - - NetworkInputVector(); - NetworkInputVector(const ConstNetworkEntityHandle& entityHandle); - ~NetworkInputVector() = default; - - NetworkInput& operator[](uint32_t index); - const NetworkInput& operator[](uint32_t index) const; - - void SetPreviousInputId(ClientInputId previousInputId); - ClientInputId GetPreviousInputId() const; - - bool Serialize(AzNetworking::ISerializer& serializer); - - private: - - struct Wrapper // Strictly a workaround to deal with the private constructor of NetworkInput - { - Wrapper() : m_networkInput() {} - Wrapper(const NetworkInput& networkInput) : m_networkInput(networkInput) {} - NetworkInput m_networkInput; - }; - - ConstNetworkEntityHandle m_owner; - AZStd::fixed_vector m_inputs; - ClientInputId m_previousInputId; - }; - - //! @class MigrateNetworkInputVector + //! @class NetworkInputMigrationVector //! @brief A variable sized array of input commands, used specifically when migrate a clients inputs. - class MigrateNetworkInputVector final + class NetworkInputMigrationVector final { public: static constexpr uint32_t MaxElements = 90; // Never try to migrate a list larger than this amount, bumped up to handle DTLS connection time - MigrateNetworkInputVector(); - MigrateNetworkInputVector(const ConstNetworkEntityHandle& entityHandle); - virtual ~MigrateNetworkInputVector() = default; + NetworkInputMigrationVector(); + NetworkInputMigrationVector(const ConstNetworkEntityHandle& entityHandle); + virtual ~NetworkInputMigrationVector() = default; uint32_t GetSize() const; NetworkInput& operator[](uint32_t index); diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index 22f777a149..abcb1e62ab 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -157,14 +157,15 @@ namespace Multiplayer //} // We want to find the closest extent to the player and prioritize using that distance - const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter(); - const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal); - const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition); - const float priority = (gatherDistanceSquared > 0.0f) ? 1.0f / gatherDistanceSquared : 0.0f; AZ::Entity* entity = static_cast(visEntry->m_userData); NetBindComponent* entryNetBindComponent = entity->template FindComponent(); if (entryNetBindComponent != nullptr) { + const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter(); + const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal); + const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition); + const float priority = (gatherDistanceSquared > 0.0f) ? 1.0f / gatherDistanceSquared : 0.0f; + NetworkEntityHandle entityHandle(entryNetBindComponent, networkEntityTracker); AddEntityToReplicationSet(entityHandle, priority, gatherDistanceSquared); } diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index b340913e47..1f4e57ae43 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -81,12 +81,14 @@ set(FILES Source/NetworkEntity/NetworkEntityUpdateMessage.h Source/NetworkInput/NetworkInput.cpp Source/NetworkInput/NetworkInput.h + Source/NetworkInput/NetworkInputArray.cpp + Source/NetworkInput/NetworkInputArray.h Source/NetworkInput/NetworkInputChild.cpp Source/NetworkInput/NetworkInputChild.h Source/NetworkInput/NetworkInputHistory.cpp Source/NetworkInput/NetworkInputHistory.h - Source/NetworkInput/NetworkInputVector.cpp - Source/NetworkInput/NetworkInputVector.h + Source/NetworkInput/NetworkInputMigrationVector.cpp + Source/NetworkInput/NetworkInputMigrationVector.h Source/NetworkTime/NetworkTime.cpp Source/NetworkTime/NetworkTime.h Source/NetworkTime/RewindableObject.h From 4b1fe9b10b8e1daaaf2ae39fc7fda85335d70f05 Mon Sep 17 00:00:00 2001 From: karlberg Date: Thu, 6 May 2021 17:35:48 -0700 Subject: [PATCH 06/18] Fix a comment and minor optimization to the server to client replication window --- .../EntityVisibilityBoundsUnionSystem.cpp | 2 +- .../ServerToClientReplicationWindow.cpp | 14 +++++++------- .../ServerToClientReplicationWindow.h | 11 +++++------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp index f9c24b82db..f019039d16 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp @@ -71,7 +71,7 @@ namespace AzFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); - // ignore any entity that might activate which does not have a TransformComponent + // ignore any entity that might deactivate which does not have a TransformComponent if (entity->GetTransform() == nullptr) { return; diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index abcb1e62ab..c54a610de2 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -56,6 +56,8 @@ namespace Multiplayer ServerToClientReplicationWindow::ServerToClientReplicationWindow(NetworkEntityHandle controlledEntity, const AzNetworking::IConnection* connection) : m_controlledEntity(controlledEntity) + , m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); }) + , m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); }) , m_connection(connection) , m_lastCheckedSentPackets(connection->GetMetrics().m_packetsSent) , m_lastCheckedLostPackets(connection->GetMetrics().m_packetsLost) @@ -74,7 +76,9 @@ namespace Multiplayer //} m_updateWindowEvent.Enqueue(sv_ClientReplicationWindowUpdateMs, true); - AZ::EntitySystemBus::Handler::BusConnect(); + + AZ::Interface::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler); + AZ::Interface::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler); } bool ServerToClientReplicationWindow::ReplicationSetUpdateReady() @@ -205,10 +209,8 @@ namespace Multiplayer //} } - void ServerToClientReplicationWindow::OnEntityActivated(const AZ::EntityId& entityId) + void ServerToClientReplicationWindow::OnEntityActivated(AZ::Entity* entity) { - AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - ConstNetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent(); if (netBindComponent != nullptr) @@ -236,10 +238,8 @@ namespace Multiplayer } } - void ServerToClientReplicationWindow::OnEntityDeactivated(const AZ::EntityId& entityId) + void ServerToClientReplicationWindow::OnEntityDeactivated(AZ::Entity* entity) { - AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - ConstNetworkEntityHandle entityHandle(entity, GetNetworkEntityTracker()); NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent(); if (netBindComponent != nullptr) diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index 423334476e..55a6a4b56e 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -27,7 +27,6 @@ namespace Multiplayer class ServerToClientReplicationWindow : public IReplicationWindow - , public AZ::EntitySystemBus::Handler { public: @@ -56,11 +55,8 @@ namespace Multiplayer //! @} private: - //! EntitySystemBus interface - //! @{ - void OnEntityActivated(const AZ::EntityId&) override; - void OnEntityDeactivated(const AZ::EntityId&) override; - //! @} + void OnEntityActivated(AZ::Entity* entity); + void OnEntityDeactivated(AZ::Entity* entity); //void CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController); //void OnAddFilteredEntity(NetEntityId filteredEntityId); @@ -79,6 +75,9 @@ namespace Multiplayer NetworkEntityHandle m_controlledEntity; AZ::TransformInterface* m_controlledEntityTransform = nullptr; + AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler; + AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler; + //FilteredEntityComponent::Authority* m_controlledFilteredEntityComponent = nullptr; //NetBindComponent* m_controlledNetBindComponent = nullptr; From b2b632aedeab5aa94a8fc4bbd81823333c79de1c Mon Sep 17 00:00:00 2001 From: karlberg Date: Thu, 6 May 2021 19:39:31 -0700 Subject: [PATCH 07/18] Bug fixes for stats and for sending rpc and property updates from the client --- .../Code/Include/MultiplayerStats.cpp | 29 +++++++++++++++++++ .../Code/Include/MultiplayerStats.h | 1 + .../ClientToServerConnectionData.cpp | 3 +- .../Source/MultiplayerSystemComponent.cpp | 4 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp index b9f47814b4..7672997ad5 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp +++ b/Gems/Multiplayer/Code/Include/MultiplayerStats.cpp @@ -14,6 +14,12 @@ namespace Multiplayer { + MultiplayerStats::Metric::Metric() + { + AZStd::uninitialized_fill_n(m_callHistory.data(), RingbufferSamples, 0); + AZStd::uninitialized_fill_n(m_byteHistory.data(), RingbufferSamples, 0); + } + void MultiplayerStats::ReserveComponentStats(NetComponentId netComponentId, uint16_t propertyCount, uint16_t rpcCount) { const uint16_t netComponentIndex = aznumeric_cast(netComponentId); @@ -71,6 +77,29 @@ namespace Multiplayer { m_totalHistoryTimeMs = metricFrameTimeMs * static_cast(RingbufferSamples); m_recordMetricIndex = ++m_recordMetricIndex % RingbufferSamples; + for (ComponentStats& componentStats : m_componentStats) + { + for (Metric& metric : componentStats.m_propertyUpdatesSent) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_propertyUpdatesRecv) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_rpcsSent) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + for (Metric& metric : componentStats.m_rpcsRecv) + { + metric.m_callHistory[m_recordMetricIndex] = 0; + metric.m_byteHistory[m_recordMetricIndex] = 0; + } + } } static void CombineMetrics(MultiplayerStats::Metric& outArg1, const MultiplayerStats::Metric& arg2) diff --git a/Gems/Multiplayer/Code/Include/MultiplayerStats.h b/Gems/Multiplayer/Code/Include/MultiplayerStats.h index fcbd741bb9..dc266a14bf 100644 --- a/Gems/Multiplayer/Code/Include/MultiplayerStats.h +++ b/Gems/Multiplayer/Code/Include/MultiplayerStats.h @@ -37,6 +37,7 @@ namespace Multiplayer using MetricRingbuffer = AZStd::array; struct Metric { + Metric(); uint64_t m_totalCalls = 0; uint64_t m_totalBytes = 0; MetricRingbuffer m_callHistory; diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp index 3aeaac5103..ee308f6ed8 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.cpp @@ -50,8 +50,9 @@ namespace Multiplayer return m_entityReplicationManager; } - void ClientToServerConnectionData::Update([[maybe_unused]] AZ::TimeMs hostTimeMs) + void ClientToServerConnectionData::Update(AZ::TimeMs hostTimeMs) { m_entityReplicationManager.ActivatePendingEntities(); + m_entityReplicationManager.SendUpdates(hostTimeMs); } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 90d55d8b26..71aa361793 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ - +#pragma optimize("", off) #include #include #include @@ -127,6 +127,7 @@ namespace Multiplayer void MultiplayerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { + AZ::TimeMs deltaTimeMs = aznumeric_cast(static_cast(deltaTime * 1000.0f)); AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs(); // Handle deferred local rpc messages that were generated during the updates @@ -137,6 +138,7 @@ namespace Multiplayer m_networkEntityManager.NotifyEntitiesDirtied(); MultiplayerStats& stats = GetStats(); + stats.TickStats(deltaTimeMs); stats.m_entityCount = GetNetworkEntityManager()->GetEntityCount(); stats.m_serverConnectionCount = 0; stats.m_clientConnectionCount = 0; From 05a39a4412f9e494e3edd61d92445491aaaa8a08 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 09:54:49 -0700 Subject: [PATCH 08/18] Fix several build failures --- .../AzCore/AzCore/Component/ComponentApplication.h | 4 ++-- Code/Framework/AzCore/Tests/BehaviorContextFixture.h | 8 ++++---- Code/Framework/AzCore/Tests/Serialization.cpp | 4 ++-- Code/Framework/Tests/ComponentAddRemove.cpp | 4 ++-- Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h | 8 ++++---- .../Code/Tests/ImageProcessing_Test.cpp | 4 ++-- Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h | 8 ++++---- Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h | 8 ++++---- .../LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp | 4 ++-- .../Code/Source/MultiplayerSystemComponent.cpp | 2 +- .../Source/ReplicationWindows/NullReplicationWindow.cpp | 2 +- Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index 3c5ff0eab8..fac2867074 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -206,8 +206,8 @@ namespace AZ void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final; void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final; void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final; - void SignalEntityActivated(AZ::Entity* entity) override final; - void SignalEntityDeactivated(AZ::Entity* entity) override final; + void SignalEntityActivated(Entity* entity) override final; + void SignalEntityDeactivated(Entity* entity) override final; bool AddEntity(Entity* entity) override; bool RemoveEntity(Entity* entity) override; bool DeleteEntity(const EntityId& id) override; diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 0e2b67addd..6ae97e1304 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -52,10 +52,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {} void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override {} void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override {} - void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {} - void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {} - void SignalEntityActivated(AZ::Entity* entity) override {} - void SignalEntityDeactivated(AZ::Entity* entity) override {} + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override {} + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override {} + void SignalEntityActivated(AZ::Entity*) override {} + void SignalEntityDeactivated(AZ::Entity*) override {} bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index c1ce9f3d03..036942f9dd 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1234,8 +1234,8 @@ namespace UnitTest void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void SignalEntityActivated(Entity*) override { } + void SignalEntityDeactivated(Entity*) override { } bool AddEntity(Entity*) override { return false; } bool RemoveEntity(Entity*) override { return false; } bool DeleteEntity(const EntityId&) override { return false; } diff --git a/Code/Framework/Tests/ComponentAddRemove.cpp b/Code/Framework/Tests/ComponentAddRemove.cpp index 3815188269..4fd6db7dde 100644 --- a/Code/Framework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/Tests/ComponentAddRemove.cpp @@ -1102,8 +1102,8 @@ namespace UnitTest void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {} void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {} void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {} - void SignalEntityActivated(AZ::Entity* entity) override {} - void SignalEntityDeactivated(AZ::Entity* entity) override {} + void SignalEntityActivated(Entity*) override {} + void SignalEntityDeactivated(Entity*) override {} bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const EntityId&) override { return true; } diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index dc746bae23..e40edcc864 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -577,10 +577,10 @@ namespace AWSClientAuthUnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } - void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } - void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index 2a26c2a0ae..c94978c63d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -107,8 +107,8 @@ namespace UnitTest void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void SignalEntityActivated(Entity*) override { } + void SignalEntityDeactivated(Entity*) override { } bool AddEntity(Entity*) override { return false; } bool RemoveEntity(Entity*) override { return false; } bool DeleteEntity(const EntityId&) override { return false; } diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index fbc39f6a40..81d9ddb87a 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -41,10 +41,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } - void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } - void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index 55a226956a..9ab6aea51a 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -38,10 +38,10 @@ namespace UnitTest void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } - void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } - void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return false; } bool RemoveEntity(AZ::Entity*) override { return false; } bool DeleteEntity(const AZ::EntityId&) override { return false; } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 27cc326ff9..2514485519 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -306,8 +306,8 @@ public: void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { } void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void SignalEntityActivated(Entity*) override { } + void SignalEntityDeactivated(Entity*) override { } bool AddEntity(Entity*) override { return true; } bool RemoveEntity(Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 71aa361793..e6fb77eca7 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -9,7 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#pragma optimize("", off) + #include #include #include diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp index 698376dccf..726c75ad86 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp @@ -10,7 +10,7 @@ * */ -#include "NullReplicationWindow.h" +#include namespace Multiplayer { diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index 8545424ca7..32437ae22a 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -82,10 +82,10 @@ protected: void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { } void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { } void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { } - void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { } - void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { } - void SignalEntityActivated(AZ::Entity* entity) override { } - void SignalEntityDeactivated(AZ::Entity* entity) override { } + void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { } + void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { } + void SignalEntityActivated(AZ::Entity*) override { } + void SignalEntityDeactivated(AZ::Entity*) override { } bool AddEntity(AZ::Entity*) override { return true; } bool RemoveEntity(AZ::Entity*) override { return true; } bool DeleteEntity(const AZ::EntityId&) override { return true; } From a8fa7a59d453106d8c10dbb2727a1c96af486441 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 10:03:07 -0700 Subject: [PATCH 09/18] CR feedback --- .../AzCore/AzCore/Console/LoggerSystemComponent.cpp | 5 +++-- .../AzFramework/Visibility/EntityBoundsUnionBus.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp index de29edc3b0..c004e2c406 100644 --- a/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Console/LoggerSystemComponent.cpp @@ -127,7 +127,10 @@ namespace AZ const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args); buffer[AZStd::min(length + 1, MaxLogBufferSize - 1)] = '\0'; + m_logEvent.Signal(level, buffer, file, function, line); + // Force a new-line before calling the AZ::Debug::Trace functions, as they assume a newline is present + buffer[AZStd::min(length + 1, MaxLogBufferSize - 2)] = '\n'; switch (level) { case LogLevel::Warn: @@ -141,8 +144,6 @@ namespace AZ AZ::Debug::Trace::Output("Logger", buffer); break; } - - m_logEvent.Signal(level, buffer, file, function, line); } void LoggerSystemComponent::SetLevel(const AZ::ConsoleCommandContainer& arguments) diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h index b607759260..e95e25871a 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h @@ -45,7 +45,7 @@ namespace AzFramework virtual void OnTransformUpdated(AZ::Entity* entity) = 0; protected: - virtual ~IEntityBoundsUnion() = default; + ~IEntityBoundsUnion() = default; }; // EBus wrapper for ScriptCanvas From e8917e0f069b366eeac952c00da46670220222b9 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 10:36:34 -0700 Subject: [PATCH 10/18] Fix for format string type mismatch --- .../Components/LocalPredictionPlayerInputComponent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 5a8fbfbe33..1a73d5bc4b 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -180,16 +180,16 @@ namespace Multiplayer } if (lostInput) { - AZLOG(NET_Prediction, "InputLost InputId=%u", input.GetClientInputId()); + AZLOG(NET_Prediction, "InputLost InputId=%u", aznumeric_cast(input.GetClientInputId())); } else { - AZLOG(NET_Prediction, "Processed InputId=%u", input.GetClientInputId()); + AZLOG(NET_Prediction, "Processed InputId=%u", aznumeric_cast(input.GetClientInputId())); } } else { - AZLOG(NET_Prediction, "Dropped InputId=%u", input.GetClientInputId()); + AZLOG(NET_Prediction, "Dropped InputId=%u", aznumeric_cast(input.GetClientInputId())); } --inputArrayIndex; } From d2df379fa42d5dc3200f92f2d5fa8656fc6515e0 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 11:26:59 -0700 Subject: [PATCH 11/18] Fixes for AR issues --- .../AzCore/Component/ComponentApplication.cpp | 5 ++++ Code/Framework/AzCore/AzCore/EBus/Event.inl | 8 ++++++ .../Code/Tests/RewindableObjectTests.cpp | 28 +++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index def98ddb63..daf5b5efd2 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -526,6 +526,11 @@ namespace AZ // are destroyed m_commandLine = {}; + m_entityAddedEvent.DisconnectAllHandlers(); + m_entityRemovedEvent.DisconnectAllHandlers(); + m_entityActivatedEvent.DisconnectAllHandlers(); + m_entityDeactivatedEvent.DisconnectAllHandlers(); + DestroyAllocator(); } diff --git a/Code/Framework/AzCore/AzCore/EBus/Event.inl b/Code/Framework/AzCore/AzCore/EBus/Event.inl index 82f5645ccd..3786f1c26b 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Event.inl +++ b/Code/Framework/AzCore/AzCore/EBus/Event.inl @@ -233,6 +233,14 @@ namespace AZ AZ_Assert(handler->m_event == this, "Entry event does not match"); handler->Disconnect(); } + + // Free up any owned memory + AZStd::vector freeHandlers; + m_handlers.swap(freeHandlers); + AZStd::vector freeAdds; + m_addList.swap(freeAdds); + AZStd::stack freeFree; + m_freeList.swap(freeFree); } diff --git a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp index d2d41723eb..367b7ee0de 100644 --- a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp +++ b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp @@ -37,12 +37,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 0; i < 16; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } @@ -50,12 +50,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 16; i < 48; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } } @@ -68,12 +68,12 @@ namespace UnitTest { test = i; EXPECT_EQ(i, test); - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } { // Note that we didn't actually set any value for time rewindableBufferFrames, so we're testing fetching a value past the last time set - Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(RewindableBufferFrames - 1, test); } } @@ -91,12 +91,12 @@ namespace UnitTest { Object& value = test.Modify(); value.value = i; - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } for (uint32_t i = 0; i < RewindableBufferFrames; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); const Object& value = test; EXPECT_EQ(value.value, i); } @@ -105,19 +105,19 @@ namespace UnitTest TEST_F(RewindableObjectTests, TestBackfillOnLargeTimestep) { Multiplayer::RewindableObject test(0); - Multiplayer::ScopedAlterTime time1(static_cast(0), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time1(static_cast(0), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); test = 1; - Multiplayer::ScopedAlterTime time2(static_cast(31), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time2(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); test = 2; for (uint32_t i = 0; i < 31; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(1, test); } - Multiplayer::ScopedAlterTime time3(static_cast(31), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time3(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(2, test); } @@ -127,13 +127,13 @@ namespace UnitTest for (uint32_t i = 0; i < 1000; ++i) { - AZ::Interface::Get()->IncrementApplicationFrameId(); + AZ::Interface::Get()->IncrementHostFrameId(); } test = 1000; for (uint32_t i = 0; i < 1000; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); EXPECT_EQ(1000, test); } } From 80f6dcd25827414c5f6a68756f53b57ef48e63e9 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 16:20:00 -0700 Subject: [PATCH 12/18] Build fixes for android --- Code/CryEngine/CryCommon/Cry_Camera.h | 22 +++++++++---------- Code/CryEngine/CryCommon/Cry_Geo.h | 2 +- Code/CryEngine/CryCommon/Cry_GeoDistance.h | 4 ++-- Code/CryEngine/CryCommon/Cry_GeoIntersect.h | 10 ++++----- Code/CryEngine/CryCommon/Cry_GeoOverlap.h | 18 +++++++-------- .../Serialization/HashSerializer.cpp | 5 +++-- .../Serialization/HashSerializer.h | 2 +- ...tionPlayerInputComponent.AutoComponent.xml | 2 +- .../LocalPredictionPlayerInputComponent.cpp | 4 ++-- .../LocalPredictionPlayerInputComponent.h | 2 +- 10 files changed, 36 insertions(+), 35 deletions(-) diff --git a/Code/CryEngine/CryCommon/Cry_Camera.h b/Code/CryEngine/CryCommon/Cry_Camera.h index 56a764d897..656f196e99 100644 --- a/Code/CryEngine/CryCommon/Cry_Camera.h +++ b/Code/CryEngine/CryCommon/Cry_Camera.h @@ -620,24 +620,24 @@ public: bool IsPointVisible(const Vec3& p) const; //sphere-frustum test - bool IsSphereVisible_F(const Sphere& s) const; - uint8 IsSphereVisible_FH(const Sphere& s) const; //this is going to be the exact version of sphere-culling + bool IsSphereVisible_F(const ::Sphere& s) const; + uint8 IsSphereVisible_FH(const ::Sphere& s) const; //this is going to be the exact version of sphere-culling // AABB-frustum test // Fast - bool IsAABBVisible_F(const AABB& aabb) const; - uint8 IsAABBVisible_FH(const AABB& aabb, bool* pAllInside) const; - uint8 IsAABBVisible_FH(const AABB& aabb) const; + bool IsAABBVisible_F(const ::AABB& aabb) const; + uint8 IsAABBVisible_FH(const ::AABB& aabb, bool* pAllInside) const; + uint8 IsAABBVisible_FH(const ::AABB& aabb) const; // Exact - bool IsAABBVisible_E(const AABB& aabb) const; - uint8 IsAABBVisible_EH(const AABB& aabb, bool* pAllInside) const; - uint8 IsAABBVisible_EH(const AABB& aabb) const; + bool IsAABBVisible_E(const ::AABB& aabb) const; + uint8 IsAABBVisible_EH(const ::AABB& aabb, bool* pAllInside) const; + uint8 IsAABBVisible_EH(const ::AABB& aabb) const; // Multi-camera - bool IsAABBVisible_EHM(const AABB& aabb, bool* pAllInside) const; - bool IsAABBVisible_EM(const AABB& aabb) const; - bool IsAABBVisible_FM(const AABB& aabb) const; + bool IsAABBVisible_EHM(const ::AABB& aabb, bool* pAllInside) const; + bool IsAABBVisible_EM(const ::AABB& aabb) const; + bool IsAABBVisible_FM(const ::AABB& aabb) const; //OBB-frustum test bool IsOBBVisible_F(const Vec3& wpos, const OBB& obb) const; diff --git a/Code/CryEngine/CryCommon/Cry_Geo.h b/Code/CryEngine/CryCommon/Cry_Geo.h index ebe27a469a..359896157c 100644 --- a/Code/CryEngine/CryCommon/Cry_Geo.h +++ b/Code/CryEngine/CryCommon/Cry_Geo.h @@ -794,7 +794,7 @@ struct HWVSphere radius = r; } - ILINE HWVSphere(const Sphere& sp) + ILINE HWVSphere(const ::Sphere& sp) { center = HWVLoadVecUnaligned(&sp.center); radius = SIMDFLoadFloat(sp.radius); diff --git a/Code/CryEngine/CryCommon/Cry_GeoDistance.h b/Code/CryEngine/CryCommon/Cry_GeoDistance.h index 47794c7671..2329038dc4 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoDistance.h +++ b/Code/CryEngine/CryCommon/Cry_GeoDistance.h @@ -1179,7 +1179,7 @@ namespace Distance { // float result = Distance::Point_TriangleSq( pos, triangle ); //---------------------------------------------------------------------------------- template - ILINE F Sphere_TriangleSq(const Sphere& s, const Triangle_tpl& t) + ILINE F Sphere_TriangleSq(const ::Sphere& s, const Triangle_tpl& t) { F sqdistance = Distance::Point_TriangleSq(s.center, t) - (s.radius * s.radius); if (sqdistance < 0) @@ -1190,7 +1190,7 @@ namespace Distance { } template - ILINE F Sphere_TriangleSq(const Sphere& s, const Triangle_tpl& t, Vec3_tpl& output) + ILINE F Sphere_TriangleSq(const ::Sphere& s, const Triangle_tpl& t, Vec3_tpl& output) { F sqdistance = Distance::Point_TriangleSq(s.center, t, output) - (s.radius * s.radius); if (sqdistance < 0) diff --git a/Code/CryEngine/CryCommon/Cry_GeoIntersect.h b/Code/CryEngine/CryCommon/Cry_GeoIntersect.h index 89f6d8ebaf..f0be567ce2 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoIntersect.h +++ b/Code/CryEngine/CryCommon/Cry_GeoIntersect.h @@ -792,7 +792,7 @@ namespace Intersect { //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Line_Sphere(const Line& line, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Line_Sphere(const Line& line, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 end = line.pointonline + line.direction; @@ -830,7 +830,7 @@ namespace Intersect { //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Ray_Sphere(const Ray& ray, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Ray_Sphere(const Ray& ray, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 end = ray.origin + ray.direction; float a = ray.direction | ray.direction; @@ -863,7 +863,7 @@ namespace Intersect { return intersection; } - inline bool Ray_SphereFirst(const Ray& ray, const Sphere& s, Vec3& intPoint) + inline bool Ray_SphereFirst(const Ray& ray, const ::Sphere& s, Vec3& intPoint) { Vec3 p2; unsigned char res = Ray_Sphere(ray, s, intPoint, p2); @@ -886,7 +886,7 @@ namespace Intersect { //--- 0x02 = one intersection, lineseg has just an EXIT point but no ENTRY point (ls.start is inside the sphere) -- //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point -- //---------------------------------------------------------------------------------- - inline unsigned char Lineseg_Sphere(const Lineseg& ls, const Sphere& s, Vec3& i0, Vec3& i1) + inline unsigned char Lineseg_Sphere(const Lineseg& ls, const ::Sphere& s, Vec3& i0, Vec3& i1) { Vec3 dir = (ls.end - ls.start); @@ -931,7 +931,7 @@ namespace Intersect { } - inline bool Lineseg_SphereFirst(const Lineseg& lineseg, const Sphere& s, Vec3& intPoint) + inline bool Lineseg_SphereFirst(const Lineseg& lineseg, const ::Sphere& s, Vec3& intPoint) { Vec3 p2; uint8 res = Lineseg_Sphere(lineseg, s, intPoint, p2); diff --git a/Code/CryEngine/CryCommon/Cry_GeoOverlap.h b/Code/CryEngine/CryCommon/Cry_GeoOverlap.h index ab560b7518..14af81258a 100644 --- a/Code/CryEngine/CryCommon/Cry_GeoOverlap.h +++ b/Code/CryEngine/CryCommon/Cry_GeoOverlap.h @@ -103,7 +103,7 @@ namespace Overlap { // Checks if a point is inside a sphere. // Example: // bool result=Overlap::Point_Sphere( point, sphere ); - ILINE bool Point_Sphere(const Vec3& p, const Sphere& s) + ILINE bool Point_Sphere(const Vec3& p, const ::Sphere& s) { Vec3 distc = p - s.center; f32 sqrad = s.radius * s.radius; @@ -407,7 +407,7 @@ namespace Overlap { //! check if a Lineseg and a Sphere overlap - inline bool Lineseg_Sphere(const Lineseg& ls, const Sphere& s) + inline bool Lineseg_Sphere(const Lineseg& ls, const ::Sphere& s) { float radius2 = s.radius * s.radius; @@ -729,7 +729,7 @@ namespace Overlap { * 0 = no overlap * 1 = overlap *----------------------------------------------------------------------------------*/ - ILINE bool Sphere_AABB(const Sphere& s, const AABB& aabb) + ILINE bool Sphere_AABB(const ::Sphere& s, const AABB& aabb) { Vec3 center(s.center); @@ -746,7 +746,7 @@ namespace Overlap { } // As Sphere_AABB but ignores z parts - ILINE bool Sphere_AABB2D(const Sphere& s, const AABB& aabb) + ILINE bool Sphere_AABB2D(const ::Sphere& s, const AABB& aabb) { Vec3 center(s.center); @@ -776,7 +776,7 @@ namespace Overlap { * 0x01 = Sphere and AABB overlap * 0x02 = Sphere in inside AABB */ - ILINE char Sphere_AABB_Inside(const Sphere& s, const AABB& aabb) + ILINE char Sphere_AABB_Inside(const ::Sphere& s, const AABB& aabb) { if (Sphere_AABB(s, aabb)) { @@ -819,7 +819,7 @@ namespace Overlap { //--- 0 = no overlap --------------------------- //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- - inline bool Sphere_OBB(const Sphere& s, const OBB& obb) + inline bool Sphere_OBB(const ::Sphere& s, const OBB& obb) { //first we transform the sphere-center into the AABB-space of the OBB Vec3 SphereInOBBSpace = s.center * obb.m33; @@ -861,7 +861,7 @@ namespace Overlap { //--- 0 = no overlap --------------------------- //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- - inline bool Sphere_Sphere(const Sphere& s1, const Sphere& s2) + inline bool Sphere_Sphere(const ::Sphere& s1, const ::Sphere& s2) { Vec3 distc = s1.center - s2.center; f32 sqrad = (s1.radius + s2.radius) * (s1.radius + s2.radius); @@ -884,7 +884,7 @@ namespace Overlap { //--- 1 = overlap ----------------- //---------------------------------------------------------------------------------- template - ILINE bool Sphere_Triangle(const Sphere& s, const Triangle_tpl& t) + ILINE bool Sphere_Triangle(const ::Sphere& s, const Triangle_tpl& t) { //create a "bouding sphere" around triangle for fast rejection test Vec3_tpl middle = (t.v0 + t.v1 + t.v2) * (1 / 3.0f); @@ -899,7 +899,7 @@ namespace Overlap { SqRad0 = (F)fsel(SqRad0 - SqRad2, SqRad0, SqRad2); //first simple rejection-test... - if (Sphere_Sphere(s, Sphere(middle, sqrt_tpl(SqRad0))) == 0) + if (Sphere_Sphere(s, ::Sphere(middle, sqrt_tpl(SqRad0))) == 0) { return 0; //overlap not possible } diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp index 80096365a4..c7f47cbc04 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp @@ -19,9 +19,10 @@ namespace AzNetworking static const int32_t FloatHashMinValue = (INT_MIN >> 7); static const int32_t FloatHashMaxValue = (INT_MAX >> 7); - AZ::HashValue64 HashSerializer::GetHash() const + AZ::HashValue32 HashSerializer::GetHash() const { - return m_hash; + // Just truncate the upper bits + return static_cast(m_hash); } SerializerMode HashSerializer::GetSerializerMode() const diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h index b4bc991746..2f86d1aafe 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h @@ -27,7 +27,7 @@ namespace AzNetworking HashSerializer() = default; - AZ::HashValue64 GetHash() const; + AZ::HashValue32 GetHash() const; // ISerializer interfaces SerializerMode GetSerializerMode() const override; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index 65e2a8884e..44edcaf505 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -21,7 +21,7 @@ - + diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 1a73d5bc4b..90b590d99d 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -107,7 +107,7 @@ namespace Multiplayer ( AzNetworking::IConnection* invokingConnection, const Multiplayer::NetworkInputArray& inputArray, - const AZ::HashValue64& stateHash, + const AZ::HashValue32& stateHash, [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState ) { @@ -201,7 +201,7 @@ namespace Multiplayer AzNetworking::HashSerializer hashSerializer; GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); - const AZ::HashValue64 localAuthorityHash = hashSerializer.GetHash(); + const AZ::HashValue32 localAuthorityHash = hashSerializer.GetHash(); if (stateHash != localAuthorityHash) { diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h index feb79c0fa2..15a4f3a048 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h @@ -45,7 +45,7 @@ namespace Multiplayer ( AzNetworking::IConnection* invokingConnection, const Multiplayer::NetworkInputArray& inputArray, - const AZ::HashValue64& stateHash, + const AZ::HashValue32& stateHash, const AzNetworking::PacketEncodingBuffer& clientState ) override; From ae8a49c4efb35b102aa7dabf8c7b4664d8689c6c Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 16:51:53 -0700 Subject: [PATCH 13/18] fix bad merge --- .../AzToolsFramework/ToolsComponents/TransformComponent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index bacb5b75e8..81684e62ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -25,7 +25,8 @@ #include #include #include -#include #include +#include +#include #include #include #include From 86fe8bf8aa455336d5975ec4f0bcec47b397f216 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 19:19:36 -0700 Subject: [PATCH 14/18] Two more touchpoints that were causing ambiguous symbol errors --- Code/CryEngine/CryCommon/Cry_Camera.h | 4 ++-- Code/CryEngine/CryCommon/IPathfinder.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/CryEngine/CryCommon/Cry_Camera.h b/Code/CryEngine/CryCommon/Cry_Camera.h index 656f196e99..d0eb318e94 100644 --- a/Code/CryEngine/CryCommon/Cry_Camera.h +++ b/Code/CryEngine/CryCommon/Cry_Camera.h @@ -1386,7 +1386,7 @@ inline bool CCamera::IsPointVisible(const Vec3& p) const // return values // CULL_EXCLUSION = sphere outside of frustum (very fast rejection-test) // CULL_INTERSECT = sphere and frustum intersects or sphere in completely inside frustum -inline bool CCamera::IsSphereVisible_F(const Sphere& s) const +inline bool CCamera::IsSphereVisible_F(const ::Sphere& s) const { if ((m_fp[0] | s.center) > s.radius) { @@ -1427,7 +1427,7 @@ inline bool CCamera::IsSphereVisible_F(const Sphere& s) const // CULL_EXCLUSION = sphere outside of frustum (very fast rejection-test) // CULL_INTERSECT = sphere intersects the borders of the frustum, further checks necessary // CULL_INCLUSION = sphere is complete inside the frustum, no further checks necessary -inline uint8 CCamera::IsSphereVisible_FH(const Sphere& s) const +inline uint8 CCamera::IsSphereVisible_FH(const ::Sphere& s) const { f32 nc, rc, lc, tc, bc, cc; if ((nc = m_fp[0] | s.center) > s.radius) diff --git a/Code/CryEngine/CryCommon/IPathfinder.h b/Code/CryEngine/CryCommon/IPathfinder.h index 3e50bb09cb..97e5f7b4f1 100644 --- a/Code/CryEngine/CryCommon/IPathfinder.h +++ b/Code/CryEngine/CryCommon/IPathfinder.h @@ -109,7 +109,7 @@ struct NavigationBlocker , costMultMod(0) , radialDecay(false) {AZ_Assert(false, "Should never get called"); } - Sphere sphere; + ::Sphere sphere; bool radialDecay; bool directional; From eb7a8b386af3beb61b653f31d4d059558537de84 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 20:40:23 -0700 Subject: [PATCH 15/18] Fixes for unit tests where component application might be null --- .../AzCore/AzCore/Component/Component.cpp | 6 +++++- .../AzCore/AzCore/Component/Entity.cpp | 18 +++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Component.cpp b/Code/Framework/AzCore/AzCore/Component/Component.cpp index f336b9e1a1..498e4d03d3 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Component.cpp @@ -174,7 +174,11 @@ namespace AZ //========================================================================= void ComponentDescriptor::ReleaseDescriptor() { - AZ::Interface::Get()->UnregisterComponentDescriptor(this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->UnregisterComponentDescriptor(this); + } delete this; } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index 6796bccb2b..b7c161b53c 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -112,7 +112,11 @@ namespace AZ { EBUS_EVENT(EntitySystemBus, OnEntityDestruction, m_id); EBUS_EVENT_ID(m_id, EntityBus, OnEntityDestruction, m_id); - AZ::Interface::Get()->RemoveEntity(this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->RemoveEntity(this); + } m_stateEvent.Signal(State::Init, State::Destroying); } @@ -216,14 +220,22 @@ namespace AZ EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityActivated, m_id); - AZ::Interface::Get()->SignalEntityActivated(this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->SignalEntityActivated(this); + } } void Entity::Deactivate() { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore); - AZ::Interface::Get()->SignalEntityDeactivated(this); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + if (componentApplication != nullptr) + { + componentApplication->SignalEntityDeactivated(this); + } EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id); From 6b9ecc69c949d6e6e23481b4589550918da9e632 Mon Sep 17 00:00:00 2001 From: karlberg Date: Fri, 7 May 2021 20:45:35 -0700 Subject: [PATCH 16/18] two more unit test touchpoints where core systems may not be initialized --- .../AzFramework/Components/TransformComponent.cpp | 6 +++++- .../AzToolsFramework/ToolsComponents/TransformComponent.cpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 866f0cc6d2..fb2d3d35bf 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -833,7 +833,11 @@ namespace AzFramework EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM); m_transformChangedEvent.Signal(m_localTM, m_worldTM); - AZ::Interface::Get()->OnTransformUpdated(GetEntity()); + AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface::Get(); + if (boundsUnion != nullptr) + { + boundsUnion->OnTransformUpdated(GetEntity()); + } } void TransformComponent::ComputeWorldTM() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 81684e62ea..ac5f1136f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -268,7 +268,11 @@ namespace AzToolsFramework GetEntityId(), &TransformNotification::OnTransformChanged, localTM, worldTM); m_transformChangedEvent.Signal(localTM, worldTM); - AZ::Interface::Get()->OnTransformUpdated(GetEntity()); + AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface::Get(); + if (boundsUnion != nullptr) + { + boundsUnion->OnTransformUpdated(GetEntity()); + } } } From 851323e1128596b61bc1a924aafa8cb77920ea54 Mon Sep 17 00:00:00 2001 From: karlberg Date: Sat, 8 May 2021 10:05:16 -0700 Subject: [PATCH 17/18] One more test crash fix due to nullptr component application --- .../AzFramework/Components/TransformComponent.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index fb2d3d35bf..5605fe567c 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -695,8 +695,8 @@ namespace AzFramework parentId = handler->GetParentId(); } #endif - - AZ::Entity* parentEntity = AZ::Interface::Get()->FindEntity(parentEntityId); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(parentEntityId) : nullptr; AZ_Assert(parentEntity, "We expect to have a parent entity associated with the provided parent's entity Id."); if (parentEntity) { @@ -745,7 +745,8 @@ namespace AzFramework m_parentId = parentId; if (m_parentId.IsValid()) { - AZ::Entity* parentEntity = AZ::Interface::Get()->FindEntity(m_parentId); + AZ::ComponentApplicationRequests* componentApplication = AZ::Interface::Get(); + AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(m_parentId) : nullptr; m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active); m_onNewParentKeepWorldTM = isKeepWorldTM; From 9c23e637a0286533cddcac6a230c53c6c53d6041 Mon Sep 17 00:00:00 2001 From: karlberg Date: Sat, 8 May 2021 18:24:13 -0700 Subject: [PATCH 18/18] Fix for white box test weirdness --- .../Visibility/EntityVisibilityBoundsUnionSystem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp index f019039d16..c71adc5c3f 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp @@ -36,6 +36,9 @@ namespace AzFramework void EntityVisibilityBoundsUnionSystem::Disconnect() { + m_entityActivatedEventHandler.Disconnect(); + m_entityDeactivatedEventHandler.Disconnect(); + AZ::TickBus::Handler::BusDisconnect(); IEntityBoundsUnionRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this);