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 CaptainsLog v1.0.0
BepInEx/plugins/CaptainsLog.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("CaptainsLog")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+185e1c70765cc70e92e30acbece1449c14dba044")] [assembly: AssemblyProduct("CaptainsLog")] [assembly: AssemblyTitle("CaptainsLog")] [assembly: AssemblyVersion("1.0.0.0")] namespace CaptainsLog; [BepInPlugin("DeathMonger.CaptainsLog", "Captain's Log", "1.0.0")] [BepInProcess("valheim.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class CaptainsLogMod : BaseUnityPlugin { public const string ModGuid = "DeathMonger.CaptainsLog"; public static CaptainsLogMod Instance; internal static ManualLogSource Log; public ConfigEntry<bool> LoggingEnabled; public ConfigEntry<float> SampleIntervalSeconds; public ConfigEntry<bool> ShowHud; public ConfigEntry<float> HudOffsetX; public ConfigEntry<float> HudOffsetY; private readonly Harmony harmony = new Harmony("DeathMonger.CaptainsLog"); private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; LoggingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "Enabled", true, new ConfigDescription("Log ship telemetry (speed, wind, heading) to a CSV file while sailing.", (AcceptableValueBase)null, Array.Empty<object>())); SampleIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Logging", "Sample Interval (s)", 0.5f, new ConfigDescription("Minimum time between logged samples.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())); ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Enabled", true, new ConfigDescription("Show a small HUD widget with live ship speed and wind data while sailing.", (AcceptableValueBase)null, Array.Empty<object>())); HudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "Offset X (px)", 10f, new ConfigDescription("Horizontal offset from the upper-left corner of the screen.", (AcceptableValueBase)null, Array.Empty<object>())); HudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "Offset Y (px)", 40f, new ConfigDescription("Vertical offset from the top of the screen.", (AcceptableValueBase)null, Array.Empty<object>())); harmony.PatchAll(); Log.LogInfo((object)"Captain's Log armed."); } private void Update() { ShipHud.Tick(); } private void OnDestroy() { ShipTelemetry.Shutdown(); } } internal static class ShipHud { private const float UpdateInterval = 0.2f; private const float StaleAfter = 0.75f; private const float Width = 280f; private const float Height = 70f; private static GameObject _go; private static Text _text; private static RectTransform _rect; private static float _lastUpdate; private static bool Enabled => CaptainsLogMod.Instance?.ShowHud?.Value ?? true; private static float OffsetX => CaptainsLogMod.Instance?.HudOffsetX?.Value ?? 10f; private static float OffsetY => CaptainsLogMod.Instance?.HudOffsetY?.Value ?? 40f; public static void Tick() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) EnsureCreated(); if ((Object)(object)_text == (Object)null) { return; } bool flag = Time.time - ShipTelemetry.LastSample.SampledAtTime < 0.75f; bool flag2 = Enabled && flag; if (_go.activeSelf != flag2) { _go.SetActive(flag2); } if (flag2) { _rect.anchoredPosition = new Vector2(OffsetX, 0f - OffsetY); float time = Time.time; if (!(time - _lastUpdate < 0.2f)) { _lastUpdate = time; ShipSample lastSample = ShipTelemetry.LastSample; _text.text = $"Speed: {lastSample.SpeedMs:F1} m/s ({lastSample.SpeedKnots:F1} kn) {lastSample.Propulsion}\n" + $"Wind: {lastSample.WindIntensity * 100f:F1}% @ {lastSample.WindAngleDeg:F0}°\n" + $"Sail: {lastSample.WindAngleFactor * 100f:F0}% Rudder: {lastSample.Rudder:F1}"; } } } private static void EnsureCreated() { //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) //IL_0060: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_go != (Object)null) && GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { _go = GUIManager.Instance.CreateText(string.Empty, GUIManager.CustomGUIFront.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(OffsetX, 0f - OffsetY), GUIManager.Instance.AveriaSerifBold, 16, GUIManager.Instance.ValheimOrange, true, Color.black, 280f, 70f, false); ((Object)_go).name = "CaptainsLog_ShipHud"; _rect = _go.GetComponent<RectTransform>(); _rect.pivot = new Vector2(0f, 1f); _rect.anchoredPosition = new Vector2(OffsetX, 0f - OffsetY); _text = _go.GetComponent<Text>(); _text.alignment = (TextAnchor)0; ((Graphic)_text).raycastTarget = false; } } } internal struct ShipSample { public float SpeedMs; public float SpeedKnots; public Speed SpeedSetting; public string Propulsion; public float Rudder; public float WindAngleDeg; public float WindAngleFactor; public float WindIntensity; public float SampledAtTime; } internal static class ShipTelemetry { private const float MetersPerSecondToKnots = 1.9438444f; private static StreamWriter _writer; private static float _lastSampleTime = -999f; internal static ShipSample LastSample; internal unsafe static void Sample(Ship ship) { //IL_0037: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; float num = Mathf.Max(0.05f, CaptainsLogMod.Instance.SampleIntervalSeconds.Value); if (!(time - _lastSampleTime < num)) { _lastSampleTime = time; Vector3 position = ((Component)ship).transform.position; float num2 = NormalizeAngle(((Component)ship).transform.eulerAngles.y); Vector3 val = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetWindDir() : Vector3.zero); float windIntensity = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetWindIntensity() : 0f); float num3 = NormalizeAngle(Mathf.Atan2(val.x, val.z) * 57.29578f); Biome val2 = Heightmap.FindBiome(position); string text = ((Object)((Component)ship).gameObject).name.Replace("(Clone)", string.Empty).Trim(); float speed = ship.GetSpeed(); Speed speedSetting = ship.GetSpeedSetting(); ShipSample shipSample = (LastSample = new ShipSample { SpeedMs = speed, SpeedKnots = speed * 1.9438444f, SpeedSetting = speedSetting, Propulsion = PropulsionLabel(speedSetting), Rudder = ship.GetRudder(), WindAngleDeg = NormalizeSignedAngle(ship.GetWindAngle()), WindAngleFactor = ship.GetWindAngleFactor(), WindIntensity = windIntensity, SampledAtTime = time }); if (CaptainsLogMod.Instance.LoggingEnabled.Value) { EnsureWriter(); _writer.WriteLine(string.Join(",", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture), text, position.x.ToString("F1", CultureInfo.InvariantCulture), position.z.ToString("F1", CultureInfo.InvariantCulture), ((object)(*(Biome*)(&val2))/*cast due to .constrained prefix*/).ToString(), shipSample.SpeedMs.ToString("F2", CultureInfo.InvariantCulture), shipSample.SpeedKnots.ToString("F2", CultureInfo.InvariantCulture), ((object)(*(Speed*)(&shipSample.SpeedSetting))/*cast due to .constrained prefix*/).ToString(), shipSample.Propulsion, shipSample.Rudder.ToString("F2", CultureInfo.InvariantCulture), num2.ToString("F1", CultureInfo.InvariantCulture), shipSample.WindAngleDeg.ToString("F1", CultureInfo.InvariantCulture), shipSample.WindAngleFactor.ToString("F2", CultureInfo.InvariantCulture), shipSample.WindIntensity.ToString("F2", CultureInfo.InvariantCulture), num3.ToString("F1", CultureInfo.InvariantCulture))); } } } private static float NormalizeAngle(float deg) { deg %= 360f; if (!(deg < 0f)) { return deg; } return deg + 360f; } private static float NormalizeSignedAngle(float deg) { deg = NormalizeAngle(deg); if (!(deg > 180f)) { return deg; } return deg - 360f; } private static string PropulsionLabel(Speed speed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected I4, but got Unknown return (speed - 1) switch { 0 => "Oars-Reverse", 1 => "Oars-Forward", 2 => "Sail-Half", 3 => "Sail-Full", _ => "Idle", }; } private static void EnsureWriter() { if (_writer == null) { string text = Path.Combine(Paths.BepInExRootPath, "CaptainsLog"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, $"shiplog-{DateTime.Now:yyyyMMdd-HHmmss}.csv"); _writer = new StreamWriter(text2, append: false) { AutoFlush = true }; _writer.WriteLine("Timestamp,ShipName,PosX,PosZ,Biome,SpeedMs,SpeedKnots,SpeedSetting,Propulsion,Rudder,HeadingDeg,WindAngleDeg,WindAngleFactor,WindIntensity,WindDirWorldDeg"); CaptainsLogMod.Log.LogInfo((object)("Logging ship telemetry to " + text2)); } } internal static void Shutdown() { _writer?.Flush(); _writer?.Dispose(); _writer = null; } } [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] internal static class Ship_CustomFixedUpdate_Telemetry { [HarmonyPostfix] private static void Postfix(Ship __instance) { if (!((Object)(object)Player.m_localPlayer == (Object)null) && __instance.IsPlayerInBoat(Player.m_localPlayer)) { ShipTelemetry.Sample(__instance); } } }