using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SyncSubtitles")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.2.3.0")] [assembly: AssemblyInformationalVersion("0.2.3")] [assembly: AssemblyProduct("WK_SyncSubtitles")] [assembly: AssemblyTitle("SyncSubtitles")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.3.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace WK_SyncSubtitles { [HarmonyPatch(typeof(CL_LocalizationManager), "Awake")] public static class SubtitleStringsPatch { public static string[] LinebreakPattern = new string[1] { "
" }; public static string DelayPattern = ""; public static Regex DelayRegex = new Regex(DelayPattern, RegexOptions.IgnoreCase); private static void Postfix(CL_LocalizationManager __instance) { Plugin.Logger.LogInfo((object)"Patching..."); CL_LocalizationManager.currentLocalization.announcements = GetCorrectDelaySubtitles(CL_LocalizationManager.currentLocalization.announcements); } public static Dictionary GetCorrectDelaySubtitles(Dictionary subtitles) { if (Plugin.SubtitleDisplayTimings == null) { return subtitles; } Dictionary dictionary = new Dictionary(); foreach (KeyValuePair subtitle in subtitles) { string key = subtitle.Key; string value = subtitle.Value; if ((!Plugin.UseOriginalDelay.Value || !DelayRegex.Match(value).Success) && Plugin.SubtitleDisplayTimings.TryGetValue(key, out var value2)) { string[] array = value.Split(LinebreakPattern, StringSplitOptions.None); int num = Math.Min(array.Length, value2.Count); for (int i = 0; i < num; i++) { string line = array[i].TrimStart(Array.Empty()); line = RemoveLineDelay(line); float num2 = (float)line.Length * Plugin.CharacterInterval.Value + Plugin.BaseDuration.Value; float num3 = value2[i]; num3 -= ((i > 0) ? value2[i - 1] : 0f); float delay = num3 - num2; string text = AddLineDelay(line, delay); array[i] = text; } dictionary[key] = string.Join(LinebreakPattern[0], array); } else { dictionary[key] = value; } } return dictionary; } public static string RemoveLineDelay(string line) { Match match = DelayRegex.Match(line); if (match.Success) { line = line.Remove(match.Index, match.Length); } return line; } public static string AddLineDelay(string line, float delay) { if (delay == 0f) { return line; } string text = ""; Match match = DelayRegex.Match(line); line = ((!match.Success) ? (line + text) : line.Insert(match.Index, text)); return line; } } [BepInPlugin("mimimi-turret.wk-sync-subtitles", "SyncSubtitles", "0.2.3")] [BepInProcess("White Knuckle.exe")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; public static ConfigEntry UseOriginalDelay; public static ConfigEntry BaseDuration; public static ConfigEntry CharacterInterval; public static string RelativeSubtitleTimingsPath = "data\\SubtitleDisplayTimings.json"; public static Dictionary> SubtitleDisplayTimings; private void Awake() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Initializing"); UseOriginalDelay = ((BaseUnityPlugin)this).Config.Bind("General", "UseOriginalDelay", false, "If set to \"true\", skip texts that contain \"\" tag(s) during patching"); BaseDuration = ((BaseUnityPlugin)this).Config.Bind("Timing", "BaseDuration", 2.5f, "Base display duration of a subtitle, in seconds"); CharacterInterval = ((BaseUnityPlugin)this).Config.Bind("Timing", "CharacterInterval", 0.1f, "Display duration exteneded by each character, in seconds"); LoadSubtitleDisplayTimings(); if (SubtitleDisplayTimings != null) { Harmony val = new Harmony("mimimi-turret.wk-sync-subtitles"); val.PatchAll(); } } public static void LoadSubtitleDisplayTimings() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, RelativeSubtitleTimingsPath); try { string text2 = File.ReadAllText(text); SubtitleDisplayTimings = JsonConvert.DeserializeObject>>(text2); } catch (Exception) { Logger.LogInfo((object)("Failed to load " + text)); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "SyncSubtitles"; public const string PLUGIN_NAME = "WK_SyncSubtitles"; public const string PLUGIN_VERSION = "0.2.3"; } }