public void OnPlayerAdded(string playfabId) { if (_connectedPlayers != null) { _connectedPlayers.Add(new ConnectedPlayer(playfabId)); GameserverSDK.UpdateConnectedPlayers(_connectedPlayers); GameserverSDK.LogMessage("GameServer added player: " + playfabId); } }
public void OnPlayerRemoved(string playfabId) { if (_connectedPlayers != null) { ConnectedPlayer player = _connectedPlayers.Find(x => x.PlayerId.Equals(playfabId, StringComparison.OrdinalIgnoreCase)); _connectedPlayers.Remove(player); GameserverSDK.UpdateConnectedPlayers(_connectedPlayers); GameserverSDK.LogMessage("GameServer removed player: " + player.PlayerId); //PlayFabMultiplayerAgentAPI.UpdateConnectedPlayers(_connectedPlayers); } }
void UpdatePlayFabPlayers() { List <ConnectedPlayer> listPfPlayers = new List <ConnectedPlayer>(); foreach (KeyValuePair <IClient, Player> player in players) { listPfPlayers.Add(new ConnectedPlayer(player.Value.playerName)); } GameserverSDK.UpdateConnectedPlayers(listPfPlayers); }
public static void ProcessPlayerList() { // Update player list if dirty if (PlayersIsDirty) { PlayersIsDirty = false; List <ConnectedPlayer> lstPlayers = new List <ConnectedPlayer>(); foreach (var keyValuePair in Players) { lstPlayers.Add(new ConnectedPlayer(keyValuePair.Value)); } GameserverSDK.UpdateConnectedPlayers(lstPlayers); } }
// starts main game process and wait for it to complete public static void InitiateAndWaitForGameProcess(string gameserverExe, IEnumerable <string> args) { // here we're starting the script that initiates the game process gameProcess = StartProcess(gameserverExe, args); // as part of wrapping the main game server executable, // we create event handlers to process the output from the game (standard output/standard error) // based on this output, we will activate the server and process connected players gameProcess.OutputDataReceived += DataReceived; gameProcess.ErrorDataReceived += DataReceived; // start reading output (stdout/stderr) from the game gameProcess.BeginOutputReadLine(); gameProcess.BeginErrorReadLine(); // Call this when your game is done initializing and players can connect // Note: This is a blocking call, and will return when this game server is either allocated or terminated if (GameserverSDK.ReadyForPlayers()) { // After allocation, we can grab the session cookie from the config IDictionary <string, string> activeConfig = GameserverSDK.getConfigSettings(); var connectedPlayers = new List <ConnectedPlayer>(); // initial players includes the list of the players that are allowed to connect to the game // they might or might not end up connecting // in this sample we're nevertheless adding them to the list foreach (var player in GameserverSDK.GetInitialPlayers()) { connectedPlayers.Add(new ConnectedPlayer(player)); } GameserverSDK.UpdateConnectedPlayers(connectedPlayers); 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."); gameProcess?.Kill(); // we still need to call WaitForExit https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.kill?view=netcore-3.1#remarks } // wait till it exits or crashes gameProcess.WaitForExit(); }
// runs when we received data (stdout/stderr) from our game server process public static void DataReceived(object sender, DataReceivedEventArgs e) { Console.WriteLine(e.Data); // used for debug purposes only - you can use `docker logs <container_id> to see the stdout logs if (e.Data.Contains("Opening IP socket")) { // Call this when your game is done initializing and players can connect // Note: This is a blocking call, and will return when this game server is either allocated or terminated if (GameserverSDK.ReadyForPlayers()) { // 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."); gameProcess?.Kill(); // we still need to call WaitForExit https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.kill?view=netcore-3.1#remarks } } else if (e.Data.Contains("ClientBegin:")) // new player connected { players.Add(new ConnectedPlayer("gamer" + new Random().Next(0, 21))); GameserverSDK.UpdateConnectedPlayers(players); } else if (e.Data.Contains("ClientDisconnect:")) // player disconnected { players.RemoveAt(new Random().Next(0, players.Count)); GameserverSDK.UpdateConnectedPlayers(players); // some games may need to exit if player count is zero } else if (e.Data.Contains("AAS shutdown")) // game changes map { players.Clear(); GameserverSDK.UpdateConnectedPlayers(players); } }
/// <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 (_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()}"); } } }
static void Main(string[] args) { // Test startup GameserverSDK.Start(); GameserverSDK.RegisterShutdownCallback(() => Console.WriteLine("Server is shutting me down!!!!!")); GameserverSDK.RegisterHealthCallback(getIsHealthy); GameserverSDK.RegisterMaintenanceCallback(maintenanceScheduled); // Test grabbing config Console.WriteLine("Config before Active."); foreach (var config in GameserverSDK.getConfigSettings()) { Console.WriteLine($"{config.Key}: {config.Value}"); } if (GameserverSDK.ReadyForPlayers()) { IList <string> initialPlayers = GameserverSDK.GetInitialPlayers(); Console.WriteLine("Initial Players: " + string.Join(",", initialPlayers)); List <ConnectedPlayer> players = new List <ConnectedPlayer>() { new ConnectedPlayer("player1"), new ConnectedPlayer("player2") }; GameserverSDK.UpdateConnectedPlayers(players); Console.WriteLine("Config after Active."); foreach (var config in GameserverSDK.getConfigSettings()) { Console.WriteLine($"{config.Key}: {config.Value}"); } // Print a rainbow int size = 13; for (int i = 0; i < 5; i++) { String edge = new String(new char[size]).Replace('\0', ' '); String middle = new String(new char[2 * i]).Replace('\0', ' '); Console.WriteLine(edge + "====" + middle + "=====" + edge); size--; } for (int i = 0; i < 4; i++) { String edge = new String(new char[size]).Replace('\0', ' '); String middle = new String(new char[10]).Replace('\0', ' '); Console.WriteLine(edge + "====" + middle + "=====" + edge); } // Leave running a bit more to see the heartbeats for (int i = 0; i < 10; i++) { Console.WriteLine("..."); System.Threading.Thread.Sleep(1000); } } else { Console.WriteLine("Did not activate, instead shutting down..."); } Console.WriteLine("Press enter to exit."); Console.ReadKey(); }
/// <summary> /// Listens for any requests and responds with the game host's config values /// </summary> /// <param name="config">The config values we're returning</param> private static void ProcessRequests() { while (_listener.IsListening) { try { HttpListenerContext context = _listener.GetContext(); HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; LogMessage(string.Format("HTTP:Received {0}", request.Headers.ToString())); 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>(); // First, check if we need to delay shutdown for testing if (config.TryGetValue(GameserverSDK.SessionCookieKey, out string sessionCookie) && sessionCookie.Equals("delayshutdown", StringComparison.OrdinalIgnoreCase)) { _delayShutdown = true; } // If the server has been allocated, add the list of players to the response. if (_isActivated) { config.Add("initialPlayers", string.Join(",", GameserverSDK.GetInitialPlayers())); } config.Add("isActivated", _isActivated.ToString()); config.Add("isShutdown", _isShutdown.ToString()); config.Add("assetFileText", _assetFileText); config.Add("logsDirectory", GameserverSDK.GetLogsDirectory()); config.Add("sharedContentDirectory", GameserverSDK.GetSharedContentDirectory()); config.Add("installedCertThumbprint", _installedCertThumbprint); config.Add("cmdArgs", _cmdArgs); if (_nextMaintenance != DateTimeOffset.MinValue) { config.Add("nextMaintenance", _nextMaintenance.ToLocalTime().ToString()); } foreach (GamePort portInformation in GameserverSDK.GetGameServerConnectionInfo().GamePortsConfiguration) { config.Add($"Public{portInformation.Name}", portInformation.ClientConnectionPort.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); } // Once we're shut down, return a response one more time (so the tests can // verify the _isShutdown field) and then actually terminate if (_isShutdown) { _listener.Stop(); _listener.Close(); } } catch (HttpListenerException httpEx) { // This one is expected if we stopped the listener because we were asked to shutdown LogMessage($"Got HttpListenerException: {httpEx.ToString()}, shutdown value is: {_isShutdown} "); } catch (Exception ex) { LogMessage($"Got Exception: {ex.ToString()}"); } } }
// starts main game process and wait for it to complete public static void InitiateAndWaitForGameProcess(string gameserverExe, IEnumerable <string> args) { // Here we're starting the script that initiates the game process activeConfig = GameserverSDK.getConfigSettings(); // When Wrapper is running in a container, Port Information (Port Name, Port Number, and Protocol) is already set as build configuration. // For example, if you already set port number as 80 in container build configuration, activeConfig will return 80 as port number. // But if Wrapper is running as a process, port will be mapped internally by MPS, so different number will be dynamically assigned. if (activeConfig.TryGetValue(portName, out string listeningPortString)) { GameserverSDK.LogMessage($"{portName}:{listeningPortString} was found in GSDK Config Settings."); _listeningPort = listeningPortString; } else { LogMessage($"Cannot find {portName} in GSDK Config Settings. Please make sure the LocalMultiplayerAgent is running " + $"and that the MultiplayerSettings.json file includes correct {portName} as a GamePort Name."); return; } // Check if there is any process already using the port (_listeningPort). This will only work for Windows. if (CheckIfPortIsUsed(gameserverExe)) { return; } ; // We pass port number as a 3rd argument when we start fakegame.exe // Port number is grabbed via GSDK and will be passed to fake game as a listening port. gameProcess = StartProcess(gameserverExe, string.Join(' ', args.Append(_listeningPort))); // as part of wrapping the main game server executable, // we create event handlers to process the output from the game (standard output/standard error) // based on this output, we will activate the server and process connected players gameProcess.OutputDataReceived += DataReceived; gameProcess.ErrorDataReceived += DataReceived; // start reading output (stdout/stderr) from the game gameProcess.BeginOutputReadLine(); gameProcess.BeginErrorReadLine(); // Call this when your game is done initializing and players can connect // Note: This is a blocking call, and will return when this game server is either allocated or terminated if (GameserverSDK.ReadyForPlayers()) { // After allocation, we can grab the session cookie from the config activeConfig = GameserverSDK.getConfigSettings(); var connectedPlayers = new List <ConnectedPlayer>(); // initial players includes the list of the players that are allowed to connect to the game // they might or might not end up connecting // in this sample we're nevertheless adding them to the list foreach (var player in GameserverSDK.GetInitialPlayers()) { connectedPlayers.Add(new ConnectedPlayer(player)); } GameserverSDK.UpdateConnectedPlayers(connectedPlayers); 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."); gameProcess?.Kill(); // we still need to call WaitForExit https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.kill?view=netcore-3.1#remarks } // wait till it exits or crashes gameProcess.WaitForExit(); }