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 ImmersiveBuildCamera v0.2.3
BepInEx/plugins/ImmersiveBuildCamera/ImmersiveBuildCamera.dll
Decompiled an hour agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ImmersiveBuildCamera")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ImmersiveBuildCamera")] [assembly: AssemblyTitle("ImmersiveBuildCamera")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ImmersiveBuildCamera { internal static class BuildCameraState { private static int _toggledShoulderDirection; private static readonly FieldInfo? RightItemField = AccessTools.Field(typeof(Humanoid), "m_rightItem"); internal static bool Active { get; private set; } internal static bool PrecisionMovementActive { get; private set; } internal static bool ShoulderPeekActive { get { if (Active) { return GetShoulderDirection() != 0; } return false; } } internal static void Update(Player player) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } if (!CanUseImmersiveCamera(player)) { SetActive(active: false); return; } if (Input.GetKeyDown(Plugin.ToggleCameraKey.Value)) { SetActive(!Active); } if (Active) { UpdateShoulderPeekState(); if (Plugin.EnablePrecisionMovement.Value && Input.GetKeyDown(Plugin.TogglePrecisionMovementKey.Value)) { SetPrecisionMovement(!PrecisionMovementActive); } } } internal static int GetShoulderDirection() { if (!Active) { return 0; } if (Plugin.ToggleShoulderPeek.Value) { return _toggledShoulderDirection; } return GetHeldShoulderDirection(); } private static void UpdateShoulderPeekState() { //IL_0018: 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) if (!Plugin.ToggleShoulderPeek.Value) { _toggledShoulderDirection = 0; return; } bool keyDown = Input.GetKeyDown(Plugin.LeftShoulderKey.Value); bool keyDown2 = Input.GetKeyDown(Plugin.RightShoulderKey.Value); if (keyDown && keyDown2) { _toggledShoulderDirection = 0; } else if (keyDown) { ToggleShoulderDirection(-1); } else if (keyDown2) { ToggleShoulderDirection(1); } } private static void ToggleShoulderDirection(int direction) { if (_toggledShoulderDirection == direction) { _toggledShoulderDirection = 0; } else { _toggledShoulderDirection = direction; } } private static int GetHeldShoulderDirection() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) bool key = Input.GetKey(Plugin.LeftShoulderKey.Value); bool key2 = Input.GetKey(Plugin.RightShoulderKey.Value); if (key && !key2) { return -1; } if (key2 && !key) { return 1; } return 0; } private static void SetActive(bool active) { if (Active != active) { Active = active; if (active) { PrecisionMovementActive = Plugin.EnablePrecisionMovement.Value && Plugin.PrecisionMovementDefaultOn.Value; } else { PrecisionMovementActive = false; _toggledShoulderDirection = 0; PlayerRendererVisibility.ForceVisible(); } Plugin.Log.LogInfo((object)(active ? ("Immersive build camera active. Precision movement: " + (PrecisionMovementActive ? "on" : "off") + ".") : "Immersive build camera inactive.")); } } private static void SetPrecisionMovement(bool active) { if (PrecisionMovementActive != active) { PrecisionMovementActive = active; Plugin.Log.LogInfo((object)(active ? "Precision movement active." : "Precision movement inactive.")); } } private static bool CanUseImmersiveCamera(Player player) { if (!IsSafePlayerState(player)) { return false; } if (!HasBuildTool(player)) { return false; } return true; } private static bool HasBuildTool(Player player) { if (RightItemField == null) { Plugin.Log.LogWarning((object)"Could not find Humanoid.m_rightItem."); return false; } object? value = RightItemField.GetValue(player); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val == null) { return false; } if (val.m_shared == null) { return false; } return (Object)(object)val.m_shared.m_buildPieces != (Object)null; } private static bool IsSafePlayerState(Player player) { if (((Character)player).IsDead()) { return false; } if (((Character)player).IsAttached()) { return false; } if (((Character)player).IsSwimming()) { return false; } if (InventoryGui.IsVisible()) { return false; } if (Menu.IsVisible()) { return false; } if (Minimap.IsOpen()) { return false; } return true; } } [HarmonyPatch(typeof(GameCamera))] [HarmonyPatch("UpdateCamera")] internal static class GameCameraUpdatePatch { private static readonly FieldInfo? CameraField = AccessTools.Field(typeof(GameCamera), "m_camera"); private static float _originalFov; private static float _originalNearClip; private static bool _savedOriginals; private static int _cachedCollisionMask = -1; private static void Postfix(GameCamera __instance) { if ((Object)(object)__instance == (Object)null) { return; } Camera val = GetCamera(__instance) ?? Camera.main; if (!((Object)(object)val == (Object)null)) { if (!_savedOriginals) { _originalFov = val.fieldOfView; _originalNearClip = val.nearClipPlane; _savedOriginals = true; } if (!BuildCameraState.Active) { RestoreCamera(val); } else { ApplyImmersiveBuildCamera(__instance, val); } } } private static Camera? GetCamera(GameCamera gameCamera) { if (CameraField == null) { return null; } object? value = CameraField.GetValue(gameCamera); return (Camera?)((value is Camera) ? value : null); } private static void ApplyImmersiveBuildCamera(GameCamera gameCamera, Camera camera) { //IL_002e: 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_0034: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Transform val = (((Object)(object)((Character)localPlayer).m_eye != (Object)null) ? ((Character)localPlayer).m_eye : ((Component)localPlayer).transform); Vector3 position = val.position; Vector3 val2 = position; Quaternion rotation = val.rotation; int shoulderDirection = BuildCameraState.GetShoulderDirection(); if (shoulderDirection != 0) { float num = Plugin.ShoulderOffsetX.Value * (float)shoulderDirection; val2 += val.right * num; val2 += val.up * Plugin.ShoulderOffsetY.Value; val2 -= val.forward * Plugin.ShoulderDistance.Value; val2 = ResolveCameraCollision(position, val2); } ((Component)gameCamera).transform.position = val2; ((Component)gameCamera).transform.rotation = rotation; camera.fieldOfView = Plugin.BuildFov.Value; camera.nearClipPlane = Plugin.NearClip.Value; } } private static Vector3 ResolveCameraCollision(Vector3 anchorPosition, Vector3 desiredPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0007: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0037: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Vector3 val = desiredPosition - anchorPosition; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.001f) { return desiredPosition; } Vector3 val2 = val / magnitude; RaycastHit val3 = default(RaycastHit); if (!Physics.SphereCast(anchorPosition, Mathf.Max(0.01f, Plugin.CollisionRadius.Value), val2, ref val3, magnitude, GetCollisionMask(), (QueryTriggerInteraction)1)) { return desiredPosition; } float num = Mathf.Max(0f, ((RaycastHit)(ref val3)).distance - Plugin.CollisionRadius.Value); return anchorPosition + val2 * num; } private static int GetCollisionMask() { if (_cachedCollisionMask != -1) { return _cachedCollisionMask; } int num = LayerMask.GetMask(new string[5] { "Default", "static_solid", "terrain", "piece", "piece_nonsolid" }); if (num == 0) { num = -5; Plugin.Log.LogWarning((object)"Could not resolve Valheim-specific collision layers. Falling back to Physics.DefaultRaycastLayers."); } _cachedCollisionMask = num; return _cachedCollisionMask; } private static void RestoreCamera(Camera camera) { if (_savedOriginals) { camera.fieldOfView = _originalFov; camera.nearClipPlane = _originalNearClip; } } } [HarmonyPatch(typeof(Player))] [HarmonyPatch("Update")] internal static class PlayerUpdatePatch { private static void Postfix(Player __instance) { BuildCameraState.Update(__instance); PlayerRendererVisibility.Update(__instance); } } internal static class PlayerRendererVisibility { private static readonly Dictionary<Renderer, bool> OriginalRendererStates = new Dictionary<Renderer, bool>(); private static readonly List<Renderer> DeadRenderers = new List<Renderer>(); private static readonly FieldInfo? PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static Player? _cachedPlayer; private static bool _hidden; private static float _nextRefreshTime; internal static void Update(Player player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { bool shouldHide = Plugin.HideLocalPlayerWhenImmersive.Value && BuildCameraState.Active && !BuildCameraState.ShoulderPeekActive; Apply(player, shouldHide); } } internal static void ForceVisible() { RestoreRendererStates(); ResetCache(); } private static void Apply(Player player, bool shouldHide) { if ((Object)(object)player == (Object)null) { ForceVisible(); return; } if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player) { ForceVisible(); } _cachedPlayer = player; if (shouldHide) { HidePlayerRenderers(player); } else { RestoreRendererStates(); } } private static void HidePlayerRenderers(Player player) { if (!_hidden) { OriginalRendererStates.Clear(); _hidden = true; _nextRefreshTime = 0f; } if (OriginalRendererStates.Count == 0 || Time.unscaledTime >= _nextRefreshTime) { RefreshRendererCache(player); _nextRefreshTime = Time.unscaledTime + 0.25f; } foreach (Renderer key in OriginalRendererStates.Keys) { if (!((Object)(object)key == (Object)null) && key.enabled) { key.enabled = false; } } } private static void RefreshRendererCache(Player player) { RemoveDestroyedRenderers(); Renderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !ShouldSkipRenderer(player, val) && !OriginalRendererStates.ContainsKey(val)) { OriginalRendererStates.Add(val, val.enabled); } } } private static bool ShouldSkipRenderer(Player player, Renderer renderer) { GameObject placementGhost = GetPlacementGhost(player); if ((Object)(object)placementGhost != (Object)null && (Object)(object)((Component)renderer).transform != (Object)null && ((Component)renderer).transform.IsChildOf(placementGhost.transform)) { return true; } return false; } private static GameObject? GetPlacementGhost(Player player) { if (PlacementGhostField == null) { return null; } object? value = PlacementGhostField.GetValue(player); return (GameObject?)((value is GameObject) ? value : null); } private static void RestoreRendererStates() { if (!_hidden && OriginalRendererStates.Count == 0) { return; } foreach (KeyValuePair<Renderer, bool> originalRendererState in OriginalRendererStates) { Renderer key = originalRendererState.Key; if (!((Object)(object)key == (Object)null)) { key.enabled = originalRendererState.Value; } } OriginalRendererStates.Clear(); DeadRenderers.Clear(); _hidden = false; _nextRefreshTime = 0f; } private static void RemoveDestroyedRenderers() { DeadRenderers.Clear(); foreach (Renderer key in OriginalRendererStates.Keys) { if ((Object)(object)key == (Object)null) { DeadRenderers.Add(key); } } foreach (Renderer deadRenderer in DeadRenderers) { OriginalRendererStates.Remove(deadRenderer); } DeadRenderers.Clear(); } private static void ResetCache() { _cachedPlayer = null; _hidden = false; _nextRefreshTime = 0f; OriginalRendererStates.Clear(); DeadRenderers.Clear(); } } [BepInPlugin("com.geronimo.valheim.immersivebuildcamera", "Immersive Build Camera", "0.2.3")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.geronimo.valheim.immersivebuildcamera"; public const string PluginName = "Immersive Build Camera"; public const string PluginVersion = "0.2.3"; internal static ManualLogSource Log; internal static ConfigEntry<KeyCode> ToggleCameraKey; internal static ConfigEntry<KeyCode> TogglePrecisionMovementKey; internal static ConfigEntry<KeyCode> LeftShoulderKey; internal static ConfigEntry<KeyCode> RightShoulderKey; internal static ConfigEntry<float> BuildFov; internal static ConfigEntry<float> NearClip; internal static ConfigEntry<float> ShoulderOffsetX; internal static ConfigEntry<float> ShoulderOffsetY; internal static ConfigEntry<float> ShoulderDistance; internal static ConfigEntry<float> CollisionRadius; internal static ConfigEntry<bool> ToggleShoulderPeek; internal static ConfigEntry<bool> EnablePrecisionMovement; internal static ConfigEntry<bool> PrecisionMovementDefaultOn; internal static ConfigEntry<float> PrecisionMoveMultiplier; internal static ConfigEntry<bool> HideLocalPlayerWhenImmersive; private Harmony _harmony; private void Awake() { //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ToggleCameraKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ToggleCameraKey", (KeyCode)308, "Press this while using a build tool to toggle immersive build camera."); TogglePrecisionMovementKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "TogglePrecisionMovementKey", (KeyCode)306, "Press this while immersive build camera is active to toggle slow precision movement."); LeftShoulderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "LeftShoulderKey", (KeyCode)113, "Hold or press this while immersive build camera is active to peek left, depending on ToggleShoulderPeek."); RightShoulderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "RightShoulderKey", (KeyCode)101, "Hold or press this while immersive build camera is active to peek right, depending on ToggleShoulderPeek."); BuildFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "BuildFov", 68f, "Field of view while immersive build camera is active."); NearClip = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "NearClip", 0.04f, "Near clipping plane while immersive build camera is active."); ShoulderOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderOffsetX", 0.75f, "Horizontal shoulder offset. Higher values make shoulder peek more useful but more likely to hit collision."); ShoulderOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderOffsetY", 0.06f, "Vertical shoulder offset."); ShoulderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderDistance", 0.5f, "Backward shoulder camera distance."); CollisionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "CollisionRadius", 0.1f, "Sphere radius used to prevent shoulder peek camera clipping into objects."); ToggleShoulderPeek = ((BaseUnityPlugin)this).Config.Bind<bool>("Shoulder Peek", "ToggleShoulderPeek", false, "If false, shoulder peek keys must be held. If true, shoulder peek keys toggle left, right, or centered."); EnablePrecisionMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "EnablePrecisionMovement", true, "Allow slow precision movement while immersive build camera is active."); PrecisionMovementDefaultOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "PrecisionMovementDefaultOn", true, "Whether slow precision movement starts enabled whenever immersive build camera is toggled on."); PrecisionMoveMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "PrecisionMoveMultiplier", 0.35f, "Movement input multiplier when precision movement is enabled. Lower means slower."); HideLocalPlayerWhenImmersive = ((BaseUnityPlugin)this).Config.Bind<bool>("Local Visibility", "HideLocalPlayerWhenImmersive", true, "Hide only the local player's renderers while immersive build camera is active and shoulder peek is not being used."); _harmony = new Harmony("com.geronimo.valheim.immersivebuildcamera"); _harmony.PatchAll(); PrecisionMovementPatches.Apply(_harmony); Log.LogInfo((object)"Immersive Build Camera loaded."); } private void OnDestroy() { PlayerRendererVisibility.ForceVisible(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PrecisionMovementPatches { internal static void Apply(Harmony harmony) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Player), "SetControls", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PrecisionMovementPatches), "PrefixSetControls", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogWarning((object)"Could not find Player.SetControls. Precision movement patch skipped."); return; } if (methodInfo2 == null) { Plugin.Log.LogWarning((object)"Could not find precision movement prefix."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Patched Player.SetControls for precision movement."); } private static void PrefixSetControls(Player __instance, ref Vector3 movedir, ref bool run, ref bool autoRun) { //IL_0047: 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_0052: Unknown result type (might be due to invalid IL or missing references) if (Plugin.EnablePrecisionMovement.Value && BuildCameraState.Active && BuildCameraState.PrecisionMovementActive && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { float num = Mathf.Clamp(Plugin.PrecisionMoveMultiplier.Value, 0.05f, 1f); movedir *= num; run = false; autoRun = false; } } } }