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 Njords Hond v1.0.0
Valheim.NjordsHond.dll
Decompiled 11 months 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.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("Valheim.NjordsHond")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5604e7a4b7071a41b780caf038a8988c7f64a694")] [assembly: AssemblyProduct("Valheim.NjordsHond")] [assembly: AssemblyTitle("Valheim.NjordsHond")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class ModInfo { public const string ModGUID = "com.scoobymooch.njords_hond"; public const string ModName = "Njords Hond"; public const string ModVersion = "0.1.0"; } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.scoobymooch.njords_hond", "Njords Hond", "0.1.0")] public class VegvisirPlugin : BaseUnityPlugin { internal static bool _autoSetSailSpeed = true; private readonly Harmony _harmony = new Harmony("com.scoobymooch.njords_hond"); private FieldInfo steerDirectionField; private float _updateTimer; private static List<Vector3> _waypointTargets = new List<Vector3>(); private static List<string> _waypointNames = new List<string>(); private static int _currentWaypointIndex = 0; private static int _lastMessageWaypointIndex = -1; private bool _previousIsAutoSteerOn; public static bool AutoPilotEnabled { get; private set; } = false; private void Awake() { Log.CreateInstance(((BaseUnityPlugin)this).Logger); Log.Info("Initializing mod. Version: 0.1.0"); _harmony.PatchAll(); Type type = AccessTools.TypeByName("ShipNavigator.Patches.Ship_Patch"); if (type != null) { steerDirectionField = type.GetField("steerDirection", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (steerDirectionField == null) { Log.Warning("Could not find 'steerDirection' field."); } else { Log.Info("steerDirectionField successfully acquired."); } } else { Log.Warning("Could not find Ship_Patch type."); } } private string GetPath(Transform current) { string text = ((Object)current).name; while ((Object)(object)current.parent != (Object)null) { current = current.parent; text = ((Object)current.parent).name + "/" + text; } return text; } private void OnEnable() { } private void OnDisable() { } private void OnDestroy() { _harmony.UnpatchSelf(); Log.Info("Unpatching mod."); } private void Update() { //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_058d: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_05b6: Unknown result type (might be due to invalid IL or missing references) //IL_0230: 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_0239: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) _updateTimer += Time.deltaTime; if (_updateTimer < 0.5f) { return; } _updateTimer = 0f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)((localPlayer != null) ? localPlayer.GetControlledShip() : null) == (Object)null) { Log.Debug("Skipping update: player is not controlling a ship."); return; } bool flag = false; Type type = AccessTools.TypeByName("ShipNavigator.Patches.Ship_Patch"); FieldInfo fieldInfo = type?.GetField("isAutoSteerOn", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { flag = (bool)fieldInfo.GetValue(null); Log.Debug("Auto-steer is " + (flag ? "ON" : "OFF")); } if (!flag) { Log.Debug("ShipNavigator steering set to manual. AutoPilot set to off"); if (_previousIsAutoSteerOn) { Log.Info("ShipNavigator steering set to manual. AutoPilot set to off"); } _previousIsAutoSteerOn = false; AutoPilotEnabled = false; ShipHudIcon.SetColor(Color32.op_Implicit(new Color32(byte.MaxValue, (byte)187, (byte)66, byte.MaxValue))); return; } if (!AutoPilotEnabled) { ShipHudIcon.SetColor(Color32.op_Implicit(new Color32((byte)34, (byte)133, (byte)200, byte.MaxValue))); } else { ShipHudIcon.SetColor(Color32.op_Implicit(new Color32((byte)150, (byte)171, (byte)91, byte.MaxValue))); } _previousIsAutoSteerOn = true; if (!AutoPilotEnabled) { Log.Debug("AutoPilot is OFF"); return; } if (AutoPilotEnabled && (Object)(object)Player.m_localPlayer != (Object)null) { Ship controlledShip = Player.m_localPlayer.GetControlledShip(); if (controlledShip != null && _autoSetSailSpeed) { float windAngle = controlledShip.GetWindAngle(); float num = Mathf.DeltaAngle(0f, windAngle); bool flag2 = Mathf.Abs(Mathf.DeltaAngle(180f, windAngle)) <= 45f; Log.Debug(string.Format("Ship.GetWindAngle() = {0:F1}° (normalized: {1:F1}°) → {2}", windAngle, num, flag2 ? "Head to wind" : "Not head to wind")); if (controlledShip.IsOwner()) { FieldInfo fieldInfo2 = AccessTools.Field(((object)controlledShip).GetType(), "m_speed"); if (fieldInfo2 != null) { Speed val = (Speed)fieldInfo2.GetValue(controlledShip); Speed val2 = (Speed)((_waypointTargets.Count != 0) ? (flag2 ? 2 : 4) : 0); if (val != val2) { fieldInfo2.SetValue(controlledShip, val2); Log.Debug($"Auto-set ship speed to {val2} due to wind angle and waypoint count."); } } } } } if (!AutoPilotEnabled) { return; } if (!flag) { Log.Debug("Not steering: Auto-steer is OFF"); return; } if (_waypointTargets.Count == 0) { Log.Debug("Not steering: No waypoint targets"); return; } if (steerDirectionField == null) { Log.Debug("Not steering: steerDirectionField is NULL"); return; } if ((Object)(object)Player.m_localPlayer == (Object)null) { Log.Debug("Not steering: local player is NULL"); return; } Vector3 val3 = _waypointTargets[_currentWaypointIndex]; Log.Debug($"Target position: {val3}, Player position: {((Component)Player.m_localPlayer).transform.position}"); Vector3 val4 = val3 - ((Component)Player.m_localPlayer).transform.position; val4.y = 0f; Log.Debug($"Vector to target (flattened): {val4}"); float magnitude = ((Vector3)(ref val4)).magnitude; Log.Debug($"Distance to target: {magnitude}"); Log.Debug($"Current waypoint #{_currentWaypointIndex + 1}, distance: {magnitude:F1}m"); if (magnitude < 10f) { _currentWaypointIndex++; if (_currentWaypointIndex >= _waypointTargets.Count) { Log.Info("Course complete."); if ((Object)(object)Player.m_localPlayer != (Object)null) { Ship controlledShip2 = Player.m_localPlayer.GetControlledShip(); if (controlledShip2 != null && controlledShip2.IsOwner()) { FieldInfo fieldInfo3 = AccessTools.Field(((object)controlledShip2).GetType(), "m_speed"); if (fieldInfo3 != null) { fieldInfo3.SetValue(controlledShip2, (object)(Speed)0); Log.Info("Final waypoint reached. Auto-set ship speed to Stop."); } } } Player localPlayer2 = Player.m_localPlayer; if (localPlayer2 != null) { ((Character)localPlayer2).Message((MessageType)2, "You have reached your destination.", 0, (Sprite)null); } _waypointTargets.Clear(); _waypointNames.Clear(); try { FieldInfo fieldInfo4 = type?.GetField("isAutoSteerOn", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo4 != null) { fieldInfo4.SetValue(null, false); Log.Info("ShipNavigator auto-steer set to OFF (final waypoint reached)."); } else { Log.Warning("Could not find 'isAutoSteerOn' field to disable auto-steer."); } return; } catch (Exception ex) { Log.Error("Error disabling ShipNavigator auto-steer at final waypoint: " + ex); return; } } val3 = _waypointTargets[_currentWaypointIndex]; val4 = val3 - ((Component)Player.m_localPlayer).transform.position; val4.y = 0f; } float num2 = Mathf.Atan2(val4.x, val4.z) * 57.29578f; if (num2 < 0f) { num2 += 360f; } if (_currentWaypointIndex != _lastMessageWaypointIndex) { string arg = ((_waypointNames.Count > _currentWaypointIndex) ? _waypointNames[_currentWaypointIndex] : $"#{_currentWaypointIndex + 1}"); ((Character)Player.m_localPlayer).Message((MessageType)2, $"Setting course to new waypoint: {arg}, {num2:F0}° from north.", 0, (Sprite)null); Log.Info($"Setting course to new waypoint: {arg}, {num2:F0}° from north."); _lastMessageWaypointIndex = _currentWaypointIndex; } ((Vector3)(ref val4)).Normalize(); Log.Debug($"Normalized direction vector: {val4}"); steerDirectionField.SetValue(null, val4); Log.Debug($"Updated steerDirection to {val4} ({num2:F1}° from north)"); } public static void SetWaypointCourse(List<(string name, Vector3 pos)> targets) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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) Log.Info("Waypoint targets received: " + string.Join(", ", targets.Select(((string name, Vector3 pos) t) => t.name))); _waypointTargets.Clear(); _waypointNames.Clear(); _currentWaypointIndex = 0; _lastMessageWaypointIndex = -1; if (targets.Count > 0) { foreach (var target in targets) { _waypointNames.Add(target.name); _waypointTargets.Add(target.pos); } foreach (var (arg, val) in targets) { Log.Debug($"Waypoint: {arg} at {val}"); } Log.Info($"Found {targets.Count} valid pins from input."); Log.Info($"Charting course to {_waypointTargets.Count} pins."); } else { Log.Warning("No valid pins found for course."); } } public static void ClearWaypointCourse() { _waypointTargets.Clear(); _waypointNames.Clear(); _currentWaypointIndex = 0; _lastMessageWaypointIndex = -1; ((Character)Player.m_localPlayer).Message((MessageType)2, "Waypoint course cleared.", 0, (Sprite)null); Log.Info("Waypoint course cleared."); } } internal class Log { public enum VegvisirLogLevel { Debug, Info, Warning, Error, Fatal } private static Log _instance; private ManualLogSource _source; public static VegvisirLogLevel LogLevel { get; set; } = VegvisirLogLevel.Info; public static Log CreateInstance(ManualLogSource source) { _instance = new Log { _source = source }; return _instance; } private Log() { } public static void Info(object msg) { if (LogLevel > VegvisirLogLevel.Info) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogInfo((object)FormatMessage(msg)); } } } public static void Message(object msg) { if (LogLevel > VegvisirLogLevel.Info) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogMessage((object)FormatMessage(msg)); } } } public static void Debug(object msg) { if (LogLevel > VegvisirLogLevel.Debug) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogDebug((object)FormatMessage(msg)); } } } public static void Warning(object msg) { if (LogLevel > VegvisirLogLevel.Warning) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogWarning((object)FormatMessage(msg)); } } } public static void Error(object msg) { if (LogLevel > VegvisirLogLevel.Error) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogError((object)FormatMessage(msg)); } } } public static void Fatal(object msg) { if (LogLevel > VegvisirLogLevel.Fatal) { return; } Log instance = _instance; if (instance != null) { ManualLogSource source = instance._source; if (source != null) { source.LogFatal((object)FormatMessage(msg)); } } } private static string FormatMessage(object msg) { return string.Format("[{0}] [{1}] {2}", DateTime.UtcNow, "Njords Hond", msg); } } [HarmonyPatch(typeof(Chat), "InputText")] public static class Chat_InputText_Patch { [HarmonyPrefix] public static void Prefix(Chat __instance) { //IL_0158: Unknown result type (might be due to invalid IL or missing references) string text = ((TMP_InputField)((Terminal)__instance).m_input).text; if (string.IsNullOrWhiteSpace(text) || (!text.StartsWith("/njordshond ", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("/nh ", StringComparison.OrdinalIgnoreCase))) { return; } Log.Info("Chat command received: " + text); string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length < 2) { return; } string text2 = array[1].ToLowerInvariant(); if ((text2 == "setcourse" || text2 == "sc") && array.Length >= 3) { Log.Info("AutoPilot enabled. Adding waypoints..."); typeof(VegvisirPlugin).GetProperty("AutoPilotEnabled").SetValue(null, true); List<(string, Vector3)> list = new List<(string, Vector3)>(); int num = 2; Log.Debug("Searching pins for names: " + string.Join(", ", array.Skip(num))); if (!((Object)(object)Minimap.instance == (Object)null)) { for (int i = num; i < array.Length; i++) { string name = array[i]; PinData val = Traverse.Create((object)Minimap.instance).Field<List<PinData>>("m_pins").Value?.FirstOrDefault((Func<PinData, bool>)((PinData p) => p.m_name.Equals(name, StringComparison.OrdinalIgnoreCase))); if (val != null) { list.Add((val.m_name, val.m_pos)); } else { Log.Warning("No pin named '" + name + "' found."); } } Log.Info($"Total matched pins: {list.Count}"); VegvisirPlugin.SetWaypointCourse(list); try { FieldInfo fieldInfo = AccessTools.TypeByName("ShipNavigator.Patches.Ship_Patch")?.GetField("isAutoSteerOn", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { fieldInfo.SetValue(null, true); Log.Info("ShipNavigator auto-steer set to ON."); } else { Log.Warning("Could not find 'isAutoSteerOn' field."); } return; } catch (Exception ex) { Log.Error("Error setting ShipNavigator auto-steer ON: " + ex); return; } } Log.Warning("Minimap instance is null. Cannot find pins."); } else { if (!(text2 == "clearcourse") && !(text2 == "cc")) { return; } Log.Info("Clearing course. AutoPilot disabled."); typeof(VegvisirPlugin).GetProperty("AutoPilotEnabled").SetValue(null, false); VegvisirPlugin.ClearWaypointCourse(); try { FieldInfo fieldInfo2 = AccessTools.TypeByName("ShipNavigator.Patches.Ship_Patch")?.GetField("isAutoSteerOn", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo2 != null) { fieldInfo2.SetValue(null, false); Log.Info("ShipNavigator auto-steer set to OFF."); } else { Log.Warning("Could not find 'isAutoSteerOn' field."); } } catch (Exception ex2) { Log.Error("Error setting ShipNavigator auto-steer OFF: " + ex2); } } } } public static class ShipHudIcon { private static GameObject _shipIcon; public static bool TryFind() { if ((Object)(object)_shipIcon == (Object)null) { _shipIcon = GameObject.Find("/_GameMain/LoadingGUI/PixelFix/IngameGui/HUD/hudroot/ShipHud/WindIndicator/Ship"); } return (Object)(object)_shipIcon != (Object)null; } public static void SetColor(Color color) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!TryFind()) { Log.Warning("Ship icon not found."); return; } Image component = _shipIcon.GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = color; } else { Log.Warning("Ship icon found, but Image component missing."); } } } [HarmonyPatch] public static class ShipNavigatorInputBlocker { private static MethodBase TargetMethod() { return AccessTools.Method("ShipNavigator.ShipNavigator:Update", (Type[])null, (Type[])null); } private static bool Prefix() { if ((Object)(object)((Terminal)(Chat.instance?)).m_input != (Object)null && ((TMP_InputField)((Terminal)Chat.instance).m_input).isFocused) { Log.Debug("Blocking ShipNavigator input: chat input is focused."); return false; } return true; } }