using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using RunicBuildCamera.Core; using RunicBuildCamera.Integration; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("RunicBuildCamera")] [assembly: AssemblyDescription("A standalone detached build camera for Valheim.")] [assembly: AssemblyCompany("Chazman Mods")] [assembly: AssemblyProduct("Runic Build Camera")] [assembly: AssemblyCopyright("Copyright © 2026 Chazman")] [assembly: ComVisible(false)] [assembly: Guid("9e457d0a-f7b7-475f-91f0-16f97680663c")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: InternalsVisibleTo("RunicBuildCamera.Tests")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RunicBuildCamera { internal static class CompatibilityGuard { internal const string BuildCameraCheGuid = "Azumatt.BuildCameraCHE"; internal static bool TryFindHardConflict(out string reason) { reason = null; foreach (KeyValuePair pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; object a; if (value == null) { a = null; } else { BepInPlugin metadata = value.Metadata; a = ((metadata != null) ? metadata.GUID : null); } PluginInfo value2 = pluginInfo.Value; object obj; if (value2 == null) { obj = null; } else { BepInPlugin metadata2 = value2.Metadata; obj = ((metadata2 != null) ? metadata2.Name : null); } string text = (string)obj; if (string.Equals((string?)a, "Azumatt.BuildCameraCHE", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "BuildCameraCHE", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "Build Camera Custom Hammers Edition", StringComparison.OrdinalIgnoreCase)) { reason = (text ?? "Azumatt.BuildCameraCHE") + " is installed. Both plugins own the detached build-camera transform, so Runic Build Camera was disabled. Remove or disable one."; return true; } } bool flag = false; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { if (assembly.GetType("Valheim_Build_Camera.Valheim_Build_CameraPlugin", throwOnError: false, ignoreCase: false) == null) { continue; } flag = true; break; } catch (Exception) { } } if (flag) { reason = "Another Build Camera runtime was detected. Runic Build Camera was disabled to prevent two plugins from controlling the same camera."; return true; } return false; } } internal static class BuildCameraConfig { internal const float DefaultCameraRange = 60f; internal const float CameraRangeHardMaximum = 100f; internal const float DefaultRemoteActionDistance = 100f; internal const float RemoteActionDistanceHardMaximum = 100f; private const float MinimumDistance = 1f; private static readonly List UnsubscribeActions = new List(); internal static ConfigEntry Enabled { get; private set; } internal static ConfigEntry ToggleShortcut { get; private set; } internal static ConfigEntry CameraRange { get; private set; } internal static ConfigEntry MoveSpeed { get; private set; } internal static ConfigEntry FastMoveMultiplier { get; private set; } internal static ConfigEntry WorldRelativeMovement { get; private set; } internal static ConfigEntry RemoteActionDistance { get; private set; } internal static ConfigEntry PickupEnabled { get; private set; } internal static ConfigEntry PickupRange { get; private set; } internal static ConfigEntry PickupIntervalSeconds { get; private set; } internal static ConfigEntry DemisterFollowCamera { get; private set; } internal static ConfigEntry DemisterRangeMultiplier { get; private set; } internal static ConfigEntry InvertMouseHorizontal { get; private set; } internal static ConfigEntry InvertMouseVertical { get; private set; } internal static ConfigEntry InvertControllerHorizontal { get; private set; } internal static ConfigEntry InvertControllerVertical { get; private set; } internal static ConfigEntry VerboseLogging { get; private set; } internal static event Action Changed; internal static void Bind(ConfigFile config) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (config == null) { throw new ArgumentNullException("config"); } UnhookChanges(); Enabled = BindEntry(config, "General", "Enabled", defaultValue: true, "Enable Runic Build Camera. Disabling it leaves Valheim's normal build controls unchanged."); ToggleShortcut = BindEntry(config, "Controls", "ToggleShortcut", new KeyboardShortcut((KeyCode)98, Array.Empty()), "Keyboard shortcut that enters or exits the detached build camera."); CameraRange = BindRange(config, "Camera", "CameraRange", 60f, 1f, 100f, "Maximum distance, in metres, that the detached camera may travel from the player."); MoveSpeed = BindRange(config, "Camera", "MoveSpeed", 10f, 0.5f, 50f, "Base detached-camera movement speed in metres per second."); FastMoveMultiplier = BindRange(config, "Camera", "FastMoveMultiplier", 3f, 1f, 10f, "Multiplier applied while the fast-move input is held."); WorldRelativeMovement = BindEntry(config, "Camera", "WorldRelativeMovement", defaultValue: false, "Move on fixed world axes instead of axes derived from the camera view."); RemoteActionDistance = BindRange(config, "Remote Actions", "RemoteActionDistance", 100f, 1f, 100f, "Maximum avatar-to-target distance, in metres, while detached placement, repair, or removal runs. Effective crafting-station build range is raised only inside the scoped call; station data is not changed. Valheim's camera ray remains limited to 50 metres."); PickupEnabled = BindEntry(config, "Pickup", "PickupEnabled", defaultValue: true, "Allow nearby loose world-item drops to be collected while the detached camera is active. Chests and other containers are excluded."); PickupRange = BindRange(config, "Pickup", "PickupRange", 10f, 1f, 50f, "Collection radius, in metres, around the detached camera for eligible loose world items."); PickupIntervalSeconds = BindRange(config, "Pickup", "PickupIntervalSeconds", 0.25f, 0.05f, 2f, "Minimum time, in seconds, between detached-camera pickup scans."); DemisterFollowCamera = BindEntry(config, "Mist", "DemisterFollowCamera", defaultValue: true, "Move the player's active Wisplight mist-clearing effect with the detached camera. This does nothing without an active Wisplight demister."); DemisterRangeMultiplier = BindRange(config, "Mist", "DemisterRangeMultiplier", 2f, 0.25f, 5f, "Multiplier applied to mist-clearing range while it follows the detached camera."); InvertMouseHorizontal = BindEntry(config, "Controls", "InvertMouseHorizontal", defaultValue: false, "Invert horizontal mouse look while the detached camera is active."); InvertMouseVertical = BindEntry(config, "Controls", "InvertMouseVertical", defaultValue: false, "Invert vertical mouse look while the detached camera is active."); InvertControllerHorizontal = BindEntry(config, "Controls", "InvertControllerHorizontal", defaultValue: false, "Invert horizontal controller look while the detached camera is active."); InvertControllerVertical = BindEntry(config, "Controls", "InvertControllerVertical", defaultValue: false, "Invert vertical controller look while the detached camera is active."); VerboseLogging = BindEntry(config, "Diagnostics", "VerboseLogging", defaultValue: false, "Write additional state-transition diagnostics. Per-frame logging remains disabled."); } private static ConfigEntry BindEntry(ConfigFile config, string section, string key, T defaultValue, string description) { ConfigEntry obj = config.Bind(section, key, defaultValue, description); HookChange(obj); return obj; } private static ConfigEntry BindRange(ConfigFile config, string section, string key, float defaultValue, float minimum, float maximum, string description) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown ConfigEntry obj = config.Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(minimum, maximum), Array.Empty())); HookChange(obj); return obj; } private static void HookChange(ConfigEntry entry) { entry.SettingChanged += OnSettingChanged; UnsubscribeActions.Add(delegate { entry.SettingChanged -= OnSettingChanged; }); } private static void UnhookChanges() { foreach (Action unsubscribeAction in UnsubscribeActions) { unsubscribeAction(); } UnsubscribeActions.Clear(); } private static void OnSettingChanged(object sender, EventArgs args) { BuildCameraConfig.Changed?.Invoke(); } } internal static class Diagnostics { private static ManualLogSource _log; internal static bool IsInitialized => _log != null; internal static void Initialize(ManualLogSource log) { _log = log ?? throw new ArgumentNullException("log"); } internal static void Verbose(string message) { if (BuildCameraConfig.VerboseLogging != null && BuildCameraConfig.VerboseLogging.Value) { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)message); } } } internal static void Debug(string message) { if (BuildCameraConfig.VerboseLogging != null && BuildCameraConfig.VerboseLogging.Value) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)message); } } } internal static void Info(string message) { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)message); } } internal static void Warn(string message) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)message); } } internal static void Error(string message) { ManualLogSource log = _log; if (log != null) { log.LogError((object)message); } } internal static void Error(Exception exception, string context) { if (exception == null) { Error(context); return; } ManualLogSource log = _log; if (log != null) { log.LogError((object)(context + Environment.NewLine + exception)); } } } [BepInPlugin("chazman.RunicBuildCamera", "Runic Build Camera", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chazman.RunicBuildCamera"; public const string Name = "Runic Build Camera"; public const string Version = "1.0.0"; private Harmony _harmony; private bool _runtimeReady; private bool _runtimeFailureReported; private void Awake() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown Diagnostics.Initialize(((BaseUnityPlugin)this).Logger); BuildCameraConfig.Bind(((BaseUnityPlugin)this).Config); BuildCameraConfig.Changed += OnConfigurationChanged; try { if (CompatibilityGuard.TryFindHardConflict(out var reason)) { Diagnostics.Warn(reason); Diagnostics.Info("Runic Build Camera v1.0.0 loaded with its camera disabled."); return; } if (!ValheimAdapter.Initialize(out var error)) { Diagnostics.Error(error); Diagnostics.Info("Runic Build Camera v1.0.0 loaded with its camera disabled."); return; } _harmony = new Harmony("chazman.RunicBuildCamera"); _harmony.PatchAll(typeof(Plugin).Assembly); BuildCameraRuntime.Initialize(); _runtimeReady = true; Diagnostics.Info("Runic Build Camera v1.0.0 ready. Precision Build Tool remains an independent plugin and is not required."); } catch (Exception exception) { Diagnostics.Error(exception, "Runic Build Camera startup failed; vanilla camera behavior was preserved."); DisableRuntime(); } } private void Update() { if (!_runtimeReady) { return; } try { BuildCameraRuntime.Tick(); } catch (Exception exception) { BuildCameraRuntime.ForceStop(); RemotePickupRuntime.Reset(); DemisterRuntime.OnCameraExit(); if (!_runtimeFailureReported) { _runtimeFailureReported = true; Diagnostics.Error(exception, "Runic Build Camera stopped after an update failure; normal Valheim camera controls remain available."); } } } private void OnApplicationFocus(bool focused) { if (_runtimeReady) { BuildCameraRuntime.OnApplicationFocus(focused); if (!focused) { RemotePickupRuntime.Reset(); DemisterRuntime.OnCameraExit(); } } } private void OnConfigurationChanged() { if (!_runtimeReady) { return; } try { BuildCameraRuntime.OnConfigurationChanged(); } catch (Exception exception) { BuildCameraRuntime.ForceStop(); Diagnostics.Error(exception, "A configuration change stopped the detached camera safely."); } } private void OnDestroy() { BuildCameraConfig.Changed -= OnConfigurationChanged; DisableRuntime(); } private void DisableRuntime() { _runtimeReady = false; TryCleanup(RemotePickupRuntime.Shutdown, "remote pickup cleanup"); TryCleanup(DemisterRuntime.Shutdown, "mist-effect cleanup"); TryCleanup(BuildCameraRuntime.Shutdown, "camera-session cleanup"); TryCleanup(ValheimAdapter.Shutdown, "Valheim adapter cleanup"); if (_harmony == null) { return; } try { _harmony.UnpatchSelf(); } catch (Exception exception) { Diagnostics.Error(exception, "Runic Build Camera could not remove every Harmony patch during cleanup."); } finally { _harmony = null; } } private static void TryCleanup(Action cleanup, string label) { try { cleanup(); } catch (Exception exception) { Diagnostics.Error(exception, "Runic Build Camera " + label + " encountered an error."); } } } } namespace RunicBuildCamera.Integration { internal static class BuildCameraRuntime { private static readonly BuildCameraSession Session = new BuildCameraSession(); private static bool _initialized; private static bool _focused = true; internal static bool IsActive { get { if (_initialized) { return Session.IsActive; } return false; } } internal static void Initialize() { Session.End(); _focused = Application.isFocused; _initialized = true; } internal static void Shutdown() { Stop(); _initialized = false; } internal static void Tick() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { return; } Player localPlayer = Player.m_localPlayer; if (!ConfigEnabled() || !_focused) { Stop(); return; } if (Session.IsActive && (!SessionBelongsToUsablePlayer(localPlayer) || (Object)(object)GameCamera.instance == (Object)null)) { Stop(); return; } KeyboardShortcut value = BuildCameraConfig.ToggleShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && ((KeyboardShortcut)(ref value)).IsDown()) { if (Session.IsActive) { Stop(); } else if (ValheimAdapter.CanTakeInput(localPlayer)) { TryStart(localPlayer); } } else if (Session.IsActive) { if (ZInput.GetButtonDown("Hide") || ZInput.GetButtonDown("JoyHide") || !ValheimAdapter.IsBuildToolEquipped(localPlayer)) { Stop(); return; } Session.Reanchor(((Component)localPlayer).transform.position); Session.UpdateRange(Positive(BuildCameraConfig.CameraRange.Value, 1f)); } } internal static void OnApplicationFocus(bool focused) { _focused = focused; if (!focused) { Stop(); } } internal static void OnConfigurationChanged() { if (_initialized) { if (!ConfigEnabled()) { Stop(); } else if (Session.IsActive) { Session.UpdateRange(Positive(BuildCameraConfig.CameraRange.Value, 1f)); } } } internal static void OnLocalPlayerAssigned(Player player) { if (Session.IsActive && ((Object)(object)player == (Object)null || !Session.BelongsTo(((Object)player).GetInstanceID()))) { Stop(); } } internal static bool ShouldFreezePlayer(Player player) { if (IsActive && (Object)(object)player != (Object)null && Session.BelongsTo(((Object)player).GetInstanceID())) { return ValheimAdapter.IsLocalPlayer(player); } return false; } internal static ValheimAdapter.RangeLease EnterRemoteActionRange(Player player) { if (!ShouldFreezePlayer(player)) { return null; } float num = Positive(BuildCameraConfig.RemoteActionDistance.Value, 1f); return ValheimAdapter.EnterRemoteActionRange(player, num, num); } internal static bool IsWithinRemoteActionLimit(Player player, Vector3 target) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_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) if (!ShouldFreezePlayer(player) || (Object)(object)((Character)player).m_eye == (Object)null || !IsFinite(target)) { return false; } float num = Positive(BuildCameraConfig.RemoteActionDistance.Value, 1f); Vector3 value = target - ((Character)player).m_eye.position; if (IsFinite(value)) { return (double)((Vector3)(ref value)).sqrMagnitude <= (double)num * (double)num; } return false; } internal static bool TryUpdateCamera(GameCamera camera, float deltaTime) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (!IsActive || (Object)(object)camera == (Object)null) { return false; } Player localPlayer = Player.m_localPlayer; if (!SessionBelongsToUsablePlayer(localPlayer)) { Stop(); return false; } Session.Reanchor(((Component)localPlayer).transform.position); if (_focused && ValheimAdapter.CanTakeInput(localPlayer) && !Console.IsVisible() && ((Object)(object)Hud.instance == (Object)null || !Hud.IsPieceSelectionVisible())) { Session.SetPose(StepCamera(Session, deltaTime)); } ((Component)camera).transform.SetPositionAndRotation(Session.Position, Session.Rotation); return true; } internal static bool TryGetActiveContext(out Player player, out Vector3 cameraPosition, out Quaternion cameraRotation) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_004a: Unknown result type (might be due to invalid IL or missing references) player = Player.m_localPlayer; if (!IsActive || !SessionBelongsToUsablePlayer(player)) { cameraPosition = Vector3.zero; cameraRotation = Quaternion.identity; return false; } cameraPosition = Session.Position; cameraRotation = Session.Rotation; return true; } internal static void ForceStop() { Stop(); } private static void TryStart(Player player) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (ValheimAdapter.IsBuildToolEquipped(player)) { GameCamera instance = GameCamera.instance; if (!((Object)(object)instance == (Object)null)) { float range = Positive(BuildCameraConfig.CameraRange.Value, 1f); Session.Begin(((Object)player).GetInstanceID(), ((Component)player).transform.position, ((Component)instance).transform.position, ((Component)instance).transform.rotation, range); } } } private static CameraPose StepCamera(BuildCameraSession session, float deltaTime) { //IL_0137: 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_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: 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_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) float right = ButtonAxis("Right", "Left") + ZInput.GetJoyLeftStickX(false); float forward = ButtonAxis("Forward", "Backward") - ZInput.GetJoyLeftStickY(true); float up = ((ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump")) ? 1f : 0f) - ((ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch")) ? 1f : 0f); float num = Input.GetAxis("Mouse X") * PlayerController.m_mouseSens; float num2 = Input.GetAxis("Mouse Y") * PlayerController.m_mouseSens; float num3 = ZInput.GetJoyRightStickX(true) * 110f * deltaTime; float num4 = ZInput.GetJoyRightStickY(true) * 110f * deltaTime; if (BuildCameraConfig.InvertMouseHorizontal.Value) { num = 0f - num; } if (PlayerController.m_invertMouse) { num2 = 0f - num2; } if (BuildCameraConfig.InvertMouseVertical.Value) { num2 = 0f - num2; } if (BuildCameraConfig.InvertControllerHorizontal.Value) { num3 = 0f - num3; } if (BuildCameraConfig.InvertControllerVertical.Value) { num4 = 0f - num4; } CameraMotionInput input = new CameraMotionInput(right, up, forward, num + num3, 0f - num2 + num4, ZInput.GetButton("Run") || ZInput.GetButton("JoyRun")); CameraPose result = CameraMotion.Step(session.Position, session.Yaw, session.Pitch, session.Anchor, session.Range, in input, deltaTime, Positive(BuildCameraConfig.MoveSpeed.Value, 0f), Positive(BuildCameraConfig.FastMoveMultiplier.Value, 1f), BuildCameraConfig.WorldRelativeMovement.Value); float num5 = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(result.Position, ref num5) && result.Position.y < num5) { Vector3 position = result.Position; position.y = num5; position = CameraMotion.ClampToAnchor(position, session.Anchor, session.Range); result = new CameraPose(position, result.Yaw, result.Pitch); } return result; } private static float ButtonAxis(string positive, string negative) { return (ZInput.GetButton(positive) ? 1f : 0f) - (ZInput.GetButton(negative) ? 1f : 0f); } private static bool SessionBelongsToUsablePlayer(Player player) { if ((Object)(object)player != (Object)null && Session.BelongsTo(((Object)player).GetInstanceID())) { return ValheimAdapter.IsUsableLocalPlayer(player); } return false; } private static bool ConfigEnabled() { if (BuildCameraConfig.Enabled != null && BuildCameraConfig.ToggleShortcut != null && BuildCameraConfig.CameraRange != null && BuildCameraConfig.MoveSpeed != null && BuildCameraConfig.FastMoveMultiplier != null && BuildCameraConfig.WorldRelativeMovement != null && BuildCameraConfig.RemoteActionDistance != null && BuildCameraConfig.InvertMouseHorizontal != null && BuildCameraConfig.InvertMouseVertical != null && BuildCameraConfig.InvertControllerHorizontal != null && BuildCameraConfig.InvertControllerVertical != null) { return BuildCameraConfig.Enabled.Value; } return false; } private static float Positive(float value, float fallback) { if (float.IsNaN(value) || float.IsInfinity(value) || !(value > 0f)) { return fallback; } return value; } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private static void Stop() { if (Session.IsActive) { Session.End(); } ValheimAdapter.ForceRestoreRanges(); } } internal static class PlayerUpdateInputIsolation { [ThreadStatic] private static int _depth; [ThreadStatic] private static Player _player; [ThreadStatic] private static bool _captured; [ThreadStatic] private static bool _originalTakeInput; internal static bool Enter(Player player) { if (!BuildCameraRuntime.ShouldFreezePlayer(player)) { return false; } if (_depth == 0) { _player = player; _captured = false; _originalTakeInput = false; } _depth++; return true; } internal static void CaptureTakeInput(Player player, bool original) { if (_depth > 0 && !((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)_player)) { _captured = true; _originalTakeInput = original; } } internal static bool ShouldSuppress(Player player) { if (_depth > 0 && (Object)(object)player != (Object)null) { return (Object)(object)player == (Object)(object)_player; } return false; } internal static bool PlacementInput(Player player, bool current) { if (!ShouldSuppress(player) || !_captured) { return current; } return _originalTakeInput; } internal static void Exit() { if (_depth > 0) { _depth--; if (_depth == 0) { _player = null; _captured = false; _originalTakeInput = false; } } } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerUpdateInputScopePatch { private static void Prefix(Player __instance, ref bool __state) { try { __state = PlayerUpdateInputIsolation.Enter(__instance); } catch { __state = false; BuildCameraRuntime.ForceStop(); } } private static Exception Finalizer(Exception __exception, bool __state) { if (__state) { PlayerUpdateInputIsolation.Exit(); } return __exception; } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class PlayerTakeInputIsolationPatch { private static void Postfix(Player __instance, ref bool __result) { if (PlayerUpdateInputIsolation.ShouldSuppress(__instance)) { PlayerUpdateInputIsolation.CaptureTakeInput(__instance, __result); __result = false; } } } [HarmonyPatch(typeof(Player), "SetMouseLook", new Type[] { typeof(Vector2) })] internal static class PlayerSetMouseLookIsolationPatch { private static void Prefix(Player __instance, ref Vector2 mouseLook) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (BuildCameraRuntime.ShouldFreezePlayer(__instance)) { mouseLook = Vector2.zero; } } } [HarmonyPatch(typeof(CraftingStation), "GetStationBuildRange")] internal static class CraftingStationScopedBuildRangePatch { private static void Postfix(ref float __result) { if (ValheimAdapter.TryGetScopedStationRange(out var range) && __result < range) { __result = range; } } } [HarmonyPatch(typeof(Player), "PieceRayTest")] internal static class PlayerPieceRayRemoteLimitPatch { private static void Postfix(Player __instance, [HarmonyArgument("point")] ref Vector3 point, ref bool __result) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (__result && BuildCameraRuntime.ShouldFreezePlayer(__instance) && !BuildCameraRuntime.IsWithinRemoteActionLimit(__instance, point)) { __result = false; } } } [HarmonyPatch] internal static class GameCameraUpdateCameraPatch { private static MethodBase TargetMethod() { return ValheimAdapter.UpdateCameraMethod; } private static bool Prefix(GameCamera __instance, float dt) { try { return !BuildCameraRuntime.TryUpdateCamera(__instance, dt); } catch { BuildCameraRuntime.ForceStop(); return true; } } } [HarmonyPatch] internal static class PlayerSetControlsPatch { private static MethodBase TargetMethod() { return ValheimAdapter.SetControlsMethod; } private static void Prefix(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (BuildCameraRuntime.ShouldFreezePlayer(__instance)) { movedir = Vector3.zero; attack = false; attackHold = false; secondaryAttack = false; secondaryAttackHold = false; block = false; blockHold = false; jump = false; crouch = false; run = false; autoRun = false; dodge = false; } } } [HarmonyPatch] internal static class PlayerUpdatePlacementRangePatch { private static MethodBase TargetMethod() { return ValheimAdapter.UpdatePlacementMethod; } [HarmonyPriority(800)] [HarmonyBefore(new string[] { "chazman.RunicPrecisionBuildTool" })] private static void Prefix(Player __instance, ref bool takeInput, ref ValheimAdapter.RangeLease __state) { try { takeInput = PlayerUpdateInputIsolation.PlacementInput(__instance, takeInput); __state = BuildCameraRuntime.EnterRemoteActionRange(__instance); } catch { __state = null; BuildCameraRuntime.ForceStop(); } } private static Exception Finalizer(Exception __exception, ValheimAdapter.RangeLease __state) { try { __state?.Dispose(); } catch { BuildCameraRuntime.ForceStop(); } return __exception; } } [HarmonyPatch] internal static class PlayerUpdatePlacementGhostRangePatch { private static MethodBase TargetMethod() { return ValheimAdapter.UpdatePlacementGhostMethod; } private static void Prefix(Player __instance, ref ValheimAdapter.RangeLease __state) { try { __state = BuildCameraRuntime.EnterRemoteActionRange(__instance); } catch { __state = null; BuildCameraRuntime.ForceStop(); } } private static Exception Finalizer(Exception __exception, ValheimAdapter.RangeLease __state) { try { __state?.Dispose(); } catch { BuildCameraRuntime.ForceStop(); } return __exception; } } [HarmonyPatch(typeof(Player), "SetLocalPlayer")] internal static class PlayerSetLocalPlayerCameraCleanupPatch { private static void Postfix(Player __instance) { try { BuildCameraRuntime.OnLocalPlayerAssigned(__instance); } catch { BuildCameraRuntime.ForceStop(); } } } internal static class DemisterRuntime { private readonly struct ForceFieldBaseline { internal ParticleSystemForceField Field { get; } internal float EndRange { get; } internal ForceFieldBaseline(ParticleSystemForceField field, float endRange) { Field = field; EndRange = endRange; } } private sealed class BallState { internal GameObject Ball { get; } internal ForceFieldBaseline[] ForceFields { get; } internal BallState(GameObject ball, ForceFieldBaseline[] forceFields) { Ball = ball; ForceFields = forceFields ?? Array.Empty(); } } private static readonly FieldInfo BallInstanceField = AccessTools.Field(typeof(SE_Demister), "m_ballInstance"); private static readonly Dictionary BallStates = new Dictionary(); private static readonly Dictionary EffectBallIds = new Dictionary(); private static bool _subscribed; internal static void AfterStatusEffectUpdate(SE_Demister effect) { //IL_00b0: 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) EnsureSubscribed(); if ((Object)(object)effect == (Object)null) { RefreshActiveState(); return; } GameObject ball = GetBall(effect); if (!Object.op_Implicit((Object)(object)ball)) { RestoreEffect(effect); PruneDestroyedBalls(); return; } int instanceID = ((Object)effect).GetInstanceID(); int instanceID2 = ((Object)ball).GetInstanceID(); if (EffectBallIds.TryGetValue(instanceID, out var value) && value != instanceID2) { RestoreBall(value); } EffectBallIds[instanceID] = instanceID2; bool num = BuildCameraConfig.DemisterFollowCamera != null && BuildCameraConfig.DemisterFollowCamera.Value; Player player; Vector3 cameraPosition; Quaternion cameraRotation; bool flag = BuildCameraRuntime.TryGetActiveContext(out player, out cameraPosition, out cameraRotation); if (!num || !flag || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)((StatusEffect)effect).m_character != (Object)(object)player || !IsFinite(cameraPosition)) { RestoreEffect(effect); return; } BallState orCaptureBall = GetOrCaptureBall(ball); if (orCaptureBall != null) { float multiplier = ((BuildCameraConfig.DemisterRangeMultiplier != null) ? BuildCameraConfig.DemisterRangeMultiplier.Value : 1f); ApplyRange(orCaptureBall, multiplier); ball.transform.position = cameraPosition; PruneDestroyedBalls(); } } internal static void BeforeRemoveEffects(SE_Demister effect) { EnsureSubscribed(); RestoreEffect(effect); PruneDestroyedBalls(); } internal static void RefreshActiveState() { EnsureSubscribed(); if (BuildCameraConfig.DemisterFollowCamera == null || !BuildCameraConfig.DemisterFollowCamera.Value || !BuildCameraRuntime.TryGetActiveContext(out var _, out var _, out var _)) { RestoreAll(); } else { PruneDestroyedBalls(); } } internal static void OnCameraExit() { RestoreAll(); } internal static void Shutdown() { if (_subscribed) { BuildCameraConfig.Changed -= OnConfigurationChanged; _subscribed = false; } RestoreAll(); } private static BallState GetOrCaptureBall(GameObject ball) { int instanceID = ((Object)ball).GetInstanceID(); if (BallStates.TryGetValue(instanceID, out var value) && value.Ball == ball) { return value; } if (value != null) { RestoreState(value); } ParticleSystemForceField[] array; try { array = ball.GetComponentsInChildren(true); } catch { array = Array.Empty(); } List list = new List(array.Length); ParticleSystemForceField[] array2 = array; foreach (ParticleSystemForceField val in array2) { if (Object.op_Implicit((Object)(object)val)) { list.Add(new ForceFieldBaseline(val, val.endRange)); } } BallState ballState = new BallState(ball, list.ToArray()); BallStates[instanceID] = ballState; return ballState; } private static void ApplyRange(BallState state, float multiplier) { float num = ((IsFinite(multiplier) && multiplier > 0f) ? multiplier : 1f); ForceFieldBaseline[] forceFields = state.ForceFields; for (int i = 0; i < forceFields.Length; i++) { ForceFieldBaseline forceFieldBaseline = forceFields[i]; ParticleSystemForceField field = forceFieldBaseline.Field; if (Object.op_Implicit((Object)(object)field)) { double num2 = (double)forceFieldBaseline.EndRange * (double)num; field.endRange = ((double.IsNaN(num2) || double.IsInfinity(num2) || num2 > 3.4028234663852886E+38 || num2 < -3.4028234663852886E+38) ? forceFieldBaseline.EndRange : ((float)num2)); } } } private static void RestoreEffect(SE_Demister effect) { if ((Object)(object)effect == (Object)null) { return; } int instanceID = ((Object)effect).GetInstanceID(); if (EffectBallIds.TryGetValue(instanceID, out var value)) { RestoreBall(value); EffectBallIds.Remove(instanceID); return; } GameObject ball = GetBall(effect); if (Object.op_Implicit((Object)(object)ball)) { RestoreBall(((Object)ball).GetInstanceID()); } } private static void RestoreBall(int ballId) { if (!BallStates.TryGetValue(ballId, out var value)) { return; } RestoreState(value); BallStates.Remove(ballId); List list = null; foreach (KeyValuePair effectBallId in EffectBallIds) { if (effectBallId.Value == ballId) { if (list == null) { list = new List(); } list.Add(effectBallId.Key); } } if (list == null) { return; } foreach (int item in list) { EffectBallIds.Remove(item); } } private static void RestoreState(BallState state) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) ForceFieldBaseline[] forceFields = state.ForceFields; for (int i = 0; i < forceFields.Length; i++) { ForceFieldBaseline forceFieldBaseline = forceFields[i]; ParticleSystemForceField field = forceFieldBaseline.Field; if (Object.op_Implicit((Object)(object)field)) { field.endRange = forceFieldBaseline.EndRange; } } Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)state.Ball) && Object.op_Implicit((Object)(object)localPlayer)) { state.Ball.transform.position = ((Character)localPlayer).GetCenterPoint(); } } private static void RestoreAll() { foreach (BallState value in BallStates.Values) { RestoreState(value); } BallStates.Clear(); EffectBallIds.Clear(); } private static void PruneDestroyedBalls() { List list = null; foreach (KeyValuePair ballState in BallStates) { if (!Object.op_Implicit((Object)(object)ballState.Value.Ball)) { if (list == null) { list = new List(); } list.Add(ballState.Key); } } if (list == null) { return; } foreach (int item in list) { RestoreBall(item); } } private static GameObject GetBall(SE_Demister effect) { if ((Object)(object)effect == (Object)null || BallInstanceField == null || BallInstanceField.FieldType != typeof(GameObject) || BallInstanceField.IsStatic) { return null; } try { object? value = BallInstanceField.GetValue(effect); return (GameObject)((value is GameObject) ? value : null); } catch { return null; } } private static void EnsureSubscribed() { if (!_subscribed) { BuildCameraConfig.Changed += OnConfigurationChanged; _subscribed = true; } } private static void OnConfigurationChanged() { RestoreAll(); } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(value.x) && IsFinite(value.y)) { return IsFinite(value.z); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } [HarmonyPatch] internal static class GameCameraRemoteEffectsPatch { private static MethodBase TargetMethod() { return ValheimAdapter.UpdateCameraMethod; } private static void Postfix() { try { RemotePickupRuntime.Tick(); DemisterRuntime.RefreshActiveState(); } catch { RemotePickupRuntime.Reset(); DemisterRuntime.OnCameraExit(); } } } [HarmonyPatch(typeof(SE_Demister), "UpdateStatusEffect")] internal static class DemisterUpdateStatusEffectPatch { private static void Postfix(SE_Demister __instance) { try { DemisterRuntime.AfterStatusEffectUpdate(__instance); } catch { DemisterRuntime.OnCameraExit(); } } } [HarmonyPatch(typeof(SE_Demister), "RemoveEffects")] internal static class DemisterRemoveEffectsPatch { private static void Prefix(SE_Demister __instance) { try { DemisterRuntime.BeforeRemoveEffects(__instance); } catch { DemisterRuntime.OnCameraExit(); } } } [HarmonyPatch(typeof(Player), "SetLocalPlayer")] internal static class RemoteEffectsLocalPlayerCleanupPatch { private static void Prefix() { RemotePickupRuntime.Reset(); DemisterRuntime.OnCameraExit(); } } internal static class RemotePickupRuntime { private readonly struct CooldownEntry { internal float RetryAt { get; } internal long Ordinal { get; } internal CooldownEntry(float retryAt, long ordinal) { RetryAt = retryAt; Ordinal = ordinal; } } private static readonly Collider[] ColliderBuffer = (Collider[])(object)new Collider[128]; private static readonly HashSet SeenThisScan = new HashSet(); private static readonly Dictionary Cooldowns = new Dictionary(); private static readonly FieldInfo EnableAutoPickupField = AccessTools.Field(typeof(Player), "m_enableAutoPickup"); private static readonly FieldInfo AutoPickupMaskField = AccessTools.Field(typeof(Player), "m_autoPickupMask"); private static bool _subscribed; private static bool _wasActive; private static Player _lastPlayer; private static float _nextScanAt; private static long _cooldownOrdinal; internal static void Tick() { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) EnsureSubscribed(); Player player; Vector3 cameraPosition; Quaternion cameraRotation; bool flag = BuildCameraRuntime.TryGetActiveContext(out player, out cameraPosition, out cameraRotation); if (!(BuildCameraRuntime.IsActive && BuildCameraConfig.PickupEnabled != null && BuildCameraConfig.PickupEnabled.Value && flag) || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsTeleporting() || !TryReadAutoPickupState(player, out var enabled, out var pickupMask) || !enabled) { if (_wasActive || (Object)(object)_lastPlayer != (Object)null || Cooldowns.Count != 0) { ResetTransientState(); } return; } if ((Object)(object)player != (Object)(object)_lastPlayer) { ResetTransientState(); _lastPlayer = player; } _wasActive = true; float time = Time.time; if (!PickupPolicy.IsScanDue(time, _nextScanAt)) { return; } float num = ((BuildCameraConfig.PickupIntervalSeconds != null) ? BuildCameraConfig.PickupIntervalSeconds.Value : 0.2f); _nextScanAt = PickupPolicy.NextScanAt(time, num); float num2 = ((BuildCameraConfig.PickupRange != null) ? BuildCameraConfig.PickupRange.Value : 0f); if (!float.IsNaN(num2) && !float.IsInfinity(num2) && !(num2 <= 0f) && IsFinite(cameraPosition)) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { Scan(player, inventory, cameraPosition, num2, num, time, pickupMask); } } } internal static void Reset() { ResetTransientState(); } internal static void Shutdown() { if (_subscribed) { BuildCameraConfig.Changed -= OnConfigurationChanged; _subscribed = false; } ResetTransientState(); } private static void Scan(Player player, Inventory inventory, Vector3 cameraPosition, float range, float interval, float now, int pickupMask) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0155: 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) int val; try { val = Physics.OverlapSphereNonAlloc(cameraPosition, range, ColliderBuffer, pickupMask); } catch { return; } SeenThisScan.Clear(); PruneExpiredCooldowns(now); int num = 0; try { int num2 = Math.Min(val, ColliderBuffer.Length); for (int i = 0; i < num2; i++) { if (num >= 16) { break; } Collider val2 = ColliderBuffer[i]; if (!Object.op_Implicit((Object)(object)val2)) { continue; } ItemDrop val3 = ResolveLooseItem(val2); if (!Object.op_Implicit((Object)(object)val3)) { continue; } ZNetView component = ((Component)val3).GetComponent(); ZDO val4 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val4 == null || ((ZDOID)(ref val4.m_uid)).IsNone() || !SeenThisScan.Add(val4.m_uid)) { continue; } try { val3.Load(); if (!TryEvaluate(val3, val4.m_uid, player, inventory, cameraPosition, range, now)) { continue; } val3.RequestOwn(); num++; if (!val3.CanPickup(true)) { SetCooldown(val4.m_uid, PickupPolicy.OwnershipRetryAt(now, interval)); continue; } val3.Load(); if (!TryEvaluate(val3, val4.m_uid, player, inventory, cameraPosition, range, now, ignoreCooldown: true)) { SetCooldown(val4.m_uid, PickupPolicy.FailedPickupRetryAt(now)); continue; } bool flag = ((Humanoid)player).Pickup(((Component)val3).gameObject, true, true); SetCooldown(val4.m_uid, flag ? PickupPolicy.CompletedPickupRetryAt(now) : PickupPolicy.FailedPickupRetryAt(now)); } catch { SetCooldown(val4.m_uid, PickupPolicy.FailedPickupRetryAt(now)); } } } finally { SeenThisScan.Clear(); for (int j = 0; j < Math.Min(val, ColliderBuffer.Length); j++) { ColliderBuffer[j] = null; } } } private static bool TryEvaluate(ItemDrop itemDrop, ZDOID id, Player player, Inventory inventory, Vector3 cameraPosition, float range, float now, bool ignoreCooldown = false) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) ItemData itemData = itemDrop.m_itemData; SharedData val = itemData?.m_shared; if (itemData == null || val == null) { return false; } CooldownEntry value; bool isCoolingDown = !ignoreCooldown && Cooldowns.TryGetValue(id, out value) && now < value.RetryAt; Vector3 position = ((Component)itemDrop).transform.position; int num; if (IsFinite(position)) { Vector3 val2 = position - cameraPosition; num = (PickupPolicy.IsWithinRange(((Vector3)(ref val2)).sqrMagnitude, range) ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; bool wardAllows = flag && PrivateArea.CheckAccess(position, 0f, false, true); bool isUniqueOrQuestItem = val.m_questItem || ((Humanoid)player).HaveUniqueKey(val.m_name); bool inventoryCanAdd = inventory.CanAddItem(itemData, -1); float weight = itemData.GetWeight(-1); float num2 = inventory.GetTotalWeight() + weight; float maxCarryWeight = player.GetMaxCarryWeight(); bool wouldExceedCarryWeight = float.IsNaN(weight) || float.IsInfinity(weight) || weight < 0f || float.IsNaN(num2) || float.IsInfinity(num2) || float.IsNaN(maxCarryWeight) || float.IsInfinity(maxCarryWeight) || num2 > maxCarryWeight; return PickupPolicy.Evaluate(new PickupCandidateFacts(!((ZDOID)(ref id)).IsNone(), flag, wardAllows, itemDrop.m_autoPickup, itemDrop.IsPiece(), itemDrop.InTar(), isUniqueOrQuestItem, inventoryCanAdd, wouldExceedCarryWeight, isCoolingDown)) == PickupRejectionReason.None; } private static ItemDrop ResolveLooseItem(Collider collider) { Rigidbody attachedRigidbody = collider.attachedRigidbody; if (!Object.op_Implicit((Object)(object)attachedRigidbody)) { return null; } ItemDrop component = ((Component)attachedRigidbody).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return component; } FloatingTerrainDummy component2 = ((Component)attachedRigidbody).GetComponent(); if (!Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component2.m_parent)) { return null; } return ((Component)component2.m_parent).gameObject.GetComponent(); } private static void SetCooldown(ZDOID id, float retryAt) { //IL_000f: 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 (!((ZDOID)(ref id)).IsNone()) { if (!Cooldowns.ContainsKey(id) && Cooldowns.Count >= 256) { RemoveOldestCooldown(); } if (_cooldownOrdinal == long.MaxValue) { Cooldowns.Clear(); _cooldownOrdinal = 0L; } long ordinal = ++_cooldownOrdinal; Cooldowns[id] = new CooldownEntry(retryAt, ordinal); } } private static void PruneExpiredCooldowns(float now) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (Cooldowns.Count == 0) { return; } List list = null; foreach (KeyValuePair cooldown in Cooldowns) { if (!(now < cooldown.Value.RetryAt)) { if (list == null) { list = new List(); } list.Add(cooldown.Key); } } if (list == null) { return; } foreach (ZDOID item in list) { Cooldowns.Remove(item); } } private static void RemoveOldestCooldown() { //IL_0002: 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_0042: 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_007a: Unknown result type (might be due to invalid IL or missing references) bool flag = false; ZDOID key = ZDOID.None; long num = long.MaxValue; foreach (KeyValuePair cooldown in Cooldowns) { if (!flag || cooldown.Value.Ordinal < num) { flag = true; key = cooldown.Key; num = cooldown.Value.Ordinal; } } if (flag) { Cooldowns.Remove(key); } } private static void EnsureSubscribed() { if (!_subscribed) { BuildCameraConfig.Changed += OnConfigurationChanged; _subscribed = true; } } private static void OnConfigurationChanged() { ResetTransientState(); } private static void ResetTransientState() { _wasActive = false; _lastPlayer = null; _nextScanAt = 0f; _cooldownOrdinal = 0L; Cooldowns.Clear(); SeenThisScan.Clear(); Array.Clear(ColliderBuffer, 0, ColliderBuffer.Length); } private static bool TryReadAutoPickupState(Player player, out bool enabled, out int pickupMask) { enabled = false; pickupMask = 0; if ((Object)(object)player == (Object)null || EnableAutoPickupField == null || AutoPickupMaskField == null || EnableAutoPickupField.FieldType != typeof(bool) || AutoPickupMaskField.FieldType != typeof(int) || !EnableAutoPickupField.IsStatic || AutoPickupMaskField.IsStatic) { return false; } try { enabled = (bool)EnableAutoPickupField.GetValue(null); pickupMask = (int)AutoPickupMaskField.GetValue(player); return pickupMask != 0; } catch { enabled = false; pickupMask = 0; return false; } } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } } internal static class ValheimAdapter { private delegate bool TakeInputDelegate(Player player); internal sealed class RangeState { internal Player Player; internal float Original; internal float Requested; internal int Depth; } internal sealed class RangeLease : IDisposable { private readonly int _playerId; private readonly RangeState _state; private bool _disposed; internal RangeLease(int playerId, RangeState state) { _playerId = playerId; _state = state; } public void Dispose() { if (!_disposed) { _disposed = true; ExitRange(_playerId, _state); } } } private static readonly Dictionary RangeStates = new Dictionary(); private static FieldRef _maxPlaceDistance; private static FieldRef _rightItem; private static TakeInputDelegate _takeInput; private static bool _initialized; internal static MethodInfo UpdatePlacementMethod { get; private set; } internal static MethodInfo UpdatePlacementGhostMethod { get; private set; } internal static MethodInfo UpdateCameraMethod { get; private set; } internal static MethodInfo SetControlsMethod { get; private set; } internal static bool Initialize(out string error) { error = null; if (_initialized) { return true; } try { _maxPlaceDistance = AccessTools.FieldRefAccess(RequireField(typeof(Player), "m_maxPlaceDistance", typeof(float))); _rightItem = AccessTools.FieldRefAccess(RequireField(typeof(Humanoid), "m_rightItem", typeof(ItemData))); UpdatePlacementMethod = RequireMethod(typeof(Player), "UpdatePlacement", typeof(void), typeof(bool), typeof(float)); UpdatePlacementGhostMethod = RequireMethod(typeof(Player), "UpdatePlacementGhost", typeof(void), typeof(bool)); UpdateCameraMethod = RequireMethod(typeof(GameCamera), "UpdateCamera", typeof(void), typeof(float)); SetControlsMethod = RequireMethod(typeof(Player), "SetControls", typeof(void), typeof(Vector3), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool)); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "TakeInput", Type.EmptyTypes, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { throw new MissingMethodException(typeof(Player).FullName, "TakeInput()"); } _takeInput = AccessTools.MethodDelegate(methodInfo, (object)null, true); _initialized = true; return true; } catch (Exception ex) { Shutdown(); error = "Valheim camera adapter verification failed: " + ex.GetType().Name + ": " + ex.Message; return false; } } internal static void Shutdown() { ForceRestoreRanges(); _maxPlaceDistance = null; _rightItem = null; _takeInput = null; UpdatePlacementMethod = null; UpdatePlacementGhostMethod = null; UpdateCameraMethod = null; SetControlsMethod = null; _initialized = false; } internal static bool IsLocalPlayer(Player player) { if ((Object)(object)player != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } internal static bool IsUsableLocalPlayer(Player player) { if (!IsLocalPlayer(player)) { return false; } try { return !((Character)player).IsDead() && !((Character)player).IsTeleporting(); } catch { return false; } } internal static bool IsBuildToolEquipped(Player player) { if (!IsUsableLocalPlayer(player)) { return false; } try { ItemData val = ((_rightItem != null) ? _rightItem.Invoke((Humanoid)(object)player) : null); return val != null && val.m_shared != null && (Object)(object)val.m_shared.m_buildPieces != (Object)null && ((Character)player).InPlaceMode(); } catch { return false; } } internal static bool CanTakeInput(Player player) { if (!IsUsableLocalPlayer(player) || _takeInput == null) { return false; } try { return _takeInput(player); } catch { return false; } } internal static RangeLease EnterRemoteActionRange(Player player, float requestedPlayerRange, float requestedStationRange) { if (!_initialized || !IsLocalPlayer(player) || _maxPlaceDistance == null || !IsFinite(requestedPlayerRange) || !IsPositiveFinite(requestedStationRange)) { return null; } int instanceID = ((Object)player).GetInstanceID(); if (!RangeStates.TryGetValue(instanceID, out var value)) { value = new RangeState { Player = player, Original = _maxPlaceDistance.Invoke(player), Requested = requestedStationRange, Depth = 0 }; RangeStates.Add(instanceID, value); } value.Depth++; _maxPlaceDistance.Invoke(player) = requestedPlayerRange; return new RangeLease(instanceID, value); } internal static void ForceRestoreRanges() { foreach (RangeState value in RangeStates.Values) { try { if ((Object)(object)value.Player != (Object)null && _maxPlaceDistance != null) { _maxPlaceDistance.Invoke(value.Player) = value.Original; } } catch { } } RangeStates.Clear(); } internal static bool TryGetScopedStationRange(out float range) { foreach (RangeState value in RangeStates.Values) { if (value.Depth > 0 && IsPositiveFinite(value.Requested)) { range = value.Requested; return true; } } range = 0f; return false; } private static void ExitRange(int playerId, RangeState expected) { if (!RangeStates.TryGetValue(playerId, out var value) || value != expected) { return; } value.Depth--; if (value.Depth <= 0) { if ((Object)(object)value.Player != (Object)null && _maxPlaceDistance != null) { _maxPlaceDistance.Invoke(value.Player) = value.Original; } RangeStates.Remove(playerId); } } private static FieldInfo RequireField(Type owner, string name, Type fieldType) { FieldInfo fieldInfo = AccessTools.Field(owner, name); if (fieldInfo == null || fieldInfo.FieldType != fieldType) { throw new MissingFieldException(owner.FullName, name); } return fieldInfo; } private static MethodInfo RequireMethod(Type owner, string name, Type returnType, params Type[] parameters) { MethodInfo methodInfo = AccessTools.Method(owner, name, parameters, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != returnType) { throw new MissingMethodException(owner.FullName, name); } return methodInfo; } private static bool IsPositiveFinite(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return value > 0f; } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } } namespace RunicBuildCamera.Core { internal sealed class BuildCameraSession { internal bool IsActive { get; private set; } internal int PlayerInstanceId { get; private set; } internal Vector3 Anchor { get; private set; } internal Vector3 Position { get; private set; } internal float Yaw { get; private set; } internal float Pitch { get; private set; } internal float Range { get; private set; } internal Quaternion Rotation => Quaternion.Euler(Pitch, Yaw, 0f); internal bool Begin(int playerInstanceId, Vector3 anchor, Vector3 cameraPosition, Quaternion cameraRotation, float range) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (playerInstanceId == 0 || !IsFinite(anchor) || !IsFinite(cameraPosition) || !IsFinite(cameraRotation) || !IsPositiveFinite(range)) { return false; } Vector3 eulerAngles = ((Quaternion)(ref cameraRotation)).eulerAngles; IsActive = true; PlayerInstanceId = playerInstanceId; Anchor = anchor; Range = range; Yaw = CameraMotion.NormalizeAngle(eulerAngles.y); Pitch = Mathf.Clamp(CameraMotion.NormalizeAngle(eulerAngles.x), -89f, 89f); Position = CameraMotion.ClampToAnchor(cameraPosition, anchor, range); return true; } internal bool BelongsTo(int playerInstanceId) { if (IsActive && playerInstanceId != 0) { return PlayerInstanceId == playerInstanceId; } return false; } internal void Reanchor(Vector3 anchor) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (IsActive && IsFinite(anchor)) { Vector3 val = anchor - Anchor; Anchor = anchor; Position = CameraMotion.ClampToAnchor(Position + val, Anchor, Range); } } internal void SetPose(in CameraPose pose) { //IL_0009: 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_0038: 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) if (IsActive && IsFinite(pose.Position) && IsFinite(pose.Yaw) && IsFinite(pose.Pitch)) { Position = CameraMotion.ClampToAnchor(pose.Position, Anchor, Range); Yaw = CameraMotion.NormalizeAngle(pose.Yaw); Pitch = Mathf.Clamp(pose.Pitch, -89f, 89f); } } internal void UpdateRange(float range) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (IsActive && IsPositiveFinite(range)) { Range = range; Position = CameraMotion.ClampToAnchor(Position, Anchor, Range); } } internal void End() { //IL_000f: 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) IsActive = false; PlayerInstanceId = 0; Anchor = Vector3.zero; Position = Vector3.zero; Yaw = 0f; Pitch = 0f; Range = 0f; } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(value.x) && IsFinite(value.y)) { return IsFinite(value.z); } return false; } private static bool IsFinite(Quaternion value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z)) { return IsFinite(value.w); } return false; } private static bool IsPositiveFinite(float value) { if (IsFinite(value)) { return value > 0f; } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal readonly struct CameraMotionInput { internal float Right { get; } internal float Up { get; } internal float Forward { get; } internal float YawDelta { get; } internal float PitchDelta { get; } internal bool Fast { get; } internal CameraMotionInput(float right, float up, float forward, float yawDelta, float pitchDelta, bool fast) { Right = Mathf.Clamp(right, -1f, 1f); Up = Mathf.Clamp(up, -1f, 1f); Forward = Mathf.Clamp(forward, -1f, 1f); YawDelta = yawDelta; PitchDelta = pitchDelta; Fast = fast; } } internal readonly struct CameraPose { internal Vector3 Position { get; } internal float Yaw { get; } internal float Pitch { get; } internal Quaternion Rotation => Quaternion.Euler(Pitch, Yaw, 0f); internal CameraPose(Vector3 position, float yaw, float pitch) { //IL_0001: 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) Position = position; Yaw = yaw; Pitch = pitch; } } internal static class CameraMotion { internal static CameraPose Step(Vector3 position, float yaw, float pitch, Vector3 anchor, float range, in CameraMotionInput input, float deltaTime, float moveSpeed, float fastMoveMultiplier, bool worldRelativeMovement) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) float num = SanitizeDeltaTime(deltaTime); float num2 = NormalizeAngle(yaw + Sanitize(input.YawDelta)); float num3 = Mathf.Clamp(pitch + Sanitize(input.PitchDelta), -89f, 89f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(input.Right, input.Up, input.Forward); if (((Vector3)(ref val)).sqrMagnitude > 1f) { ((Vector3)(ref val)).Normalize(); } Vector3 val2; if (worldRelativeMovement) { val2 = val; } else { val2 = Quaternion.Euler(num3, num2, 0f) * new Vector3(val.x, 0f, val.z) + Vector3.up * val.y; if (((Vector3)(ref val2)).sqrMagnitude > 1f) { ((Vector3)(ref val2)).Normalize(); } } float num4 = Mathf.Max(0f, Sanitize(moveSpeed)); if (input.Fast) { num4 *= Mathf.Max(1f, Sanitize(fastMoveMultiplier)); } Vector3 position2 = position + val2 * (num4 * num); float range2 = ((IsFinite(range) && range > 0f) ? range : 0.01f); return new CameraPose(ClampToAnchor(position2, anchor, range2), num2, num3); } internal static Vector3 ClampToAnchor(Vector3 position, Vector3 anchor, float range) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_002b: 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_003f: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!IsFinite(position) || !IsFinite(anchor)) { return anchor; } if (!IsFinite(range) || range <= 0f) { return anchor; } Vector3 val = position - anchor; float num = range * range; if (((Vector3)(ref val)).sqrMagnitude <= num) { return position; } return anchor + ((Vector3)(ref val)).normalized * range; } internal static float NormalizeAngle(float degrees) { if (!IsFinite(degrees)) { return 0f; } degrees %= 360f; if (degrees > 180f) { degrees -= 360f; } if (degrees <= -180f) { degrees += 360f; } return degrees; } private static float SanitizeDeltaTime(float value) { if (!IsFinite(value)) { return 0f; } return Mathf.Clamp(value, 0f, 0.1f); } private static float Sanitize(float value) { if (!IsFinite(value)) { return 0f; } return value; } private static bool IsFinite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(value.x) && IsFinite(value.y)) { return IsFinite(value.z); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal enum PickupRejectionReason { None, InvalidNetworkIdentity, OutsideRange, WardDenied, AutoPickupDisabled, Piece, InTar, UniqueOrQuestItem, InventoryFull, TooHeavy, CoolingDown } internal readonly struct PickupCandidateFacts { internal bool HasValidNetworkIdentity { get; } internal bool IsWithinRange { get; } internal bool WardAllows { get; } internal bool AutoPickupEnabled { get; } internal bool IsPiece { get; } internal bool IsInTar { get; } internal bool IsUniqueOrQuestItem { get; } internal bool InventoryCanAdd { get; } internal bool WouldExceedCarryWeight { get; } internal bool IsCoolingDown { get; } internal PickupCandidateFacts(bool hasValidNetworkIdentity, bool isWithinRange, bool wardAllows, bool autoPickupEnabled, bool isPiece, bool isInTar, bool isUniqueOrQuestItem, bool inventoryCanAdd, bool wouldExceedCarryWeight, bool isCoolingDown) { HasValidNetworkIdentity = hasValidNetworkIdentity; IsWithinRange = isWithinRange; WardAllows = wardAllows; AutoPickupEnabled = autoPickupEnabled; IsPiece = isPiece; IsInTar = isInTar; IsUniqueOrQuestItem = isUniqueOrQuestItem; InventoryCanAdd = inventoryCanAdd; WouldExceedCarryWeight = wouldExceedCarryWeight; IsCoolingDown = isCoolingDown; } } internal static class PickupPolicy { internal const int ColliderCapacity = 128; internal const int MaximumAttemptsPerScan = 16; internal const int MaximumCooldownEntries = 256; internal const float MinimumOwnershipRetrySeconds = 0.2f; internal const float FailedPickupRetrySeconds = 0.5f; internal const float CompletedPickupDedupeSeconds = 5f; internal static bool IsScanDue(float now, float nextScanAt) { if (IsFinite(now) && IsFinite(nextScanAt)) { return now >= nextScanAt; } return false; } internal static float NextScanAt(float now, float configuredIntervalSeconds) { float right = (IsFinite(configuredIntervalSeconds) ? Math.Max(0.02f, configuredIntervalSeconds) : 0.2f); return SaturatingAdd(now, right); } internal static bool IsWithinRange(float squaredDistance, float rangeMeters) { if (!IsFinite(squaredDistance) || squaredDistance < 0f || !IsFinite(rangeMeters) || rangeMeters <= 0f) { return false; } double num = rangeMeters; return (double)squaredDistance <= num * num; } internal static PickupRejectionReason Evaluate(in PickupCandidateFacts facts) { if (!facts.HasValidNetworkIdentity) { return PickupRejectionReason.InvalidNetworkIdentity; } if (!facts.IsWithinRange) { return PickupRejectionReason.OutsideRange; } if (!facts.WardAllows) { return PickupRejectionReason.WardDenied; } if (!facts.AutoPickupEnabled) { return PickupRejectionReason.AutoPickupDisabled; } if (facts.IsPiece) { return PickupRejectionReason.Piece; } if (facts.IsInTar) { return PickupRejectionReason.InTar; } if (facts.IsUniqueOrQuestItem) { return PickupRejectionReason.UniqueOrQuestItem; } if (!facts.InventoryCanAdd) { return PickupRejectionReason.InventoryFull; } if (facts.WouldExceedCarryWeight) { return PickupRejectionReason.TooHeavy; } if (facts.IsCoolingDown) { return PickupRejectionReason.CoolingDown; } return PickupRejectionReason.None; } internal static float OwnershipRetryAt(float now, float configuredIntervalSeconds) { return SaturatingAdd(now, Math.Max(0.2f, IsFinite(configuredIntervalSeconds) ? configuredIntervalSeconds : 0f)); } internal static float FailedPickupRetryAt(float now) { return SaturatingAdd(now, 0.5f); } internal static float CompletedPickupRetryAt(float now) { return SaturatingAdd(now, 5f); } private static float SaturatingAdd(float left, float right) { if (!IsFinite(left) || !IsFinite(right)) { return float.MaxValue; } double num = (double)left + (double)right; if (!(num >= 3.4028234663852886E+38)) { return (float)num; } return float.MaxValue; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } }