/// <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)"); } } }
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)); }
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()); }
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); } }
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); }
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); }
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); } }
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!"); }
static KeyboardShortcut() { TomlTypeConverter.AddConverter( typeof(KeyboardShortcut), new TypeConverter { ConvertToString = (o, type) => ((KeyboardShortcut)o).Serialize(), ConvertToObject = (s, type) => Deserialize(s) }); }
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; } }
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)); }
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); }
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}"); } }
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)); } }
/// <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}"); } }
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(); }
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)); }
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); } }
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); }
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); } }
internal void Write(NetworkWriter writer) { writer.Write(GetTypeIndex(this.type)); writer.Write(TomlTypeConverter.GetConverter(this.type).ConvertToString(this.value, this.type)); }
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)); } } }
/// <summary> /// Get the serialized representation of the value. /// </summary> public string GetSerializedValue() => TomlTypeConverter.ConvertToString(BoxedValue, SettingType);
/// <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; } }
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); }