Пример #1
0
        /// <summary>
        ///     Write a description of this setting using all available metadata.
        /// </summary>
        public void WriteDescription(StreamWriter writer)
        {
            if (!string.IsNullOrEmpty(Description.Description))
            {
                writer.WriteLine($"## {Description.Description.Replace("\n", "\n## ")}");
            }

            writer.WriteLine("# Setting type: " + SettingType.Name);

            writer.WriteLine("# Default value: " + TomlTypeConverter.ConvertToString(DefaultValue, SettingType));

            if (Description.AcceptableValues != null)
            {
                writer.WriteLine(Description.AcceptableValues.ToDescriptionString());
            }
            else if (SettingType.IsEnum)
            {
                writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(SettingType)));

                if (SettingType.GetCustomAttributes(typeof(FlagsAttribute), true).Any())
                {
                    writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)");
                }
            }
        }
Пример #2
0
        public static string GetEditValue(ICacheEntry field, object value)
        {
            var valueType = field.Type();

            if (valueType == typeof(string))
            {
                return((string)value ?? "");
            }

            var isNull = value.IsNullOrDestroyed();

            if (isNull != null)
            {
                return(isNull);
            }

            var typeConverter = TomlTypeConverter.GetConverter(valueType);

            if (typeConverter != null)
            {
                return(typeConverter.ConvertToString(value, valueType));
            }

            return(ToStringConverter.ObjectToString(value));
        }
Пример #3
0
        internal static void AICSyncAllToOneLegacy(NetworkConnection conn)
        {
            var validInsts = AutoItemConfig.instances.Where(x => !x.allowNetMismatch);
            var serValues  = new List <string>();
            var modnames   = new List <string>();
            var categories = new List <string>();
            var cfgnames   = new List <string>();

            foreach (var i in validInsts)
            {
                serValues.Add(TomlTypeConverter.ConvertToString(i.cachedValue, i.propType));
                modnames.Add(i.modName);
                categories.Add(i.configEntry.Definition.Section);
                cfgnames.Add(i.configEntry.Definition.Key);
            }

            string password = Guid.NewGuid().ToString("d");

            connectionsToCheck.Add(new WaitingConnCheck {
                connection    = conn,
                password      = password,
                timeRemaining = connCheckWaitTime
            });

            instance.TargetAICSyncAllToOneLegacy(conn, password, modnames.ToArray(), categories.ToArray(), cfgnames.ToArray(), serValues.ToArray());
        }
Пример #4
0
    public static void AddUnityEngineConverters()
    {
        var colorConverter = new TypeConverter
        {
            ConvertToString = (obj, type) => ColorUtility.ToHtmlStringRGBA((Color)obj),
            ConvertToObject = (str, type) =>
            {
                if (!ColorUtility.TryParseHtmlString("#" + str.Trim('#', ' '), out var c))
                {
                    throw new FormatException("Invalid color string, expected hex #RRGGBBAA");
                }
                return(c);
            }
        };

        TomlTypeConverter.AddConverter(typeof(Color), colorConverter);

        var jsonConverter = new TypeConverter
        {
            ConvertToString = (obj, type) => JsonUtility.ToJson(obj),
            ConvertToObject = (str, type) => JsonUtility.FromJson(type: type, json: str)
        };

        TomlTypeConverter.AddConverter(typeof(Vector2), jsonConverter);
        TomlTypeConverter.AddConverter(typeof(Vector3), jsonConverter);
        TomlTypeConverter.AddConverter(typeof(Vector4), jsonConverter);
        TomlTypeConverter.AddConverter(typeof(Quaternion), jsonConverter);
    }
}
Пример #5
0
        public ConfigSettingEntry(ConfigEntryBase entry, BepInPlugin meta, ConfigFile configFile)
        {
            Entry = entry;

            DispName    = entry.Definition.Key;
            Category    = entry.Definition.Section;
            Description = entry.Description?.Description;

            var converter = TomlTypeConverter.GetConverter(entry.SettingType);

            if (converter != null)
            {
                ObjToStr = o => converter.ConvertToString(o, entry.SettingType);
                StrToObj = s => converter.ConvertToObject(s, entry.SettingType);
            }

            var values = entry.Description?.AcceptableValues;

            if (values != null)
            {
                GetAcceptableValues(values);
            }

            DefaultValue = entry.DefaultValue;

            SetFromAttributes(entry.Description?.Tags, meta, configFile);
        }
