using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Timers;
using AudibleDistanceLib;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SubtitlesAPI;
using TMPro;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Subtitles")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Displays text for in-game sounds to help make the game more accessible for Deaf/HoH gamers.")]
[assembly: AssemblyFileVersion("2.1.1.0")]
[assembly: AssemblyInformationalVersion("2.1.1+4f99db70e06b5ed7de3e4263d547e4e95c0494f8")]
[assembly: AssemblyProduct("Subtitles")]
[assembly: AssemblyTitle("Subtitles")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.1.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 Subtitles
{
public class Constants
{
public static readonly int DefaultExpireSubtitleTimeMs = 5000;
public static readonly int DefaultVisibleSubtitleLines = 3;
public static readonly string HtmlLineBreakTag = "<br>";
public static readonly string PlayerScreenGUIName = "Systems/UI/Canvas/Panel/GameObject/PlayerScreen";
}
[BepInPlugin("JustJelly.Subtitles", "Subtitles", "2.1.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
private const string pluginGuid = "JustJelly.Subtitles";
private const string pluginName = "Subtitles";
private const string pluginVersion = "2.1.1";
private Harmony harmony;
public static Plugin Instance;
public static ManualLogSource ManualLogSource;
public SubtitleList subtitles = new SubtitleList();
public ConfigEntry<float> minimumAudibleVolume;
public ConfigEntry<bool> logSoundNames;
private void Awake()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Expected O, but got Unknown
if (Instance == null)
{
Instance = this;
}
ManualLogSource = Logger.CreateLogSource("JustJelly.Subtitles");
ManualLogSource.LogInfo((object)"Subtitles 2.1.1 loaded!");
minimumAudibleVolume = ((BaseUnityPlugin)this).Config.Bind<float>("\u200bOptions", "MinimumAudibleVolume", 12f, "The minimum volume this mod determines is audible. Scale of 0-100. Any sound heard above this volume will be displayed on subtitles, any sound below will not.");
logSoundNames = ((BaseUnityPlugin)this).Config.Bind<bool>("Contributors/Developers", "LogSoundNames", false, "Whether the mod should log the names of sounds. Only valuable if trying to add more subtitles / localization.");
harmony = new Harmony("JustJelly.Subtitles");
harmony.PatchAll();
}
}
public class SubtitleList : IList<string>, ICollection<string>, IEnumerable<string>, IEnumerable
{
private volatile List<Tuple<DateTime, string>> collection = new List<Tuple<DateTime, string>>();
private readonly Timer timer;
private readonly TimeSpan expiration;
public string this[int index]
{
get
{
return collection[index].Item2;
}
set
{
collection[index] = new Tuple<DateTime, string>(DateTime.Now, value);
}
}
public int Count => collection.Count;
public bool IsSynchronized => false;
public bool IsReadOnly => false;
public SubtitleList()
{
timer = new Timer
{
Interval = 1000.0
};
timer.Elapsed += RemoveExpiredElements;
timer.Start();
expiration = TimeSpan.FromMilliseconds(Constants.DefaultExpireSubtitleTimeMs);
}
private void RemoveExpiredElements(object sender, EventArgs e)
{
for (int num = collection.Count - 1; num >= 0; num--)
{
if (DateTime.Now - collection[num].Item1 >= expiration)
{
collection.RemoveAt(num);
}
}
}
public List<string> TakeLast(int number)
{
return (from element in collection
where DateTime.Now >= element.Item1
orderby element.Item1
select element.Item2).TakeLast(number).ToList();
}
public IEnumerator<string> GetEnumerator()
{
return collection.Select((Tuple<DateTime, string> x) => x.Item2).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return collection.Select((Tuple<DateTime, string> x) => x.Item2).GetEnumerator();
}
public void Add(string item)
{
collection.Add(new Tuple<DateTime, string>(DateTime.Now, item));
}
public void Add(string item, float seconds)
{
collection.Add(new Tuple<DateTime, string>(DateTime.Now.AddSeconds(seconds), item));
}
public void CopyTo(string[] array, int index)
{
for (int i = 0; i < collection.Count; i++)
{
array[i + index] = collection[i].Item2;
}
}
public bool Remove(string item)
{
bool result = Contains(item);
for (int num = collection.Count - 1; num >= 0; num--)
{
if (collection[num].Item2 == item)
{
collection.RemoveAt(num);
}
}
return result;
}
public void RemoveAt(int i)
{
collection.RemoveAt(i);
}
public bool Contains(string item)
{
for (int i = 0; i < collection.Count; i++)
{
if (collection[i].Item2 == item)
{
return true;
}
}
return false;
}
public void Insert(int index, string item)
{
collection.Insert(index, new Tuple<DateTime, string>(DateTime.Now, item));
}
public int IndexOf(string item)
{
for (int i = 0; i < collection.Count; i++)
{
if (collection[i].Item2 == item)
{
return i;
}
}
return -1;
}
public void Clear()
{
collection.Clear();
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "Subtitles";
public const string PLUGIN_NAME = "Subtitles";
public const string PLUGIN_VERSION = "2.1.1";
}
}
namespace Subtitles.Patches
{
[HarmonyPatch(typeof(AudioSource))]
public class AudioSourcePatch
{
[HarmonyPrefix]
[HarmonyPatch("PlayOneShotHelper", new Type[]
{
typeof(AudioSource),
typeof(AudioClip),
typeof(float)
})]
public static void PlayOneShotHelper_Prefix(AudioSource source, ref AudioClip clip, float volumeScale)
{
if (AudibleDistanceLib.IsInWithinAudiableDistance(GameNetworkManager.Instance, source, volumeScale, Plugin.Instance.minimumAudibleVolume.Value))
{
AddSubtitle(clip);
}
}
[HarmonyPrefix]
[HarmonyPatch("Play", new Type[] { typeof(double) })]
public static void PlayDelayed_Prefix(AudioSource __instance)
{
if (!((Object)(object)__instance.clip == (Object)null) && AudibleDistanceLib.IsInWithinAudiableDistance(GameNetworkManager.Instance, __instance, __instance.volume, Plugin.Instance.minimumAudibleVolume.Value))
{
AddSubtitle(__instance.clip);
}
}
[HarmonyPrefix]
[HarmonyPatch("Play", new Type[] { })]
public static void Play_Prefix(AudioSource __instance)
{
if (!((Object)(object)__instance.clip == (Object)null) && AudibleDistanceLib.IsInWithinAudiableDistance(GameNetworkManager.Instance, __instance, __instance.volume, Plugin.Instance.minimumAudibleVolume.Value))
{
AddSubtitle(__instance.clip);
}
}
private static void AddSubtitle(AudioClip clip)
{
if (((clip != null) ? ((Object)clip).name : null) == null)
{
return;
}
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(((Object)clip).name);
if (SubtitlesAPI.Localization.Translations.TryGetValue(fileNameWithoutExtension, out var value))
{
if (Plugin.Instance.logSoundNames.Value)
{
Plugin.ManualLogSource.LogInfo((object)("Found translation for " + fileNameWithoutExtension + "!"));
}
Plugin.Instance.subtitles.Add(FormatSoundTranslation(value));
return;
}
if (SubtitlesAPI.Localization.DialogueTranslations.TryGetValue(fileNameWithoutExtension, out List<(float, string)> value2))
{
if (Plugin.Instance.logSoundNames.Value)
{
Plugin.ManualLogSource.LogInfo((object)("Found dialogue translation for " + fileNameWithoutExtension + "!"));
}
{
foreach (var (seconds, translation) in value2)
{
Plugin.Instance.subtitles.Add(ForamtDialogueTranslation(translation), seconds);
}
return;
}
}
if (Plugin.Instance.logSoundNames.Value)
{
Plugin.ManualLogSource.LogInfo((object)("No translation for " + fileNameWithoutExtension + "."));
}
}
private static string FormatSoundTranslation(string translation)
{
if (translation.StartsWith("[") && translation.EndsWith("]"))
{
return "<color=yellow>" + translation + "</color>";
}
return "<color=yellow>[" + translation + "]</color>";
}
private static string ForamtDialogueTranslation(string translation)
{
if (translation.StartsWith("[") && translation.EndsWith("]"))
{
return FormatSoundTranslation(translation);
}
return "<color=green>" + translation + "</color>";
}
}
[HarmonyPatch(typeof(HUDManager))]
public class HUDManagerPatch
{
private static TextMeshProUGUI subtitleGUItext;
[HarmonyPostfix]
[HarmonyPatch("Awake")]
private static void Awake_Postfix(ref HUDManager __instance)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("SubtitlesGUI");
val.AddComponent<RectTransform>();
TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
RectTransform rectTransform = ((TMP_Text)val2).rectTransform;
((Transform)rectTransform).SetParent(GameObject.Find(Constants.PlayerScreenGUIName).transform, false);
rectTransform.sizeDelta = new Vector2(600f, 200f);
rectTransform.anchoredPosition = new Vector2(0f, -125f);
((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
((TMP_Text)val2).font = ((TMP_Text)__instance.controlTipLines[0]).font;
((TMP_Text)val2).fontSize = 14f;
subtitleGUItext = val2;
}
[HarmonyPostfix]
[HarmonyPatch("Update")]
private static void Update_Postfix()
{
((TMP_Text)subtitleGUItext).text = GetLatestSubtitles();
}
private static string GetLatestSubtitles()
{
StringBuilder stringBuilder = new StringBuilder();
IList<string> list = Plugin.Instance.subtitles.TakeLast(Constants.DefaultVisibleSubtitleLines).ToList();
string value = string.Empty;
foreach (string item in list)
{
stringBuilder.Append(value);
stringBuilder.Append(item);
value = Constants.HtmlLineBreakTag;
}
return stringBuilder.ToString();
}
}
}