complete password protected servers

closes #2290
This commit is contained in:
Matthias Mailänder
2013-10-05 13:02:47 +02:00
parent a6cdcea414
commit b618fc7cc2
17 changed files with 229 additions and 81 deletions

View File

@@ -49,9 +49,9 @@ namespace OpenRA
public static Renderer Renderer; public static Renderer Renderer;
public static bool HasInputFocus = false; public static bool HasInputFocus = false;
public static void JoinServer(string host, int port) public static void JoinServer(string host, int port, string password)
{ {
JoinInner(new OrderManager(host, port, JoinInner(new OrderManager(host, port, password,
new ReplayRecorderConnection(new NetworkConnection(host, port), ChooseReplayFilename))); new ReplayRecorderConnection(new NetworkConnection(host, port), ChooseReplayFilename)));
} }
@@ -70,12 +70,12 @@ namespace OpenRA
public static void JoinReplay(string replayFile) public static void JoinReplay(string replayFile)
{ {
JoinInner(new OrderManager("<no server>", -1, new ReplayConnection(replayFile))); JoinInner(new OrderManager("<no server>", -1, "", new ReplayConnection(replayFile)));
} }
static void JoinLocal() static void JoinLocal()
{ {
JoinInner(new OrderManager("<no server>", -1, new EchoConnection())); JoinInner(new OrderManager("<no server>", -1, "", new EchoConnection()));
} }
public static int RenderFrame = 0; public static int RenderFrame = 0;

View File

@@ -28,6 +28,7 @@ namespace OpenRA.GameRules
public int ListenPort = 1234; public int ListenPort = 1234;
public int ExternalPort = 1234; public int ExternalPort = 1234;
public bool AdvertiseOnline = true; public bool AdvertiseOnline = true;
public string Password = "";
public string MasterServer = "http://master.open-ra.org/"; public string MasterServer = "http://master.open-ra.org/";
public bool DiscoverNatDevices = false; // Allow users to disable NAT discovery if problems occur public bool DiscoverNatDevices = false; // Allow users to disable NAT discovery if problems occur
public bool AllowPortForward = true; // let the user disable it even if compatible devices are found public bool AllowPortForward = true; // let the user disable it even if compatible devices are found
@@ -51,6 +52,7 @@ namespace OpenRA.GameRules
ListenPort = other.ListenPort; ListenPort = other.ListenPort;
ExternalPort = other.ExternalPort; ExternalPort = other.ExternalPort;
AdvertiseOnline = other.AdvertiseOnline; AdvertiseOnline = other.AdvertiseOnline;
Password = other.Password;
MasterServer = other.MasterServer; MasterServer = other.MasterServer;
DiscoverNatDevices = other.DiscoverNatDevices; DiscoverNatDevices = other.DiscoverNatDevices;
AllowPortForward = other.AllowPortForward; AllowPortForward = other.AllowPortForward;

View File

@@ -135,7 +135,7 @@ namespace OpenRA.Network
{ {
var len = reader.ReadInt32(); var len = reader.ReadInt32();
var client = reader.ReadInt32(); var client = reader.ReadInt32();
var buf = reader.ReadBytes( len ); var buf = reader.ReadBytes(len);
if (len == 0) if (len == 0)
throw new NotImplementedException(); throw new NotImplementedException();
lock (this) lock (this)

View File

@@ -27,8 +27,10 @@ namespace OpenRA.Network
public readonly string Host; public readonly string Host;
public readonly int Port; public readonly int Port;
public readonly string Password = "";
public string ServerError = "Server is not responding."; public string ServerError = "Server is not responding";
public bool AuthenticationFailed = false;
public int NetFrameNumber { get; private set; } public int NetFrameNumber { get; private set; }
public int LocalFrameNumber; public int LocalFrameNumber;
@@ -52,10 +54,11 @@ namespace OpenRA.Network
Connection.Send(i, new List<byte[]>()); Connection.Send(i, new List<byte[]>());
} }
public OrderManager(string host, int port, IConnection conn) public OrderManager(string host, int port, string password, IConnection conn)
{ {
this.Host = host; Host = host;
this.Port = port; Port = port;
Password = password;
Connection = conn; Connection = conn;
syncReport = new SyncReport(this); syncReport = new SyncReport(this);
} }

