Cleanup and consolidate MPSystemComponent and add StopListening to AzNetworking

This commit is contained in:
puvvadar
2021-06-17 16:17:36 -07:00
parent a86524122d
commit a748c2e152
9 changed files with 103 additions and 59 deletions
@@ -88,6 +88,11 @@ namespace AzNetworking
//! @return boolean true if the packet is confirmed acknowledged, false if the packet number is out of range, lost, or still pending acknowledgment
virtual bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) = 0;
//! Closes the network interface to stop accepting new incoming connections.
//! @param port the listen port number this network interface will potentially bind to, 0 if it's a don't care
//! @return boolean true if the operation was successful, false if it failed
virtual bool StopListening() = 0;
//! Disconnects the specified connection.
//! @param connectionId identifier of the connection to terminate
//! @param reason reason for the disconnect
@@ -162,6 +162,12 @@ namespace AzNetworking
return connection->WasPacketAcked(packetId);
}
bool TcpNetworkInterface::StopListening()
{
m_port = 0;
return m_listenThread.StopListening(*this);
}
bool TcpNetworkInterface::Disconnect(ConnectionId connectionId, DisconnectReason reason)
{
IConnection* connection = m_connectionSet.GetConnection(connectionId);
@@ -63,6 +63,7 @@ namespace AzNetworking
bool SendReliablePacket(ConnectionId connectionId, const IPacket& packet) override;
PacketId SendUnreliablePacket(ConnectionId connectionId, const IPacket& packet) override;
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
//! @}
@@ -359,6 +359,21 @@ namespace AzNetworking
return connection->WasPacketAcked(packetId);
}
bool UdpNetworkInterface::StopListening()
{
if (!m_socket->IsOpen())
{
AZ_Assert(false, "StopListen cannot be invoked on an already closed network interface");
return false;
}
m_port = 0;
m_readerThread.UnregisterSocket(m_socket.get());
m_allowIncomingConnections = false;
m_socket->Close();
return true;
}
bool UdpNetworkInterface::Disconnect(ConnectionId connectionId, DisconnectReason reason)
{
IConnection* connection = m_connectionSet.GetConnection(connectionId);
@@ -60,6 +60,7 @@ namespace AzNetworking
bool SendReliablePacket(ConnectionId connectionId, const IPacket& packet) override;
PacketId SendUnreliablePacket(ConnectionId connectionId, const IPacket& packet) override;
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
//! @}
@@ -23,6 +23,7 @@
namespace AzNetworking
{
class INetworkInterface;
class IpAddress;
}
namespace Multiplayer
@@ -66,6 +67,19 @@ namespace Multiplayer
//! @param state The state of this connection
virtual void InitializeMultiplayer(MultiplayerAgentType state) = 0;
//! Starts hosting a server
//! @param port The port to listen for connection on
//! @param isDedicated Whether the server is dedicated or client hosted
virtual void StartHost(uint16_t port, bool isDedicated = true) = 0;
//! Connects to the specified IP as a Client
//! @param remoteAddress The domain or IP to connect to
//! @param port The port to connect to
virtual void Connect(AZStd::string remoteAddress, uint16_t port) = 0;
// Disconnects all multiplayer connections, stops listening on the server and invokes handlers appropriate to network context
virtual void Terminate() = 0;
//! Adds a ClientDisconnectedEvent Handler which is invoked on the client when a disconnection occurs
//! @param handler The ClientDisconnectedEvent Handler to add
virtual void AddClientDisconnectedHandler(ClientDisconnectedEvent::Handler& handler) = 0;
@@ -20,6 +20,7 @@
#include <AzCore/Utils/Utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <AzFramework/Session/ISessionHandlingRequests.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzNetworking/ConnectionLayer/IConnection.h>
#include <AzNetworking/Framework/INetworking.h>
@@ -143,13 +144,7 @@ namespace Multiplayer
console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound)
{
// Connect the Editor to the editor server for Multiplayer simulation
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
INetworkInterface* networkInterface =
AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType());
networkInterface->Connect(ipAddress);
AZ::Interface<IMultiplayer>::Get()->Connect(remoteAddress.c_str(), remotePort);
AZ::Interface<IMultiplayer>::Get()->SendReadyForEntityUpdates(true);
}
}
@@ -201,14 +201,43 @@ namespace Multiplayer
AZ::TickBus::Handler::BusDisconnect();
}
void MultiplayerSystemComponent::StartHost(uint16_t port, bool isDedicated)
{
InitializeMultiplayer(isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
networkInterface->Listen(port);
}
void MultiplayerSystemComponent::Connect(AZStd::string remoteAddress, uint16_t port)
{
InitializeMultiplayer(MultiplayerAgentType::Client);
const IpAddress address(remoteAddress.c_str(), port, m_networkInterface->GetType());
m_networkInterface->Connect(address);
}
void MultiplayerSystemComponent::Terminate()
{
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); };
networkInterface->GetConnectionSet().VisitConnections(visitor);
if (GetAgentType() == MultiplayerAgentType::DedicatedServer || GetAgentType() == MultiplayerAgentType::ClientServer)
{
networkInterface->StopListening();
m_shutdownEvent.Signal(m_networkInterface);
if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get() != nullptr)
{
AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get()->HandleDestroySession();
}
}
InitializeMultiplayer(MultiplayerAgentType::Uninitialized);
}
bool MultiplayerSystemComponent::RequestPlayerJoinSession(const AzFramework::SessionConnectionConfig& config)
{
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
m_pendingConnectionTickets.push(config.m_playerSessionId);
AZStd::string hostname = config.m_dnsName.empty() ? config.m_ipAddress : config.m_dnsName;
const IpAddress ipAddress(hostname.c_str(), config.m_port, m_networkInterface->GetType());
m_networkInterface->Connect(ipAddress);
Connect(hostname.c_str(), config.m_port);
return true;
}
@@ -217,12 +246,7 @@ namespace Multiplayer
{
if (GetAgentType() == MultiplayerAgentType::Client)
{
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Uninitialized);
auto visitor = [](IConnection& connection)
{
connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local);
};
m_networkInterface->GetConnectionSet().VisitConnections(visitor);
Terminate();
}
}
@@ -254,7 +278,7 @@ namespace Multiplayer
}
Multiplayer::MultiplayerAgentType serverType = sv_isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer;
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(serverType);
InitializeMultiplayer(serverType);
return m_networkInterface->Listen(sessionConfig.m_port);
}
@@ -422,10 +446,9 @@ namespace Multiplayer
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); };
m_networkInterface->GetConnectionSet().VisitConnections(visitor);
return true;
}
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->SetProviderTicket(packet.GetTicket().c_str());
}
}
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->SetProviderTicket(packet.GetTicket().c_str());
if (connection->SendReliablePacket(MultiplayerPackets::Accept(InvalidHostId, sv_map)))
{
@@ -655,17 +678,10 @@ namespace Multiplayer
m_clientDisconnectedEvent.Signal();
}
// Clean up any multiplayer connection data we've bound to this connection instance
if (connection->GetUserData() != nullptr)
{
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
delete connectionData;
connection->SetUserData(nullptr);
}
// Signal to session management that a user has left the server
if (m_agentType == MultiplayerAgentType::DedicatedServer || m_agentType == MultiplayerAgentType::ClientServer)
{
if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get() != nullptr &&
connection->GetConnectionRole() == ConnectionRole::Acceptor)
{
@@ -676,17 +692,21 @@ namespace Multiplayer
}
}
// Clean up any multiplayer connection data we've bound to this connection instance
if (connection->GetUserData() != nullptr)
{
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
delete connectionData;
connection->SetUserData(nullptr);
}
// Signal to session management when there are no remaining players in a dedicated server for potential cleanup
// We avoid this for client server as the host itself is a user
if (m_agentType == MultiplayerAgentType::DedicatedServer && connection->GetConnectionRole() == ConnectionRole::Acceptor)
// We avoid this for client server as the host itself is a user and non-transient dedicated servers
if (sv_isTransient && m_agentType == MultiplayerAgentType::DedicatedServer && connection->GetConnectionRole() == ConnectionRole::Acceptor)
{
if (m_networkInterface->GetConnectionSet().GetConnectionCount() == 0)
{
m_shutdownEvent.Signal(m_networkInterface);
if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get() != nullptr)
{
AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get()->HandleDestroySession();
}
Terminate();
}
}
}
@@ -917,30 +937,18 @@ namespace Multiplayer
void host([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
Multiplayer::MultiplayerAgentType serverType = sv_isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer;
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(serverType);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
networkInterface->Listen(sv_port);
AZ::Interface<IMultiplayer>::Get()->StartHost(sv_port, sv_isDedicated);
}
AZ_CONSOLEFREEFUNC(host, AZ::ConsoleFunctorFlags::DontReplicate, "Opens a multiplayer connection as a host for other clients to connect to");
void stophost([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Uninitialized);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
networkInterface->StopListening();
}
AZ_CONSOLEFREEFUNC(stophost, AZ::ConsoleFunctorFlags::DontReplicate, "Closes a multiplayer connection as a host for other clients to connect to");
void connect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
AzFramework::SessionConnectionConfig config;
AzNetworking::IpAddress address;
if (arguments.size() < 1)
{
const AZ::CVarFixedString remoteAddress = cl_serveraddr;
config.m_ipAddress = remoteAddress;
config.m_port = cl_serverport;
AZ::Interface<IMultiplayer>::Get()->Connect(remoteAddress.c_str(), cl_serverport);
}
else
{
@@ -956,21 +964,16 @@ namespace Multiplayer
const char* addressStr = mutableAddress;
const char* portStr = &(mutableAddress[portSeparator + 1]);
int32_t portNumber = atol(portStr);
config.m_ipAddress = addressStr;
config.m_port = portNumber;
AZ::Interface<IMultiplayer>::Get()->Connect(addressStr, portNumber);
}
AZ::Interface<AzFramework::ISessionHandlingClientRequests>::Get()->RequestPlayerJoinSession(config);
}
AZ_CONSOLEFREEFUNC(connect, AZ::ConsoleFunctorFlags::DontReplicate, "Opens a multiplayer connection to a remote host");
void disconnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Uninitialized);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); };
networkInterface->GetConnectionSet().VisitConnections(visitor);
networkInterface->StopListening();
AZ::Interface<IMultiplayer>::Get()->Terminate();
}
AZ_CONSOLEFREEFUNC(disconnect, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects any open multiplayer connections");
}
@@ -37,6 +37,7 @@ namespace AzFramework
namespace AzNetworking
{
class INetworkInterface;
class IpAddress;
}
namespace Multiplayer
@@ -112,6 +113,9 @@ namespace Multiplayer
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
void StartHost(uint16_t port, bool isDedicated = true) override;
void Connect(AZStd::string remoteAddress, uint16_t port) override;
void Terminate() override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
AZ::TimeMs GetCurrentHostTimeMs() const override;
INetworkTime* GetNetworkTime() override;