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 ValheimHoeCamera v1.2.0
BepInEx/plugins/HoeCam/HoeCam.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Hoe Cam")] [assembly: AssemblyFileVersion("0.1.6.0")] [assembly: AssemblyVersion("0.1.6.0")] namespace HoeCam; internal struct MovementVector { internal float X; internal float Y; internal float Z; internal MovementVector(float x, float y, float z) { X = x; Y = y; Z = z; } } internal static class CameraMath { internal static float FreeCameraRange(float baseMetres, float minimumBase, float multiplier) { return Clamp(baseMetres, 25f, minimumBase, 25f) * Clamp(multiplier, 2f, 1f, 2f); } internal static float HoeCameraRange(float baseMetres, float minimumBase, float multiplier) { return FreeCameraRange(baseMetres, minimumBase, multiplier) * 2f; } internal static float BuildRayDistance(float cameraEyeDistance, float appliedReach, float pieceExtraDistance) { return Math.Max(50f, cameraEyeDistance + appliedReach + Math.Max(0f, pieceExtraDistance) + 1f); } internal static MovementVector ViewRelativeMovement(float yawDegrees, float pitchDegrees, float strafe, float vertical, float forward) { double num = (double)yawDegrees * Math.PI / 180.0; double num2 = (double)pitchDegrees * Math.PI / 180.0; float num3 = (float)Math.Sin(num); float num4 = (float)Math.Cos(num); float num5 = (float)Math.Cos(num2); float num6 = (float)Math.Sin(num2); float num7 = num4; float num8 = 0f - num3; float num9 = num3 * num5; float num10 = 0f - num6; float num11 = num4 * num5; return new MovementVector(num7 * strafe + num9 * forward, vertical + num10 * forward, num8 * strafe + num11 * forward); } internal static float Clamp(float value, float fallback, float min, float max) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Math.Max(min, Math.Min(max, value)); } return fallback; } internal static void NormalizeInput(ref float x, ref float y, ref float z) { float num = x * x + y * y + z * z; if (!(num <= 1f)) { float num2 = (float)Math.Sqrt(num); x /= num2; y /= num2; z /= num2; } } internal static void ClampToSphere(ref float x, ref float y, ref float z, float radius) { float num = x * x + y * y + z * z; if (!(num <= radius * radius) && !(num < 1E-10f)) { float num2 = (float)Math.Sqrt(num); float num3 = radius / num2; x *= num3; y *= num3; z *= num3; } } internal static bool ControllerToggleEligible(bool enabled, bool localPlayerPresent, bool modal, bool active, bool hasBuildingTool) { if (enabled && localPlayerPresent && !modal) { return active || hasBuildingTool; } return false; } } internal sealed class HoldToggle { private float _held; private bool _fired; internal bool Step(bool pressed, float dt) { if (!pressed) { _held = 0f; _fired = false; return false; } _held += CameraMath.Clamp(dt, 0f, 0f, 0.1f); if (_fired || _held < 0.5f) { return false; } _fired = true; return true; } internal void Reset() { _held = 0f; _fired = false; } } internal sealed class ButtonChordToggle { private float _window; private float _bothHeld; private bool _fired; internal bool Step(bool left, bool right, float dt) { dt = CameraMath.Clamp(dt, 0f, 0f, 0.1f); if (!left && !right) { Reset(); return false; } _window = Math.Min(2f, _window + dt); if (left && right) { _bothHeld = Math.Min(1f, _bothHeld + dt); if (!_fired && (_window <= 0.35f || _bothHeld >= 0.25f)) { _fired = true; return true; } } else { _bothHeld = 0f; } return false; } internal void Reset() { _window = 0f; _bothHeld = 0f; _fired = false; } } internal sealed class CameraToggleInput { private readonly ButtonChordToggle _chord = new ButtonChordToggle(); private int _keyboardFrame = -1; private bool _waitForRelease; internal bool HasPendingKeyboard => _keyboardFrame >= 0; internal bool Step(int frame, bool keyDown, bool keyboardAllowed, bool left, bool right, bool controllerAllowed, float dt) { if (_waitForRelease) { if (keyDown || left || right) { return false; } _waitForRelease = false; } bool num = _chord.Step(left, right, dt); if (!keyboardAllowed) { CancelPending(); } bool flag = HasPendingKeyboard && frame > _keyboardFrame; if ((num && controllerAllowed) || flag) { CancelPending(); return true; } if (keyDown && keyboardAllowed) { _keyboardFrame = frame; } return false; } internal void CancelPending() { _keyboardFrame = -1; } internal void Reset(bool waitForRelease) { CancelPending(); _chord.Reset(); _waitForRelease = waitForRelease; } } internal static class CircletCameraLight { private static Light _light; private static Type _playerType; private static Type _itemType; private static FieldInfo _inventory; private static FieldInfo _prefab; private static FieldInfo _equipped; private static MethodInfo _getItems; private static bool _warned; private static FieldInfo FindField(Type type, string name) { while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } throw new MissingFieldException(name); } internal static bool IsCirclet(string prefabName) { if (prefabName == null) { return false; } prefabName = prefabName.Trim(); if (prefabName.EndsWith("(Clone)", StringComparison.Ordinal)) { prefabName = prefabName.Substring(0, prefabName.Length - "(Clone)".Length).TrimEnd(); } return string.Equals(prefabName, "HelmetDverger", StringComparison.Ordinal); } private static bool Equipped(object player) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (player == null || !(player is Object) || !Object.op_Implicit((Object)player)) { return false; } Type type = player.GetType(); if (_playerType != type) { _inventory = FindField(type, "m_inventory"); _getItems = null; _playerType = type; } object value = _inventory.GetValue(player); if (value == null) { return false; } if (_getItems == null) { _getItems = value.GetType().GetMethod("GetAllItems", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (_getItems == null) { throw new MissingMethodException("Inventory.GetAllItems"); } } foreach (object item in (IEnumerable)_getItems.Invoke(value, null)) { if (item == null) { continue; } if (_itemType != item.GetType()) { _prefab = FindField(item.GetType(), "m_dropPrefab"); _equipped = FindField(item.GetType(), "m_equipped"); _itemType = item.GetType(); } if ((bool)_equipped.GetValue(item)) { object? value2 = _prefab.GetValue(item); GameObject val = (GameObject)((value2 is GameObject) ? value2 : null); if (Object.op_Implicit((Object)(object)val) && IsCirclet(((Object)val).name)) { return true; } } } return false; } internal static void Update(object player, 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_003b: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) try { if (!Object.op_Implicit((Object)(object)camera) || !Equipped(player)) { Stop(); return; } if (!Object.op_Implicit((Object)(object)_light)) { GameObject val = new GameObject("HoeCamera_CircletLight") { hideFlags = (HideFlags)52 }; val.SetActive(false); _light = val.AddComponent<Light>(); _light.type = (LightType)0; _light.range = 35f; _light.spotAngle = 100f; _light.intensity = 1.5f; _light.color = new Color(1f, 0.95f, 0.85f); _light.shadows = (LightShadows)2; _light.renderMode = (LightRenderMode)1; ((Component)_light).transform.SetParent(((Component)camera).transform, false); ((Component)_light).transform.localPosition = Vector3.zero; ((Component)_light).transform.localRotation = Quaternion.identity; _light.cullingMask = camera.cullingMask; val.SetActive(true); Debug.Log((object)"Hoe Cam circlet light: camera spotlight activated (local only)."); } if ((Object)(object)((Component)_light).transform.parent != (Object)(object)((Component)camera).transform) { ((Component)_light).transform.SetParent(((Component)camera).transform, false); ((Component)_light).transform.localPosition = Vector3.zero; ((Component)_light).transform.localRotation = Quaternion.identity; } _light.cullingMask = camera.cullingMask; } catch (Exception ex) { Stop(); if (!_warned) { _warned = true; Debug.LogWarning((object)("Hoe Cam circlet light unavailable: " + ex.Message)); } } } internal static void Stop() { if (Object.op_Implicit((Object)(object)_light)) { ((Behaviour)_light).enabled = false; Object.Destroy((Object)(object)((Component)_light).gameObject); } _light = null; } } internal static class FeatherCapeMist { [HarmonyPatch(typeof(ParticleMist), "Update")] private static class ParticleMistUpdate { private static bool Prefix(ParticleMist __instance) { try { if ((!Object.op_Implicit((Object)(object)HoeCamera.Instance) || !HoeCamera.Instance.Active) && !hidden) { return true; } if (mistParticleField == null) { mistParticleField = FindField(typeof(ParticleMist), "m_ps"); } object? value = mistParticleField.GetValue(__instance); object? obj = ((value is ParticleSystem) ? value : null); if ((Object)obj != (Object)(object)mistParticles && hidden) { SetHidden(value: false); } mistParticles = (ParticleSystem)obj; if (ShouldHide()) { SetHidden(value: true); } else if (hidden) { SetHidden(value: false); mistParticles = null; } return true; } catch (Exception ex) { if (hidden) { SetHidden(value: false); } if (!warned) { warned = true; Debug.LogWarning((object)("Hoe Cam feather-cape mist control unavailable: " + ex.Message)); } return true; } } } private static FieldInfo inventoryField; private static FieldInfo prefabField; private static FieldInfo equippedField; private static FieldInfo mistParticleField; private static MethodInfo getItems; private static Type playerType; private static Type itemType; private static ParticleSystem mistParticles; private static bool hidden; private static Renderer mistRenderer; private static bool previousForceOff; private static bool warned; private static Player cachedPlayer; private static float nextEquipmentCheck; private static bool cachedEquipped; private static FieldInfo FindField(Type type, string name) { while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } throw new MissingFieldException(name); } private static bool Equipped(object player) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (player == null || !(player is Object) || !Object.op_Implicit((Object)player)) { return false; } Type type = player.GetType(); if (playerType != type) { inventoryField = FindField(type, "m_inventory"); getItems = null; playerType = type; } object value = inventoryField.GetValue(player); if (value == null) { return false; } if (getItems == null) { getItems = value.GetType().GetMethod("GetAllItems", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); } if (getItems == null) { return false; } foreach (object item in (IEnumerable)getItems.Invoke(value, null)) { if (item == null) { continue; } if (itemType != item.GetType()) { prefabField = FindField(item.GetType(), "m_dropPrefab"); equippedField = FindField(item.GetType(), "m_equipped"); itemType = item.GetType(); } if ((bool)equippedField.GetValue(item)) { object? value2 = prefabField.GetValue(item); GameObject val = (GameObject)((value2 is GameObject) ? value2 : null); if (Object.op_Implicit((Object)(object)val) && string.Equals(((Object)val).name.Trim().Replace("(Clone)", "").Trim(), "CapeFeather", StringComparison.Ordinal)) { return true; } } } return false; } private static void SetHidden(bool value) { if (!Object.op_Implicit((Object)(object)mistParticles) && value) { return; } if (value && !hidden) { mistRenderer = (Renderer)(object)((Component)mistParticles).GetComponent<ParticleSystemRenderer>(); if (!Object.op_Implicit((Object)(object)mistRenderer)) { return; } previousForceOff = mistRenderer.forceRenderingOff; } if (Object.op_Implicit((Object)(object)mistRenderer)) { mistRenderer.forceRenderingOff = value || previousForceOff; } hidden = value; } private static bool ShouldHide() { if (!Object.op_Implicit((Object)(object)HoeCamera.Instance) || !HoeCamera.Instance.Active || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } if ((Object)(object)cachedPlayer != (Object)(object)Player.m_localPlayer || Time.unscaledTime >= nextEquipmentCheck) { cachedPlayer = Player.m_localPlayer; cachedEquipped = Equipped(cachedPlayer); nextEquipmentCheck = Time.unscaledTime + 0.25f; } return cachedEquipped; } internal static void Clear() { if (hidden) { SetHidden(value: false); } mistParticles = null; hidden = false; cachedPlayer = null; nextEquipmentCheck = 0f; cachedEquipped = false; } } [BepInPlugin("valheim.hoecam", "Hoe Cam", "0.1.6")] [BepInProcess("valheim.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [DefaultExecutionOrder(1000)] public sealed class HoeCamera : BaseUnityPlugin { [HarmonyPatch(typeof(InventoryGui), "Show", new Type[] { typeof(Container), typeof(int) })] private static class KeepInventoryClosedInHoeCamera { private static bool Prefix() { HoeCamera instance = Instance; if (Object.op_Implicit((Object)(object)instance)) { return !instance.Active; } return true; } } [HarmonyPatch(typeof(Player), "Update")] private static class BeforePlayerUpdate { private static void Prefix(Player __instance) { HoeCamera instance = Instance; if (Object.op_Implicit((Object)(object)instance) && instance.IsLocal(__instance)) { instance.Tick(); } } } [HarmonyPatch(typeof(GameCamera), "LateUpdate")] private static class DetachedCameraLateUpdate { private static void Postfix(GameCamera __instance) { HoeCamera instance = Instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.Active || (Object)(object)__instance != (Object)(object)instance._gameCamera) { return; } try { instance.ApplyPose(); } catch (Exception error) { instance.Fail(error); } } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static class DetachedCamera { private static bool Prefix(GameCamera __instance) { HoeCamera instance = Instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.Active || (Object)(object)__instance != (Object)(object)instance._gameCamera) { return true; } try { instance.ApplyPose(); return false; } catch (Exception error) { instance.Fail(error); return true; } } } [HarmonyPatch(typeof(Player), "SetControls")] private static class KeepBodyStill { 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) HoeCamera instance = Instance; if (Object.op_Implicit((Object)(object)instance) && instance.ControlsOwned(__instance)) { movedir = Vector3.zero; attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false))))); jump = (crouch = (run = (autoRun = (dodge = false)))); __instance.m_autoRun = false; if (instance._active) { ((Character)__instance).StopMovement(); } } } } [HarmonyPatch(typeof(Player), "SetMouseLook")] private static class KeepBodyLook { private static bool Prefix(Player __instance) { HoeCamera instance = Instance; if (Object.op_Implicit((Object)(object)instance)) { return !instance.ControlsOwned(__instance); } return true; } } [HarmonyPatch(typeof(Player), "TakeInput")] private static class ProtectToggleAndDialogs { private static void Postfix(Player __instance, ref bool __result) { HoeCamera instance = Instance; if (Object.op_Implicit((Object)(object)instance) && instance.HooksEnabled && instance.IsLocal(__instance) && (instance._active || instance._chordHeld || Time.unscaledTime < instance._suppressUntil)) { __result = false; } } } [HarmonyPatch(typeof(Player), "StartGuardianPower")] private static class ProtectGuardianPowerChord { private static bool Prefix(Player __instance) { HoeCamera instance = Instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.HooksEnabled || !instance.IsLocal(__instance)) { return true; } if (!instance._active) { return !instance._chordHeld; } return false; } } private enum BrushMode { Flatten, Raise, Lower } [HarmonyPatch(typeof(Player), "UpdatePlacement")] private static class SuppressNativeHoePlacement { private static bool Prefix(Player __instance) { if (Object.op_Implicit((Object)(object)Instance) && Instance.Active) { return !Instance.IsLocal(__instance); } return true; } } public const string PluginId = "valheim.hoecam"; public const string PluginVersion = "0.1.6"; internal static HoeCamera Instance; private float _nextCircletCheck; private ConfigEntry<bool> _enabled; private ConfigEntry<bool> _controllerToggle; private ConfigEntry<bool> _hidePlayer; private ConfigEntry<bool> _showIndicator; private ConfigEntry<bool> _exitOnDamage; private ConfigEntry<KeyboardShortcut> _toggleKey; private ConfigEntry<KeyboardShortcut> _resetKey; private ConfigEntry<KeyboardShortcut> _reportKey; private ConfigEntry<float> _speed; private ConfigEntry<float> _fastMultiplier; private ConfigEntry<float> _radius; private ConfigEntry<float> _reach; private ConfigEntry<float> _rangeMultiplier; private ConfigEntry<float> _startPitch; private ConfigEntry<float> _startFov; private Harmony _harmony; private bool _ready; private bool _active; private bool _failed; private bool _chordHeld; private Player _player; private GameCamera _gameCamera; private Camera _camera; private Camera _skyCamera; private Vector3 _position; private Vector3 _bodyOrigin; private Vector3 _savedCameraPosition; private Quaternion _savedCameraRotation; private Quaternion _rotation; private float _yaw; private float _pitch; private float _fov; private float _savedFov; private float _savedSkyFov; private float _savedNearClip; private float _savedReach; private float _appliedReach; private float _suppressUntil; private float _nextRendererScan; private float _activeNearClip; private int _tickFrame = -1; private string _lastExit = "Not activated yet"; private readonly CameraToggleInput _toggleInput = new CameraToggleInput(); private string _indicatorText; private BrushMode _mode; private ConfigEntry<float> _brushRadius; private ConfigEntry<float> _heightStep; private bool _heightLocked; private bool _terrainArmed; private bool _hasTerrain; private float _flatHeight; private float _nextStroke; private float _nextBrushDraw; private float _statusUntil; private Vector3 _terrainPoint; private string _terrainStatus = "Aim at the ground"; private LineRenderer _brushRing; private Material _brushMaterial; private GameObject _savedGhost; private bool _ghostWasActive; private GUIStyle _hudTitle; private GUIStyle _hudText; private readonly List<Heightmap> _terrainMaps = new List<Heightmap>(); private readonly List<TerrainComp> _terrainCompilers = new List<TerrainComp>(); private static readonly FieldInfo GhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly FieldInfo TerrainInitialized = AccessTools.Field(typeof(TerrainComp), "m_initialized"); private static readonly MethodInfo TerrainLoad = AccessTools.Method(typeof(TerrainComp), "CheckLoad", (Type[])null, (Type[])null); private static readonly MethodInfo TerrainApply = AccessTools.Method(typeof(TerrainComp), "DoOperation", new Type[3] { typeof(Vector3), typeof(Vector3), typeof(Settings) }, (Type[])null); private static PropertyInfo _otherActive; private static object _otherPlugin; internal bool HooksEnabled { get { if (_ready && !_failed) { return ((Behaviour)this).isActiveAndEnabled; } return false; } } internal bool Active { get { if (HooksEnabled) { return _active; } return false; } } private float EffectiveCameraRadius => CameraMath.HoeCameraRange(_radius.Value, 8f, _rangeMultiplier.Value); private float EffectiveBuildReach => CameraMath.HoeCameraRange(_reach.Value, 5f, _rangeMultiplier.Value); private static void ValidateHooks() { Require(typeof(Player), "Update", Type.EmptyTypes); Require(typeof(ParticleMist), "Update", Type.EmptyTypes); Require(typeof(InventoryGui), "Show", new Type[2] { typeof(Container), typeof(int) }); Require(typeof(Player), "SetControls", new Type[12] { typeof(Vector3), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }); Require(typeof(Player), "SetMouseLook", new Type[1] { typeof(Vector2) }); Require(typeof(Player), "TakeInput", Type.EmptyTypes); Require(typeof(Player), "StartGuardianPower", Type.EmptyTypes); Require(typeof(GameCamera), "UpdateCamera", new Type[1] { typeof(float) }); Require(typeof(GameCamera), "LateUpdate", Type.EmptyTypes); Require(typeof(Player), "UpdatePlacement", new Type[2] { typeof(bool), typeof(float) }); } private static void Require(Type type, string name, Type[] arguments) { if (AccessTools.DeclaredMethod(type, name, arguments, (Type[])null) == null) { throw new MissingMethodException(type.FullName, name); } } internal bool IsLocal(Player player) { if (Object.op_Implicit((Object)(object)player)) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } internal bool ControlsOwned(Player player) { if (HooksEnabled && IsLocal(player)) { if (!_active && !_chordHeld) { return Time.unscaledTime < _suppressUntil; } return true; } return false; } private void Awake() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Expected O, but got Unknown if (Application.isBatchMode) { return; } Instance = this; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the hoe camera on this client."); _toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ToggleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Enter/leave hoe camera with a hoe equipped."); _resetKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ResetViewKey", new KeyboardShortcut((KeyCode)292, Array.Empty<KeyCode>()), "Reset the active camera to its initial angled view."); _reportKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ReloadAndReportKey", new KeyboardShortcut((KeyCode)293, Array.Empty<KeyCode>()), "Write camera diagnostics, exit camera mode, and reload configuration. Separate from Larger HUD's F8."); _controllerToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "ControllerStickToggle", true, "Press both stick buttons together to enter/leave. A hoe is needed to enter, but not to leave. Release both before toggling again."); _hidePlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("View", "HideLocalPlayer", true, "Hide your character's renderers on your own screen while active. Your body remains in the world."); _showIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("View", "ShowIndicator", true, "Show the top-left terrain controls and status while the hoe camera is active."); _exitOnDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "ExitOnDamage", true, "Exit immediately when the physical player takes damage. Set false only if you deliberately want environmental damage to be tolerated; death still exits."); _speed = FloatSetting("Camera", "MoveSpeed", 6f, 1f, 15f, "Camera movement in metres per second."); _fastMultiplier = FloatSetting("Camera", "FastMultiplier", 2f, 1f, 3f, "Hold your Run control for faster camera movement."); _radius = FloatSetting("Camera", "CameraRadius", 25f, 8f, 25f, "Base camera radius in metres, multiplied by FreeCameraRangeMultiplier. Hoe Cam doubles the result: default 25 x 2 x 2 = 100 metres around the stationary body. Existing base settings are retained."); _reach = FloatSetting("Building", "BuildReach", 25f, 5f, 25f, "Terrain reach from the stationary player, multiplied by FreeCameraRangeMultiplier and then doubled by Hoe Cam (100m by default). The entire brush must fit inside this distance."); _rangeMultiplier = FloatSetting("Camera", "FreeCameraRangeMultiplier", 2f, 1f, 2f, "Multiply both base camera radius and active build reach. The default multiplier is 2. Set 1 for a smaller working area. Does not affect normal player building reach."); _startPitch = FloatSetting("View", "StartingPitch", 50f, 20f, 75f, "Downward angle when entering/resetting the camera. Mouse/right stick can adjust it afterward."); _startFov = FloatSetting("View", "FieldOfView", 45f, 25f, 75f, "Starting perspective field of view. Page Up/Down zoom while active; mouse wheel changes brush size."); try { StickInput.Initialize(typeof(ZInput), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); ValidateHooks(); _harmony = new Harmony("valheim.hoecam"); _harmony.PatchAll(typeof(HoeCamera).Assembly); InstallBuildCameraCompatibility(); ConfigureTerrain(); _ready = true; RefreshIndicatorText(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hoe Cam 0.1.6 loaded. F6 toggle; F11 reset; F12 report/reload."); } catch (Exception ex) { _ready = false; _failed = true; if (_harmony != null) { _harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Hoe Cam could not install its game hooks and remains inactive. " + ex)); } WriteDiagnostics("Startup"); } private ConfigEntry<float> FloatSetting(string section, string key, float value, float min, float max, string text) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, value, new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())); } private void Update() { Tick(); } internal void Tick() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) if (!_ready || !((Behaviour)this).isActiveAndEnabled || _tickFrame == Time.frameCount) { return; } _tickFrame = Time.frameCount; try { KeyboardShortcut value; if (Application.isFocused) { value = _reportKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { WriteDiagnostics("F12 before reload"); StopCamera("Configuration reload", message: false); ResetInput(); ((BaseUnityPlugin)this).Config.Reload(); RefreshIndicatorText(); _failed = false; Notify("Hoe camera settings reloaded; diagnostic report saved."); return; } } if (_failed) { return; } if (!_enabled.Value) { StopCamera("Disabled in configuration", message: false); ResetInput(); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ZInput.instance == null) { StopCamera("Player/input changed", message: false); ResetInput(); return; } if (!Application.isFocused) { ResetInput(); return; } value = _toggleKey.Value; bool flag = (((KeyboardShortcut)(ref value)).IsDown() || ZInput.GetKeyDown((KeyCode)287, true)) && (_active || HasBuildingTool(localPlayer)); bool left = false; bool right = false; if (_controllerToggle.Value) { ReadControllerSticks(out left, out right); } if (!_active && !flag && !_toggleInput.HasPendingKeyboard && !left && !right) { _toggleInput.Step(Time.frameCount, keyDown: false, keyboardAllowed: false, left: false, right: false, controllerAllowed: false, Time.unscaledDeltaTime); _chordHeld = false; return; } bool flag2 = MenuBlocksCamera(); bool flag3 = CameraMath.ControllerToggleEligible(_controllerToggle.Value, localPlayerPresent: true, flag2, _active, _active || HasBuildingTool(localPlayer)); _chordHeld = flag3 && left && right; if (_toggleInput.Step(Time.frameCount, flag, _active || !flag2, left, right, flag3, Time.unscaledDeltaTime)) { if (_active) { StopCamera("Toggled off", message: true); } else if (!flag2) { StartCamera(localPlayer); } } else { if (!_active) { return; } string text = InvalidActiveReason(); if (text != null) { StopCamera(text, message: true); return; } KeepBodyAtAnchor(); if (Menu.IsVisible() || ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyMenu") || ZInput.GetButtonDown("JoyStart")) { StopCamera("Escape", message: true); return; } value = _resetKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !flag2) { ResetView(); _suppressUntil = Time.unscaledTime + 0.2f; } if (!flag2 && !_chordHeld && Time.unscaledTime >= _suppressUntil) { MoveCamera(); } ApplyPose(); if (!flag2 && !_chordHeld && Time.unscaledTime >= _suppressUntil) { TickTerrain(); } else { HideBrush(); } } } catch (Exception error) { Fail(error); } } private void LateUpdate() { if (!_active) { return; } try { HoeCameraRumble.Stop(); string text = InvalidActiveReason(); if (text != null) { StopCamera(text, message: true); return; } KeepBodyAtAnchor(); ApplyPose(); if (Time.unscaledTime >= _nextCircletCheck) { CircletCameraLight.Update(_player, _camera); _nextCircletCheck = Time.unscaledTime + 0.25f; } if (!_hidePlayer.Value) { RestoreRenderers(); } else if (_hidePlayer.Value && Time.unscaledTime >= _nextRendererScan) { HideRenderers(); _nextRendererScan = Time.unscaledTime + 0.25f; } } catch (Exception error) { Fail(error); } } private static bool HasBuildingTool(Player player) { return IsBuildTool(((Humanoid)player).RightItem); } private static bool IsBuildTool(ItemData item) { if (item != null && item.m_shared != null && (Object)(object)item.m_shared.m_buildPieces != (Object)null) { if (!Object.op_Implicit((Object)(object)item.m_dropPrefab) || !(((Object)item.m_dropPrefab).name == "Hoe")) { return item.m_shared.m_name == "$item_hoe"; } return true; } return false; } private static void ReadControllerSticks(out bool left, out bool right) { left = ZInput.GetButton("JoyLStick"); right = ZInput.GetButton("JoyRStick"); try { Gamepad current = Gamepad.current; if (current != null) { left |= current.leftStickButton.isPressed; right |= current.rightStickButton.isPressed; } } catch (Exception) { } } internal static bool MenuBlocksCamera() { try { return (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus()) || Console.IsVisible() || TextInput.IsVisible() || InventoryGui.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible() || Minimap.IsOpen() || (Object.op_Implicit((Object)(object)TextViewer.instance) && TextViewer.instance.IsVisible()) || UnifiedPopup.IsVisible() || Hud.IsPieceSelectionVisible() || Hud.InRadial() || PlayerCustomizaton.IsBarberGuiVisible() || IsGamePausedSafe(); } catch (NullReferenceException) { return true; } } private static bool IsGamePausedSafe() { if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } try { return Game.IsPaused(); } catch (NullReferenceException) { return false; } } private void StartCamera(Player local) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)local) || !HasBuildingTool(local)) { Notify("Equip your hoe first."); return; } if (((Character)local).IsDead() || ((Character)local).InCutscene() || ((Character)local).IsTeleporting() || ((Character)local).IsAttached() || local.GetDoodadController() != null || !((Character)local).IsOnGround() || ((Character)local).IsSwimming()) { Notify("Stand on solid ground to enter the hoe camera."); return; } if (!Object.op_Implicit((Object)(object)GameCamera.instance) || GameCamera.InFreeFly()) { Notify("Return to the normal game camera first."); return; } if (OtherBuildCameraActive()) { Notify("Exit the hammer build camera first."); return; } _gameCamera = GameCamera.instance; _camera = ((Component)_gameCamera).GetComponent<Camera>(); if (!Object.op_Implicit((Object)(object)_camera)) { Notify("The game camera is not ready yet."); _gameCamera = null; return; } _skyCamera = _gameCamera.m_skyCamera; _player = local; _bodyOrigin = ((Component)local).transform.position; _savedCameraPosition = ((Component)_gameCamera).transform.position; _savedCameraRotation = ((Component)_gameCamera).transform.rotation; _savedFov = _camera.fieldOfView; _savedNearClip = _camera.nearClipPlane; _activeNearClip = Mathf.Min(_savedNearClip, 0.1f); _savedSkyFov = (Object.op_Implicit((Object)(object)_skyCamera) ? _skyCamera.fieldOfView : _savedFov); _savedReach = local.m_maxPlaceDistance; _appliedReach = EffectiveBuildReach; _active = true; StartTerrain(); local.m_autoRun = false; ((Character)local).StopMovement(); local.SetControls(Vector3.zero, false, false, false, false, false, false, false, false, false, false, false); local.m_maxPlaceDistance = _appliedReach; ((Character)local).m_onDamaged = (Action<float, Character>)Delegate.Combine(((Character)local).m_onDamaged, new Action<float, Character>(OnPlayerDamaged)); ResetView(); if (_hidePlayer.Value) { HideRenderers(); } _suppressUntil = Time.unscaledTime + 0.2f; _nextRendererScan = Time.unscaledTime + 0.25f; ApplyPose(); Notify("Hoe camera ON. Jump: up; Crouch: down. F6 or press both stick clicks: exit."); WriteDiagnostics("Activated"); } private void KeepBodyAtAnchor() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0044: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_player)) { Vector3 val = ((Component)_player).transform.position - _bodyOrigin; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { ((Component)_player).transform.position = _bodyOrigin; Physics.SyncTransforms(); } ((Character)_player).StopMovement(); } } private string InvalidActiveReason() { if (!Object.op_Implicit((Object)(object)_player) || (Object)(object)_player != (Object)(object)Player.m_localPlayer) { return "Player changed"; } if (!Object.op_Implicit((Object)(object)_gameCamera) || (Object)(object)GameCamera.instance != (Object)(object)_gameCamera || !Object.op_Implicit((Object)(object)_camera)) { return "Camera changed"; } if (!HasBuildingTool(_player)) { return "Hoe unequipped"; } if (((Character)_player).IsDead()) { return "Player died"; } if (((Character)_player).InCutscene() || ((Character)_player).IsTeleporting() || ((Character)_player).IsAttached() || _player.GetDoodadController() != null) { return "Player changed activity"; } return null; } private void OnPlayerDamaged(float damage, Character attacker) { if (_active && _exitOnDamage.Value && damage > 0f) { StopCamera("You took damage", message: true); } } private void ResetView() { //IL_000c: 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_0014: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) Quaternion rotation = ((Character)_player).m_eye.rotation; _yaw = ((Quaternion)(ref rotation)).eulerAngles.y; _pitch = CameraMath.Clamp(_startPitch.Value, 50f, 20f, 75f); _fov = CameraMath.Clamp(_startFov.Value, 45f, 25f, 75f); _rotation = Quaternion.Euler(_pitch, _yaw, 0f); Vector3 val = ((Component)_player).transform.position + Quaternion.Euler(0f, _yaw, 0f) * Vector3.forward * 5f + Vector3.up; _position = val - _rotation * Vector3.forward * 12f; ClampCameraPosition(); } private void MoveCamera() { //IL_001a: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) float num = CameraMath.Clamp(Time.unscaledDeltaTime, 0f, 0f, 0.05f); Vector2 val = Vector2.zero; if (ZInput.IsMouseActive()) { val = ZInput.GetMouseDelta() * (ZInput.IsGamepadMouseActive() ? PlayerController.m_switchMouseSens : PlayerController.m_mouseSens); if (PlayerController.m_invertMouse) { val.y *= -1f; } } else if (ZInput.IsGamepadActive()) { val = new Vector2(StickInput.RightStickX(), 0f - StickInput.RightStickY()) * 110f * num * PlayerController.m_gamepadSens; if (PlayerController.m_invertCameraX) { val.x *= -1f; } if (PlayerController.m_invertCameraY) { val.y *= -1f; } } _yaw = Mathf.Repeat(_yaw + val.x, 360f); _pitch = Mathf.Clamp(_pitch - val.y, -80f, 85f); if (ZInput.GetKey((KeyCode)280, true)) { _fov -= 25f * num; } if (ZInput.GetKey((KeyCode)281, true)) { _fov += 25f * num; } _fov = Mathf.Clamp(_fov, 25f, 75f); _rotation = Quaternion.Euler(_pitch, _yaw, 0f); float x = (ZInput.GetButton("Right") ? 1f : 0f) - (ZInput.GetButton("Left") ? 1f : 0f) + StickInput.LeftStickX(); float z = (ZInput.GetButton("Forward") ? 1f : 0f) - (ZInput.GetButton("Backward") ? 1f : 0f) - StickInput.LeftStickY(); float y = ((ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump")) ? 1f : 0f) - ((ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch")) ? 1f : 0f); CameraMath.NormalizeInput(ref x, ref y, ref z); float num2 = CameraMath.Clamp(_speed.Value, 6f, 1f, 15f); if (ZInput.GetButton("Run") || ZInput.GetButton("JoyRun")) { num2 *= CameraMath.Clamp(_fastMultiplier.Value, 2f, 1f, 3f); } if (x != 0f || y != 0f || z != 0f) { MovementVector movementVector = CameraMath.ViewRelativeMovement(_yaw, _pitch, x, y, z); float x2 = movementVector.X; float y2 = movementVector.Y; float z2 = movementVector.Z; CameraMath.NormalizeInput(ref x2, ref y2, ref z2); _position += new Vector3(x2, y2, z2) * num2 * num; ClampCameraPosition(); } } private void ClampCameraPosition() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Vector3 val = _bodyOrigin + Vector3.up; Vector3 val2 = _position - val; float x = val2.x; float y = val2.y; float z = val2.z; CameraMath.ClampToSphere(ref x, ref y, ref z, EffectiveCameraRadius); _position = val + new Vector3(x, y, z); } internal void ApplyPose() { //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_003e: 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_0068: 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_0050: 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) if (!_active || !Object.op_Implicit((Object)(object)_camera) || !Object.op_Implicit((Object)(object)_gameCamera)) { return; } HoeCameraRumble.Stop(); Transform transform = ((Component)_gameCamera).transform; Vector3 position = transform.position; if (((Vector3)(ref position)).Equals(_position)) { Quaternion rotation = transform.rotation; if (((Quaternion)(ref rotation)).Equals(_rotation)) { goto IL_0072; } } transform.SetPositionAndRotation(_position, _rotation); goto IL_0072; IL_0072: if (_camera.fieldOfView != _fov) { _camera.fieldOfView = _fov; } if (_camera.nearClipPlane != _activeNearClip) { _camera.nearClipPlane = _activeNearClip; } if (Object.op_Implicit((Object)(object)_skyCamera) && _skyCamera.fieldOfView != _fov) { _skyCamera.fieldOfView = _fov; } } private void HideRenderers() { LocalPlayerVisuals.Hide(_player, _camera); } private void StopCamera(string reason, bool message) { //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) _nextCircletCheck = 0f; StopTerrain(); if (_active) { HoeCameraRumble.Stop(); } CircletCameraLight.Stop(); FeatherCapeMist.Clear(); _toggleInput.CancelPending(); if (!_active) { return; } _active = false; _lastExit = reason; try { if (Object.op_Implicit((Object)(object)_player)) { Player player = _player; ((Character)player).m_onDamaged = (Action<float, Character>)Delegate.Remove(((Character)player).m_onDamaged, new Action<float, Character>(OnPlayerDamaged)); if (Mathf.Approximately(_player.m_maxPlaceDistance, _appliedReach)) { _player.m_maxPlaceDistance = _savedReach; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Build reach cleanup: " + ex.Message)); } RestoreRenderers(); try { if (Object.op_Implicit((Object)(object)_camera)) { _camera.fieldOfView = _savedFov; _camera.nearClipPlane = _savedNearClip; } if (Object.op_Implicit((Object)(object)_skyCamera)) { _skyCamera.fieldOfView = _savedSkyFov; } if (Object.op_Implicit((Object)(object)_player) && (Object)(object)_player == (Object)(object)Player.m_localPlayer && !((Character)_player).IsTeleporting() && !((Character)_player).InCutscene() && !((Character)_player).IsAttached() && _player.GetDoodadController() == null) { Vector3 val = ((Component)_player).transform.position - _bodyOrigin; if (((Vector3)(ref val)).sqrMagnitude < 1f && Object.op_Implicit((Object)(object)_gameCamera) && (Object)(object)_gameCamera == (Object)(object)GameCamera.instance && !GameCamera.InFreeFly()) { ((Component)_gameCamera).transform.SetPositionAndRotation(_savedCameraPosition, _savedCameraRotation); } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Camera cleanup: " + ex2.Message)); } _player = null; _gameCamera = null; _camera = null; _skyCamera = null; float suppressUntil; switch (reason) { default: suppressUntil = 0f; break; case "Toggled off": case "Escape": case "Configuration reload": suppressUntil = Time.unscaledTime + 0.2f; break; } _suppressUntil = suppressUntil; if (message) { Notify("Hoe camera OFF: " + reason + "."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Hoe Cam stopped: " + reason)); } private void RestoreRenderers() { LocalPlayerVisuals.Restore(); } internal void Fail(Exception error) { StopCamera("Stopped after an error", message: false); _failed = true; ResetInput(); ((BaseUnityPlugin)this).Logger.LogError((object)("Hoe Cam stopped and restored its local changes. " + error)); WriteDiagnostics("Error: " + error.GetType().Name + ": " + error.Message); } private static void Notify(string text) { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true); } } private void OnGUI() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 if ((int)Event.current.type == 7 && Active && !MenuBlocksCamera()) { DrawTerrainHud(); } } private void RefreshIndicatorText() { //IL_000c: 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) _indicatorText = "HOE CAM | " + ((object)_toggleKey.Value/*cast due to .constrained prefix*/).ToString() + (_controllerToggle.Value ? " / press both stick clicks to exit" : " to exit"); } private void ResetInput() { _toggleInput.Reset(waitForRelease: true); _chordHeld = false; _suppressUntil = 0f; } private void OnApplicationFocus(bool focused) { if (!focused) { StopCamera("Focus lost", message: false); ResetInput(); } } private void OnDisable() { StopCamera("Plugin disabled", message: false); ResetInput(); } private void OnDestroy() { StopCamera("Plugin unloaded", message: false); ResetInput(); if (_harmony != null) { _harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void WriteDiagnostics(string reason) { //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Hoe Cam 0.1.6 - client diagnostics"); stringBuilder.AppendLine("Reason: " + reason); stringBuilder.AppendLine("No player names, server addresses, chat, item descriptions or world coordinates included."); stringBuilder.AppendLine("Unity=" + Application.unityVersion + "; screen=" + Screen.width + "x" + Screen.height); stringBuilder.AppendLine("Ready=" + _ready + "; failed=" + _failed + "; active=" + _active + "; last exit=" + _lastExit); stringBuilder.AppendLine("Effective camera radius=" + EffectiveCameraRadius + "; configured free-camera reach=" + EffectiveBuildReach + "; range multiplier=" + _rangeMultiplier.Value); stringBuilder.AppendLine("Game assembly=" + typeof(Player).Assembly.GetName().Version?.ToString() + "; Harmony=" + typeof(Harmony).Assembly.GetName().Version); if (Object.op_Implicit((Object)(object)_player)) { stringBuilder.AppendLine("Building tool=" + HasBuildingTool(_player) + "; grounded=" + ((Character)_player).IsOnGround() + "; menu paused=" + MenuBlocksCamera()); stringBuilder.AppendLine("Camera distance from body=" + Vector3.Distance(_position, _bodyOrigin).ToString("F2", CultureInfo.InvariantCulture)); stringBuilder.AppendLine("Pitch=" + _pitch + "; FOV=" + _fov + "; temporary reach=" + _player.m_maxPlaceDistance + "; original reach=" + _savedReach); stringBuilder.AppendLine("Tracked local renderers=" + LocalPlayerVisuals.RendererCount); } stringBuilder.AppendLine("Native terrain operations are sent without material, stamina or durability costs while Hoe Cam is active. Ward checks and native terrain height limits remain."); File.WriteAllText(Path.Combine(Paths.ConfigPath, "valheim.hoecam.diagnostics.txt"), stringBuilder.ToString()); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write hoe camera diagnostics: " + ex.Message)); } } private void ConfigureTerrain() { if (TerrainApply == null || TerrainLoad == null || TerrainInitialized == null || GhostField == null) { throw new MissingMethodException("Required native terrain/placement methods were not found."); } _brushRadius = FloatSetting("Terrain", "BrushRadius", 3f, 1f, 6f, "Circular brush radius in metres."); _heightStep = FloatSetting("Terrain", "HeightStep", 0.5f, 0.25f, 1f, "Raise/lower amount per stroke. Uses native persistent terrain baselines beyond the vanilla height limit."); } private void StartTerrain() { _heightLocked = false; _terrainArmed = false; _hasTerrain = false; _statusUntil = 0f; _terrainStatus = "Aim at the ground"; _nextStroke = Time.unscaledTime + 0.25f; _nextBrushDraw = 0f; ref GameObject savedGhost = ref _savedGhost; object? value = GhostField.GetValue(_player); savedGhost = (GameObject)((value is GameObject) ? value : null); _ghostWasActive = Object.op_Implicit((Object)(object)_savedGhost) && _savedGhost.activeSelf; if (Object.op_Implicit((Object)(object)_savedGhost)) { _savedGhost.SetActive(false); } } private void StopTerrain() { HideBrush(); if (Object.op_Implicit((Object)(object)_savedGhost)) { _savedGhost.SetActive(_ghostWasActive); } _savedGhost = null; _hasTerrain = false; if (Object.op_Implicit((Object)(object)_brushRing)) { Object.Destroy((Object)(object)((Component)_brushRing).gameObject); } if (Object.op_Implicit((Object)(object)_brushMaterial)) { Object.Destroy((Object)(object)_brushMaterial); } _brushRing = null; _brushMaterial = null; _terrainMaps.Clear(); _terrainCompilers.Clear(); } private void HideBrush() { if (Object.op_Implicit((Object)(object)_brushRing)) { ((Renderer)_brushRing).enabled = false; } } private void TickTerrain() { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) Gamepad current = Gamepad.current; bool flag = ZInput.IsGamepadActive() && current != null; if (ZInput.GetKeyDown((KeyCode)49, true)) { _mode = BrushMode.Flatten; } if (ZInput.GetKeyDown((KeyCode)50, true)) { _mode = BrushMode.Raise; } if (ZInput.GetKeyDown((KeyCode)51, true)) { _mode = BrushMode.Lower; } if (flag && current.dpad.left.wasPressedThisFrame) { _mode = (BrushMode)((int)(_mode + 2) % 3); } if (flag && current.dpad.right.wasPressedThisFrame) { _mode = (BrushMode)((int)(_mode + 1) % 3); } float num = (flag ? ((current.dpad.up.wasPressedThisFrame ? 1f : 0f) - (current.dpad.down.wasPressedThisFrame ? 1f : 0f)) : ((float)TerrainPolicy.ScrollStep(ZInput.GetMouseScrollWheel()))); if (num != 0f) { _brushRadius.Value = Mathf.Clamp(_brushRadius.Value + num, 1f, 6f); } bool flag2 = (flag ? current.rightTrigger.isPressed : ZInput.GetMouseButton(0)); if (!flag2) { _terrainArmed = true; } RaycastHit val = default(RaycastHit); _hasTerrain = Physics.Raycast(((Component)_camera).transform.position, ((Component)_camera).transform.forward, ref val, EffectiveCameraRadius * 2f + 10f, LayerMask.GetMask(new string[1] { "terrain" }), (QueryTriggerInteraction)1); if (!_hasTerrain) { _terrainStatus = "Aim at loaded ground"; HideBrush(); return; } _terrainPoint = ((RaycastHit)(ref val)).point; float num2 = Mathf.Clamp(_brushRadius.Value, 1f, 6f); bool flag3 = TerrainPolicy.InRange(Vector3.Distance(_bodyOrigin, _terrainPoint), num2, EffectiveBuildReach); if ((flag ? current.buttonNorth.wasPressedThisFrame : ZInput.GetKeyDown((KeyCode)114, true)) && flag3 && _mode == BrushMode.Flatten) { _flatHeight = _terrainPoint.y; _heightLocked = true; _terrainStatus = "Height chosen! Aim elsewhere and apply to flatten."; _statusUntil = Time.unscaledTime + 2f; } if (Time.unscaledTime >= _nextBrushDraw) { _nextBrushDraw = Time.unscaledTime + 0.08f; bool flag4 = flag3 && TerrainAllowed(_terrainPoint, num2); DrawBrush(num2, flag4); if (!flag4 || Time.unscaledTime >= _statusUntil) { _terrainStatus = ((!flag3) ? "Outside hoe camera reach" : ((!flag4) ? "Protected area — terrain locked" : ((_mode == BrushMode.Flatten && !_heightLocked) ? "First stroke sets the flatten height" : "Ready"))); } } if (!flag2 || !_terrainArmed || Time.unscaledTime < _nextStroke) { return; } _nextStroke = Time.unscaledTime + 0.3f; if (flag3 && TerrainAllowed(_terrainPoint, num2)) { if (Heightmap.HaveQueuedRebuild(_terrainPoint, num2)) { _terrainStatus = "Updating terrain"; } else { ApplyTerrain(num2); } } } private static bool TerrainAllowed(Vector3 point, float radius) { //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_002a: 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_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) if (!PrivateArea.CheckAccess(point, radius, false, false)) { return false; } if (Location.IsInsideNoBuildLocation(point)) { return false; } for (int i = 0; i < 8; i++) { float num = (float)i * (float)Math.PI / 4f; if (Location.IsInsideNoBuildLocation(point + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * radius)) { return false; } } return true; } private void ApplyTerrain(float radius) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: 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_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) if (!_heightLocked && _mode == BrushMode.Flatten) { _flatHeight = _terrainPoint.y; _heightLocked = true; } _terrainMaps.Clear(); _terrainCompilers.Clear(); Heightmap.FindHeightmap(_terrainPoint, radius + 1f, _terrainMaps); if (_terrainMaps.Count == 0 || _terrainMaps.Count > 4) { _terrainStatus = "Terrain not ready"; return; } foreach (Heightmap terrainMap in _terrainMaps) { if (!Object.op_Implicit((Object)(object)terrainMap) || terrainMap.HaveQueuedRebuild()) { _terrainStatus = "Updating terrain"; return; } TerrainComp andCreateTerrainCompiler = terrainMap.GetAndCreateTerrainCompiler(); if (!Object.op_Implicit((Object)(object)andCreateTerrainCompiler) || !(bool)TerrainInitialized.GetValue(andCreateTerrainCompiler)) { _terrainStatus = "Terrain not ready"; return; } ZNetView component = ((Component)andCreateTerrainCompiler).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return; } TerrainLoad.Invoke(andCreateTerrainCompiler, null); if (!component.IsOwner()) { component.ClaimOwnership(); } if (!component.IsOwner()) { _terrainStatus = "Waiting for terrain ownership"; return; } TerrainLoad.Invoke(andCreateTerrainCompiler, null); _terrainCompilers.Add(andCreateTerrainCompiler); } Settings settings = new Settings { m_level = (_mode == BrushMode.Flatten), m_levelRadius = radius, m_levelOffset = 0f, m_raise = (_mode != BrushMode.Flatten), m_raiseRadius = radius, m_raiseDelta = TerrainPolicy.Delta((int)_mode, _heightStep.Value), m_raisePower = 1f, m_square = false, m_halfOffset = false, m_smooth = false, m_paintCleared = (_mode == BrushMode.Flatten), m_paintType = (PaintType)0, m_paintRadius = radius, m_paintStrength = 1f, m_paintHeightCheck = false, m_rotation = false, m_sides = false }; Vector3 terrainPoint = _terrainPoint; if (_mode == BrushMode.Flatten) { terrainPoint.y = _flatHeight; } if (!NativeTerrainBaseline.Apply(_terrainMaps, _terrainCompilers, terrainPoint, settings, out var failure)) { _terrainStatus = failure; _statusUntil = Time.unscaledTime + 4f; } else { _terrainStatus = "Terrain updated"; } } private void DrawBrush(float radius, bool allowed) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_0030: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0100: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_brushRing)) { Shader val = Shader.Find("Sprites/Default"); if (!Object.op_Implicit((Object)(object)val)) { return; } _brushMaterial = new Material(val); GameObject val2 = new GameObject("HoeCam_BrushPreview"); _brushRing = val2.AddComponent<LineRenderer>(); ((Renderer)_brushRing).sharedMaterial = _brushMaterial; _brushRing.useWorldSpace = true; _brushRing.loop = true; _brushRing.positionCount = 48; LineRenderer brushRing = _brushRing; float startWidth = (_brushRing.endWidth = 0.045f); brushRing.startWidth = startWidth; ((Renderer)_brushRing).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)_brushRing).receiveShadows = false; } Color val3 = (allowed ? new Color(0.35f, 1f, 0.6f, 0.9f) : new Color(1f, 0.25f, 0.2f, 0.9f)); LineRenderer brushRing2 = _brushRing; Color startColor = (_brushRing.endColor = val3); brushRing2.startColor = startColor; float y = default(float); for (int i = 0; i < 48; i++) { float num2 = (float)i * (float)Math.PI * 2f / 48f; Vector3 val5 = _terrainPoint + new Vector3(Mathf.Cos(num2), 0f, Mathf.Sin(num2)) * radius; if (_mode == BrushMode.Flatten && _heightLocked) { val5.y = _flatHeight; } else if (Heightmap.GetHeight(val5, ref y)) { val5.y = y; } val5.y += 0.08f; _brushRing.SetPosition(i, val5); } ((Renderer)_brushRing).enabled = true; } private void DrawTerrainHud() { //IL_0024: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0057: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) if (_showIndicator.Value) { if (_hudTitle == null) { _hudTitle = new GUIStyle(GUI.skin.label) { fontSize = 25, fontStyle = (FontStyle)1 }; _hudTitle.normal.textColor = new Color(1f, 0.78f, 0.35f); _hudText = new GUIStyle(GUI.skin.label) { fontSize = 20, wordWrap = true }; _hudText.normal.textColor = Color.white; } bool flag = ZInput.IsGamepadActive(); string text = (flag ? "RT" : "left mouse"); string text2 = (flag ? "Y" : "R"); string text3; if (_mode == BrushMode.Flatten) { text3 = "1. Aim at ground with the height you want.\n2. Press " + text2 + " to choose that height.\n3. Aim elsewhere. Hold " + text + " to flatten."; text3 += (_heightLocked ? ("\nHeight is locked until you press " + text2 + " again.") : "\nOr start flattening to use the first aimed height."); } else { text3 = "1. Aim at the ground you want to change.\n2. Hold " + text + " to " + ((_mode == BrushMode.Raise) ? "raise" : "lower") + " the ground.\n3. Release to stop. Move your aim to continue."; } text3 = text3 + "\n\n" + _terrainStatus + "\n"; text3 += (flag ? "\nD-pad left/right: Flatten / Raise / Lower\nD-pad up: larger · D-pad down: smaller\nLeft stick: move camera · Right stick: look\nJump / Crouch: move camera up / down\nClick BOTH sticks: exit · Start: game menu" : "\n1: Flatten · 2: Raise · 3: Lower\nMouse wheel: brush size · F11: reset view\nWASD: move camera · Mouse: look\nJump / Crouch: move camera up / down\nF6: exit · Escape: game menu"); float num = _hudText.CalcHeight(new GUIContent(text3), 515f); string text4 = "Brush radius: " + _brushRadius.Value.ToString("0") + " m"; if (_mode != BrushMode.Flatten) { text4 = text4 + " · Step: " + _heightStep.Value.ToString("0.00") + " m"; } Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; float num2 = Mathf.Clamp((float)Screen.height / 1080f, 0.7f, 2.5f); GUI.matrix = Matrix4x4.Scale(new Vector3(num2, num2, 1f)); GUI.color = new Color(0.07f, 0.09f, 0.11f, 0.94f); GUI.DrawTexture(new Rect(20f, 155f, 543f, num + 90f), (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUI.Label(new Rect(34f, 165f, 515f, 34f), "HOE CAM · " + _mode, _hudTitle); GUI.Label(new Rect(34f, 200f, 515f, 28f), text4, _hudText); GUI.Label(new Rect(34f, 235f, 515f, num), text3, _hudText); GUI.color = color; GUI.matrix = matrix; } } private void InstallBuildCameraCompatibility() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("valheim.buildcamera", out var value)) { _otherPlugin = value.Instance; Type type = ((object)value.Instance).GetType(); _otherActive = AccessTools.Property(type, "Active"); MethodInfo methodInfo = AccessTools.Method(type, "IsBuildTool", new Type[1] { typeof(ItemData) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HoeCamera), "ExcludeHoeFromOtherCamera", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Build camera compatibility gate unavailable; use separate keyboard toggles."); } MethodInfo methodInfo2 = AccessTools.Method(type, "StartCamera", new Type[1] { typeof(Player) }, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(HoeCamera), "ReserveHoeKeyboardActivation", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } private static void ExcludeHoeFromOtherCamera(ItemData __0, ref bool __result) { if (Object.op_Implicit((Object)(object)Instance) && Instance.HooksEnabled && Instance._enabled.Value && IsBuildTool(__0)) { __result = false; } } private static bool ReserveHoeKeyboardActivation(Player __0) { if (Object.op_Implicit((Object)(object)Instance) && Instance.HooksEnabled && Instance._enabled.Value && Object.op_Implicit((Object)(object)__0) && Instance.IsLocal(__0)) { return !HasBuildingTool(__0); } return true; } private static bool OtherBuildCameraActive() { if (_otherPlugin != null && _otherActive != null) { return (bool)_otherActive.GetValue(_otherPlugin, null); } return false; } } internal static class HoeCameraRumble { [HarmonyPatch(typeof(ZInput), "InternalSetGamepadRumble")] private static class SuppressFreeCameraRumble { private static bool Prefix() { if (Object.op_Implicit((Object)(object)HoeCamera.Instance)) { return !HoeCamera.Instance.Active; } return true; } } private static readonly FieldRef<GameCamera, float> Shake = AccessTools.FieldRefAccess<GameCamera, float>("m_shakeIntensity"); internal static void Stop() { if (Object.op_Implicit((Object)(object)GameCamera.instance)) { Shake.Invoke(GameCamera.instance) = 0f; } ZInput.StopGamepadRumble(); } } internal static class LocalPlayerVisuals { private static readonly Dictionary<Renderer, bool> Renderers = new Dictionary<Renderer, bool>(); private static readonly Dictionary<Light, bool> Lights = new Dictionary<Light, bool>(); private static readonly HashSet<Renderer> SeenRenderers = new HashSet<Renderer>(); private static readonly HashSet<Light> SeenLights = new HashSet<Light>(); private static readonly List<Renderer> RendererScan = new List<Renderer>(); private static readonly List<Light> LightScan = new List<Light>(); private static readonly List<Renderer> RetiredRenderers = new List<Renderer>(); private static readonly List<Light> RetiredLights = new List<Light>(); private static Component _owner; private static bool _warned; private static readonly Dictionary<Type, FieldInfo> EffectFields = new Dictionary<Type, FieldInfo>(); internal static int RendererCount => Renderers.Count; private static void Scan(GameObject root, Camera camera) { if (!Object.op_Implicit((Object)(object)root)) { return; } RendererScan.Clear(); LightScan.Clear(); root.GetComponentsInChildren<Renderer>(true, RendererScan); root.GetComponentsInChildren<Light>(true, LightScan); foreach (Renderer item in RendererScan) { if (Object.op_Implicit((Object)(object)item) && (!Object.op_Implicit((Object)(object)camera) || !((Component)item).transform.IsChildOf(((Component)camera).transform))) { SeenRenderers.Add(item); if (!Renderers.ContainsKey(item)) { Renderers.Add(item, item.forceRenderingOff); } item.forceRenderingOff = true; } } foreach (Light item2 in LightScan) { if (Object.op_Implicit((Object)(object)item2) && (!Object.op_Implicit((Object)(object)camera) || !((Component)item2).transform.IsChildOf(((Component)camera).transform))) { SeenLights.Add(item2); if (!Lights.ContainsKey(item2)) { Lights.Add(item2, ((Behaviour)item2).enabled); } ((Behaviour)item2).enabled = false; } } } internal static void Hide(object player, Camera camera) { Component val = (Component)((player is Component) ? player : null); if (!Object.op_Implicit((Object)(object)val)) { Restore(); return; } if ((Object)(object)_owner != (Object)(object)val) { Restore(); _owner = val; } SeenRenderers.Clear(); SeenLights.Clear(); Scan(val.gameObject, camera); try { MethodInfo method = ((object)val).GetType().GetMethod("GetSEMan", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null) { object obj = method.Invoke(val, null); if (obj != null) { MethodInfo method2 = obj.GetType().GetMethod("GetStatusEffects", Type.EmptyTypes); if (method2 != null) { foreach (object item in (IEnumerable)method2.Invoke(obj, null)) { if (item == null) { continue; } Type type = item.GetType(); if (!EffectFields.TryGetValue(type, out var value)) { Type type2 = type; while (type2 != null && value == null) { value = type2.GetField("m_startEffectInstances", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); type2 = type2.BaseType; } EffectFields.Add(type, value); } IEnumerable enumerable = ((value == null) ? null : (value.GetValue(item) as IEnumerable)); if (enumerable == null) { continue; } foreach (object item2 in enumerable) { Scan((GameObject)((item2 is GameObject) ? item2 : null), camera); } } } } } } catch (Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("Hoe Cam effect visibility: " + ex.Message)); } } RetiredRenderers.Clear(); RetiredLights.Clear(); foreach (KeyValuePair<Renderer, bool> renderer in Renderers) { if (!Object.op_Implicit((Object)(object)renderer.Key) || !SeenRenderers.Contains(renderer.Key)) { if (Object.op_Implicit((Object)(object)renderer.Key)) { renderer.Key.forceRenderingOff = renderer.Value; } RetiredRenderers.Add(renderer.Key); } } foreach (KeyValuePair<Light, bool> light in Lights) { if (!Object.op_Implicit((Object)(object)light.Key) || !SeenLights.Contains(light.Key)) { if (Object.op_Implicit((Object)(object)light.Key)) { ((Behaviour)light.Key).enabled = light.Value; } RetiredLights.Add(light.Key); } } foreach (Renderer retiredRenderer in RetiredRenderers) { Renderers.Remove(retiredRenderer); } foreach (Light retiredLight in RetiredLights) { Lights.Remove(retiredLight); } } internal static void Restore() { foreach (KeyValuePair<Renderer, bool> renderer in Renderers) { if (Object.op_Implicit((Object)(object)renderer.Key)) { renderer.Key.forceRenderingOff = renderer.Value; } } foreach (KeyValuePair<Light, bool> light in Lights) { if (Object.op_Implicit((Object)(object)light.Key)) { ((Behaviour)light.Key).enabled = light.Value; } } Renderers.Clear(); Lights.Clear(); SeenRenderers.Clear(); SeenLights.Clear(); RendererScan.Clear(); LightScan.Clear(); RetiredRenderers.Clear(); RetiredLights.Clear(); _owner = null; } } internal static class NativeTerrainBaseline { private sealed class Snapshot { internal TerrainComp Compiler; internal Heightmap Map; internal readonly Dictionary<FieldInfo, object> Values = new Dictionary<FieldInfo, object>(); internal float[] OldLevel; internal float[] OldSmooth; internal float[] Level; internal float[] Smooth; internal Snapshot(TerrainComp compiler, Heightmap map) { Compiler = compiler; Map = map; string[] snapshotFields = SnapshotFields; foreach (string text in snapshotFields) { FieldInfo fieldInfo = AccessTools.Field(typeof(TerrainComp), text); if (fieldInfo == null) { throw new MissingFieldException("TerrainComp", text); } object value = fieldInfo.GetValue(compiler); Values.Add(fieldInfo, (value is Array) ? ((Array)value).Clone() : value); } OldLevel = (float[])Values[Levels]; OldSmooth = (float[])Values[NativeTerrainBaseline.Smooth]; Level = (float[])Levels.GetValue(compiler); Smooth = (float[])NativeTerrainBaseline.Smooth.GetValue(compiler); } internal void Restore() { foreach (KeyValuePair<FieldInfo, object> value in Values) { if (value.Value is Array) { Array.Copy((Array)value.Value, (Array)value.Key.GetValue(Compiler), ((Array)value.Value).Length); } else { value.Key.SetValue(Compiler, value.Value); } } } } private sealed class Node { internal Snapshot Snapshot; internal int Index; } private sealed class Baseline { internal Vector3 Point; internal bool Required; internal int SortOrder = 1000000; internal readonly List<Node> Nodes = new List<Node>(); internal readonly List<ZNetView> Previous = new List<ZNetView>(); } private const string Marker = "HoeCam.NativeBaseline.v1"; private const float SingleVertexRadius = -0.001f; private static readonly MethodInfo Edit = AccessTools.Method(typeof(TerrainComp), "InternalDoOperation", (Type[])null, (Type[])null); private static readonly MethodInfo Save = AccessTools.Method(typeof(TerrainComp), "Save", (Type[])null, (Type[])null); private static readonly MethodInfo GetLocation = AccessTools.Method(typeof(ZoneSystem), "GetLocation", new Type[1] { typeof(int) }, (Type[])null); private static readonly FieldInfo Levels = AccessTools.Field(typeof(TerrainComp), "m_levelDelta"); private static readonly FieldInfo Smooth = AccessTools.Field(typeof(TerrainComp), "m_smoothDelta"); private static readonly string[] SnapshotFields = new string[8] { "m_levelDelta", "m_smoothDelta", "m_modifiedHeight", "m_modifiedPaint", "m_paintMask", "m_operations", "m_lastOpPoint", "m_lastOpRadius" }; private static readonly string[] CandidateNames = new string[19] { "WoodHouse1", "WoodHouse2", "WoodHouse3", "WoodHouse4", "WoodHouse5", "WoodHouse6", "WoodHouse7", "WoodHouse8", "WoodHouse9", "WoodHouse10", "AbandonedLogCabin02", "AbandonedLogCabin03", "DevHouse1", "DevHouse2", "StoneHouse1", "StoneHouse2", "StoneHouse3", "StoneHouse4", "StoneHouse5" }; private static ZoneSystem selectedWorld; private static string locationName; private static Vector3 modifierOffset; private static float levelOffset; private static bool searched; private static string lastError; internal static bool Apply(List<Heightmap> maps, List<TerrainComp> compilers, Vector3 point, Settings settings, out string failure) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0620: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) //IL_04ed: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Unknown result type (might be due to invalid IL or missing references) failure = null; List<Snapshot> list = new List<Snapshot>(); List<ZNetView> list2 = new List<ZNetView>(); bool flag = false; try { if (Edit == null || Save == null) { throw new MissingMethodException("Native terrain save/edit API unavailable"); } for (int i = 0; i < compilers.Count; i++) { if (!compilers[i].IsOwner()) { throw new InvalidOperationException("Waiting for terrain ownership"); } list.Add(new Snapshot(compilers[i], maps[i])); } TerrainHeightPolicy.Enter(); try { foreach (Snapshot item in list) { Edit.Invoke(item.Compiler, new object[3] { point, Vector3.zero, settings }); } } finally { TerrainHeightPolicy.Exit(); } Dictionary<Vector2, Baseline> dictionary = new Dictionary<Vector2, Baseline>(); Vector2 key = default(Vector2); foreach (Snapshot item2 in list) { Heightmap map = item2.Map; int num = map.m_width + 1; for (int j = 0; j < item2.Level.Length; j++) { if (item2.Level[j] != item2.OldLevel[j] || item2.Smooth[j] != item2.OldSmooth[j]) { float num2 = item2.Level[j] + item2.Smooth[j]; float num3 = item2.OldLevel[j] + item2.OldSmooth[j]; int num4 = j % num; int num5 = j / num; Vector3 val = ((Component)map).transform.position + new Vector3((float)(num4 - map.m_width / 2) * map.m_scale, map.GetHeight(num4, num5), (float)(num5 - map.m_width / 2) * map.m_scale); if (Math.Abs(num3) > 8.001f) { throw new InvalidOperationException("Old unlimited edit here: restore this area with 0.1.5 first"); } val.y += num2 - num3; if (float.IsNaN(val.y) || float.IsInfinity(val.y)) { throw new InvalidOperationException("Invalid terrain height"); } ((Vector2)(ref key))..ctor(val.x, val.z); if (!dictionary.TryGetValue(key, out var value)) { value = new Baseline { Point = val }; dictionary.Add(key, value); } else if (Math.Abs(value.Point.y - val.y) > 0.01f) { throw new InvalidOperationException("Terrain border is still syncing — try again"); } value.Required |= Math.Abs(num2) > 7.5f; value.Nodes.Add(new Node { Snapshot = item2, Index = j }); } } } List<Baseline> list3 = new List<Baseline>(); foreach (Baseline value2 in dictionary.Values) { if (value2.Required) { list3.Add(value2); } } if (list3.Count > 0) { foreach (Baseline item3 in list3) { foreach (Node node in item3.Nodes) { int width = node.Snapshot.Map.m_width; int num6 = width + 1; int num7 = node.Index % num6; int num8 = node.Index / num6; int num9 = ((num7 != 0 && num7 != width) ? 1 : 2) * ((num8 != 0 && num8 != width) ? 1 : 2); if (item3.Nodes.Count < num9) { throw new InvalidOperationException("Load both sides of the terrain border before editing"); } } } EnsureTemplate(); if (selectedWorld.ShouldDelayProxyLocationSpawning(StringExtensionMethods.GetStableHashCode(locationName))) { throw new InvalidOperationException("Loading native terrain carrier — try again"); } List<TerrainModifier> list4 = new List<TerrainModifier>(TerrainModifier.GetAllInstances()); foreach (Baseline item4 in list3) { foreach (TerrainModifier item5 in list4) { if (!Object.op_Implicit((Object)(object)item5) || !((Behaviour)item5).enabled) { continue; } ZNetView componentInParent = ((Component)item5).GetComponentInParent<ZNetView>(); bool num10 = Object.op_Implicit((Object)(object)componentInParent) && componentInParent.IsValid() && componentInParent.GetZDO().GetBool("HoeCam.NativeBaseline.v1", false); float num11 = Vector2.Distance(new Vector2(((Component)item5).transform.position.x, ((Component)item5).transform.position.z), new Vector2(item4.Point.x, item4.Point.z)); if (num10 && num11 < 0.01f) { if (!componentInParent.IsOwner()) { componentInParent.ClaimOwnership(); } if (!componentInParent.IsOwner()) { throw new InvalidOperationException("Waiting for terrain baseline ownership"); } if (item5.m_sortOrder == int.MaxValue) { throw new InvalidOperationException("Terrain baseline ordering exhausted"); } item4.SortOrder = Math.Max(item4.SortOrder, item5.m_sortOrder + 1); item4.Previous.Add(componentInParent); } else if (item5.m_playerModifiction && (item5.m_level || item5.m_smooth) && num11 <= Math.Max(0f, item5.GetRadius()) * 1.415f + 1f) { throw new InvalidOperationException("Legacy terrain modifier here prevents shared unlimited editing"); } } } foreach (Baseline item6 in list3) { list2.Add(Create(item6.Point, item6.SortOrder)); } } foreach (Snapshot item7 in list) { if (!item7.Compiler.IsOwner()) { throw new InvalidOperationException("Terrain ownership changed — try again"); } } foreach (Baseline item8 in list3) { foreach (ZNetView previou in item8.Previous) { if (!previou.IsOwner()) { throw new InvalidOperationException("Terrain baseline ownership changed — try again"); } } } foreach (Baseline item9 in list3) { foreach (Node node2 in item9.Nodes) { node2.Snapshot.Level[node2.Index] = 0f; node2.Snapshot.Smooth[node2.Index] = 0f; } } flag = true; foreach (Snapshot item10 in list) { Save.Invoke(item10.Compiler, new object[1] { false }); } foreach (Baseline item11 in list3) { foreach (ZNetView previou2 in item11.Previous) { previou2.Destroy(); } } foreach (Snapshot item12 in list) { item12.Map.Poke(1, false); } lastError = null; return true; } catch (Exception ex) { if (!flag) { foreach (Snapshot item13 in list) { item13.Restore(); } foreach (ZNetView item14 in list2) { if (Object.op_Implicit((Object)(object)item14) && item14.IsValid() && item14.IsOwner()) { item14.Destroy(); } } } else { foreach (Snapshot item15 in list) { item15.Map.Poke(1, false); } } Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex); failure = (flag ? "Terrain save failed — stop editing and check log" : ex2.Message); if (lastError != ex.ToString()) { lastError = ex.ToString(); Debug.LogWarning((object)("[HoeCam] Native terrain edit " + (flag ? "commit failed: " : "cancelled: ") + ex)); } return false; } } private static void EnsureTemplate() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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) if ((Object)(object)selectedWorld != (Object)(object)ZoneSystem.instance) { selectedWorld = ZoneSystem.instance; searched = false; locationName = null; } if (locationName != null) { return; } if (!Object.op_Implicit((Object)(object)selectedWorld) || !Object.op_Implicit((Object)(object)selectedWorld.m_locationProxyPrefab)) { throw new InvalidOperationException("World terrain assets not ready"); } if (!searched) { searched = true; string[] candidateNames = CandidateNames; foreach (string text in candidateNames) { if (GetLocation == null) { throw new MissingMethodException("Native location lookup unavailable"); } ZoneLocation val = (ZoneLocation)GetLocation.Invoke(selectedWorld, new object[1] { StringExtensionMethods.GetStableHashCode(text) }); if (val == null || !val.m_prefab.IsValid) { continue; } val.m_prefab.Load(); try { GameObject asset = val.m_prefab.Asset; if (!IsPureProxy(asset, out var modifier)) { continue; } locationName = text; modifierOffset = Quaternion.Inverse(asset.transform.rotation) * (((Component)modifier).transform.position - asset.transform.position); levelOffset = modifier.m_levelOffset; Debug.Log((object)("[HoeCam] Native baseline carrier: " + text + " (vanilla LocationProxy; no building objects spawned).")); return; } finally { val.m_prefab.Release(); } } } throw new InvalidOperationException("No compatible vanilla terrain carrier — check HoeCam log"); } private static bool IsPureProxy(GameObject prefab, out TerrainModifier modifier) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) modifier = null; if (!Object.op_Implicit((Object)(object)prefab) || prefab.transform.localScale != Vector3.one) { return false; } Component[] componentsInChildren = prefab.GetComponentsInChildren<Component>(true); foreach (Component val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val)) { return false; } if (Object.op_Implicit((Object)(object)val.GetComponentInParent<ZNetView>(true)) || val is Transform) { continue; } Location val2 = (Location)(object)((val is Location) ? val : null); if (Object.op_Implicit((Object)(object)val2)) { if ((Object)(object)((Component)val2).gameObject != (Object)(object)prefab || val2.m_hasInterior || Object.op_Implicit((Object)(object)val2.m_generator) || Object.op_Implicit((Object)(object)val2.m_interiorPrefab)) { return false; } continue; } TerrainModifier val3 = (TerrainModifier)(object)((val is TerrainModifier) ? val : null); if (Object.op_Implicit((Object)(object)val3)) { if (Object.op_Implicit((Object)(object)modifier) || !((Behaviour)val3).enabled || val3.m_playerModifiction || val3.m_useTerrainCompiler) { return false; } Transform val4 = ((Component)val3).transform; while ((Object)(object)val4 != (Object)(object)prefab.transform) { if (!((Component)val4).gameObject.activeSelf) { return false; } val4 = val4.parent; } modifier = val3; continue; } return false; } return (Object)(object)modifier != (Object)null; } private static ZNetView Create(Vector3 point, int sortOrder) { //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_0006: 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_0015: 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_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0297: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = point - modifierOffset - Vector3.up * levelOffset; GameObject val2 = null; State state = Random.state; try { val2 = Object.Instantiate<GameObject>(ZoneSystem.instance.m_locationProxyPrefab, val, Quaternion.identity); ZNetView component = val2.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { throw new InvalidOperationException("Cannot create native terrain baseline"); } ZDO zDO = component.GetZDO(); if (!zDO.Persistent) { throw new InvalidOperationException("Native terrain carrier is not persistent"); } zDO.Set("HoeCam.NativeBaseline.v1", true); zDO.Set("HasFields", true); zDO.Set("HasFieldsTerrainModifier", true); zDO.Set("TerrainModifier.m_level", true); zDO.Set("TerrainModifier.m_square", true); zDO.Set("TerrainModifier.m_sortOrder", sortOrder); zDO.Set("TerrainModifier.m_levelRadius", -0.001f); zDO.Set("TerrainModifier.m_smoothRadius", -1000f); zDO.Set("TerrainModifier.m_paintRadius", -1000f); zDO.Set("HasFieldsLocation", true); zDO.Set("Location.m_exteriorRadius", -1000000f); zDO.Set("Location.m_interiorRadius", -1000000f); zDO.Set("Location.m_noBuildRadiusOverride", -1000000f); LocationProxy component2 = val2.GetComponent<LocationProxy>(); if (!Object.op_Implicit((Object)(object)component2)) { throw new InvalidOperationException("Vanilla location proxy unavailable"); } component2.SetLocation(locationName, 1, true); component.LoadFields(); TerrainModifier[] componentsInChildren = val2.GetComponentsInChildren<TerrainModifier>(); if (componentsInChildren.Length != 1 || componentsInChildren[0].m_playerModifiction || componentsInChildren[0].m_levelRadius != -0.001f || !componentsInChildren[0].m_square || !componentsInChildren[0].m_level) { throw new InvalidOperationException("Native terrain carrier failed initialization"); } Renderer[] componentsInChildren2 = val2.GetComponentsInChildren<Renderer>(); for (int i = 0; i < componentsInChildren2.Length; i++) { if (componentsInChildren2[i].enabled) { throw new InvalidOperationException("Native terrain carrier contains visible geometry"); } } Collider[] componentsInChildren3 = val2.GetComponentsInChildren<Collider>(); for (int i = 0; i < componentsInChildren3.Length; i++) { if (componentsInChildren3[i].enabled) { throw new InvalidOperationException("Native terrain carrier contains collision geometry"); } } Vector3 val3 = ((Component)componentsInChildren[0]).transform.position + Vector3.up * componentsInChildren[0].m_levelOffset - point; if (((Vector3)(ref val