14
OpenRA.Game/Network/UnitOrders.cs Executable file → Normal file
View File

@@ -51,9 +51,11 @@ namespace OpenRA.Network
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString); Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
break; break;
} }
case "Message": // Server message case "Message": // Server message
Game.AddChatLine(Color.White, "Server", order.TargetString); Game.AddChatLine(Color.White, "Server", order.TargetString);
break; break;
case "Disconnected": /* reports that the target player disconnected */ case "Disconnected": /* reports that the target player disconnected */
{ {
var client = orderManager.LobbyInfo.ClientWithIndex(clientId); var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
@@ -146,7 +148,7 @@ namespace OpenRA.Network
{ {
Client = info, Client = info,
Mods = localMods, Mods = localMods,
Password = "Foo" Password = orderManager.Password
}; };
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize())); orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize()));
@@ -156,6 +158,14 @@ namespace OpenRA.Network
case "ServerError": case "ServerError":
{ {
orderManager.ServerError = order.TargetString; orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = false;
break;
}
case "AuthenticationError":
{
orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = true;
break; break;
} }
@@ -195,11 +205,13 @@ namespace OpenRA.Network
break; break;
} }
case "Ping": case "Ping":
{ {
orderManager.IssueOrder(Order.Pong(order.TargetString)); orderManager.IssueOrder(Order.Pong(order.TargetString));
break; break;
} }
default: default:
{ {
if (!order.IsImmediate) if (!order.IsImmediate)

View File

@@ -239,6 +239,14 @@ namespace OpenRA.Server
var handshake = HandshakeResponse.Deserialize(data); var handshake = HandshakeResponse.Deserialize(data);
if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password)
{
var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password";
SendOrderTo(newConn, "AuthenticationError", message);
DropClient(newConn);
return;
}
var client = new Session.Client() var client = new Session.Client()
{ {
Name = handshake.Client.Name, Name = handshake.Client.Name,
@@ -270,7 +278,7 @@ namespace OpenRA.Server
Log.Write("server", "Rejected connection from {0}; mods do not match.", Log.Write("server", "Rejected connection from {0}; mods do not match.",
newConn.socket.RemoteEndPoint); newConn.socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "Your mods don't match the server"); SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod");
DropClient(newConn); DropClient(newConn);
return; return;
} }
@@ -283,7 +291,7 @@ namespace OpenRA.Server
Log.Write("server", "Rejected connection from {0}; Not running the same version.", Log.Write("server", "Rejected connection from {0}; Not running the same version.",
newConn.socket.RemoteEndPoint); newConn.socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "Not running the same version."); SendOrderTo(newConn, "ServerError", "Server is running an incompatible version");
DropClient(newConn); DropClient(newConn);
return; return;
} }
@@ -293,7 +301,7 @@ namespace OpenRA.Server
if (bans.Contains(client.IpAddress)) if (bans.Contains(client.IpAddress))
{ {
Log.Write("server", "Rejected connection from {0}; Banned.", newConn.socket.RemoteEndPoint); Log.Write("server", "Rejected connection from {0}; Banned.", newConn.socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "You are {0} from the server.".F(Settings.Ban.Contains(client.IpAddress) ? "banned" : "temporarily banned")); SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IpAddress) ? "banned" : "temporarily banned"));
DropClient(newConn); DropClient(newConn);
return; return;
} }

View File