Пример #6
0
        private int CliAICSyncLegacy(string modname, string category, string cfgname, string value, bool silent)
        {
            var exactMatches = AutoItemConfig.instances.FindAll(x => {
                return(x.configEntry.Definition.Key == cfgname &&
                       x.configEntry.Definition.Section == category &&
                       x.modName == modname);
            });

            if (exactMatches.Count > 1)
            {
                TILER2Plugin._logger.LogError("(Server requesting update, LEGACY CHECK) There are multiple config entries with the path \"" + modname + "/" + category + "/" + cfgname + "\"; this should never happen! Please report this as a bug.");
                return(-1);
            }
            else if (exactMatches.Count == 0)
            {
                TILER2Plugin._logger.LogError("(LEGACY CHECK) The server requested an update for a nonexistent config entry with the path \"" + modname + "/" + category + "/" + cfgname + "\". Make sure you're using the same mods AND mod versions as the server!");
                return(-1);
            }

            var newVal = TomlTypeConverter.ConvertToValue(value, exactMatches[0].propType);

            if (!exactMatches[0].cachedValue.Equals(newVal))
            {
                if (exactMatches[0].netMismatchCritical)
                {
                    TILER2Plugin._logger.LogError("(LEGACY CHECK) CRITICAL MISMATCH on \"" + modname + "/" + category + "/" + cfgname + "\": Requested " + newVal.ToString() + " vs current " + exactMatches[0].cachedValue.ToString());
                    return(-2);
                }
                exactMatches[0].OverrideProperty(newVal, silent);
                return(1);
            }
            return(0);
        }
Пример #7
0
        public static bool CanEditValue(ICacheEntry field, object value)
        {
            var valueType = field.Type();

            if (valueType == typeof(string))
            {
                return(true);
            }

            if (_canCovertCache.ContainsKey(valueType))
            {
                return(_canCovertCache[valueType]);
            }

            if (TomlTypeConverter.GetConverter(valueType) != null)
            {
                _canCovertCache[valueType] = true;
                return(true);
            }

            try
            {
                var converted = ToStringConverter.ObjectToString(value);
                var _         = Convert.ChangeType(converted, valueType);
                _canCovertCache[valueType] = true;
                return(true);
            }
            catch
            {
                _canCovertCache[valueType] = false;
                return(false);
            }
        }
Пример #8
0
        private static void AICSet(ConCommandArgs args, bool isTemporary)
        {
            var targetCmd = isTemporary ? "aic_settemp" : "aic_set";

            var errorPre  = "ConCmd " + targetCmd + " failed (";
            var usagePost = ").\nUsage: " + targetCmd + " \"path1\" \"optional path2\" \"optional path3\" newValue. Path matches mod name, config category, and config name, in that order.";

            if (args.Count < 2)
            {
                NetConfigOrchestrator.SendConMsg(args.sender, errorPre + "not enough arguments" + usagePost, LogLevel.Warning);
                return;
            }
            if (args.Count > 4)
            {
                NetConfigOrchestrator.SendConMsg(args.sender, errorPre + "too many arguments" + usagePost, LogLevel.Warning);
                return;
            }

            var(matches, errmsg) = GetAICFromPath(args[0], (args.Count > 2) ? args[1] : null, (args.Count > 3) ? args[2] : null);

            if (errmsg != null)
            {
                errmsg += ").";
                if (matches != null)
                {
                    errmsg += "\nThe following config settings have a matching path: " + String.Join(", ", matches.Select(x => "\"" + x.readablePath + "\""));
                }
                NetConfigOrchestrator.SendConMsg(args.sender, errorPre + errmsg, LogLevel.Warning);
                return;
            }

            var convStr = args[args.Count - 1];

            object convObj;

            try {
                convObj = TomlTypeConverter.ConvertToValue(convStr, matches[0].propType);
            } catch {
                NetConfigOrchestrator.SendConMsg(args.sender, errorPre + "(can't convert argument 2 'newValue' to the target config type, " + matches[0].propType.Name + ").", LogLevel.Warning);
                return;
            }

            if (!isTemporary)
            {
                matches[0].configEntry.BoxedValue = convObj;
                if (!matches[0].configEntry.ConfigFile.SaveOnConfigSet)
                {
                    matches[0].configEntry.ConfigFile.Save();
                }
            }
            else
            {
                matches[0].OverrideProperty(convObj);
            }
            if (args.sender && !args.sender.hasAuthority)
            {
                TILER2Plugin._logger.LogMessage("ConCmd " + targetCmd + " from client " + args.sender.userName + " passed. Changed config setting " + matches[0].readablePath + " to " + convObj.ToString());
            }
            NetConfigOrchestrator.SendConMsg(args.sender, "ConCmd " + targetCmd + " successfully updated config entry!");
        }
Пример #9
0
 static KeyboardShortcut()
 {
     TomlTypeConverter.AddConverter(
         typeof(KeyboardShortcut),
         new TypeConverter
     {
         ConvertToString = (o, type) => ((KeyboardShortcut)o).Serialize(),
         ConvertToObject = (s, type) => Deserialize(s)
     });
 }
Пример #10
0
 private static void BuildTypeIndexMap()
 {
     typeIndexMap = new Dictionary <Type, string>();
     indexTypeMap = new Dictionary <string, Type>();
     foreach (Type t in TomlTypeConverter.GetSupportedTypes())
     {
         typeIndexMap[t] = t.AssemblyQualifiedName;
         indexTypeMap[t.AssemblyQualifiedName] = t;
     }
 }
