Пример #1
0
 public WRange DistanceToEdge(WPos pos, WVec dir)
 {
     var tl = CenterOfCell(Cells.TopLeft) - new WVec(512, 512, 0);
     var br = CenterOfCell(Cells.BottomRight) + new WVec(511, 511, 0);
     var x = dir.X == 0 ? int.MaxValue : ((dir.X < 0 ? tl.X : br.X) - pos.X) / dir.X;
     var y = dir.Y == 0 ? int.MaxValue : ((dir.Y < 0 ? tl.Y : br.Y) - pos.Y) / dir.Y;
     return new WRange(Math.Min(x, y) * dir.Length);
 }
Пример #2
0
 public static WVec Lerp(WVec a, WVec b, int mul, int div)
 {
     return a + (b - a) * mul / div;
 }
Пример #3
0
        public static WVec LerpQuadratic(WVec a, WVec b, WAngle pitch, int mul, int div)
        {
            // Start with a linear lerp between the points
            var ret = Lerp(a, b, mul, div);

            if (pitch.Angle == 0)
                return ret;

            // Add an additional quadratic variation to height
            // Uses fp to avoid integer overflow
            var offset = (int)((float)((float)(b - a).Length*pitch.Tan()*mul*(div - mul)) / (float)(1024*div*div));
            return new WVec(ret.X, ret.Y, ret.Z + offset);
        }
Пример #4
0
 public WDist DistanceToEdge(WPos pos, WVec dir)
 {
     var projectedPos = pos - new WVec(0, pos.Z, pos.Z);
     var x = dir.X == 0 ? int.MaxValue : ((dir.X < 0 ? ProjectedTopLeft.X : ProjectedBottomRight.X) - projectedPos.X) / dir.X;
     var y = dir.Y == 0 ? int.MaxValue : ((dir.Y < 0 ? ProjectedTopLeft.Y : ProjectedBottomRight.Y) - projectedPos.Y) / dir.Y;
     return new WDist(Math.Min(x, y) * dir.Length);
 }
Пример #5
0
 public static int Dot(WVec a, WVec b)
 {
     return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
 }
Пример #6
0
 public static CVec ToCVec(this WVec a)
 {
     return(new CVec(a.X / 1024, a.Y / 1024));
 }
Пример #7
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(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))
            {
                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.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 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.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);
        }
Пример #8
0
        public MapGrid(MiniYaml yaml)
        {
            FieldLoader.Load(this, yaml);

            // The default subcell index defaults to the middle entry
            var defaultSubCellIndex = (byte)DefaultSubCell;

            if (defaultSubCellIndex == byte.MaxValue)
            {
                DefaultSubCell = (SubCell)(SubCellOffsets.Length / 2);
            }
            else
            {
                var minSubCellOffset = SubCellOffsets.Length > 1 ? 1 : 0;
                if (defaultSubCellIndex < minSubCellOffset || defaultSubCellIndex >= 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");
                }
            }

            // Rotation axes and amounts for the different slope types
            var southEast = new WVec(724, 724, 0);
            var southWest = new WVec(-724, 724, 0);
            var south     = new WVec(0, 1024, 0);
            var east      = new WVec(1024, 0, 0);

            var forward      = new WAngle(64);
            var backward     = -forward;
            var halfForward  = new WAngle(48);
            var halfBackward = -halfForward;

            // Slope types are hardcoded following the convention from the TS and RA2 map format
            Ramps = new[]
            {
                // Flat
                new CellRamp(Type, WRot.None),

                // Two adjacent corners raised by half a cell
                new CellRamp(Type, new WRot(southEast, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southWest, backward), br: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southEast, forward), tl: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(southWest, forward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half),

                // One corner raised by half a cell
                new CellRamp(Type, new WRot(south, halfBackward), br: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfForward), bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfBackward), tr: RampCornerHeight.Half, split: RampSplit.Y),

                // Three corners raised by half a cell
                new CellRamp(Type, new WRot(south, halfBackward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfForward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, new WRot(east, halfBackward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),

                // Full tile sloped (mid corners raised by half cell, far corner by full cell)
                new CellRamp(Type, new WRot(south, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(east, forward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full),
                new CellRamp(Type, new WRot(south, forward), tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half),
                new CellRamp(Type, new WRot(east, backward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half),

                // Two opposite corners raised by half a cell
                new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
                new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
                new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X),
            };

            TilesByDistance = CreateTilesByDistance();
        }
Пример #9
0
        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);
        }
Пример #10
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 && Color.TryParse(value, out color))
                {
                    return(color);
                }

                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(bool))
            {
                bool result;
                if (bool.TryParse(value.ToLowerInvariant(), out 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;
                    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 <>))
            {
                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))
            {
                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);
        }