Remove requirement for server to explicitly generate maps.
This commit is contained in:
committed by
Gustas Kažukauskas
parent
156122f9e3
commit
ed1ebd536b
@@ -60,7 +60,10 @@ namespace OpenRA
|
||||
{
|
||||
var preview = modData.MapCache[MapUid];
|
||||
if (preview.Status != MapStatus.Available && MapGenerationArgs != null)
|
||||
modData.MapCache.GenerateMap(modData, MapGenerationArgs);
|
||||
{
|
||||
preview.UpdateFromGenerationArgs(MapGenerationArgs);
|
||||
preview.Generate();
|
||||
}
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using FS = OpenRA.FileSystem.FileSystem;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -221,45 +220,6 @@ namespace OpenRA
|
||||
yield return mapPackage;
|
||||
}
|
||||
|
||||
public void GenerateMap(ModData modData, MapGenerationArgs args)
|
||||
{
|
||||
var p = previews[args.Uid];
|
||||
if (p.Class == MapClassification.Generated)
|
||||
return;
|
||||
|
||||
p.UpdateFromGenerationArgs(args);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var generator = modData.DefaultRules.Actors[SystemActors.EditorWorld]
|
||||
.TraitInfos<IMapGeneratorInfo>()
|
||||
.FirstOrDefault(info => info.Type == args.Generator);
|
||||
|
||||
if (generator == null)
|
||||
throw new Exception($"Unknown map generator type {args.Generator}");
|
||||
|
||||
var map = generator.Generate(modData, args);
|
||||
|
||||
// Uid is generated when the map is saved
|
||||
map.Save(new ZipFileLoader.ReadWriteZipFile());
|
||||
|
||||
if (map.Uid != args.Uid)
|
||||
throw new InvalidOperationException("Map generation UID mismatch");
|
||||
|
||||
Game.RunAfterTick(() => p.UpdateFromMap(map.Package, MapClassification.Generated));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Map generation failed with error:");
|
||||
Log.Write("debug", e);
|
||||
|
||||
p.UpdateFromGenerationArgs(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void QueryRemoteMapDetails(string repositoryUrl, IEnumerable<string> uids,
|
||||
Action<MapPreview> mapDetailsReceived = null, Action<MapPreview> mapQueryFailed = null)
|
||||
{
|
||||
|
||||
@@ -24,10 +24,11 @@ using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public enum MapStatus { Available, Unavailable, Searching, DownloadAvailable, Downloading, DownloadError, Generating }
|
||||
public enum MapStatus { Available, Unavailable, Searching, DownloadAvailable, Downloading, DownloadError, Generatable, Generating }
|
||||
|
||||
// Used for grouping maps in the UI
|
||||
[Flags]
|
||||
@@ -467,20 +468,84 @@ namespace OpenRA
|
||||
{
|
||||
var newData = innerData.Clone();
|
||||
newData.Class = MapClassification.Generated;
|
||||
if (args != null)
|
||||
newData.Status = MapStatus.Generatable;
|
||||
newData.Title = args.Title;
|
||||
newData.Author = args.Author;
|
||||
newData.TileSet = args.Tileset;
|
||||
newData.GenerationArgs = args;
|
||||
newData.MapFormat = Map.CurrentMapFormat;
|
||||
|
||||
try
|
||||
{
|
||||
newData.Status = MapStatus.Generating;
|
||||
newData.Title = args.Title;
|
||||
newData.Author = args.Author;
|
||||
newData.GenerationArgs = args;
|
||||
var generator = modData.DefaultRules.Actors[SystemActors.EditorWorld]
|
||||
.TraitInfos<IMapGeneratorInfo>()
|
||||
.FirstOrDefault(info => info.Type == args.Generator);
|
||||
|
||||
if (generator == null)
|
||||
throw new Exception($"Unknown map generator type {args.Generator}");
|
||||
|
||||
if (!generator.TryGenerateMetadata(modData, args, out var players, out var ruleDefinitions))
|
||||
throw new Exception("Failed to generate map metadata");
|
||||
|
||||
newData.Players = players;
|
||||
newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable);
|
||||
newData.SetCustomRules(modData, this, ruleDefinitions, null);
|
||||
|
||||
// Placeholder to satisfy server-side lint checks
|
||||
newData.SpawnPoints = Exts.MakeArray(newData.PlayerCount, i => new CPos(i, i)).ToImmutableArray();
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Map generation failed with error:");
|
||||
Log.Write("debug", e);
|
||||
|
||||
newData.Status = MapStatus.Unavailable;
|
||||
}
|
||||
|
||||
lock (syncRoot)
|
||||
innerData = newData;
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
{
|
||||
if (Class != MapClassification.Generated || Status != MapStatus.Generatable)
|
||||
return;
|
||||
|
||||
lock (syncRoot)
|
||||
innerData.Status = MapStatus.Generating;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var generator = modData.DefaultRules.Actors[SystemActors.EditorWorld]
|
||||
.TraitInfos<IMapGeneratorInfo>()
|
||||
.FirstOrDefault(info => info.Type == GenerationArgs.Generator);
|
||||
|
||||
if (generator == null)
|
||||
throw new Exception($"Unknown map generator type {GenerationArgs.Generator}");
|
||||
|
||||
var map = generator.Generate(modData, GenerationArgs);
|
||||
|
||||
// Uid is generated when the map is saved
|
||||
map.Save(new ZipFileLoader.ReadWriteZipFile());
|
||||
|
||||
if (map.Uid != GenerationArgs.Uid)
|
||||
throw new InvalidOperationException("Map generation UID mismatch");
|
||||
|
||||
Game.RunAfterTick(() => UpdateFromMap(map.Package, MapClassification.Generated));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Map generation failed with error:");
|
||||
Log.Write("debug", e);
|
||||
|
||||
lock (syncRoot)
|
||||
innerData.Status = MapStatus.Unavailable;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void BeginRemoteSearch()
|
||||
{
|
||||
var newData = innerData.Clone();
|
||||
|
||||
@@ -393,7 +393,14 @@ namespace OpenRA.Network
|
||||
case "GenerateMap":
|
||||
{
|
||||
var yaml = new MiniYaml(order.OrderString, MiniYaml.FromString(order.TargetString, order.OrderString));
|
||||
Game.ModData.MapCache.GenerateMap(Game.ModData, FieldLoader.Load<MapGenerationArgs>(yaml));
|
||||
var args = FieldLoader.Load<MapGenerationArgs>(yaml);
|
||||
var preview = Game.ModData.MapCache[args.Uid];
|
||||
if (preview.Status != MapStatus.Available && preview.Class != MapClassification.Generated)
|
||||
{
|
||||
preview.UpdateFromGenerationArgs(args);
|
||||
preview.Generate();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1127,8 +1127,8 @@ namespace OpenRA.Server
|
||||
var yaml = new MiniYaml(o.OrderString, MiniYaml.FromString(o.TargetString, o.OrderString));
|
||||
var args = FieldLoader.Load<MapGenerationArgs>(yaml);
|
||||
var preview = ModData.MapCache[args.Uid];
|
||||
if (preview.Status != MapStatus.Available)
|
||||
ModData.MapCache.GenerateMap(ModData, args);
|
||||
if (preview.Status != MapStatus.Available && preview.Class != MapClassification.Generated)
|
||||
preview.UpdateFromGenerationArgs(args);
|
||||
|
||||
GeneratedMapData = o.TargetString;
|
||||
DispatchServerOrdersToClients(Order.FromTargetString("GenerateMap", o.TargetString, true));
|
||||
|
||||
@@ -659,5 +659,6 @@ namespace OpenRA.Traits
|
||||
string MapTitle { get; }
|
||||
|
||||
Map Generate(ModData modData, MapGenerationArgs args);
|
||||
bool TryGenerateMetadata(ModData modData, MapGenerationArgs args, out MapPlayers players, out Dictionary<string, MiniYaml> rules);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,23 +656,8 @@ namespace OpenRA.Mods.Common.Server
|
||||
}
|
||||
|
||||
var m = server.ModData.MapCache[s];
|
||||
if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable)
|
||||
if (m.Status is MapStatus.Available or MapStatus.DownloadAvailable or MapStatus.Generatable or MapStatus.Generating)
|
||||
SelectMap(m);
|
||||
else if (m.Class == MapClassification.Generated)
|
||||
{
|
||||
if (m.Status == MapStatus.Generating)
|
||||
{
|
||||
// Wait up to 5 seconds for the map to be generated
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
while (m.Status == MapStatus.Generating && stopwatch.ElapsedMilliseconds < 5000)
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
if (m.Status == MapStatus.Available)
|
||||
SelectMap(m);
|
||||
else
|
||||
QueryFailed();
|
||||
}
|
||||
else if (server.Settings.QueryMapRepository)
|
||||
{
|
||||
server.SendFluentMessageTo(conn, SearchingMap);
|
||||
|
||||
@@ -953,6 +953,26 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return map;
|
||||
}
|
||||
|
||||
public bool TryGenerateMetadata(ModData modData, MapGenerationArgs args, out MapPlayers players, out Dictionary<string, MiniYaml> ruleDefinitions)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playerCount = FieldLoader.GetValue<int>("Players", args.Settings.NodeWithKey("Players").Value.Value);
|
||||
|
||||
// Generated maps use the default ruleset
|
||||
ruleDefinitions = [];
|
||||
players = new MapPlayers(modData.DefaultRules, playerCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
players = null;
|
||||
ruleDefinitions = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override object Create(ActorInitializer init)
|
||||
{
|
||||
return new ClassicMapGenerator(init, this);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.MapGenerator;
|
||||
@@ -93,6 +94,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return map;
|
||||
}
|
||||
|
||||
public bool TryGenerateMetadata(ModData modData, MapGenerationArgs args, out MapPlayers players, out Dictionary<string, MiniYaml> ruleDefinitions)
|
||||
{
|
||||
ruleDefinitions = [];
|
||||
players = new MapPlayers(modData.DefaultRules, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override object Create(ActorInitializer init)
|
||||
{
|
||||
return new ClearMapGenerator(this);
|
||||
|
||||
@@ -327,11 +327,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
if (savePath != null)
|
||||
{
|
||||
selectedSave = new GameSave(savePath);
|
||||
var map = modData.MapCache[selectedSave.GlobalSettings.Map];
|
||||
if (map.Status != MapStatus.Available && selectedSave.MapGenerationArgs != null)
|
||||
var preview = modData.MapCache[selectedSave.GlobalSettings.Map];
|
||||
if (preview.Status != MapStatus.Available && selectedSave.MapGenerationArgs != null)
|
||||
{
|
||||
// Add to the MapCache so the server will accept the map
|
||||
modData.MapCache.GenerateMap(modData, selectedSave.MapGenerationArgs);
|
||||
preview.UpdateFromGenerationArgs(selectedSave.MapGenerationArgs);
|
||||
preview.Generate();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -616,6 +616,26 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
return map;
|
||||
}
|
||||
|
||||
public bool TryGenerateMetadata(ModData modData, MapGenerationArgs args, out MapPlayers players, out Dictionary<string, MiniYaml> ruleDefinitions)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playerCount = FieldLoader.GetValue<int>("Players", args.Settings.NodeWithKey("Players").Value.Value);
|
||||
|
||||
// Generated maps use the default ruleset
|
||||
ruleDefinitions = [];
|
||||
players = new MapPlayers(modData.DefaultRules, playerCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
players = null;
|
||||
ruleDefinitions = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override object Create(ActorInitializer init)
|
||||
{
|
||||
return new D2kMapGenerator(this);
|
||||
|
||||
Reference in New Issue
Block a user