Пример #11
0
        private static void DrawColor(ICacheEntry obj, object value)
        {
            var setting = (Color)value;

            if (!_colorCache.TryGetValue(obj, out var cacheEntry))
            {
                cacheEntry = new ColorCacheEntry {
                    Tex = new Texture2D(14, 14, TextureFormat.ARGB32, false), Last = setting
                };
                cacheEntry.Tex.FillTexture(setting);
                _colorCache[obj] = cacheEntry;
            }

            GUILayout.Label("R", GUILayout.ExpandWidth(false));
            setting.r = GUILayout.HorizontalSlider(setting.r, 0f, 1f, GUILayout.ExpandWidth(true));
            GUILayout.Label("G", GUILayout.ExpandWidth(false));
            setting.g = GUILayout.HorizontalSlider(setting.g, 0f, 1f, GUILayout.ExpandWidth(true));
            GUILayout.Label("B", GUILayout.ExpandWidth(false));
            setting.b = GUILayout.HorizontalSlider(setting.b, 0f, 1f, GUILayout.ExpandWidth(true));
            GUILayout.Label("A", GUILayout.ExpandWidth(false));
            setting.a = GUILayout.HorizontalSlider(setting.a, 0f, 1f, GUILayout.ExpandWidth(true));

            GUILayout.Space(4);

            GUI.changed = false;
            var isBeingEdited = _currentlyEditingTag == obj;
            var text          = isBeingEdited ? _currentlyEditingText : TomlTypeConverter.ConvertToString(setting, typeof(Color));

            text = GUILayout.TextField(text, GUILayout.Width(75));
            if (GUI.changed && !text.Equals(TomlTypeConverter.ConvertToString(setting, typeof(Color))) || isBeingEdited)
            {
                if (_userHasHitReturn)
                {
                    _currentlyEditingTag = null;
                    _userHasHitReturn    = false;

                    try { obj.SetValue(TomlTypeConverter.ConvertToValue <Color>(text)); }
                    catch { }
                }
                else
                {
                    _currentlyEditingText = text;
                    _currentlyEditingTag  = obj;
                }
            }

            if (setting != cacheEntry.Last)
            {
                obj.SetValue(setting);
                cacheEntry.Tex.FillTexture(setting);
                cacheEntry.Last = setting;
            }

            GUILayout.Label(cacheEntry.Tex, GUILayout.ExpandWidth(false));
        }
Пример #12
0
        public static void Init()
        {
            TypeConverter converter = new TypeConverter
            {
                ConvertToString = ((object obj, Type type) => JsonConvert.SerializeObject(obj)),
                ConvertToObject = ((string str, Type type) => JsonConvert.DeserializeObject(str, type))
            };

            TomlTypeConverter.AddConverter(typeof(int[]), converter);
            TomlTypeConverter.AddConverter(typeof(bool[]), converter);
        }
Пример #13
0
 public void SetSerializedValue(string value)
 {
     try
     {
         object tmp = (_serverValue = TomlTypeConverter.ConvertToValue(value, BaseEntry.SettingType));
         _didError = false;
     }
     catch (Exception ex)
     {
         Config.Logger.LogWarning($"Config value of setting \"{BaseEntry.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
     }
 }
Пример #14
0
 internal void ServerAICSyncOneToAll(AutoConfigBinding targetConfig, object newValue)
 {
     foreach (var user in NetworkUser.readOnlyInstancesList)
     {
         if (user.hasAuthority || (user.connectionToClient != null && Util.ConnectionIsLocal(user.connectionToClient)))
         {
             continue;
         }
         TargetAICSyncOneToAll(user.connectionToClient, targetConfig.modName, targetConfig.configEntry.Definition.Section, targetConfig.configEntry.Definition.Key,
                               TomlTypeConverter.ConvertToString(newValue, targetConfig.propType));
     }
 }
Пример #15
0
 /// <summary>
 ///     Set the value by using its serialized form.
 /// </summary>
 public void SetSerializedValue(string value)
 {
     try
     {
         var newValue = TomlTypeConverter.ConvertToValue(value, SettingType);
         BoxedValue = newValue;
     }
     catch (Exception e)
     {
         Logger.Log(LogLevel.Warning,
                    $"Config value of setting \"{Definition}\" could not be parsed and will be ignored. Reason: {e.Message}; Value: {value}");
     }
 }
Пример #16
0
        void Awake()
        {
            StaticLogger = Logger;

            TomlTypeConverter.AddConverter(typeof(ToggleableFloat), new TypeConverter
            {
                ConvertToObject = (str, type) =>
                {
                    var match = Regex.Match(str, @"\s*\[(false|true),\s*([\d.eE-])+", RegexOptions.IgnoreCase);

                    if (!match.Success)
                    {
                        throw new Exception("Invalid format. Expected '[bool, float]'");
                    }

                    var enabled = match.Groups[1].Value.ToLower() == "true";

                    return(new ToggleableFloat(enabled, float.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture)));
                },
                ConvertToString = (obj, type) =>
                {
                    var val = (ToggleableFloat)obj;
                    return("[" + val.enabled + ", " + val.value.ToString(CultureInfo.InvariantCulture) + "]");
                }
            });

            configEnabled = Config.Bind("General", "Enabled", true, new ConfigDescription("Enable/Disable all Cheats at once", null, new ConfigurationManagerAttributes {
                Category = "", Order = 100
            }));

            configInfiniteAmmo = Config.Bind("General", "Infinite Ammo", false, new ConfigDescription("Infinite Ammo", null, new ConfigurationManagerAttributes {
                Category = "", Order = 99
            }));

            configEnableCheats   = Config.Bind("1. Cheats and Dev options", "Enable Cheats", false);
            configEnableDev      = Config.Bind("1. Cheats and Dev options", "Enable Dev Options", false);
            configEnableDevExtra = Config.Bind("1. Cheats and Dev options", "Enable Extra Dev Options", false);

            configCorpseKnockoutRange = Config.BindToggleableFloat("3. Corpse Throwing", "Knockout Range", new ToggleableFloat(false, 2));
            configMultiKnockOut       = Config.Bind("3. Corpse Throwing", "Allow throws to knockout multiple enemies", false);

            Commands.Bind(Config);

            overrides = new Overrides(Config);

            harmony = Harmony.CreateAndPatchAll(typeof(Hooks));

            OnSettingsChanged();

            Config.SettingChanged += (_, __) => OnSettingsChanged();
        }
