/// <summary> /// Checks whether the patch is valid for current game's version. /// </summary> /// <param name="patchType">Type of the patching method.</param> /// <param name="showDebuggingMessage">Whether to show debugging message in logs.</param> /// <returns>Patch's current availability in <see cref="bool"/>.</returns> public static bool IsValidPatch(Type patchType, bool showDebuggingMessage = false) { showDebuggingMessage = true; var patchAttr = patchType.GetCustomAttribute <SafePatchAttribute>(); if (patchAttr == null) { if (showDebuggingMessage) { ADOLib.Log($"Patch Type {patchType.FullName} is invalid! - no SafePatch attribute found!\n"); } return(false); } var classType = patchAttr.Assembly.GetType(patchAttr.ClassName); if ((patchAttr.MinVersion <= ADOLib.RELEASE_NUMBER_FIELD || patchAttr.MinVersion == -1) && (patchAttr.MaxVersion >= ADOLib.RELEASE_NUMBER_FIELD || patchAttr.MaxVersion == -1) && classType != null) { return(true); } if (showDebuggingMessage) { ADOLib.Log($"Patch {patchAttr.PatchId} is invalid! - Specific criteria check:\n" + $"Metadata.MinVersion <= ADOLib.RELEASE_NUMBER_FIELD ({patchAttr.MinVersion} <= {ADOLib.RELEASE_NUMBER_FIELD}) is {patchAttr.MinVersion <= ADOLib.RELEASE_NUMBER_FIELD}\n" + $"Metadata.MinVersion <= ADOLib.RELEASE_NUMBER_FIELD ({patchAttr.MaxVersion} >= {ADOLib.RELEASE_NUMBER_FIELD}) is {patchAttr.MaxVersion >= ADOLib.RELEASE_NUMBER_FIELD || patchAttr.MaxVersion == -1}\n" + $"ClassType is {classType}\n" + $"PatchType is {patchType}\n", LogType.Warning); } return(false); }
public static void PatchCategory(this HarmonyLib.Harmony harmony, Type type) { ADOLib.Log($"Patching category {type}"); var patchAttr = type.GetCustomAttribute <CategoryAttribute>(); if (!patchAttr.isValid) { ADOLib.Log($"{type} is not valid for this ADOFAI version", LogType.Warning); return; } var patchClass = patchAttr.PatchClass; if (patchClass == null) { ADOLib.Log($"No patch class found in category {type}", LogType.Warning); return; } var patches = patchClass.GetNestedTypes(AccessTools.all).Where(t => t.GetCustomAttribute <SafePatchAttribute>() != null); foreach (var p in patches) { harmony.SafePatch(p); } ADOLib.Log($"Successfully patched category {type}", LogType.Success); }
/// <summary> /// Unpatches patch. /// </summary> public static void SafeUnpatch(this HarmonyLib.Harmony harmony, Type patchType) { var metadata = patchType.GetCustomAttribute <SafePatchAttribute>(); if (metadata == null) { ADOLib.Log($"Type {patchType} doesn't have SafePatch attribute."); return; } ADOLib.Log($"Unpatching {metadata.PatchId}"); if (!metadata.IsEnabled) { ADOLib.Log($"{metadata.PatchId} is not patched!", LogType.Warning); return; } var classType = metadata.Assembly.GetType(metadata.ClassName); if (classType == null) { ADOLib.Log($"Type {metadata.ClassName} not found in assembly {metadata.Assembly}."); return; } var original = metadata.info.method; foreach (var patch in patchType.GetMethods()) { harmony.Unpatch(original, patch); } metadata.IsEnabled = false; ADOLib.Log($"Successfully unpatched {metadata.PatchId}", LogType.Success); }
/// <summary> /// Get instance of the <see cref="Category"/>. /// </summary> /// <param name="type">Category type to get the instance.</param> /// <returns>Instance of the input Category. </returns> public static Category GetCategory(Type type) { if (Categories.ContainsKey(type)) { return(Categories[type]); } if (!(Activator.CreateInstance(type) is Category category)) { ADOLib.Log($"Type {type} is not a category!", LogType.Error); return(null); } var mod = category.Mod; var path = category.XmlPath; if (File.Exists(path)) { try { using FileStream fileStream = File.OpenRead(path); Categories[type] = (Category) new XmlSerializer(type).Deserialize(fileStream); return(Categories[type]); } catch (Exception e) { MelonLogger.Error("Can't read " + path + "."); MelonLogger.Error(e); } Categories[type] = category; RegisterCategories(new [] { type }); return(Categories[type]); } Categories[type] = category; RegisterCategories(new [] { type }); return(Categories[type]); }
/// <summary> /// Instantiates new translator with path. /// </summary> /// <param name="path">Path the language files are located.</param> public Translator(string path) { Path = path; StringsMap = new Dictionary <SystemLanguage, Dictionary <string, string> >(); var lPath = Path + Setting.LanguageDirectory; if (!Directory.Exists(lPath)) { Directory.CreateDirectory(lPath); } var langFiles = Directory.GetFiles(lPath); ADOLib.Log(langFiles.Length); foreach (var langFile in langFiles) { ADOLib.Log(langFile); SystemLanguage lang; var langNames = langFile.Split('\\'); var langName = langNames[langNames.Length - 1].Replace(".lang", ""); if (!Enum.TryParse(langName, out lang)) { continue; } var builder = new DeserializerBuilder().Build(); Dictionary <string, string> langStrings; using (var stream = File.Open(langFile, FileMode.Open, FileAccess.Read)) { using (var reader = new StreamReader(stream)) { try { langStrings = builder.Deserialize(reader, typeof(Dictionary <string, string>)) as Dictionary <string, string>; } catch (YamlException) { ADOLib.Log($"Cannot load language {lang} from {path}", LogType.Error); langStrings = new Dictionary <string, string>(); } } } StringsMap[lang] = langStrings; } if (!StringsMap.ContainsKey(SystemLanguage.English)) { StringsMap[SystemLanguage.English] = new Dictionary <string, string>(); } }
public void Awake() { BG.LoadImage(File.ReadAllBytes($"{ADOLib.PathStatic}settingsBG.png")); Background.normal.background = BG; ButtonActivated.LoadImage(File.ReadAllBytes($"{ADOLib.PathStatic}buttonActivated.png")); ButtonNotActivated.LoadImage(File.ReadAllBytes($"{ADOLib.PathStatic}buttonNotActivated.png")); Text = GUIExtended.Text; Selection = GUIExtended.Selection; SelectionActive = GUIExtended.SelectionActive; TextInput = GUIExtended.TextInput; ADOLib.Log("SettingsUI Awake"); }
/// <summary> /// Translates text with key. /// </summary> /// <param name="input">Key of the translated string</param> /// <param name="language"><see cref="SystemLanguage">Language</see> to translate into.</param> /// <returns>String translated into the language.</returns> public string Translate(string input, SystemLanguage language) { if (!StringsMap.ContainsKey(language)) { language = SystemLanguage.English; } if (!StringsMap[language].ContainsKey(input)) { ADOLib.Log(input); StringsMap[language][input] = $"{language}.{input}.NotTranslated"; var serializer = new SerializerBuilder().Build(); var path = Path + Setting.LanguageDirectory + $"{language}.lang"; ADOLib.Log(path); File.WriteAllText(path, serializer.Serialize(StringsMap[language])); } return(StringsMap[language][input].Replace("\\n", "\n")); }
/// <summary> /// Patches patch. /// <param name="harmony">Harmony class to apply patch.</param> /// <param name="patchType">Harmony class to apply patch.</param> /// </summary> public static void SafePatch(this HarmonyLib.Harmony harmony, Type patchType) { var metadata = patchType.GetCustomAttribute <SafePatchAttribute>(); if (metadata == null) { ADOLib.Log($"Type {patchType} doesn't have SafePatch attribute.", LogType.Error); return; } ADOLib.Log($"Patching {metadata.PatchId}"); if (metadata.IsEnabled) { ADOLib.Log($"{metadata.PatchId} is already patched!", LogType.Warning); return; } if (!IsValidPatch(patchType)) { ADOLib.Log($"Type {patchType} is not valid for this ADOFAI version", LogType.Warning); return; } Type declaringType = metadata.Assembly.GetType(metadata.ClassName); if (declaringType == null) { ADOLib.Log($"Type {metadata.ClassName} not found", LogType.Warning); return; } try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception) { ADOLib.Log($"Wrong patch method {metadata.MethodName}", LogType.Warning); return; } metadata.IsEnabled = true; var metadata2 = patchType.GetCustomAttribute <SafePatchAttribute>(); ADOLib.Log($"Successfully patched {metadata.PatchId}", LogType.Success); }
public static void UnpatchCategory(this HarmonyLib.Harmony harmony, Type type) { ADOLib.Log($"Unpatching category {type}"); var patchAttr = type.GetCustomAttribute <CategoryAttribute>(); if (!patchAttr.isValid) { ADOLib.Log($"Not unpatching {type}; ADOFAI version is not compatible", LogType.Warning); return; } var patchClass = patchAttr.PatchClass; if (patchClass == null) { ADOLib.Log($"No patch class found in category {type}", LogType.Warning); return; } ADOLib.Log("Unpatching SafePatch..."); var patches = patchClass.GetNestedTypes(AccessTools.all).Where(t => t.GetCustomAttribute <SafePatchAttribute>() != null); patches.Do(harmony.SafeUnpatch); ADOLib.Log($"Successfully patched category {type}", LogType.Success); }
public void Start() { ADOLib.Log("SettingsUI Start"); Category.RegisterCategories(AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes())); }
public override void OnDisable() { ADOLib.Log("ADOLib Settings Disabled"); }
public override void OnEnable() { ADOLib.Log("ADOLib Settings Enabled"); }
internal static void RegisterCategories(IEnumerable <Type> types) { ADOLib.Log("Registering Category"); var categoryTypes = types.Where(t => t.GetCustomAttribute <CategoryAttribute>(true) != null).ToList(); int success = 0; foreach (var category in categoryTypes) { var categoryAttr = category.GetCustomAttribute <CategoryAttribute>(); var tabName = categoryAttr.TabName; var instance = GetCategory(category); if (instance.isRegistered) { ADOLib.Log($"Category already registered, skipping category {category}", LogType.Warning); continue; } instance.Name = categoryAttr.Name; instance.TabName = categoryAttr.TabName; instance.ForceType = categoryAttr.ForceType; instance.InvalidMode = categoryAttr.InvalidMode; instance.ForceReason = categoryAttr.ForceReason; if (!instance.Metadata.isValid) { if (instance.InvalidMode == InvalidMode.UnRegister) { ADOLib.Log($"Category version uncompatible, skipping category {category}", LogType.Warning); continue; } instance.ForceType = ForceType.ForceDisable; if (categoryAttr.MinVersion == -1) { instance.ForceReason = string.Format(ADOLib.translator .Translate("Category.AdofaiVersionNotCompatible1"), ADOLib.RELEASE_NUMBER_FIELD, categoryAttr.MaxVersion); } else if (categoryAttr.MaxVersion == -1) { instance.ForceReason = string.Format(ADOLib.translator .Translate("Category.AdofaiVersionNotCompatible2"), ADOLib.RELEASE_NUMBER_FIELD, categoryAttr.MinVersion); } else if (categoryAttr.MinVersion == categoryAttr.MaxVersion) { instance.ForceReason = string.Format(ADOLib.translator .Translate("Category.AdofaiVersionNotCompatible3"), ADOLib.RELEASE_NUMBER_FIELD, categoryAttr.MinVersion); } else { instance.ForceReason = string.Format(ADOLib.translator .Translate("Category.AdofaiVersionNotCompatible0"), ADOLib.RELEASE_NUMBER_FIELD, categoryAttr.MinVersion, categoryAttr.MaxVersion); } } if (instance.ForceType == ForceType.ForceDisable) { instance.IsEnabled = false; } else if (instance.ForceType == ForceType.ForceEnable) { instance.IsEnabled = true; } var text = GUIExtended.Text; text.alignment = TextAnchor.MiddleLeft; text.font = GUIExtended.ArialFont; text.fontSize = 20; Action OnGUI = () => { GUILayout.BeginHorizontal(); instance.IsExpanded = GUILayout.Toggle( instance.IsExpanded, instance.IsEnabled ? instance.IsExpanded ? "▼" : "━" : "<color=#444444>━</color>", new GUIStyle { fixedWidth = 10, normal = new GUIStyleState { textColor = Color.black }, fontSize = 20, margin = new RectOffset(4, 16, 24, 0) }); if (instance.ForceType == ForceType.DontForce) { var wasEnabled = instance.IsEnabled; instance.IsEnabled = GUIExtended.Toggle(instance.IsEnabled, $"<size=50>{instance.Name}</size>"); if (instance.IsEnabled != wasEnabled) { if (instance.IsEnabled) { instance.OnEnable(); } else { instance.OnDisable(); } } } else if (instance.ForceType == ForceType.ForceDisable) { GUIExtended.Toggle(instance.IsEnabled, $"<size=50><color=#444444>{instance.Name}</color></size> <color=#555555>{instance.ForceReason}</color>", GUIExtended.Text, "<color=#555555>☐</color>", "<color=#555555>☐</color>"); } else { GUIExtended.Toggle(instance.IsEnabled, $"<size=50>{instance.Name}</size> <color=#555555>{instance.ForceReason}</color>", GUIExtended.Text, "<color=#555555>☑</color>", "<color=#555555>☑</color>"); } GUILayout.EndHorizontal(); if (instance.IsEnabled && instance.IsExpanded) { GUIExtended.BeginIndent(15); instance.OnGUI(); GUIExtended.EndIndent(); } GUIExtended.HorizontalLine(0.2f); }; if (!SettingsUI.Tabs.Contains(tabName)) { SettingsUI.Categories[tabName] = instance; SettingsUI.Settings[tabName] = OnGUI; SettingsUI.Saves[tabName] = instance.Save; SettingsUI.Tabs.Insert(0, tabName); } else { SettingsUI.Settings[tabName] += OnGUI; SettingsUI.Saves[tabName] += instance.Save; } instance.Init(); if (instance.IsEnabled) { instance.OnEnable(); } else { instance.OnDisable(); } ADOLib.Log($"Successfully registered category {category}", LogType.Success); success++; } }