Allow rules to be constructed from a MapPreview.

This commit is contained in:
Paul Chote
2016-03-09 19:17:14 +00:00
parent 43a3d42d31
commit be5eee0227
4 changed files with 98 additions and 17 deletions

View File

@@ -148,7 +148,9 @@ namespace OpenRA
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences); return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences);
} }
public static Ruleset LoadFromMap(ModData modData, Map map) public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet,
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications,
MiniYaml mapMusic, MiniYaml mapSequences)
{ {
var m = modData.Manifest; var m = modData.Manifest;
var dr = modData.DefaultRules; var dr = modData.DefaultRules;
@@ -156,27 +158,27 @@ namespace OpenRA
Ruleset ruleset = null; Ruleset ruleset = null;
Action f = () => Action f = () =>
{ {
var actors = MergeOrDefault("Manifest,Rules", map, m.Rules, map.RuleDefinitions, dr.Actors, var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors,
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value));
var weapons = MergeOrDefault("Manifest,Weapons", map, m.Weapons, map.WeaponDefinitions, dr.Weapons, var weapons = MergeOrDefault("Weapons", fileSystem, m.Weapons, mapWeapons, dr.Weapons,
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
var voices = MergeOrDefault("Manifest,Voices", map, m.Voices, map.VoiceDefinitions, dr.Voices, var voices = MergeOrDefault("Voices", fileSystem, m.Voices, mapVoices, dr.Voices,
k => new SoundInfo(k.Value)); k => new SoundInfo(k.Value));
var notifications = MergeOrDefault("Manifest,Notifications", map, m.Notifications, map.NotificationDefinitions, dr.Notifications, var notifications = MergeOrDefault("Notifications", fileSystem, m.Notifications, mapNotifications, dr.Notifications,
k => new SoundInfo(k.Value)); k => new SoundInfo(k.Value));
var music = MergeOrDefault("Manifest,Music", map, m.Music, map.NotificationDefinitions, dr.Music, var music = MergeOrDefault("Music", fileSystem, m.Music, mapMusic, dr.Music,
k => new MusicInfo(k.Key, k.Value)); k => new MusicInfo(k.Key, k.Value));
// TODO: Add support for merging custom tileset modifications // TODO: Add support for merging custom tileset modifications
var ts = modData.DefaultTileSets[map.Tileset]; var ts = modData.DefaultTileSets[tileSet];
// TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object // TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object
var sequences = map.SequenceDefinitions == null ? modData.DefaultSequences[map.Tileset] : var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] :
new SequenceProvider(map, modData, ts, map.SequenceDefinitions); new SequenceProvider(fileSystem, modData, ts, mapSequences);
// TODO: Add support for custom voxel sequences // TODO: Add support for custom voxel sequences
ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences); ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences);

View File

@@ -296,7 +296,8 @@ namespace OpenRA
{ {
try try
{ {
return Ruleset.LoadFromMap(modData, this); return Ruleset.Load(modData, this, Tileset, RuleDefinitions, WeaponDefinitions,
VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -25,7 +25,7 @@ namespace OpenRA
{ {
public sealed class MapCache : IEnumerable<MapPreview>, IDisposable public sealed class MapCache : IEnumerable<MapPreview>, IDisposable
{ {
public static readonly MapPreview UnknownMap = new MapPreview(null, MapGridType.Rectangular, null); public static readonly MapPreview UnknownMap = new MapPreview(null, null, MapGridType.Rectangular, null);
public readonly IReadOnlyDictionary<IReadOnlyPackage, MapClassification> MapLocations; public readonly IReadOnlyDictionary<IReadOnlyPackage, MapClassification> MapLocations;
readonly Cache<string, MapPreview> previews; readonly Cache<string, MapPreview> previews;
@@ -41,7 +41,7 @@ namespace OpenRA
this.modData = modData; this.modData = modData;
var gridType = Exts.Lazy(() => modData.Manifest.Get<MapGrid>().Type); var gridType = Exts.Lazy(() => modData.Manifest.Get<MapGrid>().Type);
previews = new Cache<string, MapPreview>(uid => new MapPreview(uid, gridType.Value, this)); previews = new Cache<string, MapPreview>(uid => new MapPreview(modData, uid, gridType.Value, this));
sheetBuilder = new SheetBuilder(SheetType.BGRA); sheetBuilder = new SheetBuilder(SheetType.BGRA);
// Enumerate map directories // Enumerate map directories

View File

@@ -53,10 +53,11 @@ namespace OpenRA
public readonly bool downloading; public readonly bool downloading;
} }
public class MapPreview : IDisposable public class MapPreview : IDisposable, IReadOnlyFileSystem
{ {
static readonly CPos[] NoSpawns = new CPos[] { }; static readonly CPos[] NoSpawns = new CPos[] { };
MapCache cache; MapCache cache;
ModData modData;
public readonly string Uid; public readonly string Uid;
public IReadOnlyPackage Package { get; private set; } public IReadOnlyPackage Package { get; private set; }
@@ -65,6 +66,8 @@ namespace OpenRA
public string Title { get; private set; } public string Title { get; private set; }
public string Type { get; private set; } public string Type { get; private set; }
public string Author { get; private set; } public string Author { get; private set; }
public string TileSet { get; private set; }
public MapPlayers Players { get; private set; }
public int PlayerCount { get; private set; } public int PlayerCount { get; private set; }
public CPos[] SpawnPoints { get; private set; } public CPos[] SpawnPoints { get; private set; }
public MapGridType GridType { get; private set; } public MapGridType GridType { get; private set; }
@@ -75,6 +78,10 @@ namespace OpenRA
public MapVisibility Visibility { get; private set; } public MapVisibility Visibility { get; private set; }
public bool SuitableForInitialMap { get; private set; } public bool SuitableForInitialMap { get; private set; }
Lazy<Ruleset> rules;
public Ruleset Rules { get { return rules != null ? rules.Value : null; } }
public bool InvalidCustomRules { get; private set; }
Download download; Download download;
public long DownloadBytes { get; private set; } public long DownloadBytes { get; private set; }
public int DownloadPercentage { get; private set; } public int DownloadPercentage { get; private set; }
@@ -101,9 +108,11 @@ namespace OpenRA
generatingMinimap = false; generatingMinimap = false;
} }
public MapPreview(string uid, MapGridType gridType, MapCache cache) public MapPreview(ModData modData, string uid, MapGridType gridType, MapCache cache)
{ {
this.cache = cache; this.cache = cache;
this.modData = modData;
Uid = uid; Uid = uid;
Title = "Unknown Map"; Title = "Unknown Map";
Type = "Unknown"; Type = "Unknown";
@@ -145,6 +154,8 @@ namespace OpenRA
Title = temp.Value; Title = temp.Value;
if (yaml.TryGetValue("Type", out temp)) if (yaml.TryGetValue("Type", out temp))
Type = temp.Value; Type = temp.Value;
if (yaml.TryGetValue("Tileset", out temp))
TileSet = temp.Value;
if (yaml.TryGetValue("Author", out temp)) if (yaml.TryGetValue("Author", out temp))
Author = temp.Value; Author = temp.Value;
if (yaml.TryGetValue("Bounds", out temp)) if (yaml.TryGetValue("Bounds", out temp))
@@ -188,9 +199,9 @@ namespace OpenRA
MiniYaml playerDefinitions; MiniYaml playerDefinitions;
if (yaml.TryGetValue("Players", out playerDefinitions)) if (yaml.TryGetValue("Players", out playerDefinitions))
{ {
var players = new MapPlayers(playerDefinitions.Nodes).Players; Players = new MapPlayers(playerDefinitions.Nodes);
PlayerCount = players.Count(x => x.Value.Playable); PlayerCount = Players.Players.Count(x => x.Value.Playable);
SuitableForInitialMap = EvaluateUserFriendliness(players); SuitableForInitialMap = EvaluateUserFriendliness(Players.Players);
} }
} }
catch (Exception) catch (Exception)
@@ -198,11 +209,41 @@ namespace OpenRA
Status = MapStatus.Unavailable; Status = MapStatus.Unavailable;
} }
rules = Exts.Lazy(() =>
{
try
{
var ruleDefinitions = LoadRuleSection(yaml, "Rules");
var weaponDefinitions = LoadRuleSection(yaml, "Weapons");
var voiceDefinitions = LoadRuleSection(yaml, "Voices");
var musicDefinitions = LoadRuleSection(yaml, "Music");
var notificationDefinitions = LoadRuleSection(yaml, "Notifications");
var sequenceDefinitions = LoadRuleSection(yaml, "Sequences");
return Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions);
}
catch
{
InvalidCustomRules = true;
}
return Ruleset.LoadDefaultsForTileSet(modData, TileSet);
});
if (p.Contains("map.png")) if (p.Contains("map.png"))
using (var dataStream = p.GetStream("map.png")) using (var dataStream = p.GetStream("map.png"))
Preview = new Bitmap(dataStream); Preview = new Bitmap(dataStream);
} }
MiniYaml LoadRuleSection(Dictionary<string, MiniYaml> yaml, string section)
{
MiniYaml node;
if (!yaml.TryGetValue(section, out node))
return null;
return node;
}
bool EvaluateUserFriendliness(Dictionary<string, PlayerReference> players) bool EvaluateUserFriendliness(Dictionary<string, PlayerReference> players)
{ {
if (Status != MapStatus.Available || !Visibility.HasFlag(MapVisibility.Lobby)) if (Status != MapStatus.Available || !Visibility.HasFlag(MapVisibility.Lobby))
@@ -367,5 +408,42 @@ namespace OpenRA
if (deleteFromPackage != null) if (deleteFromPackage != null)
deleteFromPackage.Delete(Package.Name); deleteFromPackage.Delete(Package.Name);
} }
Stream IReadOnlyFileSystem.Open(string filename)
{
// Explicit package paths never refer to a map
if (!filename.Contains("|") && Package.Contains(filename))
return Package.GetStream(filename);
return modData.DefaultFileSystem.Open(filename);
}
bool IReadOnlyFileSystem.TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename)
{
// Packages aren't supported inside maps
return modData.DefaultFileSystem.TryGetPackageContaining(path, out package, out filename);
}
bool IReadOnlyFileSystem.TryOpen(string filename, out Stream s)
{
// Explicit package paths never refer to a map
if (!filename.Contains("|"))
{
s = Package.GetStream(filename);
if (s != null)
return true;
}
return modData.DefaultFileSystem.TryOpen(filename, out s);
}
bool IReadOnlyFileSystem.Exists(string filename)
{
// Explicit package paths never refer to a map
if (!filename.Contains("|") && Package.Contains(filename))
return true;
return modData.DefaultFileSystem.Exists(filename);
}
} }
} }