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:
@@ -47,5 +47,9 @@ namespace AzNetworking
|
||||
//! Returns the current total connection count for this connection set
|
||||
//! @return the current total connection count for this connection set
|
||||
virtual uint32_t GetConnectionCount() const = 0;
|
||||
|
||||
//! Returns the current total count of connections not pending disconnect for this connection set
|
||||
//! @return the current total count of connections not pending disconnect for this connection set
|
||||
virtual uint32_t GetActiveConnectionCount() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ 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.
|
||||
//! @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
|
||||
|
||||
@@ -114,6 +114,24 @@ namespace AzNetworking
|
||||
return aznumeric_cast<uint32_t>(m_connectionIdMap.size());
|
||||
}
|
||||
|
||||
uint32_t TcpConnectionSet::GetActiveConnectionCount() const
|
||||
{
|
||||
uint32_t activeConnections = 0;
|
||||
for (auto iter = m_connectionIdMap.begin(); iter != m_connectionIdMap.end(); ++iter)
|
||||
{
|
||||
if (iter->second.get())
|
||||
{
|
||||
ConnectionState state = iter->second.get()->GetConnectionState();
|
||||
if (state == ConnectionState::Connected || state == ConnectionState::Connecting)
|
||||
{
|
||||
++activeConnections;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return activeConnections;
|
||||
}
|
||||
|
||||
TcpConnection* TcpConnectionSet::GetConnection(SocketFd socketFd) const
|
||||
{
|
||||
SocketFdMap::const_iterator lookup = m_socketFdMap.find(socketFd);
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace AzNetworking
|
||||
IConnection* GetConnection(ConnectionId connectionId) const override;
|
||||
ConnectionId GetNextConnectionId() override;
|
||||
uint32_t GetConnectionCount() const override;
|
||||
uint32_t GetActiveConnectionCount() const override;
|
||||
//! @}
|
||||
|
||||
//! Retrieves a connection from this connection list instance by socket fd.
|
||||
|
||||
@@ -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;
|
||||
//! @}
|
||||
|
||||
|
||||
@@ -111,6 +111,24 @@ namespace AzNetworking
|
||||
return aznumeric_cast<uint32_t>(m_connectionIdMap.size());
|
||||
}
|
||||
|
||||
uint32_t UdpConnectionSet::GetActiveConnectionCount() const
|
||||
{
|
||||
uint32_t activeConnections = 0;
|
||||
for (auto iter = m_connectionIdMap.begin(); iter != m_connectionIdMap.end(); ++iter)
|
||||
{
|
||||
if (iter->second.get())
|
||||
{
|
||||
ConnectionState state = iter->second.get()->GetConnectionState();
|
||||
if (state == ConnectionState::Connected || state == ConnectionState::Connecting)
|
||||
{
|
||||
++activeConnections;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return activeConnections;
|
||||
}
|
||||
|
||||
UdpConnection* UdpConnectionSet::GetConnection(const IpAddress& address) const
|
||||
{
|
||||
RemoteAddressMap::const_iterator lookup = m_remoteAddressMap.find(address);
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace AzNetworking
|
||||
IConnection* GetConnection(ConnectionId connectionId) const override;
|
||||
ConnectionId GetNextConnectionId() override;
|
||||
uint32_t GetConnectionCount() const override;
|
||||
uint32_t GetActiveConnectionCount() const override;
|
||||
//! @}
|
||||
|
||||
//! Retrieves a connection from this connection list instance by endpoint remote address
|
||||
|
||||
@@ -116,17 +116,29 @@ namespace AzNetworking
|
||||
|
||||
m_port = port;
|
||||
m_allowIncomingConnections = true;
|
||||
m_socket->Open(m_port, UdpSocket::CanAcceptConnections::True, m_trustZone);
|
||||
m_readerThread.RegisterSocket(m_socket.get());
|
||||
return true;
|
||||
if (m_socket->Open(m_port, UdpSocket::CanAcceptConnections::True, m_trustZone))
|
||||
{
|
||||
m_readerThread.RegisterSocket(m_socket.get());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionId UdpNetworkInterface::Connect(const IpAddress& remoteAddress)
|
||||
{
|
||||
if (!m_socket->IsOpen())
|
||||
{
|
||||
m_socket->Open(m_port, UdpSocket::CanAcceptConnections::False, m_trustZone);
|
||||
m_readerThread.RegisterSocket(m_socket.get());
|
||||
if (m_socket->Open(m_port, UdpSocket::CanAcceptConnections::False, m_trustZone))
|
||||
{
|
||||
m_readerThread.RegisterSocket(m_socket.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
return InvalidConnectionId;
|
||||
}
|
||||
}
|
||||
|
||||
const ConnectionId connectionId = m_connectionSet.GetNextConnectionId();
|
||||
@@ -359,6 +371,20 @@ namespace AzNetworking
|
||||
return connection->WasPacketAcked(packetId);
|
||||
}
|
||||
|
||||
bool UdpNetworkInterface::StopListening()
|
||||
{
|
||||
if (!m_socket->IsOpen())
|
||||
{
|
||||
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;
|
||||
//! @}
|
||||
|
||||
|
||||
@@ -66,6 +66,21 @@ 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
|
||||
//! @return if the application successfully started hosting
|
||||
virtual bool StartHosting(uint16_t port, bool isDedicated = true) = 0;
|
||||
|
||||
//! Connects to the specified IP as a Client
|
||||
//! @param remoteAddress The domain or IP to connect to
|
||||
//! @param port The port to connect to
|
||||
//! @result if a connection was successfully created
|
||||
virtual bool Connect(AZStd::string remoteAddress, uint16_t port) = 0;
|
||||
|
||||
// Disconnects all multiplayer connections, stops listening on the server and invokes handlers appropriate to network context
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user