Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LoveLLM v1.0.2
LoveLLM.dll
Decompiled a year agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LoveLLM")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LoveLLM Plugin")] [assembly: AssemblyTitle("LoveLLM")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LoveLLM { public static class MyPluginInfo { public const string PLUGIN_GUID = "LoveLLM"; public const string PLUGIN_NAME = "LoveLLM Plugin"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace repo_mod { public static class Native { [DllImport("LLMNative.dll")] public static extern IntPtr GenerateToken(string str, IntPtr model, int n_ctx); [DllImport("LLMNative.dll")] public static extern bool PollToken(IntPtr req); [DllImport("LLMNative.dll")] public static extern IntPtr RetrieveToken(IntPtr req); [DllImport("LLMNative.dll")] public static extern void FreeToken(IntPtr req); [DllImport("LLMNative.dll")] public static extern IntPtr LoadModel(string path, int ngl); [DllImport("LLMNative.dll")] public static extern void FreeModel(IntPtr model); } internal static class PatchUtils { public struct OpcodeMatch { public OpCode opcode; public object operandOrNull; public OpcodeMatch(OpCode opcode) { operandOrNull = null; this.opcode = opcode; } public OpcodeMatch(OpCode opcode, object operand) { operandOrNull = null; this.opcode = opcode; operandOrNull = operand; } } public static int LocateCodeSegment(int startIndex, List<CodeInstruction> searchSpace, List<OpcodeMatch> searchFor) { if (startIndex < 0 || startIndex >= searchSpace.Count) { return -1; } int num = 0; for (int i = startIndex; i < searchSpace.Count; i++) { CodeInstruction obj = searchSpace[i]; OpcodeMatch opcodeMatch = searchFor[num]; if (obj.opcode == opcodeMatch.opcode) { num++; if (num == searchFor.Count) { return i - num + 1; } } else { num = 0; } } return -1; } } internal class PromptConfig { public struct Prompt { public string PromptString { get; set; } public PossessChatID PossessChatID { get; set; } } public static List<Prompt> Prompts { get; set; } } [HarmonyPatch(typeof(ValuableLovePotion))] internal class ValuableLovePotionPatches { public class InternalStateData { public enum EState { State_Idle, State_Cooldown, State_WaitingForToken, State_TokenAvailable } public PromptConfig.Prompt? currentPrompt; public IntPtr? currentRequest; public EState state = EState.State_Cooldown; public float coolDownUntilNextToken = 3f; } public static IntPtr? LoadedModel = null; public static ConfigEntry<int> NCtxConfig; public static Dictionary<ValuableLovePotion, InternalStateData> internalStateStore = new Dictionary<ValuableLovePotion, InternalStateData>(); internal static void SelectPrompt(InternalStateData stateData) { int index = Random.RandomRangeInt(0, PromptConfig.Prompts.Count); stateData.currentPrompt = PromptConfig.Prompts[index]; } internal static string GetPrompt(string inPlayerName, PromptConfig.Prompt prompt) { string text = inPlayerName; if (text.Equals("this potion") || text.Equals("[playerName]")) { text = "Doug"; } return prompt.PromptString.Replace("{playerName}", "\"" + text + "\""); } internal static string GetCurrentPlayerName(ValuableLovePotion instance) { return (string)AccessTools.Field(typeof(ValuableLovePotion), "playerName").GetValue(instance); } [HarmonyPatch("Update")] [HarmonyPrefix] private static void Update_Prefix(ValuableLovePotion __instance) { if (!internalStateStore.ContainsKey(__instance)) { InternalStateData value = new InternalStateData { state = InternalStateData.EState.State_Cooldown, coolDownUntilNextToken = 15f }; internalStateStore.Add(__instance, value); } if (!internalStateStore.TryGetValue(__instance, out var value2)) { return; } switch (value2.state) { case InternalStateData.EState.State_Idle: { SelectPrompt(value2); string prompt = GetPrompt(GetCurrentPlayerName(__instance), value2.currentPrompt.Value); Plugin.Logger.LogInfo((object)("Requesting prompt: " + prompt)); value2.currentRequest = Native.GenerateToken(prompt, LoadedModel.Value, NCtxConfig.Value); value2.state = InternalStateData.EState.State_WaitingForToken; goto case InternalStateData.EState.State_WaitingForToken; } case InternalStateData.EState.State_WaitingForToken: if (Native.PollToken(value2.currentRequest.Value)) { value2.state = InternalStateData.EState.State_TokenAvailable; } break; case InternalStateData.EState.State_Cooldown: value2.coolDownUntilNextToken -= Time.deltaTime; if (value2.coolDownUntilNextToken <= 0f) { value2.coolDownUntilNextToken = 0f; value2.state = InternalStateData.EState.State_Idle; } break; case InternalStateData.EState.State_TokenAvailable: break; } } private static void Hooked_UpdateStateMachine(ValuableLovePotion __instance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (!internalStateStore.TryGetValue(__instance, out var value) || value.state != InternalStateData.EState.State_TokenAvailable) { return; } string text = Marshal.PtrToStringAnsi(Native.RetrieveToken(value.currentRequest.Value)); PossessChatID possessChatID = value.currentPrompt.Value.PossessChatID; Color val = default(Color); ((Color)(ref val))..ctor(1f, 1f, 1f, 1f); if ((int)possessChatID != 1) { if ((int)possessChatID == 4) { ((Color)(ref val))..ctor(0.5f, 0.01f, 0.01f); } } else { ((Color)(ref val))..ctor(1f, 0.3f, 0.6f, 1f); } ChatManager.instance.PossessChatScheduleStart(10); Plugin.Logger.LogInfo((object)("LoveLLM Got token: " + text)); ChatManager.instance.PossessChat(value.currentPrompt.Value.PossessChatID, text, 1f, val, 0f, false, 0, (UnityEvent)null); ChatManager.instance.PossessChatScheduleEnd(); value.coolDownUntilNextToken = Random.Range(25f, 30f); value.state = InternalStateData.EState.State_Cooldown; Native.FreeToken(value.currentRequest.Value); } [HarmonyPatch("StateIdle")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> StateIdle_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<PatchUtils.OpcodeMatch> searchFor = new List<PatchUtils.OpcodeMatch>(new <>z__ReadOnlyArray<PatchUtils.OpcodeMatch>(new PatchUtils.OpcodeMatch[4] { new PatchUtils.OpcodeMatch(OpCodes.Ldc_R4, 1.0), new PatchUtils.OpcodeMatch(OpCodes.Ldc_R4, 0.3), new PatchUtils.OpcodeMatch(OpCodes.Ldc_R4, 0.6), new PatchUtils.OpcodeMatch(OpCodes.Ldc_R4, 1.0) })); int num = PatchUtils.LocateCodeSegment(0, list, searchFor); if (num == -1) { Plugin.Logger.LogError((object)"Could not transpile ValuableLovePotion.Update"); return instructions; } for (int i = num - 7; !(list[i].opcode == OpCodes.Ret); i++) { list[i] = new CodeInstruction(OpCodes.Nop, (object)null); } list[num - 7] = new CodeInstruction(OpCodes.Ldarg_0, (object)null); list[num - 6] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ValuableLovePotionPatches), "Hooked_UpdateStateMachine", (Type[])null, (Type[])null)); return list; } } [BepInPlugin("LoveLLM", "LoveLLM Plugin", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; internal static ConfigEntry<string> ModelPathConfig; internal static ConfigEntry<string> PromptFileConfig; internal static ConfigEntry<int> NglConfig; internal static Harmony? Harmony { get; set; } public static Plugin Instance { get; private set; } private void InitModel() { NglConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ngl", 99, "Ngl parameter to pass to llama"); ValuableLovePotionPatches.NCtxConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "n_ctx", 2048, "n_ctx parameter to pass to llama. Increasing this will increase the memory footprint and maybe get some better responses. Idk its finnciky.."); string text = "Models/SmolLM2-1.7B.gguf"; ModelPathConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Model", text, "Model to load"); string text2 = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), ModelPathConfig.Value); Logger.LogInfo((object)("INIT MODEL " + text2)); ValuableLovePotionPatches.LoadedModel = Native.LoadModel(text2, NglConfig.Value); } private void InitPrompts() { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) string text = "Models/Prompts.txt"; PromptFileConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Prompts", text, "Prompt config. Each entry in the prompt config is delimited by a new line, and separated with a semicolon. The value to the left of the semicolon is the prompt and to the right is the chat possess id, so 1 is pink love potion and 4 is red."); string text2 = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), PromptFileConfig.Value); Logger.LogInfo((object)("INIT PROMPTS " + text2)); string[] array = File.ReadAllText(text2).Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); List<PromptConfig.Prompt> list = new List<PromptConfig.Prompt>(); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string[] array3 = array2[i].Split(";"); PromptConfig.Prompt item = default(PromptConfig.Prompt); item.PromptString = array3[0]; item.PossessChatID = (PossessChatID)Enum.Parse(typeof(PossessChatID), array3[1]); list.Add(item); Logger.LogInfo((object)$"Loaded prompt {item.PromptString} -- {item.PossessChatID}"); } PromptConfig.Prompts = list; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; InitPrompts(); InitModel(); Patch(); Logger.LogInfo((object)"LoveLLM v1.0.0 has loaded!"); } public void OnApplicationQuit() { Logger.LogInfo((object)"LoveLLM is unloading... Game is shutting down or plugin is disabled."); Native.FreeModel(ValuableLovePotionPatches.LoadedModel.Value); } internal static void Patch() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("LoveLLM"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } } } internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return ((ICollection<T>)_items).Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { ((ICollection<T>)_items).CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return ((IList<T>)_items).IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }