1 #region Copyright & License Information 2 /* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10 #endregion 11 12 using System; 13 using System.Linq; 14 using System.Net; 15 using OpenRA.Network; 16 using OpenRA.Primitives; 17 using OpenRA.Widgets; 18 19 namespace OpenRA.Mods.Common.Widgets.Logic 20 { 21 public class ServerCreationLogic : ChromeLogic 22 { 23 readonly Widget panel; 24 readonly LabelWidget noticesLabelA, noticesLabelB, noticesLabelC; 25 readonly Action onCreate; 26 readonly Action onExit; 27 MapPreview preview = MapCache.UnknownMap; 28 bool advertiseOnline; 29 30 [ObjectCreator.UseCtor] ServerCreationLogic(Widget widget, ModData modData, Action onExit, Action openLobby)31 public ServerCreationLogic(Widget widget, ModData modData, Action onExit, Action openLobby) 32 { 33 panel = widget; 34 onCreate = openLobby; 35 this.onExit = onExit; 36 37 var settings = Game.Settings; 38 preview = modData.MapCache[modData.MapCache.ChooseInitialMap(Game.Settings.Server.Map, Game.CosmeticRandom)]; 39 40 panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; 41 panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin; 42 43 var mapButton = panel.GetOrNull<ButtonWidget>("MAP_BUTTON"); 44 if (mapButton != null) 45 { 46 panel.Get<ButtonWidget>("MAP_BUTTON").OnClick = () => 47 { 48 Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs() 49 { 50 { "initialMap", preview.Uid }, 51 { "initialTab", MapClassification.System }, 52 { "onExit", () => { } }, 53 { "onSelect", (Action<string>)(uid => preview = modData.MapCache[uid]) }, 54 { "filter", MapVisibility.Lobby }, 55 { "onStart", () => { } } 56 }); 57 }; 58 59 panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => preview; 60 61 var titleLabel = panel.GetOrNull<LabelWithTooltipWidget>("MAP_TITLE"); 62 if (titleLabel != null) 63 { 64 var font = Game.Renderer.Fonts[titleLabel.Font]; 65 var title = new CachedTransform<MapPreview, string>(m => WidgetUtils.TruncateText(m.Title, titleLabel.Bounds.Width, font)); 66 titleLabel.GetText = () => title.Update(preview); 67 titleLabel.GetTooltipText = () => preview.Title; 68 } 69 70 var typeLabel = panel.GetOrNull<LabelWidget>("MAP_TYPE"); 71 if (typeLabel != null) 72 { 73 var type = new CachedTransform<MapPreview, string>(m => m.Categories.FirstOrDefault() ?? ""); 74 typeLabel.GetText = () => type.Update(preview); 75 } 76 77 var authorLabel = panel.GetOrNull<LabelWidget>("MAP_AUTHOR"); 78 if (authorLabel != null) 79 { 80 var font = Game.Renderer.Fonts[authorLabel.Font]; 81 var author = new CachedTransform<MapPreview, string>( 82 m => WidgetUtils.TruncateText("Created by {0}".F(m.Author), authorLabel.Bounds.Width, font)); 83 authorLabel.GetText = () => author.Update(preview); 84 } 85 } 86 87 var serverName = panel.Get<TextFieldWidget>("SERVER_NAME"); 88 serverName.Text = Settings.SanitizedServerName(settings.Server.Name); 89 serverName.OnEnterKey = () => { serverName.YieldKeyboardFocus(); return true; }; 90 serverName.OnLoseFocus = () => 91 { 92 serverName.Text = Settings.SanitizedServerName(serverName.Text); 93 settings.Server.Name = serverName.Text; 94 }; 95 96 panel.Get<TextFieldWidget>("LISTEN_PORT").Text = settings.Server.ListenPort.ToString(); 97 98 advertiseOnline = Game.Settings.Server.AdvertiseOnline; 99 100 var advertiseCheckbox = panel.Get<CheckboxWidget>("ADVERTISE_CHECKBOX"); 101 advertiseCheckbox.IsChecked = () => advertiseOnline; 102 advertiseCheckbox.OnClick = () => 103 { 104 advertiseOnline ^= true; 105 BuildNotices(); 106 }; 107 108 var passwordField = panel.GetOrNull<PasswordFieldWidget>("PASSWORD"); 109 if (passwordField != null) 110 passwordField.Text = Game.Settings.Server.Password; 111 112 noticesLabelA = panel.GetOrNull<LabelWidget>("NOTICES_HEADER_A"); 113 noticesLabelB = panel.GetOrNull<LabelWidget>("NOTICES_HEADER_B"); 114 noticesLabelC = panel.GetOrNull<LabelWidget>("NOTICES_HEADER_C"); 115 116 var noticesNoUPnP = panel.GetOrNull("NOTICES_NO_UPNP"); 117 if (noticesNoUPnP != null) 118 { 119 noticesNoUPnP.IsVisible = () => advertiseOnline && 120 (UPnP.Status == UPnPStatus.NotSupported || UPnP.Status == UPnPStatus.Disabled); 121 122 var settingsA = noticesNoUPnP.GetOrNull("SETTINGS_A"); 123 if (settingsA != null) 124 settingsA.IsVisible = () => UPnP.Status == UPnPStatus.Disabled; 125 126 var settingsB = noticesNoUPnP.GetOrNull("SETTINGS_B"); 127 if (settingsB != null) 128 settingsB.IsVisible = () => UPnP.Status == UPnPStatus.Disabled; 129 } 130 131 var noticesUPnP = panel.GetOrNull("NOTICES_UPNP"); 132 if (noticesUPnP != null) 133 noticesUPnP.IsVisible = () => advertiseOnline && UPnP.Status == UPnPStatus.Enabled; 134 135 var noticesLAN = panel.GetOrNull("NOTICES_LAN"); 136 if (noticesLAN != null) 137 noticesLAN.IsVisible = () => !advertiseOnline; 138 139 BuildNotices(); 140 } 141 BuildNotices()142 void BuildNotices() 143 { 144 if (noticesLabelA == null || noticesLabelB == null || noticesLabelC == null) 145 return; 146 147 if (advertiseOnline) 148 { 149 noticesLabelA.Text = "Internet Server (UPnP "; 150 var aWidth = Game.Renderer.Fonts[noticesLabelA.Font].Measure(noticesLabelA.Text).X; 151 noticesLabelA.Bounds.Width = aWidth; 152 153 var status = UPnP.Status; 154 noticesLabelB.Text = status == UPnPStatus.Enabled ? "Enabled" : 155 status == UPnPStatus.NotSupported ? "Not Supported" : "Disabled"; 156 157 noticesLabelB.TextColor = status == UPnPStatus.Enabled ? ChromeMetrics.Get<Color>("NoticeSuccessColor") : 158 status == UPnPStatus.NotSupported ? ChromeMetrics.Get<Color>("NoticeErrorColor") : 159 ChromeMetrics.Get<Color>("NoticeInfoColor"); 160 161 var bWidth = Game.Renderer.Fonts[noticesLabelB.Font].Measure(noticesLabelB.Text).X; 162 noticesLabelB.Bounds.X = noticesLabelA.Bounds.Right; 163 noticesLabelB.Bounds.Width = bWidth; 164 noticesLabelB.Visible = true; 165 166 noticesLabelC.Text = "):"; 167 noticesLabelC.Bounds.X = noticesLabelB.Bounds.Right; 168 noticesLabelC.Visible = true; 169 } 170 else 171 { 172 noticesLabelA.Text = "Local Server:"; 173 noticesLabelB.Visible = false; 174 noticesLabelC.Visible = false; 175 } 176 } 177 CreateAndJoin()178 void CreateAndJoin() 179 { 180 var name = Settings.SanitizedServerName(panel.Get<TextFieldWidget>("SERVER_NAME").Text); 181 int listenPort; 182 if (!Exts.TryParseIntegerInvariant(panel.Get<TextFieldWidget>("LISTEN_PORT").Text, out listenPort)) 183 listenPort = 1234; 184 185 var passwordField = panel.GetOrNull<PasswordFieldWidget>("PASSWORD"); 186 var password = passwordField != null ? passwordField.Text : ""; 187 188 // Save new settings 189 Game.Settings.Server.Name = name; 190 Game.Settings.Server.ListenPort = listenPort; 191 Game.Settings.Server.AdvertiseOnline = advertiseOnline; 192 Game.Settings.Server.Map = preview.Uid; 193 Game.Settings.Server.Password = password; 194 Game.Settings.Save(); 195 196 // Take a copy so that subsequent changes don't affect the server 197 var settings = Game.Settings.Server.Clone(); 198 199 // Create and join the server 200 try 201 { 202 Game.CreateServer(settings); 203 } 204 catch (System.Net.Sockets.SocketException e) 205 { 206 var message = "Could not listen on port {0}.".F(Game.Settings.Server.ListenPort); 207 208 // AddressAlreadyInUse (WSAEADDRINUSE) 209 if (e.ErrorCode == 10048) 210 message += "\nCheck if the port is already being used."; 211 else 212 message += "\nError is: \"{0}\" ({1})".F(e.Message, e.ErrorCode); 213 214 ConfirmationDialogs.ButtonPrompt("Server Creation Failed", message, onCancel: () => { }, cancelText: "Back"); 215 return; 216 } 217 218 Ui.CloseWindow(); 219 ConnectionLogic.Connect(IPAddress.Loopback.ToString(), Game.Settings.Server.ListenPort, password, onCreate, onExit); 220 } 221 } 222 } 223