Пример #17
0
            internal static ConfigOption Read(NetworkReader reader)
            {
                var typeString = reader.ReadString();
                var objString  = reader.ReadString();
                var type       = GetIndexType(typeString);

                if (type == null)
                {
                    return(new ConfigOption(typeof(int), -999));
                }
                var obj = TomlTypeConverter.GetConverter(type).ConvertToObject(objString, type);

                return(new ConfigOption(type, obj));
            }
Пример #18
0
        public static void SetEditValue(ICacheEntry field, object value, string result)
        {
            var    valueType = field.Type();
            object converted;

            if (valueType == typeof(string))
            {
                converted = result;
            }
            else
            {
                var typeConverter = TomlTypeConverter.GetConverter(valueType);
                converted = typeConverter != null?typeConverter.ConvertToObject(result, valueType) : Convert.ChangeType(result, valueType);
            }

            if (!Equals(converted, value))
            {
                field.SetValue(converted);
            }
        }
Пример #19
0
            internal bool Matches(ConfigOption option)
            {
                if (this.type != option.type)
                {
                    return(false);
                }
                string val1 = null;
                string val2 = null;

                try {
                    val1 = TomlTypeConverter.GetConverter(this.type).ConvertToString(this.value, this.type);
                    val2 = TomlTypeConverter.GetConverter(option.type).ConvertToString(option.value, option.type);
                } catch {
                    return(false);
                }
                if (val1 != val2)
                {
                    return(false);
                }
                return(true);
            }
Пример #20
0
 public static bool MyWriteDescription(ref ConfigEntryBase __instance, ref StreamWriter writer)
 {
     if (__instance.ConfigFile == configFile)
     {
         if (!typeStr.TryGetValue(__instance.SettingType, out string TypeName))
         {
             TypeName = __instance.SettingType.Name;
         }
         string TypeDescription = TypeName + ", default: " + TomlTypeConverter.ConvertToString(__instance.DefaultValue, __instance.SettingType);
         if (!string.IsNullOrEmpty(__instance.Description.Description))
         {
             writer.WriteLine("# " + __instance.Description.Description.Replace("\n", "\n# ") + " (" + TypeDescription + ")");
         }
         else
         {
             writer.WriteLine("# " + TypeDescription);
         }
         if (__instance.Description.AcceptableValues != null)
         {
             writer.WriteLine(__instance.Description.AcceptableValues.ToDescriptionString());
         }
         else if (__instance.SettingType.IsEnum)
         {
             writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(__instance.SettingType)));
             if (__instance.SettingType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any())
             {
                 writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)");
             }
         }
         return(false);
     }
     else
     {
         return(true);
     }
 }
Пример #21
0
 internal void Write(NetworkWriter writer)
 {
     writer.Write(GetTypeIndex(this.type));
     writer.Write(TomlTypeConverter.GetConverter(this.type).ConvertToString(this.value, this.type));
 }
