Merge pull request #4878 from pchote/mapcache

Reorganize map management and preview generation
This commit is contained in:
Matthias Mailänder
2014-03-17 20:49:58 +01:00
26 changed files with 725 additions and 529 deletions

View File

@@ -20,27 +20,28 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
public class LobbyLogic
{
readonly Action onStart;
readonly Action onExit;
readonly OrderManager orderManager;
readonly bool skirmishMode;
enum PanelType { Players, Options, Kick }
PanelType panel = PanelType.Players;
Widget lobby;
Widget EditablePlayerTemplate, NonEditablePlayerTemplate, EmptySlotTemplate,
EditableSpectatorTemplate, NonEditableSpectatorTemplate, NewSpectatorTemplate;
Widget editablePlayerTemplate, nonEditablePlayerTemplate, emptySlotTemplate,
editableSpectatorTemplate, nonEditableSpectatorTemplate, newSpectatorTemplate;
ScrollPanelWidget chatPanel;
Widget chatTemplate;
ScrollPanelWidget Players;
Dictionary<string, string> CountryNames;
string MapUid;
Map Map;
ScrollPanelWidget players;
Dictionary<string, string> countryNames;
MapPreview preview = MapCache.UnknownMap;
ColorPreviewManagerWidget colorPreview;
readonly Action OnGameStart;
readonly Action onExit;
readonly OrderManager orderManager;
readonly bool skirmishMode;
// Listen for connection failures
void ConnectionStateChanged(OrderManager om)
{
@@ -54,7 +55,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Game.OpenWindow("SERVER_LOBBY", new WidgetArgs()
{
{ "onExit", onExit },
{ "onStart", OnGameStart },
{ "onStart", onStart },
{ "skirmishMode", false }
});
};
@@ -90,8 +91,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
lobby = widget;
this.orderManager = orderManager;
this.OnGameStart = () => { CloseWindow(); onStart(); };
this.onExit = onExit;
this.onStart = onStart;
this.onExit = onExit;
this.skirmishMode = skirmishMode;
Game.LobbyInfoChanged += UpdateCurrentMap;
@@ -105,49 +106,43 @@ namespace OpenRA.Mods.RA.Widgets.Logic
name.GetText = () => orderManager.LobbyInfo.GlobalSettings.ServerName;
UpdateCurrentMap();
Players = Ui.LoadWidget<ScrollPanelWidget>("LOBBY_PLAYER_BIN", lobby.Get("PLAYER_BIN_ROOT"), new WidgetArgs());
Players.IsVisible = () => panel == PanelType.Players;
players = Ui.LoadWidget<ScrollPanelWidget>("LOBBY_PLAYER_BIN", lobby.Get("PLAYER_BIN_ROOT"), new WidgetArgs());
players.IsVisible = () => panel == PanelType.Players;
EditablePlayerTemplate = Players.Get("TEMPLATE_EDITABLE_PLAYER");
NonEditablePlayerTemplate = Players.Get("TEMPLATE_NONEDITABLE_PLAYER");
EmptySlotTemplate = Players.Get("TEMPLATE_EMPTY");
EditableSpectatorTemplate = Players.Get("TEMPLATE_EDITABLE_SPECTATOR");
NonEditableSpectatorTemplate = Players.Get("TEMPLATE_NONEDITABLE_SPECTATOR");
NewSpectatorTemplate = Players.Get("TEMPLATE_NEW_SPECTATOR");
var playerBinHeaders = lobby.GetOrNull<ContainerWidget>("LABEL_CONTAINER");
if (playerBinHeaders != null)
playerBinHeaders.IsVisible = () => panel == PanelType.Players;
editablePlayerTemplate = players.Get("TEMPLATE_EDITABLE_PLAYER");
nonEditablePlayerTemplate = players.Get("TEMPLATE_NONEDITABLE_PLAYER");
emptySlotTemplate = players.Get("TEMPLATE_EMPTY");
editableSpectatorTemplate = players.Get("TEMPLATE_EDITABLE_SPECTATOR");
nonEditableSpectatorTemplate = players.Get("TEMPLATE_NONEDITABLE_SPECTATOR");
newSpectatorTemplate = players.Get("TEMPLATE_NEW_SPECTATOR");
colorPreview = lobby.Get<ColorPreviewManagerWidget>("COLOR_MANAGER");
colorPreview.Color = Game.Settings.Player.Color;
var mapPreview = lobby.Get<MapPreviewWidget>("MAP_PREVIEW");
mapPreview.IsVisible = () => Map != null;
mapPreview.Map = () => Map;
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, Map, mi);
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, Map);
mapPreview.Preview = () => preview;
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, preview, mi);
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, preview);
var mapTitle = lobby.GetOrNull<LabelWidget>("MAP_TITLE");
if (mapTitle != null)
{
mapTitle.IsVisible = () => Map != null;
mapTitle.GetText = () => Map.Title;
}
mapTitle.GetText = () => preview.Title;
var mapType = lobby.GetOrNull<LabelWidget>("MAP_TYPE");
if (mapType != null)
{
mapType.IsVisible = () => Map != null;
mapType.GetText = () => Map.Type;
}
mapType.GetText = () => preview.Type;
var mapAuthor = lobby.GetOrNull<LabelWidget>("MAP_AUTHOR");
if (mapAuthor != null)
{
mapAuthor.IsVisible = () => Map != null;
mapAuthor.GetText = () => "Created by {0}".F(Map.Author);
}
mapAuthor.GetText = () => "Created by {0}".F(preview.Author);
CountryNames = Rules.Info["world"].Traits.WithInterface<CountryInfo>()
countryNames = Rules.Info["world"].Traits.WithInterface<CountryInfo>()
.Where(c => c.Selectable)
.ToDictionary(a => a.Race, a => a.Name);
CountryNames.Add("random", "Any");
countryNames.Add("random", "Any");
var gameStarting = false;
Func<bool> configurationDisabled = () => !Game.IsHost || gameStarting || panel == PanelType.Kick ||
@@ -159,17 +154,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic
mapButton.IsDisabled = configurationDisabled;
mapButton.OnClick = () =>
{
var onSelect = new Action<Map>(m =>
var onSelect = new Action<string>(uid =>
{
orderManager.IssueOrder(Order.Command("map " + m.Uid));
Game.Settings.Server.Map = m.Uid;
orderManager.IssueOrder(Order.Command("map " + uid));
Game.Settings.Server.Map = uid;
Game.Settings.Save();
});
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
{
{ "initialMap", Map.Uid },
{ "onExit", () => {} },
{ "initialMap", preview.Uid },
{ "onExit", () => { } },
{ "onSelect", onSelect }
});
};
@@ -181,7 +176,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
slotsButton.IsDisabled = () => configurationDisabled() || panel != PanelType.Players ||
!orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots || !s.LockTeam);
var aiModes = Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name);
var botNames = Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name);
slotsButton.OnMouseDown = _ =>
{
var options = new Dictionary<string, IEnumerable<DropDownOption>>();
@@ -189,21 +184,24 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
if (orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots))
{
var botOptions = new List<DropDownOption>(){ new DropDownOption()
var botOptions = new List<DropDownOption>()
{
Title = "Add",
IsSelected = () => false,
OnClick = () =>
new DropDownOption()
{
foreach (var slot in orderManager.LobbyInfo.Slots)
Title = "Add",
IsSelected = () => false,
OnClick = () =>
{
var bot = aiModes.Random(Game.CosmeticRandom);
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
foreach (var slot in orderManager.LobbyInfo.Slots)
{
var bot = botNames.Random(Game.CosmeticRandom);
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
}
}
}
}};
};
if (orderManager.LobbyInfo.Clients.Any(c => c.Bot != null))
{
@@ -217,7 +215,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
if (c != null && c.Bot != null)
orderManager.IssueOrder(Order.Command("slot_open "+slot.Value.PlayerReference));
orderManager.IssueOrder(Order.Command("slot_open " + slot.Value.PlayerReference));
}
}
});
@@ -299,7 +297,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (allowCheats != null)
{
allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats;
allowCheats.IsDisabled = () => Map.Options.Cheats.HasValue || configurationDisabled();
allowCheats.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Cheats.HasValue || configurationDisabled();
allowCheats.OnClick = () => orderManager.IssueOrder(Order.Command(
"allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats)));
}
@@ -308,7 +306,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (crates != null)
{
crates.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Crates;
crates.IsDisabled = () => Map.Options.Crates.HasValue || configurationDisabled();
crates.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Crates.HasValue || configurationDisabled();
crates.OnClick = () => orderManager.IssueOrder(Order.Command(
"crates {0}".F(!orderManager.LobbyInfo.GlobalSettings.Crates)));
}
@@ -317,7 +315,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (allybuildradius != null)
{
allybuildradius.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius;
allybuildradius.IsDisabled = () => Map.Options.AllyBuildRadius.HasValue || configurationDisabled();
allybuildradius.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.AllyBuildRadius.HasValue || configurationDisabled();
allybuildradius.OnClick = () => orderManager.IssueOrder(Order.Command(
"allybuildradius {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius)));
}
@@ -326,7 +324,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (fragileAlliance != null)
{
fragileAlliance.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.FragileAlliances;
fragileAlliance.IsDisabled = () => Map.Options.FragileAlliances.HasValue || configurationDisabled();
fragileAlliance.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.FragileAlliances.HasValue || configurationDisabled();
fragileAlliance.OnClick = () => orderManager.IssueOrder(Order.Command(
"fragilealliance {0}".F(!orderManager.LobbyInfo.GlobalSettings.FragileAlliances)));
}
@@ -334,12 +332,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var difficulty = optionsBin.GetOrNull<DropDownButtonWidget>("DIFFICULTY_DROPDOWNBUTTON");
if (difficulty != null)
{
difficulty.IsVisible = () => Map.Options.Difficulties.Any();
difficulty.IsDisabled = configurationDisabled;
difficulty.IsVisible = () => preview.Status == MapStatus.Available && preview.Map.Options.Difficulties.Any();
difficulty.IsDisabled = () => preview.Status != MapStatus.Available || configurationDisabled();
difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty;
difficulty.OnMouseDown = _ =>
{
var options = Map.Options.Difficulties.Select(d => new DropDownOption
var options = preview.Map.Options.Difficulties.Select(d => new DropDownOption
{
Title = d,
IsSelected = () => orderManager.LobbyInfo.GlobalSettings.Difficulty == d,
@@ -360,19 +358,19 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var startingUnits = optionsBin.GetOrNull<DropDownButtonWidget>("STARTINGUNITS_DROPDOWNBUTTON");
if (startingUnits != null)
{
var classNames = new Dictionary<string,string>()
var classNames = new Dictionary<string, string>()
{
{"none", "MCV Only"},
{"light", "Light Support"},
{"heavy", "Heavy Support"},
{ "none", "MCV Only" },
{ "light", "Light Support" },
{ "heavy", "Heavy Support" },
};
Func<string, string> className = c => classNames.ContainsKey(c) ? classNames[c] : c;
var classes = Rules.Info["world"].Traits.WithInterface<MPStartUnitsInfo>()
.Select(a => a.Class).Distinct();
startingUnits.IsDisabled = () => !Map.Options.ConfigurableStartingUnits || configurationDisabled();
startingUnits.GetText = () => !Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
startingUnits.IsDisabled = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits || configurationDisabled();
startingUnits.GetText = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
startingUnits.OnMouseDown = _ =>
{
var options = classes.Select(c => new DropDownOption
@@ -398,8 +396,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var startingCash = optionsBin.GetOrNull<DropDownButtonWidget>("STARTINGCASH_DROPDOWNBUTTON");
if (startingCash != null)
{
startingCash.IsDisabled = () => Map.Options.StartingCash.HasValue || configurationDisabled();
startingCash.GetText = () => Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
startingCash.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue || configurationDisabled();
startingCash.GetText = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
startingCash.OnMouseDown = _ =>
{
var options = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>().SelectableCash.Select(c => new DropDownOption
@@ -424,7 +422,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (enableShroud != null)
{
enableShroud.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Shroud;
enableShroud.IsDisabled = () => Map.Options.Shroud.HasValue || configurationDisabled();
enableShroud.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Shroud.HasValue || configurationDisabled();
enableShroud.OnClick = () => orderManager.IssueOrder(Order.Command(
"shroud {0}".F(!orderManager.LobbyInfo.GlobalSettings.Shroud)));
}
@@ -433,7 +431,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (enableFog != null)
{
enableFog.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Fog;
enableFog.IsDisabled = () => Map.Options.Fog.HasValue || configurationDisabled();
enableFog.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Fog.HasValue || configurationDisabled();
enableFog.OnClick = () => orderManager.IssueOrder(Order.Command(
"fog {0}".F(!orderManager.LobbyInfo.GlobalSettings.Fog)));
}
@@ -461,7 +459,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
chatTextField.OnTabKey = () =>
{
teamChat ^= true;
chatLabel.Text = (teamChat) ? "Team:" : "Chat:";
chatLabel.Text = teamChat ? "Team:" : "Chat:";
return true;
};
@@ -471,8 +469,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var musicButton = lobby.GetOrNull<ButtonWidget>("MUSIC_BUTTON");
if (musicButton != null)
musicButton.OnClick = () => Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs
{ { "onExit", () => {} } });
musicButton.OnClick = () => Ui.OpenWindow("MUSIC_PANEL",
new WidgetArgs { { "onExit", () => { } } });
// Add a bot on the first lobbyinfo update
if (this.skirmishMode)
@@ -523,23 +521,25 @@ namespace OpenRA.Mods.RA.Widgets.Logic
void UpdateCurrentMap()
{
if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map)
var uid = orderManager.LobbyInfo.GlobalSettings.Map;
if (preview.Uid == uid)
return;
MapUid = orderManager.LobbyInfo.GlobalSettings.Map;
if (!Game.modData.AvailableMaps.ContainsKey (MapUid))
preview = Game.modData.MapCache[uid];
if (preview.Status != MapStatus.Available)
{
if (Game.Settings.Game.AllowDownloading)
{
Game.DownloadMap (MapUid);
Game.DownloadMap(uid);
Game.Debug("A new map has been downloaded...");
}
else
throw new InvalidOperationException("Server's new map doesn't exist on your system and Downloading turned off");
Map = new Map(Game.modData.AvailableMaps[MapUid].Path);
}
// Restore default starting cash if the last map set it to something invalid
var pri = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>();
if (!Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash))
if (!preview.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash))
orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash)));
}
@@ -554,14 +554,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Widget template = null;
// get template for possible reuse
if (idx < Players.Children.Count)
template = Players.Children[idx];
if (idx < players.Children.Count)
template = players.Children[idx];
// Empty slot
if (client == null)
{
if (template == null || template.Id != EmptySlotTemplate.Id)
template = EmptySlotTemplate.Clone();
// Empty slot
if (template == null || template.Id != emptySlotTemplate.Id)
template = emptySlotTemplate.Clone();
if (Game.IsHost)
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager);
@@ -573,13 +573,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
join.IsDisabled = () => orderManager.LocalClient.IsReady;
join.OnClick = () => orderManager.IssueOrder(Order.Command("slot " + key));
}
// Editable player in slot
else if ((client.Index == orderManager.LocalClient.Index) ||
(client.Bot != null && Game.IsHost))
{
if (template == null || template.Id != EditablePlayerTemplate.Id)
template = EditablePlayerTemplate.Clone();
// Editable player in slot
if (template == null || template.Id != editablePlayerTemplate.Id)
template = editablePlayerTemplate.Clone();
LobbyUtils.SetupClientWidget(template, slot, client, orderManager, client.Bot == null);
@@ -589,31 +588,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic
LobbyUtils.SetupEditableNameWidget(template, slot, client, orderManager);
LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview);
LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, CountryNames);
LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map.GetSpawnPoints().Length);
LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, countryNames);
LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, preview.SpawnPoints.Count);
LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager);
}
else
{ // Non-editable player in slot
if (template == null || template.Id != NonEditablePlayerTemplate.Id)
template = NonEditablePlayerTemplate.Clone();
{
// Non-editable player in slot
if (template == null || template.Id != nonEditablePlayerTemplate.Id)
template = nonEditablePlayerTemplate.Clone();
LobbyUtils.SetupClientWidget(template, slot, client, orderManager, client.Bot == null);
LobbyUtils.SetupNameWidget(template, slot, client);
LobbyUtils.SetupKickWidget(template, slot, client, orderManager, lobby,
() => panel = PanelType.Kick, () => panel = PanelType.Players);
LobbyUtils.SetupColorWidget(template, slot, client);
LobbyUtils.SetupFactionWidget(template, slot, client, CountryNames);
LobbyUtils.SetupFactionWidget(template, slot, client, countryNames);
LobbyUtils.SetupTeamWidget(template, slot, client);
LobbyUtils.SetupReadyWidget(template, slot, client);
}
template.IsVisible = () => true;
if (idx >= Players.Children.Count)
Players.AddChild(template);
else if (Players.Children[idx].Id != template.Id)
Players.ReplaceChild(Players.Children[idx], template);
if (idx >= players.Children.Count)
players.AddChild(template);
else if (players.Children[idx].Id != template.Id)
players.ReplaceChild(players.Children[idx], template);
idx++;
}
@@ -625,22 +625,22 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var c = client;
// get template for possible reuse
if (idx < Players.Children.Count)
template = Players.Children[idx];
if (idx < players.Children.Count)
template = players.Children[idx];
// Editable spectator
if (c.Index == orderManager.LocalClient.Index)
{
if (template == null || template.Id != EditableSpectatorTemplate.Id)
template = EditableSpectatorTemplate.Clone();
if (template == null || template.Id != editableSpectatorTemplate.Id)
template = editableSpectatorTemplate.Clone();
LobbyUtils.SetupEditableNameWidget(template, null, c, orderManager);
}
// Non-editable spectator
else
{
if (template == null || template.Id != NonEditableSpectatorTemplate.Id)
template = NonEditableSpectatorTemplate.Clone();
// Non-editable spectator
if (template == null || template.Id != nonEditableSpectatorTemplate.Id)
template = nonEditableSpectatorTemplate.Clone();
LobbyUtils.SetupNameWidget(template, null, client);
LobbyUtils.SetupKickWidget(template, null, client, orderManager, lobby,
@@ -650,10 +650,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
LobbyUtils.SetupClientWidget(template, null, c, orderManager, true);
template.IsVisible = () => true;
if (idx >= Players.Children.Count)
Players.AddChild(template);
else if (Players.Children[idx].Id != template.Id)
Players.ReplaceChild(Players.Children[idx], template);
if (idx >= players.Children.Count)
players.AddChild(template);
else if (players.Children[idx].Id != template.Id)
players.ReplaceChild(players.Children[idx], template);
idx++;
}
@@ -662,10 +662,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (orderManager.LocalClient.Slot != null)
{
Widget spec = null;
if (idx < Players.Children.Count)
spec = Players.Children[idx];
if (spec == null || spec.Id != NewSpectatorTemplate.Id)
spec = NewSpectatorTemplate.Clone();
if (idx < players.Children.Count)
spec = players.Children[idx];
if (spec == null || spec.Id != newSpectatorTemplate.Id)
spec = newSpectatorTemplate.Clone();
LobbyUtils.SetupKickSpectatorsWidget(spec, orderManager, lobby,
() => panel = PanelType.Kick, () => panel = PanelType.Players, this.skirmishMode);
@@ -677,17 +677,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|| orderManager.LocalClient.IsAdmin;
spec.IsVisible = () => true;
if (idx >= Players.Children.Count)
Players.AddChild(spec);
else if (Players.Children[idx].Id != spec.Id)
Players.ReplaceChild(Players.Children[idx], spec);
if (idx >= players.Children.Count)
players.AddChild(spec);
else if (players.Children[idx].Id != spec.Id)
players.ReplaceChild(players.Children[idx], spec);
idx++;
}
while (Players.Children.Count > idx)
Players.RemoveChild(Players.Children[idx]);
while (players.Children.Count > idx)
players.RemoveChild(players.Children[idx]);
}
void OnGameStart()
{
CloseWindow();
onStart();
}
class DropDownOption

View File

@@ -130,26 +130,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
color.AttachPanel(colorChooser, onExit);
}
public static Dictionary<int2, Session.Client> GetSpawnClients(OrderManager orderManager, Map map)
public static Dictionary<CPos, Session.Client> GetSpawnClients(OrderManager orderManager, MapPreview preview)
{
var spawns = map.GetSpawnPoints();
var spawns = preview.SpawnPoints;
return orderManager.LobbyInfo.Clients
.Where(c => c.SpawnPoint != 0)
.ToDictionary(
c => spawns[c.SpawnPoint - 1],
c => c);
.ToDictionary(c => spawns[c.SpawnPoint - 1], c => c);
}
public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, Map map, MouseInput mi)
public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
{
if (map == null)
return;
if (mi.Button != MouseButton.Left)
return;
if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready)
return;
var selectedSpawn = map.GetSpawnPoints()
var selectedSpawn = preview.SpawnPoints
.Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp), i))
.Where(a => (a.First - mi.Location).LengthSquared < 64)
.Select(a => a.Second + 1)

