Merge pull request #1425 from aws-lumberyard-dev/mp_systemcomp_cleanup

Cleanup and consolidate MultiplayerSystemComponent and add StopListening to AzNetworking
This commit is contained in:
AMZN-puvvadar
2021-06-22 10:03:20 -07:00
committed by GitHub
14 changed files with 178 additions and 69 deletions
@@ -143,13 +143,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);
}
}
@@ -82,6 +82,7 @@ namespace Multiplayer
AZ_CVAR(AZ::CVarFixedString, sv_gamerules, "norules", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "GameRules server works with");
AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking");
AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server");
AZ_CVAR(bool, sv_isTransient, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether a dedicated server shuts down if all existing connections disconnect.");
AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything");
AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update");
AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects");
@@ -200,14 +201,40 @@ namespace Multiplayer
AZ::TickBus::Handler::BusDisconnect();
}
bool MultiplayerSystemComponent::StartHosting(uint16_t port, bool isDedicated)
{
InitializeMultiplayer(isDedicated ? MultiplayerAgentType::DedicatedServer : MultiplayerAgentType::ClientServer);
return m_networkInterface->Listen(port);
}
bool MultiplayerSystemComponent::Connect(AZStd::string remoteAddress, uint16_t port)
{
InitializeMultiplayer(MultiplayerAgentType::Client);
const IpAddress address(remoteAddress.c_str(), port, m_networkInterface->GetType());
return m_networkInterface->Connect(address) != InvalidConnectionId;
}
void MultiplayerSystemComponent::Terminate()
{
auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); };
m_networkInterface->GetConnectionSet().VisitConnections(visitor);
if (GetAgentType() == MultiplayerAgentType::DedicatedServer || GetAgentType() == MultiplayerAgentType::ClientServer)
{
m_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;
}
@@ -216,12 +243,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();
}
}
@@ -253,7 +275,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);
}
@@ -421,10 +443,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)))
{
@@ -654,14 +675,6 @@ 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)
{
@@ -675,17 +688,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)
if (m_networkInterface->GetConnectionSet().GetActiveConnectionCount() == 0)
{
m_shutdownEvent.Signal(m_networkInterface);
if (AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get() != nullptr)
{
AZ::Interface<AzFramework::ISessionHandlingProviderRequests>::Get()->HandleDestroySession();
}
Terminate();
}
}
}
@@ -697,6 +714,16 @@ namespace Multiplayer
void MultiplayerSystemComponent::InitializeMultiplayer(MultiplayerAgentType multiplayerType)
{
if (m_agentType == multiplayerType)
{
return;
}
if (m_agentType != MultiplayerAgentType::Uninitialized && multiplayerType != MultiplayerAgentType::Uninitialized)
{
AZLOG_WARN("Attemping to InitializeMultiplayer from one initialized type to another. Your session may not have been properly torn down.");
}
if (m_agentType == MultiplayerAgentType::Uninitialized)
{
if (multiplayerType == MultiplayerAgentType::ClientServer || multiplayerType == MultiplayerAgentType::DedicatedServer)
@@ -916,49 +943,39 @@ 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()->StartHosting(sv_port, sv_isDedicated);
}
AZ_CONSOLEFREEFUNC(host, AZ::ConsoleFunctorFlags::DontReplicate, "Opens a multiplayer connection as a host for other clients to connect to");
void connect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
INetworkInterface* networkInterface = AZ::Interface<INetworking>::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName));
if (arguments.size() < 1)
{
const AZ::CVarFixedString remoteAddress = cl_serveraddr;
const IpAddress ipAddress(remoteAddress.c_str(), cl_serverport, networkInterface->GetType());
networkInterface->Connect(ipAddress);
return;
AZ::Interface<IMultiplayer>::Get()->Connect(remoteAddress.c_str(), cl_serverport);
}
AZ::CVarFixedString remoteAddress{ arguments.front() };
const AZStd::size_t portSeparator = remoteAddress.find_first_of(':');
if (portSeparator == AZStd::string::npos)
else
{
AZLOG_INFO("Remote address %s was malformed", remoteAddress.c_str());
return;
AZ::CVarFixedString remoteAddress{ arguments.front() };
const AZStd::size_t portSeparator = remoteAddress.find_first_of(':');
if (portSeparator == AZStd::string::npos)
{
AZLOG_INFO("Remote address %s was malformed", remoteAddress.c_str());
return;
}
char* mutableAddress = remoteAddress.data();
mutableAddress[portSeparator] = '\0';
const char* addressStr = mutableAddress;
const char* portStr = &(mutableAddress[portSeparator + 1]);
int32_t portNumber = atol(portStr);
AZ::Interface<IMultiplayer>::Get()->Connect(addressStr, portNumber);
}
char* mutableAddress = remoteAddress.data();
mutableAddress[portSeparator] = '\0';
const char* addressStr = mutableAddress;
const char* portStr = &(mutableAddress[portSeparator + 1]);
int32_t portNumber = atol(portStr);
const IpAddress ipAddress(addressStr, aznumeric_cast<uint16_t>(portNumber), networkInterface->GetType());
networkInterface->Connect(ipAddress);
}
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);
AZ::Interface<IMultiplayer>::Get()->Terminate();
}
AZ_CONSOLEFREEFUNC(disconnect, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects any open multiplayer connections");
}
@@ -112,6 +112,9 @@ namespace Multiplayer
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
bool StartHosting(uint16_t port, bool isDedicated = true) override;
bool Connect(AZStd::string remoteAddress, uint16_t port) override;
void Terminate() override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
AZ::TimeMs GetCurrentHostTimeMs() const override;
INetworkTime* GetNetworkTime() override;