public Manifest(string mod) { var path = Platform.ResolvePath(".", "mods", mod, "mod.yaml"); yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary(); Mod = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); Mod.Id = mod; // TODO: Use fieldloader Folders = YamlList(yaml, "Folders", true); MapFolders = YamlDictionary(yaml, "MapFolders", true); Packages = YamlDictionary(yaml, "Packages", true); Rules = YamlList(yaml, "Rules", true); Sequences = YamlList(yaml, "Sequences", true); VoxelSequences = YamlList(yaml, "VoxelSequences", true); Cursors = YamlList(yaml, "Cursors", true); Chrome = YamlList(yaml, "Chrome", true); Assemblies = YamlList(yaml, "Assemblies", true); ChromeLayout = YamlList(yaml, "ChromeLayout", true); Weapons = YamlList(yaml, "Weapons", true); Voices = YamlList(yaml, "Voices", true); Notifications = YamlList(yaml, "Notifications", true); Music = YamlList(yaml, "Music", true); Translations = YamlList(yaml, "Translations", true); TileSets = YamlList(yaml, "TileSets", true); ChromeMetrics = YamlList(yaml, "ChromeMetrics", true); Missions = YamlList(yaml, "Missions", true); ServerTraits = YamlList(yaml, "ServerTraits"); if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) { throw new InvalidDataException("`LoadScreen` section is not defined."); } if (!yaml.TryGetValue("LobbyDefaults", out LobbyDefaults)) { throw new InvalidDataException("`LobbyDefaults` section is not defined."); } Fonts = yaml["Fonts"].ToDictionary(my => { var nd = my.ToDictionary(); return(Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value))); }); if (yaml.ContainsKey("TileSize")) { TileSize = FieldLoader.GetValue <Size>("TileSize", yaml["TileSize"].Value); } if (yaml.ContainsKey("TileShape")) { TileShape = FieldLoader.GetValue <TileShape>("TileShape", yaml["TileShape"].Value); } if (yaml.ContainsKey("SubCells")) { var subcells = yaml["SubCells"].ToDictionary(); // Read (x,y,z) offset (relative to cell center) pairs for positioning subcells if (subcells.ContainsKey("Offsets")) { SubCellOffsets = FieldLoader.GetValue <WVec[]>("Offsets", subcells["Offsets"].Value); } if (subcells.ContainsKey("DefaultIndex")) { SubCellDefaultIndex = FieldLoader.GetValue <int>("DefaultIndex", subcells["DefaultIndex"].Value); } else // Otherwise set the default subcell index to the middle subcell entry { SubCellDefaultIndex = SubCellOffsets.Length / 2; } } // Validate default index - 0 for no subcells, otherwise > 1 & <= subcell count (offset triples count - 1) if (SubCellDefaultIndex < (SubCellOffsets.Length > 1 ? 1 : 0) || SubCellDefaultIndex >= SubCellOffsets.Length) { throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells"); } // Allow inherited mods to import parent maps. var compat = new List <string>(); compat.Add(mod); if (yaml.ContainsKey("SupportsMapsFrom")) { foreach (var c in yaml["SupportsMapsFrom"].Value.Split(',')) { compat.Add(c.Trim()); } } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("SpriteFormats")) { SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value); } }
public Manifest(string modId, IReadOnlyPackage package) { Id = modId; Package = package; yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary(); Metadata = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); // TODO: Use fieldloader MapFolders = YamlDictionary(yaml, "MapFolders"); MiniYaml packages; if (yaml.TryGetValue("Packages", out packages)) { Packages = packages.ToDictionary(x => x.Value).AsReadOnly(); } Rules = YamlList(yaml, "Rules"); Sequences = YamlList(yaml, "Sequences"); VoxelSequences = YamlList(yaml, "VoxelSequences"); Cursors = YamlList(yaml, "Cursors"); Chrome = YamlList(yaml, "Chrome"); Assemblies = YamlList(yaml, "Assemblies"); ChromeLayout = YamlList(yaml, "ChromeLayout"); Weapons = YamlList(yaml, "Weapons"); Voices = YamlList(yaml, "Voices"); Notifications = YamlList(yaml, "Notifications"); Music = YamlList(yaml, "Music"); Translations = YamlList(yaml, "Translations"); TileSets = YamlList(yaml, "TileSets"); ChromeMetrics = YamlList(yaml, "ChromeMetrics"); Missions = YamlList(yaml, "Missions"); ServerTraits = YamlList(yaml, "ServerTraits"); if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) { throw new InvalidDataException("`LoadScreen` section is not defined."); } Fonts = yaml["Fonts"].ToDictionary(my => { var nd = my.ToDictionary(); return(Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value))); }); RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value); // Allow inherited mods to import parent maps. var compat = new List <string> { Id }; if (yaml.ContainsKey("SupportsMapsFrom")) { compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim())); } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("SoundFormats")) { SoundFormats = FieldLoader.GetValue <string[]>("SoundFormats", yaml["SoundFormats"].Value); } if (yaml.ContainsKey("SpriteFormats")) { SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value); } }
public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false) { Languages = new string[0]; // Take a local copy of the manifest Manifest = new Manifest(mod.Id, mod.Package); ObjectCreator = new ObjectCreator(Manifest, mods); PackageLoaders = ObjectCreator.GetLoaders <IPackageLoader>(Manifest.PackageFormats, "package"); ModFiles = new FS(mod.Id, mods, PackageLoaders); ModFiles.LoadFromManifest(Manifest); Manifest.LoadCustomData(ObjectCreator); if (useLoadScreen) { LoadScreen = ObjectCreator.CreateObject <ILoadScreen>(Manifest.LoadScreen.Value); LoadScreen.Init(this, Manifest.LoadScreen.ToDictionary(my => my.Value)); LoadScreen.Display(); } WidgetLoader = new WidgetLoader(this); MapCache = new MapCache(this); SoundLoaders = ObjectCreator.GetLoaders <ISoundLoader>(Manifest.SoundFormats, "sound"); SpriteLoaders = ObjectCreator.GetLoaders <ISpriteLoader>(Manifest.SpriteFormats, "sprite"); var sequenceFormat = Manifest.Get <SpriteSequenceFormat>(); var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader"); var sequenceCtor = sequenceLoader != null?sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null; if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null) { throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type)); } SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this }); SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s); var modelFormat = Manifest.Get <ModelSequenceFormat>(); var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader"); var modelCtor = modelLoader != null?modelLoader.GetConstructor(new[] { typeof(ModData) }) : null; if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null) { throw new InvalidOperationException("Unable to find a model loader for type '{0}'.".F(modelFormat.Type)); } ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this }); ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s); Hotkeys = new HotkeyManager(ModFiles, Game.Settings.Keys, Manifest); defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this)); defaultTileSets = Exts.Lazy(() => { var items = new Dictionary <string, TileSet>(); foreach (var file in Manifest.TileSets) { var t = new TileSet(DefaultFileSystem, file); items.Add(t.Id, t); } return((IReadOnlyDictionary <string, TileSet>)(new ReadOnlyDictionary <string, TileSet>(items))); }); defaultSequences = Exts.Lazy(() => { var items = DefaultTileSets.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Value, null)); return((IReadOnlyDictionary <string, SequenceProvider>)(new ReadOnlyDictionary <string, SequenceProvider>(items))); }); initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; }
// Sampled a N-sample probability density function in the range [-1024..1024] // 1 sample produces a rectangular probability // 2 samples produces a triangular probability // ... // N samples approximates a true gaussian public static WDist FromPDF(MersenneTwister r, int samples) { return(new WDist(Exts.MakeArray(samples, _ => r.Next(-1024, 1024)) .Sum() / samples)); }
public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field) { var value = yaml.Value; if (value != null) { value = value.Trim(); } if (fieldType == typeof(int)) { int res; if (Exts.TryParseIntegerInvariant(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(ushort)) { ushort res; if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } if (fieldType == typeof(long)) { long res; if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(float)) { float res; if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { return(res * (value.Contains('%') ? 0.01f : 1f)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(decimal)) { decimal res; if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { return(res * (value.Contains('%') ? 0.01m : 1m)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(string)) { if (field != null && MemberHasTranslateAttribute[field] && value != null) { return(Regex.Replace(value, "@[^@]+@", m => Translate(m.Value.Substring(1, m.Value.Length - 2)), RegexOptions.Compiled)); } return(value); } else if (fieldType == typeof(Color)) { Color color; if (value != null && HSLColor.TryParseRGB(value, out color)) { return(color); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(Color[])) { if (value != null) { var parts = value.Split(','); var colors = new Color[parts.Length]; for (var i = 0; i < colors.Length; i++) { if (!HSLColor.TryParseRGB(parts[i], out colors[i])) { return(InvalidValueAction(value, fieldType, fieldName)); } } return(colors); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(HSLColor)) { if (value != null) { Color rgb; if (HSLColor.TryParseRGB(value, out rgb)) { return(new HSLColor(rgb)); } // Allow old HSLColor/ColorRamp formats to be parsed as HSLColor var parts = value.Split(','); if (parts.Length == 3 || parts.Length == 4) { return(new HSLColor( (byte)Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255))); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(Hotkey)) { Hotkey res; if (Hotkey.TryParse(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(HotkeyReference)) { return(Game.ModData.Hotkeys[value]); } else if (fieldType == typeof(WDist)) { WDist res; if (WDist.TryParse(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WVec)) { if (value != null) { var parts = value.Split(','); if (parts.Length == 3) { WDist rx, ry, rz; if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz)) { return(new WVec(rx, ry, rz)); } } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WVec[])) { if (value != null) { var parts = value.Split(','); if (parts.Length % 3 != 0) { return(InvalidValueAction(value, fieldType, fieldName)); } var vecs = new WVec[parts.Length / 3]; for (var i = 0; i < vecs.Length; ++i) { WDist rx, ry, rz; if (WDist.TryParse(parts[3 * i], out rx) && WDist.TryParse(parts[3 * i + 1], out ry) && WDist.TryParse(parts[3 * i + 2], out rz)) { vecs[i] = new WVec(rx, ry, rz); } } return(vecs); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WPos)) { if (value != null) { var parts = value.Split(','); if (parts.Length == 3) { WDist rx, ry, rz; if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz)) { return(new WPos(rx, ry, rz)); } } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WAngle)) { int res; if (Exts.TryParseIntegerInvariant(value, out res)) { return(new WAngle(res)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WRot)) { if (value != null) { var parts = value.Split(','); if (parts.Length == 3) { int rr, rp, ry; if (Exts.TryParseIntegerInvariant(parts[0], out rr) && Exts.TryParseIntegerInvariant(parts[1], out rp) && Exts.TryParseIntegerInvariant(parts[2], out ry)) { return(new WRot(new WAngle(rr), new WAngle(rp), new WAngle(ry))); } } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(CPos)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new CPos(Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(CVec)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new CVec(Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(CVec[])) { if (value != null) { var parts = value.Split(','); if (parts.Length % 2 != 0) { return(InvalidValueAction(value, fieldType, fieldName)); } var vecs = new CVec[parts.Length / 2]; for (var i = 0; i < vecs.Length; i++) { int rx, ry; if (int.TryParse(parts[2 * i], out rx) && int.TryParse(parts[2 * i + 1], out ry)) { vecs[i] = new CVec(rx, ry); } } return(vecs); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(BooleanExpression)) { if (value != null) { try { return(BooleanExpressionCache[value]); } catch (InvalidDataException e) { throw new YamlException(e.Message); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(IntegerExpression)) { if (value != null) { try { return(IntegerExpressionCache[value]); } catch (InvalidDataException e) { throw new YamlException(e.Message); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType.IsEnum) { try { return(Enum.Parse(fieldType, value, true)); } catch (ArgumentException) { return(InvalidValueAction(value, fieldType, fieldName)); } } else if (fieldType == typeof(ImageFormat)) { if (value != null) { switch (value.ToLowerInvariant()) { case "bmp": return(ImageFormat.Bmp); case "gif": return(ImageFormat.Gif); case "jpg": case "jpeg": return(ImageFormat.Jpeg); case "tif": case "tiff": return(ImageFormat.Tiff); default: return(ImageFormat.Png); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(bool)) { return(ParseYesNo(value, fieldType, fieldName)); } else if (fieldType == typeof(int2[])) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length % 2 != 0) { return(InvalidValueAction(value, fieldType, fieldName)); } var ints = new int2[parts.Length / 2]; for (var i = 0; i < ints.Length; i++) { ints[i] = new int2(Exts.ParseIntegerInvariant(parts[2 * i]), Exts.ParseIntegerInvariant(parts[2 * i + 1])); } return(ints); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType.IsArray && fieldType.GetArrayRank() == 1) { if (value == null) { return(Array.CreateInstance(fieldType.GetElementType(), 0)); } var options = field != null && field.HasAttribute <AllowEmptyEntriesAttribute>() ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries; var parts = value.Split(new char[] { ',' }, options); var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length); for (var i = 0; i < parts.Length; i++) { ret.SetValue(GetValue(fieldName, fieldType.GetElementType(), parts[i].Trim(), field), i); } return(ret); } else if (fieldType.IsGenericType && (fieldType.GetGenericTypeDefinition() == typeof(HashSet <>) || fieldType.GetGenericTypeDefinition() == typeof(List <>))) { var set = Activator.CreateInstance(fieldType); if (value == null) { return(set); } var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var addMethod = fieldType.GetMethod("Add", fieldType.GetGenericArguments()); for (var i = 0; i < parts.Length; i++) { addMethod.Invoke(set, new[] { GetValue(fieldName, fieldType.GetGenericArguments()[0], parts[i].Trim(), field) }); } return(set); } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary <,>)) { var dict = Activator.CreateInstance(fieldType); var arguments = fieldType.GetGenericArguments(); var addMethod = fieldType.GetMethod("Add", arguments); foreach (var node in yaml.Nodes) { var key = GetValue(fieldName, arguments[0], node.Key, field); var val = GetValue(fieldName, arguments[1], node.Value, field); addMethod.Invoke(dict, new[] { key, val }); } return(dict); } else if (fieldType == typeof(Size)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new Size(Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(int2)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != 2) { return(InvalidValueAction(value, fieldType, fieldName)); } return(new int2(Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(float2)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); float xx = 0; float yy = 0; float res; if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { xx = res * (parts[0].Contains('%') ? 0.01f : 1f); } if (float.TryParse(parts[1].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { yy = res * (parts[1].Contains('%') ? 0.01f : 1f); } return(new float2(xx, yy)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(float3)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); float x = 0; float y = 0; float z = 0; float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out x); float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out y); // z component is optional for compatibility with older float2 definitions if (parts.Length > 2) { float.TryParse(parts[2], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out z); } return(new float3(x, y, z)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(Rectangle)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new Rectangle( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]), Exts.ParseIntegerInvariant(parts[2]), Exts.ParseIntegerInvariant(parts[3]))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(BitSet <>)) { if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var ctor = fieldType.GetConstructor(new[] { typeof(string[]) }); return(ctor.Invoke(new object[] { parts.Select(p => p.Trim()).ToArray() })); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var innerType = fieldType.GetGenericArguments().First(); var innerValue = GetValue("Nullable<T>", innerType, value, field); return(fieldType.GetConstructor(new[] { innerType }).Invoke(new[] { innerValue })); } else if (fieldType == typeof(DateTime)) { DateTime dt; if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dt)) { return(dt); } return(InvalidValueAction(value, fieldType, fieldName)); } else { var conv = TypeDescriptor.GetConverter(fieldType); if (conv.CanConvertFrom(typeof(string))) { try { return(conv.ConvertFromInvariantString(value)); } catch { return(InvalidValueAction(value, fieldType, fieldName)); } } } UnknownFieldAction("[Type] {0}".F(value), fieldType); return(null); }
public static object GetValue(string fieldName, Type fieldType, string value, MemberInfo field) { if (value != null) { value = value.Trim(); } if (fieldType == typeof(int)) { int res; if (Exts.TryParseIntegerInvariant(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(ushort)) { ushort res; if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } if (fieldType == typeof(long)) { long res; if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(float)) { float res; if (float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { return(res * (value.Contains('%') ? 0.01f : 1f)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(decimal)) { decimal res; if (decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { return(res * (value.Contains('%') ? 0.01m : 1m)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(string)) { if (field != null && field.HasAttribute <TranslateAttribute>()) { return(Regex.Replace(value, "@[^@]+@", m => Translate(m.Value.Substring(1, m.Value.Length - 2)), RegexOptions.Compiled)); } return(value); } else if (fieldType == typeof(Color)) { var parts = value.Split(','); if (parts.Length == 3) { return(Color.FromArgb( Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255), Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255), Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255))); } if (parts.Length == 4) { return(Color.FromArgb( Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255), Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255), Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255), Exts.ParseIntegerInvariant(parts[3]).Clamp(0, 255))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(HSLColor)) { var parts = value.Split(','); // Allow old ColorRamp format to be parsed as HSLColor if (parts.Length == 3 || parts.Length == 4) { return(new HSLColor( (byte)Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255))); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(Hotkey)) { Hotkey res; if (Hotkey.TryParse(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WRange)) { WRange res; if (WRange.TryParse(value, out res)) { return(res); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WVec)) { var parts = value.Split(','); if (parts.Length == 3) { WRange rx, ry, rz; if (WRange.TryParse(parts[0], out rx) && WRange.TryParse(parts[1], out ry) && WRange.TryParse(parts[2], out rz)) { return(new WVec(rx, ry, rz)); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WVec[])) { var parts = value.Split(','); if (parts.Length % 3 != 0) { return(InvalidValueAction(value, fieldType, fieldName)); } var vecs = new WVec[parts.Length / 3]; for (var i = 0; i < vecs.Length; ++i) { WRange rx, ry, rz; if (WRange.TryParse(parts[3 * i], out rx) && WRange.TryParse(parts[3 * i + 1], out ry) && WRange.TryParse(parts[3 * i + 2], out rz)) { vecs[i] = new WVec(rx, ry, rz); } } return(vecs); } else if (fieldType == typeof(WPos)) { var parts = value.Split(','); if (parts.Length == 3) { WRange rx, ry, rz; if (WRange.TryParse(parts[0], out rx) && WRange.TryParse(parts[1], out ry) && WRange.TryParse(parts[2], out rz)) { return(new WPos(rx, ry, rz)); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WAngle)) { int res; if (Exts.TryParseIntegerInvariant(value, out res)) { return(new WAngle(res)); } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(WRot)) { var parts = value.Split(','); if (parts.Length == 3) { int rr, rp, ry; if (Exts.TryParseIntegerInvariant(value, out rr) && Exts.TryParseIntegerInvariant(value, out rp) && Exts.TryParseIntegerInvariant(value, out ry)) { return(new WRot(new WAngle(rr), new WAngle(rp), new WAngle(ry))); } } return(InvalidValueAction(value, fieldType, fieldName)); } else if (fieldType == typeof(CPos)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new CPos( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } else if (fieldType == typeof(CVec)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new CVec( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } else if (fieldType.IsEnum) { try { return(Enum.Parse(fieldType, value, true)); } catch (ArgumentException) { return(InvalidValueAction(value, fieldType, fieldName)); } } else if (fieldType == typeof(bool)) { return(ParseYesNo(value, fieldType, fieldName)); } else if (fieldType.IsArray) { if (value == null) { return(Array.CreateInstance(fieldType.GetElementType(), 0)); } var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length); for (var i = 0; i < parts.Length; i++) { ret.SetValue(GetValue(fieldName, fieldType.GetElementType(), parts[i].Trim(), field), i); } return(ret); } else if (fieldType == typeof(Size)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new Size( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } else if (fieldType == typeof(int2)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new int2( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]))); } else if (fieldType == typeof(float2)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); float xx = 0; float yy = 0; float res; if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { xx = res * (parts[0].Contains('%') ? 0.01f : 1f); } if (float.TryParse(parts[1].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) { yy = res * (parts[1].Contains('%') ? 0.01f : 1f); } return(new float2(xx, yy)); } else if (fieldType == typeof(Rectangle)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); return(new Rectangle( Exts.ParseIntegerInvariant(parts[0]), Exts.ParseIntegerInvariant(parts[1]), Exts.ParseIntegerInvariant(parts[2]), Exts.ParseIntegerInvariant(parts[3]))); } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Bits <>)) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var argTypes = new Type[] { typeof(string[]) }; var argValues = new object[] { parts }; return(fieldType.GetConstructor(argTypes).Invoke(argValues)); } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var innerType = fieldType.GetGenericArguments().First(); var innerValue = GetValue("Nullable<T>", innerType, value, field); return(fieldType.GetConstructor(new[] { innerType }).Invoke(new[] { innerValue })); } else if (fieldType == typeof(DateTime)) { DateTime dt; if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dt)) { return(dt); } return(InvalidValueAction(value, fieldType, fieldName)); } else { var conv = TypeDescriptor.GetConverter(fieldType); if (conv.CanConvertFrom(typeof(string))) { try { return(conv.ConvertFromInvariantString(value)); } catch { return(InvalidValueAction(value, fieldType, fieldName)); } } } UnknownFieldAction("[Type] {0}".F(value), fieldType); return(null); }
public void OnScriptBind(ScriptContext context) { luaInterface = Exts.Lazy(() => new ScriptPlayerInterface(context, this)); }
public Manifest(string mod) { var path = Platform.ResolvePath(".", "mods", mod, "mod.yaml"); yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary(); Mod = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); Mod.Id = mod; // TODO: Use fieldloader Folders = YamlList(yaml, "Folders", true); MapFolders = YamlDictionary(yaml, "MapFolders", true); Packages = YamlDictionary(yaml, "Packages", true); Rules = YamlList(yaml, "Rules", true); Sequences = YamlList(yaml, "Sequences", true); VoxelSequences = YamlList(yaml, "VoxelSequences", true); Cursors = YamlList(yaml, "Cursors", true); Chrome = YamlList(yaml, "Chrome", true); Assemblies = YamlList(yaml, "Assemblies", true); ChromeLayout = YamlList(yaml, "ChromeLayout", true); Weapons = YamlList(yaml, "Weapons", true); Voices = YamlList(yaml, "Voices", true); Notifications = YamlList(yaml, "Notifications", true); Music = YamlList(yaml, "Music", true); Translations = YamlList(yaml, "Translations", true); TileSets = YamlList(yaml, "TileSets", true); ChromeMetrics = YamlList(yaml, "ChromeMetrics", true); Missions = YamlList(yaml, "Missions", true); ServerTraits = YamlList(yaml, "ServerTraits"); if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) { throw new InvalidDataException("`LoadScreen` section is not defined."); } if (!yaml.TryGetValue("LobbyDefaults", out LobbyDefaults)) { throw new InvalidDataException("`LobbyDefaults` section is not defined."); } Fonts = yaml["Fonts"].ToDictionary(my => { var nd = my.ToDictionary(); return(Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value))); }); RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value); // Allow inherited mods to import parent maps. var compat = new List <string>(); compat.Add(mod); if (yaml.ContainsKey("SupportsMapsFrom")) { foreach (var c in yaml["SupportsMapsFrom"].Value.Split(',')) { compat.Add(c.Trim()); } } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("SoundFormats")) { SoundFormats = FieldLoader.GetValue <string[]>("SoundFormats", yaml["SoundFormats"].Value); } if (yaml.ContainsKey("SpriteFormats")) { SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value); } }
public static Order Deserialize(World world, BinaryReader r) { try { var type = (OrderType)r.ReadByte(); switch (type) { case OrderType.Fields: { var order = r.ReadString(); var flags = (OrderFields)r.ReadByte(); Actor subject = null; if (flags.HasField(OrderFields.Subject)) { var subjectId = r.ReadUInt32(); if (world != null) { TryGetActorFromUInt(world, subjectId, out subject); } } var target = Target.Invalid; if (flags.HasField(OrderFields.Target)) { switch ((TargetType)r.ReadByte()) { case TargetType.Actor: { Actor targetActor; if (world != null && TryGetActorFromUInt(world, r.ReadUInt32(), out targetActor)) { target = Target.FromActor(targetActor); } break; } case TargetType.FrozenActor: { var playerActorID = r.ReadUInt32(); var frozenActorID = r.ReadUInt32(); Actor playerActor; if (world == null || !TryGetActorFromUInt(world, playerActorID, out playerActor)) { break; } if (playerActor.Owner.FrozenActorLayer == null) { break; } var frozen = playerActor.Owner.FrozenActorLayer.FromID(frozenActorID); if (frozen != null) { target = Target.FromFrozenActor(frozen); } break; } case TargetType.Terrain: { if (flags.HasField(OrderFields.TargetIsCell)) { var cell = new CPos(r.ReadInt32()); var subCell = (SubCell)r.ReadByte(); if (world != null) { target = Target.FromCell(world, cell, subCell); } } else { var pos = new WPos(r.ReadInt32(), r.ReadInt32(), r.ReadInt32()); target = Target.FromPos(pos); } break; } } } var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null; var queued = flags.HasField(OrderFields.Queued); Actor[] extraActors = null; if (flags.HasField(OrderFields.ExtraActors)) { var count = r.ReadInt32(); if (world != null) { extraActors = Exts.MakeArray(count, _ => world.GetActorById(r.ReadUInt32())); } else { r.ReadBytes(4 * count); } } var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32()) : CPos.Zero; var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0; if (world == null) { return(new Order(order, null, target, targetString, queued, extraActors, extraLocation, extraData)); } if (subject == null && flags.HasField(OrderFields.Subject)) { return(null); } return(new Order(order, subject, target, targetString, queued, extraActors, extraLocation, extraData)); } case OrderType.Handshake: { var name = r.ReadString(); var targetString = r.ReadString(); return(new Order(name, null, false) { Type = OrderType.Handshake, TargetString = targetString }); } default: { Log.Write("debug", "Received unknown order with type {0}", type); return(null); } } } catch (Exception e) { Log.Write("debug", "Caught exception while processing order"); Log.Write("debug", e.ToString()); // HACK: this can hopefully go away in the future Game.Debug("Ignoring malformed order that would have crashed the game"); Game.Debug("Please file a bug report and include the replay from this match"); return(null); } }
public Manifest(string mod) { var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine); var yaml = new MiniYaml(null, MiniYaml.FromFile(path)).NodesDict; Mod = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); Mod.Id = mod; // TODO: Use fieldloader Folders = YamlList(yaml, "Folders"); MapFolders = YamlDictionary(yaml, "MapFolders"); Packages = YamlDictionary(yaml, "Packages"); Rules = YamlList(yaml, "Rules"); ServerTraits = YamlList(yaml, "ServerTraits"); Sequences = YamlList(yaml, "Sequences"); VoxelSequences = YamlList(yaml, "VoxelSequences"); Cursors = YamlList(yaml, "Cursors"); Chrome = YamlList(yaml, "Chrome"); Assemblies = YamlList(yaml, "Assemblies"); ChromeLayout = YamlList(yaml, "ChromeLayout"); Weapons = YamlList(yaml, "Weapons"); Voices = YamlList(yaml, "Voices"); Notifications = YamlList(yaml, "Notifications"); Music = YamlList(yaml, "Music"); Movies = YamlList(yaml, "Movies"); Translations = YamlList(yaml, "Translations"); TileSets = YamlList(yaml, "TileSets"); ChromeMetrics = YamlList(yaml, "ChromeMetrics"); PackageContents = YamlList(yaml, "PackageContents"); LuaScripts = YamlList(yaml, "LuaScripts"); Missions = YamlList(yaml, "Missions"); LoadScreen = yaml["LoadScreen"]; LobbyDefaults = yaml["LobbyDefaults"]; Fonts = yaml["Fonts"].NodesDict.ToDictionary(x => x.Key, x => Pair.New(x.Value.NodesDict["Font"].Value, Exts.ParseIntegerInvariant(x.Value.NodesDict["Size"].Value))); if (yaml.ContainsKey("TileSize")) { TileSize = FieldLoader.GetValue <Size>("TileSize", yaml["TileSize"].Value); } // Allow inherited mods to import parent maps. var compat = new List <string>(); compat.Add(mod); if (yaml.ContainsKey("SupportsMapsFrom")) { foreach (var c in yaml["SupportsMapsFrom"].Value.Split(',')) { compat.Add(c.Trim()); } } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("NewsUrl")) { NewsUrl = yaml["NewsUrl"].Value; } }
/// <summary>Initializes a map loaded from disk.</summary> public Map(string path) { containsTest = Contains; Path = path; Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue); AssertExists("map.yaml"); AssertExists("map.bin"); var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetContent("map.yaml"), path)); FieldLoader.Load(this, yaml); // Support for formats 1-3 dropped 2011-02-11. // Use release-20110207 to convert older maps to format 4 // Use release-20110511 to convert older maps to format 5 // Use release-20141029 to convert older maps to format 6 if (MapFormat < 6) { throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path)); } var nd = yaml.ToDictionary(); // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum if (MapFormat < 7) { MiniYaml useAsShellmap; if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value)) { Visibility = MapVisibility.Shellmap; } else if (Type == "Mission" || Type == "Campaign") { Visibility = MapVisibility.MissionSelector; } } SpawnPoints = Exts.Lazy(() => { var spawns = new List <CPos>(); foreach (var kv in ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get <LocationInit>().Value(null)); } return(spawns.ToArray()); }); RuleDefinitions = MiniYaml.NodesOrEmpty(yaml, "Rules"); SequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Sequences"); VoxelSequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "VoxelSequences"); WeaponDefinitions = MiniYaml.NodesOrEmpty(yaml, "Weapons"); VoiceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Voices"); NotificationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Notifications"); TranslationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Translations"); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); SmudgeDefinitions = MiniYaml.NodesOrEmpty(yaml, "Smudges"); MapTiles = Exts.Lazy(LoadMapTiles); MapResources = Exts.Lazy(LoadResourceTiles); MapHeight = Exts.Lazy(LoadMapHeight); TileShape = Game.ModData.Manifest.TileShape; MaximumTerrainHeight = Game.ModData.Manifest.MaximumTerrainHeight; SubCellOffsets = Game.ModData.Manifest.SubCellOffsets; LastSubCell = (SubCell)(SubCellOffsets.Length - 1); DefaultSubCell = (SubCell)Game.ModData.Manifest.SubCellDefaultIndex; if (Container.Exists("map.png")) { using (var dataStream = Container.GetContent("map.png")) CustomPreview = new Bitmap(dataStream); } PostInit(); // The Uid is calculated from the data on-disk, so // format changes must be flushed to disk. // TODO: this isn't very nice if (MapFormat < 7) { Save(path); } Uid = ComputeHash(); }
internal Actor(World world, string name, TypeDictionary initDict) { var init = new ActorInitializer(this, initDict); World = world; ActorID = world.NextAID(); if (initDict.Contains <OwnerInit>()) { Owner = init.Get <OwnerInit, Player>(); } occupySpace = Exts.Lazy(() => TraitOrDefault <IOccupySpace>()); if (name != null) { name = name.ToLowerInvariant(); if (!world.Map.Rules.Actors.ContainsKey(name)) { throw new NotImplementedException("No rules definition for unit " + name); } Info = world.Map.Rules.Actors[name]; foreach (var trait in Info.TraitsInConstructOrder()) { AddTrait(trait.Create(init)); } } facing = Exts.Lazy(() => TraitOrDefault <IFacing>()); health = Exts.Lazy(() => TraitOrDefault <Health>()); effectiveOwner = Exts.Lazy(() => TraitOrDefault <IEffectiveOwner>()); bounds = Exts.Lazy(() => { var si = Info.Traits.GetOrDefault <SelectableInfo>(); var size = (si != null && si.Bounds != null) ? new int2(si.Bounds[0], si.Bounds[1]) : TraitsImplementing <IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault(); var offset = -size / 2; if (si != null && si.Bounds != null && si.Bounds.Length > 2) { offset += new int2(si.Bounds[2], si.Bounds[3]); } return(new Rectangle(offset.X, offset.Y, size.X, size.Y)); }); visualBounds = Exts.Lazy(() => { var sd = Info.Traits.GetOrDefault <ISelectionDecorationsInfo>(); if (sd == null || sd.SelectionBoxBounds == null) { return(bounds.Value); } var size = new int2(sd.SelectionBoxBounds[0], sd.SelectionBoxBounds[1]); var offset = -size / 2; if (sd.SelectionBoxBounds.Length > 2) { offset += new int2(sd.SelectionBoxBounds[2], sd.SelectionBoxBounds[3]); } return(new Rectangle(offset.X, offset.Y, size.X, size.Y)); }); renderModifiers = TraitsImplementing <IRenderModifier>().ToArray(); renders = TraitsImplementing <IRender>().ToArray(); disables = TraitsImplementing <IDisable>().ToArray(); }
// Sampled a N-sample probability density function in the range [-1024..1024] // 1 sample produces a rectangular probability // 2 samples produces a triangular probability // ... // N samples approximates a true gaussian public static WRange FromPDF(Thirdparty.Random r, int samples) { return(new WRange(Exts.MakeArray(samples, _ => r.Next(-1024, 1024)) .Sum() / samples)); }
public static float Gauss1D(this Thirdparty.Random r, int samples) { return(Exts.MakeArray(samples, _ => (float)r.NextDouble() * 2 - 1f) .Sum() / samples); }
void PostInit() { rules = Exts.Lazy(() => Game.modData.RulesetCache.LoadMapRules(this)); }
// Support upgrading format 5 maps to a more // recent version by defining upgradeForMod. public Map(string path, string upgradeForMod) { Path = path; Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue); AssertExists("map.yaml"); AssertExists("map.bin"); var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetContent("map.yaml"))); FieldLoader.Load(this, yaml); // Support for formats 1-3 dropped 2011-02-11. // Use release-20110207 to convert older maps to format 4 // Use release-20110511 to convert older maps to format 5 if (MapFormat < 5) { throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path)); } // Format 5 -> 6 enforces the use of RequiresMod if (MapFormat == 5) { if (upgradeForMod == null) { throw new InvalidDataException("Map format {0} is not supported, but can be upgraded.\n File: {1}".F(MapFormat, path)); } Console.WriteLine("Upgrading {0} from Format 5 to Format 6", path); // TODO: This isn't very nice, but there is no other consistent way // of finding the mod early during the engine initialization. RequiresMod = upgradeForMod; } // Load players foreach (var kv in yaml.NodesDict["Players"].NodesDict) { var player = new PlayerReference(kv.Value); Players.Add(player.Name, player); } Actors = Exts.Lazy(() => { var ret = new Dictionary <string, ActorReference>(); foreach (var kv in yaml.NodesDict["Actors"].NodesDict) { ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.NodesDict)); } return(ret); }); // Smudges Smudges = Exts.Lazy(() => { var ret = new List <SmudgeReference>(); foreach (var kv in yaml.NodesDict["Smudges"].NodesDict) { var vals = kv.Key.Split(' '); var loc = vals[1].Split(','); ret.Add(new SmudgeReference(vals[0], new int2( Exts.ParseIntegerInvariant(loc[0]), Exts.ParseIntegerInvariant(loc[1])), Exts.ParseIntegerInvariant(vals[2]))); } return(ret); }); RuleDefinitions = MiniYaml.NodesOrEmpty(yaml, "Rules"); SequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Sequences"); VoxelSequenceDefinitions = MiniYaml.NodesOrEmpty(yaml, "VoxelSequences"); WeaponDefinitions = MiniYaml.NodesOrEmpty(yaml, "Weapons"); VoiceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Voices"); NotificationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Notifications"); TranslationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Translations"); CustomTerrain = new string[MapSize.X, MapSize.Y]; MapTiles = Exts.Lazy(() => LoadMapTiles()); MapResources = Exts.Lazy(() => LoadResourceTiles()); // The Uid is calculated from the data on-disk, so // format changes must be flushed to disk. // TODO: this isn't very nice if (MapFormat < 6) { Save(path); } Uid = ComputeHash(); if (Container.Exists("map.png")) { CustomPreview = new Bitmap(Container.GetContent("map.png")); } PostInit(); }