Пример #22
0
        public override void Initialize()
        {
            base.Initialize();

            if (mode == GenMode.BepInExConfig)
            {
                ICollection <ConfigDefinition> keys = bepConfig.Keys;
                List <string> sections = new List <string>();
                foreach (ConfigDefinition k in keys)
                {
                    // Debug.Log($"{rwMod.ModID}) {k.Section}: {k.Key}");
                    if (!sections.Contains(k.Section))
                    {
                        sections.Add(k.Section);
                    }
                }
                sections.Sort();

                bool        hasUnsupported = false, hasFirstScroll = false;
                OpScrollBox firstScroll = null;
                Tabs = new OpTab[Mathf.Min(20, sections.Count)];
                for (int t = 0; t < Tabs.Length; t++)
                {
                    Tabs[t] = new OpTab(sections[t]);
                    float h = t != 0 ? 50f : 150f;
                    List <ConfigDefinition> cds = new List <ConfigDefinition>();
                    foreach (ConfigDefinition k in keys)
                    {
                        if (k.Section == sections[t])
                        {
                            cds.Add(k);
                        }
                    }
                    cds.Sort(CompareCDkey);
                    List <UIelement> elms = new List <UIelement>();
                    for (int e = 0; e < cds.Count; e++)
                    {
                        if (TryGetBase(bepConfig, cds[e], out ConfigEntryBase entryBase))
                        {
                            string desc = entryBase.Description.Description; // LoremIpsum.Generate(3, 4);
                            switch (entryBase.SettingType.Name.ToLower())
                            {
                            case "bool":     // OpCheckBox
                            case "boolean":
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <bool> eBool))
                                {
                                    elms.Add(new OpCheckBox(new Vector2(30f, 600f - h - 40f), GenerateKey(cds[e]), (bool)eBool.DefaultValue)
                                    {
                                        description = GetFirstSentence(desc)
                                    });
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(70f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(80f, 600f - h - 80f), new Vector2(500f, 45f), desc));
                                    }
                                    h += 60f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "byte":     //OpSliderSubtle
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <byte> eByte))
                                {
                                    elms.Add(new OpSliderSubtle(new Vector2(30f, 600f - h - 45f), GenerateKey(cds[e]), new IntVector2(0, 20), 240, false, Mathf.Clamp((byte)eByte.DefaultValue, 0, 20))
                                    {
                                        description = GetFirstSentence(desc)
                                    });
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(80f, 600f - h - 90f), new Vector2(500f, 45f), desc));
                                    }
                                    h += 90f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "uint":     //OpSlider
                            case "uint32":
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <uint> eUint))
                                {
                                    elms.Add(new OpSlider(new Vector2(30f, 600f - h - 45f), GenerateKey(cds[e]), new IntVector2(0, 100), 400, false, Mathf.Clamp(Convert.ToInt32((uint)eUint.DefaultValue), 0, 100))
                                    {
                                        description = GetFirstSentence(desc)
                                    });
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(80f, 600f - h - 90f), new Vector2(500f, 45f), desc));
                                    }
                                    h += 90f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "int":     //OpUpdown
                            case "int32":
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <int> eInt))
                                {
                                    elms.Add(new OpUpdown(new Vector2(30f, 600f - h - 45f), 110f, GenerateKey(cds[e]), (int)eInt.DefaultValue)
                                    {
                                        description = GetFirstSentence(desc), allowSpace = true
                                    });
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(160f, 600f - h - 60f), new Vector2(420f, 45f), desc));
                                    }
                                    h += 60f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "float":     //OpUpdown
                            case "single":
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <float> eFloat))
                                {
                                    elms.Add(new OpUpdown(new Vector2(30f, 600f - h - 45f), 110f, GenerateKey(cds[e]), (float)eFloat.DefaultValue, 2)
                                    {
                                        description = GetFirstSentence(desc), allowSpace = true
                                    });
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(160f, 600f - h - 60f), new Vector2(420f, 45f), desc));
                                    }
                                    h += 60f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "string":     //OpTextBox or OpColorPicker
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <string> eString))
                                {
                                    string defaultString = (string)eString.DefaultValue;
                                    if (OpColorPicker.IsStringHexColor(defaultString))
                                    {     //OpColorPicker
                                        elms.Add(new OpColorPicker(new Vector2(30f, 600f - h - 170f), GenerateKey(cds[e]), defaultString));
                                        elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                        {
                                            alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                        });
                                        if (!string.IsNullOrEmpty(desc))
                                        {
                                            elms.Add(new OpLabelLong(new Vector2(200f, 600f - h - 170f), new Vector2(380f, 135f), desc));
                                        }
                                        h += 170f;
                                    }
                                    else
                                    {
                                        elms.Add(new OpTextBox(new Vector2(30f, 600f - h - 45f), 110f, GenerateKey(cds[e]), defaultString, OpTextBox.Accept.StringASCII)
                                        {
                                            description = GetFirstSentence(desc)
                                        });
                                        elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                        {
                                            alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                        });
                                        if (!string.IsNullOrEmpty(desc))
                                        {
                                            elms.Add(new OpLabelLong(new Vector2(160f, 600f - h - 60f), new Vector2(420f, 45f), desc));
                                        }
                                        h += 60f;
                                    }
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case "keycode":     //OpKeyBinder
                                if (bepConfig.TryGetEntry(cds[e], out ConfigEntry <KeyCode> eKeyCode))
                                {
                                    elms.Add(new OpKeyBinder(new Vector2(30f, 600f - h - 50f), new Vector2(150f, 30f), rwMod.ModID, GenerateKey(cds[e]), ((KeyCode)eKeyCode.DefaultValue).ToString(), false));
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(200f, 600f - h - 90f), new Vector2(380f, 75f), desc));
                                    }
                                    h += 100f;
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            default:
                                // if type is enum => OpComboBox
                                if (entryBase.SettingType.IsEnum)
                                {
                                    elms.Add(new OpResourceSelector(new Vector2(30f, 600f - h - 45f), 120f, GenerateKey(cds[e]), entryBase.SettingType, entryBase.DefaultValue.ToString()));
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(160f, 600f - h - 60f), new Vector2(420f, 45f), desc));
                                    }
                                    h += 60f;
                                    break;
                                }

                                if (TryAcceptableValueList(entryBase.Description.AcceptableValues,
                                                           out var valueType, out var values))
                                {
                                    var items = new List <ListItem>();
                                    for (var i = 0; i < values.Length; i++)
                                    {
                                        var value = values[i];
                                        var name  = TomlTypeConverter.ConvertToString(value, valueType);
                                        var item  = new ListItem(name, i)
                                        {
                                            displayName = value.ToString()
                                        };
                                        items.Add(item);
                                    }

                                    elms.Add(new OpComboBox(new Vector2(30f, 600f - h - 45f), 120f, GenerateKey(cds[e]), items, TomlTypeConverter.ConvertToString(entryBase.DefaultValue, valueType)));
                                    elms.Add(new OpLabel(new Vector2(20f, 600f - h - 15f), new Vector2(120f, 15f), cds[e].Key)
                                    {
                                        alignment = FLabelAlignment.Left, description = GetFirstSentence(desc), bumpBehav = (elms[elms.Count - 1] as UIconfig).bumpBehav
                                    });
                                    if (!string.IsNullOrEmpty(desc))
                                    {
                                        elms.Add(new OpLabelLong(new Vector2(160f, 600f - h - 60f), new Vector2(420f, 45f), desc));
                                    }
                                    h += 60f;
                                    break;
                                }

                                Debug.Log($"{rwMod.ModID} has unsupported ConfigEntry: {cds[e].Key}({entryBase.SettingType.Name})");
                                hasUnsupported = true; continue; // Not supported
                            }
                            h += 20f;                            // between gap
                        }
                    }
                    if (h <= 600f)
                    {
                        if (t == 0)
                        {
                            AddBasicProfile(Tabs[0], rwMod); hasFirstScroll = false;
                        }
                        Tabs[t].AddItems(elms.ToArray());
                    }
                    else
                    {
                        OpScrollBox box = new OpScrollBox(Tabs[t], h);
                        if (t == 0)
                        {
                            AddBasicProfile(box, rwMod); hasFirstScroll = true; firstScroll = box;
                        }
                        foreach (UIelement elm in elms)
                        {
                            elm.pos = new Vector2(elm.GetPos().x, elm.GetPos().y - 600f + h);
                        }
                        box.AddItems(elms.ToArray());
                    }
                }
                if (hasUnsupported)
                {
                    string warn = InternalTranslator.Translate("This Plugin contains types of settings that are not supported by Config Machine:") + Environment.NewLine
                                  + InternalTranslator.Translate("Go to [BepInEx]-[config] folder and use Notepad to edit those settings.");
                    if (hasFirstScroll)
                    {
                        firstScroll.AddItems(new OpLabel(new Vector2(50f, firstScroll.GetContentSize() - 600f + 525f), new Vector2(500f, 30f), warn));
                    }
                    else
                    {
                        Tabs[0].AddItems(new OpLabel(new Vector2(50f, 525f), new Vector2(500f, 20f), warn));
                    }
                }
            }
            else
            {
                Tabs    = new OpTab[1];
                Tabs[0] = new OpTab();
                AddBasicProfile(Tabs[0], rwMod);
                if (!string.IsNullOrEmpty(modDescription))
                {
                    Tabs[0].AddItems(new OpLabelLong(new Vector2(50f, 200f), new Vector2(500f, 250f), modDescription, alignment: FLabelAlignment.Center));
                }
            }
        }
