Guest User

Untitled

a guest
May 11th, 2020
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.53 KB | None | 0 0
  1. // Copyright (c) 2019 Jennifer Messerly
  2. // This code is licensed under MIT license (see LICENSE for details)
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Security.Cryptography;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using Kingmaker;
  15. using Kingmaker.Blueprints;
  16. using Kingmaker.Blueprints.Items.Weapons;
  17. using Kingmaker.Blueprints.Root;
  18. using Kingmaker.UI.Common.Animations;
  19. using Kingmaker.UI.LevelUp;
  20. using Kingmaker.UnitLogic.Abilities.Blueprints;
  21. using Kingmaker.UnitLogic.Abilities.Components;
  22. using Kingmaker.UnitLogic.Mechanics;
  23. using Kingmaker.UnitLogic.Mechanics.Actions;
  24. using Kingmaker.Utility;
  25. using UnityEngine;
  26. using UnityModManagerNet;
  27.  
  28. namespace zQOLEndless
  29. {
  30.     public class Main
  31.     {
  32.  
  33.         //@@Nemorga : that's athing I need for later Assembly GetAssemblyByName(string name) { return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(assembly => assembly.GetName().Name == name).DefinedTypes; }
  34.  
  35.  
  36.         //Main patch to the library everythiong done here is eithyer geting the library in a variable or modifying it
  37.         [Harmony12.HarmonyPatch(typeof(LibraryScriptableObject), "LoadDictionary", new Type[0])]
  38.         static class LibraryScriptableObject_LoadDictionary_Patch
  39.         {
  40.             [Harmony12.HarmonyPriority(Harmony12.Priority.Low)]
  41.             static void Postfix(LibraryScriptableObject __instance)
  42.             {
  43.                 var self = __instance;
  44.                 if (Main.library != null) return;
  45.                 Main.library = self;
  46.                 //needed for thing
  47.                 EnableGameLogging();
  48.  
  49.                 //Needed to use helper
  50.                 SafeLoad(Helpers.Load, "Initialization code");
  51.  
  52.  
  53. #if DEBUG
  54.                 // Perform extra sanity checks in debug builds.
  55.                 SafeLoad(CheckPatchingSuccess, "Check that all patches are used, and were loaded");
  56.                 SafeLoad(SaveCompatibility.CheckCompat, "Check save game compatibility");
  57.                 //Jaku
  58.                 SafeLoad(Tweaks.Load, "Test jaku");
  59.                 SafeLoad(CustomItems.Load, "Custom items");
  60.                 SafeLoad(CustomSpells.Load, "Custom Spells");
  61.  
  62.                 Log.Write("Loaded finished.");
  63. #endif
  64.  
  65.  
  66.  
  67.             }
  68.  
  69.         }
  70.  
  71.         //Patch needed for replacing dummy shader, only intresting if you added custom asset
  72.         /*
  73.         [Harmony12.HarmonyPatch(typeof(LibraryScriptableObject), "LoadDictionary")]
  74.         static class LibraryScriptableObject_LoadDictionary2_Patch
  75.         {
  76.             static void Postfix()
  77.             {
  78.                 try
  79.                 {
  80.                     if (ShaderLookup == null)
  81.                     {
  82.                         ShaderLookup = new Dictionary<string, Shader>();
  83.                         foreach (var shader in Resources.FindObjectsOfTypeAll<Shader>())
  84.                         {
  85.                             if (ShaderLookup.ContainsKey(shader.name))
  86.                             {
  87.                                 Error($"Duplicate shader {shader.name}");
  88.                             }
  89.                             else
  90.                             {
  91.                                 ShaderLookup[shader.name] = shader;
  92.                             }
  93.                         }
  94.                     }
  95.                 }
  96.                 catch (Exception ex)
  97.                 {
  98.                     Log.Error(ex);
  99.                 }
  100.             }
  101.         }
  102.         */
  103.        
  104.        
  105.         //All this are thing needed later
  106.         internal static LibraryScriptableObject library;
  107.         static Dictionary<string, Shader> ShaderLookup;//this one is for shader lookup
  108.         public static UnityModManager.ModEntry modEntry;
  109.         public static bool enabled;
  110.  
  111.  
  112.         public static UnityModManager.ModEntry.ModLogger logger;
  113.         public static string modpath;
  114.         //internal static Settings settings;
  115.  
  116.  
  117.         static Harmony12.HarmonyInstance harmonyInstance;
  118.  
  119.         static readonly Dictionary<Type, bool> typesPatched = new Dictionary<Type, bool>();
  120.         static readonly List<String> failedPatches = new List<String>();
  121.         static readonly List<String> failedLoading = new List<String>();
  122.  
  123.         [System.Diagnostics.Conditional("DEBUG")]
  124.         static void EnableGameLogging()
  125.         {
  126.             if (UberLogger.Logger.Enabled) return;
  127.  
  128.             // Code taken from GameStarter.Awake(). PF:K logging can be enabled with command line flags,
  129.             // but when developing the mod it's easier to force it on.
  130.             var dataPath = ApplicationPaths.persistentDataPath;
  131.             Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None);
  132.             UberLogger.Logger.Enabled = true;
  133.             var text = Path.Combine(dataPath, "GameLog.txt");
  134.             if (File.Exists(text))
  135.             {
  136.                 File.Copy(text, Path.Combine(dataPath, "GameLogPrev.txt"), overwrite: true);
  137.                 File.Delete(text);
  138.             }
  139.             UberLogger.Logger.AddLogger(new UberLoggerFile("GameLogFull.txt", dataPath));
  140.             UberLogger.Logger.AddLogger(new UberLoggerFilter(new UberLoggerFile("GameLog.txt", dataPath), UberLogger.LogSeverity.Warning, "MatchLight"));
  141.  
  142.             UberLogger.Logger.Enabled = true;
  143.         }
  144.  
  145.  
  146.         static string GetMd5Hash(MD5 md5, string input)
  147.         {
  148.             // Note: this uses MD5 to hash a string to 128-bits, it's not for any security purpose.
  149.             var str = new StringBuilder();
  150.             foreach (var b in md5.ComputeHash(Encoding.UTF8.GetBytes(input)))
  151.             {
  152.                 str.Append(b.ToString("x2"));
  153.             }
  154.             Log.Write($"md5 hash of '${input}' is: {str}");
  155.             return str.ToString();
  156.         }
  157.  
  158.  
  159.  
  160.         // We don't want one patch failure to take down the entire mod, so they're applied individually.
  161.         //
  162.         // Also, in general the return value should be ignored. If a patch fails, we still want to create
  163.         // blueprints, otherwise the save won't load. Better to have something be non-functional.
  164.         internal static bool ApplyPatch(Type type, String featureName)
  165.         {
  166.             try
  167.             {
  168.                 if (typesPatched.ContainsKey(type)) return typesPatched[type];
  169.  
  170.                 var patchInfo = Harmony12.HarmonyMethodExtensions.GetHarmonyMethods(type);
  171.                 if (patchInfo == null || patchInfo.Count() == 0)
  172.                 {
  173.                     Log.Error($"Failed to apply patch {type}: could not find Harmony attributes");
  174.                     failedPatches.Add(featureName);
  175.                     typesPatched.Add(type, false);
  176.                     return false;
  177.                 }
  178.                 var processor = new Harmony12.PatchProcessor(harmonyInstance, type, Harmony12.HarmonyMethod.Merge(patchInfo));
  179.                 var patch = processor.Patch().FirstOrDefault();
  180.                 if (patch == null)
  181.                 {
  182.                     Log.Error($"Failed to apply patch {type}: no dynamic method generated");
  183.                     failedPatches.Add(featureName);
  184.                     typesPatched.Add(type, false);
  185.                     return false;
  186.                 }
  187.                 typesPatched.Add(type, true);
  188.                 return true;
  189.             }
  190.             catch (Exception e)
  191.             {
  192.                 Log.Error($"Failed to apply patch {type}: {e}");
  193.                 failedPatches.Add(featureName);
  194.                 typesPatched.Add(type, false);
  195.                 return false;
  196.             }
  197.         }
  198.  
  199.         static void CheckPatchingSuccess()
  200.         {
  201.             // Check to make sure we didn't forget to patch something.
  202.             foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
  203.             {
  204.                 var infos = Harmony12.HarmonyMethodExtensions.GetHarmonyMethods(type);
  205.                 if (infos != null && infos.Count() > 0 && !typesPatched.ContainsKey(type))
  206.                 {
  207.                     Log.Write($"Did not apply patch for {type}");
  208.                 }
  209.             }
  210.         }
  211.  
  212.         //this is the function that load the mod, the info.json must point to it In entry method
  213.         static bool Load(UnityModManager.ModEntry modEntry)
  214.         {
  215.             logger = modEntry.Logger;
  216.             modEntry.OnToggle = OnToggle;
  217.             modEntry.OnGUI = OnGUI;
  218.             //modEntry.OnSaveGUI = OnSaveGUI;
  219.             modpath = modEntry.Path;
  220.             //settings = UnityModManager.ModSettings.Load<Settings>(modEntry);
  221.             harmonyInstance = Harmony12.HarmonyInstance.Create(modEntry.Info.Id);
  222.             //ApplyPatch(typeof(LibraryScriptableObject_LoadDictionary2_Patch), "Loading the shader");          
  223.             if (!ApplyPatch(typeof(LibraryScriptableObject_LoadDictionary_Patch), "All mod features"))
  224.             {
  225.                 // If we can't patch this, nothing will work, so want the mod to turn red in UMM.
  226.                 throw Error("Failed to patch LibraryScriptableObject.LoadDictionary(), cannot load mod");
  227.             }
  228.            
  229.             return true;
  230.         }
  231.  
  232.         static void WriteBlueprints()
  233.         {
  234.             Log.Append("\n--------------------------------------------------------------------------------");
  235.             foreach (var blueprint in library.GetAllBlueprints())
  236.             {
  237.                 Log.Append($"var {blueprint.name} = library.Get<{blueprint.GetType().Name}>(\"{blueprint.AssetGuid}\");");
  238.             }
  239.             Log.Append("--------------------------------------------------------------------------------\n");
  240.             Log.Flush();
  241.         }
  242.  
  243.         static bool OnToggle(UnityModManager.ModEntry modEntry, bool value)
  244.         {
  245.             enabled = value;
  246.             return true;
  247.         }
  248.  
  249.         static void OnGUI(UnityModManager.ModEntry modEntry)
  250.         {
  251.             if (!enabled) return;
  252.  
  253.             var fixedWidth = new GUILayoutOption[1] { GUILayout.ExpandWidth(false) };
  254.  
  255.             if (failedPatches.Count > 0)
  256.             {
  257.                 GUILayout.BeginVertical();
  258.                 GUILayout.Label("<b>Error: Some patches failed to apply. These features may not work:</b>", fixedWidth);
  259.                 foreach (var featureName in failedPatches)
  260.                 {
  261.                     GUILayout.Label($"  • <b>{featureName}</b>", fixedWidth);
  262.                 }
  263.                 GUILayout.EndVertical();
  264.             }
  265.             if (failedLoading.Count > 0)
  266.             {
  267.                 GUILayout.BeginVertical();
  268.                 GUILayout.Label("<b>Error: Some assets failed to load. Saves using these features won't work:</b>", fixedWidth);
  269.                 foreach (var featureName in failedLoading)
  270.                 {
  271.                     GUILayout.Label($"  • <b>{featureName}</b>", fixedWidth);
  272.                 }
  273.                 GUILayout.EndVertical();
  274.             }
  275.             /*
  276.             settings.EldritchKnightFix = GUILayout.Toggle(settings.EldritchKnightFix,
  277.                 "Eldritch Knight requires martial class (doesn't affect existing EKs)", fixedWidth);
  278.  
  279.             settings.ShowCustomPortraits = GUILayout.Toggle(settings.ShowCustomPortraits,
  280.                 "Show custom portraits in the portrait list at character creation (if changed, requires restart)", fixedWidth);
  281.  
  282.             settings.OracleHas3SkillPoints = GUILayout.Toggle(settings.OracleHas3SkillPoints,
  283.                 "Give Oracle class 3+int skill points on level up (instead of 4, due to condensed skills)");
  284.            
  285.  
  286.             settings.RelaxAncientLorekeeper = GUILayout.Toggle(settings.RelaxAncientLorekeeper,
  287.                 "Any race can choose the Oracle Ancient Lorekeeper archetype", fixedWidth);
  288.  
  289.             settings.RelaxTonguesCurse = GUILayout.Toggle(settings.RelaxTonguesCurse,
  290.                 "Disable Tongues curse penalty (that party members need 1 rank Knowledge: World to be controlled by PC in combat)", fixedWidth);*/
  291.         }
  292.  
  293.         /* static void OnSaveGUI(UnityModManager.ModEntry modEntry)
  294.          {
  295.              settings.Save(modEntry);
  296.          }*/
  297.  
  298.         //The safe load function used in the mod so that a failed thing don't failed alll the mod
  299.         internal static void SafeLoad(Action load, String name)
  300.         {
  301.             try
  302.             {
  303.                 load();
  304.             }
  305.             catch (Exception e)
  306.             {
  307.                 failedLoading.Add(name);
  308.                 Log.Error(e);
  309.             }
  310.         }
  311.  
  312.         internal static T SafeLoad<T>(Func<T> load, String name)
  313.         {
  314.             try
  315.             {
  316.                 return load();
  317.             }
  318.             catch (Exception e)
  319.             {
  320.                 failedLoading.Add(name);
  321.                 Log.Error(e);
  322.                 return default(T);
  323.             }
  324.         }
  325.  
  326.         internal static Exception Error(String message)
  327.         {
  328.             logger?.Log(message);
  329.             return new InvalidOperationException(message);
  330.         }
  331.     }
  332.  
  333.  
  334.     /* public class Settings : UnityModManager.ModSettings
  335.      {
  336.          public bool EldritchKnightFix = true;
  337.  
  338.          public bool ShowCustomPortraits = false;
  339.  
  340.          public bool RelaxAncientLorekeeper = false;
  341.  
  342.          public bool RelaxTonguesCurse = false;
  343.  
  344.          public bool OracleHas3SkillPoints = true;
  345.  
  346.          public override void Save(UnityModManager.ModEntry modEntry)
  347.          {
  348.              UnityModManager.ModSettings.Save<Settings>(this, modEntry);
  349.          }
  350.      }*/
  351. }
Add Comment
Please, Sign In to add comment