@@ -137,6 +137,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
ConnectionLogic.Connect(IPAddress.Loopback.ToString(), ConnectionLogic.Connect(IPAddress.Loopback.ToString(),
Game.CreateLocalServer(map), Game.CreateLocalServer(map),
"",
() => OpenLobbyPanel(MenuType.Main, true), () => OpenLobbyPanel(MenuType.Main, true),
() => { Game.CloseServer(); menuType = MenuType.Main; }); () => { Game.CloseServer(); menuType = MenuType.Main; });
} }

View File

@@ -90,6 +90,7 @@ namespace OpenRA.Mods.RA
case "StartGame": case "StartGame":
case "Disconnected": case "Disconnected":
case "ServerError": case "ServerError":
case "AuthenticationError":
case "SyncInfo": case "SyncInfo":
return; return;
} }

View File

@@ -16,7 +16,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ {
public class ConnectionLogic public class ConnectionLogic
{ {
Action onConnect, onRetry, onAbort; Action onConnect, onAbort;
Action<string> onRetry;
void ConnectionStateChanged(OrderManager om) void ConnectionStateChanged(OrderManager om)
{ {
@@ -44,11 +45,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
} }
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public ConnectionLogic(Widget widget, string host, int port, Action onConnect, Action onRetry, Action onAbort) public ConnectionLogic(Widget widget, string host, int port, Action onConnect, Action onAbort, Action<string> onRetry)
{ {
this.onConnect = onConnect; this.onConnect = onConnect;
this.onRetry = onRetry;
this.onAbort = onAbort; this.onAbort = onAbort;
this.onRetry = onRetry;
Game.ConnectionStateChanged += ConnectionStateChanged; Game.ConnectionStateChanged += ConnectionStateChanged;
@@ -59,31 +60,81 @@ namespace OpenRA.Mods.RA.Widgets.Logic
"Connecting to {0}:{1}...".F(host, port); "Connecting to {0}:{1}...".F(host, port);
} }
public static void Connect(string host, int port, Action onConnect, Action onAbort) public static void Connect(string host, int port, string password, Action onConnect, Action onAbort)
{ {
Game.JoinServer(host, port); Game.JoinServer(host, port, password);
Action<string> onRetry = newPassword => Connect(host, port, newPassword, onConnect, onAbort);
Ui.OpenWindow("CONNECTING_PANEL", new WidgetArgs() Ui.OpenWindow("CONNECTING_PANEL", new WidgetArgs()
{ {
{ "host", host }, { "host", host },
{ "port", port }, { "port", port },
{ "onConnect", onConnect }, { "onConnect", onConnect },
{ "onAbort", onAbort }, { "onAbort", onAbort },
{ "onRetry", () => Connect(host, port, onConnect, onAbort) } { "onRetry", onRetry }
}); });
} }
} }
public class ConnectionFailedLogic public class ConnectionFailedLogic
{ {
PasswordFieldWidget passwordField;
bool passwordOffsetAdjusted;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public ConnectionFailedLogic(Widget widget, OrderManager orderManager, Action onRetry, Action onAbort) public ConnectionFailedLogic(Widget widget, OrderManager orderManager, Action onAbort, Action<string> onRetry)
{ {
var panel = widget; var panel = widget;
panel.Get<ButtonWidget>("ABORT_BUTTON").OnClick = () => { Ui.CloseWindow(); onAbort(); }; var abortButton = panel.Get<ButtonWidget>("ABORT_BUTTON");
panel.Get<ButtonWidget>("RETRY_BUTTON").OnClick = () => { Ui.CloseWindow(); onRetry(); }; var retryButton = panel.Get<ButtonWidget>("RETRY_BUTTON");
abortButton.OnClick = () => { Ui.CloseWindow(); onAbort(); };
retryButton.OnClick = () =>
{
var password = passwordField != null && passwordField.IsVisible() ? passwordField.Text : orderManager.Password;
Ui.CloseWindow();
onRetry(password);
};
widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () => widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () =>
"Could not connect to {0}:{1}\n{2}".F(orderManager.Host, orderManager.Port, orderManager.ServerError); "Could not connect to {0}:{1}".F(orderManager.Host, orderManager.Port);
var connectionError = widget.Get<LabelWidget>("CONNECTION_ERROR");
connectionError.GetText = () => orderManager.ServerError;
passwordField = panel.GetOrNull<PasswordFieldWidget>("PASSWORD");
if (passwordField != null)
{
passwordField.Text = orderManager.Password;
passwordField.IsVisible = () => orderManager.AuthenticationFailed;
var passwordLabel = widget.Get<LabelWidget>("PASSWORD_LABEL");
passwordLabel.IsVisible = passwordField.IsVisible;
}
passwordOffsetAdjusted = false;
var connectionFailedTicker = panel.GetOrNull<LogicTickerWidget>("CONNECTION_FAILED_TICKER");
if (connectionFailedTicker != null)
{
connectionFailedTicker.OnTick = () =>
{
// Adjust the dialog once the AuthenticationError is parsed.
if (passwordField.IsVisible() && !passwordOffsetAdjusted)
{
var offset = passwordField.Bounds.Y - connectionError.Bounds.Y;
abortButton.Bounds.Y += offset;
retryButton.Bounds.Y += offset;
panel.Bounds.Height += offset;
panel.Bounds.Y -= offset / 2;
var background = panel.GetOrNull("CONNECTION_BACKGROUND");
if (background != null)
background.Bounds.Height += offset;
passwordOffsetAdjusted = true;
}
};
}
} }
} }
} }

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Game.Settings.Save(); Game.Settings.Save();
Ui.CloseWindow(); Ui.CloseWindow();
ConnectionLogic.Connect(ipField.Text, port, openLobby, onExit); ConnectionLogic.Connect(ipField.Text, port, "", openLobby, onExit);
}; };
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };

