#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.Generic; using System.Linq; using OpenRA.FileFormats; using OpenRA.GameRules; using OpenRA.Support; namespace OpenRA { public static class Rules { public static Dictionary Info { get { return Game.modData.Rules.Actors; } } public static Dictionary Weapons { get { return Game.modData.Rules.Weapons; } } public static Dictionary Voices { get { return Game.modData.Rules.Voices; } } public static Dictionary Notifications { get { return Game.modData.Rules.Notifications; } } public static Dictionary Music { get { return Game.modData.Rules.Music; } } public static Dictionary Movies { get { return Game.modData.Rules.Movies; } } public static Dictionary TileSets { get { return Game.modData.Rules.TileSets; } } public static void LoadRules(Manifest m, Map map) { // HACK: Fallback for code that hasn't been updated yet Game.modData.Rules = new ModRules(Game.modData); Game.modData.Rules.ActivateMap(map); } public static IEnumerable> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } } } public class ModRules { readonly ModData modData; // // These contain all unique instances created from each mod/map combination // readonly Dictionary actorCache = new Dictionary(); readonly Dictionary weaponCache = new Dictionary(); readonly Dictionary voiceCache = new Dictionary(); readonly Dictionary notificationCache = new Dictionary(); readonly Dictionary musicCache = new Dictionary(); readonly Dictionary movieCache = new Dictionary(); readonly Dictionary tileSetCache = new Dictionary(); // // These are the instances needed for the current map // public Dictionary Actors { get; private set; } public Dictionary Weapons { get; private set; } public Dictionary Voices { get; private set; } public Dictionary Notifications { get; private set; } public Dictionary Music { get; private set; } public Dictionary Movies { get; private set; } public Dictionary TileSets { get; private set; } public ModRules(ModData modData) { this.modData = modData; } public void ActivateMap(Map map) { var m = modData.Manifest; using (new PerfTimer("Actors")) Actors = LoadYamlRules(actorCache, m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y)); using (new PerfTimer("Weapons")) Weapons = LoadYamlRules(weaponCache, m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); using (new PerfTimer("Voices")) Voices = LoadYamlRules(voiceCache, m.Voices, map.Voices, (k, _) => new SoundInfo(k.Value)); using (new PerfTimer("Notifications")) Notifications = LoadYamlRules(notificationCache, m.Notifications, map.Notifications, (k, _) => new SoundInfo(k.Value)); using (new PerfTimer("Music")) Music = LoadYamlRules(musicCache, m.Music, new List(), (k, _) => new MusicInfo(k.Key, k.Value)); using (new PerfTimer("Movies")) Movies = LoadYamlRules(movieCache, m.Movies, new List(), (k, v) => k.Value.Value); using (new PerfTimer("TileSets")) TileSets = LoadTileSets(tileSetCache, m.TileSets); } Dictionary LoadYamlRules( Dictionary itemCache, string[] files, List nodes, Func, T> f) { var mergedNodes = files .Select(s => MiniYaml.FromFile(s)) .Aggregate(nodes, MiniYaml.MergeLiberal); Func, T> wrap = (wkv, wyy) => { var key = wkv.Value.ToLines(wkv.Key).JoinWith("|"); T t; if (itemCache.TryGetValue(key, out t)) return t; t = f(wkv, wyy); itemCache.Add(key, t); return t; }; var yy = mergedNodes.ToDictionary(x => x.Key, x => x.Value); var itemSet = mergedNodes.ToDictionaryWithConflictLog(kv => kv.Key.ToLowerInvariant(), kv => wrap(kv, yy), "LoadYamlRules", null, null); return itemSet; } Dictionary LoadTileSets(Dictionary itemCache, string[] files) { var items = new Dictionary(); foreach (var file in files) { TileSet t; if (itemCache.TryGetValue(file, out t)) { items.Add(t.Id, t); } else { t = new TileSet(file); itemCache.Add(file, t); items.Add(t.Id, t); } } return items; } } }