Merge pull request #4878 from pchote/mapcache
Reorganize map management and preview generation
This commit is contained in:
@@ -117,6 +117,7 @@ NEW:
|
|||||||
Updated RenderBuildingCharge so you can set a custom charge sequence name (default is active).
|
Updated RenderBuildingCharge so you can set a custom charge sequence name (default is active).
|
||||||
Added IEffectiveOwner interface for traits/logic that temporarily alter an actor's apparent owner.
|
Added IEffectiveOwner interface for traits/logic that temporarily alter an actor's apparent owner.
|
||||||
Renamed Spy trait to Disguise, SpyToolTip trait to DisguiseToolTip, and RenderSpy trait to RenderDisguise.
|
Renamed Spy trait to Disguise, SpyToolTip trait to DisguiseToolTip, and RenderSpy trait to RenderDisguise.
|
||||||
|
Overhauled the internal map management and preview generation code.
|
||||||
Server:
|
Server:
|
||||||
Message of the day is now shared between all mods and a default motd.txt gets created in the user directory.
|
Message of the day is now shared between all mods and a default motd.txt gets created in the user directory.
|
||||||
Asset Browser:
|
Asset Browser:
|
||||||
@@ -137,6 +138,7 @@ NEW:
|
|||||||
If you spot black tiles in your Dune 2000 ARRAKIS maps, replace them with the remaining sand and rock tiles. Go to Map → Fix Open Areas to randomize them.
|
If you spot black tiles in your Dune 2000 ARRAKIS maps, replace them with the remaining sand and rock tiles. Go to Map → Fix Open Areas to randomize them.
|
||||||
The TestFile check in mod.yaml has been renamed to TestFiles (plural!) and now supports a comma-separated list of assets that are required to load the game.
|
The TestFile check in mod.yaml has been renamed to TestFiles (plural!) and now supports a comma-separated list of assets that are required to load the game.
|
||||||
DisabledOverlay has been split from RenderBuilding. Use it together with RequiresPower and CanPowerDown for buildings or directly with Husk.
|
DisabledOverlay has been split from RenderBuilding. Use it together with RequiresPower and CanPowerDown for buildings or directly with Husk.
|
||||||
|
Added support for custom map previews that replace the minimap in the game browser and lobby. Add map.png inside the map package.
|
||||||
Packaging:
|
Packaging:
|
||||||
Removed portable install option from Windows installer as the game left without write access breaks content download and error log generation.
|
Removed portable install option from Windows installer as the game left without write access breaks content download and error log generation.
|
||||||
Added HTML documentation to the Windows installer.
|
Added HTML documentation to the Windows installer.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace OpenRA.Editor
|
|||||||
if (DirectoryIsEmpty(MapFolderPath))
|
if (DirectoryIsEmpty(MapFolderPath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var map in ModData.FindMapsIn(MapFolderPath))
|
foreach (var map in MapCache.FindMapsIn(MapFolderPath))
|
||||||
{
|
{
|
||||||
ListViewItem map1 = new ListViewItem();
|
ListViewItem map1 = new ListViewItem();
|
||||||
map1.Tag = map;
|
map1.Tag = map;
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ namespace OpenRA
|
|||||||
wc.DownloadFileAsync(new Uri(url), path);
|
wc.DownloadFileAsync(new Uri(url), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Download(string url, Action<DownloadProgressChangedEventArgs> onProgress, Action<DownloadDataCompletedEventArgs, bool> onComplete)
|
||||||
|
{
|
||||||
|
wc = new WebClient();
|
||||||
|
wc.Proxy = null;
|
||||||
|
|
||||||
|
wc.DownloadProgressChanged += (_, a) => onProgress(a);
|
||||||
|
wc.DownloadDataCompleted += (_, a) => onComplete(a, cancelled);
|
||||||
|
|
||||||
|
Game.OnQuit += Cancel;
|
||||||
|
wc.DownloadDataCompleted += (_, a) => { Game.OnQuit -= Cancel; };
|
||||||
|
|
||||||
|
wc.DownloadDataAsync(new Uri(url));
|
||||||
|
}
|
||||||
|
|
||||||
public void Cancel()
|
public void Cancel()
|
||||||
{
|
{
|
||||||
Game.OnQuit -= Cancel;
|
Game.OnQuit -= Cancel;
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ namespace OpenRA
|
|||||||
modData = new ModData(mod);
|
modData = new ModData(mod);
|
||||||
Renderer.InitializeFonts(modData.Manifest);
|
Renderer.InitializeFonts(modData.Manifest);
|
||||||
modData.InitializeLoaders();
|
modData.InitializeLoaders();
|
||||||
modData.LoadMaps();
|
modData.MapCache.LoadMaps();
|
||||||
|
|
||||||
PerfHistory.items["render"].hasNormalTick = false;
|
PerfHistory.items["render"].hasNormalTick = false;
|
||||||
PerfHistory.items["batches"].hasNormalTick = false;
|
PerfHistory.items["batches"].hasNormalTick = false;
|
||||||
@@ -401,7 +401,7 @@ namespace OpenRA
|
|||||||
if (Settings.Server.DedicatedLoop)
|
if (Settings.Server.DedicatedLoop)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Starting a new server instance...");
|
Console.WriteLine("Starting a new server instance...");
|
||||||
modData.LoadMaps();
|
modData.MapCache.LoadMaps();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,13 +426,14 @@ namespace OpenRA
|
|||||||
|
|
||||||
static string ChooseShellmap()
|
static string ChooseShellmap()
|
||||||
{
|
{
|
||||||
var shellmaps = modData.AvailableMaps
|
var shellmaps = modData.MapCache
|
||||||
.Where(m => m.Value.UseAsShellmap);
|
.Where(m => m.Status == MapStatus.Available && m.Map.UseAsShellmap)
|
||||||
|
.Select(m => m.Uid);
|
||||||
|
|
||||||
if (!shellmaps.Any())
|
if (!shellmaps.Any())
|
||||||
throw new InvalidDataException("No valid shellmaps available");
|
throw new InvalidDataException("No valid shellmaps available");
|
||||||
|
|
||||||
return shellmaps.Random(CosmeticRandom).Key;
|
return shellmaps.Random(CosmeticRandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool quit;
|
static bool quit;
|
||||||
@@ -553,7 +554,7 @@ namespace OpenRA
|
|||||||
WebClient webClient = new WebClient();
|
WebClient webClient = new WebClient();
|
||||||
webClient.DownloadFile(url, tempFile);
|
webClient.DownloadFile(url, tempFile);
|
||||||
File.Move(tempFile, mapPath);
|
File.Move(tempFile, mapPath);
|
||||||
Game.modData.AvailableMaps.Add(mapHash, new Map(mapPath));
|
Game.modData.MapCache[mapHash].UpdateFromMap(new Map(mapPath));
|
||||||
Log.Write("debug", "New map has been downloaded to '{0}'", mapPath);
|
Log.Write("debug", "New map has been downloaded to '{0}'", mapPath);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -67,6 +67,14 @@ namespace OpenRA.Graphics
|
|||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sprite Add(Bitmap src)
|
||||||
|
{
|
||||||
|
var rect = Allocate(src.Size);
|
||||||
|
Util.FastCopyIntoSprite(rect, src);
|
||||||
|
current.CommitData();
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
public Sprite Add(Size size, byte paletteIndex)
|
public Sprite Add(Size size, byte paletteIndex)
|
||||||
{
|
{
|
||||||
var data = new byte[size.Width * size.Height];
|
var data = new byte[size.Width * size.Height];
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
using OpenRA.FileFormats.Graphics;
|
using OpenRA.FileFormats.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
@@ -59,6 +61,36 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void FastCopyIntoSprite(Sprite dest, Bitmap src)
|
||||||
|
{
|
||||||
|
var destStride = dest.sheet.Size.Width;
|
||||||
|
var width = dest.bounds.Width;
|
||||||
|
var height = dest.bounds.Height;
|
||||||
|
|
||||||
|
var srcData = src.LockBits(src.Bounds(),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var c = (int*)srcData.Scan0;
|
||||||
|
|
||||||
|
// Cast the data to an int array so we can copy the src data directly
|
||||||
|
fixed (byte* bd = &dest.sheet.Data[0])
|
||||||
|
{
|
||||||
|
var data = (int*)bd;
|
||||||
|
var x = dest.bounds.Left;
|
||||||
|
var y = dest.bounds.Top;
|
||||||
|
|
||||||
|
for (var j = 0; j < height; j++)
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
data[(y + j) * destStride + x + i] = *(c + (j * srcData.Stride >> 2) + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src.UnlockBits(srcData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static float[] IdentityMatrix()
|
public static float[] IdentityMatrix()
|
||||||
{
|
{
|
||||||
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
|
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace OpenRA
|
|||||||
public string Author;
|
public string Author;
|
||||||
public string Tileset;
|
public string Tileset;
|
||||||
public bool AllowStartUnitConfig = true;
|
public bool AllowStartUnitConfig = true;
|
||||||
|
public Bitmap CustomPreview;
|
||||||
|
|
||||||
[FieldLoader.LoadUsing("LoadOptions")]
|
[FieldLoader.LoadUsing("LoadOptions")]
|
||||||
public MapOptions Options;
|
public MapOptions Options;
|
||||||
@@ -226,13 +227,16 @@ namespace OpenRA
|
|||||||
Save(path);
|
Save(path);
|
||||||
|
|
||||||
Uid = ComputeHash();
|
Uid = ComputeHash();
|
||||||
|
|
||||||
|
if (Container.Exists("map.png"))
|
||||||
|
CustomPreview = new Bitmap(Container.GetContent("map.png"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int2[] GetSpawnPoints()
|
public CPos[] GetSpawnPoints()
|
||||||
{
|
{
|
||||||
return Actors.Value.Values
|
return Actors.Value.Values
|
||||||
.Where(a => a.Type == "mpspawn")
|
.Where(a => a.Type == "mpspawn")
|
||||||
.Select(a => a.InitDict.Get<LocationInit>().value)
|
.Select(a => (CPos)a.InitDict.Get<LocationInit>().value)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
148
OpenRA.Game/MapCache.cs
Executable file
148
OpenRA.Game/MapCache.cs
Executable file
@@ -0,0 +1,148 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
|
namespace OpenRA
|
||||||
|
{
|
||||||
|
public class MapCache : IEnumerable<MapPreview>
|
||||||
|
{
|
||||||
|
public static readonly MapPreview UnknownMap = new MapPreview(null, null);
|
||||||
|
readonly Cache<string, MapPreview> previews;
|
||||||
|
readonly Manifest manifest;
|
||||||
|
readonly SheetBuilder sheetBuilder;
|
||||||
|
Thread previewLoaderThread;
|
||||||
|
object syncRoot = new object();
|
||||||
|
Queue<MapPreview> generateMinimap = new Queue<MapPreview>();
|
||||||
|
|
||||||
|
public MapCache(Manifest m)
|
||||||
|
{
|
||||||
|
manifest = m;
|
||||||
|
previews = new Cache<string, MapPreview>(uid => new MapPreview(uid, this));
|
||||||
|
sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadMaps()
|
||||||
|
{
|
||||||
|
var paths = manifest.MapFolders.SelectMany(f => FindMapsIn(f));
|
||||||
|
foreach (var path in paths)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var map = new Map(path, manifest.Mod.Id);
|
||||||
|
if (manifest.MapCompatibility.Contains(map.RequiresMod))
|
||||||
|
previews[map.Uid].UpdateFromMap(map);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed to load map: {0}", path);
|
||||||
|
Console.WriteLine("Details: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> FindMapsIn(string dir)
|
||||||
|
{
|
||||||
|
string[] noMaps = { };
|
||||||
|
|
||||||
|
// Ignore optional flag
|
||||||
|
if (dir.StartsWith("~"))
|
||||||
|
dir = dir.Substring(1);
|
||||||
|
|
||||||
|
// Paths starting with ^ are relative to the user directory
|
||||||
|
if (dir.StartsWith("^"))
|
||||||
|
dir = Platform.SupportDir + dir.Substring(1);
|
||||||
|
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
return noMaps;
|
||||||
|
|
||||||
|
var dirsWithMaps = Directory.GetDirectories(dir)
|
||||||
|
.Where(d => Directory.GetFiles(d, "map.yaml").Any() && Directory.GetFiles(d, "map.bin").Any());
|
||||||
|
|
||||||
|
return dirsWithMaps.Concat(Directory.GetFiles(dir, "*.oramap"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadAsyncInternal()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
MapPreview p;
|
||||||
|
lock (syncRoot)
|
||||||
|
{
|
||||||
|
if (generateMinimap.Count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = generateMinimap.Peek();
|
||||||
|
|
||||||
|
// Preview already exists
|
||||||
|
if (p.Minimap != null)
|
||||||
|
{
|
||||||
|
generateMinimap.Dequeue();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the minimap into the shared sheet
|
||||||
|
// Note: this is not generally thread-safe, but it works here because:
|
||||||
|
// (a) This worker is the only thread writing to this sheet
|
||||||
|
// (b) The main thread is the only thread reading this sheet
|
||||||
|
// (c) The sheet is marked dirty after the write is completed,
|
||||||
|
// which causes the main thread to copy this to the texture during
|
||||||
|
// the next render cycle.
|
||||||
|
// (d) Any partially written bytes from the next minimap is in an
|
||||||
|
// unallocated area, and will be committed in the next cycle.
|
||||||
|
var bitmap = p.CustomPreview ?? Minimap.RenderMapPreview(p.Map, true);
|
||||||
|
p.Minimap = sheetBuilder.Add(bitmap);
|
||||||
|
|
||||||
|
lock (syncRoot)
|
||||||
|
generateMinimap.Dequeue();
|
||||||
|
|
||||||
|
// Yuck... But this helps the UI Jank when opening the map selector significantly.
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CacheMinimap(MapPreview preview)
|
||||||
|
{
|
||||||
|
lock (syncRoot)
|
||||||
|
generateMinimap.Enqueue(preview);
|
||||||
|
|
||||||
|
if (previewLoaderThread == null || !previewLoaderThread.IsAlive)
|
||||||
|
{
|
||||||
|
previewLoaderThread = new Thread(LoadAsyncInternal);
|
||||||
|
previewLoaderThread.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapPreview this[string key]
|
||||||
|
{
|
||||||
|
get { return previews[key]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<MapPreview> GetEnumerator()
|
||||||
|
{
|
||||||
|
return previews.Values.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
OpenRA.Game/MapPreview.cs
Executable file
93
OpenRA.Game/MapPreview.cs
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
|
namespace OpenRA
|
||||||
|
{
|
||||||
|
public enum MapStatus { Available, Unavailable }
|
||||||
|
public class MapPreview
|
||||||
|
{
|
||||||
|
static readonly List<CPos> NoSpawns = new List<CPos>();
|
||||||
|
|
||||||
|
public readonly string Uid;
|
||||||
|
public string Title { get; private set; }
|
||||||
|
public string Type { get; private set; }
|
||||||
|
public string Author { get; private set; }
|
||||||
|
public int PlayerCount { get; private set; }
|
||||||
|
public List<CPos> SpawnPoints { get; private set; }
|
||||||
|
public Rectangle Bounds { get; private set; }
|
||||||
|
public Bitmap CustomPreview { get; private set; }
|
||||||
|
public Map Map { get; private set; }
|
||||||
|
public MapStatus Status { get; private set; }
|
||||||
|
|
||||||
|
Sprite minimap;
|
||||||
|
bool generatingMinimap;
|
||||||
|
public Sprite Minimap
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (minimap != null)
|
||||||
|
return minimap;
|
||||||
|
|
||||||
|
if (!generatingMinimap && Status == MapStatus.Available)
|
||||||
|
{
|
||||||
|
generatingMinimap = true;
|
||||||
|
cache.CacheMinimap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
minimap = value;
|
||||||
|
generatingMinimap = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MapCache cache;
|
||||||
|
public MapPreview(string uid, MapCache cache)
|
||||||
|
{
|
||||||
|
this.cache = cache;
|
||||||
|
Uid = uid;
|
||||||
|
Title = "Unknown Map";
|
||||||
|
Type = "Unknown";
|
||||||
|
Author = "Unknown Author";
|
||||||
|
PlayerCount = 0;
|
||||||
|
Bounds = Rectangle.Empty;
|
||||||
|
SpawnPoints = NoSpawns;
|
||||||
|
Status = MapStatus.Unavailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateFromMap(Map m)
|
||||||
|
{
|
||||||
|
Map = m;
|
||||||
|
Title = m.Title;
|
||||||
|
Type = m.Type;
|
||||||
|
Type = m.Type;
|
||||||
|
Author = m.Author;
|
||||||
|
PlayerCount = m.Players.Count(x => x.Value.Playable);
|
||||||
|
Bounds = m.Bounds;
|
||||||
|
SpawnPoints = m.GetSpawnPoints().ToList();
|
||||||
|
CustomPreview = m.CustomPreview;
|
||||||
|
Status = MapStatus.Available;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,34 +22,13 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public readonly Manifest Manifest;
|
public readonly Manifest Manifest;
|
||||||
public readonly ObjectCreator ObjectCreator;
|
public readonly ObjectCreator ObjectCreator;
|
||||||
public Dictionary<string, Map> AvailableMaps { get; private set; }
|
|
||||||
public readonly WidgetLoader WidgetLoader;
|
public readonly WidgetLoader WidgetLoader;
|
||||||
|
public readonly MapCache MapCache;
|
||||||
public ILoadScreen LoadScreen = null;
|
public ILoadScreen LoadScreen = null;
|
||||||
public SheetBuilder SheetBuilder;
|
public SheetBuilder SheetBuilder;
|
||||||
public SpriteLoader SpriteLoader;
|
public SpriteLoader SpriteLoader;
|
||||||
public VoxelLoader VoxelLoader;
|
public VoxelLoader VoxelLoader;
|
||||||
|
|
||||||
public static IEnumerable<string> FindMapsIn(string dir)
|
|
||||||
{
|
|
||||||
string[] noMaps = { };
|
|
||||||
|
|
||||||
// ignore optional flag
|
|
||||||
if (dir.StartsWith("~"))
|
|
||||||
dir = dir.Substring(1);
|
|
||||||
|
|
||||||
// paths starting with ^ are relative to the user directory
|
|
||||||
if (dir.StartsWith("^"))
|
|
||||||
dir = Platform.SupportDir + dir.Substring(1);
|
|
||||||
|
|
||||||
if (!Directory.Exists(dir))
|
|
||||||
return noMaps;
|
|
||||||
|
|
||||||
var dirsWithMaps = Directory.GetDirectories(dir)
|
|
||||||
.Where(d => Directory.GetFiles(d, "map.yaml").Any() && Directory.GetFiles(d, "map.bin").Any());
|
|
||||||
|
|
||||||
return dirsWithMaps.Concat(Directory.GetFiles(dir, "*.oramap"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModData(string mod)
|
public ModData(string mod)
|
||||||
{
|
{
|
||||||
Languages = new string[0];
|
Languages = new string[0];
|
||||||
@@ -59,6 +38,7 @@ namespace OpenRA
|
|||||||
LoadScreen.Init(Manifest, Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
|
LoadScreen.Init(Manifest, Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
|
||||||
LoadScreen.Display();
|
LoadScreen.Display();
|
||||||
WidgetLoader = new WidgetLoader(this);
|
WidgetLoader = new WidgetLoader(this);
|
||||||
|
MapCache = new MapCache(Manifest);
|
||||||
|
|
||||||
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
||||||
FileSystem.UnmountAll();
|
FileSystem.UnmountAll();
|
||||||
@@ -119,17 +99,13 @@ namespace OpenRA
|
|||||||
FieldLoader.Translations = translations;
|
FieldLoader.Translations = translations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadMaps()
|
|
||||||
{
|
|
||||||
AvailableMaps = FindMaps();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map PrepareMap(string uid)
|
public Map PrepareMap(string uid)
|
||||||
{
|
{
|
||||||
LoadScreen.Display();
|
LoadScreen.Display();
|
||||||
if (!AvailableMaps.ContainsKey(uid))
|
|
||||||
|
var map = MapCache[uid].Map;
|
||||||
|
if (map == null)
|
||||||
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
||||||
var map = new Map(AvailableMaps[uid].Path);
|
|
||||||
|
|
||||||
LoadTranslations(map);
|
LoadTranslations(map);
|
||||||
|
|
||||||
@@ -148,33 +124,6 @@ namespace OpenRA
|
|||||||
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences);
|
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, Map> FindMaps()
|
|
||||||
{
|
|
||||||
var paths = Manifest.MapFolders.SelectMany(f => FindMapsIn(f));
|
|
||||||
var ret = new Dictionary<string, Map>();
|
|
||||||
foreach (var path in paths)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var map = new Map(path, Manifest.Mod.Id);
|
|
||||||
if (Manifest.MapCompatibility.Contains(map.RequiresMod))
|
|
||||||
ret.Add(map.Uid, map);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Failed to load map: {0}", path);
|
|
||||||
Console.WriteLine("Details: {0}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map FindMapByUid(string uid)
|
|
||||||
{
|
|
||||||
return AvailableMaps.ContainsKey(uid) ? AvailableMaps[uid] : null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ILoadScreen
|
public interface ILoadScreen
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace OpenRA.Network
|
|||||||
|
|
||||||
// Don't have the map locally
|
// Don't have the map locally
|
||||||
// TODO: We allow joining, then drop on game start if the map isn't available
|
// TODO: We allow joining, then drop on game start if the map isn't available
|
||||||
if (!Game.modData.AvailableMaps.ContainsKey(Map) && !Game.Settings.Game.AllowDownloading)
|
if (Game.modData.MapCache[Map].Status != MapStatus.Available && !Game.Settings.Game.AllowDownloading)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2011 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OpenRA.Network
|
|
||||||
{
|
|
||||||
public class Replay
|
|
||||||
{
|
|
||||||
public readonly string Filename;
|
|
||||||
public readonly int Duration;
|
|
||||||
public readonly Session LobbyInfo;
|
|
||||||
|
|
||||||
public Replay(string filename)
|
|
||||||
{
|
|
||||||
Filename = filename;
|
|
||||||
|
|
||||||
using (var conn = new ReplayConnection(filename))
|
|
||||||
{
|
|
||||||
Duration = conn.TickCount * Game.NetTickScale;
|
|
||||||
LobbyInfo = conn.LobbyInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map Map()
|
|
||||||
{
|
|
||||||
if (LobbyInfo == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var map = LobbyInfo.GlobalSettings.Map;
|
|
||||||
if (!Game.modData.AvailableMaps.ContainsKey(map))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return Game.modData.AvailableMaps[map];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2011 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using OpenRA.FileFormats;
|
|
||||||
|
|
||||||
namespace OpenRA.Network
|
|
||||||
{
|
|
||||||
public static class ServerList
|
|
||||||
{
|
|
||||||
public static void Query(Action<GameServer[]> onComplete)
|
|
||||||
{
|
|
||||||
var masterServerUrl = Game.Settings.Server.MasterServer;
|
|
||||||
|
|
||||||
new Thread(() =>
|
|
||||||
{
|
|
||||||
GameServer[] games = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var str = GetData(new Uri(masterServerUrl + "list.php"));
|
|
||||||
|
|
||||||
var yaml = MiniYaml.FromString(str);
|
|
||||||
|
|
||||||
games = yaml.Select(a => FieldLoader.Load<GameServer>(a.Value))
|
|
||||||
.Where(gs => gs.Address != null).ToArray();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
Game.RunAfterTick(() => onComplete(games));
|
|
||||||
}) { IsBackground = true }.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
static string GetData(Uri uri)
|
|
||||||
{
|
|
||||||
var wc = new WebClient();
|
|
||||||
wc.Proxy = null;
|
|
||||||
var data = wc.DownloadData(uri);
|
|
||||||
return Encoding.UTF8.GetString(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -129,9 +129,7 @@
|
|||||||
<Compile Include="Network\Order.cs" />
|
<Compile Include="Network\Order.cs" />
|
||||||
<Compile Include="Network\OrderIO.cs" />
|
<Compile Include="Network\OrderIO.cs" />
|
||||||
<Compile Include="Network\OrderManager.cs" />
|
<Compile Include="Network\OrderManager.cs" />
|
||||||
<Compile Include="Network\Replay.cs" />
|
|
||||||
<Compile Include="Network\ReplayConnection.cs" />
|
<Compile Include="Network\ReplayConnection.cs" />
|
||||||
<Compile Include="Network\ServerList.cs" />
|
|
||||||
<Compile Include="Network\Session.cs" />
|
<Compile Include="Network\Session.cs" />
|
||||||
<Compile Include="Network\SyncReport.cs" />
|
<Compile Include="Network\SyncReport.cs" />
|
||||||
<Compile Include="Network\UnitOrders.cs" />
|
<Compile Include="Network\UnitOrders.cs" />
|
||||||
@@ -232,6 +230,8 @@
|
|||||||
<Compile Include="Traits\World\ActorMap.cs" />
|
<Compile Include="Traits\World\ActorMap.cs" />
|
||||||
<Compile Include="Widgets\HotkeyEntryWidget.cs" />
|
<Compile Include="Widgets\HotkeyEntryWidget.cs" />
|
||||||
<Compile Include="Effects\MoveFlash.cs" />
|
<Compile Include="Effects\MoveFlash.cs" />
|
||||||
|
<Compile Include="MapCache.cs" />
|
||||||
|
<Compile Include="MapPreview.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ namespace OpenRA.Widgets
|
|||||||
{
|
{
|
||||||
public class MapPreviewWidget : Widget
|
public class MapPreviewWidget : Widget
|
||||||
{
|
{
|
||||||
public Func<Map> Map = () => null;
|
public Func<MapPreview> Preview = () => null;
|
||||||
public Func<Dictionary<int2, Session.Client>> SpawnClients = () => new Dictionary<int2, Session.Client>();
|
public Func<Dictionary<CPos, Session.Client>> SpawnClients = () => new Dictionary<CPos, Session.Client>();
|
||||||
public Action<MouseInput> OnMouseDown = _ => {};
|
public Action<MouseInput> OnMouseDown = _ => {};
|
||||||
public bool IgnoreMouseInput = false;
|
public bool IgnoreMouseInput = false;
|
||||||
public bool ShowSpawnPoints = true;
|
public bool ShowSpawnPoints = true;
|
||||||
@@ -32,6 +32,9 @@ namespace OpenRA.Widgets
|
|||||||
Lazy<TooltipContainerWidget> tooltipContainer;
|
Lazy<TooltipContainerWidget> tooltipContainer;
|
||||||
public int TooltipSpawnIndex = -1;
|
public int TooltipSpawnIndex = -1;
|
||||||
|
|
||||||
|
Rectangle MapRect;
|
||||||
|
float PreviewScale = 0;
|
||||||
|
|
||||||
public MapPreviewWidget()
|
public MapPreviewWidget()
|
||||||
{
|
{
|
||||||
tooltipContainer = Lazy.New(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
tooltipContainer = Lazy.New(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||||
@@ -40,8 +43,7 @@ namespace OpenRA.Widgets
|
|||||||
protected MapPreviewWidget(MapPreviewWidget other)
|
protected MapPreviewWidget(MapPreviewWidget other)
|
||||||
: base(other)
|
: base(other)
|
||||||
{
|
{
|
||||||
lastMap = other.lastMap;
|
Preview = other.Preview;
|
||||||
Map = other.Map;
|
|
||||||
SpawnClients = other.SpawnClients;
|
SpawnClients = other.SpawnClients;
|
||||||
ShowSpawnPoints = other.ShowSpawnPoints;
|
ShowSpawnPoints = other.ShowSpawnPoints;
|
||||||
TooltipTemplate = other.TooltipTemplate;
|
TooltipTemplate = other.TooltipTemplate;
|
||||||
@@ -65,74 +67,51 @@ namespace OpenRA.Widgets
|
|||||||
|
|
||||||
public override void MouseEntered()
|
public override void MouseEntered()
|
||||||
{
|
{
|
||||||
if (TooltipContainer == null) return;
|
if (TooltipContainer != null)
|
||||||
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "preview", this }});
|
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "preview", this }});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MouseExited()
|
public override void MouseExited()
|
||||||
{
|
{
|
||||||
if (TooltipContainer == null) return;
|
if (TooltipContainer != null)
|
||||||
tooltipContainer.Value.RemoveTooltip();
|
tooltipContainer.Value.RemoveTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int2 ConvertToPreview(int2 point)
|
public int2 ConvertToPreview(CPos point)
|
||||||
{
|
{
|
||||||
var map = Map();
|
var preview = Preview();
|
||||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top)));
|
return new int2(MapRect.X + (int)(PreviewScale*(point.X - preview.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - preview.Bounds.Top)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Sheet mapChooserSheet;
|
Sprite minimap;
|
||||||
Sprite mapChooserSprite;
|
|
||||||
Map lastMap;
|
|
||||||
Rectangle MapRect;
|
|
||||||
float PreviewScale = 0;
|
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
var map = Map();
|
var preview = Preview();
|
||||||
if (map == null)
|
if (preview == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Preview unavailable
|
// Stash a copy of the minimap to ensure consistency
|
||||||
if (!Loaded)
|
// (it may be modified by another thread)
|
||||||
{
|
minimap = preview.Minimap;
|
||||||
GeneratePreview();
|
if (minimap == null)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (lastMap != map)
|
|
||||||
{
|
|
||||||
lastMap = map;
|
|
||||||
|
|
||||||
// Update image data
|
|
||||||
Bitmap preview;
|
|
||||||
lock (syncRoot)
|
|
||||||
preview = Previews[map.Uid];
|
|
||||||
|
|
||||||
if (mapChooserSheet == null || mapChooserSheet.Size.Width != preview.Width || mapChooserSheet.Size.Height != preview.Height)
|
|
||||||
mapChooserSheet = new Sheet(new Size(preview.Width, preview.Height));
|
|
||||||
|
|
||||||
mapChooserSheet.Texture.SetData(preview);
|
|
||||||
mapChooserSprite = new Sprite(mapChooserSheet, new Rectangle(0, 0, map.Bounds.Width, map.Bounds.Height), TextureChannel.Alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update map rect
|
// Update map rect
|
||||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height);
|
PreviewScale = Math.Min(RenderBounds.Width / minimap.size.X, RenderBounds.Height / minimap.size.Y);
|
||||||
var size = Math.Max(map.Bounds.Width, map.Bounds.Height);
|
var w = (int)(PreviewScale * minimap.size.X);
|
||||||
var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2;
|
var h = (int)(PreviewScale * minimap.size.Y);
|
||||||
var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2;
|
var x = RenderBounds.X + (RenderBounds.Width - w) / 2;
|
||||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale));
|
var y = RenderBounds.Y + (RenderBounds.Height - h) / 2;
|
||||||
|
MapRect = new Rectangle(x, y, w, h);
|
||||||
|
|
||||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(mapChooserSprite,
|
Game.Renderer.RgbaSpriteRenderer.DrawSprite(minimap, new float2(MapRect.Location), new float2(MapRect.Size));
|
||||||
new float2(MapRect.Location),
|
|
||||||
new float2(MapRect.Size));
|
|
||||||
|
|
||||||
TooltipSpawnIndex = -1;
|
TooltipSpawnIndex = -1;
|
||||||
if (ShowSpawnPoints)
|
if (ShowSpawnPoints)
|
||||||
{
|
{
|
||||||
var colors = SpawnClients().ToDictionary(c => c.Key, c => c.Value.Color.RGB);
|
var colors = SpawnClients().ToDictionary(c => c.Key, c => c.Value.Color.RGB);
|
||||||
|
|
||||||
var spawnPoints = map.GetSpawnPoints().ToList();
|
var spawnPoints = preview.SpawnPoints;
|
||||||
foreach (var p in spawnPoints)
|
foreach (var p in spawnPoints)
|
||||||
{
|
{
|
||||||
var owned = colors.ContainsKey(p);
|
var owned = colors.ContainsKey(p);
|
||||||
@@ -151,79 +130,6 @@ namespace OpenRA.Widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Async map preview generation bits
|
public bool Loaded { get { return minimap != null; } }
|
||||||
enum PreviewStatus { Invalid, Uncached, Generating, Cached }
|
|
||||||
static Thread previewLoaderThread;
|
|
||||||
static object syncRoot = new object();
|
|
||||||
static Queue<string> cacheUids = new Queue<string>();
|
|
||||||
static readonly Dictionary<string, Bitmap> Previews = new Dictionary<string, Bitmap>();
|
|
||||||
|
|
||||||
void LoadAsyncInternal()
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
string uid;
|
|
||||||
lock (syncRoot)
|
|
||||||
{
|
|
||||||
if (cacheUids.Count == 0)
|
|
||||||
break;
|
|
||||||
uid = cacheUids.Peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
var bitmap = Minimap.RenderMapPreview(Game.modData.AvailableMaps[uid], false);
|
|
||||||
lock (syncRoot)
|
|
||||||
{
|
|
||||||
// TODO: We should add previews to a sheet here (with multiple previews per sheet)
|
|
||||||
Previews.Add(uid, bitmap);
|
|
||||||
cacheUids.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yuck... But this helps the UI Jank when opening the map selector significantly.
|
|
||||||
Thread.Sleep(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compatibleTileset;
|
|
||||||
|
|
||||||
void GeneratePreview()
|
|
||||||
{
|
|
||||||
var m = Map();
|
|
||||||
if (m == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
compatibleTileset = Rules.TileSets.Values.Any(t => t.Id == m.Tileset);
|
|
||||||
|
|
||||||
var status = Status(m);
|
|
||||||
if (status == PreviewStatus.Uncached)
|
|
||||||
lock (syncRoot)
|
|
||||||
cacheUids.Enqueue(m.Uid);
|
|
||||||
|
|
||||||
if (previewLoaderThread == null || !previewLoaderThread.IsAlive)
|
|
||||||
{
|
|
||||||
previewLoaderThread = new Thread(LoadAsyncInternal);
|
|
||||||
previewLoaderThread.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PreviewStatus Status(Map m)
|
|
||||||
{
|
|
||||||
if (m == null)
|
|
||||||
return PreviewStatus.Invalid;
|
|
||||||
|
|
||||||
lock (syncRoot)
|
|
||||||
{
|
|
||||||
if (Previews.ContainsKey(m.Uid))
|
|
||||||
return PreviewStatus.Cached;
|
|
||||||
|
|
||||||
if (cacheUids.Contains(m.Uid))
|
|
||||||
return PreviewStatus.Generating;
|
|
||||||
|
|
||||||
if (!compatibleTileset)
|
|
||||||
return PreviewStatus.Invalid;
|
|
||||||
}
|
|
||||||
return PreviewStatus.Uncached;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Loaded { get { return Status(Map()) == PreviewStatus.Cached; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,14 +225,13 @@ namespace OpenRA.Widgets
|
|||||||
|
|
||||||
public static Action Once( Action a ) { return () => { if (a != null) { a(); a = null; } }; }
|
public static Action Once( Action a ) { return () => { if (a != null) { a(); a = null; } }; }
|
||||||
|
|
||||||
public static string ChooseInitialMap(string map)
|
public static string ChooseInitialMap(string initialUid)
|
||||||
{
|
{
|
||||||
var availableMaps = Game.modData.AvailableMaps;
|
if (string.IsNullOrEmpty(initialUid) || Game.modData.MapCache[initialUid].Status != MapStatus.Available)
|
||||||
if (string.IsNullOrEmpty(map) || !availableMaps.ContainsKey(map))
|
|
||||||
{
|
{
|
||||||
Func<Map, bool> isIdealMap = m =>
|
Func<MapPreview, bool> isIdealMap = m =>
|
||||||
{
|
{
|
||||||
if (!m.Selectable)
|
if (m.Status != MapStatus.Available || !m.Map.Selectable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Other map types may have confusing settings or gameplay
|
// Other map types may have confusing settings or gameplay
|
||||||
@@ -240,22 +239,22 @@ namespace OpenRA.Widgets
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Maps with bots disabled confuse new players
|
// Maps with bots disabled confuse new players
|
||||||
if (m.Players.Any(s => !s.Value.AllowBots))
|
if (m.Map.Players.Any(s => !s.Value.AllowBots))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Large maps expose unfortunate performance problems
|
// Large maps expose unfortunate performance problems
|
||||||
if (m.MapSize.X > 128 || m.MapSize.Y > 128)
|
if (m.Bounds.Width > 128 || m.Bounds.Height > 128)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var selected = availableMaps.Values.Where(m => isIdealMap(m)).RandomOrDefault(Game.CosmeticRandom) ??
|
var selected = Game.modData.MapCache.Where(m => isIdealMap(m)).RandomOrDefault(Game.CosmeticRandom) ??
|
||||||
availableMaps.Values.First(m => m.Selectable);
|
Game.modData.MapCache.First(m => m.Status == MapStatus.Available && m.Map.Selectable);
|
||||||
return selected.Uid;
|
return selected.Uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return initialUid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -52,14 +53,16 @@ namespace OpenRA.Lint
|
|||||||
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
||||||
Game.modData = new ModData(mod);
|
Game.modData = new ModData(mod);
|
||||||
|
|
||||||
var maps = new Map[] { new Map() };
|
IEnumerable<Map> maps;
|
||||||
if (!string.IsNullOrEmpty(map))
|
if (string.IsNullOrEmpty(map))
|
||||||
maps = new Map[] { new Map(map) };
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Game.modData.LoadMaps();
|
Game.modData.MapCache.LoadMaps();
|
||||||
maps = Game.modData.AvailableMaps.Values.ToArray();
|
maps = Game.modData.MapCache
|
||||||
|
.Where(m => m.Status == MapStatus.Available)
|
||||||
|
.Select(m => m.Map);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
maps = new [] { new Map(map) };
|
||||||
|
|
||||||
foreach (var testMap in maps)
|
foreach (var testMap in maps)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void WorldLoaded(World world, WorldRenderer wr)
|
public void WorldLoaded(World world, WorldRenderer wr)
|
||||||
{
|
{
|
||||||
|
var spawns = world.Map.GetSpawnPoints();
|
||||||
var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != null)
|
var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != null)
|
||||||
.Select(c => (CPos) world.Map.GetSpawnPoints()[c.SpawnPoint-1]).ToList();
|
.Select(c => spawns[c.SpawnPoint-1]).ToList();
|
||||||
var available = world.Map.GetSpawnPoints().Select(c => (CPos)c).Except(taken).ToList();
|
var available = spawns.Except(taken).ToList();
|
||||||
|
|
||||||
// Set spawn
|
// Set spawn
|
||||||
foreach (var kv in world.LobbyInfo.Slots)
|
foreach (var kv in world.LobbyInfo.Slots)
|
||||||
@@ -41,7 +42,7 @@ namespace OpenRA.Mods.RA
|
|||||||
var client = world.LobbyInfo.ClientInSlot(kv.Key);
|
var client = world.LobbyInfo.ClientInSlot(kv.Key);
|
||||||
var spid = (client == null || client.SpawnPoint == 0)
|
var spid = (client == null || client.SpawnPoint == 0)
|
||||||
? ChooseSpawnPoint(world, available, taken)
|
? ChooseSpawnPoint(world, available, taken)
|
||||||
: (CPos)world.Map.GetSpawnPoints()[client.SpawnPoint-1];
|
: world.Map.GetSpawnPoints()[client.SpawnPoint-1];
|
||||||
|
|
||||||
Start.Add(player, spid);
|
Start.Add(player, spid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server.ModData.AvailableMaps.ContainsKey(s))
|
if (server.ModData.MapCache[s].Status != MapStatus.Available)
|
||||||
{
|
{
|
||||||
server.SendOrderTo(conn, "Message", "Map was not found on server");
|
server.SendOrderTo(conn, "Message", "Map was not found on server");
|
||||||
return true;
|
return true;
|
||||||
@@ -720,7 +720,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
|
|
||||||
static void LoadMap(S server)
|
static void LoadMap(S server)
|
||||||
{
|
{
|
||||||
server.Map = new Map(server.ModData.AvailableMaps[server.LobbyInfo.GlobalSettings.Map].Path);
|
server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map].Map;
|
||||||
server.LobbyInfo.Slots = server.Map.Players
|
server.LobbyInfo.Slots = server.Map.Players
|
||||||
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
||||||
.Where(s => s != null)
|
.Where(s => s != null)
|
||||||
|
|||||||
@@ -20,27 +20,28 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
public class LobbyLogic
|
public class LobbyLogic
|
||||||
{
|
{
|
||||||
|
readonly Action onStart;
|
||||||
|
readonly Action onExit;
|
||||||
|
readonly OrderManager orderManager;
|
||||||
|
readonly bool skirmishMode;
|
||||||
|
|
||||||
enum PanelType { Players, Options, Kick }
|
enum PanelType { Players, Options, Kick }
|
||||||
PanelType panel = PanelType.Players;
|
PanelType panel = PanelType.Players;
|
||||||
|
|
||||||
Widget lobby;
|
Widget lobby;
|
||||||
Widget EditablePlayerTemplate, NonEditablePlayerTemplate, EmptySlotTemplate,
|
|
||||||
EditableSpectatorTemplate, NonEditableSpectatorTemplate, NewSpectatorTemplate;
|
Widget editablePlayerTemplate, nonEditablePlayerTemplate, emptySlotTemplate,
|
||||||
|
editableSpectatorTemplate, nonEditableSpectatorTemplate, newSpectatorTemplate;
|
||||||
|
|
||||||
ScrollPanelWidget chatPanel;
|
ScrollPanelWidget chatPanel;
|
||||||
Widget chatTemplate;
|
Widget chatTemplate;
|
||||||
|
|
||||||
ScrollPanelWidget Players;
|
ScrollPanelWidget players;
|
||||||
Dictionary<string, string> CountryNames;
|
Dictionary<string, string> countryNames;
|
||||||
string MapUid;
|
MapPreview preview = MapCache.UnknownMap;
|
||||||
Map Map;
|
|
||||||
|
|
||||||
ColorPreviewManagerWidget colorPreview;
|
ColorPreviewManagerWidget colorPreview;
|
||||||
|
|
||||||
readonly Action OnGameStart;
|
|
||||||
readonly Action onExit;
|
|
||||||
readonly OrderManager orderManager;
|
|
||||||
readonly bool skirmishMode;
|
|
||||||
|
|
||||||
// Listen for connection failures
|
// Listen for connection failures
|
||||||
void ConnectionStateChanged(OrderManager om)
|
void ConnectionStateChanged(OrderManager om)
|
||||||
{
|
{
|
||||||
@@ -54,7 +55,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
Game.OpenWindow("SERVER_LOBBY", new WidgetArgs()
|
Game.OpenWindow("SERVER_LOBBY", new WidgetArgs()
|
||||||
{
|
{
|
||||||
{ "onExit", onExit },
|
{ "onExit", onExit },
|
||||||
{ "onStart", OnGameStart },
|
{ "onStart", onStart },
|
||||||
{ "skirmishMode", false }
|
{ "skirmishMode", false }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -90,7 +91,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
lobby = widget;
|
lobby = widget;
|
||||||
this.orderManager = orderManager;
|
this.orderManager = orderManager;
|
||||||
this.OnGameStart = () => { CloseWindow(); onStart(); };
|
this.onStart = onStart;
|
||||||
this.onExit = onExit;
|
this.onExit = onExit;
|
||||||
this.skirmishMode = skirmishMode;
|
this.skirmishMode = skirmishMode;
|
||||||
|
|
||||||
@@ -105,49 +106,43 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
name.GetText = () => orderManager.LobbyInfo.GlobalSettings.ServerName;
|
name.GetText = () => orderManager.LobbyInfo.GlobalSettings.ServerName;
|
||||||
|
|
||||||
UpdateCurrentMap();
|
UpdateCurrentMap();
|
||||||
Players = Ui.LoadWidget<ScrollPanelWidget>("LOBBY_PLAYER_BIN", lobby.Get("PLAYER_BIN_ROOT"), new WidgetArgs());
|
players = Ui.LoadWidget<ScrollPanelWidget>("LOBBY_PLAYER_BIN", lobby.Get("PLAYER_BIN_ROOT"), new WidgetArgs());
|
||||||
Players.IsVisible = () => panel == PanelType.Players;
|
players.IsVisible = () => panel == PanelType.Players;
|
||||||
|
|
||||||
EditablePlayerTemplate = Players.Get("TEMPLATE_EDITABLE_PLAYER");
|
var playerBinHeaders = lobby.GetOrNull<ContainerWidget>("LABEL_CONTAINER");
|
||||||
NonEditablePlayerTemplate = Players.Get("TEMPLATE_NONEDITABLE_PLAYER");
|
if (playerBinHeaders != null)
|
||||||
EmptySlotTemplate = Players.Get("TEMPLATE_EMPTY");
|
playerBinHeaders.IsVisible = () => panel == PanelType.Players;
|
||||||
EditableSpectatorTemplate = Players.Get("TEMPLATE_EDITABLE_SPECTATOR");
|
|
||||||
NonEditableSpectatorTemplate = Players.Get("TEMPLATE_NONEDITABLE_SPECTATOR");
|
editablePlayerTemplate = players.Get("TEMPLATE_EDITABLE_PLAYER");
|
||||||
NewSpectatorTemplate = Players.Get("TEMPLATE_NEW_SPECTATOR");
|
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 = lobby.Get<ColorPreviewManagerWidget>("COLOR_MANAGER");
|
||||||
colorPreview.Color = Game.Settings.Player.Color;
|
colorPreview.Color = Game.Settings.Player.Color;
|
||||||
|
|
||||||
var mapPreview = lobby.Get<MapPreviewWidget>("MAP_PREVIEW");
|
var mapPreview = lobby.Get<MapPreviewWidget>("MAP_PREVIEW");
|
||||||
mapPreview.IsVisible = () => Map != null;
|
mapPreview.Preview = () => preview;
|
||||||
mapPreview.Map = () => Map;
|
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, preview, mi);
|
||||||
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, Map, mi);
|
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, preview);
|
||||||
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, Map);
|
|
||||||
|
|
||||||
var mapTitle = lobby.GetOrNull<LabelWidget>("MAP_TITLE");
|
var mapTitle = lobby.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||||
if (mapTitle != null)
|
if (mapTitle != null)
|
||||||
{
|
mapTitle.GetText = () => preview.Title;
|
||||||
mapTitle.IsVisible = () => Map != null;
|
|
||||||
mapTitle.GetText = () => Map.Title;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mapType = lobby.GetOrNull<LabelWidget>("MAP_TYPE");
|
var mapType = lobby.GetOrNull<LabelWidget>("MAP_TYPE");
|
||||||
if (mapType != null)
|
if (mapType != null)
|
||||||
{
|
mapType.GetText = () => preview.Type;
|
||||||
mapType.IsVisible = () => Map != null;
|
|
||||||
mapType.GetText = () => Map.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mapAuthor = lobby.GetOrNull<LabelWidget>("MAP_AUTHOR");
|
var mapAuthor = lobby.GetOrNull<LabelWidget>("MAP_AUTHOR");
|
||||||
if (mapAuthor != null)
|
if (mapAuthor != null)
|
||||||
{
|
mapAuthor.GetText = () => "Created by {0}".F(preview.Author);
|
||||||
mapAuthor.IsVisible = () => Map != null;
|
|
||||||
mapAuthor.GetText = () => "Created by {0}".F(Map.Author);
|
|
||||||
}
|
|
||||||
|
|
||||||
CountryNames = Rules.Info["world"].Traits.WithInterface<CountryInfo>()
|
countryNames = Rules.Info["world"].Traits.WithInterface<CountryInfo>()
|
||||||
.Where(c => c.Selectable)
|
.Where(c => c.Selectable)
|
||||||
.ToDictionary(a => a.Race, a => a.Name);
|
.ToDictionary(a => a.Race, a => a.Name);
|
||||||
CountryNames.Add("random", "Any");
|
countryNames.Add("random", "Any");
|
||||||
|
|
||||||
var gameStarting = false;
|
var gameStarting = false;
|
||||||
Func<bool> configurationDisabled = () => !Game.IsHost || gameStarting || panel == PanelType.Kick ||
|
Func<bool> configurationDisabled = () => !Game.IsHost || gameStarting || panel == PanelType.Kick ||
|
||||||
@@ -159,16 +154,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
mapButton.IsDisabled = configurationDisabled;
|
mapButton.IsDisabled = configurationDisabled;
|
||||||
mapButton.OnClick = () =>
|
mapButton.OnClick = () =>
|
||||||
{
|
{
|
||||||
var onSelect = new Action<Map>(m =>
|
var onSelect = new Action<string>(uid =>
|
||||||
{
|
{
|
||||||
orderManager.IssueOrder(Order.Command("map " + m.Uid));
|
orderManager.IssueOrder(Order.Command("map " + uid));
|
||||||
Game.Settings.Server.Map = m.Uid;
|
Game.Settings.Server.Map = uid;
|
||||||
Game.Settings.Save();
|
Game.Settings.Save();
|
||||||
});
|
});
|
||||||
|
|
||||||
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
||||||
{
|
{
|
||||||
{ "initialMap", Map.Uid },
|
{ "initialMap", preview.Uid },
|
||||||
{ "onExit", () => { } },
|
{ "onExit", () => { } },
|
||||||
{ "onSelect", onSelect }
|
{ "onSelect", onSelect }
|
||||||
});
|
});
|
||||||
@@ -181,7 +176,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
slotsButton.IsDisabled = () => configurationDisabled() || panel != PanelType.Players ||
|
slotsButton.IsDisabled = () => configurationDisabled() || panel != PanelType.Players ||
|
||||||
!orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots || !s.LockTeam);
|
!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 = _ =>
|
slotsButton.OnMouseDown = _ =>
|
||||||
{
|
{
|
||||||
var options = new Dictionary<string, IEnumerable<DropDownOption>>();
|
var options = new Dictionary<string, IEnumerable<DropDownOption>>();
|
||||||
@@ -189,7 +184,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
||||||
if (orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots))
|
if (orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots))
|
||||||
{
|
{
|
||||||
var botOptions = new List<DropDownOption>(){ new DropDownOption()
|
var botOptions = new List<DropDownOption>()
|
||||||
|
{
|
||||||
|
new DropDownOption()
|
||||||
{
|
{
|
||||||
Title = "Add",
|
Title = "Add",
|
||||||
IsSelected = () => false,
|
IsSelected = () => false,
|
||||||
@@ -197,13 +194,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
foreach (var slot in orderManager.LobbyInfo.Slots)
|
foreach (var slot in orderManager.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
var bot = aiModes.Random(Game.CosmeticRandom);
|
var bot = botNames.Random(Game.CosmeticRandom);
|
||||||
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
|
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
|
||||||
if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
|
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)));
|
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (orderManager.LobbyInfo.Clients.Any(c => c.Bot != null))
|
if (orderManager.LobbyInfo.Clients.Any(c => c.Bot != null))
|
||||||
{
|
{
|
||||||
@@ -299,7 +297,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (allowCheats != null)
|
if (allowCheats != null)
|
||||||
{
|
{
|
||||||
allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats;
|
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.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats)));
|
"allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats)));
|
||||||
}
|
}
|
||||||
@@ -308,7 +306,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (crates != null)
|
if (crates != null)
|
||||||
{
|
{
|
||||||
crates.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Crates;
|
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.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"crates {0}".F(!orderManager.LobbyInfo.GlobalSettings.Crates)));
|
"crates {0}".F(!orderManager.LobbyInfo.GlobalSettings.Crates)));
|
||||||
}
|
}
|
||||||
@@ -317,7 +315,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (allybuildradius != null)
|
if (allybuildradius != null)
|
||||||
{
|
{
|
||||||
allybuildradius.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius;
|
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.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"allybuildradius {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius)));
|
"allybuildradius {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius)));
|
||||||
}
|
}
|
||||||
@@ -326,7 +324,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (fragileAlliance != null)
|
if (fragileAlliance != null)
|
||||||
{
|
{
|
||||||
fragileAlliance.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.FragileAlliances;
|
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.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"fragilealliance {0}".F(!orderManager.LobbyInfo.GlobalSettings.FragileAlliances)));
|
"fragilealliance {0}".F(!orderManager.LobbyInfo.GlobalSettings.FragileAlliances)));
|
||||||
}
|
}
|
||||||
@@ -334,12 +332,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var difficulty = optionsBin.GetOrNull<DropDownButtonWidget>("DIFFICULTY_DROPDOWNBUTTON");
|
var difficulty = optionsBin.GetOrNull<DropDownButtonWidget>("DIFFICULTY_DROPDOWNBUTTON");
|
||||||
if (difficulty != null)
|
if (difficulty != null)
|
||||||
{
|
{
|
||||||
difficulty.IsVisible = () => Map.Options.Difficulties.Any();
|
difficulty.IsVisible = () => preview.Status == MapStatus.Available && preview.Map.Options.Difficulties.Any();
|
||||||
difficulty.IsDisabled = configurationDisabled;
|
difficulty.IsDisabled = () => preview.Status != MapStatus.Available || configurationDisabled();
|
||||||
difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty;
|
difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty;
|
||||||
difficulty.OnMouseDown = _ =>
|
difficulty.OnMouseDown = _ =>
|
||||||
{
|
{
|
||||||
var options = Map.Options.Difficulties.Select(d => new DropDownOption
|
var options = preview.Map.Options.Difficulties.Select(d => new DropDownOption
|
||||||
{
|
{
|
||||||
Title = d,
|
Title = d,
|
||||||
IsSelected = () => orderManager.LobbyInfo.GlobalSettings.Difficulty == d,
|
IsSelected = () => orderManager.LobbyInfo.GlobalSettings.Difficulty == d,
|
||||||
@@ -371,8 +369,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var classes = Rules.Info["world"].Traits.WithInterface<MPStartUnitsInfo>()
|
var classes = Rules.Info["world"].Traits.WithInterface<MPStartUnitsInfo>()
|
||||||
.Select(a => a.Class).Distinct();
|
.Select(a => a.Class).Distinct();
|
||||||
|
|
||||||
startingUnits.IsDisabled = () => !Map.Options.ConfigurableStartingUnits || configurationDisabled();
|
startingUnits.IsDisabled = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits || configurationDisabled();
|
||||||
startingUnits.GetText = () => !Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
|
startingUnits.GetText = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
|
||||||
startingUnits.OnMouseDown = _ =>
|
startingUnits.OnMouseDown = _ =>
|
||||||
{
|
{
|
||||||
var options = classes.Select(c => new DropDownOption
|
var options = classes.Select(c => new DropDownOption
|
||||||
@@ -398,8 +396,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var startingCash = optionsBin.GetOrNull<DropDownButtonWidget>("STARTINGCASH_DROPDOWNBUTTON");
|
var startingCash = optionsBin.GetOrNull<DropDownButtonWidget>("STARTINGCASH_DROPDOWNBUTTON");
|
||||||
if (startingCash != null)
|
if (startingCash != null)
|
||||||
{
|
{
|
||||||
startingCash.IsDisabled = () => Map.Options.StartingCash.HasValue || configurationDisabled();
|
startingCash.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue || configurationDisabled();
|
||||||
startingCash.GetText = () => Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
|
startingCash.GetText = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
|
||||||
startingCash.OnMouseDown = _ =>
|
startingCash.OnMouseDown = _ =>
|
||||||
{
|
{
|
||||||
var options = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>().SelectableCash.Select(c => new DropDownOption
|
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)
|
if (enableShroud != null)
|
||||||
{
|
{
|
||||||
enableShroud.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Shroud;
|
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(
|
enableShroud.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"shroud {0}".F(!orderManager.LobbyInfo.GlobalSettings.Shroud)));
|
"shroud {0}".F(!orderManager.LobbyInfo.GlobalSettings.Shroud)));
|
||||||
}
|
}
|
||||||
@@ -433,7 +431,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (enableFog != null)
|
if (enableFog != null)
|
||||||
{
|
{
|
||||||
enableFog.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Fog;
|
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(
|
enableFog.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||||
"fog {0}".F(!orderManager.LobbyInfo.GlobalSettings.Fog)));
|
"fog {0}".F(!orderManager.LobbyInfo.GlobalSettings.Fog)));
|
||||||
}
|
}
|
||||||
@@ -461,7 +459,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
chatTextField.OnTabKey = () =>
|
chatTextField.OnTabKey = () =>
|
||||||
{
|
{
|
||||||
teamChat ^= true;
|
teamChat ^= true;
|
||||||
chatLabel.Text = (teamChat) ? "Team:" : "Chat:";
|
chatLabel.Text = teamChat ? "Team:" : "Chat:";
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -471,8 +469,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
var musicButton = lobby.GetOrNull<ButtonWidget>("MUSIC_BUTTON");
|
var musicButton = lobby.GetOrNull<ButtonWidget>("MUSIC_BUTTON");
|
||||||
if (musicButton != null)
|
if (musicButton != null)
|
||||||
musicButton.OnClick = () => Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs
|
musicButton.OnClick = () => Ui.OpenWindow("MUSIC_PANEL",
|
||||||
{ { "onExit", () => {} } });
|
new WidgetArgs { { "onExit", () => { } } });
|
||||||
|
|
||||||
// Add a bot on the first lobbyinfo update
|
// Add a bot on the first lobbyinfo update
|
||||||
if (this.skirmishMode)
|
if (this.skirmishMode)
|
||||||
@@ -523,23 +521,25 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
void UpdateCurrentMap()
|
void UpdateCurrentMap()
|
||||||
{
|
{
|
||||||
if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map)
|
var uid = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||||
|
if (preview.Uid == uid)
|
||||||
return;
|
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)
|
if (Game.Settings.Game.AllowDownloading)
|
||||||
{
|
{
|
||||||
Game.DownloadMap (MapUid);
|
Game.DownloadMap(uid);
|
||||||
Game.Debug("A new map has been downloaded...");
|
Game.Debug("A new map has been downloaded...");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new InvalidOperationException("Server's new map doesn't exist on your system and Downloading turned off");
|
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
|
// Restore default starting cash if the last map set it to something invalid
|
||||||
var pri = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>();
|
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)));
|
orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,14 +554,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
Widget template = null;
|
Widget template = null;
|
||||||
|
|
||||||
// get template for possible reuse
|
// get template for possible reuse
|
||||||
if (idx < Players.Children.Count)
|
if (idx < players.Children.Count)
|
||||||
template = Players.Children[idx];
|
template = players.Children[idx];
|
||||||
|
|
||||||
// Empty slot
|
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
if (template == null || template.Id != EmptySlotTemplate.Id)
|
// Empty slot
|
||||||
template = EmptySlotTemplate.Clone();
|
if (template == null || template.Id != emptySlotTemplate.Id)
|
||||||
|
template = emptySlotTemplate.Clone();
|
||||||
|
|
||||||
if (Game.IsHost)
|
if (Game.IsHost)
|
||||||
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager);
|
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager);
|
||||||
@@ -573,13 +573,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
join.IsDisabled = () => orderManager.LocalClient.IsReady;
|
join.IsDisabled = () => orderManager.LocalClient.IsReady;
|
||||||
join.OnClick = () => orderManager.IssueOrder(Order.Command("slot " + key));
|
join.OnClick = () => orderManager.IssueOrder(Order.Command("slot " + key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Editable player in slot
|
|
||||||
else if ((client.Index == orderManager.LocalClient.Index) ||
|
else if ((client.Index == orderManager.LocalClient.Index) ||
|
||||||
(client.Bot != null && Game.IsHost))
|
(client.Bot != null && Game.IsHost))
|
||||||
{
|
{
|
||||||
if (template == null || template.Id != EditablePlayerTemplate.Id)
|
// Editable player in slot
|
||||||
template = EditablePlayerTemplate.Clone();
|
if (template == null || template.Id != editablePlayerTemplate.Id)
|
||||||
|
template = editablePlayerTemplate.Clone();
|
||||||
|
|
||||||
LobbyUtils.SetupClientWidget(template, slot, client, orderManager, client.Bot == null);
|
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.SetupEditableNameWidget(template, slot, client, orderManager);
|
||||||
|
|
||||||
LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview);
|
LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview);
|
||||||
LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, CountryNames);
|
LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, countryNames);
|
||||||
LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, Map.GetSpawnPoints().Length);
|
LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, preview.SpawnPoints.Count);
|
||||||
LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager);
|
LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // Non-editable player in slot
|
{
|
||||||
if (template == null || template.Id != NonEditablePlayerTemplate.Id)
|
// Non-editable player in slot
|
||||||
template = NonEditablePlayerTemplate.Clone();
|
if (template == null || template.Id != nonEditablePlayerTemplate.Id)
|
||||||
|
template = nonEditablePlayerTemplate.Clone();
|
||||||
|
|
||||||
LobbyUtils.SetupClientWidget(template, slot, client, orderManager, client.Bot == null);
|
LobbyUtils.SetupClientWidget(template, slot, client, orderManager, client.Bot == null);
|
||||||
LobbyUtils.SetupNameWidget(template, slot, client);
|
LobbyUtils.SetupNameWidget(template, slot, client);
|
||||||
LobbyUtils.SetupKickWidget(template, slot, client, orderManager, lobby,
|
LobbyUtils.SetupKickWidget(template, slot, client, orderManager, lobby,
|
||||||
() => panel = PanelType.Kick, () => panel = PanelType.Players);
|
() => panel = PanelType.Kick, () => panel = PanelType.Players);
|
||||||
LobbyUtils.SetupColorWidget(template, slot, client);
|
LobbyUtils.SetupColorWidget(template, slot, client);
|
||||||
LobbyUtils.SetupFactionWidget(template, slot, client, CountryNames);
|
LobbyUtils.SetupFactionWidget(template, slot, client, countryNames);
|
||||||
LobbyUtils.SetupTeamWidget(template, slot, client);
|
LobbyUtils.SetupTeamWidget(template, slot, client);
|
||||||
LobbyUtils.SetupReadyWidget(template, slot, client);
|
LobbyUtils.SetupReadyWidget(template, slot, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
template.IsVisible = () => true;
|
template.IsVisible = () => true;
|
||||||
|
|
||||||
if (idx >= Players.Children.Count)
|
if (idx >= players.Children.Count)
|
||||||
Players.AddChild(template);
|
players.AddChild(template);
|
||||||
else if (Players.Children[idx].Id != template.Id)
|
else if (players.Children[idx].Id != template.Id)
|
||||||
Players.ReplaceChild(Players.Children[idx], template);
|
players.ReplaceChild(players.Children[idx], template);
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@@ -625,22 +625,22 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var c = client;
|
var c = client;
|
||||||
|
|
||||||
// get template for possible reuse
|
// get template for possible reuse
|
||||||
if (idx < Players.Children.Count)
|
if (idx < players.Children.Count)
|
||||||
template = Players.Children[idx];
|
template = players.Children[idx];
|
||||||
|
|
||||||
// Editable spectator
|
// Editable spectator
|
||||||
if (c.Index == orderManager.LocalClient.Index)
|
if (c.Index == orderManager.LocalClient.Index)
|
||||||
{
|
{
|
||||||
if (template == null || template.Id != EditableSpectatorTemplate.Id)
|
if (template == null || template.Id != editableSpectatorTemplate.Id)
|
||||||
template = EditableSpectatorTemplate.Clone();
|
template = editableSpectatorTemplate.Clone();
|
||||||
|
|
||||||
LobbyUtils.SetupEditableNameWidget(template, null, c, orderManager);
|
LobbyUtils.SetupEditableNameWidget(template, null, c, orderManager);
|
||||||
}
|
}
|
||||||
// Non-editable spectator
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (template == null || template.Id != NonEditableSpectatorTemplate.Id)
|
// Non-editable spectator
|
||||||
template = NonEditableSpectatorTemplate.Clone();
|
if (template == null || template.Id != nonEditableSpectatorTemplate.Id)
|
||||||
|
template = nonEditableSpectatorTemplate.Clone();
|
||||||
|
|
||||||
LobbyUtils.SetupNameWidget(template, null, client);
|
LobbyUtils.SetupNameWidget(template, null, client);
|
||||||
LobbyUtils.SetupKickWidget(template, null, client, orderManager, lobby,
|
LobbyUtils.SetupKickWidget(template, null, client, orderManager, lobby,
|
||||||
@@ -650,10 +650,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
LobbyUtils.SetupClientWidget(template, null, c, orderManager, true);
|
LobbyUtils.SetupClientWidget(template, null, c, orderManager, true);
|
||||||
template.IsVisible = () => true;
|
template.IsVisible = () => true;
|
||||||
|
|
||||||
if (idx >= Players.Children.Count)
|
if (idx >= players.Children.Count)
|
||||||
Players.AddChild(template);
|
players.AddChild(template);
|
||||||
else if (Players.Children[idx].Id != template.Id)
|
else if (players.Children[idx].Id != template.Id)
|
||||||
Players.ReplaceChild(Players.Children[idx], template);
|
players.ReplaceChild(players.Children[idx], template);
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@@ -662,10 +662,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (orderManager.LocalClient.Slot != null)
|
if (orderManager.LocalClient.Slot != null)
|
||||||
{
|
{
|
||||||
Widget spec = null;
|
Widget spec = null;
|
||||||
if (idx < Players.Children.Count)
|
if (idx < players.Children.Count)
|
||||||
spec = Players.Children[idx];
|
spec = players.Children[idx];
|
||||||
if (spec == null || spec.Id != NewSpectatorTemplate.Id)
|
if (spec == null || spec.Id != newSpectatorTemplate.Id)
|
||||||
spec = NewSpectatorTemplate.Clone();
|
spec = newSpectatorTemplate.Clone();
|
||||||
|
|
||||||
LobbyUtils.SetupKickSpectatorsWidget(spec, orderManager, lobby,
|
LobbyUtils.SetupKickSpectatorsWidget(spec, orderManager, lobby,
|
||||||
() => panel = PanelType.Kick, () => panel = PanelType.Players, this.skirmishMode);
|
() => panel = PanelType.Kick, () => panel = PanelType.Players, this.skirmishMode);
|
||||||
@@ -678,16 +678,22 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
spec.IsVisible = () => true;
|
spec.IsVisible = () => true;
|
||||||
|
|
||||||
if (idx >= Players.Children.Count)
|
if (idx >= players.Children.Count)
|
||||||
Players.AddChild(spec);
|
players.AddChild(spec);
|
||||||
else if (Players.Children[idx].Id != spec.Id)
|
else if (players.Children[idx].Id != spec.Id)
|
||||||
Players.ReplaceChild(Players.Children[idx], spec);
|
players.ReplaceChild(players.Children[idx], spec);
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (Players.Children.Count > idx)
|
while (players.Children.Count > idx)
|
||||||
Players.RemoveChild(Players.Children[idx]);
|
players.RemoveChild(players.Children[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnGameStart()
|
||||||
|
{
|
||||||
|
CloseWindow();
|
||||||
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
class DropDownOption
|
class DropDownOption
|
||||||
|
|||||||
@@ -130,26 +130,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
color.AttachPanel(colorChooser, onExit);
|
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
|
return orderManager.LobbyInfo.Clients
|
||||||
.Where(c => c.SpawnPoint != 0)
|
.Where(c => c.SpawnPoint != 0)
|
||||||
.ToDictionary(
|
.ToDictionary(c => spawns[c.SpawnPoint - 1], c => c);
|
||||||
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)
|
if (mi.Button != MouseButton.Left)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready)
|
if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var selectedSpawn = map.GetSpawnPoints()
|
var selectedSpawn = preview.SpawnPoints
|
||||||
.Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp), i))
|
.Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp), i))
|
||||||
.Where(a => (a.First - mi.Location).LengthSquared < 64)
|
.Where(a => (a.First - mi.Location).LengthSquared < 64)
|
||||||
.Select(a => a.Second + 1)
|
.Select(a => a.Second + 1)
|
||||||
|
|||||||
@@ -18,21 +18,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
public class MapChooserLogic
|
public class MapChooserLogic
|
||||||
{
|
{
|
||||||
Map map;
|
string selectedUid;
|
||||||
|
|
||||||
// May be a subset of available maps if a mode filter is active
|
// May be a subset of available maps if a mode filter is active
|
||||||
Dictionary<string, Map> visibleMaps;
|
List<string> visibleMaps;
|
||||||
|
|
||||||
ScrollPanelWidget scrollpanel;
|
ScrollPanelWidget scrollpanel;
|
||||||
ScrollItemWidget itemTemplate;
|
ScrollItemWidget itemTemplate;
|
||||||
string gameMode;
|
string gameMode;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[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(); };
|
widget.Get<ButtonWidget>("BUTTON_CANCEL").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||||
|
|
||||||
scrollpanel = widget.Get<ScrollPanelWidget>("MAP_LIST");
|
scrollpanel = widget.Get<ScrollPanelWidget>("MAP_LIST");
|
||||||
@@ -44,9 +44,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var gameModeDropdown = widget.GetOrNull<DropDownButtonWidget>("GAMEMODE_FILTER");
|
var gameModeDropdown = widget.GetOrNull<DropDownButtonWidget>("GAMEMODE_FILTER");
|
||||||
if (gameModeDropdown != null)
|
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
|
var gameModes = selectableMaps
|
||||||
.GroupBy(m => m.Value.Type)
|
.GroupBy(m => m.Type)
|
||||||
.Select(g => Pair.New(g.Key, g.Count())).ToList();
|
.Select(g => Pair.New(g.Key, g.Count())).ToList();
|
||||||
|
|
||||||
// 'all game types' extra item
|
// 'all game types' extra item
|
||||||
@@ -75,9 +75,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
randomMapButton.OnClick = () =>
|
randomMapButton.OnClick = () =>
|
||||||
{
|
{
|
||||||
var kv = visibleMaps.Random(Game.CosmeticRandom);
|
var uid = visibleMaps.Random(Game.CosmeticRandom);
|
||||||
map = kv.Value;
|
selectedUid = uid;
|
||||||
scrollpanel.ScrollToItem(kv.Key);
|
scrollpanel.ScrollToItem(uid);
|
||||||
};
|
};
|
||||||
randomMapButton.IsDisabled = () => visibleMaps == null || visibleMaps.Count == 0;
|
randomMapButton.IsDisabled = () => visibleMaps == null || visibleMaps.Count == 0;
|
||||||
}
|
}
|
||||||
@@ -85,27 +85,27 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
EnumerateMaps(onSelect);
|
EnumerateMaps(onSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumerateMaps(Action<Map> onSelect)
|
void EnumerateMaps(Action<string> onSelect)
|
||||||
{
|
{
|
||||||
var maps = Game.modData.AvailableMaps
|
var maps = Game.modData.MapCache
|
||||||
.Where(kv => kv.Value.Selectable)
|
.Where(m => m.Status == MapStatus.Available && m.Map.Selectable)
|
||||||
.Where(kv => kv.Value.Type == gameMode || gameMode == null)
|
.Where(m => m.Type == gameMode || gameMode == null)
|
||||||
.OrderBy(kv => kv.Value.PlayerCount)
|
.OrderBy(m => m.PlayerCount)
|
||||||
.ThenBy(kv => kv.Value.Title);
|
.ThenBy(m => m.Title);
|
||||||
|
|
||||||
scrollpanel.RemoveChildren();
|
scrollpanel.RemoveChildren();
|
||||||
foreach (var kv in maps)
|
foreach (var loop in maps)
|
||||||
{
|
{
|
||||||
var m = kv.Value;
|
var preview = loop;
|
||||||
var item = ScrollItemWidget.Setup(kv.Key, itemTemplate, () => m == map, () => map = m, () => { Ui.CloseWindow(); onSelect(m); });
|
var item = ScrollItemWidget.Setup(preview.Uid, itemTemplate, () => selectedUid == preview.Uid, () => selectedUid = preview.Uid, () => { Ui.CloseWindow(); onSelect(preview.Uid); });
|
||||||
|
|
||||||
var titleLabel = item.Get<LabelWidget>("TITLE");
|
var titleLabel = item.Get<LabelWidget>("TITLE");
|
||||||
titleLabel.GetText = () => m.Title;
|
titleLabel.GetText = () => preview.Title;
|
||||||
|
|
||||||
var previewWidget = item.Get<MapPreviewWidget>("PREVIEW");
|
var previewWidget = item.Get<MapPreviewWidget>("PREVIEW");
|
||||||
previewWidget.IgnoreMouseOver = true;
|
previewWidget.IgnoreMouseOver = true;
|
||||||
previewWidget.IgnoreMouseInput = true;
|
previewWidget.IgnoreMouseInput = true;
|
||||||
previewWidget.Map = () => m;
|
previewWidget.Preview = () => preview;
|
||||||
previewWidget.IsVisible = () => previewWidget.RenderBounds.IntersectsWith(scrollpanel.RenderBounds);
|
previewWidget.IsVisible = () => previewWidget.RenderBounds.IntersectsWith(scrollpanel.RenderBounds);
|
||||||
|
|
||||||
var previewLoadingWidget = item.GetOrNull<BackgroundWidget>("PREVIEW_PLACEHOLDER");
|
var previewLoadingWidget = item.GetOrNull<BackgroundWidget>("PREVIEW_PLACEHOLDER");
|
||||||
@@ -114,17 +114,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
var detailsWidget = item.GetOrNull<LabelWidget>("DETAILS");
|
var detailsWidget = item.GetOrNull<LabelWidget>("DETAILS");
|
||||||
if (detailsWidget != null)
|
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");
|
var authorWidget = item.GetOrNull<LabelWidget>("AUTHOR");
|
||||||
if (authorWidget != null)
|
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");
|
var sizeWidget = item.GetOrNull<LabelWidget>("SIZE");
|
||||||
if (sizeWidget != null)
|
if (sizeWidget != null)
|
||||||
{
|
{
|
||||||
var size = m.Bounds.Width + "x" + m.Bounds.Height;
|
var size = preview.Bounds.Width + "x" + preview.Bounds.Height;
|
||||||
var numberPlayableCells = m.Bounds.Width * m.Bounds.Height;
|
var numberPlayableCells = preview.Bounds.Width * preview.Bounds.Height;
|
||||||
if (numberPlayableCells >= 120 * 120) size += " (Huge)";
|
if (numberPlayableCells >= 120 * 120) size += " (Huge)";
|
||||||
else if (numberPlayableCells >= 90 * 90) size += " (Large)";
|
else if (numberPlayableCells >= 90 * 90) size += " (Large)";
|
||||||
else if (numberPlayableCells >= 60 * 60) size += " (Medium)";
|
else if (numberPlayableCells >= 60 * 60) size += " (Medium)";
|
||||||
@@ -135,9 +135,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
scrollpanel.AddChild(item);
|
scrollpanel.AddChild(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
visibleMaps = maps.ToDictionary(kv => kv.Key, kv => kv.Value);
|
visibleMaps = maps.Select(m => m.Uid).ToList();
|
||||||
if (visibleMaps.ContainsValue(map))
|
if (visibleMaps.Contains(selectedUid))
|
||||||
scrollpanel.ScrollToItem(visibleMaps.First(m => m.Value == map).Key);
|
scrollpanel.ScrollToItem(selectedUid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
public class ReplayBrowserLogic
|
public class ReplayBrowserLogic
|
||||||
{
|
{
|
||||||
Widget panel;
|
Widget panel;
|
||||||
|
MapPreview selectedMap = MapCache.UnknownMap;
|
||||||
|
string selectedFilename;
|
||||||
|
string selectedDuration;
|
||||||
|
string selectedPlayers;
|
||||||
|
bool selectedValid;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ReplayBrowserLogic(Widget widget, Action onExit, Action onStart)
|
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");
|
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(); };
|
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)
|
void SelectReplay(string filename)
|
||||||
{
|
{
|
||||||
if (filename == null)
|
if (filename == null)
|
||||||
@@ -60,32 +66,31 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
currentReplay = new Replay(filename);
|
using (var conn = new ReplayConnection(filename))
|
||||||
currentMap = currentReplay.Map();
|
{
|
||||||
|
selectedFilename = filename;
|
||||||
panel.Get<LabelWidget>("DURATION").GetText =
|
selectedMap = Game.modData.MapCache[conn.LobbyInfo.GlobalSettings.Map];
|
||||||
() => WidgetUtils.FormatTime(currentReplay.Duration);
|
selectedDuration = WidgetUtils.FormatTime(conn.TickCount * Game.NetTickScale);
|
||||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Map = () => currentMap;
|
selectedPlayers = conn.LobbyInfo.Slots
|
||||||
panel.Get<LabelWidget>("MAP_TITLE").GetText =
|
.Count(s => conn.LobbyInfo.ClientInSlot(s.Key) != null)
|
||||||
() => currentMap != null ? currentMap.Title : "(Unknown Map)";
|
.ToString();
|
||||||
|
selectedValid = conn.TickCount > 0;
|
||||||
var players = currentReplay.LobbyInfo.Slots
|
}
|
||||||
.Count(s => currentReplay.LobbyInfo.ClientInSlot(s.Key) != null);
|
|
||||||
panel.Get<LabelWidget>("PLAYERS").GetText = () => players.ToString();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Write("debug", "Exception while parsing replay: {0}", e);
|
Log.Write("debug", "Exception while parsing replay: {0}", e);
|
||||||
currentReplay = null;
|
selectedFilename = null;
|
||||||
currentMap = null;
|
selectedValid = false;
|
||||||
|
selectedMap = MapCache.UnknownMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchReplay()
|
void WatchReplay()
|
||||||
{
|
{
|
||||||
if (currentReplay != null)
|
if (selectedFilename != null)
|
||||||
{
|
{
|
||||||
Game.JoinReplay(currentReplay.Filename);
|
Game.JoinReplay(selectedFilename);
|
||||||
Ui.CloseWindow();
|
Ui.CloseWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +98,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
void AddReplay(ScrollPanelWidget list, string filename, ScrollItemWidget template)
|
void AddReplay(ScrollPanelWidget list, string filename, ScrollItemWidget template)
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(template,
|
var item = ScrollItemWidget.Setup(template,
|
||||||
() => currentReplay != null && currentReplay.Filename == filename,
|
() => selectedFilename == filename,
|
||||||
() => SelectReplay(filename),
|
() => SelectReplay(filename),
|
||||||
() => WatchReplay());
|
() => WatchReplay());
|
||||||
var f = Path.GetFileName(filename);
|
var f = Path.GetFileName(filename);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Server;
|
using OpenRA.Server;
|
||||||
@@ -29,6 +31,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
enum SearchStatus { Fetching, Failed, NoGames, Hidden }
|
enum SearchStatus { Fetching, Failed, NoGames, Hidden }
|
||||||
SearchStatus searchStatus = SearchStatus.Fetching;
|
SearchStatus searchStatus = SearchStatus.Fetching;
|
||||||
|
Download currentQuery;
|
||||||
|
Widget panel, serverList;
|
||||||
|
|
||||||
bool showWaiting = true;
|
bool showWaiting = true;
|
||||||
bool showEmpty = true;
|
bool showEmpty = true;
|
||||||
@@ -39,7 +43,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
switch (searchStatus)
|
switch (searchStatus)
|
||||||
{
|
{
|
||||||
case SearchStatus.Fetching: return "Fetching game list...";
|
|
||||||
case SearchStatus.Failed: return "Failed to contact master server.";
|
case SearchStatus.Failed: return "Failed to contact master server.";
|
||||||
case SearchStatus.NoGames: return "No games found.";
|
case SearchStatus.NoGames: return "No games found.";
|
||||||
default: return "";
|
default: return "";
|
||||||
@@ -49,16 +52,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ServerBrowserLogic(Widget widget, Action onStart, Action onExit)
|
public ServerBrowserLogic(Widget widget, Action onStart, Action onExit)
|
||||||
{
|
{
|
||||||
var panel = widget;
|
panel = widget;
|
||||||
this.onStart = onStart;
|
this.onStart = onStart;
|
||||||
this.onExit = onExit;
|
this.onExit = onExit;
|
||||||
|
|
||||||
var sl = panel.Get<ScrollPanelWidget>("SERVER_LIST");
|
serverList = panel.Get<ScrollPanelWidget>("SERVER_LIST");
|
||||||
|
serverTemplate = serverList.Get<ScrollItemWidget>("SERVER_TEMPLATE");
|
||||||
|
|
||||||
// Menu buttons
|
// Menu buttons
|
||||||
var refreshButton = panel.Get<ButtonWidget>("REFRESH_BUTTON");
|
var refreshButton = panel.Get<ButtonWidget>("REFRESH_BUTTON");
|
||||||
refreshButton.IsDisabled = () => searchStatus == SearchStatus.Fetching;
|
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>("DIRECTCONNECT_BUTTON").OnClick = OpenDirectConnectPanel;
|
||||||
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = OpenCreateServerPanel;
|
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(); };
|
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
|
// Display the progress label over the server list
|
||||||
// The text is only visible when the list is empty
|
// The text is only visible when the list is empty
|
||||||
var progressText = panel.Get<LabelWidget>("PROGRESS_LABEL");
|
var progressText = panel.Get<LabelWidget>("PROGRESS_LABEL");
|
||||||
@@ -82,33 +84,163 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (showWaitingCheckbox != null)
|
if (showWaitingCheckbox != null)
|
||||||
{
|
{
|
||||||
showWaitingCheckbox.IsChecked = () => showWaiting;
|
showWaitingCheckbox.IsChecked = () => showWaiting;
|
||||||
showWaitingCheckbox.OnClick = () => { showWaiting ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
|
showWaitingCheckbox.OnClick = () => { showWaiting ^= true; RefreshServerList(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
var showEmptyCheckbox = panel.GetOrNull<CheckboxWidget>("EMPTY");
|
var showEmptyCheckbox = panel.GetOrNull<CheckboxWidget>("EMPTY");
|
||||||
if (showEmptyCheckbox != null)
|
if (showEmptyCheckbox != null)
|
||||||
{
|
{
|
||||||
showEmptyCheckbox.IsChecked = () => showEmpty;
|
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");
|
var showAlreadyStartedCheckbox = panel.GetOrNull<CheckboxWidget>("ALREADY_STARTED");
|
||||||
if (showAlreadyStartedCheckbox != null)
|
if (showAlreadyStartedCheckbox != null)
|
||||||
{
|
{
|
||||||
showAlreadyStartedCheckbox.IsChecked = () => showStarted;
|
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");
|
var showIncompatibleCheckbox = panel.GetOrNull<CheckboxWidget>("INCOMPATIBLE_VERSION");
|
||||||
if (showIncompatibleCheckbox != null)
|
if (showIncompatibleCheckbox != null)
|
||||||
{
|
{
|
||||||
showIncompatibleCheckbox.IsChecked = () => showIncompatible;
|
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());
|
// 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()
|
void OpenLobby()
|
||||||
@@ -155,10 +287,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (game == null || game.Players == 0)
|
if (game == null || game.Players == 0)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
var map = Game.modData.FindMapByUid(game.Map);
|
var map = Game.modData.MapCache[game.Map];
|
||||||
|
return "{0} / {1}".F(game.Players, map.PlayerCount == 0 ? "?" : map.PlayerCount.ToString());
|
||||||
var maxPlayers = map == null ? "?" : (object)map.PlayerCount;
|
|
||||||
return "{0} / {1}".F(game.Players, maxPlayers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetStateLabel(GameServer game)
|
string GetStateLabel(GameServer game)
|
||||||
@@ -176,11 +306,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
return "Unknown server state";
|
return "Unknown server state";
|
||||||
}
|
}
|
||||||
|
|
||||||
Map GetMapPreview(GameServer game)
|
|
||||||
{
|
|
||||||
return (game == null) ? null : Game.modData.FindMapByUid(game.Map);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateModLabel(GameServer s)
|
public static string GenerateModLabel(GameServer s)
|
||||||
{
|
{
|
||||||
Mod mod;
|
Mod mod;
|
||||||
@@ -241,20 +366,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
var item = ScrollItemWidget.Setup(serverTemplate, () => currentServer == game, () => currentServer = game, () => Join(game));
|
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");
|
var preview = item.Get<MapPreviewWidget>("MAP_PREVIEW");
|
||||||
preview.Map = () => GetMapPreview(game);
|
preview.Preview = () => map;
|
||||||
preview.IsVisible = () => GetMapPreview(game) != null;
|
|
||||||
|
|
||||||
var title = item.Get<LabelWidget>("TITLE");
|
var title = item.Get<LabelWidget>("TITLE");
|
||||||
title.GetText = () => game.Name;
|
title.GetText = () => game.Name;
|
||||||
|
|
||||||
// TODO: Use game.MapTitle once the server supports it
|
// TODO: Use game.MapTitle once the server supports it
|
||||||
var maptitle = item.Get<LabelWidget>("MAP");
|
var maptitle = item.Get<LabelWidget>("MAP");
|
||||||
maptitle.GetText = () =>
|
maptitle.GetText = () => map.Title;
|
||||||
{
|
|
||||||
var map = Game.modData.FindMapByUid(game.Map);
|
|
||||||
return map == null ? "Unknown Map" : map.Title;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Use game.MaxPlayers once the server supports it
|
// TODO: Use game.MaxPlayers once the server supports it
|
||||||
var players = item.Get<LabelWidget>("PLAYERS");
|
var players = item.Get<LabelWidget>("PLAYERS");
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
Widget panel;
|
Widget panel;
|
||||||
Action onCreate;
|
Action onCreate;
|
||||||
Action onExit;
|
Action onExit;
|
||||||
Map map;
|
MapPreview preview = MapCache.UnknownMap;
|
||||||
bool advertiseOnline;
|
bool advertiseOnline;
|
||||||
bool allowPortForward;
|
bool allowPortForward;
|
||||||
|
|
||||||
@@ -32,12 +32,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
this.onExit = onExit;
|
this.onExit = onExit;
|
||||||
|
|
||||||
var settings = Game.Settings;
|
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>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||||
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin;
|
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin;
|
||||||
|
|
||||||
map = Game.modData.AvailableMaps[ WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map) ];
|
|
||||||
|
|
||||||
var mapButton = panel.GetOrNull<ButtonWidget>("MAP_BUTTON");
|
var mapButton = panel.GetOrNull<ButtonWidget>("MAP_BUTTON");
|
||||||
if (mapButton != null)
|
if (mapButton != null)
|
||||||
{
|
{
|
||||||
@@ -45,14 +44,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
||||||
{
|
{
|
||||||
{ "initialMap", map.Uid },
|
{ "initialMap", preview.Uid },
|
||||||
{ "onExit", () => {} },
|
{ "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<MapPreviewWidget>("MAP_PREVIEW").Preview = () => preview;
|
||||||
panel.Get<LabelWidget>("MAP_NAME").GetText = () => map.Title;
|
panel.Get<LabelWidget>("MAP_NAME").GetText = () => preview.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.Get<TextFieldWidget>("SERVER_NAME").Text = settings.Server.Name ?? "";
|
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.ExternalPort = externalPort;
|
||||||
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 = preview.Uid;
|
||||||
Game.Settings.Server.Password = password;
|
Game.Settings.Server.Password = password;
|
||||||
Game.Settings.Save();
|
Game.Settings.Save();
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,11 @@ namespace OpenRA.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Processing Maps:");
|
Console.WriteLine("Processing Maps:");
|
||||||
foreach (var map in Game.modData.FindMaps().Values)
|
var maps = Game.modData.MapCache
|
||||||
|
.Where(m => m.Status == MapStatus.Available)
|
||||||
|
.Select(m => m.Map);
|
||||||
|
|
||||||
|
foreach (var map in maps)
|
||||||
{
|
{
|
||||||
Console.WriteLine("\t" + map.Path);
|
Console.WriteLine("\t" + map.Path);
|
||||||
UpgradeActorRules(engineDate, ref map.Rules, null, 0);
|
UpgradeActorRules(engineDate, ref map.Rules, null, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user