Exemple #1
0
        static object ParseRectangle(string fieldName, Type fieldType, string value, MemberInfo field)
        {
            if (value != null)
            {
                var parts = value.Split(SplitComma, 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));
        }
Exemple #2
0
        static object ParseInt2Array(string fieldName, Type fieldType, string value, MemberInfo field)
        {
            if (value != null)
            {
                var parts = value.Split(SplitComma, 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));
        }
Exemple #3
0
        // 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;
            }

            var nd = yaml.ToDictionary();

            // Load players
            foreach (var my in nd["Players"].ToDictionary().Values)
            {
                var player = new PlayerReference(my);
                Players.Add(player.Name, player);
            }

            Actors = Exts.Lazy(() =>
            {
                var ret = new Dictionary <string, ActorReference>();
                foreach (var kv in nd["Actors"].ToDictionary())
                {
                    ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary()));
                }
                return(ret);
            });

            // Smudges
            Smudges = Exts.Lazy(() =>
            {
                var ret = new List <SmudgeReference>();
                foreach (var name in nd["Smudges"].ToDictionary().Keys)
                {
                    var vals = name.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");

            MapTiles     = Exts.Lazy(() => LoadMapTiles());
            MapResources = Exts.Lazy(() => LoadResourceTiles());
            TileShape    = Game.modData.Manifest.TileShape;

            // 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();
        }
Exemple #4
0
        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)));
            });

            // 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);
            }
        }
Exemple #5
0
        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(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(new BooleanExpression(value));
                    }
                    catch (InvalidDataException e)
                    {
                        throw new YamlException(e.Message);
                    }
                }

                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(IntegerExpression))
            {
                if (value != null)
                {
                    try
                    {
                        return(new IntegerExpression(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.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 <>))
            {
                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);
                    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(Bits <>))
            {
                if (value != null)
                {
                    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));
                }

                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);
        }
Exemple #6
0
        public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field)
        {
            var value = yaml.Value?.Trim();

            if (fieldType == typeof(int))
            {
                if (Exts.TryParseIntegerInvariant(value, out var res))
                {
                    return(res);
                }
                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(ushort))
            {
                if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res))
                {
                    return(res);
                }
                return(InvalidValueAction(value, fieldType, fieldName));
            }

            if (fieldType == typeof(long))
            {
                if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res))
                {
                    return(res);
                }
                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(float))
            {
                if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res))
                {
                    return(res * (value.Contains('%') ? 0.01f : 1f));
                }
                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(decimal))
            {
                if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var 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))
            {
                if (value != null && Color.TryParse(value, out var color))
                {
                    return(color);
                }

                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(Hotkey))
            {
                if (Hotkey.TryParse(value, out var res))
                {
                    return(res);
                }

                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(HotkeyReference))
            {
                return(Game.ModData.Hotkeys[value]);
            }
            else if (fieldType == typeof(WDist))
            {
                if (WDist.TryParse(value, out var res))
                {
                    return(res);
                }

                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(WVec))
            {
                if (value != null)
                {
                    var parts = value.Split(',');
                    if (parts.Length == 3)
                    {
                        if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var 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)
                    {
                        if (WDist.TryParse(parts[3 * i], out var rx) && WDist.TryParse(parts[3 * i + 1], out var ry) && WDist.TryParse(parts[3 * i + 2], out var 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)
                    {
                        if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var rz))
                        {
                            return(new WPos(rx, ry, rz));
                        }
                    }
                }

                return(InvalidValueAction(value, fieldType, fieldName));
            }
            else if (fieldType == typeof(WAngle))
            {
                if (Exts.TryParseIntegerInvariant(value, out var 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)
                    {
                        if (Exts.TryParseIntegerInvariant(parts[0], out var rr) && Exts.TryParseIntegerInvariant(parts[1], out var rp) && Exts.TryParseIntegerInvariant(parts[2], out var 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++)
                    {
                        if (int.TryParse(parts[2 * i], out var rx) && int.TryParse(parts[2 * i + 1], out var 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(bool))
            {
                if (bool.TryParse(value.ToLowerInvariant(), out var result))
                {
                    return(result);
                }

                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 != 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 <>))
            {
                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;
                    if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var 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.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var x);
                    float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var y);

                    // z component is optional for compatibility with older float2 definitions
                    float z = 0;
                    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 <>))
            {
                if (string.IsNullOrEmpty(value))
                {
                    return(null);
                }

                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))
            {
                if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var 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(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 (int 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));
            }

            UnknownFieldAction("[Type] {0}".F(value), fieldType);
            return(null);
        }
Exemple #8
0
        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");
            ModelSequences = YamlList(yaml, "ModelSequences");
            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");
            Hotkeys        = YamlList(yaml, "Hotkeys");

            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)));
            });

            // 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("PackageFormats"))
            {
                PackageFormats = FieldLoader.GetValue <string[]>("PackageFormats", yaml["PackageFormats"].Value);
            }

            if (yaml.ContainsKey("SoundFormats"))
            {
                SoundFormats = FieldLoader.GetValue <string[]>("SoundFormats", yaml["SoundFormats"].Value);
            }

            if (yaml.ContainsKey("SpriteFormats"))
            {
                SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value);
            }
        }
Exemple #9
0
        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("MaximumTerrainHeight"))
            {
                MaximumTerrainHeight = FieldLoader.GetValue <byte>("MaximumTerrainHeight", yaml["MaximumTerrainHeight"].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);
            }
        }
Exemple #10
0
        // The standard constructor for most purposes
        public Map(string path)
        {
            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;
                }
            }

            // Load players
            foreach (var my in nd["Players"].ToDictionary().Values)
            {
                var player = new PlayerReference(my);
                Players.Add(player.Name, player);
            }

            Actors = Exts.Lazy(() =>
            {
                var ret = new Dictionary <string, ActorReference>();
                foreach (var kv in nd["Actors"].ToDictionary())
                {
                    ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary()));
                }
                return(ret);
            });

            // Smudges
            Smudges = Exts.Lazy(() =>
            {
                var ret = new List <SmudgeReference>();
                foreach (var name in nd["Smudges"].ToDictionary().Keys)
                {
                    var vals = name.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");

            MapTiles     = Exts.Lazy(() => LoadMapTiles());
            MapResources = Exts.Lazy(() => LoadResourceTiles());
            MapHeight    = Exts.Lazy(() => LoadMapHeight());

            TileShape      = Game.ModData.Manifest.TileShape;
            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();
        }
Exemple #11
0
        public Manifest(string mod)
        {
            var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine);
            var yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary();

            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"];

            if (yaml.ContainsKey("ContentInstaller"))
            {
                ContentInstaller = FieldLoader.Load <InstallData>(yaml["ContentInstaller"]);
            }

            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);
            }

            // 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();
        }