Merging latest development

Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
kberg-amzn
2021-10-14 19:17:10 -07:00
1528 changed files with 33581 additions and 22343 deletions
@@ -33,6 +33,8 @@ namespace Multiplayer
void Update() override;
bool CanSendUpdates() const override;
void SetCanSendUpdates(bool canSendUpdates) override;
bool DidHandshake() const override;
void SetDidHandshake(bool didHandshake) override;
//! @}
const AZStd::string& GetProviderTicket() const;
@@ -43,6 +45,7 @@ namespace Multiplayer
AZStd::string m_providerTicket;
AzNetworking::IConnection* m_connection = nullptr;
bool m_canSendUpdates = true;
bool m_didHandshake = false;
};
}
@@ -27,4 +27,14 @@ namespace Multiplayer
{
m_providerTicket = ticket;
}
inline bool ClientToServerConnectionData::DidHandshake() const
{
return m_didHandshake;
}
inline void ClientToServerConnectionData::SetDidHandshake(bool didHandshake)
{
m_didHandshake = didHandshake;
}
}
@@ -34,6 +34,8 @@ namespace Multiplayer
void Update() override;
bool CanSendUpdates() const override;
void SetCanSendUpdates(bool canSendUpdates) override;
bool DidHandshake() const override;
void SetDidHandshake(bool didHandshake) override;
//! @}
NetworkEntityHandle GetPrimaryPlayerEntity();
@@ -53,6 +55,7 @@ namespace Multiplayer
AZStd::string m_providerTicket;
AzNetworking::IConnection* m_connection = nullptr;
bool m_canSendUpdates = false;
bool m_didHandshake = false;
};
}
@@ -37,4 +37,14 @@ namespace Multiplayer
{
m_providerTicket = ticket;
}
inline bool ServerToClientConnectionData::DidHandshake() const
{
return m_didHandshake;
}
inline void ServerToClientConnectionData::SetDidHandshake(bool didHandshake)
{
m_didHandshake = didHandshake;
}
}
@@ -0,0 +1,225 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "MultiplayerDebugHierarchyReporter.h"
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Visibility/IVisibilitySystem.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
#if defined(IMGUI_ENABLED)
#include <imgui/imgui.h>
#endif
namespace Multiplayer
{
MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter()
: m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug"))
{
CollectHierarchyRoots();
AZ::EntitySystemBus::Handler::BusConnect();
m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true);
}
MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter()
{
AZ::EntitySystemBus::Handler::BusDisconnect();
}
// --------------------------------------------------------------------------------------------
void MultiplayerDebugHierarchyReporter::OnImGuiUpdate()
{
#if defined(IMGUI_ENABLED)
ImGui::Text("Hierarchies");
ImGui::Separator();
for (const auto& root : m_hierarchyRoots)
{
if (const auto* rootComponent = root.second.m_rootComponent)
{
if (rootComponent->IsHierarchicalRoot())
{
const AZStd::vector<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(),
"[%s] %4zu members",
rootComponent->GetEntity()->GetName().c_str(),
hierarchicalChildren.size()))
{
ImGui::Separator();
ImGui::Columns(4, "hierarchy_columns");
ImGui::Text("EntityId");
ImGui::NextColumn();
ImGui::Text("NetEntityId");
ImGui::NextColumn();
ImGui::Text("Entity Name");
ImGui::NextColumn();
ImGui::Text("Role");
ImGui::NextColumn();
ImGui::Separator();
ImGui::Columns(4, "hierarchy child info");
bool firstEntity = true;
for (const AZ::Entity* entity : hierarchicalChildren)
{
ImGui::Text("%s", entity->GetId().ToString().c_str());
ImGui::NextColumn();
ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId()));
ImGui::NextColumn();
ImGui::Text("%s", entity->GetName().c_str());
ImGui::NextColumn();
if (firstEntity)
{
ImGui::Text("Root node");
}
else if (entity->FindComponent<NetworkHierarchyRootComponent>())
{
ImGui::Text("Inner root node");
}
else if (entity->FindComponent<NetworkHierarchyChildComponent>())
{
ImGui::Text("Child node");
}
ImGui::NextColumn();
firstEntity = false;
}
ImGui::Columns(1);
ImGui::TreePop();
}
}
}
}
ImGui::Separator();
if (ImGui::InputFloat("Awareness Radius", &m_awarenessRadius))
{
CollectHierarchyRoots();
}
if (ImGui::Button("Refresh"))
{
CollectHierarchyRoots();
}
#endif
}
void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay()
{
if (!m_hierarchyRoots.empty())
{
if (m_debugDisplay == nullptr)
{
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
}
const AZ::u32 stateBefore = m_debugDisplay->GetState();
m_debugDisplay->SetColor(AZ::Colors::White);
for (const auto& root : m_hierarchyRoots)
{
if (const auto* rootComponent = root.second.m_rootComponent)
{
if (rootComponent->IsHierarchicalRoot())
{
const AZStd::vector<AZ::Entity*>& hierarchicalChildren = rootComponent->GetHierarchicalEntities();
azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(),
aznumeric_cast<AZ::u32>(hierarchicalChildren.size()));
AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation();
constexpr bool centerText = true;
m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0);
}
}
}
m_debugDisplay->SetState(stateBefore);
}
}
void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId)
{
if (const AZ::Entity* childEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
{
if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
{
HierarchyRootInfo info;
info.m_rootComponent = rootComponent;
rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent);
rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent);
m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info));
}
}
}
void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId)
{
if (const AZ::Entity* childEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId))
{
if (auto* rootComponent = childEntity->FindComponent<NetworkHierarchyRootComponent>())
{
m_hierarchyRoots.erase(rootComponent);
}
}
}
void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots()
{
m_hierarchyRoots.clear();
AZ::Sphere awarenessSphere(AZ::Vector3::CreateZero(), m_awarenessRadius);
const auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
if (const auto viewportContext = viewportContextManager->GetDefaultViewportContext())
{
awarenessSphere.SetCenter(viewportContext->GetCameraTransform().GetTranslation());
}
AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries;
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere,
[&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData)
{
gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size());
for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
{
if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
{
gatheredEntries.push_back(visEntry);
}
}
}
);
for (const AzFramework::VisibilityEntry* entry : gatheredEntries)
{
const AZ::Entity* entity = static_cast<AZ::Entity*>(entry->m_userData);
if (auto* rootComponent = entity->FindComponent<NetworkHierarchyRootComponent>())
{
if (awarenessSphere.GetCenter().GetDistanceEstimate(entity->GetTransform()->GetWorldTranslation()) < m_awarenessRadius)
{
HierarchyRootInfo info;
info.m_rootComponent = rootComponent;
rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent);
rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent);
m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info));
}
}
}
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/EntityBus.h>
#include <AzCore/EBus/ScheduledEvent.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Multiplayer/Components/NetworkHierarchyRootComponent.h>
namespace Multiplayer
{
/**
* /brief Provides ImGui and debug draw hierarchy information at runtime.
*/
class MultiplayerDebugHierarchyReporter
: public AZ::EntitySystemBus::Handler
{
public:
MultiplayerDebugHierarchyReporter();
~MultiplayerDebugHierarchyReporter() override;
//! Main update loop.
void OnImGuiUpdate();
//! Draws hierarchy information over hierarchy root entities.
void UpdateDebugOverlay();
//! EntitySystemBus overrides.
//! @{
void OnEntityActivated(const AZ::EntityId& entityId) override;
void OnEntityDeactivated(const AZ::EntityId& entityId) override;
//! @}
private:
AZ::ScheduledEvent m_updateDebugOverlay;
AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr;
struct HierarchyRootInfo
{
NetworkHierarchyRootComponent* m_rootComponent = nullptr;
NetworkHierarchyChangedEvent::Handler m_changedEvent;
NetworkHierarchyLeaveEvent::Handler m_leaveEvent;
};
AZStd::unordered_map<NetworkHierarchyRootComponent*, HierarchyRootInfo> m_hierarchyRoots;
void CollectHierarchyRoots();
char m_statusBuffer[100] = {};
float m_awarenessRadius = 1000.f;
};
}
@@ -76,6 +76,7 @@ namespace Multiplayer
ImGui::Checkbox("Networking Stats", &m_displayNetworkingStats);
ImGui::Checkbox("Multiplayer Stats", &m_displayMultiplayerStats);
ImGui::Checkbox("Multiplayer Entity Stats", &m_displayPerEntityStats);
ImGui::Checkbox("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger);
ImGui::EndMenu();
}
}
@@ -473,6 +474,29 @@ namespace Multiplayer
}
}
}
if (m_displayHierarchyDebugger)
{
if (ImGui::Begin("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger))
{
if (m_hierarchyDebugger == nullptr)
{
m_hierarchyDebugger = AZStd::make_unique<MultiplayerDebugHierarchyReporter>();
}
if (m_hierarchyDebugger)
{
m_hierarchyDebugger->OnImGuiUpdate();
}
}
}
else
{
if (m_hierarchyDebugger)
{
m_hierarchyDebugger.reset();
}
}
}
#endif
}
@@ -8,6 +8,8 @@
#pragma once
#include "MultiplayerDebugHierarchyReporter.h"
#include <AzCore/Component/Component.h>
#include <AzCore/Interface/Interface.h>
#include <Debug/MultiplayerDebugPerEntityReporter.h>
@@ -62,5 +64,8 @@ namespace Multiplayer
bool m_displayPerEntityStats = false;
AZStd::unique_ptr<MultiplayerDebugPerEntityReporter> m_reporter;
bool m_displayHierarchyDebugger = false;
AZStd::unique_ptr<MultiplayerDebugHierarchyReporter> m_hierarchyDebugger;
};
}
@@ -146,7 +146,6 @@ namespace Multiplayer
{
// Connect the Editor to the editor server for Multiplayer simulation
AZ::Interface<IMultiplayer>::Get()->Connect(remoteAddress.c_str(), remotePort);
AZ::Interface<IMultiplayer>::Get()->SendReadyForEntityUpdates(true);
}
}
}
@@ -33,7 +33,6 @@ namespace Multiplayer
MultiplayerEditorConnection();
~MultiplayerEditorConnection() = default;
bool IsHandshakeComplete() const { return true; };
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet);
@@ -62,6 +62,7 @@ namespace Multiplayer
}
MultiplayerEditorSystemComponent::MultiplayerEditorSystemComponent()
: m_serverAcceptanceReceivedHandler([this](){OnServerAcceptanceReceived();})
{
;
}
@@ -70,6 +71,7 @@ namespace Multiplayer
{
AzFramework::GameEntityContextEventBus::Handler::BusConnect();
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
AZ::Interface<IMultiplayer>::Get()->AddServerAcceptanceReceivedHandler(m_serverAcceptanceReceivedHandler);
}
void MultiplayerEditorSystemComponent::Deactivate()
@@ -143,7 +145,11 @@ namespace Multiplayer
// Start the configured server if it's available
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" --editorsv_isDedicated true", serverPath.c_str());
processLaunchInfo.m_commandlineParameters = AZStd::string::format(
R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")",
serverPath.c_str(),
AZ::Utils::GetProjectPath().c_str(),
static_cast<AZ::CVarFixedString>(sv_defaultPlayerSpawnAsset).c_str());
processLaunchInfo.m_showWindow = true;
processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL;
@@ -239,4 +245,12 @@ namespace Multiplayer
void MultiplayerEditorSystemComponent::OnGameEntitiesReset()
{
}
void MultiplayerEditorSystemComponent::OnServerAcceptanceReceived()
{
// We're now accepting the connection to the EditorServer.
// In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded,
// but since we're in Editor, we're already in the level.
AZ::Interface<IMultiplayer>::Get()->SendReadyForEntityUpdates(true);
}
}
@@ -8,6 +8,8 @@
#pragma once
#include <Multiplayer/IMultiplayer.h>
#include <IEditor.h>
#include <Editor/MultiplayerEditorConnection.h>
@@ -45,6 +47,9 @@ namespace Multiplayer
MultiplayerEditorSystemComponent();
~MultiplayerEditorSystemComponent() override = default;
//! Called once the editor receives the server's accept packet
void OnServerAcceptanceReceived();
//! AZ::Component overrides.
//! @{
void Activate() override;
@@ -71,5 +76,7 @@ namespace Multiplayer
IEditor* m_editor = nullptr;
AzFramework::ProcessWatcher* m_serverProcess = nullptr;
AzNetworking::ConnectionId m_editorConnId;
ServerAcceptanceReceivedEvent::Handler m_serverAcceptanceReceivedHandler;
};
}
@@ -325,6 +325,12 @@ namespace Multiplayer
return true;
}
void MultiplayerSystemComponent::OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason)
{
AZ_UNUSED(sessionConfig);
AZ_UNUSED(updateReason);
}
void MultiplayerSystemComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
if (bg_multiplayerDebugDraw)
@@ -463,9 +469,9 @@ namespace Multiplayer
MultiplayerPackets::SyncConsole m_syncPacket;
};
bool MultiplayerSystemComponent::IsHandshakeComplete() const
bool MultiplayerSystemComponent::IsHandshakeComplete(AzNetworking::IConnection* connection) const
{
return m_didHandshake;
return reinterpret_cast<IConnectionData*>(connection->GetUserData())->DidHandshake();
}
bool MultiplayerSystemComponent::HandleRequest
@@ -520,7 +526,7 @@ namespace Multiplayer
if (connection->SendReliablePacket(MultiplayerPackets::Accept(sv_map)))
{
m_didHandshake = true;
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->SetDidHandshake(true);
if (packet.GetTemporaryUserId() == 0)
{
// Sync our console
@@ -539,7 +545,7 @@ namespace Multiplayer
[[maybe_unused]] MultiplayerPackets::Accept& packet
)
{
m_didHandshake = true;
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->SetDidHandshake(true);
if (m_temporaryUserIdentifier == 0)
{
AZ::CVarFixedString commandString = "sv_map " + packet.GetMap();
@@ -560,6 +566,8 @@ namespace Multiplayer
connectionData->GetReplicationManager().AddAutonomousEntityReplicatorCreatedHandler(m_autonomousEntityReplicatorCreatedHandler);
}
}
m_serverAcceptanceReceivedEvent.Signal();
return true;
}
@@ -878,6 +886,11 @@ namespace Multiplayer
handler.Connect(m_connectionAcquiredEvent);
}
void MultiplayerSystemComponent::AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler)
{
handler.Connect(m_serverAcceptanceReceivedEvent);
}
void MultiplayerSystemComponent::AddSessionInitHandler(SessionInitEvent::Handler& handler)
{
handler.Connect(m_initEvent);
@@ -1120,7 +1133,7 @@ namespace Multiplayer
INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate);
NetworkEntityHandle controlledEntity;
if (entityList.size() > 0)
if (!entityList.empty())
{
controlledEntity = entityList[0];
}
@@ -37,6 +37,8 @@ namespace AzNetworking
namespace Multiplayer
{
AZ_CVAR_EXTERNED(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset);
//! Multiplayer system component wraps the bridging logic between the game and transport layer.
class MultiplayerSystemComponent final
: public AZ::Component
@@ -68,6 +70,7 @@ namespace Multiplayer
bool OnSessionHealthCheck() override;
bool OnCreateSessionBegin(const AzFramework::SessionConfig& sessionConfig) override;
bool OnDestroySessionBegin() override;
void OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason) override;
//! @}
//! AZ::TickBus::Handler overrides.
@@ -76,7 +79,7 @@ namespace Multiplayer
int GetTickOrder() override;
//! @}
bool IsHandshakeComplete() const;
bool IsHandshakeComplete(AzNetworking::IConnection* connection) const;
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Connect& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Accept& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet);
@@ -116,6 +119,7 @@ namespace Multiplayer
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
void AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) override;
void SendNotifyClientMigrationEvent(AzNetworking::ConnectionId connectionId, const HostId& hostId, uint64_t userIdentifier, ClientInputId lastClientInputId, NetEntityId controlledEntityId) override;
void SendNotifyEntityMigrationEvent(const ConstNetworkEntityHandle& entityHandle, const HostId& remoteHostId) override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
@@ -160,6 +164,7 @@ namespace Multiplayer
SessionInitEvent m_initEvent;
SessionShutdownEvent m_shutdownEvent;
ConnectionAcquiredEvent m_connectionAcquiredEvent;
ServerAcceptanceReceivedEvent m_serverAcceptanceReceivedEvent;
ClientDisconnectedEvent m_clientDisconnectedEvent;
ClientMigrationStartEvent m_clientMigrationStartEvent;
ClientMigrationEndEvent m_clientMigrationEndEvent;
@@ -178,7 +183,6 @@ namespace Multiplayer
double m_serverSendAccumulator = 0.0;
float m_renderBlendFactor = 0.0f;
float m_tickFactor = 0.0f;
bool m_didHandshake = false;
bool m_spawnNetboundEntities = true;
#if !defined(AZ_RELEASE_BUILD)