using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FastDialogue")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FastDialogue")]
[assembly: AssemblyTitle("FastDialogue")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 FastDialogue
{
internal static class Diag
{
internal static ManualLogSource Log;
internal static bool Enabled = true;
internal static void Write(string msg)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (Enabled && Log != null)
{
ManualLogSource log = Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(6, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<DateTime>(DateTime.Now, "HH:mm:ss.fff");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" t=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Time.realtimeSinceStartup, "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(msg);
}
log.LogInfo(val);
}
}
}
[HarmonyPatch(typeof(SpeechController), "SetSpeechActive")]
internal static class SetSpeechActivePatch
{
private static readonly Dictionary<IntPtr, bool> _last = new Dictionary<IntPtr, bool>();
private static void Postfix(SpeechController __instance, bool val)
{
try
{
if (!_last.TryGetValue(((Il2CppObjectBase)__instance).Pointer, out var value) || value != val)
{
_last[((Il2CppObjectBase)__instance).Pointer] = val;
int value2 = ((__instance.speechQueue != null) ? __instance.speechQueue.Count : (-1));
Diag.Write($"SpeechController.SetSpeechActive({val}) em '{((Object)__instance).name}' fila={value2} speechDelay={__instance.speechDelay:F2}");
}
}
catch (Exception ex)
{
Diag.Write("SetSpeechActivePatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(DialogButtonController), "SetSelectable")]
internal static class SetSelectablePatch
{
private static void Postfix(DialogButtonController __instance, bool val)
{
try
{
Diag.Write($"DialogButtonController.SetSelectable({val}) em '{((Object)__instance).name}'");
}
catch (Exception ex)
{
Diag.Write("SetSelectablePatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(SpeechBubbleController), "Setup")]
internal static class BubbleSetupPatch
{
private static void Postfix(SpeechBubbleController __instance)
{
try
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(79, 4);
defaultInterpolatedStringHandler.AppendLiteral("SpeechBubbleController.Setup texto=\"");
defaultInterpolatedStringHandler.AppendFormatted(__instance.actualString);
defaultInterpolatedStringHandler.AppendLiteral("\" oncreenTime=");
defaultInterpolatedStringHandler.AppendFormatted(__instance.oncreenTime, "F2");
defaultInterpolatedStringHandler.AppendLiteral(" delayProgress=");
defaultInterpolatedStringHandler.AppendFormatted(__instance.delayProgress, "F2");
defaultInterpolatedStringHandler.AppendLiteral(" delay(queue)=");
QueueElement speech = __instance.speech;
defaultInterpolatedStringHandler.AppendFormatted((speech != null) ? new float?(speech.delay) : ((float?)null), "F2");
Diag.Write(defaultInterpolatedStringHandler.ToStringAndClear());
}
catch (Exception ex)
{
Diag.Write("BubbleSetupPatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(SpeechBubbleController), "Update")]
internal static class BubbleTracePatch
{
private static float _next;
private static void Postfix(SpeechBubbleController __instance)
{
if (!Diag.Enabled || Time.realtimeSinceStartup < _next)
{
return;
}
try
{
InteractionController instance = InteractionController.Instance;
if (!((Object)(object)instance == (Object)null) && instance.dialogMode && instance.talkingTo != null)
{
SpeechController speechController = instance.talkingTo.speechController;
SpeechController speechController2 = __instance.speechController;
if (!((Object)(object)speechController == (Object)null) && !((Object)(object)speechController2 == (Object)null) && !(((Il2CppObjectBase)speechController).Pointer != ((Il2CppObjectBase)speechController2).Pointer))
{
_next = Time.realtimeSinceStartup + 0.2f;
int value = ((__instance.actualString != null) ? __instance.actualString.Length : 0);
Diag.Write($"[bolha] len={value} stringReveal={__instance.stringReveal:F1} revealedChars={__instance.revealedChars} words={__instance.wordsRevealed} timeStamp={__instance.timeStamp:F2} oncreenTime={__instance.oncreenTime:F2} delayProgress={__instance.delayProgress:F2} fade={__instance.fadeProgress:F2} final={__instance.setFinalText} skip={Skip.IsTarget(speechController2)}");
}
}
}
catch (Exception ex)
{
Diag.Write("BubbleTracePatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(SpeechBubbleController), "OnDestroy")]
internal static class BubbleDestroyPatch
{
private static void Prefix(SpeechBubbleController __instance)
{
try
{
Diag.Write($"SpeechBubbleController.OnDestroy setFinalText={__instance.setFinalText} stringReveal={__instance.stringReveal:F2} fade={__instance.fadeProgress:F2}");
}
catch (Exception ex)
{
Diag.Write("BubbleDestroyPatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(InteractionController), "SetDialog")]
internal static class SetDialogPatch
{
private static void Postfix(bool val)
{
Diag.Write($"InteractionController.SetDialog({val})");
}
}
[HarmonyPatch(typeof(InteractionController), "RefreshDialogOptions")]
internal static class RefreshDialogOptionsPatch
{
private static void Postfix(InteractionController __instance)
{
try
{
Diag.Write("InteractionController.RefreshDialogOptions -> " + DialogWatch.DescribeOptions(__instance));
}
catch (Exception ex)
{
Diag.Write("RefreshDialogOptionsPatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(InteractionController), "Update")]
internal static class DialogWatch
{
private static string _last;
private static void Postfix(InteractionController __instance)
{
if (!Diag.Enabled)
{
return;
}
try
{
if (!__instance.dialogMode)
{
_last = null;
return;
}
string text = Snapshot(__instance);
if (text != _last)
{
Diag.Write("[watch] " + text);
_last = text;
}
}
catch (Exception ex)
{
Diag.Write("DialogWatch erro: " + ex.Message);
}
}
private static string Snapshot(InteractionController ic)
{
string text = "sem speechController";
Interactable talkingTo = ic.talkingTo;
SpeechController val = ((talkingTo != null) ? talkingTo.speechController : null);
if ((Object)(object)val != (Object)null)
{
int value = ((val.speechQueue != null) ? val.speechQueue.Count : (-1));
string value2 = "sem actor";
if ((Object)(object)val.actor != (Object)null)
{
value2 = $"isSpeaking={val.actor.isSpeaking} inConversation={val.actor.inConversation}";
}
text = $"speechActive={val.speechActive} fila={value} bolha={(Object)(object)val.activeSpeechBubble != (Object)null} endAfterThisSpeech={val.endAfterThisSpeech} {value2}";
}
return text + " | " + DescribeOptions(ic);
}
internal static string DescribeOptions(InteractionController ic)
{
List<DialogButtonController> dialogOptions = ic.dialogOptions;
if (dialogOptions == null)
{
return "opções=null";
}
int num = 0;
for (int i = 0; i < dialogOptions.Count; i++)
{
DialogButtonController val = dialogOptions[i];
if ((Object)(object)val != (Object)null && val.selectable)
{
num++;
}
}
return $"opções={dialogOptions.Count} selecionáveis={num}";
}
}
[BepInPlugin("com.eckylise.fastdialogue", "FastDialogue", "0.2.1")]
public class Plugin : BasePlugin
{
private static readonly Type[] SkipPatches = new Type[3]
{
typeof(SkipInputPatch),
typeof(SkipBubblePatch),
typeof(SkipBubbleDestroyPatch)
};
private static readonly Type[] DiagnosticPatches = new Type[8]
{
typeof(SetSpeechActivePatch),
typeof(SetSelectablePatch),
typeof(BubbleSetupPatch),
typeof(BubbleTracePatch),
typeof(BubbleDestroyPatch),
typeof(SetDialogPatch),
typeof(RefreshDialogOptionsPatch),
typeof(DialogWatch)
};
public override void Load()
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Expected O, but got Unknown
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Expected O, but got Unknown
Diag.Log = ((BasePlugin)this).Log;
Diag.Enabled = ((BasePlugin)this).Config.Bind<bool>("Debug", "DiagnosticLogs", false, "Loga no console/LogOutput.log quando a fala começa/termina e quando as opções de diálogo liberam.").Value;
Skip.Key = ((BasePlugin)this).Config.Bind<KeyCode>("Skip", "SkipKey", (KeyCode)323, "Tecla que pula a fala do NPC durante o diálogo (Mouse0 = botão esquerdo).").Value;
Skip.WholeAnswer = ((BasePlugin)this).Config.Bind<bool>("Skip", "SkipWholeAnswer", false, "true: um clique pula a resposta inteira (todas as falas na fila). false: um clique por fala.").Value;
Skip.MinVisibleSeconds = ((BasePlugin)this).Config.Bind<float>("Skip", "MinVisibleSeconds", 0.3f, "Tempo (s) que o texto completo fica na tela depois do clique, antes de sumir.").Value;
Harmony val = new Harmony("com.eckylise.fastdialogue");
Type[] skipPatches = SkipPatches;
foreach (Type type in skipPatches)
{
val.CreateClassProcessor(type).Patch();
}
if (Diag.Enabled)
{
skipPatches = DiagnosticPatches;
foreach (Type type2 in skipPatches)
{
val.CreateClassProcessor(type2).Patch();
}
}
ManualLogSource log = ((BasePlugin)this).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(37, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("FastDialogue carregado (diagnóstico ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Diag.Enabled ? "ligado" : "desligado");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
}
log.LogInfo(val2);
}
}
internal static class Skip
{
internal static KeyCode Key = (KeyCode)323;
internal static bool WholeAnswer = false;
internal static float MinVisibleSeconds = 0.3f;
internal static IntPtr Target;
internal static bool IsTarget(SpeechController sc)
{
if (Target != IntPtr.Zero && (Object)(object)sc != (Object)null)
{
return ((Il2CppObjectBase)sc).Pointer == Target;
}
return false;
}
internal static void Clear(string reason)
{
if (!(Target == IntPtr.Zero))
{
Target = IntPtr.Zero;
Diag.Write("[skip] desligado (" + reason + ")");
}
}
}
[HarmonyPatch(typeof(InteractionController), "Update")]
internal static class SkipInputPatch
{
private const float IgnoreAfterOptionsSeconds = 0.15f;
private static float _optionsLastSeen;
private static void Postfix(InteractionController __instance)
{
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
try
{
List<DialogButtonController> dialogOptions = __instance.dialogOptions;
if (dialogOptions != null && dialogOptions.Count > 0)
{
_optionsLastSeen = Time.realtimeSinceStartup;
}
if (!__instance.dialogMode)
{
Skip.Clear("saiu do diálogo");
return;
}
Interactable talkingTo = __instance.talkingTo;
SpeechController val = ((talkingTo != null) ? talkingTo.speechController : null);
if ((Object)(object)val == (Object)null)
{
return;
}
int num = ((val.speechQueue != null) ? val.speechQueue.Count : 0);
if (!val.speechActive && num <= 0)
{
Skip.Clear("fala terminou");
}
else if (Skip.Target == IntPtr.Zero && Input.GetKeyDown(Skip.Key))
{
bool flag = (Object)(object)val.activeSpeechBubble != (Object)null;
bool flag2 = Time.realtimeSinceStartup - _optionsLastSeen > 0.15f;
if (!flag || !flag2)
{
Diag.Write($"[skip] clique ignorado (bolha={flag} opçõesSumiram={flag2})");
}
else
{
Skip.Target = ((Il2CppObjectBase)val).Pointer;
Diag.Write($"[skip] clique: pulando fala de '{((Object)val).name}' (fila={num})");
}
}
}
catch (Exception ex)
{
Diag.Write("SkipInputPatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(SpeechBubbleController), "Update")]
internal static class SkipBubblePatch
{
private static void Prefix(SpeechBubbleController __instance)
{
try
{
if (Skip.IsTarget(__instance.speechController))
{
int num = __instance.actualString?.Length ?? 0;
if (__instance.stringReveal < (float)num)
{
__instance.stringReveal = num;
}
if (__instance.oncreenTime > Skip.MinVisibleSeconds)
{
__instance.oncreenTime = Skip.MinVisibleSeconds;
}
}
}
catch (Exception ex)
{
Diag.Write("SkipBubblePatch erro: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(SpeechBubbleController), "OnDestroy")]
internal static class SkipBubbleDestroyPatch
{
private static void Prefix(SpeechBubbleController __instance)
{
try
{
if (!Skip.WholeAnswer && Skip.IsTarget(__instance.speechController))
{
Skip.Clear("balão pulado terminou");
}
}
catch (Exception ex)
{
Diag.Write("SkipBubbleDestroyPatch erro: " + ex.Message);
}
}
}
}