Port back to Mono.Nat and make discovery async.
This commit is contained in:
committed by
Paul Chote
parent
3f510b6d93
commit
d15e7f76fc
5
AUTHORS
5
AUTHORS
@@ -173,9 +173,8 @@ under the MIT license.
|
|||||||
Using FuzzyLogicLibrary (fuzzynet) by Dmitry
|
Using FuzzyLogicLibrary (fuzzynet) by Dmitry
|
||||||
Kaluzhny and released under the GNU GPL terms.
|
Kaluzhny and released under the GNU GPL terms.
|
||||||
|
|
||||||
Using Open.Nat by Lucas Ontivero, based on the work
|
Using Mono.Nat by Alan McGovern, Ben Motmans,
|
||||||
of Alan McGovern and Ben Motmans and distributed
|
Nicholas Terry distributed under the MIT license.
|
||||||
under the MIT license.
|
|
||||||
|
|
||||||
Using ICSharpCode.SharpZipLib initially by Mike
|
Using ICSharpCode.SharpZipLib initially by Mike
|
||||||
Krueger and distributed under the GNU GPL terms.
|
Krueger and distributed under the GNU GPL terms.
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ namespace OpenRA
|
|||||||
public static string EngineVersion { get; private set; }
|
public static string EngineVersion { get; private set; }
|
||||||
public static LocalPlayerProfile LocalPlayerProfile;
|
public static LocalPlayerProfile LocalPlayerProfile;
|
||||||
|
|
||||||
static Task discoverNat;
|
|
||||||
static bool takeScreenshot = false;
|
static bool takeScreenshot = false;
|
||||||
static Benchmark benchmark = null;
|
static Benchmark benchmark = null;
|
||||||
|
|
||||||
@@ -360,8 +359,7 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.Server.DiscoverNatDevices)
|
Nat.Initialize();
|
||||||
discoverNat = UPnP.DiscoverNatDevices(Settings.Server.NatDiscoveryTimeout);
|
|
||||||
|
|
||||||
var modSearchArg = args.GetValue("Engine.ModSearchPaths", null);
|
var modSearchArg = args.GetValue("Engine.ModSearchPaths", null);
|
||||||
var modSearchPaths = modSearchArg != null ?
|
var modSearchPaths = modSearchArg != null ?
|
||||||
@@ -472,16 +470,6 @@ namespace OpenRA
|
|||||||
|
|
||||||
JoinLocal();
|
JoinLocal();
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
discoverNat?.Wait();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("NAT discovery failed: {0}", e.Message);
|
|
||||||
Log.Write("nat", e.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
ChromeMetrics.TryGet("ChatMessageColor", out chatMessageColor);
|
ChromeMetrics.TryGet("ChatMessageColor", out chatMessageColor);
|
||||||
ChromeMetrics.TryGet("SystemMessageColor", out systemMessageColor);
|
ChromeMetrics.TryGet("SystemMessageColor", out systemMessageColor);
|
||||||
if (!ChromeMetrics.TryGet("SystemMessageLabel", out systemMessageLabel))
|
if (!ChromeMetrics.TryGet("SystemMessageLabel", out systemMessageLabel))
|
||||||
|
|||||||
101
OpenRA.Game/Network/Nat.cs
Normal file
101
OpenRA.Game/Network/Nat.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using Mono.Nat;
|
||||||
|
|
||||||
|
namespace OpenRA.Network
|
||||||
|
{
|
||||||
|
public enum NatStatus { Enabled, Disabled, NotSupported }
|
||||||
|
|
||||||
|
public class Nat
|
||||||
|
{
|
||||||
|
public static NatStatus Status => NatUtility.IsSearching ? natDevice != null ? NatStatus.Enabled : NatStatus.NotSupported : NatStatus.Disabled;
|
||||||
|
|
||||||
|
static Mapping mapping;
|
||||||
|
static INatDevice natDevice;
|
||||||
|
static bool initialized;
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if (initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Game.Settings.Server.DiscoverNatDevices)
|
||||||
|
{
|
||||||
|
NatUtility.DeviceFound += DeviceFound;
|
||||||
|
NatUtility.StartDiscovery();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly SemaphoreSlim Locker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
|
static async void DeviceFound(object sender, DeviceEventArgs args)
|
||||||
|
{
|
||||||
|
await Locker.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Only interact with one at a time. Some support both UPnP and NAT-PMP.
|
||||||
|
natDevice = args.Device;
|
||||||
|
|
||||||
|
Log.Write("nat", "Device found: {0}", natDevice.DeviceEndpoint);
|
||||||
|
Log.Write("nat", "Type: {0}", natDevice.NatProtocol);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Locker.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryForwardPort(int listen, int external)
|
||||||
|
{
|
||||||
|
if (natDevice == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lifetime = Game.Settings.Server.NatPortMappingLifetime;
|
||||||
|
mapping = new Mapping(Protocol.Tcp, listen, external, lifetime, "OpenRA");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
natDevice.CreatePortMap(mapping);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Port forwarding failed: {0}", e.Message);
|
||||||
|
Log.Write("nat", e.StackTrace);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryRemovePortForward()
|
||||||
|
{
|
||||||
|
if (natDevice == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
natDevice.DeletePortMap(mapping);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Port removal failed: {0}", e.Message);
|
||||||
|
Log.Write("nat", e.StackTrace);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
|
||||||
* available to you under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version. For more
|
|
||||||
* information, see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Open.Nat;
|
|
||||||
|
|
||||||
namespace OpenRA.Network
|
|
||||||
{
|
|
||||||
public enum UPnPStatus { Enabled, Disabled, NotSupported }
|
|
||||||
|
|
||||||
public class UPnP
|
|
||||||
{
|
|
||||||
static NatDevice natDevice;
|
|
||||||
static Mapping mapping;
|
|
||||||
static bool initialized;
|
|
||||||
|
|
||||||
public static IPAddress ExternalIP { get; private set; }
|
|
||||||
public static UPnPStatus Status =>
|
|
||||||
initialized ? natDevice != null ?
|
|
||||||
UPnPStatus.Enabled : UPnPStatus.NotSupported : UPnPStatus.Disabled;
|
|
||||||
|
|
||||||
public static async Task DiscoverNatDevices(int timeout)
|
|
||||||
{
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
NatDiscoverer.TraceSource.Switch.Level = SourceLevels.Verbose;
|
|
||||||
var logChannel = Log.Channel("nat");
|
|
||||||
NatDiscoverer.TraceSource.Listeners.Add(new TextWriterTraceListener(logChannel.Writer));
|
|
||||||
|
|
||||||
var natDiscoverer = new NatDiscoverer();
|
|
||||||
var token = new CancellationTokenSource(timeout);
|
|
||||||
natDevice = await natDiscoverer.DiscoverDeviceAsync(PortMapper.Upnp, token);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ExternalIP = await natDevice.GetExternalIPAsync();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Getting the external IP from NAT device failed: {0}", e.Message);
|
|
||||||
Log.Write("nat", e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ForwardPort(int listen, int external)
|
|
||||||
{
|
|
||||||
mapping = new Mapping(Protocol.Tcp, listen, external, "OpenRA");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await natDevice.CreatePortMapAsync(mapping);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Port forwarding failed: {0}", e.Message);
|
|
||||||
Log.Write("nat", e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task RemovePortForward()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await natDevice.DeletePortMapAsync(mapping);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Port removal failed: {0}", e.Message);
|
|
||||||
Log.Write("nat", e.StackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenRA-Eluant" Version="1.0.18" />
|
<PackageReference Include="OpenRA-Eluant" Version="1.0.18" />
|
||||||
<PackageReference Include="OpenRA-Open.NAT" Version="1.0.0" />
|
<PackageReference Include="Mono.NAT" Version="3.0.1" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.3.1" />
|
<PackageReference Include="SharpZipLib" Version="1.3.1" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||||
|
|||||||
@@ -221,8 +221,8 @@ namespace OpenRA.Server
|
|||||||
if (type != ServerType.Local && settings.EnableGeoIP)
|
if (type != ServerType.Local && settings.EnableGeoIP)
|
||||||
GeoIP.Initialize();
|
GeoIP.Initialize();
|
||||||
|
|
||||||
if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled)
|
if (type != ServerType.Local)
|
||||||
UPnP.ForwardPort(Settings.ListenPort, Settings.ListenPort).Wait();
|
Nat.TryForwardPort(Settings.ListenPort, Settings.ListenPort);
|
||||||
|
|
||||||
foreach (var trait in modData.Manifest.ServerTraits)
|
foreach (var trait in modData.Manifest.ServerTraits)
|
||||||
serverTraits.Add(modData.ObjectCreator.CreateObject<ServerTrait>(trait));
|
serverTraits.Add(modData.ObjectCreator.CreateObject<ServerTrait>(trait));
|
||||||
@@ -310,8 +310,8 @@ namespace OpenRA.Server
|
|||||||
if (State == ServerState.ShuttingDown)
|
if (State == ServerState.ShuttingDown)
|
||||||
{
|
{
|
||||||
EndGame();
|
EndGame();
|
||||||
if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled)
|
if (type != ServerType.Local)
|
||||||
UPnP.RemovePortForward().Wait();
|
Nat.TryRemovePortForward();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ namespace OpenRA
|
|||||||
[Desc("Locks the game with a password.")]
|
[Desc("Locks the game with a password.")]
|
||||||
public string Password = "";
|
public string Password = "";
|
||||||
|
|
||||||
[Desc("Allow users to enable NAT discovery for external IP detection and automatic port forwarding.")]
|
[Desc("Allow users to search UPnP/NAT-PMP enabled devices for automatic port forwarding.")]
|
||||||
public bool DiscoverNatDevices = false;
|
public bool DiscoverNatDevices = false;
|
||||||
|
|
||||||
[Desc("Time in milliseconds to search for UPnP enabled NAT devices.")]
|
[Desc("Time in seconds for UPnP/NAT-PMP mappings to last.")]
|
||||||
public int NatDiscoveryTimeout = 5000;
|
public int NatPortMappingLifetime = 36000;
|
||||||
|
|
||||||
[Desc("Starts the game with a default map. Input as hash that can be obtained by the utility.")]
|
[Desc("Starts the game with a default map. Input as hash that can be obtained by the utility.")]
|
||||||
public string Map = null;
|
public string Map = null;
|
||||||
|
|||||||
@@ -116,20 +116,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (noticesNoUPnP != null)
|
if (noticesNoUPnP != null)
|
||||||
{
|
{
|
||||||
noticesNoUPnP.IsVisible = () => advertiseOnline &&
|
noticesNoUPnP.IsVisible = () => advertiseOnline &&
|
||||||
(UPnP.Status == UPnPStatus.NotSupported || UPnP.Status == UPnPStatus.Disabled);
|
(Nat.Status == NatStatus.NotSupported || Nat.Status == NatStatus.Disabled);
|
||||||
|
|
||||||
var settingsA = noticesNoUPnP.GetOrNull("SETTINGS_A");
|
var settingsA = noticesNoUPnP.GetOrNull("SETTINGS_A");
|
||||||
if (settingsA != null)
|
if (settingsA != null)
|
||||||
settingsA.IsVisible = () => UPnP.Status == UPnPStatus.Disabled;
|
settingsA.IsVisible = () => Nat.Status == NatStatus.Disabled;
|
||||||
|
|
||||||
var settingsB = noticesNoUPnP.GetOrNull("SETTINGS_B");
|
var settingsB = noticesNoUPnP.GetOrNull("SETTINGS_B");
|
||||||
if (settingsB != null)
|
if (settingsB != null)
|
||||||
settingsB.IsVisible = () => UPnP.Status == UPnPStatus.Disabled;
|
settingsB.IsVisible = () => Nat.Status == NatStatus.Disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
var noticesUPnP = panel.GetOrNull("NOTICES_UPNP");
|
var noticesUPnP = panel.GetOrNull("NOTICES_UPNP");
|
||||||
if (noticesUPnP != null)
|
if (noticesUPnP != null)
|
||||||
noticesUPnP.IsVisible = () => advertiseOnline && UPnP.Status == UPnPStatus.Enabled;
|
noticesUPnP.IsVisible = () => advertiseOnline && Nat.Status == NatStatus.Enabled;
|
||||||
|
|
||||||
var noticesLAN = panel.GetOrNull("NOTICES_LAN");
|
var noticesLAN = panel.GetOrNull("NOTICES_LAN");
|
||||||
if (noticesLAN != null)
|
if (noticesLAN != null)
|
||||||
@@ -145,16 +145,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
if (advertiseOnline)
|
if (advertiseOnline)
|
||||||
{
|
{
|
||||||
noticesLabelA.Text = "Internet Server (UPnP ";
|
noticesLabelA.Text = "Internet Server (UPnP/NAT-PMP ";
|
||||||
var aWidth = Game.Renderer.Fonts[noticesLabelA.Font].Measure(noticesLabelA.Text).X;
|
var aWidth = Game.Renderer.Fonts[noticesLabelA.Font].Measure(noticesLabelA.Text).X;
|
||||||
noticesLabelA.Bounds.Width = aWidth;
|
noticesLabelA.Bounds.Width = aWidth;
|
||||||
|
|
||||||
var status = UPnP.Status;
|
noticesLabelB.Text = Nat.Status == NatStatus.Enabled ? "Enabled" :
|
||||||
noticesLabelB.Text = status == UPnPStatus.Enabled ? "Enabled" :
|
Nat.Status == NatStatus.NotSupported ? "Not Supported" : "Disabled";
|
||||||
status == UPnPStatus.NotSupported ? "Not Supported" : "Disabled";
|
|
||||||
|
|
||||||
noticesLabelB.TextColor = status == UPnPStatus.Enabled ? ChromeMetrics.Get<Color>("NoticeSuccessColor") :
|
noticesLabelB.TextColor = Nat.Status == NatStatus.Enabled ? ChromeMetrics.Get<Color>("NoticeSuccessColor") :
|
||||||
status == UPnPStatus.NotSupported ? ChromeMetrics.Get<Color>("NoticeErrorColor") :
|
Nat.Status == NatStatus.NotSupported ? ChromeMetrics.Get<Color>("NoticeErrorColor") :
|
||||||
ChromeMetrics.Get<Color>("NoticeInfoColor");
|
ChromeMetrics.Get<Color>("NoticeInfoColor");
|
||||||
|
|
||||||
var bWidth = Game.Renderer.Fonts[noticesLabelB.Font].Measure(noticesLabelB.Text).X;
|
var bWidth = Game.Renderer.Fonts[noticesLabelB.Font].Measure(noticesLabelB.Text).X;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using OpenRA.Network;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
|
|
||||||
namespace OpenRA.Server
|
namespace OpenRA.Server
|
||||||
@@ -56,6 +57,8 @@ namespace OpenRA.Server
|
|||||||
Game.InitializeSettings(arguments);
|
Game.InitializeSettings(arguments);
|
||||||
var settings = Game.Settings.Server;
|
var settings = Game.Settings.Server;
|
||||||
|
|
||||||
|
Nat.Initialize();
|
||||||
|
|
||||||
var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS");
|
var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS");
|
||||||
var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ?
|
var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ?
|
||||||
FieldLoader.GetValue<string[]>("MOD_SEARCH_PATHS", envModSearchPaths) :
|
FieldLoader.GetValue<string[]>("MOD_SEARCH_PATHS", envModSearchPaths) :
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - You can enable UPnP (if supported by your router) in the
|
Text: - You can enable UPnP/NAT-PMP (if supported by your router)
|
||||||
Label@SETTINGS_B:
|
Label@SETTINGS_B:
|
||||||
X: 7
|
X: 7
|
||||||
Y: 60
|
Y: 60
|
||||||
@@ -170,7 +170,7 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: Advanced tab of the OpenRA settings menu.
|
Text: in the Advanced tab of the settings menu.
|
||||||
Container@NOTICES_UPNP:
|
Container@NOTICES_UPNP:
|
||||||
X: 20
|
X: 20
|
||||||
Y: 145
|
Y: 145
|
||||||
@@ -196,14 +196,14 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - OpenRA will use UPnP to automaticaly configure port forwarding.
|
Text: - Game will automatically configure port forwarding.
|
||||||
Label@SETTINGS_A:
|
Label@SETTINGS_A:
|
||||||
Y: 36
|
Y: 36
|
||||||
Width: 305
|
Width: 305
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - You can disable UPnP in the OpenRA settings menu.
|
Text: - You can disable UPnP/NAT-PMP in the settings menu.
|
||||||
Background@MAP_BG:
|
Background@MAP_BG:
|
||||||
X: PARENT_RIGHT - 189
|
X: PARENT_RIGHT - 189
|
||||||
Y: 15
|
Y: 15
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Container@ADVANCED_PANEL:
|
|||||||
Width: 200
|
Width: 200
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Text: Enable Network Discovery (UPnP)
|
Text: Enable UPnP/NAT-PMP Discovery
|
||||||
Checkbox@PERFTEXT_CHECKBOX:
|
Checkbox@PERFTEXT_CHECKBOX:
|
||||||
X: 15
|
X: 15
|
||||||
Y: 73
|
Y: 73
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - You can enable UPnP (if supported by your router) in the
|
Text: - You can enable UPnP/NAT-PMP (if supported by your router)
|
||||||
Label@SETTINGS_B:
|
Label@SETTINGS_B:
|
||||||
X: 7
|
X: 7
|
||||||
Y: 60
|
Y: 60
|
||||||
@@ -165,7 +165,7 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: Advanced tab of the OpenRA settings menu.
|
Text: in the Advanced tab of the settings menu.
|
||||||
Container@NOTICES_UPNP:
|
Container@NOTICES_UPNP:
|
||||||
X: 25
|
X: 25
|
||||||
Y: 176
|
Y: 176
|
||||||
@@ -191,14 +191,14 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
|||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - OpenRA will use UPnP to automaticaly configure port forwarding.
|
Text: - Game will automatically configure port forwarding.
|
||||||
Label@SETTINGS_A:
|
Label@SETTINGS_A:
|
||||||
Y: 36
|
Y: 36
|
||||||
Width: 305
|
Width: 305
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Tiny
|
Font: Tiny
|
||||||
Align: Left
|
Align: Left
|
||||||
Text: - You can disable UPnP in the OpenRA settings menu.
|
Text: - You can disable UPnP/NAT-PMP in the settings menu.
|
||||||
Background@MAP_BG:
|
Background@MAP_BG:
|
||||||
X: PARENT_RIGHT - 194
|
X: PARENT_RIGHT - 194
|
||||||
Y: 45
|
Y: 45
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Container@ADVANCED_PANEL:
|
|||||||
Width: 200
|
Width: 200
|
||||||
Height: 20
|
Height: 20
|
||||||
Font: Regular
|
Font: Regular
|
||||||
Text: Enable Network Discovery (UPnP)
|
Text: Enable UPnP/NAT-PMP Discovery
|
||||||
Checkbox@PERFTEXT_CHECKBOX:
|
Checkbox@PERFTEXT_CHECKBOX:
|
||||||
X: 15
|
X: 15
|
||||||
Y: 73
|
Y: 73
|
||||||
|
|||||||
Reference in New Issue
Block a user