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 BetterTombstoneHints v1.0.0
BetterTombstoneHints.dll
Decompiled 3 days agousing 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; using BepInEx; using BetterTombstoneHints.Features; using BetterTombstoneHints.Infrastructure; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("BetterTombstoneHints")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+808f97ed19ef8b65c5b49ca9c6bfee53c795e7ec")] [assembly: AssemblyProduct("BetterTombstoneHints")] [assembly: AssemblyTitle("BetterTombstoneHints")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 BetterTombstoneHints { [BepInPlugin("JevMods.BetterTombstoneHints", "BetterTombstoneHints", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "JevMods.BetterTombstoneHints"; public const string PluginName = "BetterTombstoneHints"; private IFeature[] _features; private Harmony _harmony; private void Awake() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown GameEvents events = (GameEvents.Instance = new GameEvents()); _features = CreateFeatures(events); IFeature[] features = _features; for (int i = 0; i < features.Length; i++) { features[i].Enable(); } _harmony = new Harmony("JevMods.BetterTombstoneHints"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if (_features != null) { IFeature[] features = _features; for (int i = 0; i < features.Length; i++) { features[i].Disable(); } } GameEvents.Instance = null; } private static IFeature[] CreateFeatures(IGameEvents events) { TombstoneNotes notes = new TombstoneNotes(); NoteRenderer renderer = new NoteRenderer(new Translator(new EmbeddedTranslations()), new GameLanguage()); return new IFeature[3] { new NoteWritingFeature(events, new LocalPlayerDeath(), notes), new NoteDisplayFeature(events, notes, renderer), new NameplateFeature(events, new TombstoneNameplates(notes, renderer)) }; } } internal static class BuildInfo { public const string Version = "1.0.0"; } } namespace BetterTombstoneHints.Patches { internal static class TombStonePatches { [HarmonyPatch(typeof(TombStone), "Setup")] private static class Setup { private static void Postfix(TombStone __instance) { GameEvents.Instance?.RaiseTombstoneCreated(__instance); } } [HarmonyPatch(typeof(TombStone), "Start")] private static class Start { private static void Postfix(TombStone __instance) { GameEvents.Instance?.RaiseTombstoneStarted(__instance); } } [HarmonyPatch(typeof(TombStone), "GetHoverText")] private static class GetHoverText { private static void Postfix(TombStone __instance, ref string __result) { GameEvents.Instance?.RaiseHoverTextBuilt(__instance, ref __result); } } } } namespace BetterTombstoneHints.Infrastructure { public sealed class EmbeddedTranslations : ITranslationSource { public string Read(string language) { using Stream stream = typeof(EmbeddedTranslations).Assembly.GetManifestResourceStream(language + ".txt"); if (stream == null) { return null; } using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); return streamReader.ReadToEnd(); } } public sealed class GameEvents : IGameEvents { internal static GameEvents Instance { get; set; } public event Action<TombStone> TombstoneCreated; public event Action<TombStone> TombstoneStarted; public event HoverTextBuiltHandler HoverTextBuilt; internal void RaiseTombstoneCreated(TombStone tombstone) { this.TombstoneCreated?.Invoke(tombstone); } internal void RaiseTombstoneStarted(TombStone tombstone) { this.TombstoneStarted?.Invoke(tombstone); } internal void RaiseHoverTextBuilt(TombStone tombstone, ref string text) { this.HoverTextBuilt?.Invoke(tombstone, ref text); } } public sealed class GameLanguage : IGameLanguage { private const string DefaultLanguage = "English"; public string Current { get { Localization instance = Localization.instance; return ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English"; } } public string Localize(string text, params string[] words) { if (Localization.instance == null) { return text; } return Localization.instance.Localize(text, words); } } public sealed class LocalPlayerDeath : IDeathSource { public DeathNote Latest() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_004a: Invalid comparison between Unknown and I4 Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)EnvMan.instance == (Object)null) { return null; } int currentDay = EnvMan.instance.GetCurrentDay(); HitData lastHit = ((Character)localPlayer).m_lastHit; if (lastHit == null) { return new DeathNote("died", currentDay); } HitType hitType = lastHit.m_hitType; if (hitType - 1 <= 1) { return SlainBy(lastHit.GetAttacker(), currentDay); } return new DeathNote(CauseKeys.ForHitType(((object)Unsafe.As<HitType, HitType>(ref lastHit.m_hitType)/*cast due to .constrained prefix*/).ToString()), currentDay); } private static DeathNote SlainBy(Character attacker, int day) { if ((Object)(object)attacker == (Object)null) { return new DeathNote("slain", day); } Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null) { return new DeathNote("slain_by", val.GetPlayerName(), day); } return new DeathNote(attacker.IsBoss() ? "slain_by" : "slain_by_creature", attacker.m_name, day); } } public sealed class TombstoneNameplate : MonoBehaviour { private const float RefreshSeconds = 0.5f; private TombStone _tombstone; private ITombstoneNotes _notes; private INoteRenderer _renderer; private TextWrappingModes _wrappingMode; private float _nextRefresh; public void Initialize(TombStone tombstone, ITombstoneNotes notes, INoteRenderer renderer) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) _tombstone = tombstone; _notes = notes; _renderer = renderer; _wrappingMode = tombstone.m_worldText.textWrappingMode; tombstone.m_worldText.textWrappingMode = (TextWrappingModes)0; } private void Update() { if (!(Time.time < _nextRefresh)) { _nextRefresh = Time.time + 0.5f; Show(BuildText()); } } private void OnDestroy() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_tombstone != (Object)null) { _tombstone.m_worldText.textWrappingMode = _wrappingMode; Show(_tombstone.GetOwnerName()); } } private string BuildText() { string ownerName = _tombstone.GetOwnerName(); DeathNote deathNote = _notes.Read(_tombstone); if (deathNote != null) { return ownerName + "\n" + _renderer.Render(deathNote); } return ownerName; } private void Show(string text) { if (_tombstone.m_worldText.text != text) { _tombstone.m_worldText.text = text; } } } public sealed class TombstoneNameplates : INameplates { private readonly ITombstoneNotes _notes; private readonly INoteRenderer _renderer; private readonly List<TombstoneNameplate> _attached = new List<TombstoneNameplate>(); public TombstoneNameplates(ITombstoneNotes notes, INoteRenderer renderer) { _notes = notes; _renderer = renderer; } public void Attach(TombStone tombstone) { if (!((Object)(object)((Component)tombstone).GetComponent<TombstoneNameplate>() != (Object)null)) { _attached.RemoveAll((TombstoneNameplate nameplate) => (Object)(object)nameplate == (Object)null); TombstoneNameplate tombstoneNameplate = ((Component)tombstone).gameObject.AddComponent<TombstoneNameplate>(); tombstoneNameplate.Initialize(tombstone, _notes, _renderer); _attached.Add(tombstoneNameplate); } } public void DetachAll() { foreach (TombstoneNameplate item in _attached) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _attached.Clear(); } } public sealed class TombstoneNotes : ITombstoneNotes { private static readonly int CauseKey = StringExtensionMethods.GetStableHashCode("JevMods_Cause"); private static readonly int KillerKey = StringExtensionMethods.GetStableHashCode("JevMods_Killer"); private static readonly int DayKey = StringExtensionMethods.GetStableHashCode("JevMods_Day"); public void Write(TombStone tombstone, DeathNote note) { if (tombstone.m_nview.IsValid()) { ZDO zDO = tombstone.m_nview.GetZDO(); zDO.Set(CauseKey, note.Cause); zDO.Set(KillerKey, note.Killer); zDO.Set(DayKey, note.Day, false); } } public DeathNote Read(TombStone tombstone) { if (!tombstone.m_nview.IsValid()) { return null; } ZDO zDO = tombstone.m_nview.GetZDO(); string text = zDO.GetString(CauseKey, ""); if (text.Length == 0) { return null; } return new DeathNote(text, zDO.GetString(KillerKey, ""), zDO.GetInt(DayKey, 0)); } } } namespace BetterTombstoneHints.Features { public static class CauseKeys { public const string Died = "died"; public const string Slain = "slain"; public const string SlainBy = "slain_by"; public const string SlainByCreature = "slain_by_creature"; public static readonly IReadOnlyDictionary<string, string> ByHitType = new Dictionary<string, string> { { "Fall", "fall" }, { "Drowning", "drowning" }, { "Burning", "burning" }, { "Freezing", "freezing" }, { "Poisoned", "poisoned" }, { "Water", "water" }, { "Smoke", "smoke" }, { "EdgeOfWorld", "edge_of_world" }, { "Impact", "impact" }, { "Cart", "cart" }, { "Tree", "tree" }, { "Self", "self" }, { "Structural", "structural" }, { "Turret", "turret" }, { "Boat", "boat" }, { "Stalagtite", "stalactite" }, { "Catapult", "catapult" }, { "CinderFire", "cinder_fire" }, { "AshlandsOcean", "ashlands_ocean" }, { "AshlandsLava", "ashlands_lava" }, { "Incinerator", "incinerator" }, { "DrawBridge", "drawbridge" } }; public static string ForHitType(string hitType) { if (!ByHitType.TryGetValue(hitType, out var value)) { return "died"; } return value; } } public sealed class DeathNote { public string Cause { get; } public string Killer { get; } public int Day { get; } public DeathNote(string cause, int day) : this(cause, string.Empty, day) { } public DeathNote(string cause, string killer, int day) { Cause = cause; Killer = killer; Day = day; } } public static class HoverNote { public static string Insert(string hoverText, string note) { if (hoverText.Length == 0 || note.Length == 0) { return hoverText; } int num = hoverText.IndexOf('\n'); if (num >= 0) { return hoverText.Insert(num, "\n" + note); } return hoverText + "\n" + note; } } public delegate void HoverTextBuiltHandler(TombStone tombstone, ref string text); public interface IDeathSource { DeathNote Latest(); } public interface IFeature { void Enable(); void Disable(); } public interface IGameEvents { event Action<TombStone> TombstoneCreated; event Action<TombStone> TombstoneStarted; event HoverTextBuiltHandler HoverTextBuilt; } public interface IGameLanguage { string Current { get; } string Localize(string text, params string[] words); } public interface INameplates { void Attach(TombStone tombstone); void DetachAll(); } public interface INoteRenderer { string Render(DeathNote note); } public interface ITombstoneNotes { void Write(TombStone tombstone, DeathNote note); DeathNote Read(TombStone tombstone); } public interface ITranslationSource { string Read(string language); } public sealed class NameplateFeature : IFeature { private readonly IGameEvents _events; private readonly INameplates _nameplates; public NameplateFeature(IGameEvents events, INameplates nameplates) { _events = events; _nameplates = nameplates; } public void Enable() { _events.TombstoneStarted += _nameplates.Attach; } public void Disable() { _events.TombstoneStarted -= _nameplates.Attach; _nameplates.DetachAll(); } } public sealed class NoteDisplayFeature : IFeature { private readonly IGameEvents _events; private readonly ITombstoneNotes _notes; private readonly INoteRenderer _renderer; public NoteDisplayFeature(IGameEvents events, ITombstoneNotes notes, INoteRenderer renderer) { _events = events; _notes = notes; _renderer = renderer; } public void Enable() { _events.HoverTextBuilt += OnHoverTextBuilt; } public void Disable() { _events.HoverTextBuilt -= OnHoverTextBuilt; } private void OnHoverTextBuilt(TombStone tombstone, ref string text) { DeathNote deathNote = ((text.Length == 0) ? null : _notes.Read(tombstone)); if (deathNote != null) { text = HoverNote.Insert(text, _renderer.Render(deathNote)); } } } public sealed class NoteRenderer : INoteRenderer { private const string DayToken = "$msg_newday"; private const string Separator = ", "; private readonly Translator _translator; private readonly IGameLanguage _language; public NoteRenderer(Translator translator, IGameLanguage language) { _translator = translator; _language = language; } public string Render(DeathNote note) { string text = _language.Localize("$msg_newday", note.Day.ToString(CultureInfo.InvariantCulture)); return RenderCause(note) + ", " + text; } private static string Article(string name) { if (name.Length <= 0 || "AEIOUaeiou".IndexOf(name[0]) < 0) { return "a"; } return "an"; } private string RenderCause(DeathNote note) { string text = _language.Localize(note.Killer); return _translator.Translate(_language.Current, note.Cause).Replace("{a}", Article(text)).Replace("$1", text); } } public sealed class NoteWritingFeature : IFeature { private readonly IGameEvents _events; private readonly IDeathSource _deaths; private readonly ITombstoneNotes _notes; public NoteWritingFeature(IGameEvents events, IDeathSource deaths, ITombstoneNotes notes) { _events = events; _deaths = deaths; _notes = notes; } public void Enable() { _events.TombstoneCreated += OnTombstoneCreated; } public void Disable() { _events.TombstoneCreated -= OnTombstoneCreated; } private void OnTombstoneCreated(TombStone tombstone) { DeathNote deathNote = _deaths.Latest(); if (deathNote != null) { _notes.Write(tombstone, deathNote); } } } public sealed class Translator { private const string FallbackLanguage = "English"; private readonly ITranslationSource _source; private readonly Dictionary<string, Dictionary<string, string>> _tables = new Dictionary<string, Dictionary<string, string>>(); public Translator(ITranslationSource source) { _source = source; } public string Translate(string language, string key) { if (Load(language).TryGetValue(key, out var value) || Load("English").TryGetValue(key, out value)) { return value; } return key; } private static Dictionary<string, string> Parse(string text) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); if (text == null) { return dictionary; } string[] array = text.Split(new char[1] { '\n' }); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num > 0) { string key = text2.Substring(0, num).Trim(); dictionary[key] = text2.Substring(num + 1).Trim(); } } return dictionary; } private Dictionary<string, string> Load(string language) { if (!_tables.TryGetValue(language, out var value)) { value = Parse(_source.Read(language)); _tables[language] = value; } return value; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }