/
Program.cs
227 lines (194 loc) · 8.97 KB
/
Program.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Microsoft.Playfab.Gaming.GSDK.CSharp;
using Newtonsoft.Json;
namespace WindowsRunnerCSharp
{
///-------------------------------------------------------------------------------
/// Simple executable that integrates with PlayFab's Gameserver SDK (GSDK).
/// It starts an http server that will respond to GET requests with a json file
/// containing whatever configuration values it read from the GSDK.
///-------------------------------------------------------------------------------
class Program
{
private static HttpListener _listener = new HttpListener();
const string ListeningPortKey = "gameport";
const string AssetFilePath = @"C:\Assets\testassetfile.txt";
private const string GameCertAlias = "winRunnerTestCert";
private static List<ConnectedPlayer> players = new List<ConnectedPlayer>();
private static int requestCount = 0;
private static bool _isActivated = false;
private static string _assetFileText = String.Empty;
private static string _installedCertThumbprint = String.Empty;
private static DateTimeOffset _nextMaintenance = DateTimeOffset.MinValue;
static void OnShutdown()
{
LogMessage("Shutting down...");
_listener.Stop();
_listener.Close();
}
static bool IsHealthy()
{
// Should return whether this game server is healthy
return true;
}
static void OnMaintenanceScheduled(DateTimeOffset time)
{
LogMessage($"Maintenance Scheduled at: {time}");
_nextMaintenance = time;
}
static void Main(string[] args)
{
// GSDK Setup
try
{
GameserverSDK.Start();
}
catch (Microsoft.Playfab.Gaming.GSDK.CSharp.GSDKInitializationException initEx)
{
LogMessage("Cannot start GSDK. Please make sure the MockAgent is running. ", false);
LogMessage($"Got Exception: {initEx.ToString()}", false);
return;
}
catch (Exception ex)
{
LogMessage($"Got Exception: {ex.ToString()}", false);
}
GameserverSDK.RegisterShutdownCallback(OnShutdown);
GameserverSDK.RegisterHealthCallback(IsHealthy);
GameserverSDK.RegisterMaintenanceCallback(OnMaintenanceScheduled);
// Read our asset file
if (File.Exists(AssetFilePath))
{
_assetFileText = File.ReadAllText(AssetFilePath);
}
IDictionary<string, string> initialConfig = GameserverSDK.getConfigSettings();
// Start the http server
if (initialConfig?.ContainsKey(ListeningPortKey) == true)
{
int listeningPort = int.Parse(initialConfig[ListeningPortKey]);
string address = $"http://*:{listeningPort}/";
_listener.Prefixes.Add(address);
_listener.Start();
}
else
{
LogMessage($"Cannot find {ListeningPortKey} in GSDK Config Settings. Please make sure the MockAgent is running " +
$"and that the MultiplayerSettings.json file includes {ListeningPortKey} as a GamePort Name.");
return;
}
// Load our game certificate if it was installed
if (initialConfig?.ContainsKey(GameCertAlias) == true)
{
string expectedThumbprint = initialConfig[GameCertAlias];
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificateCollection = store.Certificates.Find(X509FindType.FindByThumbprint, expectedThumbprint, false);
if (certificateCollection.Count > 0)
{
_installedCertThumbprint = certificateCollection[0].Thumbprint;
}
else
{
LogMessage("Could not find installed game cert in LocalMachine\\My. Expected thumbprint is: " + expectedThumbprint);
}
}
else
{
LogMessage("Config did not contain cert! Config is: " + string.Join(";", initialConfig.Select(x => x.Key + "=" + x.Value)));
}
Thread t = new Thread(ProcessRequests);
t.Start();
if (GameserverSDK.ReadyForPlayers())
{
_isActivated = true;
// After allocation, we can grab the session cookie from the config
IDictionary<string, string> activeConfig = GameserverSDK.getConfigSettings();
if (activeConfig.TryGetValue(GameserverSDK.SessionCookieKey, out string sessionCookie))
{
LogMessage($"The session cookie from the allocation call is: {sessionCookie}");
}
}
else
{
// No allocation happened, the server is getting terminated (likely because there are too many already in standing by)
LogMessage("Server is getting terminated.");
}
}
/// <summary>
/// Listens for any requests and responds with the game server's config values
/// </summary>
private static void ProcessRequests()
{
while (_listener.IsListening)
{
try
{
HttpListenerContext context = _listener.GetContext();
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string requestMessage = $"HTTP:Received {request.Headers.ToString()}";
LogMessage(requestMessage);
IDictionary<string, string> config = null;
// For each request, "add" a connected player, but limit player count to 20.
const int maxPlayers = 20;
if (players.Count < maxPlayers )
{
players.Add(new ConnectedPlayer("gamer" + requestCount));
}
else
{
LogMessage($"Player not added since max of {maxPlayers} is reached. Current request count: {requestCount}.");
}
requestCount++;
GameserverSDK.UpdateConnectedPlayers(players);
config = GameserverSDK.getConfigSettings() ?? new Dictionary<string, string>();
config.Add("isActivated", _isActivated.ToString());
config.Add("assetFileText", _assetFileText);
config.Add("logsDirectory", GameserverSDK.GetLogsDirectory());
config.Add("installedCertThumbprint", _installedCertThumbprint);
if (_isActivated)
{
IList<string> players = GameserverSDK.GetInitialPlayers();
config.Add("players", players == null ? "NULL" : string.Join(", ", players));
}
config.Add("connectionInfo", JsonConvert.SerializeObject(GameserverSDK.GetGameServerConnectionInfo()));
if (_nextMaintenance != DateTimeOffset.MinValue)
{
config.Add("nextMaintenance", _nextMaintenance.ToLocalTime().ToString());
}
string content = JsonConvert.SerializeObject(config, Formatting.Indented);
response.AddHeader("Content-Type", "application/json");
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(content);
response.ContentLength64 = buffer.Length;
using (System.IO.Stream output = response.OutputStream)
{
output.Write(buffer, 0, buffer.Length);
}
}
catch (HttpListenerException httpEx)
{
// This one is expected if we stopped the listener because we were asked to shutdown
LogMessage($"Got HttpListenerException: {httpEx.ToString()}, we are being shut down.");
}
catch (Exception ex)
{
LogMessage($"Got Exception: {ex.ToString()}");
}
}
}
private static void LogMessage(string message, bool enableGSDKLogging = true)
{
Console.WriteLine(message);
if (enableGSDKLogging)
{
GameserverSDK.LogMessage(message);
}
}
}
}