Пример #23
0
 /// <summary>
 ///     Get the serialized representation of the value.
 /// </summary>
 public string GetSerializedValue() => TomlTypeConverter.ConvertToString(BoxedValue, SettingType);
Пример #24
0
        /// <summary>Binds a property to a BepInEx config file, using reflection and attributes to automatically generate much of the necessary information.</summary>
        public void Bind(PropertyInfo prop, ConfigFile cfl, string modName, string categoryName, AutoItemConfigAttribute attrib, AutoUpdateEventInfoAttribute eiattr = null, BindSubDictInfo?subDict = null)
        {
            string errorStr = "AutoItemCfg.Bind on property " + prop.Name + " in category " + categoryName + " failed: ";

            if (!subDict.HasValue)
            {
                if (this.autoItemConfigs.Exists(x => x.boundProperty == prop))
                {
                    TILER2Plugin._logger.LogError(errorStr + "this property has already been bound.");
                    return;
                }
                if ((attrib.flags & AutoItemConfigFlags.BindDict) == AutoItemConfigFlags.BindDict)
                {
                    if (!prop.PropertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary <,>)))
                    {
                        TILER2Plugin._logger.LogError(errorStr + "BindDict flag cannot be used on property types which don't implement IDictionary.");
                        return;
                    }
                    var kTyp = prop.PropertyType.GetGenericArguments()[1];
                    if (attrib.avb != null && attrib.avbType != kTyp)
                    {
                        TILER2Plugin._logger.LogError(errorStr + "dict value and AcceptableValue types must match (received " + kTyp.Name + " and " + attrib.avbType.Name + ").");
                        return;
                    }
                    if (!TomlTypeConverter.CanConvert(kTyp))
                    {
                        TILER2Plugin._logger.LogError(errorStr + "dict value type cannot be converted by BepInEx.Configuration.TomlTypeConverter (received " + kTyp.Name + ").");
                        return;
                    }
                    var idict = (System.Collections.IDictionary)prop.GetValue(this, null);
                    int ind   = 0;
                    var dkeys = (from object k in idict.Keys
                                 select k).ToList();
                    foreach (object o in dkeys)
                    {
                        Bind(prop, cfl, modName, categoryName, attrib, eiattr, new BindSubDictInfo {
                            key = o, val = idict[o], keyType = kTyp, index = ind
                        });
                        ind++;
                    }
                    return;
                }
            }
            if (!subDict.HasValue)
            {
                if (attrib.avb != null && attrib.avbType != prop.PropertyType)
                {
                    TILER2Plugin._logger.LogError(errorStr + "property and AcceptableValue types must match (received " + prop.PropertyType.Name + " and " + attrib.avbType.Name + ").");
                    return;
                }
                if (!TomlTypeConverter.CanConvert(prop.PropertyType))
                {
                    TILER2Plugin._logger.LogError(errorStr + "property type cannot be converted by BepInEx.Configuration.TomlTypeConverter (received " + prop.PropertyType.Name + ").");
                    return;
                }
            }

            object propObj    = subDict.HasValue ? prop.GetValue(this) : this;
            var    dict       = subDict.HasValue ? (System.Collections.IDictionary)propObj : null;
            var    propGetter = subDict.HasValue ? dict.GetType().GetProperty("Item").GetGetMethod(true)
                : (prop.GetGetMethod(true) ?? prop.DeclaringType.GetProperty(prop.Name)?.GetGetMethod(true));
            var propSetter = subDict.HasValue ? dict.GetType().GetProperty("Item").GetSetMethod(true)
                : (prop.GetSetMethod(true) ?? prop.DeclaringType.GetProperty(prop.Name)?.GetSetMethod(true));
            var propType = subDict.HasValue ? subDict.Value.keyType : prop.PropertyType;

            if (propGetter == null || propSetter == null)
            {
                TILER2Plugin._logger.LogError(errorStr + "property (or IDictionary Item property, if using BindDict flag) must have both a getter and a setter.");
                return;
            }

            string cfgName = attrib.name;

            if (cfgName != null)
            {
                cfgName = ReplaceTags(cfgName, prop, categoryName, subDict);
            }
            else
            {
                cfgName = char.ToUpperInvariant(prop.Name[0]) + prop.Name.Substring(1) + (subDict.HasValue ? ":" + subDict.Value.index : "");
            }

            string cfgDesc = attrib.desc;

            if (cfgDesc != null)
            {
                cfgDesc = ReplaceTags(cfgDesc, prop, categoryName, subDict);
            }
            else
            {
                cfgDesc = "Automatically generated from a C# " + (subDict.HasValue ? "dictionary " : "") + "property.";
            }

            //Matches ConfigFile.Bind<T>(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription)
            var genm = typeof(ConfigFile).GetMethods().First(
                x => x.Name == nameof(ConfigFile.Bind) &&
                x.GetParameters().Length == 3 &&
                x.GetParameters()[0].ParameterType == typeof(ConfigDefinition) &&
                x.GetParameters()[2].ParameterType == typeof(ConfigDescription)
                ).MakeGenericMethod(propType);

            var propValue = subDict.HasValue ? subDict.Value.val : prop.GetValue(this);

            bool allowMismatch = (attrib.flags & AutoItemConfigFlags.PreventNetMismatch) != AutoItemConfigFlags.PreventNetMismatch;
            bool deferForever  = (attrib.flags & AutoItemConfigFlags.DeferForever) == AutoItemConfigFlags.DeferForever;
            bool deferRun      = (attrib.flags & AutoItemConfigFlags.DeferUntilEndGame) == AutoItemConfigFlags.DeferUntilEndGame;
            bool deferStage    = (attrib.flags & AutoItemConfigFlags.DeferUntilNextStage) == AutoItemConfigFlags.DeferUntilNextStage;
            bool allowCon      = (attrib.flags & AutoItemConfigFlags.PreventConCmd) != AutoItemConfigFlags.PreventConCmd;

            if (deferForever && !allowMismatch)
            {
                cfgDesc += "\nWARNING: THIS SETTING CANNOT BE CHANGED WHILE THE GAME IS RUNNING, AND MUST BE SYNCED MANUALLY FOR MULTIPLAYER!";
            }

            var cfe = (ConfigEntryBase)genm.Invoke(cfl, new[] {
                new ConfigDefinition(categoryName, cfgName),
                propValue,
                new ConfigDescription(cfgDesc, attrib.avb)
            });

            observedFiles[cfl] = System.IO.File.GetLastWriteTime(cfl.ConfigFilePath);

            var newAIC = new AutoItemConfig {
                boundProperty       = prop,
                allowConCmd         = allowCon && !deferForever && !deferRun,
                allowNetMismatch    = allowMismatch,
                netMismatchCritical = !allowMismatch && deferForever,
                deferType           = deferForever ? 3 : (deferRun ? 2 : (deferStage ? 1 : 0)),
                configEntry         = cfe,
                modName             = modName,
                owner                = this,
                propGetter           = propGetter,
                propSetter           = propSetter,
                propType             = propType,
                onDict               = subDict.HasValue,
                boundKey             = subDict.HasValue ? subDict.Value.key : null,
                updateEventAttribute = eiattr,
                cachedValue          = propValue,
                target               = propObj
            };

            this.autoItemConfigs.Add(newAIC);

            if (!deferForever)
            {
                var gtyp = typeof(ConfigEntry <>).MakeGenericType(propType);
                var evh  = gtyp.GetEvent("SettingChanged");

                evh.ReflAddEventHandler(cfe, (object obj, EventArgs evtArgs) => {
                    newAIC.UpdateProperty(cfe.BoxedValue);
                });
            }

            if ((attrib.flags & AutoItemConfigFlags.NoInitialRead) != AutoItemConfigFlags.NoInitialRead)
            {
                propSetter.Invoke(propObj, subDict.HasValue ? new[] { subDict.Value.key, cfe.BoxedValue } : new[] { cfe.BoxedValue });
                newAIC.cachedValue = cfe.BoxedValue;
            }
        }
