-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathSteamServer.cs
156 lines (130 loc) · 5.95 KB
/
SteamServer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// This file is a 1:1 conversion from Tom Weilands Riptide Transport https://github.com/tom-weiland/RiptideSteamTransport/
using Steamworks;
using System;
using System.Collections.Generic;
using Godot;
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(OS.HasFeature("dedicated_server"))
SteamGameServerNetworkingUtils.InitRelayNetworkAccess();
else
SteamNetworkingUtils.InitRelayNetworkAccess();
}
catch (Exception ex)
{
GD.PrintErr(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:
GD.Print($"{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
GD.Print($"{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)
GD.Print($"{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);
}
}
}
}