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 ValynAxeClues v0.4.1
plugins/ValynAxeClues.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.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 ValynMods.AxeClues { [BepInPlugin("valyn.mods.axeclues", "Valyn Axe Clues", "0.4.1")] public sealed class AxeCluesPlugin : BaseUnityPlugin { private struct Candidate { public string Key; public Vector3 Position; public float Distance; public string Head; public string Landmark; public bool WaterCrossing; public bool Valid; } internal static AxeCluesPlugin Instance; private static readonly FieldInfo RuneText = AccessTools.Field(typeof(RuneStone), "m_text"); private static readonly FieldInfo CurrentContainer = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly FieldInfo KnownTexts = AccessTools.Field(typeof(Player), "m_knownTexts"); private static readonly FieldInfo TextsDialogField = AccessTools.Field(typeof(InventoryGui), "m_textsDialog"); private static readonly FieldInfo JournalTexts = AccessTools.Field(typeof(TextsDialog), "m_texts"); private static readonly MethodInfo SelectedText = AccessTools.Method(typeof(TextsDialog), "GetSelectedText", (Type[])null, (Type[])null); private static readonly MethodInfo SetupTexts = AccessTools.Method(typeof(TextsDialog), "Setup", (Type[])null, (Type[])null); private static readonly MethodInfo CurrentDay = AccessTools.Method(typeof(EnvMan), "GetCurrentDay", (Type[])null, (Type[])null); private const string JournalKey = "Scratched notes"; private const string RuneClueMarker = "\n\nScratches beneath the old words:\n"; private const string OldRuneClueMarker = "\n\nAnother hand has scratched a trail beneath the old words:\n"; private List<LocationInstance> locations = new List<LocationInstance>(); private readonly HashSet<string> checkedSites = new HashSet<string>(); private readonly HashSet<string> readLids = new HashSet<string>(); private ConfigEntry<float> clueRange; private ConfigEntry<bool> avoidWaterCrossings; private ConfigEntry<string> checkedWorldSites; private ConfigEntry<string> readWorldLids; private ConfigFile worldConfig; private string worldProgressDirectory; private Harmony harmony; private long worldUid = long.MinValue; private float nextEmptyCheck; private float nearEmptySince; private string nearEmptyKey; private string pendingRuneClue; private string pendingRuneSource; private object randomRuneText; private string originalRandomRuneText; private List<Candidate> pendingTrail; private readonly List<Candidate> trail = new List<Candidate>(); private readonly LineRenderer[] arrows = (LineRenderer[])(object)new LineRenderer[3]; private Material arrowMaterial; private float trailStarted = -1f; private float trailDelay = 0.5f; private int trailLastIndex = -1; private bool trailWarning; private bool journalWarning; private bool fontWarning; private MethodInfo guiButton; private Player migratedPlayer; private void Awake() { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown Instance = this; clueRange = ((BaseUnityPlugin)this).Config.Bind<float>("Clues", "Maximum clue distance", 1800f, "Only describe candidate ruins within this straight-line distance in game units."); avoidWaterCrossings = ((BaseUnityPlugin)this).Config.Bind<bool>("Clues", "Avoid water crossings", true, "Only describe ruins connected to the clue source by an approximate dry-land route. Disable to use the old nearest-site behavior."); worldProgressDirectory = Path.Combine(Paths.ConfigPath, "ValynAxeCluesWorlds"); try { MigrateLegacyProgress(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not move existing axe clue progress; mod stopped to preserve it: " + ex)); Instance = null; return; } if (RuneText == null || CurrentContainer == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"RuneStone or InventoryGui fields changed; axe clues cannot start on this game version."); return; } harmony = new Harmony("valyn.mods.axeclues"); harmony.PatchAll(typeof(AxeCluesPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Valyn Axe Clues 0.4.1 ready. Read a Meadows runestone or open a Meadows chest to discover clues."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ClearArrows(); if ((Object)(object)arrowMaterial != (Object)null) { Object.Destroy((Object)(object)arrowMaterial); } Instance = null; } private void Update() { if (Instance != this) { return; } if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { StopTrail(); return; } EnsureWorld(); MigrateNotes(Player.m_localPlayer); UpdateTrail(); if (!(Time.time < nextEmptyCheck) && Ready()) { nextEmptyCheck = Time.time + 2f; CheckEmptyRuin(); } } private void EnsureWorld() { long worldUID = ZNet.instance.GetWorldUID(); if (worldUID != worldUid) { worldUid = worldUID; StopTrail(); nearEmptyKey = null; checkedSites.Clear(); readLids.Clear(); worldConfig = OpenWorldConfig(worldUID); checkedWorldSites = worldConfig.Bind<string>("Progress", "Checked sites", "", "Visited axe-head ruins. Clear to reset search progress for this world."); readWorldLids = worldConfig.Bind<string>("Progress", "Read chest notes", "", "Chests that already revealed a clue. Clear to repeat their notes for testing."); string[] array = checkedWorldSites.Value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in array) { checkedSites.Add(item); } string[] array2 = readWorldLids.Value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item2 in array2) { readLids.Add(item2); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("World " + worldUID + ": " + checkedSites.Count + " checked ruins, " + readLids.Count + " previously read chest notes.")); } } private string WorldProgressPath(long uid) { return Path.Combine(worldProgressDirectory, "world-" + uid.ToString(CultureInfo.InvariantCulture) + ".dat"); } private ConfigFile OpenWorldConfig(long uid) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Directory.CreateDirectory(worldProgressDirectory); return new ConfigFile(WorldProgressPath(uid), false); } private static bool LegacyWorldEntry(ConfigDefinition definition, out long uid, out string section) { uid = 0L; section = null; if (!definition.Section.StartsWith("World ", StringComparison.Ordinal)) { return false; } string text = definition.Section.Substring("World ".Length); bool flag = text.EndsWith(" rune scratches", StringComparison.Ordinal); if (flag) { text = text.Substring(0, text.Length - " rune scratches".Length); } if (!long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out uid)) { return false; } if (flag && definition.Key.StartsWith("rune:", StringComparison.Ordinal)) { section = "Rune scratches"; } else if (!flag && (definition.Key == "Checked sites" || definition.Key == "Read chest notes")) { section = "Progress"; } return section != null; } private void MigrateLegacyProgress() { HashSet<ConfigDefinition> hashSet = new HashSet<ConfigDefinition>(((BaseUnityPlugin)this).Config.Keys); if (!(AccessTools.Field(typeof(ConfigFile), "<OrphanedEntries>k__BackingField")?.GetValue(((BaseUnityPlugin)this).Config) is Dictionary<ConfigDefinition, string> dictionary)) { throw new InvalidOperationException("Cannot read older world entries from BepInEx config."); } foreach (ConfigDefinition key in dictionary.Keys) { hashSet.Add(key); } Dictionary<long, List<ConfigDefinition>> dictionary2 = new Dictionary<long, List<ConfigDefinition>>(); foreach (ConfigDefinition item in hashSet) { if (LegacyWorldEntry(item, out var uid, out var _)) { if (!dictionary2.TryGetValue(uid, out var value)) { dictionary2.Add(uid, value = new List<ConfigDefinition>()); } value.Add(item); } } if (dictionary2.Count == 0) { return; } bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { foreach (KeyValuePair<long, List<ConfigDefinition>> item2 in dictionary2) { ConfigFile val = OpenWorldConfig(item2.Key); long uid2; foreach (ConfigDefinition item3 in item2.Value) { LegacyWorldEntry(item3, out uid2, out var section2); string value2 = ((BaseUnityPlugin)this).Config.Bind<string>(item3.Section, item3.Key, "", "Previous axe clue progress").Value; ConfigEntry<string> val2 = val.Bind<string>(section2, item3.Key, "", "World-specific axe clue progress"); if (string.IsNullOrEmpty(val2.Value) && !string.IsNullOrEmpty(value2)) { val2.Value = value2; } } val.Save(); foreach (ConfigDefinition item4 in item2.Value) { ((BaseUnityPlugin)this).Config.Remove(item4); } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj = new string[5] { "Moved ", item2.Value.Count.ToString(), " progress entries for world ", null, null }; uid2 = item2.Key; obj[3] = uid2.ToString(); obj[4] = " out of the main config."; logger.LogInfo((object)string.Concat(obj)); } ((BaseUnityPlugin)this).Config.Save(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } internal static long BeforeWorldDeleted(string name, object source) { AxeCluesPlugin instance = Instance; if (instance == null) { return long.MinValue; } try { foreach (World world in SaveSystem.GetWorldList()) { if (world.m_worldName == name && object.Equals(AccessTools.Field(typeof(World), "m_fileSource")?.GetValue(world), source)) { return world.m_uid; } } } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Cannot identify deleted world: " + ex.Message)); } return long.MinValue; } internal static void AfterWorldDeleted(long uid) { AxeCluesPlugin instance = Instance; if (instance == null || uid == long.MinValue) { return; } try { foreach (World world in SaveSystem.GetWorldList()) { if (world.m_uid == uid) { return; } } string path = instance.WorldProgressPath(uid); if (File.Exists(path)) { File.Delete(path); } ((BaseUnityPlugin)instance).Logger.LogInfo((object)("Removed axe clue progress for deleted world " + uid + ".")); } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Could not clean deleted world progress: " + ex.Message)); } } private bool Ready() { return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.LocationsGenerated; } private bool IsMeadows(Vector3 point) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 return WorldGenerator.instance != null && (int)WorldGenerator.instance.GetBiome(point) == 1; } private static bool Carries(string prefab) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == prefab) { return true; } } return false; } private Candidate FindCandidate(bool curious, Vector3 origin, LandReachability land = null, bool preferLand = true) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) string text = (curious ? "WoodHouse6" : "WoodHouse2"); Candidate candidate = default(Candidate); Candidate candidate2 = default(Candidate); float num = float.MaxValue; float num2 = float.MaxValue; locations.Clear(); if (!ZoneSystem.instance.FindLocations(text, ref locations)) { return candidate; } foreach (LocationInstance location in locations) { Vector3 position = location.m_position; string text2 = Key(text, position); if (checkedSites.Contains(text2)) { continue; } float num3 = HorizontalDistance(origin, position); if (num3 > Mathf.Max(100f, clueRange.Value) || (num3 >= num && num3 >= num2)) { continue; } bool flag = land?.Reaches(position) ?? true; float num4 = BroadWaterLength(origin, position); bool flag2 = !flag || num4 >= 48f; if (!(flag2 ? (num3 >= num2) : (num3 >= num))) { Candidate candidate3 = new Candidate { Key = text2, Position = position, Distance = num3, Valid = true, WaterCrossing = flag2, Head = (curious ? "Curious" : "Mysterious"), Landmark = (curious ? "a tall broken timber house" : "a low abandoned timber house") }; if (flag2) { num2 = num3; candidate2 = candidate3; } else { num = num3; candidate = candidate3; } } } if (!preferLand && candidate2.Valid && (!candidate.Valid || candidate2.Distance < candidate.Distance)) { return candidate2; } return candidate.Valid ? candidate : candidate2; } private string ComposeClue(Vector3 origin, out List<Candidate> targets) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) targets = new List<Candidate>(); if (!Ready()) { return null; } bool flag = Carries("AxeHead1"); bool flag2 = Carries("AxeHead2"); if (flag && flag2) { return null; } List<string> list = new List<string>(); LandReachability land = (avoidWaterCrossings.Value ? new LandReachability(origin, Mathf.Max(100f, clueRange.Value)) : null); if (!flag2) { AddLine(curious: false, origin, list, targets, land); } if (!flag) { AddLine(curious: true, origin, list, targets, land); } return (list.Count == 0) ? null : string.Join("\n", list); } private void AddLine(bool curious, Vector3 origin, List<string> lines, List<Candidate> targets, LandReachability land) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) Candidate item = FindCandidate(curious, origin, land, avoidWaterCrossings.Value); if (item.Valid) { targets.Add(item); int num = Mathf.Max(100, Mathf.RoundToInt(item.Distance / 100f) * 100); lines.Add("\"" + num + " paces " + Direction(origin, item.Position) + " — " + (curious ? "tall timbers" : "low timbers") + (item.WaterCrossing ? ", across the water" : "") + "\""); ((BaseUnityPlugin)this).Logger.LogInfo((object)(item.Head + " clue: source " + Point(origin) + ", target " + item.Key + " at " + Point(item.Position) + ", " + Mathf.RoundToInt(item.Distance) + " paces; longest direct water stretch " + Mathf.RoundToInt(BroadWaterLength(origin, item.Position)) + " paces; " + (item.WaterCrossing ? "water crossing indicated" : "land route indicated") + "; world UID " + worldUid + ".")); } } private static float BroadWaterLength(Vector3 from, Vector3 to) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (WorldGenerator.instance == null) { return 0f; } float num = HorizontalDistance(from, to); int num2 = Mathf.Max(1, Mathf.CeilToInt(num / 8f)); float num3 = 0f; float num4 = 0f; for (int i = 1; i < num2; i++) { float num5 = (float)i / (float)num2; float num6 = Mathf.Lerp(from.x, to.x, num5); float num7 = Mathf.Lerp(from.z, to.z, num5); if (WorldGenerator.instance.GetHeight(num6, num7) * 200f < 30.3f) { num4 += num / (float)num2; num3 = Mathf.Max(num3, num4); } else { num4 = 0f; } } return num3; } internal static void BeforeRune(RuneStone stone, Humanoid user, bool hold, out string original) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) original = null; AxeCluesPlugin instance = Instance; if (instance == null || hold || (Object)(object)user != (Object)(object)Player.m_localPlayer || !instance.Ready() || !instance.IsMeadows(((Component)stone).transform.position)) { return; } instance.EnsureWorld(); instance.MigrateNotes(Player.m_localPlayer); string text = Key("rune", ((Component)stone).transform.position); ConfigEntry<string> val = instance.worldConfig.Bind<string>("Rune scratches", text, "", "Clue fixed when this runestone was first read. Clear only to reroll this stone."); List<Candidate> targets; string text2 = DecodeRune(val.Value, out targets); if (text2 == null) { text2 = instance.ComposeClue(((Component)stone).transform.position, out targets); if (!string.IsNullOrEmpty(text2)) { val.Value = EncodeRune(text2, targets); instance.worldConfig.Save(); } } if (!string.IsNullOrEmpty(text2)) { instance.pendingTrail = targets; instance.pendingRuneSource = text; instance.pendingRuneClue = "\n\nScratches beneath the old words:\n" + text2; original = (string)RuneText.GetValue(stone); RuneText.SetValue(stone, original + "\n\n<size=75%>Scratches beneath the old words:\n" + text2 + "</size>"); } } internal static void AfterRune(RuneStone stone, string original) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (original != null) { RuneText.SetValue(stone, original); } AxeCluesPlugin instance = Instance; if (instance != null) { if (original != null && instance.pendingTrail != null) { instance.QueueTrail(instance.pendingTrail, chest: false); instance.AppendNote(Player.m_localPlayer, "Runestone " + Point(((Component)stone).transform.position), instance.pendingRuneSource, instance.pendingRuneClue.Substring("\n\nScratches beneath the old words:\n".Length)); } if (instance.randomRuneText != null) { AccessTools.Field(instance.randomRuneText.GetType(), "m_text")?.SetValue(instance.randomRuneText, instance.originalRandomRuneText); instance.randomRuneText = null; instance.originalRandomRuneText = null; } instance.pendingRuneClue = null; instance.pendingRuneSource = null; instance.pendingTrail = null; } } internal static void AddRandomRuneClue(object randomText) { AxeCluesPlugin instance = Instance; if (instance != null && randomText != null && instance.pendingRuneClue != null) { FieldInfo fieldInfo = AccessTools.Field(randomText.GetType(), "m_text"); if (!(fieldInfo == null)) { instance.randomRuneText = randomText; instance.originalRandomRuneText = (string)fieldInfo.GetValue(randomText); fieldInfo.SetValue(randomText, instance.originalRandomRuneText + "\n\n<size=75%>Scratches beneath the old words:\n" + instance.pendingRuneClue.Substring("\n\nScratches beneath the old words:\n".Length) + "</size>"); } } } private static string EncodeRune(string clue, List<Candidate> targets) { List<string> list = new List<string> { Convert.ToBase64String(Encoding.UTF8.GetBytes(clue)) }; foreach (Candidate target in targets) { list.Add(target.Head + "," + target.Position.x.ToString("R", CultureInfo.InvariantCulture) + "," + target.Position.z.ToString("R", CultureInfo.InvariantCulture)); } return string.Join("|", list); } private static string DecodeRune(string saved, out List<Candidate> targets) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) targets = new List<Candidate>(); if (string.IsNullOrEmpty(saved)) { return null; } try { string[] array = saved.Split('|'); string result = Encoding.UTF8.GetString(Convert.FromBase64String(array[0])); for (int i = 1; i < array.Length; i++) { string[] array2 = array[i].Split(','); targets.Add(new Candidate { Head = array2[0], Valid = true, Position = new Vector3(float.Parse(array2[1], CultureInfo.InvariantCulture), 0f, float.Parse(array2[2], CultureInfo.InvariantCulture)) }); } return result; } catch { return null; } } internal static void KeepRuneOutOfJournal(ref string text) { if (Instance?.pendingRuneClue != null && text != null) { int num = text.IndexOf("\n\n<size=75%>Scratches beneath the old words:", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } } } internal static void UsePlainScratchFont(TextViewer viewer) { AxeCluesPlugin instance = Instance; if (instance?.pendingRuneClue == null) { return; } try { object obj = AccessTools.Field(typeof(TextViewer), "m_text")?.GetValue(viewer); object obj2 = AccessTools.Field(typeof(TextViewer), "m_runeText")?.GetValue(viewer); object obj3 = obj?.GetType().GetProperty("font")?.GetValue(obj); if (obj2 == null) { return; } Object val = (Object)((obj3 is Object) ? obj3 : null); if (val == null) { return; } Type type = obj.GetType().Assembly.GetType("TMPro.MaterialReferenceManager"); AccessTools.Method(type, "AddFontAsset", (Type[])null, (Type[])null)?.Invoke(null, new object[1] { obj3 }); PropertyInfo property = obj2.GetType().GetProperty("text"); if (property?.GetValue(obj2) is string text) { int num = text.IndexOf("<size=75%>Scratches beneath the old words:", StringComparison.Ordinal); if (num >= 0) { property.SetValue(obj2, text.Substring(0, num) + "<font=\"" + val.name + "\">" + text.Substring(num).Replace("</size>", "</size></font>")); } } } catch (Exception ex) { if (!instance.fontWarning) { instance.fontWarning = true; ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Plain scratch font unavailable: " + ex.Message)); } } } internal static Container BeforeInventoryHide(InventoryGui gui) { return (Container)((Instance == null) ? null : /*isinst with value type is only supported in some contexts*/); } internal static void AfterInventoryHide(Container chest) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) AxeCluesPlugin instance = Instance; if (instance == null || (Object)(object)chest == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } instance.EnsureWorld(); if (!instance.Ready() || !instance.IsMeadows(((Component)chest).transform.position)) { return; } Vector3 position = ((Component)chest).transform.position; instance.MarkNearbyRuins(position); string text = Key("lid", position); if (!instance.readLids.Contains(text)) { List<Candidate> targets; string text2 = instance.ComposeClue(position, out targets); if (!string.IsNullOrEmpty(text2)) { instance.readLids.Add(text); instance.readWorldLids.Value = string.Join(";", instance.readLids); instance.worldConfig.Save(); instance.QueueTrail(targets, chest: true); string text3 = "Scratches inside the chest lid:\n" + text2; instance.AppendNote(Player.m_localPlayer, "Chest " + Point(position), text, text2); ((Character)Player.m_localPlayer).Message((MessageType)2, text3, 0, (Sprite)null, false); } } } private void MarkNearbyRuins(Vector3 point) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) bool flag = false; string[] array = new string[2] { "WoodHouse2", "WoodHouse6" }; foreach (string text in array) { locations.Clear(); ZoneSystem.instance.FindLocations(text, ref locations); foreach (LocationInstance location in locations) { if (HorizontalDistance(point, location.m_position) < 20f) { flag |= checkedSites.Add(Key(text, location.m_position)); } } } if (flag) { SaveChecked(); } } private void CheckEmptyRuin() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)Player.m_localPlayer).transform.position; Candidate candidate = default(Candidate); bool[] array = new bool[2] { false, true }; foreach (bool curious in array) { Candidate candidate2 = FindCandidate(curious, position, null, preferLand: false); if (candidate2.Valid && candidate2.Distance < 12f && (!candidate.Valid || candidate2.Distance < candidate.Distance)) { candidate = candidate2; } } if (!candidate.Valid) { nearEmptyKey = null; } else if (candidate.Key != nearEmptyKey) { nearEmptyKey = candidate.Key; nearEmptySince = Time.time; } else { if (Time.time - nearEmptySince < 8f) { return; } Container[] array2 = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array2) { if (HorizontalDistance(((Component)val).transform.position, candidate.Position) < 18f) { return; } } checkedSites.Add(candidate.Key); SaveChecked(); nearEmptyKey = null; ((BaseUnityPlugin)this).Logger.LogInfo((object)("No chest found at " + candidate.Key + " at " + Point(candidate.Position) + "; marked checked.")); ((Character)Player.m_localPlayer).Message((MessageType)2, "Only empty timbers remain here. Perhaps another carved trail will point onward.", 0, (Sprite)null, false); } } private void SaveChecked() { checkedWorldSites.Value = string.Join(";", checkedSites); worldConfig.Save(); } private void QueueTrail(List<Candidate> targets, bool chest) { StopTrail(); trail.AddRange(targets); trailDelay = (chest ? 5f : 0.5f); trailStarted = -1f; trailLastIndex = -1; } private void StopTrail() { trail.Clear(); trailStarted = -1f; trailLastIndex = -1; ClearArrows(); } private void ClearArrows() { for (int i = 0; i < arrows.Length; i++) { if ((Object)(object)arrows[i] != (Object)null) { Object.Destroy((Object)(object)((Component)arrows[i]).gameObject); } arrows[i] = null; } } private void UpdateTrail() { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) if (trail.Count == 0) { return; } if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible()) { ClearArrows(); return; } if (trailStarted < 0f) { trailStarted = Time.time + trailDelay; } float num = Time.time - trailStarted; if (num < 0f) { return; } int num2 = Mathf.FloorToInt(num / 7f); if (num2 >= trail.Count) { StopTrail(); } else { if (!EnsureArrows()) { return; } if (num2 != trailLastIndex) { trailLastIndex = num2; ((Character)Player.m_localPlayer).Message((MessageType)2, "A faint trail traces scratch " + (num2 + 1) + ".", 0, (Sprite)null, false); } Vector3 position = ((Component)Player.m_localPlayer).transform.position; Vector3 val = trail[num2].Position - position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { ClearArrows(); return; } ((Vector3)(ref val)).Normalize(); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0f - val.z, 0f, val.x); float num3 = 7f - num % 7f; float num4 = Mathf.Clamp01(num3 / 1.4f); Color val3 = ((num2 == 0) ? new Color(0.25f, 0.95f, 0.9f, num4) : new Color(1f, 0.75f, 0.32f, num4)); for (int i = 0; i < arrows.Length; i++) { LineRenderer val4 = arrows[i]; Color startColor = (val4.endColor = val3); val4.startColor = startColor; Vector3 val6 = position + val * (4f + (float)i * 3.5f); Vector3 val7 = val6 - val * 1.15f; val4.SetPosition(0, Ground(val7 + val2 * 0.65f)); val4.SetPosition(1, Ground(val6)); val4.SetPosition(2, Ground(val7 - val2 * 0.65f)); } } } private Vector3 Ground(Vector3 point) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) float num = default(float); if (ZoneSystem.instance.GetGroundHeight(point, ref num)) { point.y = num + 0.24f; } else { point.y = ((Component)Player.m_localPlayer).transform.position.y + 0.12f; } return point; } private bool EnsureArrows() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown if ((Object)(object)arrows[0] != (Object)null) { return true; } Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color"); if ((Object)(object)val == (Object)null) { if (!trailWarning) { trailWarning = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"No shader available for the clue trail."); } StopTrail(); return false; } if ((Object)(object)arrowMaterial == (Object)null) { arrowMaterial = new Material(val); } for (int i = 0; i < arrows.Length; i++) { GameObject val2 = new GameObject("Axe clue fleeting trail"); val2.layer = 2; LineRenderer val3 = val2.AddComponent<LineRenderer>(); ((Renderer)val3).sharedMaterial = arrowMaterial; val3.useWorldSpace = true; val3.positionCount = 3; float startWidth = (val3.endWidth = 0.12f); val3.startWidth = startWidth; arrows[i] = val3; } return true; } private void AppendNote(Player player, string source, string id, string clue, bool old = false) { if (!(KnownTexts?.GetValue(player) is Dictionary<string, string> dictionary) || string.IsNullOrEmpty(clue)) { return; } string value; string text = (dictionary.TryGetValue("Scratched notes", out value) ? value : ""); string text2 = "{" + worldUid + ":" + id + "}"; if (!text.Contains(text2)) { int num = (((Object)(object)EnvMan.instance != (Object)null && CurrentDay != null) ? ((int)CurrentDay.Invoke(EnvMan.instance, null)) : 0); float num2 = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDayFraction() : 0f); int num3 = Mathf.FloorToInt(Mathf.Repeat(num2, 1f) * 1440f); string text3 = (old ? "Earlier" : ("Day " + num + " · " + (num3 / 60).ToString("00") + ":" + (num3 % 60).ToString("00"))); string text4 = "<size=72%><color=#BEB6A5>" + text3 + " · " + source + "</color></size>\n" + clue.Trim() + "<size=1%><color=#00000000>" + text2 + "</color></size>"; string text5 = ((text.Length == 0) ? text4 : (text + "\n\n" + text4)); if (text.Length == 0) { player.AddKnownText("Scratched notes", text5); } else { dictionary["Scratched notes"] = text5; } } } private void MigrateNotes(Player player) { if ((Object)(object)player == (Object)(object)migratedPlayer || !(KnownTexts?.GetValue(player) is Dictionary<string, string> dictionary)) { return; } migratedPlayer = player; List<string> list = new List<string>(); foreach (KeyValuePair<string, string> item in dictionary) { if (item.Key.StartsWith("Trail note ", StringComparison.Ordinal) || RuneMarkerIndex(item.Value) >= 0) { list.Add(item.Key); } } foreach (string item2 in list) { string text = dictionary[item2]; if (item2.StartsWith("Trail note ", StringComparison.Ordinal)) { string text2 = text; int num = text2.IndexOf('\n'); if (num >= 0) { text2 = text2.Substring(num + 1); } AppendNote(player, "Chest " + item2.Substring("Trail note ".Length), "legacy:" + item2, text2, old: true); dictionary.Remove(item2); continue; } int num2 = RuneMarkerIndex(text); string text3 = text.Substring(num2).Trim(); int num3 = text3.IndexOf('\n'); if (num3 >= 0) { text3 = text3.Substring(num3 + 1).Trim(); } AppendNote(player, "Runestone · " + item2, "legacy:" + item2, text3, old: true); dictionary[item2] = text.Substring(0, num2); } if (list.Count > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Moved " + list.Count + " older clues into Scratched notes.")); } } private void OnGUI() { //IL_0240: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { return; } object? obj = TextsDialogField?.GetValue(InventoryGui.instance); TextsDialog val = (TextsDialog)((obj is TextsDialog) ? obj : null); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy || JournalTexts == null || SelectedText == null || !(JournalTexts.GetValue(val) is IList { Count: not 0 } list)) { return; } int num = (int)SelectedText.Invoke(val, null); if (num < 0 || num >= list.Count) { return; } Type type = list[num].GetType(); string text = AccessTools.Field(type, "m_topic")?.GetValue(list[num]) as string; if (text != "Scratched notes" || !(KnownTexts?.GetValue(Player.m_localPlayer) is Dictionary<string, string> dictionary) || !dictionary.ContainsKey("Scratched notes")) { return; } if (guiButton == null) { guiButton = Type.GetType("UnityEngine.GUI, UnityEngine.IMGUIModule")?.GetMethod("Button", new Type[2] { typeof(Rect), typeof(string) }); if (guiButton == null) { if (!journalWarning) { journalWarning = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Journal delete button unavailable: Unity IMGUI was not found."); } return; } } Rect val2 = default(Rect); ((Rect)(ref val2))..ctor((float)Screen.width * 0.76f, (float)Screen.height * 0.84f, 210f, 32f); if ((bool)guiButton.Invoke(null, new object[2] { val2, "Clear scratched notes" })) { dictionary.Remove("Scratched notes"); SetupTexts?.Invoke(val, new object[1] { Player.m_localPlayer }); ((Character)Player.m_localPlayer).Message((MessageType)2, "Scratched notes cleared.", 0, (Sprite)null, false); } } private static int RuneMarkerIndex(string content) { int num = content.IndexOf("\n\nScratches beneath the old words:\n", StringComparison.Ordinal); return (num >= 0) ? num : content.IndexOf("\n\nAnother hand has scratched a trail beneath the old words:\n", StringComparison.Ordinal); } private static string Key(string prefix, Vector3 p) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) return prefix + ":" + Mathf.RoundToInt(p.x) + ":" + Mathf.RoundToInt(p.z); } private static string Point(Vector3 p) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) return "(" + Mathf.RoundToInt(p.x) + ", " + Mathf.RoundToInt(p.z) + ")"; } private static float HorizontalDistance(Vector3 a, Vector3 b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } private static string Direction(Vector3 from, Vector3 to) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; float num = Mathf.Atan2(to.x - from.x, to.z - from.z) * 57.29578f; return array[Mathf.RoundToInt((num + 360f) / 45f) % 8]; } } internal sealed class LandReachability { private const float Step = 24f; private const int MaxSamples = 30000; private readonly Vector3 origin; private readonly float maxRange; private readonly Dictionary<long, bool> dry = new Dictionary<long, bool>(); private readonly HashSet<long> connected = new HashSet<long>(); private bool built; internal LandReachability(Vector3 origin, float maxRange) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) this.origin = origin; this.maxRange = Mathf.Min(4000f, maxRange + 180f); } internal bool Reaches(Vector3 target) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (!built) { Build(); } if (WorldGenerator.instance.GetHeight(target.x, target.z) * 200f < 30.3f) { return false; } int num = Mathf.RoundToInt((target.x - origin.x) / 24f); int num2 = Mathf.RoundToInt((target.z - origin.z) / 24f); for (int i = num - 1; i <= num + 1; i++) { for (int j = num2 - 1; j <= num2 + 1; j++) { if (!connected.Contains(Key(i, j))) { continue; } Vector3 val = Point(i, j); if (!(HorizontalDistance(val, target) > 27.599998f)) { Vector3 val2 = (val + target) * 0.5f; if (WorldGenerator.instance.GetHeight(val2.x, val2.z) * 200f >= 30.3f) { return true; } } } } return false; } private void Build() { built = true; if (WorldGenerator.instance == null || !Dry(0, 0)) { return; } Queue<long> queue = new Queue<long>(); long item = Key(0, 0); connected.Add(item); queue.Enqueue(item); int num = Mathf.CeilToInt(maxRange / 24f); while (queue.Count > 0 && dry.Count < 30000) { long num2 = queue.Dequeue(); int num3 = (int)(num2 >> 32); int num4 = (int)num2; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) { continue; } int num5 = num3 + i; int num6 = num4 + j; if (num5 * num5 + num6 * num6 <= num * num) { long item2 = Key(num5, num6); if (!connected.Contains(item2) && Dry(num5, num6) && (i == 0 || j == 0 || (Dry(num3 + i, num4) && Dry(num3, num4 + j)))) { connected.Add(item2); queue.Enqueue(item2); } } } } } } private bool Dry(int x, int z) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) long key = Key(x, z); if (dry.TryGetValue(key, out var value)) { return value; } Vector3 val = Point(x, z); value = WorldGenerator.instance.GetHeight(val.x, val.z) * 200f >= 30.3f; dry.Add(key, value); return value; } private Vector3 Point(int x, int z) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) return new Vector3(origin.x + (float)x * 24f, 0f, origin.z + (float)z * 24f); } private static long Key(int x, int z) { return ((long)x << 32) | (uint)z; } private static float HorizontalDistance(Vector3 a, Vector3 b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } } [HarmonyPatch(typeof(RuneStone), "Interact", new Type[] { typeof(Humanoid), typeof(bool), typeof(bool) })] internal static class RuneStoneCluePatch { private static void Prefix(RuneStone __instance, Humanoid character, bool hold, out string __state) { AxeCluesPlugin.BeforeRune(__instance, character, hold, out __state); } private static void Postfix(RuneStone __instance, string __state) { AxeCluesPlugin.AfterRune(__instance, __state); } } [HarmonyPatch(typeof(RuneStone), "GetRandomText")] internal static class RandomRuneCluePatch { private static void Postfix(object __result) { AxeCluesPlugin.AddRandomRuneClue(__result); } } [HarmonyPatch(typeof(Player), "AddKnownText", new Type[] { typeof(string), typeof(string) })] internal static class KeepRuneJournalCleanPatch { private static void Prefix(ref string text) { AxeCluesPlugin.KeepRuneOutOfJournal(ref text); } } [HarmonyPatch(typeof(TextViewer), "ShowText", new Type[] { typeof(Style), typeof(string), typeof(string), typeof(bool) })] internal static class PlainScratchFontPatch { private static void Postfix(TextViewer __instance) { AxeCluesPlugin.UsePlainScratchFont(__instance); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class ChestCluePatch { private static void Prefix(InventoryGui __instance, out Container __state) { __state = AxeCluesPlugin.BeforeInventoryHide(__instance); } private static void Postfix(Container __state) { AxeCluesPlugin.AfterInventoryHide(__state); } } [HarmonyPatch(typeof(World), "RemoveWorld")] internal static class WorldProgressCleanupPatch { private static void Prefix(object[] __args, out long __state) { __state = AxeCluesPlugin.BeforeWorldDeleted(__args[0] as string, __args[1]); } private static void Postfix(long __state) { AxeCluesPlugin.AfterWorldDeleted(__state); } } }