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 RaftSpeedometer v1.0.0
RaftSpeedometer.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("RaftSpeedometer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RaftSpeedometer")] [assembly: AssemblyTitle("RaftSpeedometer")] [assembly: AssemblyVersion("1.0.0.0")] namespace RaftSpeedometer; internal static class GameApi { private enum State { Pending, Ready, Failed } private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static State _state = State.Pending; private static float _nextAttempt; private static FieldInfo _localPlayer; private static FieldInfo _lastGroundCollider; private static FieldInfo _lastGroundTouch; private static readonly List<MethodInfo> UiBlockers = new List<MethodInfo>(); private static MethodInfo _zinputGetKeyDown; private static object[] _zinputArgs; private static bool _legacyInputFailed; public static bool TryResolve(ManualLogSource log) { if (_state == State.Ready) { return true; } if (_state == State.Failed) { return false; } if (Time.time < _nextAttempt) { return false; } _nextAttempt = Time.time + 2f; Assembly assembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies) { if (assembly2.GetName().Name == "assembly_valheim") { assembly = assembly2; break; } } if (assembly == null) { return false; } Type type = assembly.GetType("Player", throwOnError: false); _localPlayer = type?.GetField("m_localPlayer", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (_localPlayer == null) { log.LogError((object)"Could not find Player.m_localPlayer in this Valheim version; the speedometer is disabled."); _state = State.Failed; return false; } _lastGroundCollider = FindInstanceField(type, "m_lastGroundCollider"); _lastGroundTouch = FindInstanceField(type, "m_lastGroundTouch"); if (_lastGroundCollider == null || _lastGroundTouch == null || _lastGroundTouch.FieldType != typeof(float)) { _lastGroundCollider = null; log.LogInfo((object)"Ground-contact fields not found; vehicle detection will use a downward raycast only."); } AddUiBlocker(assembly, "Minimap", "IsOpen"); AddUiBlocker(assembly, "InventoryGui", "IsVisible"); AddUiBlocker(assembly, "Menu", "IsVisible"); AddUiBlocker(assembly, "StoreGui", "IsVisible"); AddUiBlocker(assembly, "TextInput", "IsVisible"); AddUiBlocker(assembly, "Hud", "IsUserHidden"); ResolveZInput(assembly); _state = State.Ready; return true; } public static Component GetLocalPlayer() { object? obj = _localPlayer?.GetValue(null); return (Component)((obj is Component) ? obj : null); } public static Collider GetGroundCollider(Component player) { if (_lastGroundCollider == null || (Object)(object)player == (Object)null) { return null; } try { if ((float)_lastGroundTouch.GetValue(player) > 0.3f) { return null; } object? value = _lastGroundCollider.GetValue(player); return (Collider)((value is Collider) ? value : null); } catch (Exception) { _lastGroundCollider = null; return null; } } public static bool IsUiBlocking() { for (int i = 0; i < UiBlockers.Count; i++) { try { if ((bool)UiBlockers[i].Invoke(null, null)) { return true; } } catch (Exception) { UiBlockers.RemoveAt(i); i--; } } return false; } public static bool KeyDown(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) if ((int)key == 0) { return false; } if (_zinputGetKeyDown != null) { try { _zinputArgs[0] = key; return (bool)_zinputGetKeyDown.Invoke(null, _zinputArgs); } catch (Exception) { _zinputGetKeyDown = null; } } if (!_legacyInputFailed) { try { return Input.GetKeyDown(key); } catch (Exception) { _legacyInputFailed = true; } } return false; } private static FieldInfo FindInstanceField(Type type, string name) { Type type2 = type; while (type2 != null) { FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type2 = type2.BaseType; } return null; } private static void AddUiBlocker(Assembly game, string typeName, string methodName) { MethodInfo methodInfo = game.GetType(typeName, throwOnError: false)?.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (methodInfo != null && methodInfo.ReturnType == typeof(bool)) { UiBlockers.Add(methodInfo); } } private static void ResolveZInput(Assembly game) { Type type = game.GetType("ZInput", throwOnError: false); if (type == null) { return; } MethodInfo methodInfo = null; MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name != "GetKeyDown" || methodInfo2.ReturnType != typeof(bool)) { continue; } ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 0 || parameters[0].ParameterType != typeof(KeyCode)) { continue; } bool flag = true; for (int j = 1; j < parameters.Length; j++) { if (!parameters[j].IsOptional && parameters[j].ParameterType != typeof(bool)) { flag = false; break; } } if (flag && (methodInfo == null || parameters.Length < methodInfo.GetParameters().Length)) { methodInfo = methodInfo2; } } if (methodInfo == null) { return; } ParameterInfo[] parameters2 = methodInfo.GetParameters(); object[] array = new object[parameters2.Length]; for (int k = 1; k < parameters2.Length; k++) { ParameterInfo parameterInfo = parameters2[k]; if (parameterInfo.ParameterType == typeof(bool)) { array[k] = ((parameterInfo.Name != null && parameterInfo.Name.IndexOf("log", StringComparison.OrdinalIgnoreCase) >= 0) ? ((object)false) : (parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : ((object)false))); } else { array[k] = (parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : null); } } _zinputGetKeyDown = methodInfo; _zinputArgs = array; } } [BepInPlugin("burksheim.raftspeedometer", "Raft Speedometer", "1.0.0")] public sealed class RaftSpeedometerPlugin : BaseUnityPlugin { public const string PluginGuid = "burksheim.raftspeedometer"; public const string PluginName = "Raft Speedometer"; public const string PluginVersion = "1.0.0"; private const float ScanInterval = 0.1f; private const float StoppedThreshold = 0.15f; private ConfigEntry<bool> _enabled; private ConfigEntry<KeyCode> _toggleKey; private ConfigEntry<KeyCode> _resetTopKey; private ConfigEntry<SpeedUnit> _primaryUnit; private ConfigEntry<SecondaryUnit> _secondaryUnit; private ConfigEntry<bool> _showTop; private ConfigEntry<ScreenAnchor> _anchor; private ConfigEntry<int> _offsetX; private ConfigEntry<int> _offsetY; private ConfigEntry<float> _scale; private ConfigEntry<float> _backgroundOpacity; private ConfigEntry<float> _averagingSeconds; private ConfigEntry<float> _leaveDelay; private ConfigEntry<float> _maxPlausibleSpeed; private ConfigEntry<string> _extraVehicleNames; private readonly VehicleDetector _detector = new VehicleDetector(); private readonly SpeedTracker _tracker = new SpeedTracker(); private readonly SpeedHud _hud = new SpeedHud(); private Transform _vehicle; private VehicleKind _kind; private Transform _lastVehicle; private float _lastOnVehicleTime = float.MinValue; private float _nextScanTime; private bool _hasSpeed; private float _speed; private float _topSpeed; private bool _hudVisible = true; private bool _uiBlocked; private void Awake() { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turn the speedometer on or off."); _toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1 - General", "Toggle Key", (KeyCode)288, "Shows or hides the speedometer while you are on a vehicle."); _resetTopKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1 - General", "Reset Top Speed Key", (KeyCode)287, "Clears the top speed reading, e.g. after adding a sail and before a new test run."); _primaryUnit = ((BaseUnityPlugin)this).Config.Bind<SpeedUnit>("2 - Display", "Primary Unit", SpeedUnit.Knots, "Unit for the big number and the top speed."); _secondaryUnit = ((BaseUnityPlugin)this).Config.Bind<SecondaryUnit>("2 - Display", "Secondary Unit", SecondaryUnit.MetersPerSecond, "Unit shown underneath (None hides it). ValheimRAFT's config and most published Valheim ship speeds use m/s."); _showTop = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "Show Top Speed", true, "Show the highest speed reached since you boarded this vehicle."); _anchor = ((BaseUnityPlugin)this).Config.Bind<ScreenAnchor>("2 - Display", "Screen Position", ScreenAnchor.TopCenter, "Which edge or corner of the screen the panel sits against."); _offsetX = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Display", "Offset X", 0, new ConfigDescription("Sideways shift in pixels (measured at 1080p; scales with resolution).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-2000, 2000), Array.Empty<object>())); _offsetY = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Display", "Offset Y", 12, new ConfigDescription("Distance from the top or bottom edge in pixels (measured at 1080p; scales with resolution).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-2000, 2000), Array.Empty<object>())); _scale = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "Scale", 1f, new ConfigDescription("Size of the panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), Array.Empty<object>())); _backgroundOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "Background Opacity", 0.55f, new ConfigDescription("0 = no background, 1 = solid.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _averagingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Measurement", "Averaging Seconds", 1f, new ConfigDescription("Speed is averaged over this many seconds. Longer = steadier number, slower to react.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), Array.Empty<object>())); _leaveDelay = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Measurement", "Leave Delay Seconds", 1.5f, new ConfigDescription("How long the panel stays up after you step off a vehicle (so jumping on deck doesn't hide it).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _maxPlausibleSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Measurement", "Max Plausible Speed", 60f, new ConfigDescription("In m/s. A sudden jump faster than this (a teleport, or ValheimRAFT re-centering a raft after you build on it) restarts the measurement instead of showing a spike. Raise it only if you have tuned vehicles to go faster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 500f), Array.Empty<object>())); _extraVehicleNames = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Measurement", "Extra Vehicle Names", "", "Comma-separated component or object names from other boat mods to treat as vehicles. ValheimRAFT vehicles and vanilla ships are detected without this."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Raft Speedometer 1.0.0 loaded."); } private void Update() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!_enabled.Value) { ClearVehicle(); } else if (GameApi.TryResolve(((BaseUnityPlugin)this).Logger)) { if (GameApi.KeyDown(_toggleKey.Value)) { _hudVisible = !_hudVisible; } if (GameApi.KeyDown(_resetTopKey.Value)) { _topSpeed = 0f; } Tick(); _uiBlocked = (Object)(object)_vehicle != (Object)null && GameApi.IsUiBlocking(); } } private void Tick() { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) Component localPlayer = GameApi.GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { ClearVehicle(); _lastVehicle = null; return; } float time = Time.time; if (time >= _nextScanTime) { _nextScanTime = time + 0.1f; _detector.SetExtraHints(_extraVehicleNames.Value); VehicleMatch match = _detector.Detect(localPlayer); if (match.Found) { _lastOnVehicleTime = time; if ((Object)(object)match.Root != (Object)(object)_vehicle) { BoardVehicle(match); } } } if ((Object)(object)_vehicle == (Object)null) { if (_kind != VehicleKind.None) { ClearVehicle(); } return; } if (time - _lastOnVehicleTime > _leaveDelay.Value) { ClearVehicle(); return; } _tracker.Window = _averagingSeconds.Value; _tracker.MaxPlausibleSpeed = _maxPlausibleSpeed.Value; _tracker.AddSample(time, _vehicle.position); _hasSpeed = _tracker.TryGetSpeed(out _speed, out var span); if (_hasSpeed && _speed < 0.15f) { _speed = 0f; } if (_hasSpeed && span >= _tracker.Window * 0.75f && _speed > _topSpeed) { _topSpeed = _speed; } } private void BoardVehicle(VehicleMatch match) { if ((Object)(object)match.Root != (Object)(object)_lastVehicle) { _topSpeed = 0f; } _vehicle = match.Root; _lastVehicle = match.Root; _kind = match.Kind; _tracker.Clear(); _hasSpeed = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Tracking " + ((_kind == VehicleKind.Raft) ? "ValheimRAFT vehicle" : "ship") + " '" + ((Object)_vehicle).name + "'.")); } private void ClearVehicle() { _vehicle = null; _kind = VehicleKind.None; _tracker.Clear(); _hasSpeed = false; _uiBlocked = false; } private void OnGUI() { if (_hudVisible && !_uiBlocked && !((Object)(object)_vehicle == (Object)null) && _kind != VehicleKind.None) { _hud.Draw(_hasSpeed, _speed, _topSpeed, _kind, new HudSettings { Primary = _primaryUnit.Value, Secondary = _secondaryUnit.Value, ShowTop = _showTop.Value, Anchor = _anchor.Value, OffsetX = _offsetX.Value, OffsetY = _offsetY.Value, Scale = _scale.Value, BackgroundOpacity = _backgroundOpacity.Value }); } } private void OnDestroy() { _hud.Dispose(); } } public enum SpeedUnit { Knots, MetersPerSecond, KilometersPerHour, MilesPerHour } public enum SecondaryUnit { None, Knots, MetersPerSecond, KilometersPerHour, MilesPerHour } public enum ScreenAnchor { TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight } internal struct HudSettings { public SpeedUnit Primary; public SecondaryUnit Secondary; public bool ShowTop; public ScreenAnchor Anchor; public float OffsetX; public float OffsetY; public float Scale; public float BackgroundOpacity; } internal sealed class SpeedHud { private static readonly Color TitleColor = new Color(0.86f, 0.7f, 0.42f, 1f); private static readonly Color ValueColor = new Color(1f, 0.95f, 0.86f, 1f); private static readonly Color DetailColor = new Color(0.8f, 0.76f, 0.68f, 1f); private static readonly Color AccentColor = new Color(0.86f, 0.62f, 0.27f, 0.9f); private static readonly Color ShadowColor = new Color(0f, 0f, 0f, 0.85f); private static readonly Color White = new Color(1f, 1f, 1f, 1f); private Texture2D _pixel; private GUIStyle _title; private GUIStyle _value; private GUIStyle _detail; private GUIStyle _shadow; public void Draw(bool hasSpeed, float metersPerSecond, float topMetersPerSecond, VehicleKind kind, HudSettings s) { //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_012f: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_014e: 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_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0191: 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_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: 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_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) EnsureResources(); float num = (float)Screen.height / 1080f; float num2 = Math.Max(0.35f, s.Scale * num); _title.fontSize = Math.Max(8, (int)Math.Round(13f * num2)); _value.fontSize = Math.Max(10, (int)Math.Round(30f * num2)); _detail.fontSize = Math.Max(8, (int)Math.Round(14f * num2)); string text = ((kind == VehicleKind.Raft) ? "RAFT SPEED" : "SHIP SPEED"); string text2 = (hasSpeed ? Format(metersPerSecond, s.Primary) : "--"); string text3 = null; if (s.Secondary != SecondaryUnit.None && hasSpeed) { text3 = Format(metersPerSecond, (SpeedUnit)(s.Secondary - 1)); } if (s.ShowTop) { string text4 = "top " + Format(topMetersPerSecond, s.Primary); text3 = ((text3 == null) ? text4 : (text3 + " " + text4)); } Vector2 val = _title.CalcSize(new GUIContent(text)); Vector2 val2 = _value.CalcSize(new GUIContent(text2)); Vector2 val3 = (Vector2)((text3 != null) ? _detail.CalcSize(new GUIContent(text3)) : default(Vector2)); float num3 = 14f * num2; float num4 = 8f * num2; float num5 = Math.Max(1f, 2f * num2); float num6 = 1f * num2; float num7 = Math.Max(Math.Max(val.x, Math.Max(val2.x, val3.x)), 150f * num2) + num3 * 2f; float num8 = num5 + num4 + val.y + num6 + val2.y + ((text3 != null) ? (num6 + val3.y) : 0f) + num4; float num9 = s.OffsetX * num; float num10 = s.OffsetY * num; float num11; float num12; switch (s.Anchor) { case ScreenAnchor.TopLeft: num11 = num9; num12 = num10; break; case ScreenAnchor.TopRight: num11 = (float)Screen.width - num7 - num9; num12 = num10; break; case ScreenAnchor.BottomLeft: num11 = num9; num12 = (float)Screen.height - num8 - num10; break; case ScreenAnchor.BottomCenter: num11 = ((float)Screen.width - num7) / 2f + num9; num12 = (float)Screen.height - num8 - num10; break; case ScreenAnchor.BottomRight: num11 = (float)Screen.width - num7 - num9; num12 = (float)Screen.height - num8 - num10; break; default: num11 = ((float)Screen.width - num7) / 2f + num9; num12 = num10; break; } num11 = (float)Math.Round(num11); num12 = (float)Math.Round(num12); Color color = GUI.color; GUI.color = new Color(1f, 1f, 1f, Clamp01(s.BackgroundOpacity)); GUI.DrawTexture(new Rect(num11, num12, num7, num8), (Texture)(object)_pixel); GUI.color = AccentColor; GUI.DrawTexture(new Rect(num11, num12, num7, num5), (Texture)(object)_pixel); GUI.color = White; float shadow = Math.Max(1f, (float)Math.Round(1.5f * num2)); float num13 = num12 + num5 + num4; DrawCentered(text, _title, TitleColor, num11, num13, num7, val.y, shadow); num13 += val.y + num6; DrawCentered(text2, _value, ValueColor, num11, num13, num7, val2.y, shadow); num13 += val2.y + num6; if (text3 != null) { DrawCentered(text3, _detail, DetailColor, num11, num13, num7, val3.y, shadow); } GUI.color = color; } public void Dispose() { if ((Object)(object)_pixel != (Object)null) { Object.Destroy((Object)(object)_pixel); } _pixel = null; } private void DrawCentered(string text, GUIStyle style, Color color, float x, float y, float width, float height, float shadow) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) _shadow.fontSize = style.fontSize; _shadow.fontStyle = style.fontStyle; _shadow.normal.textColor = ShadowColor; GUI.Label(new Rect(x + shadow, y + shadow, width, height), text, _shadow); style.normal.textColor = color; GUI.Label(new Rect(x, y, width, height), text, style); } private void EnsureResources() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_pixel == (Object)null) { _pixel = new Texture2D(1, 1); _pixel.SetPixel(0, 0, new Color(0f, 0f, 0f, 1f)); _pixel.Apply(false, false); ((Object)_pixel).hideFlags = (HideFlags)61; } if (_title == null) { _title = MakeStyle((FontStyle)1); _value = MakeStyle((FontStyle)1); _detail = MakeStyle((FontStyle)0); _shadow = MakeStyle((FontStyle)0); } } private static GUIStyle MakeStyle(FontStyle fontStyle) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return new GUIStyle { fontStyle = fontStyle, alignment = (TextAnchor)4, richText = false }; } internal static string Format(float metersPerSecond, SpeedUnit unit) { return unit switch { SpeedUnit.MetersPerSecond => metersPerSecond.ToString("0.0", CultureInfo.InvariantCulture) + " m/s", SpeedUnit.KilometersPerHour => (metersPerSecond * 3.6f).ToString("0.0", CultureInfo.InvariantCulture) + " km/h", SpeedUnit.MilesPerHour => (metersPerSecond * 2.2369363f).ToString("0.0", CultureInfo.InvariantCulture) + " mph", _ => (metersPerSecond * 1.9438446f).ToString("0.0", CultureInfo.InvariantCulture) + " kn", }; } private static float Clamp01(float v) { if (!(v < 0f)) { if (!(v > 1f)) { return v; } return 1f; } return 0f; } } internal sealed class SpeedTracker { private struct Sample { public float Time; public float X; public float Z; } private const float SampleInterval = 0.05f; private const float MinReportSpan = 0.25f; private readonly Sample[] _buffer = new Sample[256]; private int _start; private int _count; public float Window = 1f; public float MaxPlausibleSpeed = 60f; public void Clear() { _start = 0; _count = 0; } public void AddSample(float time, Vector3 position) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (_count > 0) { Sample sample = Get(_count - 1); float num = time - sample.Time; if (num < 0.05f) { return; } float num2 = position.x - sample.X; float num3 = position.z - sample.Z; if ((float)Math.Sqrt(num2 * num2 + num3 * num3) / num > MaxPlausibleSpeed || num > 2f) { Clear(); } } Push(new Sample { Time = time, X = position.x, Z = position.z }); while (_count > 2 && time - Get(1).Time >= Window) { DropOldest(); } } public bool TryGetSpeed(out float metersPerSecond, out float span) { metersPerSecond = 0f; span = 0f; if (_count < 2) { return false; } Sample sample = Get(0); Sample sample2 = Get(_count - 1); span = sample2.Time - sample.Time; if (span < Math.Min(0.25f, Window)) { return false; } float num = sample2.X - sample.X; float num2 = sample2.Z - sample.Z; metersPerSecond = (float)Math.Sqrt(num * num + num2 * num2) / span; return true; } private Sample Get(int index) { return _buffer[(_start + index) % _buffer.Length]; } private void Push(Sample s) { if (_count == _buffer.Length) { DropOldest(); } _buffer[(_start + _count) % _buffer.Length] = s; _count++; } private void DropOldest() { _start = (_start + 1) % _buffer.Length; _count--; } } internal enum VehicleKind { None, Raft, Ship } internal struct VehicleMatch { public Transform Root; public VehicleKind Kind; public bool Found => (Object)(object)Root != (Object)null; } internal sealed class VehicleDetector { private static readonly string[] RaftTypeNames = new string[3] { "VehiclePiecesController", "MoveableBaseRootComponent", "MoveableBaseShipComponent" }; private readonly RaycastHit[] _hits = (RaycastHit[])(object)new RaycastHit[16]; private string _extraHintsSource; private string[] _extraHints = new string[0]; public void SetExtraHints(string csv) { if ((object)csv != _extraHintsSource) { _extraHintsSource = csv; _extraHints = (csv ?? string.Empty).Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < _extraHints.Length; i++) { _extraHints[i] = _extraHints[i].Trim(); } _extraHints = Array.FindAll(_extraHints, (string h) => h.Length > 0); } } public VehicleMatch Detect(Component player) { Transform transform = player.transform; Transform parent = transform.parent; if ((Object)(object)parent != (Object)null) { VehicleMatch result = Classify(parent); if (result.Found) { return result; } } Collider groundCollider = GameApi.GetGroundCollider(player); if ((Object)(object)groundCollider != (Object)null && !IsUnder(((Component)groundCollider).transform, transform)) { VehicleMatch result2 = Classify(((Component)groundCollider).transform); if (result2.Found) { return result2; } } Transform val = RaycastBelow(transform); if ((Object)(object)val != (Object)null) { VehicleMatch result3 = Classify(val); if (result3.Found) { return result3; } } return default(VehicleMatch); } private VehicleMatch Classify(Transform start) { VehicleMatch result = default(VehicleMatch); int num = 0; Transform val = start; while ((Object)(object)val != (Object)null && num < 48) { VehicleKind vehicleKind = MarkerKind(val); if (vehicleKind != VehicleKind.None) { result.Root = val; result.Kind = vehicleKind; } val = val.parent; num++; } return result; } private VehicleKind MarkerKind(Transform t) { VehicleKind vehicleKind = VehicleKind.None; Component[] components = ((Component)t).GetComponents<Component>(); foreach (Component val in components) { if ((Object)(object)val == (Object)null) { continue; } Type type = ((object)val).GetType(); string name = type.Name; for (int j = 0; j < RaftTypeNames.Length; j++) { if (name == RaftTypeNames[j]) { return VehicleKind.Raft; } } Type type2 = type; while (type2 != null) { if (type2.Name == "Ship") { vehicleKind = VehicleKind.Ship; break; } type2 = type2.BaseType; } if (vehicleKind == VehicleKind.None && MatchesExtraHint(name)) { vehicleKind = VehicleKind.Ship; } } if (vehicleKind == VehicleKind.None && _extraHints.Length != 0 && MatchesExtraHint(((Object)((Component)t).gameObject).name)) { vehicleKind = VehicleKind.Ship; } return vehicleKind; } private bool MatchesExtraHint(string name) { if (string.IsNullOrEmpty(name)) { return false; } for (int i = 0; i < _extraHints.Length; i++) { if (name.IndexOf(_extraHints[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private Transform RaycastBelow(Transform playerTransform) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_000d: 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_001f: 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) Vector3 position = playerTransform.position; int num = Physics.RaycastNonAlloc(new Vector3(position.x, position.y + 0.6f, position.z), new Vector3(0f, -1f, 0f), _hits, 2.6f, -1, (QueryTriggerInteraction)1); Transform result = null; float num2 = float.MaxValue; for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref _hits[i])).collider; if ((Object)(object)collider == (Object)null) { continue; } Transform transform = ((Component)collider).transform; if (!IsUnder(transform, playerTransform)) { float distance = ((RaycastHit)(ref _hits[i])).distance; if (distance < num2) { num2 = distance; result = transform; } } } return result; } private static bool IsUnder(Transform t, Transform ancestor) { int num = 0; Transform val = t; while ((Object)(object)val != (Object)null && num < 48) { if ((Object)(object)val == (Object)(object)ancestor) { return true; } val = val.parent; num++; } return false; } }