View File

@@ -58,9 +58,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
}); });
}; };
Action onRetry = () => Action<string> onRetry = password =>
{ {
ConnectionLogic.Connect(om.Host, om.Port, onConnect, onExit); ConnectionLogic.Connect(om.Host, om.Port, password, onConnect, onExit);
}; };
Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs()

View File

@@ -109,13 +109,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic
void Join(GameServer server) void Join(GameServer server)
{ {
if (server == null || !server.CanJoin()) if (server == null || !server.CanJoin())
return; return;
var host = server.Address.Split(':')[0]; var host = server.Address.Split(':')[0];
var port = int.Parse(server.Address.Split(':')[1]); var port = int.Parse(server.Address.Split(':')[1]);
Ui.CloseWindow(); Ui.CloseWindow();
ConnectionLogic.Connect(host, port, OpenLobby, OnExit); ConnectionLogic.Connect(host, port, "", OpenLobby, OnExit);
} }
string GetPlayersLabel(GameServer game) string GetPlayersLabel(GameServer game)

View File

@@ -32,6 +32,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
this.onExit = onExit; this.onExit = onExit;
var settings = Game.Settings; var settings = Game.Settings;
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin; panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin;
@@ -71,6 +72,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
UPnPCheckbox.IsChecked = () => allowPortForward; UPnPCheckbox.IsChecked = () => allowPortForward;
UPnPCheckbox.OnClick = () => allowPortForward ^= true; UPnPCheckbox.OnClick = () => allowPortForward ^= true;
UPnPCheckbox.IsDisabled = () => !Game.Settings.Server.NatDeviceAvailable; UPnPCheckbox.IsDisabled = () => !Game.Settings.Server.NatDeviceAvailable;
var passwordField = panel.GetOrNull<PasswordFieldWidget>("PASSWORD");
if (passwordField != null)
passwordField.Text = Game.Settings.Server.Password;
} }
void CreateAndJoin() void CreateAndJoin()
@@ -83,6 +88,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (!int.TryParse(panel.Get<TextFieldWidget>("EXTERNAL_PORT").Text, out externalPort)) if (!int.TryParse(panel.Get<TextFieldWidget>("EXTERNAL_PORT").Text, out externalPort))
externalPort = 1234; externalPort = 1234;
var passwordField = panel.GetOrNull<PasswordFieldWidget>("PASSWORD");
var password = passwordField != null ? passwordField.Text : "";
// Save new settings // Save new settings
Game.Settings.Server.Name = name; Game.Settings.Server.Name = name;
Game.Settings.Server.ListenPort = listenPort; Game.Settings.Server.ListenPort = listenPort;
@@ -90,6 +98,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Game.Settings.Server.AdvertiseOnline = advertiseOnline; Game.Settings.Server.AdvertiseOnline = advertiseOnline;
Game.Settings.Server.AllowPortForward = allowPortForward; Game.Settings.Server.AllowPortForward = allowPortForward;
Game.Settings.Server.Map = map.Uid; Game.Settings.Server.Map = map.Uid;
Game.Settings.Server.Password = password;
Game.Settings.Save(); Game.Settings.Save();
// Take a copy so that subsequent changes don't affect the server // Take a copy so that subsequent changes don't affect the server
@@ -98,7 +107,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
// Create and join the server // Create and join the server
Game.CreateServer(settings); Game.CreateServer(settings);
Ui.CloseWindow(); Ui.CloseWindow();
ConnectionLogic.Connect(IPAddress.Loopback.ToString(), Game.Settings.Server.ListenPort, onCreate, onExit); ConnectionLogic.Connect(IPAddress.Loopback.ToString(), Game.Settings.Server.ListenPort, password, onCreate, onExit);
} }
} }
} }

