using 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();
}
}