View File

@@ -18,21 +18,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
public class MapChooserLogic
{
Map map;
string selectedUid;
// May be a subset of available maps if a mode filter is active
Dictionary<string, Map> visibleMaps;
List<string> visibleMaps;
ScrollPanelWidget scrollpanel;
ScrollItemWidget itemTemplate;
string gameMode;
[ObjectCreator.UseCtor]
internal MapChooserLogic(Widget widget, string initialMap, Action onExit, Action<Map> onSelect)
internal MapChooserLogic(Widget widget, string initialMap, Action onExit, Action<string> onSelect)
{
map = Game.modData.AvailableMaps[WidgetUtils.ChooseInitialMap(initialMap)];
selectedUid = WidgetUtils.ChooseInitialMap(initialMap);
widget.Get<ButtonWidget>("BUTTON_OK").OnClick = () => { Ui.CloseWindow(); onSelect(map); };
widget.Get<ButtonWidget>("BUTTON_OK").OnClick = () => { Ui.CloseWindow(); onSelect(selectedUid); };
widget.Get<ButtonWidget>("BUTTON_CANCEL").OnClick = () => { Ui.CloseWindow(); onExit(); };
scrollpanel = widget.Get<ScrollPanelWidget>("MAP_LIST");
@@ -44,9 +44,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var gameModeDropdown = widget.GetOrNull<DropDownButtonWidget>("GAMEMODE_FILTER");
if (gameModeDropdown != null)
{
var selectableMaps = Game.modData.AvailableMaps.Where(m => m.Value.Selectable).ToList();
var selectableMaps = Game.modData.MapCache.Where(m => m.Status == MapStatus.Available && m.Map.Selectable);
var gameModes = selectableMaps
.GroupBy(m => m.Value.Type)
.GroupBy(m => m.Type)
.Select(g => Pair.New(g.Key, g.Count())).ToList();
// 'all game types' extra item
@@ -75,9 +75,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
randomMapButton.OnClick = () =>
{
var kv = visibleMaps.Random(Game.CosmeticRandom);
map = kv.Value;
scrollpanel.ScrollToItem(kv.Key);
var uid = visibleMaps.Random(Game.CosmeticRandom);
selectedUid = uid;
scrollpanel.ScrollToItem(uid);
};
randomMapButton.IsDisabled = () => visibleMaps == null || visibleMaps.Count == 0;
}
@@ -85,27 +85,27 @@ namespace OpenRA.Mods.RA.Widgets.Logic
EnumerateMaps(onSelect);
}
void EnumerateMaps(Action<Map> onSelect)
void EnumerateMaps(Action<string> onSelect)
{
var maps = Game.modData.AvailableMaps
.Where(kv => kv.Value.Selectable)
.Where(kv => kv.Value.Type == gameMode || gameMode == null)
.OrderBy(kv => kv.Value.PlayerCount)
.ThenBy(kv => kv.Value.Title);
var maps = Game.modData.MapCache
.Where(m => m.Status == MapStatus.Available && m.Map.Selectable)
.Where(m => m.Type == gameMode || gameMode == null)
.OrderBy(m => m.PlayerCount)
.ThenBy(m => m.Title);
scrollpanel.RemoveChildren();
foreach (var kv in maps)
foreach (var loop in maps)
{
var m = kv.Value;
var item = ScrollItemWidget.Setup(kv.Key, itemTemplate, () => m == map, () => map = m, () => { Ui.CloseWindow(); onSelect(m); });
var preview = loop;
var item = ScrollItemWidget.Setup(preview.Uid, itemTemplate, () => selectedUid == preview.Uid, () => selectedUid = preview.Uid, () => { Ui.CloseWindow(); onSelect(preview.Uid); });
var titleLabel = item.Get<LabelWidget>("TITLE");
titleLabel.GetText = () => m.Title;
titleLabel.GetText = () => preview.Title;
var previewWidget = item.Get<MapPreviewWidget>("PREVIEW");
previewWidget.IgnoreMouseOver = true;
previewWidget.IgnoreMouseInput = true;
previewWidget.Map = () => m;
previewWidget.Preview = () => preview;
previewWidget.IsVisible = () => previewWidget.RenderBounds.IntersectsWith(scrollpanel.RenderBounds);
var previewLoadingWidget = item.GetOrNull<BackgroundWidget>("PREVIEW_PLACEHOLDER");
@@ -114,17 +114,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var detailsWidget = item.GetOrNull<LabelWidget>("DETAILS");
if (detailsWidget != null)
detailsWidget.GetText = () => "{0} ({1} players)".F(m.Type, m.PlayerCount);
detailsWidget.GetText = () => "{0} ({1} players)".F(preview.Type, preview.PlayerCount);
var authorWidget = item.GetOrNull<LabelWidget>("AUTHOR");
if (authorWidget != null)
authorWidget.GetText = () => "Created by {0}".F(m.Author);
authorWidget.GetText = () => "Created by {0}".F(preview.Author);
var sizeWidget = item.GetOrNull<LabelWidget>("SIZE");
if (sizeWidget != null)
{
var size = m.Bounds.Width + "x" + m.Bounds.Height;
var numberPlayableCells = m.Bounds.Width * m.Bounds.Height;
var size = preview.Bounds.Width + "x" + preview.Bounds.Height;
var numberPlayableCells = preview.Bounds.Width * preview.Bounds.Height;
if (numberPlayableCells >= 120 * 120) size += " (Huge)";
else if (numberPlayableCells >= 90 * 90) size += " (Large)";
else if (numberPlayableCells >= 60 * 60) size += " (Medium)";
@@ -135,9 +135,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
scrollpanel.AddChild(item);
}
visibleMaps = maps.ToDictionary(kv => kv.Key, kv => kv.Value);
if (visibleMaps.ContainsValue(map))
scrollpanel.ScrollToItem(visibleMaps.First(m => m.Value == map).Key);
visibleMaps = maps.Select(m => m.Uid).ToList();
if (visibleMaps.Contains(selectedUid))
scrollpanel.ScrollToItem(selectedUid);
}
}
}

View File

@@ -19,6 +19,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
public class ReplayBrowserLogic
{
Widget panel;
MapPreview selectedMap = MapCache.UnknownMap;
string selectedFilename;
string selectedDuration;
string selectedPlayers;
bool selectedValid;
[ObjectCreator.UseCtor]
public ReplayBrowserLogic(Widget widget, Action onExit, Action onStart)
@@ -44,15 +49,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
}
var watch = panel.Get<ButtonWidget>("WATCH_BUTTON");
watch.IsDisabled = () => currentReplay == null || currentMap == null || currentReplay.Duration == 0;
watch.IsDisabled = () => !selectedValid || selectedMap.Status != MapStatus.Available;
watch.OnClick = () => { WatchReplay(); onStart(); };
panel.Get("REPLAY_INFO").IsVisible = () => currentReplay != null;
panel.Get("REPLAY_INFO").IsVisible = () => selectedFilename != null;;
panel.Get<LabelWidget>("DURATION").GetText = () => selectedDuration;
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => selectedMap;
panel.Get<LabelWidget>("MAP_TITLE").GetText = () => selectedMap.Title;
panel.Get<LabelWidget>("PLAYERS").GetText = () => selectedPlayers;
}
Replay currentReplay;
Map currentMap;
void SelectReplay(string filename)
{
if (filename == null)
@@ -60,32 +66,31 @@ namespace OpenRA.Mods.RA.Widgets.Logic
try
{
currentReplay = new Replay(filename);
currentMap = currentReplay.Map();
panel.Get<LabelWidget>("DURATION").GetText =
() => WidgetUtils.FormatTime(currentReplay.Duration);
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Map = () => currentMap;
panel.Get<LabelWidget>("MAP_TITLE").GetText =
() => currentMap != null ? currentMap.Title : "(Unknown Map)";
var players = currentReplay.LobbyInfo.Slots
.Count(s => currentReplay.LobbyInfo.ClientInSlot(s.Key) != null);
panel.Get<LabelWidget>("PLAYERS").GetText = () => players.ToString();
using (var conn = new ReplayConnection(filename))
{
selectedFilename = filename;
selectedMap = Game.modData.MapCache[conn.LobbyInfo.GlobalSettings.Map];
selectedDuration = WidgetUtils.FormatTime(conn.TickCount * Game.NetTickScale);
selectedPlayers = conn.LobbyInfo.Slots
.Count(s => conn.LobbyInfo.ClientInSlot(s.Key) != null)
.ToString();
selectedValid = conn.TickCount > 0;
}
}
catch (Exception e)
{
Log.Write("debug", "Exception while parsing replay: {0}", e);
currentReplay = null;
currentMap = null;
selectedFilename = null;
selectedValid = false;
selectedMap = MapCache.UnknownMap;
}
}
void WatchReplay()
{
if (currentReplay != null)
if (selectedFilename != null)
{
Game.JoinReplay(currentReplay.Filename);
Game.JoinReplay(selectedFilename);
Ui.CloseWindow();
}
}
@@ -93,7 +98,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
void AddReplay(ScrollPanelWidget list, string filename, ScrollItemWidget template)
{
var item = ScrollItemWidget.Setup(template,
() => currentReplay != null && currentReplay.Filename == filename,
() => selectedFilename == filename,
() => SelectReplay(filename),
() => WatchReplay());
var f = Path.GetFileName(filename);

View File

@@ -12,6 +12,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Net;
using System.Text;
using OpenRA.FileFormats;
using OpenRA.Network;
using OpenRA.Server;
@@ -29,6 +31,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
enum SearchStatus { Fetching, Failed, NoGames, Hidden }
SearchStatus searchStatus = SearchStatus.Fetching;
Download currentQuery;
Widget panel, serverList;
bool showWaiting = true;
bool showEmpty = true;
@@ -39,7 +43,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
switch (searchStatus)
{
case SearchStatus.Fetching: return "Fetching game list...";
case SearchStatus.Failed: return "Failed to contact master server.";
case SearchStatus.NoGames: return "No games found.";
default: return "";
@@ -49,16 +52,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
[ObjectCreator.UseCtor]
public ServerBrowserLogic(Widget widget, Action onStart, Action onExit)
{
var panel = widget;
panel = widget;
this.onStart = onStart;
this.onExit = onExit;
var sl = panel.Get<ScrollPanelWidget>("SERVER_LIST");
serverList = panel.Get<ScrollPanelWidget>("SERVER_LIST");
serverTemplate = serverList.Get<ScrollItemWidget>("SERVER_TEMPLATE");
// Menu buttons
var refreshButton = panel.Get<ButtonWidget>("REFRESH_BUTTON");
refreshButton.IsDisabled = () => searchStatus == SearchStatus.Fetching;
refreshButton.OnClick = () => ServerList.Query(games => RefreshServerList(panel, games));
refreshButton.GetText = () => searchStatus == SearchStatus.Fetching ? "Refreshing..." : "Refresh";
refreshButton.OnClick = RefreshServerList;
panel.Get<ButtonWidget>("DIRECTCONNECT_BUTTON").OnClick = OpenDirectConnectPanel;
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = OpenCreateServerPanel;
@@ -69,9 +74,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
// Server list
serverTemplate = sl.Get<ScrollItemWidget>("SERVER_TEMPLATE");
// Display the progress label over the server list
// The text is only visible when the list is empty
var progressText = panel.Get<LabelWidget>("PROGRESS_LABEL");
@@ -82,33 +84,163 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (showWaitingCheckbox != null)
{
showWaitingCheckbox.IsChecked = () => showWaiting;
showWaitingCheckbox.OnClick = () => { showWaiting ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
showWaitingCheckbox.OnClick = () => { showWaiting ^= true; RefreshServerList(); };
}
var showEmptyCheckbox = panel.GetOrNull<CheckboxWidget>("EMPTY");
if (showEmptyCheckbox != null)
{
showEmptyCheckbox.IsChecked = () => showEmpty;
showEmptyCheckbox.OnClick = () => { showEmpty ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
showEmptyCheckbox.OnClick = () => { showEmpty ^= true; RefreshServerList(); };
}
var showAlreadyStartedCheckbox = panel.GetOrNull<CheckboxWidget>("ALREADY_STARTED");
if (showAlreadyStartedCheckbox != null)
{
showAlreadyStartedCheckbox.IsChecked = () => showStarted;
showAlreadyStartedCheckbox.OnClick = () => { showStarted ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
showAlreadyStartedCheckbox.OnClick = () => { showStarted ^= true; RefreshServerList(); };
}
var showIncompatibleCheckbox = panel.GetOrNull<CheckboxWidget>("INCOMPATIBLE_VERSION");
if (showIncompatibleCheckbox != null)
{
showIncompatibleCheckbox.IsChecked = () => showIncompatible;
showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; RefreshServerList(); };
}
// Game.LoadWidget(null, "SERVERBROWSER_IRC", panel.Get("IRC_ROOT"), new WidgetArgs());
RefreshServerList();
}
ServerList.Query(games => RefreshServerList(panel, games));
void RefreshServerList()
{
// Query in progress
if (currentQuery != null)
return;
searchStatus = SearchStatus.Fetching;
Action<DownloadDataCompletedEventArgs, bool> onComplete = (i, cancelled) =>
{
currentQuery = null;
if (i.Error != null || cancelled)
{
RefreshServerListInner(null);
return;
}
var data = Encoding.UTF8.GetString(i.Result);
var yaml = MiniYaml.FromString(data);
var games = yaml.Select(a => FieldLoader.Load<GameServer>(a.Value))
.Where(gs => gs.Address != null);
RefreshServerListInner(games);
Game.RunAfterTick(() => RefreshServerListInner(games));
};
currentQuery = new Download(Game.Settings.Server.MasterServer + "list.php", _ => {}, onComplete);
}
public void RefreshServerListInner(IEnumerable<GameServer> games)
{
List<Widget> rows = new List<Widget>();
Game.RunAfterTick(() =>
{
serverList.RemoveChildren();
currentServer = null;
if (games == null)
{
searchStatus = SearchStatus.Failed;
return;
}
if (!games.Any())
{
searchStatus = SearchStatus.NoGames;
return;
}
currentServer = games.FirstOrDefault();
searchStatus = SearchStatus.Hidden;
foreach (var row in rows)
serverList.AddChild(row);
});
foreach (var loop in games.OrderByDescending(g => g.CanJoin()).ThenByDescending(g => g.Players))
{
var game = loop;
if (game == null)
continue;
var canJoin = game.CanJoin();
var item = ScrollItemWidget.Setup(serverTemplate, () => currentServer == game, () => currentServer = game, () => Join(game));
var map = Game.modData.MapCache[game.Map];
var preview = item.GetOrNull<MapPreviewWidget>("MAP_PREVIEW");
if (preview != null)
preview.Preview = () => map;
var title = item.GetOrNull<LabelWidget>("TITLE");
if (title != null)
{
title.GetText = () => game.Name;
title.GetColor = () => canJoin ? title.TextColor : Color.Gray;
}
var maptitle = item.GetOrNull<LabelWidget>("MAP");
if (title != null)
{
maptitle.GetText = () => map.Title;
maptitle.GetColor = () => canJoin ? maptitle.TextColor : Color.Gray;
}
var players = item.GetOrNull<LabelWidget>("PLAYERS");
if (players != null)
{
players.GetText = () => "{0} / {1}".F(game.Players, map.PlayerCount);
players.GetColor = () => canJoin ? players.TextColor : Color.Gray;
}
var state = item.GetOrNull<LabelWidget>("STATE");
if (state != null)
{
state.GetText = () => GetStateLabel(game);
state.GetColor = () => canJoin ? state.TextColor : Color.Gray;
}
var ip = item.GetOrNull<LabelWidget>("IP");
if (ip != null)
{
ip.GetText = () => game.Address;
ip.GetColor = () => canJoin ? ip.TextColor : Color.Gray;
}
var version = item.GetOrNull<LabelWidget>("VERSION");
if (version != null)
{
version.GetText = () => GenerateModLabel(game);
version.IsVisible = () => !game.CompatibleVersion();
version.GetColor = () => canJoin ? version.TextColor : Color.Gray;
}
var location = item.GetOrNull<LabelWidget>("LOCATION");
if (location != null)
{
var cachedServerLocation = LobbyUtils.LookupCountry(game.Address.Split(':')[0]);
location.GetText = () => cachedServerLocation;
location.IsVisible = () => game.CompatibleVersion();
location.GetColor = () => canJoin ? location.TextColor : Color.Gray;
}
if (!Filtered(game))
rows.Add(item);
}
}
void OpenLobby()
@@ -155,10 +287,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (game == null || game.Players == 0)
return "";
var map = Game.modData.FindMapByUid(game.Map);
var maxPlayers = map == null ? "?" : (object)map.PlayerCount;
return "{0} / {1}".F(game.Players, maxPlayers);
var map = Game.modData.MapCache[game.Map];
return "{0} / {1}".F(game.Players, map.PlayerCount == 0 ? "?" : map.PlayerCount.ToString());
}
string GetStateLabel(GameServer game)
@@ -176,11 +306,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
return "Unknown server state";
}
Map GetMapPreview(GameServer game)
{
return (game == null) ? null : Game.modData.FindMapByUid(game.Map);
}
public static string GenerateModLabel(GameServer s)
{
Mod mod;
@@ -241,20 +366,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var item = ScrollItemWidget.Setup(serverTemplate, () => currentServer == game, () => currentServer = game, () => Join(game));
var map = Game.modData.MapCache[game.Map];
var preview = item.Get<MapPreviewWidget>("MAP_PREVIEW");
preview.Map = () => GetMapPreview(game);
preview.IsVisible = () => GetMapPreview(game) != null;
preview.Preview = () => map;
var title = item.Get<LabelWidget>("TITLE");
title.GetText = () => game.Name;
// TODO: Use game.MapTitle once the server supports it
var maptitle = item.Get<LabelWidget>("MAP");
maptitle.GetText = () =>
{
var map = Game.modData.FindMapByUid(game.Map);
return map == null ? "Unknown Map" : map.Title;
};
maptitle.GetText = () => map.Title;
// TODO: Use game.MaxPlayers once the server supports it
var players = item.Get<LabelWidget>("PLAYERS");

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Widget panel;
Action onCreate;
Action onExit;
Map map;
MapPreview preview = MapCache.UnknownMap;
bool advertiseOnline;
bool allowPortForward;
@@ -32,12 +32,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
this.onExit = onExit;
var settings = Game.Settings;
preview = Game.modData.MapCache[WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map)];
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin;
map = Game.modData.AvailableMaps[ WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map) ];
var mapButton = panel.GetOrNull<ButtonWidget>("MAP_BUTTON");
if (mapButton != null)
{
@@ -45,14 +44,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
{
{ "initialMap", map.Uid },
{ "initialMap", preview.Uid },
{ "onExit", () => {} },
{ "onSelect", (Action<Map>)(m => map = m) }
{ "onSelect", (Action<String>)(uid => preview = Game.modData.MapCache[uid]) }
});
};
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Map = () => map;
panel.Get<LabelWidget>("MAP_NAME").GetText = () => map.Title;
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => preview;
panel.Get<LabelWidget>("MAP_NAME").GetText = () => preview.Title;
}
panel.Get<TextFieldWidget>("SERVER_NAME").Text = settings.Server.Name ?? "";
@@ -97,7 +96,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Game.Settings.Server.ExternalPort = externalPort;
Game.Settings.Server.AdvertiseOnline = advertiseOnline;
Game.Settings.Server.AllowPortForward = allowPortForward;
Game.Settings.Server.Map = map.Uid;
Game.Settings.Server.Map = preview.Uid;
Game.Settings.Server.Password = password;
Game.Settings.Save();