View File

@@ -37,8 +37,9 @@ Container@CONNECTIONFAILED_PANEL:
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - 90)/2 Y:(WINDOW_BOTTOM - 90)/2
Width:370 Width:370
Height:125 Height:129
Children: Children:
LogicTicker@CONNECTION_FAILED_TICKER:
Label@TITLE: Label@TITLE:
Width:PARENT_RIGHT Width:PARENT_RIGHT
Y:0-25 Y:0-25
@@ -46,28 +47,48 @@ Container@CONNECTIONFAILED_PANEL:
Contrast:true Contrast:true
Align:Center Align:Center
Text:Connection Failed Text:Connection Failed
Background@bg: Background@CONNECTION_BACKGROUND:
Width:370 Width:370
Height:90 Height:85
Background:panel-black Background:panel-black
Children: Children:
Label@CONNECTING_DESC: Label@CONNECTING_DESC:
Y:(PARENT_BOTTOM-HEIGHT)/2 Y:15
Width:PARENT_RIGHT Width:PARENT_RIGHT
Height:25 Height:25
Text:Failed to connect Text:Failed to connect
Font:Bold Font:Bold
Align:Center Align:Center
Label@CONNECTION_ERROR:
Y:40
Width:PARENT_RIGHT
Height:25
Align:Center
Font:Bold
Label@PASSWORD_LABEL:
X:40
Y:79
Width:95
Height:25
Align:Right
Text:Password:
Font:Bold
PasswordField@PASSWORD:
X:140
Y:80
Width:155
MaxLength:20
Height:25
Button@RETRY_BUTTON: Button@RETRY_BUTTON:
Key:return Key:return
Y:89 Y:84
Width:140 Width:140
Height:35 Height:35
Text:Retry Text:Retry
Button@ABORT_BUTTON: Button@ABORT_BUTTON:
Key:escape Key:escape
X:230 X:230
Y:89 Y:84
Width:140 Width:140
Height:35 Height:35
Text:Abort Text:Abort

View File

