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 Odins Stone Whispers v0.1.0
plugins/OdinsStoneWhispers.dll
Decompiled 10 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("OdinsStoneWhispers")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+e8e8cf64eb71ddde36d79cdef2a3b4f5650a9cbd")] [assembly: AssemblyProduct("OdinsStoneWhispers")] [assembly: AssemblyTitle("OdinsStoneWhispers")] [assembly: AssemblyVersion("0.1.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 OdinsStoneWhispers { internal class FloatingWhisper : MonoBehaviour { private const float StartY = 0.58f; private const float EndY = 0.94f; private const float FadeOutFraction = 0.3f; private static readonly Color Tint = new Color(0.86f, 0.91f, 1f); private TMP_Text _text; private RectTransform _rect; private float _elapsed = -1f; public bool Playing => _elapsed >= 0f; public void Show(string line) { if (EnsureText()) { _text.text = line; _text.fontSize = Plugin.TextSize.Value; _elapsed = 0f; Apply(0f, 0.58f); ((Component)_text).gameObject.SetActive(true); } } private void Update() { if (_elapsed < 0f || (Object)(object)_text == (Object)null) { return; } _elapsed += Time.deltaTime; float num = Mathf.Max(4f, Plugin.DurationSeconds.Value); if (_elapsed >= num) { _elapsed = -1f; ((Component)_text).gameObject.SetActive(false); return; } float num2 = _elapsed / num; float y = Mathf.Lerp(0.58f, 0.94f, num2); float num3 = Mathf.Min(Plugin.FadeInSeconds.Value, num * 0.5f); float num4 = ((num3 > 0f) ? Mathf.Clamp01(_elapsed / num3) : 1f); float num5 = 0.7f; if (num2 > num5) { num4 = Mathf.Min(num4, 1f - (num2 - num5) / 0.3f); } if (!HudVisible()) { num4 = 0f; } Apply(Mathf.SmoothStep(0f, 1f, num4), y); } private void Apply(float alpha, float y) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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) _rect.anchorMin = new Vector2(0.5f, y); _rect.anchorMax = new Vector2(0.5f, y); _rect.anchoredPosition = Vector2.zero; Color tint = Tint; tint.a = alpha; ((Graphic)_text).color = tint; } private bool EnsureText() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_text != (Object)null) { return true; } _text = HudText.Create("OdinsStoneWhispers_Line", ((Component)this).transform); if ((Object)(object)_text == (Object)null) { return false; } _rect = (RectTransform)_text.transform; _rect.sizeDelta = new Vector2(1400f, 120f); _text.fontStyle = (FontStyles)2; return true; } private static bool HudVisible() { if ((Object)(object)Hud.instance != (Object)null && !Hud.IsUserHidden()) { return Hud.instance.IsVisible(); } return false; } private void OnDestroy() { if ((Object)(object)_text != (Object)null) { Object.Destroy((Object)(object)((Component)_text).gameObject); } } } internal class GazeIndicator : MonoBehaviour { private const float Y = 0.82f; private static readonly Color Tint = new Color(1f, 0.86f, 0.55f); private TMP_Text _text; public void Show(string line) { if (EnsureText()) { _text.text = line; if (!((Component)_text).gameObject.activeSelf) { ((Component)_text).gameObject.SetActive(true); } } } public void Hide() { if ((Object)(object)_text != (Object)null && ((Component)_text).gameObject.activeSelf) { ((Component)_text).gameObject.SetActive(false); } } private bool EnsureText() { //IL_0041: 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_0047: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_text != (Object)null) { return true; } _text = HudText.Create("OdinsStoneWhispers_Gaze", ((Component)this).transform); if ((Object)(object)_text == (Object)null) { return false; } RectTransform val = (RectTransform)_text.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.82f); val.anchorMax = val2; val.anchorMin = val2; val.sizeDelta = new Vector2(1200f, 60f); _text.fontSize = 26f; ((Graphic)_text).color = Tint; Plugin.Log.LogInfo((object)"Odin's gaze distance line shown."); return true; } private void OnDestroy() { if ((Object)(object)_text != (Object)null) { Object.Destroy((Object)(object)((Component)_text).gameObject); } } } internal static class HudText { private static Canvas _canvas; public static TMP_Text Create(string name, Transform owner) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00e1: Unknown result type (might be due to invalid IL or missing references) TMP_Text val = (((Object)(object)MessageHud.instance != (Object)null) ? MessageHud.instance.m_messageCenterText : null); if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null || !EnsureCanvas(owner)) { return null; } GameObject val2 = new GameObject(name, new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(((Component)_canvas).transform, false); TextMeshProUGUI obj = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = val.font; ((TMP_Text)obj).fontSharedMaterial = val.fontSharedMaterial; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj).textWrappingMode = (TextWrappingModes)1; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).outlineWidth = 0.15f; ((TMP_Text)obj).outlineColor = new Color32((byte)0, (byte)0, (byte)0, (byte)200); RectTransform val3 = (RectTransform)val2.transform; val3.pivot = new Vector2(0.5f, 0.5f); val3.anchoredPosition = Vector2.zero; return (TMP_Text)(object)obj; } private static bool EnsureCanvas(Transform owner) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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) if ((Object)(object)_canvas != (Object)null) { return true; } GameObject val = new GameObject("OdinsStoneWhispers_Canvas"); val.transform.SetParent(owner, false); _canvas = val.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 5000; CanvasScaler obj = val.AddComponent<CanvasScaler>(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); obj.matchWidthOrHeight = 0.5f; Plugin.Log.LogInfo((object)"On-screen text layer created."); return true; } } internal static class OdinLines { private static readonly string[] BuiltIn = new string[16] { "Something mysterious is in the air...", "The stones are whispering again...", "Something old and patient is watching you...", "Even the wind has gone quiet. Listen...", "Not every rock is only a rock...", "There is wisdom near, if you would stoop to find it...", "The ground hums beneath your feet...", "Something here remembers the first winter...", "Look closer, wanderer. The land keeps a secret nearby...", "Something is staring at you. Something... grey.", "A small thing with a great deal to say is close...", "I hung nine nights for wisdom. Some find it lying in the grass...", "The air tastes of riddles...", "Hush. Something nearby is thinking very slowly...", "My ravens circle. They have seen something strange below...", "A stone that dreams lies near. Can you hear it breathing?" }; private static readonly string[] SilentLines = new string[4] { "The stones are silent here...", "Nothing stirs nearby. Wander further...", "No whispers in this place. Not yet...", "Only ordinary rocks here, wanderer..." }; private static int _last = -1; public static string Silent() { return SilentLines[Random.Range(0, SilentLines.Length)]; } public static string Next() { string[] array = Lines(); if (array.Length == 1) { return array[0]; } int num; do { num = Random.Range(0, array.Length); } while (num == _last); _last = num; return array[num]; } private static string[] Lines() { string value = Plugin.CustomLines.Value; if (!string.IsNullOrWhiteSpace(value)) { string[] array = (from s in value.Split(new char[1] { '|' }) select s.Trim() into s where s.Length > 0 select s).ToArray(); if (array.Length != 0) { if (_last >= array.Length) { _last = -1; } return array; } } return BuiltIn; } } [BepInPlugin("hevyh2o.valheim.odinsstonewhispers", "Odin's Stone Whispers", "0.1.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "hevyh2o.valheim.odinsstonewhispers"; public const string Name = "Odin's Stone Whispers"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> RangeMeters; internal static ConfigEntry<string> RockItems; internal static ConfigEntry<bool> CountPlacedRocks; internal static ConfigEntry<string> ExtraPrefabs; internal static ConfigEntry<bool> FrequencyCheck; internal static ConfigEntry<float> FrequencyMinutes; internal static ConfigEntry<float> DurationSeconds; internal static ConfigEntry<float> FadeInSeconds; internal static ConfigEntry<float> TextSize; internal static ConfigEntry<string> CustomLines; internal static ConfigEntry<bool> WindGust; internal static ConfigEntry<float> WindVolume; internal static ConfigEntry<KeyboardShortcut> LocateKey; internal static ConfigEntry<float> LocateRepeatSeconds; internal static ConfigEntry<KeyboardShortcut> PreviewKey; internal static ConfigEntry<bool> LogDetections; private RockSense _sense; private void Awake() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch."); LocateKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "LocateKey", new KeyboardShortcut((KeyCode)57, Array.Empty<KeyCode>()), "Switches rock seeking on or off. While on, your view turns so the crosshair points at the nearest Mysterious Rock anywhere in the loaded area around you (not limited to RangeMeters), right away and again every LocateRepeatSeconds. Moving the mouse cancels the current turn."); LocateRepeatSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Keys", "LocateRepeatSeconds", 10f, new ConfigDescription("While rock seeking is on, how often your view turns toward the nearest rock again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())); PreviewKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "PreviewKey", KeyboardShortcut.Empty, "Optional test key: shows a whisper (and the gust, if WindGust is on) right away, rock or no rock. Handy for trying settings. Unbound by default."); RangeMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "RangeMeters", 120f, new ConfigDescription("How close a Mysterious Rock has to be before Odin says something. The game only knows about objects in the area loaded around you, so very large values stop helping somewhere past ~150 m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 300f), Array.Empty<object>())); RockItems = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "RockItems", "StoneRock, HardRock", "Comma-separated item names to look for. StoneRock is the \"Rock\" (\"It's a stone.\"), HardRock is the Mysterious Rock. Anything that gives one of these when picked up counts, and so does the item lying loose on the ground."); CountPlacedRocks = ((BaseUnityPlugin)this).Config.Bind<bool>("Detection", "CountPlacedRocks", false, "Also count Mysterious Rocks that have been placed as pets (for example in your own base). Off by default, so only wild rocks waiting to be picked up count."); ExtraPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "ExtraPrefabs", "", "Comma-separated prefab names to treat as Mysterious Rocks as well, in case a game update or another mod adds new ones."); FrequencyCheck = ((BaseUnityPlugin)this).Config.Bind<bool>("Whisper", "FrequencyCheck", true, "When on (default), after Odin whispers about a rock he waits FrequencyMinutes before whispering again. When off, he whispers again as soon as the last line has gone, for as long as a rock is within RangeMeters. The PreviewKey never starts the wait."); FrequencyMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Whisper", "FrequencyMinutes", 5f, new ConfigDescription("With FrequencyCheck on: real-time minutes to wait after a whisper before the next, however many rocks are near. 1 to 30.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>())); DurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Whisper", "DurationSeconds", 6f, new ConfigDescription("How long the line is on screen in total, from first fading in to fully gone at the top.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 15f), Array.Empty<object>())); FadeInSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Whisper", "FadeInSeconds", 2f, new ConfigDescription("How long the line takes to fade in.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); TextSize = ((BaseUnityPlugin)this).Config.Bind<float>("Whisper", "TextSize", 32f, new ConfigDescription("Font size of the line.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(14f, 72f), Array.Empty<object>())); CustomLines = ((BaseUnityPlugin)this).Config.Bind<string>("Whisper", "CustomLines", "", "Your own lines for Odin, separated by | . When set, these are used instead of the built-in ones."); WindGust = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "WindGust", false, "Play a short gust of the game's own wind sound with the whisper. Off by default."); WindVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "WindVolume", 3f, new ConfigDescription("Gust loudness. 1 = the game's own wind on its windiest day, 3 = three times that. Also follows your in-game volume sliders.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 6f), Array.Empty<object>())); LogDetections = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogDetections", false, "Write the nearest Mysterious Rock and its distance to the BepInEx log on every whisper."); _sense = ((Component)this).gameObject.AddComponent<RockSense>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin's Stone Whispers 0.1.0 loaded. The stones are listening."); } private void OnDestroy() { if ((Object)(object)_sense != (Object)null) { Object.Destroy((Object)(object)_sense); } } } internal class RockSense : MonoBehaviour { private const float ScanInterval = 2f; private readonly List<ZDO> _zdos = new List<ZDO>(); private HashSet<int> _rockHashes; private ZNetScene _builtFor; private string _builtItems; private string _builtExtra; private bool _builtPlaced; private FloatingWhisper _whisper; private WindGust _gust; private GazeIndicator _gaze; private float _nextGazeUpdate; private float _nextScan; private float _lastWhisper = float.NegativeInfinity; private bool _pending; private bool _scanFailedLogged; private ZDO _pendingRock; private float _pendingDist; private const float TurnSeconds = 0.4f; private const float AimHeight = 0.3f; private const float MouseTakeover = 40f; private static readonly FieldRef<Player, float> LookPitch = AccessTools.FieldRefAccess<Player, float>("m_lookPitch"); private static readonly FieldRef<Character, Quaternion> LookYaw = AccessTools.FieldRefAccess<Character, Quaternion>("m_lookYaw"); private bool _seeking; private float _nextLocate; private float _turnElapsed = -1f; private float _mouseDuringTurn; private float _yawFrom; private float _yawTo; private float _pitchFrom; private float _pitchTo; private void Awake() { _whisper = ((Component)this).gameObject.AddComponent<FloatingWhisper>(); _gust = ((Component)this).gameObject.AddComponent<WindGust>(); _gaze = ((Component)this).gameObject.AddComponent<GazeIndicator>(); } private void Update() { //IL_002e: 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) //IL_0141: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { _pending = false; _seeking = false; _gaze.Hide(); return; } if (KeyDown(Plugin.PreviewKey.Value)) { Whisper(null, 0f); return; } if (!Plugin.Enabled.Value) { _seeking = false; _gaze.Hide(); return; } if (KeyDown(Plugin.LocateKey.Value) && CanShow(localPlayer)) { ToggleSeeking(localPlayer); } if (_seeking && Time.time >= _nextLocate && CanShow(localPlayer)) { _nextLocate = Time.time + Plugin.LocateRepeatSeconds.Value; Locate(localPlayer, sayIfNone: false); } UpdateTurn(localPlayer); UpdateGaze(localPlayer); if (Time.time >= _nextScan) { _nextScan = Time.time + 2f; float num = (Plugin.FrequencyCheck.Value ? (Plugin.FrequencyMinutes.Value * 60f) : Mathf.Max(4f, Plugin.DurationSeconds.Value)); if (!_pending && Time.realtimeSinceStartup - _lastWhisper >= num) { float nearest; int found; ZDO val = FindNearestRock(((Component)localPlayer).transform.position, Plugin.RangeMeters.Value, out nearest, out found); if (val != null) { _pending = true; _pendingRock = val; _pendingDist = nearest; } } } if (_pending && CanShow(localPlayer)) { _pending = false; Whisper(_pendingRock, _pendingDist); } } private void Locate(Player player, bool sayIfNone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009f: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) float nearest; int found; ZDO val = FindNearestRock(((Component)player).transform.position, float.MaxValue, out nearest, out found); if (sayIfNone) { Plugin.Log.LogInfo((object)((val == null) ? "Odin's gaze: no Mysterious Rock in the loaded area." : $"Odin's gaze: {found} Mysterious Rock(s) in the loaded area, nearest {nearest:0} m at {val.GetPosition()}.")); } if (val == null) { if (sayIfNone) { _whisper.Show(OdinLines.Silent()); } return; } Vector3 val2 = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.position : ((Character)player).GetEyePoint()); Vector3 val3 = val.GetPosition() + Vector3.up * 0.3f - val2; if (!(((Vector3)(ref val3)).sqrMagnitude < 0.01f)) { ((Vector3)(ref val3)).Normalize(); _yawFrom = ((Quaternion)(ref LookYaw.Invoke((Character)(object)player))).eulerAngles.y; Quaternion val4 = Quaternion.LookRotation(new Vector3(val3.x, 0f, val3.z)); _yawTo = ((Quaternion)(ref val4)).eulerAngles.y; _pitchFrom = LookPitch.Invoke(player); _pitchTo = Mathf.Clamp((0f - Mathf.Asin(val3.y)) * 57.29578f, -89f, 89f); _turnElapsed = 0f; _mouseDuringTurn = 0f; if (Plugin.LogDetections.Value) { Plugin.Log.LogInfo((object)$"Turning toward Mysterious Rock at {val.GetPosition()}, {nearest:0} m away."); } } } private void ToggleSeeking(Player player) { _seeking = !_seeking; MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, _seeking ? "Odin's gaze: seeking the stones" : "Odin's gaze: resting", 0, (Sprite)null, false, true); } if (!_seeking) { _turnElapsed = -1f; _gaze.Hide(); } else { _nextGazeUpdate = 0f; _nextLocate = Time.time + Plugin.LocateRepeatSeconds.Value; Locate(player, sayIfNone: true); } } private void UpdateGaze(Player player) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (_seeking) { if (!CanShow(player)) { _gaze.Hide(); _nextGazeUpdate = 0f; } else if (!(Time.time < _nextGazeUpdate)) { _nextGazeUpdate = Time.time + 1f; float nearest; int found; ZDO val = FindNearestRock(((Component)player).transform.position, float.MaxValue, out nearest, out found); _gaze.Show((val != null) ? $"Odin's gaze: a stone {nearest:0} m away" : "Odin's gaze: no stone in reach"); } } } private void UpdateTurn(Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if (_turnElapsed < 0f) { return; } float mouseDuringTurn = _mouseDuringTurn; Vector2 mouseDelta = ZInput.GetMouseDelta(); _mouseDuringTurn = mouseDuringTurn + ((Vector2)(ref mouseDelta)).magnitude; if (_mouseDuringTurn > 40f || ((Character)player).IsDead()) { _turnElapsed = -1f; return; } _turnElapsed += Time.deltaTime; float num = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(_turnElapsed / 0.4f)); LookYaw.Invoke((Character)(object)player) = Quaternion.Euler(0f, Mathf.LerpAngle(_yawFrom, _yawTo, num), 0f); LookPitch.Invoke(player) = Mathf.Lerp(_pitchFrom, _pitchTo, num); if (_turnElapsed >= 0.4f) { _turnElapsed = -1f; } } private void Whisper(ZDO rock, float dist) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (rock != null) { _lastWhisper = Time.realtimeSinceStartup; } _whisper.Show(OdinLines.Next()); if (Plugin.WindGust.Value && Plugin.WindVolume.Value > 0f) { _gust.Play(); } if (Plugin.LogDetections.Value && rock != null) { ZNetScene instance = ZNetScene.instance; object obj; if (instance == null) { obj = null; } else { GameObject prefab = instance.GetPrefab(rock.GetPrefab()); obj = ((prefab != null) ? ((Object)prefab).name : null); } if (obj == null) { obj = rock.GetPrefab().ToString(); } string arg = (string)obj; Plugin.Log.LogInfo((object)$"Mysterious Rock nearby: {arg} at {rock.GetPosition()}, {dist:0} m away."); } } private ZDO FindNearestRock(Vector3 from, float range, out float nearest, out int found) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) nearest = float.MaxValue; found = 0; HashSet<int> hashSet = RockHashes(); if (hashSet == null || hashSet.Count == 0 || ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return null; } _zdos.Clear(); try { ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(from), ZNet.instance.GetSyncedSimulationDistance(), _zdos, (List<ZDO>)null); } catch (Exception ex) { if (!_scanFailedLogged) { _scanFailedLogged = true; Plugin.Log.LogWarning((object)("Couldn't search the area for rocks (a game update may have changed things): " + ex.Message)); } return null; } ZDO result = null; foreach (ZDO zdo in _zdos) { if (zdo != null && zdo.IsValid() && hashSet.Contains(zdo.GetPrefab()) && !zdo.GetBool(ZDOVars.s_picked, false)) { found++; float num = Utils.DistanceXZ(from, zdo.GetPosition()); if (num <= range && num < nearest) { nearest = num; result = zdo; } } } _zdos.Clear(); return result; } private HashSet<int> RockHashes() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return null; } string text = Plugin.RockItems.Value ?? ""; string text2 = Plugin.ExtraPrefabs.Value ?? ""; bool value = Plugin.CountPlacedRocks.Value; if (_rockHashes != null && (Object)(object)_builtFor == (Object)(object)instance && _builtItems == text && _builtExtra == text2 && _builtPlaced == value) { return _rockHashes; } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = text.Split(new char[1] { ',' }); foreach (string text3 in array) { if (text3.Trim().Length > 0) { hashSet.Add(text3.Trim()); } } HashSet<int> hashSet2 = new HashSet<int>(); List<string> list = new List<string>(); foreach (GameObject prefab in instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { Pickable component = prefab.GetComponent<Pickable>(); if (((Object)(object)component != (Object)null) ? (((Object)(object)component.m_itemPrefab != (Object)null && hashSet.Contains(((Object)component.m_itemPrefab).name)) || hashSet.Any((string w) => ((Object)prefab).name.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0)) : ((!((Object)(object)prefab.GetComponent<ItemDrop>() != (Object)null)) ? (value && (Object)(object)prefab.GetComponent<Piece>() != (Object)null && hashSet.Any((string w) => ((Object)prefab).name.EndsWith("_" + w, StringComparison.OrdinalIgnoreCase))) : hashSet.Contains(((Object)prefab).name))) { hashSet2.Add(StringExtensionMethods.GetStableHashCode(((Object)prefab).name)); list.Add(((Object)prefab).name); } } } array = text2.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text4 = array[i].Trim(); if (text4.Length > 0 && hashSet2.Add(StringExtensionMethods.GetStableHashCode(text4))) { list.Add(text4); } } _rockHashes = hashSet2; _builtFor = instance; _builtItems = text; _builtExtra = text2; _builtPlaced = value; if (list.Count == 0) { Plugin.Log.LogWarning((object)("No prefabs found for RockItems '" + text + "'. Nothing to listen for.")); } else { Plugin.Log.LogInfo((object)("Listening for: " + string.Join(", ", list))); } return hashSet2; } private static bool CanShow(Player player) { if (((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting()) { return false; } if ((Object)(object)Hud.instance == (Object)null || Hud.IsUserHidden() || !Hud.instance.IsVisible()) { return false; } if (!Menu.IsVisible() && !Minimap.IsOpen()) { return !InventoryGui.IsVisible(); } return false; } private static bool KeyDown(KeyboardShortcut key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref key)).MainKey == 0 || Typing() || !ZInput.GetKeyDown(((KeyboardShortcut)(ref key)).MainKey, false)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref key)).Modifiers) { if (!ZInput.GetKey(modifier, false)) { return false; } } return true; } private static bool Typing() { if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible()) { return TextInput.IsVisible(); } return true; } } internal class WindGust : MonoBehaviour { private const float Length = 3.5f; private const float Attack = 0.8f; private const float Release = 2f; private const double StartDelay = 0.05; private readonly List<AudioSource> _sources = new List<AudioSource>(); private int _layers; private float _elapsed = -1f; private float _perLayerPeak; public void Play() { AudioMan instance = AudioMan.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_windAudio == (Object)null) { return; } AudioClip windAudio = instance.m_windAudio; float num = Mathf.Max(0f, instance.m_windMaxVol * Plugin.WindVolume.Value); if (num <= 0f) { return; } _layers = Mathf.Max(1, Mathf.CeilToInt(num)); _perLayerPeak = num / (float)_layers; while (_sources.Count < _layers) { AudioSource val = ((Component)this).gameObject.AddComponent<AudioSource>(); val.playOnAwake = false; val.loop = true; val.spatialBlend = 0f; val.bypassReverbZones = true; val.priority = 0; _sources.Add(val); } float pitch = Mathf.Lerp(instance.m_windMinPitch, instance.m_windMaxPitch, 0.7f); int timeSamples = (int)(Random.Range(0f, Mathf.Max(0f, windAudio.length - 3.5f - 0.1f)) * (float)windAudio.frequency); double num2 = AudioSettings.dspTime + 0.05; for (int i = 0; i < _sources.Count; i++) { AudioSource val2 = _sources[i]; val2.Stop(); if (i < _layers) { val2.outputAudioMixerGroup = instance.m_ambientMixer; val2.clip = windAudio; val2.pitch = pitch; val2.volume = 0f; val2.timeSamples = timeSamples; val2.PlayScheduled(num2); } } _elapsed = 0f; } private void Update() { if (_elapsed < 0f) { return; } _elapsed += Time.deltaTime; if (_elapsed >= 3.55f) { foreach (AudioSource source in _sources) { source.Stop(); } _elapsed = -1f; return; } float num = Mathf.Max(0f, _elapsed - 0.05f); float num2 = Mathf.Min(Mathf.Clamp01(num / 0.8f), Mathf.Clamp01((3.5f - num) / 2f)); float volume = _perLayerPeak * Mathf.SmoothStep(0f, 1f, num2); for (int i = 0; i < _layers; i++) { _sources[i].volume = volume; } } } internal static class BuildInfo { public const string Version = "0.1.0"; } }