using System; using Lidgren.Network; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Subsurface.Networking; using FarseerPhysics; using FarseerPhysics.Factories; using FarseerPhysics.Dynamics; using System.IO; using System.Collections.Generic; using RestSharp; namespace Subsurface { class ServerListScreen : Screen { //how often the client is allowed to refresh servers private TimeSpan AllowedRefreshInterval = new TimeSpan(0,0,3); private GUIFrame menu; private GUIListBox serverList; private GUIButton joinButton; private GUITextBox clientNameBox, ipBox; //private RestRequestAsyncHandle restRequestHandle; private bool masterServerResponded; private int[] columnX; //a timer for private DateTime refreshDisableTimer; private bool waitingForRefresh; public ServerListScreen() { int width = Math.Min(Game1.GraphicsWidth - 160, 1000); int height = Math.Min(Game1.GraphicsHeight - 160, 700); Rectangle panelRect = new Rectangle(0, 0, width, height); menu = new GUIFrame(panelRect, null, Alignment.Center, GUI.style); new GUITextBlock(new Rectangle(0, -25, 0, 30), "Join Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menu, false, GUI.LargeFont); new GUITextBlock(new Rectangle(0, 30, 0, 30), "Your Name:", GUI.style, menu); clientNameBox = new GUITextBox(new Rectangle(0, 60, 200, 30), GUI.style, menu); new GUITextBlock(new Rectangle(0, 100, 0, 30), "Server IP:", GUI.style, menu); ipBox = new GUITextBox(new Rectangle(0, 130, 200, 30), GUI.style, menu); int middleX = (int)(width * 0.4f); serverList = new GUIListBox(new Rectangle(middleX,60,0,(int)(height*0.7f)), GUI.style, menu); serverList.OnSelected = SelectServer; float[] columnRelativeX = new float[] { 0.15f, 0.55f, 0.15f, 0.15f }; columnX = new int[columnRelativeX.Length]; for (int n = 0; n < columnX.Length; n++) { columnX[n] = (int)(columnRelativeX[n] * serverList.Rect.Width); if (n > 0) columnX[n] += columnX[n - 1]; } new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Password", GUI.style, menu); new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.style, menu); new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.style, menu); new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Running", GUI.style, menu); joinButton = new GUIButton(new Rectangle(-170, 0, 150, 30), "Refresh", Alignment.BottomRight, GUI.style, menu); joinButton.OnClicked = RefreshServers; joinButton = new GUIButton(new Rectangle(0,0,150,30), "Join", Alignment.BottomRight, GUI.style, menu); joinButton.OnClicked = JoinServer; refreshDisableTimer = DateTime.Now; } public override void Select() { base.Select(); //RefreshServers(null, null); //UpdateServerList(); } private bool SelectServer(object obj) { string ip = obj as string; if (string.IsNullOrWhiteSpace(ip)) return false; ipBox.Text = ip; return true; } private bool RefreshServers(GUIButton button, object obj) { if (waitingForRefresh) return false; serverList.ClearChildren(); new GUITextBlock(new Rectangle(0, 0, 0, 20), "Refreshing server list...", GUI.style, serverList); CoroutineManager.StartCoroutine(WaitForRefresh()); return true; } private IEnumerable WaitForRefresh() { waitingForRefresh = true; if (refreshDisableTimer > DateTime.Now) { yield return new WaitForSeconds((float)(refreshDisableTimer - DateTime.Now).TotalSeconds); } //CoroutineManager.StartCoroutine(UpdateServerList()); CoroutineManager.StartCoroutine(SendMasterServerRequest()); waitingForRefresh = false; refreshDisableTimer = DateTime.Now + AllowedRefreshInterval; yield return Status.Success; } private void UpdateServerList(string masterServerData) { serverList.ClearChildren(); //string masterServerData = GetMasterServerData(); if (string.IsNullOrWhiteSpace(masterServerData)) { var nameText = new GUITextBlock(new Rectangle(0, 0, 0, 20), "Couldn't find any servers", GUI.style, serverList); return; } if (masterServerData.Substring(0,5).ToLower()=="error") { DebugConsole.ThrowError("Error while connecting to master server ("+masterServerData+")!"); return; } string[] lines = masterServerData.Split('\n'); for (int i = 0; i 3) ? arguments[3] : ""; string playerCountStr = (arguments.Length > 4) ? arguments[4] : ""; string hasPassWordStr = (arguments.Length > 5) ? arguments[5] : ""; var serverFrame = new GUIFrame(new Rectangle(0,0,0,20), (i%2 == 0) ? Color.Transparent : Color.White*0.2f, null, serverList); serverFrame.UserData = IP+":"+port; serverFrame.HoverColor = Color.Gold * 0.2f; serverFrame.SelectedColor = Color.Gold * 0.5f; var passwordBox = new GUITickBox(new Rectangle(columnX[0]/2, 0, 20, 20), "", Alignment.TopLeft, serverFrame); passwordBox.Selected = hasPassWordStr == "1"; passwordBox.Enabled = false; passwordBox.UserData = "password"; var nameText = new GUITextBlock(new Rectangle(columnX[0], 0, 0, 0), serverName, GUI.style, serverFrame); int playerCount, maxPlayers; playerCount = GameClient.ByteToPlayerCount((byte)int.Parse(playerCountStr), out maxPlayers); var playerCountText = new GUITextBlock(new Rectangle(columnX[1], 0, 0, 0), playerCount + "/" + maxPlayers, GUI.style, serverFrame); var gameStartedBox = new GUITickBox(new Rectangle(columnX[2] + (columnX[3] - columnX[2])/ 2, 0, 20, 20), "", Alignment.TopLeft, serverFrame); gameStartedBox.Selected = gameStarted == "1"; gameStartedBox.Enabled = false; } } private IEnumerable SendMasterServerRequest() { RestClient client = null; try { client = new RestClient(NetworkMember.MasterServerUrl); } catch (Exception e) { DebugConsole.ThrowError("Error while connecting to master server", e); } if (client == null) yield return Status.Success; var request = new RestRequest("masterserver.php", Method.GET); request.AddParameter("gamename", "subsurface"); // adds to POST or URL querystring based on Method request.AddParameter("action", "listservers"); // adds to POST or URL querystring based on Method // easily add HTTP Headers //request.AddHeader("header", "value"); //// add files to upload (works with compatible verbs) //request.AddFile(path); // execute the request masterServerResponded = false; var restRequestHandle = client.ExecuteAsync(request, response => MasterServerCallBack(response)); DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 8); while (!masterServerResponded) { if (DateTime.Now > timeOut) { serverList.ClearChildren(); restRequestHandle.Abort(); DebugConsole.ThrowError("Couldn't connect to master server (request timed out)"); } yield return Status.Running; } yield return Status.Success; } private void MasterServerCallBack(IRestResponse response) { masterServerResponded = true; if (response.ErrorException!=null) { serverList.ClearChildren(); DebugConsole.ThrowError("Error while connecting to master server", response.ErrorException); return; } if (response.StatusCode!= System.Net.HttpStatusCode.OK) { serverList.ClearChildren(); DebugConsole.ThrowError("Error while connecting to master server (" +response.StatusCode+": "+response.StatusDescription+")"); return; } UpdateServerList(response.Content); } private bool JoinServer(GUIButton button, object obj) { if (string.IsNullOrWhiteSpace(clientNameBox.Text)) { clientNameBox.Flash(); return false; } string ip = ipBox.Text; if (string.IsNullOrWhiteSpace(ip)) { ipBox.Flash(); return false; } CoroutineManager.StartCoroutine(JoinServer(ip)); return true; } private IEnumerable JoinServer(string ip) { string selectedPassword = ""; if ((serverList.Selected.GetChild("password") as GUITickBox).Selected) { var msgBox = new GUIMessageBox("Password required", ""); var passwordBox = new GUITextBox(new Rectangle(0,0,150,20), Alignment.BottomCenter, GUI.style, msgBox); passwordBox.UserData = "password"; var okButton = msgBox.GetChild(); while (GUIMessageBox.MessageBoxes.Contains(msgBox)) { okButton.Enabled = !string.IsNullOrWhiteSpace(passwordBox.Text); yield return Status.Running; } selectedPassword = passwordBox.Text; } Game1.NetworkMember = new GameClient(clientNameBox.Text); Game1.Client.ConnectToServer(ip, selectedPassword); Game1.NetLobbyScreen.Select(); yield return Status.Success; } public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { graphics.Clear(Color.CornflowerBlue); Game1.GameScreen.DrawMap(graphics, spriteBatch); spriteBatch.Begin(); menu.Draw(spriteBatch); //if (previewPlayer!=null) previewPlayer.Draw(spriteBatch); GUI.Draw((float)deltaTime, spriteBatch, null); spriteBatch.End(); } public override void Update(double deltaTime) { menu.Update((float)deltaTime); GUI.Update((float)deltaTime); } } }