@@ -2,37 +2,37 @@ Container@CREATESERVER_PANEL:
Logic:ServerCreationLogic Logic:ServerCreationLogic
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - 260)/2 Y:(WINDOW_BOTTOM - 260)/2
Width:604 Width:521
Height:295 Height:250
Children: Children:
Label@TITLE: Label@TITLE:
Text:Create Server Text:Create Server
Width:604 Width:PARENT_RIGHT
Y:0-25 Y:0-25
Font:BigBold Font:BigBold
Contrast:true Contrast:true
Align:Center Align:Center
Background@bg: Background@bg:
Width:604 Width:PARENT_RIGHT
Height:260 Height:215
Background:panel-black Background:panel-black
Children: Children:
Background@MAP_BG: Background@MAP_BG:
X:PARENT_RIGHT-WIDTH-15 X:PARENT_RIGHT-WIDTH-15
Y:15 Y:15
Width:194 Width:162
Height:194 Height:162
Background:panel-gray Background:panel-gray
Children: Children:
MapPreview@MAP_PREVIEW: MapPreview@MAP_PREVIEW:
X:1 X:1
Y:1 Y:1
Width:192 Width:160
Height:192 Height:160
Label@MAP_NAME: Label@MAP_NAME:
X:PARENT_RIGHT-WIDTH-15 X:PARENT_RIGHT-WIDTH-15
Y:220 Y:PARENT_BOTTOM - 33
Width:194 Width:162
Height:25 Height:25
Align:Center Align:Center
Font:Bold Font:Bold
@@ -46,67 +46,87 @@ Container@CREATESERVER_PANEL:
TextField@SERVER_NAME: TextField@SERVER_NAME:
X:110 X:110
Y:15 Y:15
Width:275 Width:215
MaxLength:50 MaxLength:50
Height:25 Height:25
Text:My OpenRA Server Text:My OpenRA Server
Label@PASSWORD_LABEL:
X:10
Y:49
Width:95
Height:25
Align:Right
Text:Password:
PasswordField@PASSWORD:
X:110
Y:50
Width:145
MaxLength:20
Height:25
Label@AFTER_PASSWORD_LABEL:
X:265
Y:49
Width:95
Height:25
Align:Left
Text:(optional)
Label@LISTEN_PORT_LABEL: Label@LISTEN_PORT_LABEL:
X:15 X:15
Y:119 Y:84
Width:90 Width:90
Height:25 Height:25
Align: Right Align: Right
Text:Port: Text:Port:
TextField@LISTEN_PORT: TextField@LISTEN_PORT:
X:110 X:110
Y:120 Y:85
Width:50
MaxLength:5
Height:25
Text:1234
Label@EXTERNAL_PORT_LABEL:
X:180
Y:84
Width:90
Height:25
Align:Right
Text:External Port:
TextField@EXTERNAL_PORT:
X:275
Y:85
Width:50 Width:50
MaxLength:5 MaxLength:5
Height:25 Height:25
Text:1234 Text:1234
Checkbox@ADVERTISE_CHECKBOX: Checkbox@ADVERTISE_CHECKBOX:
X:110 X:110
Y:155 Y:135
Width:150 Width:150
Height:20 Height:20
Text:Advertise Online Text:Advertise Online
Checkbox@UPNP_CHECKBOX: Checkbox@UPNP_CHECKBOX:
X:110 X:110
Y:180 Y:165
Width:300 Width:300
Height:20 Height:20
Text:Automatic port forwarding Text:Automatic port forwarding
Label@EXTERNAL_PORT_LABEL:
X:15
Y:219
Width:90
Height:25
Align:Right
Text:External Port:
TextField@EXTERNAL_PORT:
X:110
Y:220
Width:50
MaxLength:5
Height:25
Text:1234
Button@BACK_BUTTON: Button@BACK_BUTTON:
Key:escape Key:escape
X:0 X:0
Y:259 Y:214
Width:140 Width:140
Height:35 Height:35
Text:Back Text:Back
Button@MAP_BUTTON: Button@MAP_BUTTON:
X:314 X:231
Y:259 Y:214
Width:140 Width:140
Height:35 Height:35
Text:Choose Map Text:Choose Map
Button@CREATE_BUTTON: Button@CREATE_BUTTON:
Key:return Key:return
X:464 X:381
Y:259 Y:214
Width:140 Width:140
Height:35 Height:35
Text:Create Text:Create

