Introduce MapCache and MapPreview for improved UI map previews.
This commit is contained in:
@@ -370,7 +370,7 @@ namespace OpenRA
|
||||
modData = new ModData(mod);
|
||||
Renderer.InitializeFonts(modData.Manifest);
|
||||
modData.InitializeLoaders();
|
||||
modData.LoadMaps();
|
||||
modData.MapCache.LoadMaps();
|
||||
|
||||
PerfHistory.items["render"].hasNormalTick = false;
|
||||
PerfHistory.items["batches"].hasNormalTick = false;
|
||||
@@ -401,7 +401,7 @@ namespace OpenRA
|
||||
if (Settings.Server.DedicatedLoop)
|
||||
{
|
||||
Console.WriteLine("Starting a new server instance...");
|
||||
modData.LoadMaps();
|
||||
modData.MapCache.LoadMaps();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -426,13 +426,14 @@ namespace OpenRA
|
||||
|
||||
static string ChooseShellmap()
|
||||
{
|
||||
var shellmaps = modData.AvailableMaps
|
||||
.Where(m => m.Value.UseAsShellmap);
|
||||
var shellmaps = modData.MapCache
|
||||
.Where(m => m.Status == MapStatus.Available && m.Map.UseAsShellmap)
|
||||
.Select(m => m.Uid);
|
||||
|
||||
if (!shellmaps.Any())
|
||||
throw new InvalidDataException("No valid shellmaps available");
|
||||
|
||||
return shellmaps.Random(CosmeticRandom).Key;
|
||||
return shellmaps.Random(CosmeticRandom);
|
||||
}
|
||||
|
||||
static bool quit;
|
||||
@@ -553,7 +554,7 @@ namespace OpenRA
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile(url, tempFile);
|
||||
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);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -67,6 +67,14 @@ namespace OpenRA.Graphics
|
||||
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)
|
||||
{
|
||||
var data = new byte[size.Width * size.Height];
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using OpenRA.FileFormats.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()
|
||||
{
|
||||
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
91
OpenRA.Game/MapPreview.cs
Executable file
91
OpenRA.Game/MapPreview.cs
Executable file
@@ -0,0 +1,91 @@
|
||||
#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 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();
|
||||
Status = MapStatus.Available;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,34 +22,13 @@ namespace OpenRA
|
||||
{
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public Dictionary<string, Map> AvailableMaps { get; private set; }
|
||||
public readonly WidgetLoader WidgetLoader;
|
||||
public readonly MapCache MapCache;
|
||||
public ILoadScreen LoadScreen = null;
|
||||
public SheetBuilder SheetBuilder;
|
||||
public SpriteLoader SpriteLoader;
|
||||
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)
|
||||
{
|
||||
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.Display();
|
||||
WidgetLoader = new WidgetLoader(this);
|
||||
MapCache = new MapCache(Manifest);
|
||||
|
||||
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
||||
FileSystem.UnmountAll();
|
||||
@@ -119,17 +99,13 @@ namespace OpenRA
|
||||
FieldLoader.Translations = translations;
|
||||
}
|
||||
|
||||
public void LoadMaps()
|
||||
{
|
||||
AvailableMaps = FindMaps();
|
||||
}
|
||||
|
||||
public Map PrepareMap(string uid)
|
||||
{
|
||||
LoadScreen.Display();
|
||||
if (!AvailableMaps.ContainsKey(uid))
|
||||
|
||||
var map = MapCache[uid].Map;
|
||||
if (map == null)
|
||||
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
||||
var map = new Map(AvailableMaps[uid].Path);
|
||||
|
||||
LoadTranslations(map);
|
||||
|
||||
@@ -148,33 +124,6 @@ namespace OpenRA
|
||||
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences);
|
||||
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
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace OpenRA.Network
|
||||
|
||||
// Don't have the map locally
|
||||
// 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 true;
|
||||
|
||||
@@ -35,10 +35,7 @@ namespace OpenRA.Network
|
||||
return null;
|
||||
|
||||
var map = LobbyInfo.GlobalSettings.Map;
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(map))
|
||||
return null;
|
||||
|
||||
return Game.modData.AvailableMaps[map];
|
||||
return Game.modData.MapCache[map].Map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +232,8 @@
|
||||
<Compile Include="Traits\World\ActorMap.cs" />
|
||||
<Compile Include="Widgets\HotkeyEntryWidget.cs" />
|
||||
<Compile Include="Effects\MoveFlash.cs" />
|
||||
<Compile Include="MapCache.cs" />
|
||||
<Compile Include="MapPreview.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public class MapPreviewWidget : Widget
|
||||
{
|
||||
public Func<Map> Map = () => null;
|
||||
public Func<MapPreview> Preview = () => null;
|
||||
public Func<Dictionary<CPos, Session.Client>> SpawnClients = () => new Dictionary<CPos, Session.Client>();
|
||||
public Action<MouseInput> OnMouseDown = _ => {};
|
||||
public bool IgnoreMouseInput = false;
|
||||
@@ -32,6 +32,9 @@ namespace OpenRA.Widgets
|
||||
Lazy<TooltipContainerWidget> tooltipContainer;
|
||||
public int TooltipSpawnIndex = -1;
|
||||
|
||||
Rectangle MapRect;
|
||||
float PreviewScale = 0;
|
||||
|
||||
public MapPreviewWidget()
|
||||
{
|
||||
tooltipContainer = Lazy.New(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
@@ -40,8 +43,7 @@ namespace OpenRA.Widgets
|
||||
protected MapPreviewWidget(MapPreviewWidget other)
|
||||
: base(other)
|
||||
{
|
||||
lastMap = other.lastMap;
|
||||
Map = other.Map;
|
||||
Preview = other.Preview;
|
||||
SpawnClients = other.SpawnClients;
|
||||
ShowSpawnPoints = other.ShowSpawnPoints;
|
||||
TooltipTemplate = other.TooltipTemplate;
|
||||
@@ -65,74 +67,51 @@ namespace OpenRA.Widgets
|
||||
|
||||
public override void MouseEntered()
|
||||
{
|
||||
if (TooltipContainer == null) return;
|
||||
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "preview", this }});
|
||||
if (TooltipContainer != null)
|
||||
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "preview", this }});
|
||||
}
|
||||
|
||||
public override void MouseExited()
|
||||
{
|
||||
if (TooltipContainer == null) return;
|
||||
tooltipContainer.Value.RemoveTooltip();
|
||||
if (TooltipContainer != null)
|
||||
tooltipContainer.Value.RemoveTooltip();
|
||||
}
|
||||
|
||||
public int2 ConvertToPreview(CPos point)
|
||||
{
|
||||
var map = Map();
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top)));
|
||||
var preview = Preview();
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - preview.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - preview.Bounds.Top)));
|
||||
}
|
||||
|
||||
Sheet mapChooserSheet;
|
||||
Sprite mapChooserSprite;
|
||||
Map lastMap;
|
||||
Rectangle MapRect;
|
||||
float PreviewScale = 0;
|
||||
|
||||
Sprite minimap;
|
||||
public override void Draw()
|
||||
{
|
||||
var map = Map();
|
||||
if (map == null)
|
||||
var preview = Preview();
|
||||
if (preview == null)
|
||||
return;
|
||||
|
||||
// Preview unavailable
|
||||
if (!Loaded)
|
||||
{
|
||||
GeneratePreview();
|
||||
// Stash a copy of the minimap to ensure consistency
|
||||
// (it may be modified by another thread)
|
||||
minimap = preview.Minimap;
|
||||
if (minimap == null)
|
||||
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
|
||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height);
|
||||
var size = Math.Max(map.Bounds.Width, map.Bounds.Height);
|
||||
var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2;
|
||||
var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2;
|
||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale));
|
||||
PreviewScale = Math.Min(RenderBounds.Width / minimap.size.X, RenderBounds.Height / minimap.size.Y);
|
||||
var w = (int)(PreviewScale * minimap.size.X);
|
||||
var h = (int)(PreviewScale * minimap.size.Y);
|
||||
var x = RenderBounds.X + (RenderBounds.Width - w) / 2;
|
||||
var y = RenderBounds.Y + (RenderBounds.Height - h) / 2;
|
||||
MapRect = new Rectangle(x, y, w, h);
|
||||
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(mapChooserSprite,
|
||||
new float2(MapRect.Location),
|
||||
new float2(MapRect.Size));
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(minimap, new float2(MapRect.Location), new float2(MapRect.Size));
|
||||
|
||||
TooltipSpawnIndex = -1;
|
||||
if (ShowSpawnPoints)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var owned = colors.ContainsKey(p);
|
||||
@@ -151,79 +130,6 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
// Async map preview generation bits
|
||||
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; } }
|
||||
public bool Loaded { get { return minimap != null; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,14 +225,13 @@ namespace OpenRA.Widgets
|
||||
|
||||
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(map) || !availableMaps.ContainsKey(map))
|
||||
if (string.IsNullOrEmpty(initialUid) || Game.modData.MapCache[initialUid].Status != MapStatus.Available)
|
||||
{
|
||||
Func<Map, bool> isIdealMap = m =>
|
||||
Func<MapPreview, bool> isIdealMap = m =>
|
||||
{
|
||||
if (!m.Selectable)
|
||||
if (m.Status != MapStatus.Available || !m.Map.Selectable)
|
||||
return false;
|
||||
|
||||
// Other map types may have confusing settings or gameplay
|
||||
@@ -240,22 +239,22 @@ namespace OpenRA.Widgets
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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 true;
|
||||
};
|
||||
|
||||
var selected = availableMaps.Values.Where(m => isIdealMap(m)).RandomOrDefault(Game.CosmeticRandom) ??
|
||||
availableMaps.Values.First(m => m.Selectable);
|
||||
var selected = Game.modData.MapCache.Where(m => isIdealMap(m)).RandomOrDefault(Game.CosmeticRandom) ??
|
||||
Game.modData.MapCache.First(m => m.Status == MapStatus.Available && m.Map.Selectable);
|
||||
return selected.Uid;
|
||||
}
|
||||
|
||||
return map;
|
||||
return initialUid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
@@ -52,14 +53,16 @@ namespace OpenRA.Lint
|
||||
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
||||
Game.modData = new ModData(mod);
|
||||
|
||||
var maps = new Map[] { new Map() };
|
||||
if (!string.IsNullOrEmpty(map))
|
||||
maps = new Map[] { new Map(map) };
|
||||
else
|
||||
IEnumerable<Map> maps;
|
||||
if (string.IsNullOrEmpty(map))
|
||||
{
|
||||
Game.modData.LoadMaps();
|
||||
maps = Game.modData.AvailableMaps.Values.ToArray();
|
||||
Game.modData.MapCache.LoadMaps();
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -280,7 +280,7 @@ namespace OpenRA.Mods.RA.Server
|
||||
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");
|
||||
return true;
|
||||
@@ -720,7 +720,7 @@ namespace OpenRA.Mods.RA.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
|
||||
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
||||
.Where(s => s != null)
|
||||
|
||||
@@ -38,8 +38,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
ScrollPanelWidget players;
|
||||
Dictionary<string, string> countryNames;
|
||||
string mapUid;
|
||||
Map map;
|
||||
MapPreview preview = MapCache.UnknownMap;
|
||||
|
||||
ColorPreviewManagerWidget colorPreview;
|
||||
|
||||
@@ -124,31 +123,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
colorPreview.Color = Game.Settings.Player.Color;
|
||||
|
||||
var mapPreview = lobby.Get<MapPreviewWidget>("MAP_PREVIEW");
|
||||
mapPreview.IsVisible = () => map != null;
|
||||
mapPreview.Map = () => map;
|
||||
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, map, mi);
|
||||
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, map);
|
||||
mapPreview.Preview = () => preview;
|
||||
mapPreview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, mapPreview, preview, mi);
|
||||
mapPreview.SpawnClients = () => LobbyUtils.GetSpawnClients(orderManager, preview);
|
||||
|
||||
var mapTitle = lobby.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||
if (mapTitle != null)
|
||||
{
|
||||
mapTitle.IsVisible = () => map != null;
|
||||
mapTitle.GetText = () => map.Title;
|
||||
}
|
||||
mapTitle.GetText = () => preview.Title;
|
||||
|
||||
var mapType = lobby.GetOrNull<LabelWidget>("MAP_TYPE");
|
||||
if (mapType != null)
|
||||
{
|
||||
mapType.IsVisible = () => map != null;
|
||||
mapType.GetText = () => map.Type;
|
||||
}
|
||||
mapType.GetText = () => preview.Type;
|
||||
|
||||
var mapAuthor = lobby.GetOrNull<LabelWidget>("MAP_AUTHOR");
|
||||
if (mapAuthor != null)
|
||||
{
|
||||
mapAuthor.IsVisible = () => map != null;
|
||||
mapAuthor.GetText = () => "Created by {0}".F(map.Author);
|
||||
}
|
||||
mapAuthor.GetText = () => "Created by {0}".F(preview.Author);
|
||||
|
||||
countryNames = Rules.Info["world"].Traits.WithInterface<CountryInfo>()
|
||||
.Where(c => c.Selectable)
|
||||
@@ -174,7 +163,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
||||
{
|
||||
{ "initialMap", map.Uid },
|
||||
{ "initialMap", preview.Uid },
|
||||
{ "onExit", () => { } },
|
||||
{ "onSelect", onSelect }
|
||||
});
|
||||
@@ -308,7 +297,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (allowCheats != null)
|
||||
{
|
||||
allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats;
|
||||
allowCheats.IsDisabled = () => map.Options.Cheats.HasValue || configurationDisabled();
|
||||
allowCheats.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Cheats.HasValue || configurationDisabled();
|
||||
allowCheats.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats)));
|
||||
}
|
||||
@@ -317,7 +306,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (crates != null)
|
||||
{
|
||||
crates.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Crates;
|
||||
crates.IsDisabled = () => map.Options.Crates.HasValue || configurationDisabled();
|
||||
crates.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Crates.HasValue || configurationDisabled();
|
||||
crates.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"crates {0}".F(!orderManager.LobbyInfo.GlobalSettings.Crates)));
|
||||
}
|
||||
@@ -326,7 +315,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (allybuildradius != null)
|
||||
{
|
||||
allybuildradius.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius;
|
||||
allybuildradius.IsDisabled = () => map.Options.AllyBuildRadius.HasValue || configurationDisabled();
|
||||
allybuildradius.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.AllyBuildRadius.HasValue || configurationDisabled();
|
||||
allybuildradius.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"allybuildradius {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllyBuildRadius)));
|
||||
}
|
||||
@@ -335,7 +324,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (fragileAlliance != null)
|
||||
{
|
||||
fragileAlliance.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.FragileAlliances;
|
||||
fragileAlliance.IsDisabled = () => map.Options.FragileAlliances.HasValue || configurationDisabled();
|
||||
fragileAlliance.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.FragileAlliances.HasValue || configurationDisabled();
|
||||
fragileAlliance.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"fragilealliance {0}".F(!orderManager.LobbyInfo.GlobalSettings.FragileAlliances)));
|
||||
}
|
||||
@@ -343,12 +332,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var difficulty = optionsBin.GetOrNull<DropDownButtonWidget>("DIFFICULTY_DROPDOWNBUTTON");
|
||||
if (difficulty != null)
|
||||
{
|
||||
difficulty.IsVisible = () => map.Options.Difficulties.Any();
|
||||
difficulty.IsDisabled = configurationDisabled;
|
||||
difficulty.IsVisible = () => preview.Status == MapStatus.Available && preview.Map.Options.Difficulties.Any();
|
||||
difficulty.IsDisabled = () => preview.Status != MapStatus.Available || configurationDisabled();
|
||||
difficulty.GetText = () => orderManager.LobbyInfo.GlobalSettings.Difficulty;
|
||||
difficulty.OnMouseDown = _ =>
|
||||
{
|
||||
var options = map.Options.Difficulties.Select(d => new DropDownOption
|
||||
var options = preview.Map.Options.Difficulties.Select(d => new DropDownOption
|
||||
{
|
||||
Title = d,
|
||||
IsSelected = () => orderManager.LobbyInfo.GlobalSettings.Difficulty == d,
|
||||
@@ -380,8 +369,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var classes = Rules.Info["world"].Traits.WithInterface<MPStartUnitsInfo>()
|
||||
.Select(a => a.Class).Distinct();
|
||||
|
||||
startingUnits.IsDisabled = () => !map.Options.ConfigurableStartingUnits || configurationDisabled();
|
||||
startingUnits.GetText = () => !map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
|
||||
startingUnits.IsDisabled = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits || configurationDisabled();
|
||||
startingUnits.GetText = () => preview.Status != MapStatus.Available || !preview.Map.Options.ConfigurableStartingUnits ? "Not Available" : className(orderManager.LobbyInfo.GlobalSettings.StartingUnitsClass);
|
||||
startingUnits.OnMouseDown = _ =>
|
||||
{
|
||||
var options = classes.Select(c => new DropDownOption
|
||||
@@ -407,8 +396,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var startingCash = optionsBin.GetOrNull<DropDownButtonWidget>("STARTINGCASH_DROPDOWNBUTTON");
|
||||
if (startingCash != null)
|
||||
{
|
||||
startingCash.IsDisabled = () => map.Options.StartingCash.HasValue || configurationDisabled();
|
||||
startingCash.GetText = () => map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
|
||||
startingCash.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue || configurationDisabled();
|
||||
startingCash.GetText = () => preview.Status != MapStatus.Available || preview.Map.Options.StartingCash.HasValue ? "Not Available" : "${0}".F(orderManager.LobbyInfo.GlobalSettings.StartingCash);
|
||||
startingCash.OnMouseDown = _ =>
|
||||
{
|
||||
var options = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>().SelectableCash.Select(c => new DropDownOption
|
||||
@@ -433,7 +422,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (enableShroud != null)
|
||||
{
|
||||
enableShroud.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Shroud;
|
||||
enableShroud.IsDisabled = () => map.Options.Shroud.HasValue || configurationDisabled();
|
||||
enableShroud.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Shroud.HasValue || configurationDisabled();
|
||||
enableShroud.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"shroud {0}".F(!orderManager.LobbyInfo.GlobalSettings.Shroud)));
|
||||
}
|
||||
@@ -442,7 +431,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (enableFog != null)
|
||||
{
|
||||
enableFog.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.Fog;
|
||||
enableFog.IsDisabled = () => map.Options.Fog.HasValue || configurationDisabled();
|
||||
enableFog.IsDisabled = () => preview.Status != MapStatus.Available || preview.Map.Options.Fog.HasValue || configurationDisabled();
|
||||
enableFog.OnClick = () => orderManager.IssueOrder(Order.Command(
|
||||
"fog {0}".F(!orderManager.LobbyInfo.GlobalSettings.Fog)));
|
||||
}
|
||||
@@ -529,24 +518,25 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
void UpdateCurrentMap()
|
||||
{
|
||||
if (mapUid == orderManager.LobbyInfo.GlobalSettings.Map)
|
||||
var uid = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||
if (preview.Uid == uid)
|
||||
return;
|
||||
|
||||
mapUid = orderManager.LobbyInfo.GlobalSettings.Map;
|
||||
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(mapUid))
|
||||
preview = Game.modData.MapCache[uid];
|
||||
if (preview.Status != MapStatus.Available)
|
||||
{
|
||||
if (Game.Settings.Game.AllowDownloading)
|
||||
{
|
||||
Game.DownloadMap(mapUid);
|
||||
Game.DownloadMap(uid);
|
||||
Game.Debug("A new map has been downloaded...");
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("Server's new map doesn't exist on your system and Downloading turned off");
|
||||
map = new Map(Game.modData.AvailableMaps[mapUid].Path);
|
||||
}
|
||||
|
||||
// Restore default starting cash if the last map set it to something invalid
|
||||
var pri = Rules.Info["player"].Traits.Get<PlayerResourcesInfo>();
|
||||
if (!map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash))
|
||||
if (!preview.Map.Options.StartingCash.HasValue && !pri.SelectableCash.Contains(orderManager.LobbyInfo.GlobalSettings.StartingCash))
|
||||
orderManager.IssueOrder(Order.Command("startingcash {0}".F(pri.DefaultCash)));
|
||||
}
|
||||
|
||||
@@ -596,7 +586,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, colorPreview);
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -130,26 +130,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
color.AttachPanel(colorChooser, onExit);
|
||||
}
|
||||
|
||||
public static Dictionary<CPos, Session.Client> GetSpawnClients(OrderManager orderManager, Map map)
|
||||
public static Dictionary<CPos, Session.Client> GetSpawnClients(OrderManager orderManager, MapPreview preview)
|
||||
{
|
||||
var spawns = map.GetSpawnPoints();
|
||||
var spawns = preview.SpawnPoints;
|
||||
return orderManager.LobbyInfo.Clients
|
||||
.Where(c => c.SpawnPoint != 0)
|
||||
.ToDictionary(
|
||||
c => spawns[c.SpawnPoint - 1],
|
||||
c => c);
|
||||
.ToDictionary(c => spawns[c.SpawnPoint - 1], c => c);
|
||||
}
|
||||
|
||||
public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, Map map, MouseInput mi)
|
||||
public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
if (mi.Button != MouseButton.Left)
|
||||
return;
|
||||
|
||||
if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready)
|
||||
return;
|
||||
|
||||
var selectedSpawn = map.GetSpawnPoints()
|
||||
var selectedSpawn = preview.SpawnPoints
|
||||
.Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp), i))
|
||||
.Where(a => (a.First - mi.Location).LengthSquared < 64)
|
||||
.Select(a => a.Second + 1)
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
[ObjectCreator.UseCtor]
|
||||
internal MapChooserLogic(Widget widget, string initialMap, Action onExit, Action<Map> onSelect)
|
||||
{
|
||||
map = Game.modData.AvailableMaps[WidgetUtils.ChooseInitialMap(initialMap)];
|
||||
map = Game.modData.MapCache[WidgetUtils.ChooseInitialMap(initialMap)].Map;
|
||||
|
||||
widget.Get<ButtonWidget>("BUTTON_OK").OnClick = () => { Ui.CloseWindow(); onSelect(map); };
|
||||
widget.Get<ButtonWidget>("BUTTON_CANCEL").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||
@@ -44,9 +44,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var gameModeDropdown = widget.GetOrNull<DropDownButtonWidget>("GAMEMODE_FILTER");
|
||||
if (gameModeDropdown != null)
|
||||
{
|
||||
var selectableMaps = Game.modData.AvailableMaps.Where(m => m.Value.Selectable).ToList();
|
||||
var selectableMaps = Game.modData.MapCache.Where(m => m.Status == MapStatus.Available && m.Map.Selectable);
|
||||
var gameModes = selectableMaps
|
||||
.GroupBy(m => m.Value.Type)
|
||||
.GroupBy(m => m.Type)
|
||||
.Select(g => Pair.New(g.Key, g.Count())).ToList();
|
||||
|
||||
// 'all game types' extra item
|
||||
@@ -87,8 +87,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
void EnumerateMaps(Action<Map> onSelect)
|
||||
{
|
||||
var maps = Game.modData.AvailableMaps
|
||||
.Where(kv => kv.Value.Selectable)
|
||||
var maps = Game.modData.MapCache
|
||||
.Where(m => m.Status == MapStatus.Available && m.Map.Selectable)
|
||||
.ToDictionary(m => m.Uid, m => m.Map)
|
||||
.Where(kv => kv.Value.Type == gameMode || gameMode == null)
|
||||
.OrderBy(kv => kv.Value.PlayerCount)
|
||||
.ThenBy(kv => kv.Value.Title);
|
||||
@@ -102,10 +103,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var titleLabel = item.Get<LabelWidget>("TITLE");
|
||||
titleLabel.GetText = () => m.Title;
|
||||
|
||||
var preview = Game.modData.MapCache[m.Uid];
|
||||
var previewWidget = item.Get<MapPreviewWidget>("PREVIEW");
|
||||
previewWidget.IgnoreMouseOver = true;
|
||||
previewWidget.IgnoreMouseInput = true;
|
||||
previewWidget.Map = () => m;
|
||||
previewWidget.Preview = () => preview;
|
||||
previewWidget.IsVisible = () => previewWidget.RenderBounds.IntersectsWith(scrollpanel.RenderBounds);
|
||||
|
||||
var previewLoadingWidget = item.GetOrNull<BackgroundWidget>("PREVIEW_PLACEHOLDER");
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
}
|
||||
|
||||
Replay currentReplay;
|
||||
Map currentMap;
|
||||
MapPreview currentMap = MapCache.UnknownMap;
|
||||
|
||||
void SelectReplay(string filename)
|
||||
{
|
||||
@@ -61,11 +61,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
try
|
||||
{
|
||||
currentReplay = new Replay(filename);
|
||||
currentMap = currentReplay.Map();
|
||||
currentMap = Game.modData.MapCache[currentReplay.LobbyInfo.GlobalSettings.Map];
|
||||
|
||||
panel.Get<LabelWidget>("DURATION").GetText =
|
||||
() => WidgetUtils.FormatTime(currentReplay.Duration);
|
||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Map = () => currentMap;
|
||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => currentMap;
|
||||
panel.Get<LabelWidget>("MAP_TITLE").GetText =
|
||||
() => currentMap != null ? currentMap.Title : "(Unknown Map)";
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
{
|
||||
Log.Write("debug", "Exception while parsing replay: {0}", e);
|
||||
currentReplay = null;
|
||||
currentMap = null;
|
||||
currentMap = MapCache.UnknownMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,10 +155,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
if (game == null || game.Players == 0)
|
||||
return "";
|
||||
|
||||
var map = Game.modData.FindMapByUid(game.Map);
|
||||
|
||||
var maxPlayers = map == null ? "?" : (object)map.PlayerCount;
|
||||
return "{0} / {1}".F(game.Players, maxPlayers);
|
||||
var map = Game.modData.MapCache[game.Map];
|
||||
return "{0} / {1}".F(game.Players, map.PlayerCount == 0 ? "?" : map.PlayerCount.ToString());
|
||||
}
|
||||
|
||||
string GetStateLabel(GameServer game)
|
||||
@@ -176,11 +174,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
return "Unknown server state";
|
||||
}
|
||||
|
||||
Map GetMapPreview(GameServer game)
|
||||
{
|
||||
return (game == null) ? null : Game.modData.FindMapByUid(game.Map);
|
||||
}
|
||||
|
||||
public static string GenerateModLabel(GameServer s)
|
||||
{
|
||||
Mod mod;
|
||||
@@ -241,20 +234,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
var item = ScrollItemWidget.Setup(serverTemplate, () => currentServer == game, () => currentServer = game, () => Join(game));
|
||||
|
||||
var map = Game.modData.MapCache[game.Map];
|
||||
var preview = item.Get<MapPreviewWidget>("MAP_PREVIEW");
|
||||
preview.Map = () => GetMapPreview(game);
|
||||
preview.IsVisible = () => GetMapPreview(game) != null;
|
||||
preview.Preview = () => map;
|
||||
|
||||
var title = item.Get<LabelWidget>("TITLE");
|
||||
title.GetText = () => game.Name;
|
||||
|
||||
// TODO: Use game.MapTitle once the server supports it
|
||||
var maptitle = item.Get<LabelWidget>("MAP");
|
||||
maptitle.GetText = () =>
|
||||
{
|
||||
var map = Game.modData.FindMapByUid(game.Map);
|
||||
return map == null ? "Unknown Map" : map.Title;
|
||||
};
|
||||
maptitle.GetText = () => map.Title;
|
||||
|
||||
// TODO: Use game.MaxPlayers once the server supports it
|
||||
var players = item.Get<LabelWidget>("PLAYERS");
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
Widget panel;
|
||||
Action onCreate;
|
||||
Action onExit;
|
||||
Map map;
|
||||
MapPreview preview = MapCache.UnknownMap;
|
||||
bool advertiseOnline;
|
||||
bool allowPortForward;
|
||||
|
||||
@@ -32,12 +32,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
this.onExit = onExit;
|
||||
|
||||
var settings = Game.Settings;
|
||||
preview = Game.modData.MapCache[WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map)];
|
||||
|
||||
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||
panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = CreateAndJoin;
|
||||
|
||||
map = Game.modData.AvailableMaps[ WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map) ];
|
||||
|
||||
var mapButton = panel.GetOrNull<ButtonWidget>("MAP_BUTTON");
|
||||
if (mapButton != null)
|
||||
{
|
||||
@@ -45,14 +44,14 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
{
|
||||
Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
|
||||
{
|
||||
{ "initialMap", map.Uid },
|
||||
{ "initialMap", preview.Uid },
|
||||
{ "onExit", () => {} },
|
||||
{ "onSelect", (Action<Map>)(m => map = m) }
|
||||
{ "onSelect", (Action<Map>)(m => preview = Game.modData.MapCache[m.Uid]) }
|
||||
});
|
||||
};
|
||||
|
||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Map = () => map;
|
||||
panel.Get<LabelWidget>("MAP_NAME").GetText = () => map.Title;
|
||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => preview;
|
||||
panel.Get<LabelWidget>("MAP_NAME").GetText = () => preview.Title;
|
||||
}
|
||||
|
||||
panel.Get<TextFieldWidget>("SERVER_NAME").Text = settings.Server.Name ?? "";
|
||||
@@ -97,7 +96,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
Game.Settings.Server.ExternalPort = externalPort;
|
||||
Game.Settings.Server.AdvertiseOnline = advertiseOnline;
|
||||
Game.Settings.Server.AllowPortForward = allowPortForward;
|
||||
Game.Settings.Server.Map = map.Uid;
|
||||
Game.Settings.Server.Map = preview.Uid;
|
||||
Game.Settings.Server.Password = password;
|
||||
Game.Settings.Save();
|
||||
|
||||
|
||||
@@ -301,7 +301,11 @@ namespace OpenRA.Utility
|
||||
}
|
||||
|
||||
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);
|
||||
UpgradeActorRules(engineDate, ref map.Rules, null, 0);
|
||||
|
||||
Reference in New Issue
Block a user