Пример #25
0
        public Plugin()
        {
            Logger.LogDebug("Binding configs...");
            {
                TomlTypeConverter.AddConverter(typeof(IPAddress), new TypeConverter
                {
                    ConvertToObject = (raw, type) => IPAddress.Parse(raw),
                    ConvertToString = (value, type) => ((IPAddress)value).ToString()
                });

                _config = new RootConfig(Config);
            }

            Logger.LogDebug("Initializing utilities...");
            {
                _version = new Version(VERSION);
                _rng     = RandomNumberGenerator.Create();

                _clientLog  = BepInEx.Logging.Logger.CreateLogSource(NAME + "-CL");
                _serverLog  = BepInEx.Logging.Logger.CreateLogSource(NAME + "-SV");
                _discordLog = BepInEx.Logging.Logger.CreateLogSource(NAME + "-DC");
            }

            Logger.LogDebug("Initializing Discord game SDK...");
            {
                LoadLibrary("BepInEx\\plugins\\H3MP\\" + Discord.Constants.DllName + ".dll");

                DiscordClient = new Discord.Discord(DISCORD_APP_ID, (ulong)CreateFlags.Default);
                DiscordClient.SetLogHook(Discord.LogLevel.Debug, (level, message) =>
                {
                    switch (level)
                    {
                    case Discord.LogLevel.Error:
                        _discordLog.LogError(message);
                        break;

                    case Discord.LogLevel.Warn:
                        _discordLog.LogWarning(message);
                        break;

                    case Discord.LogLevel.Info:
                        _discordLog.LogInfo(message);
                        break;

                    case Discord.LogLevel.Debug:
                        _discordLog.LogDebug(message);
                        break;

                    default:
                        throw new NotImplementedException(level.ToString());
                    }
                });

                ActivityManager = DiscordClient.GetActivityManager();
                Activity        = new StatefulActivity(ActivityManager, DiscordCallbackHandler);

                ActivityManager.RegisterSteam(STEAM_APP_ID);

                ActivityManager.OnActivityJoinRequest += OnJoinRequested;
                ActivityManager.OnActivityJoin        += OnJoin;
            }

            Logger.LogDebug("Creating message table...");
            {
                _messages = new UniversalMessageList <H3Client, H3Server>(_clientLog, _serverLog)
                            // =======
                            // Client
                            // =======
                            // Time synchronization (reliable adds latency)
                            .AddClient <PingMessage>(0, DeliveryMethod.Sequenced, H3Server.OnClientPing)
                            // Player movement
                            .AddClient <Timestamped <PlayerTransformsMessage> >(1, DeliveryMethod.Sequenced, H3Server.OnPlayerMove)
                            // Asset management
                            .AddClient <LevelChangeMessage>(2, DeliveryMethod.ReliableOrdered, H3Server.OnLevelChange)
                            //
                            // =======
                            // Server
                            // =======
                            // Time synchronization (reliable adds latency)
                            .AddServer <Timestamped <PingMessage> >(0, DeliveryMethod.Sequenced, H3Client.OnServerPong)
                            // Player movement
                            .AddServer <PlayerMovesMessage>(1, DeliveryMethod.Sequenced, H3Client.OnPlayersMove)
                            // Asset management
                            .AddServer <InitMessage>(2, DeliveryMethod.ReliableOrdered, H3Client.OnInit)
                            .AddServer <LevelChangeMessage>(2, DeliveryMethod.ReliableOrdered, H3Client.OnLevelChange)
                            .AddServer <PlayerJoinMessage>(2, DeliveryMethod.ReliableOrdered, H3Client.OnPlayerJoin)
                            .AddServer <PlayerLeaveMessage>(2, DeliveryMethod.ReliableOrdered, H3Client.OnPlayerLeave)
                ;
            }

            Logger.LogDebug("Initializing shared Harmony state...");
            HarmonyState.Init(Activity);

            Logger.LogDebug("Hooking into sceneLoaded...");
            _changelogPanel = new ChangelogPanel(Logger, StartCoroutine, _version);
        }