View File

@@ -3,7 +3,7 @@ Container@DIRECTCONNECT_PANEL:
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - 90)/2 Y:(WINDOW_BOTTOM - 90)/2
Width:370 Width:370
Height:125 Height:130
Children: Children:
Label@TITLE: Label@TITLE:
Width:PARENT_RIGHT Width:PARENT_RIGHT
@@ -14,7 +14,7 @@ Container@DIRECTCONNECT_PANEL:
Text:Connect to Server Text:Connect to Server
Background@bg: Background@bg:
Width:370 Width:370
Height:90 Height:95
Background:panel-black Background:panel-black
Children: Children:
Label@ADDRESS_LABEL: Label@ADDRESS_LABEL:
@@ -44,14 +44,14 @@ Container@DIRECTCONNECT_PANEL:
Button@BACK_BUTTON: Button@BACK_BUTTON:
Key:escape Key:escape
X:0 X:0
Y:89 Y:94
Width:140 Width:140
Height:35 Height:35
Text:Back Text:Back
Button@JOIN_BUTTON: Button@JOIN_BUTTON:
Key:return Key:return
X:230 X:230
Y:89 Y:94
Width:140 Width:140
Height:35 Height:35
Text:Join Text:Join

View File

@@ -3,7 +3,7 @@ Background@CREATESERVER_BG:
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:400 Width:400
Height:240 Height:300
Children: Children:
Label@LABEL_TITLE: Label@LABEL_TITLE:
X:0 X:0
@@ -27,42 +27,62 @@ Background@CREATESERVER_BG:
MaxLength:50 MaxLength:50
Height:25 Height:25
Text:OpenRA Game Text:OpenRA Game
Label@EXTERNAL_PORT_LABEL: Label@PASSWORD_LABEL:
X:50 X:50
Y:94 Y:94
Width:95 Width:95
Height:25 Height:25
Align:Right
Text:Password:
PasswordField@PASSWORD:
X:150
Y:95
Width:145
MaxLength:20
Height:25
Label@AFTER_PASSWORD_LABEL:
X:300
Y:94
Width:95
Height:25
Align:Left
Text:(optional)
Label@EXTERNAL_PORT_LABEL:
X:50
Y:129
Width:95
Height:25
Align: Right Align: Right
Text:External Port: Text:External Port:
TextField@EXTERNAL_PORT: TextField@EXTERNAL_PORT:
X:150 X:150
Y:95 Y:130
Width:50 Width:50
MaxLength:5 MaxLength:5
Height:25 Height:25
Text:OpenRA Game Text:OpenRA Game
Label@LISTEN_PORT_LABEL: Label@LISTEN_PORT_LABEL:
X:210 X:210
Y:94 Y:129
Width:95 Width:95
Height:25 Height:25
Align: Right Align: Right
Text:Listen Port: Text:Listen Port:
TextField@LISTEN_PORT: TextField@LISTEN_PORT:
X:310 X:310
Y:95 Y:130
Width:50 Width:50
MaxLength:5 MaxLength:5
Height:25 Height:25
Checkbox@UPNP_CHECKBOX: Checkbox@UPNP_CHECKBOX:
X:150 X:150
Y:130 Y:165
Width:300 Width:300
Height:20 Height:20
Text:Automatic port forwarding Text:Automatic port forwarding
Checkbox@ADVERTISE_CHECKBOX: Checkbox@ADVERTISE_CHECKBOX:
X:150 X:150
Y:165 Y:200
Width:300 Width:300
Height:20 Height:20
Text:Advertise game Online Text:Advertise game Online