Files
K-C-Multiplayer/RiptideSteamTransport/Transport/SteamServer.cs
2025-12-13 14:28:35 +01:00

161 lines
6.1 KiB
C#

// This file is provided under The MIT License as part of RiptideSteamTransport.
// Copyright (c) Tom Weiland
// For additional information please see the included LICENSE.md file or view it on GitHub:
// https://github.com/tom-weiland/RiptideSteamTransport/blob/main/LICENSE.md
using Steamworks;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Riptide.Transports.Steam
{
public class SteamServer : SteamPeer, IServer
{
public event EventHandler<ConnectedEventArgs> Connected;
public event EventHandler<DataReceivedEventArgs> DataReceived;
public event EventHandler<DisconnectedEventArgs> Disconnected;
public ushort Port { get; private set; }
private Dictionary<CSteamID, SteamConnection> connections;
private HSteamListenSocket listenSocket;
private Callback<SteamNetConnectionStatusChangedCallback_t> connectionStatusChanged;
public void Start(ushort port)
{
Port = port;
connections = new Dictionary<CSteamID, SteamConnection>();
connectionStatusChanged = Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
try
{
#if UNITY_SERVER
SteamGameServerNetworkingUtils.InitRelayNetworkAccess();
#else
SteamNetworkingUtils.InitRelayNetworkAccess();
#endif
}
catch (Exception ex)
{
Debug.LogException(ex);
}
SteamNetworkingConfigValue_t[] options = new SteamNetworkingConfigValue_t[] { };
listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(port, options.Length, options);
}
private void OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t callback)
{
CSteamID clientSteamId = callback.m_info.m_identityRemote.GetSteamID();
switch (callback.m_info.m_eState)
{
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting:
Accept(callback.m_hConn);
break;
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connected:
Add(new SteamConnection(clientSteamId, callback.m_hConn, this));
break;
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ClosedByPeer:
SteamNetworkingSockets.CloseConnection(callback.m_hConn, 0, "Closed by peer", false);
OnDisconnected(clientSteamId, DisconnectReason.Disconnected);
break;
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
SteamNetworkingSockets.CloseConnection(callback.m_hConn, 0, "Problem detected", false);
OnDisconnected(clientSteamId, DisconnectReason.TransportError);
break;
default:
Debug.Log($"{LogName}: {clientSteamId}'s connection state changed - {callback.m_info.m_eState}");
break;
}
}
internal void Add(SteamConnection connection)
{
if (!connections.ContainsKey(connection.SteamId))
{
connections.Add(connection.SteamId, connection);
OnConnected(connection);
}
else
Debug.Log($"{LogName}: Connection from {connection.SteamId} could not be accepted: Already connected");
}
private void Accept(HSteamNetConnection connection)
{
EResult result = SteamNetworkingSockets.AcceptConnection(connection);
if (result != EResult.k_EResultOK)
Debug.LogWarning($"{LogName}: Connection could not be accepted: {result}");
}
public void Close(Connection connection)
{
if (connection is SteamConnection steamConnection)
{
SteamNetworkingSockets.CloseConnection(steamConnection.SteamNetConnection, 0, "Disconnected by server", false);
connections.Remove(steamConnection.SteamId);
}
}
public void Poll()
{
foreach (SteamConnection connection in connections.Values)
Receive(connection);
}
// TODO: disable nagle so this isn't needed
//public void Flush()
//{
// foreach (SteamConnection connection in connections.Values)
// SteamNetworkingSockets.FlushMessagesOnConnection(connection.SteamNetConnection);
//}
public void Shutdown()
{
if (connectionStatusChanged != null)
{
connectionStatusChanged.Dispose();
connectionStatusChanged = null;
}
foreach (SteamConnection connection in connections.Values)
SteamNetworkingSockets.CloseConnection(connection.SteamNetConnection, 0, "Server stopped", false);
connections.Clear();
SteamNetworkingSockets.CloseListenSocket(listenSocket);
}
protected internal virtual void OnConnected(Connection connection)
{
Connected?.Invoke(this, new ConnectedEventArgs(connection));
}
protected override void OnDataReceived(byte[] dataBuffer, int amount, SteamConnection fromConnection)
{
if ((MessageHeader)dataBuffer[0] == MessageHeader.Connect)
{
if (fromConnection.DidReceiveConnect)
return;
fromConnection.DidReceiveConnect = true;
}
DataReceived?.Invoke(this, new DataReceivedEventArgs(dataBuffer, amount, fromConnection));
}
protected virtual void OnDisconnected(CSteamID steamId, DisconnectReason reason)
{
if (connections.TryGetValue(steamId, out SteamConnection connection))
{
Disconnected?.Invoke(this, new DisconnectedEventArgs(connection, reason));
connections.Remove(steamId);
}
}
}
}