using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Lamb.UI; using MMTools; using Microsoft.CodeAnalysis; using Spine; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Follower Drag")] [assembly: AssemblyDescription("Standalone Cult of the Lamb direct follower drag prototype.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FollowerDrag")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("87a3c5bd-34f9-4f86-b2f4-792c7e1fdc53")] [assembly: AssemblyFileVersion("0.4.0.0")] [assembly: AssemblyVersion("0.4.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FollowerDrag { [BepInPlugin("com.cotl.followerdrag", "Follower Drag", "0.5.4")] public sealed class FollowerDragPlugin : BaseUnityPlugin { public const string PluginGuid = "com.cotl.followerdrag"; public const string PluginName = "Follower Drag"; public const string PluginVersion = "0.5.4"; private FollowerDragController _controller; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; FollowerDragConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.cotl.followerdrag"); _harmony.PatchAll(typeof(FollowerDragPlugin).Assembly); _controller = ((Component)this).gameObject.AddComponent(); FollowerDragController.Instance = _controller; Log.LogInfo((object)"Follower Drag 0.5.4 loaded."); } private void OnDestroy() { if ((Object)(object)_controller != (Object)null) { _controller.CancelCurrentDrag(); FollowerDragController.Instance = null; _controller = null; } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; } } [HarmonyPatch(typeof(Interactor), "Update")] internal static class InteractorUpdatePatch { private static bool Prefix(Interactor __instance) { FollowerDragController instance = FollowerDragController.Instance; if (!((Object)(object)instance == (Object)null)) { return !instance.ShouldSuppressVanillaInteraction(__instance); } return true; } } internal static class FollowerDragConfig { internal static ConfigEntry Enabled; internal static ConfigEntry MouseButton; internal static ConfigEntry HitRadius; internal static ConfigEntry GridSnapRange; internal static ConfigEntry MarkerSize; internal static ConfigEntry AssignWorkOnDrop; internal static ConfigEntry WorkSearchRadius; internal static ConfigEntry SkipProtectedFollowers; internal static ConfigEntry ShowPrompt; internal static ConfigEntry CarryAnimation; internal static ConfigEntry CarryBobHeight; internal static ConfigEntry CarryBobSpeed; internal static ConfigEntry UseGauntletCursor; internal static ConfigEntry CursorMaxSize; internal static ConfigEntry DebugLogging; internal static void Bind(ConfigFile config) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown Enabled = config.Bind("General", "Enabled", true, "Enable direct mouse follower dragging."); MouseButton = config.Bind("Input", "MouseButton", 0, new ConfigDescription("Mouse button used to grab and drag. 0 is left, 1 is right, 2 is middle.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 2), Array.Empty())); HitRadius = config.Bind("Input", "HitRadius", 0.75f, new ConfigDescription("Fallback follower hit radius when the follower collider is not directly hit.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1.5f), Array.Empty())); GridSnapRange = config.Bind("Placement", "GridSnapRange", 1f, new ConfigDescription("Maximum distance from the cursor to the nearest plot grid tile.", (AcceptableValueBase)(object)new AcceptableValueRange(0.4f, 2.5f), Array.Empty())); MarkerSize = config.Bind("Placement", "MarkerSize", 0.72f, new ConfigDescription("Size of the drag placement marker.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 1.5f), Array.Empty())); AssignWorkOnDrop = config.Bind("Work assignment", "AssignWorkOnDrop", true, "After a successful drop, send the follower to the nearest valid tree, waste pile, farm plot, rubble node, or unfinished build site near the release point."); WorkSearchRadius = config.Bind("Work assignment", "WorkSearchRadius", 2.5f, new ConfigDescription("Maximum distance from the release point to look for a work target.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 6f), Array.Empty())); SkipProtectedFollowers = config.Bind("Safety", "SkipProtectedFollowers", true, "Skip followers the game marks as explicitly locked or protected. Ordinary interaction tasks can still be interrupted by a drag."); ShowPrompt = config.Bind("UI", "ShowPrompt", true, "Show the small drag instruction panel while a follower is held."); CarryAnimation = config.Bind("Held follower", "CarryAnimation", "Medic/carried-run", "Follower body animation used while the Crown is holding a follower."); CarryBobHeight = config.Bind("Held follower", "CarryBobHeight", 0.12f, new ConfigDescription("Additional vertical bob applied to the follower while held.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.4f), Array.Empty())); CarryBobSpeed = config.Bind("Held follower", "CarryBobSpeed", 5.5f, new ConfigDescription("Speed of the held follower's floating bob.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 15f), Array.Empty())); UseGauntletCursor = config.Bind("Cursor", "UseGauntletCursor", true, "Show the game's gauntlet artwork when hovering over or holding a follower."); CursorMaxSize = config.Bind("Cursor", "CursorMaxSize", 72, new ConfigDescription("Maximum pixel size of the gauntlet cursor artwork.", (AcceptableValueBase)(object)new AcceptableValueRange(24, 128), Array.Empty())); DebugLogging = config.Bind("Debug", "DebugLogging", false, "Write follower drag state changes to the BepInEx log."); } } internal sealed class FollowerDragController : MonoBehaviour { private enum WorkKind { None, Tree, Waste, Farm, Rubble, BuildSite, BuildProject } private sealed class WorkCandidate { internal WorkKind Kind; internal int StructureId; internal Vector3 Position; internal float Distance; internal FollowerTask CreateTask() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Invalid comparison between Unknown and I4 switch (Kind) { case WorkKind.Tree: { Structures_Tree structureByID2 = StructureManager.GetStructureByID(StructureId); if (structureByID2 == null || structureByID2.TreeChopped || ((StructureBrain)structureByID2).Data == null || ((StructureBrain)structureByID2).Data.IsSapling) { return null; } return (FollowerTask)(object)new PersistentChopTreesTask(StructureId); } case WorkKind.Waste: { Structures_Waste structureByID4 = StructureManager.GetStructureByID(StructureId); if (structureByID4 == null || ((StructureBrain)structureByID4).Data == null || structureByID4.ProgressFinished || (int)((StructureBrain)structureByID4).Data.Type == 414) { return null; } return (FollowerTask)(object)new PersistentCleanWasteTask(StructureId); } case WorkKind.Farm: { Structures_FarmerStation structureByID6 = StructureManager.GetStructureByID(StructureId); if (structureByID6 == null || ((StructureBrain)structureByID6).Data == null) { return null; } return (FollowerTask)(object)new PersistentFarmTask(StructureId); } case WorkKind.Rubble: { Structures_Rubble structureByID3 = StructureManager.GetStructureByID(StructureId); if (structureByID3 == null || structureByID3.ProgressFinished || structureByID3.AvailableSlotCount <= 0) { return null; } return (FollowerTask)(object)new PersistentClearRubbleTask(StructureId); } case WorkKind.BuildSite: { Structures_BuildSite structureByID5 = StructureManager.GetStructureByID(StructureId); if (structureByID5 == null || structureByID5.ProgressFinished || structureByID5.IsObstructed) { return null; } return (FollowerTask)(object)new PersistentBuildTask(StructureId); } case WorkKind.BuildProject: { Structures_BuildSiteProject structureByID = StructureManager.GetStructureByID(StructureId); if (structureByID == null || structureByID.ProgressFinished) { return null; } return (FollowerTask)(object)new PersistentBuildProjectTask(StructureId); } default: return null; } } } private sealed class PersistentChopTreesTask : FollowerTask_ChopTrees { private const float ProgressWatchdogSeconds = 1.5f; private const float MinimumHitInterval = 0.12f; private readonly int _targetTreeId; private bool _sharedClaimed; private bool _finishing; private bool _progressInitialized; private float _lastObservedProgress; private float _lastProgressChangeTime; private float _lastHitTime = -999f; public override bool BlockTaskChanges => true; internal PersistentChopTreesTask(int treeId) : base(treeId) { _targetTreeId = treeId; } public override void ClaimReservations() { ((FollowerTask_ChopTrees)this).ClaimReservations(); ClaimSharedTree(); } public override void ReleaseReservations() { ((FollowerTask_ChopTrees)this).ReleaseReservations(); ReleaseSharedTree(); } protected override void OnStart() { Structures_Tree structureByID = StructureManager.GetStructureByID(_targetTreeId); if (structureByID == null || ((StructureBrain)structureByID).Data == null || structureByID.TreeChopped || ((StructureBrain)structureByID).Data.IsSapling) { FinishAssignedTree(); return; } ClaimSharedTree(); ((StructureBrain)structureByID).ReservedForTask = true; ObserveTreeProgress(structureByID); ((FollowerTask)this).ClearDestination(); ((FollowerTask)this).SetState((FollowerTaskState)3); } public override void OnDoingBegin(Follower follower) { ((FollowerTask_ChopTrees)this).OnDoingBegin(follower); ObserveTreeProgress(GetTargetTree()); } protected override void TaskTick(float deltaGameTime) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)((FollowerTask)this).State != 4) { return; } Structures_Tree targetTree = GetTargetTree(); if (targetTree == null || ((StructureBrain)targetTree).Data == null || targetTree.TreeChopped) { FinishAssignedTree(); return; } if (!_progressInitialized) { ObserveTreeProgress(targetTree); } else if (!Mathf.Approximately(((StructureBrain)targetTree).Data.Progress, _lastObservedProgress)) { ObserveTreeProgress(targetTree); } if (Time.unscaledTime - _lastProgressChangeTime >= 1.5f) { ((FollowerTask)this).ProgressTask(); } } public override void ProgressTask() { if (_finishing || Time.unscaledTime - _lastHitTime < 0.12f) { return; } Structures_Tree targetTree = GetTargetTree(); if (targetTree == null || ((StructureBrain)targetTree).Data == null || targetTree.TreeChopped) { FinishAssignedTree(); return; } _lastHitTime = Time.unscaledTime; float progress = ((StructureBrain)targetTree).Data.Progress; targetTree.TreeHit(0.075f * ((FollowerTask)this).Brain.Info.ProductivityMultiplier, true, ((FollowerTask)this).Brain.Info.ID); ((FollowerTask)this).Brain.GetXP(0.1f); ObserveTreeProgress(targetTree); if (Mathf.Approximately(progress, ((StructureBrain)targetTree).Data.Progress)) { _lastProgressChangeTime = Time.unscaledTime; } if (targetTree.TreeChopped) { FinishAssignedTree(); } } private Structures_Tree GetTargetTree() { return StructureManager.GetStructureByID(_targetTreeId); } private void ObserveTreeProgress(Structures_Tree tree) { if (tree != null && ((StructureBrain)tree).Data != null) { _progressInitialized = true; _lastObservedProgress = ((StructureBrain)tree).Data.Progress; _lastProgressChangeTime = Time.unscaledTime; } } private void FinishAssignedTree() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if (!_finishing) { _finishing = true; if ((int)((FollowerTask)this).State != 5 && (int)((FollowerTask)this).State != 6) { ((FollowerTask)this).End(); } } } private void ClaimSharedTree() { if (!_sharedClaimed) { SharedTreeClaims.TryGetValue(_targetTreeId, out var value); SharedTreeClaims[_targetTreeId] = value + 1; _sharedClaimed = true; } } private void ReleaseSharedTree() { if (!_sharedClaimed) { return; } if (SharedTreeClaims.TryGetValue(_targetTreeId, out var value)) { value--; if (value <= 0) { SharedTreeClaims.Remove(_targetTreeId); } else { SharedTreeClaims[_targetTreeId] = value; Structures_Tree structureByID = StructureManager.GetStructureByID(_targetTreeId); if (structureByID != null) { ((StructureBrain)structureByID).ReservedForTask = true; } } } _sharedClaimed = false; } } private sealed class PersistentCleanWasteTask : FollowerTask_CleanWaste { private readonly int _targetWasteId; private bool _sharedClaimed; public override bool BlockTaskChanges => true; internal PersistentCleanWasteTask(int wasteId) : base(wasteId) { _targetWasteId = wasteId; } public override void ClaimReservations() { ((FollowerTask_CleanWaste)this).ClaimReservations(); ClaimSharedWaste(); } public override void ReleaseReservations() { ((FollowerTask_CleanWaste)this).ReleaseReservations(); ReleaseSharedWaste(); } public override void ProgressTask() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 Structures_Waste structureByID = StructureManager.GetStructureByID(_targetWasteId); if (structureByID == null || structureByID.ProgressFinished) { if ((int)((FollowerTask)this).State != 5 && (int)((FollowerTask)this).State != 6) { ((FollowerTask)this).End(); } return; } ((FollowerTask_CleanWaste)this).ProgressTask(); structureByID = StructureManager.GetStructureByID(_targetWasteId); if ((structureByID == null || structureByID.ProgressFinished) && (int)((FollowerTask)this).State != 5 && (int)((FollowerTask)this).State != 6) { ((FollowerTask)this).End(); } } private void ClaimSharedWaste() { if (!_sharedClaimed) { SharedWasteClaims.TryGetValue(_targetWasteId, out var value); SharedWasteClaims[_targetWasteId] = value + 1; _sharedClaimed = true; } } private void ReleaseSharedWaste() { if (!_sharedClaimed) { return; } if (SharedWasteClaims.TryGetValue(_targetWasteId, out var value)) { value--; if (value <= 0) { SharedWasteClaims.Remove(_targetWasteId); } else { SharedWasteClaims[_targetWasteId] = value; Structures_Waste structureByID = StructureManager.GetStructureByID(_targetWasteId); if (structureByID != null) { ((StructureBrain)structureByID).ReservedForTask = true; } } } _sharedClaimed = false; } } private sealed class PersistentFarmTask : FollowerTask_Farm { private readonly int _stationId; private bool _sharedClaimed; public override bool BlockTaskChanges => true; internal PersistentFarmTask(int stationId) : base(stationId) { _stationId = stationId; } public override void ClaimReservations() { ((FollowerTask_Farm)this).ClaimReservations(); ClaimSharedStation(); } public override void ReleaseReservations() { ((FollowerTask_Farm)this).ReleaseReservations(); ReleaseSharedStation(); } private void ClaimSharedStation() { if (!_sharedClaimed) { SharedFarmStationClaims.TryGetValue(_stationId, out var value); SharedFarmStationClaims[_stationId] = value + 1; _sharedClaimed = true; } } private void ReleaseSharedStation() { if (!_sharedClaimed) { return; } if (SharedFarmStationClaims.TryGetValue(_stationId, out var value)) { value--; if (value <= 0) { SharedFarmStationClaims.Remove(_stationId); } else { SharedFarmStationClaims[_stationId] = value; Structures_FarmerStation structureByID = StructureManager.GetStructureByID(_stationId); if (structureByID != null) { ((StructureBrain)structureByID).ReservedForTask = true; } } } _sharedClaimed = false; } } private sealed class PersistentClearRubbleTask : FollowerTask_ClearRubble { public override bool BlockTaskChanges => true; internal PersistentClearRubbleTask(int rubbleId) : base(rubbleId) { } } private sealed class PersistentBuildTask : FollowerTask_Build { public override bool BlockTaskChanges => true; internal PersistentBuildTask(int buildSiteId) : base(buildSiteId) { } } private sealed class PersistentBuildProjectTask : FollowerTask_BuildProject { public override bool BlockTaskChanges => true; internal PersistentBuildProjectTask(int buildProjectId) : base(buildProjectId) { } } private enum CursorVisual { Default, Hover, Held } internal static FollowerDragController Instance; private Follower _draggedFollower; private Vector3 _originalPosition; private Vector3 _lastValidPosition; private TileGridTile _targetTile; private bool _targetIsValid; private LineRenderer _targetMarker; private Material _markerMaterial; private Texture2D _panelTexture; private GUIStyle _panelStyle; private GUIStyle _labelStyle; private Vector3 _grabOffset; private Transform _floatingSpineTransform; private Vector3 _originalSpineLocalPosition; private Quaternion _originalSpineLocalRotation; private Vector3 _originalSpineLocalScale; private string _heldBodyAnimation; private float _heldAnimationStartedAt; private float _nextHeldAnimationCheck; private bool _heldIconsHidden; private CursorVisual _cursorVisual; private Texture2D _openCursorTexture; private Texture2D _heldCursorTexture; private Sprite _openCursorSource; private Sprite _heldCursorSource; private float _nextCursorAssetAttempt; private Vector3 _lastCursorWorld; private static readonly Dictionary SharedTreeClaims = new Dictionary(); private static readonly Dictionary SharedWasteClaims = new Dictionary(); private static readonly Dictionary SharedFarmStationClaims = new Dictionary(); internal void CancelCurrentDrag() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_draggedFollower != (Object)null) { EndDrag(_draggedFollower, _originalPosition, placed: false, null); } else { DestroyVisuals(); } SetCursorVisual(CursorVisual.Default); } private void Update() { if ((Object)(object)_draggedFollower != (Object)null) { if (!CanUseDragInput() || Input.GetKeyDown((KeyCode)27)) { CancelCurrentDrag(); } else if (!Input.GetMouseButton(Mathf.Clamp(FollowerDragConfig.MouseButton.Value, 0, 2))) { FinishDrag(); } else { UpdateDragTarget(); } } else if (!CanUseDragInput()) { SetCursorVisual(CursorVisual.Default); } else { UpdateHoverCursor(); if (Input.GetMouseButtonDown(Mathf.Clamp(FollowerDragConfig.MouseButton.Value, 0, 2))) { TryBeginDrag(); } } } private void LateUpdate() { if (_cursorVisual != CursorVisual.Default) { ApplyCursorVisual(); } } private void UpdateHoverCursor() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!TryGetCursorWorld(out var world)) { SetCursorVisual(CursorVisual.Default); return; } Follower val = FindFollowerUnderCursor(world, useFallback: false); SetCursorVisual(((Object)(object)val != (Object)null) ? CursorVisual.Hover : CursorVisual.Default); } private void BeginFloatingVisual(Follower follower) { //IL_0008: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) _floatingSpineTransform = null; _originalSpineLocalPosition = Vector3.zero; _originalSpineLocalRotation = Quaternion.identity; _originalSpineLocalScale = Vector3.one; _heldBodyAnimation = null; _heldAnimationStartedAt = Time.unscaledTime; _nextHeldAnimationCheck = 0f; _heldIconsHidden = false; if ((Object)(object)follower == (Object)null || (Object)(object)follower.Spine == (Object)null) { return; } _floatingSpineTransform = ((Component)follower.Spine).transform; _originalSpineLocalPosition = _floatingSpineTransform.localPosition; _originalSpineLocalRotation = _floatingSpineTransform.localRotation; _originalSpineLocalScale = _floatingSpineTransform.localScale; try { string text = FollowerDragConfig.CarryAnimation.Value; if (string.IsNullOrEmpty(text)) { text = "Medic/carried-run"; } follower.State.CURRENT_STATE = (State)49; follower.HideAllFollowerIcons(); _heldIconsHidden = true; _heldBodyAnimation = text; if (text == "Medic/carried-run") { SetDirectBodyAnimation(follower, "Medic/carried-start", loop: false); AddDirectBodyAnimation(follower, "Medic/carried-run", loop: true, 0f); } else if (!string.IsNullOrEmpty(text)) { SetDirectBodyAnimation(follower, text, loop: true); } } catch (Exception ex) { DebugLog("The carry animation could not be applied: " + ex.Message); ApplyPossessedFallback(follower); } } private void UpdateFloatingVisual() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_floatingSpineTransform == (Object)null) && !((Object)(object)_draggedFollower == (Object)null)) { MaintainHeldAnimation(_draggedFollower); Vector3 originalSpineLocalPosition = _originalSpineLocalPosition; float value = FollowerDragConfig.CarryBobHeight.Value; float value2 = FollowerDragConfig.CarryBobSpeed.Value; originalSpineLocalPosition.y += value + Mathf.Sin(Time.unscaledTime * value2) * value * 0.35f; _floatingSpineTransform.localPosition = originalSpineLocalPosition; float num = Mathf.Sin(Time.unscaledTime * value2 * 0.72f) * 9f; _floatingSpineTransform.localRotation = _originalSpineLocalRotation * Quaternion.Euler(0f, 0f, num); _floatingSpineTransform.localScale = Vector3.Scale(_originalSpineLocalScale, new Vector3(1.03f, 0.94f, 1f)); } } private void MaintainHeldAnimation(Follower follower) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 if ((Object)(object)follower == (Object)null || (Object)(object)follower.Spine == (Object)null || follower.Spine.AnimationState == null) { return; } try { if ((int)follower.State.CURRENT_STATE != 49) { follower.State.CURRENT_STATE = (State)49; } if (!(Time.unscaledTime < _nextHeldAnimationCheck)) { _nextHeldAnimationCheck = Time.unscaledTime + 0.2f; string currentBodyAnimation = GetCurrentBodyAnimation(follower); if (_heldBodyAnimation == "Medic/carried-run" && Time.unscaledTime - _heldAnimationStartedAt > 0.65f && currentBodyAnimation != "Medic/carried-run") { DebugLog("Native carry track was replaced; using the direct possessed animation fallback."); ApplyPossessedFallback(follower); } else if (_heldBodyAnimation != "Medic/carried-run" && !string.IsNullOrEmpty(_heldBodyAnimation) && currentBodyAnimation != _heldBodyAnimation) { SetDirectBodyAnimation(follower, _heldBodyAnimation, loop: true); } } } catch (Exception ex) { DebugLog("Held animation maintenance failed: " + ex.Message); ApplyPossessedFallback(follower); } } private string GetCurrentBodyAnimation(Follower follower) { TrackEntry current = follower.Spine.AnimationState.GetCurrent(1); if (current == null || current.Animation == null) { return null; } return current.Animation.Name; } private void SetDirectBodyAnimation(Follower follower, string animation, bool loop) { follower.Spine.AnimationState.SetAnimation(1, animation, loop); } private void AddDirectBodyAnimation(Follower follower, string animation, bool loop, float delay) { follower.Spine.AnimationState.AddAnimation(1, animation, loop, delay); } private void ApplyPossessedFallback(Follower follower) { if (!((Object)(object)follower == (Object)null) && !((Object)(object)follower.Spine == (Object)null) && follower.Spine.AnimationState != null) { follower.State.CURRENT_STATE = (State)49; _heldBodyAnimation = "Sin/sin-floating"; _nextHeldAnimationCheck = Time.unscaledTime + 0.2f; SetDirectBodyAnimation(follower, "Sin/sin-floating", loop: true); } } private void EndFloatingVisual(Follower follower) { //IL_0015: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_floatingSpineTransform != (Object)null) { _floatingSpineTransform.localPosition = _originalSpineLocalPosition; _floatingSpineTransform.localRotation = _originalSpineLocalRotation; _floatingSpineTransform.localScale = _originalSpineLocalScale; } if (_heldIconsHidden && (Object)(object)follower != (Object)null) { try { follower.ShowAllFollowerIcons(true); } catch (Exception ex) { DebugLog("Follower icons could not be restored: " + ex.Message); } } _floatingSpineTransform = null; _originalSpineLocalPosition = Vector3.zero; _originalSpineLocalRotation = Quaternion.identity; _originalSpineLocalScale = Vector3.one; _heldBodyAnimation = null; _heldAnimationStartedAt = 0f; _nextHeldAnimationCheck = 0f; _heldIconsHidden = false; } private void SetCursorVisual(CursorVisual visual) { if (visual == CursorVisual.Default || !FollowerDragConfig.UseGauntletCursor.Value) { if (_cursorVisual != CursorVisual.Default) { RestoreVanillaCursor(); } _cursorVisual = CursorVisual.Default; return; } EnsureCursorAssets(); if ((Object)(object)((visual == CursorVisual.Held) ? _heldCursorTexture : _openCursorTexture) == (Object)null) { _cursorVisual = CursorVisual.Default; return; } _cursorVisual = visual; ApplyCursorVisual(); } private void ApplyCursorVisual() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) Texture2D val = ((_cursorVisual == CursorVisual.Held) ? _heldCursorTexture : _openCursorTexture); if (!((Object)(object)val == (Object)null)) { Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((float)((Texture)val).width * 0.18f, (float)((Texture)val).height * 0.18f); Cursor.SetCursor(val, val2, (CursorMode)0); } } private void EnsureCursorAssets() { if (!FollowerDragConfig.UseGauntletCursor.Value || Time.unscaledTime < _nextCursorAssetAttempt) { return; } _nextCursorAssetAttempt = Time.unscaledTime + 1f; try { WeaponData weaponData = EquipmentManager.GetWeaponData((EquipmentType)400); WeaponData weaponData2 = EquipmentManager.GetWeaponData((EquipmentType)407); Sprite val = (((Object)(object)weaponData != (Object)null) ? ((EquipmentData)weaponData).UISprite : null); if ((Object)(object)val == (Object)null && (Object)(object)weaponData2 != (Object)null) { val = ((EquipmentData)weaponData2).UISprite; } Sprite val2 = (((Object)(object)weaponData != (Object)null) ? ((EquipmentData)weaponData).WorldSprite : null); if ((Object)(object)val2 == (Object)null && (Object)(object)weaponData2 != (Object)null) { val2 = (((Object)(object)((EquipmentData)weaponData2).WorldSprite != (Object)null) ? ((EquipmentData)weaponData2).WorldSprite : ((EquipmentData)weaponData2).UISprite); } if ((Object)(object)val2 == (Object)null) { val2 = val; } if ((Object)(object)val != (Object)(object)_openCursorSource) { DestroyCursorTexture(ref _openCursorTexture); _openCursorSource = val; _openCursorTexture = CreateCursorTexture(val); } if ((Object)(object)val2 != (Object)(object)_heldCursorSource) { DestroyCursorTexture(ref _heldCursorTexture); _heldCursorSource = val2; _heldCursorTexture = CreateCursorTexture(val2); } } catch (Exception ex) { DebugLog("Gauntlet cursor artwork is not ready: " + ex.Message); } } private Texture2D CreateCursorTexture(Sprite source) { //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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || (Object)(object)source.texture == (Object)null) { return null; } Rect textureRect = source.textureRect; int num = Mathf.Clamp(Mathf.RoundToInt(((Rect)(ref textureRect)).x), 0, ((Texture)source.texture).width - 1); int num2 = Mathf.Clamp(Mathf.RoundToInt(((Rect)(ref textureRect)).y), 0, ((Texture)source.texture).height - 1); int num3 = Mathf.Clamp(Mathf.RoundToInt(((Rect)(ref textureRect)).width), 1, ((Texture)source.texture).width - num); int num4 = Mathf.Clamp(Mathf.RoundToInt(((Rect)(ref textureRect)).height), 1, ((Texture)source.texture).height - num2); RenderTexture val = new RenderTexture(((Texture)source.texture).width, ((Texture)source.texture).height, 0, (RenderTextureFormat)0); ((Texture)val).filterMode = (FilterMode)1; RenderTexture active = RenderTexture.active; Texture2D val2 = null; try { Graphics.Blit((Texture)(object)source.texture, val); RenderTexture.active = val; val2 = new Texture2D(num3, num4, (TextureFormat)4, false, false); val2.ReadPixels(new Rect((float)num, (float)num2, (float)num3, (float)num4), 0, 0, false); val2.Apply(false, false); } finally { RenderTexture.active = active; val.Release(); Object.Destroy((Object)(object)val); } if ((Object)(object)val2 == (Object)null) { return null; } ((Texture)val2).filterMode = (FilterMode)1; ((Texture)val2).wrapMode = (TextureWrapMode)1; return ResizeCursorTexture(val2); } private Texture2D ResizeCursorTexture(Texture2D source) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp(FollowerDragConfig.CursorMaxSize.Value, 24, 128); if (((Texture)source).width <= num && ((Texture)source).height <= num) { return source; } float num2 = Mathf.Min((float)num / (float)((Texture)source).width, (float)num / (float)((Texture)source).height); int num3 = Mathf.Max(1, Mathf.RoundToInt((float)((Texture)source).width * num2)); int num4 = Mathf.Max(1, Mathf.RoundToInt((float)((Texture)source).height * num2)); RenderTexture val = new RenderTexture(num3, num4, 0, (RenderTextureFormat)0); ((Texture)val).filterMode = (FilterMode)1; RenderTexture active = RenderTexture.active; Texture2D val2 = null; try { Graphics.Blit((Texture)(object)source, val); RenderTexture.active = val; val2 = new Texture2D(num3, num4, (TextureFormat)4, false, false); val2.ReadPixels(new Rect(0f, 0f, (float)num3, (float)num4), 0, 0, false); val2.Apply(false, false); } finally { RenderTexture.active = active; val.Release(); Object.Destroy((Object)(object)val); } if ((Object)(object)val2 != (Object)null) { ((Texture)val2).filterMode = (FilterMode)1; ((Texture)val2).wrapMode = (TextureWrapMode)1; Object.Destroy((Object)(object)source); return val2; } return source; } private void DestroyCursorTexture(ref Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); texture = null; } } private void DestroyCursorAssets() { DestroyCursorTexture(ref _openCursorTexture); DestroyCursorTexture(ref _heldCursorTexture); _openCursorSource = null; _heldCursorSource = null; } private void RestoreVanillaCursor() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) try { UIManager instance = MonoSingleton.Instance; if ((Object)(object)instance != (Object)null) { int currentCursor = instance.currentCursor; int currentCursor2 = ((currentCursor == 0) ? 1 : 0); instance.SetCurrentCursor(currentCursor2); instance.SetCurrentCursor(currentCursor); return; } } catch (Exception ex) { DebugLog("The vanilla cursor could not be refreshed: " + ex.Message); } Cursor.SetCursor((Texture2D)null, Vector2.zero, (CursorMode)0); } private bool CanUseDragInput() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 if (!FollowerDragConfig.Enabled.Value || (Object)(object)PlayerFarming.Instance == (Object)null) { return false; } if ((int)PlayerFarming.Location != 1 || Time.timeScale <= 0f || SimulationManager.IsPaused) { return false; } if (LetterBox.IsPlaying || MMConversation.isPlaying || (Object)(object)PlacementObject.Instance != (Object)null) { return false; } return true; } private void TryBeginDrag() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) if (!TryGetCursorWorld(out var world)) { return; } Follower val = FindFollowerUnderCursor(world, useFallback: true); if ((Object)(object)val == (Object)null || !IsSelectable(val)) { return; } PlacementRegion instance = PlacementRegion.Instance; if ((Object)(object)instance == (Object)null || instance.Grid == null || instance.Grid.Count == 0) { DebugLog("Follower drag ignored because the base plot grid is unavailable."); return; } _draggedFollower = val; _originalPosition = ((Component)val).transform.position; _lastValidPosition = _originalPosition; _grabOffset = _originalPosition - world; _grabOffset.z = 0f; _targetTile = null; _targetIsValid = false; _lastCursorWorld = world; try { ClearPrimaryVanillaInteraction(); val.PickUp(); val.ClearPath(); val.Brain.LastPosition = ((Component)val).transform.position; BeginFloatingVisual(val); CreateVisuals(); SetCursorVisual(CursorVisual.Held); UpdateDragTarget(); DebugLog("Grabbed follower " + val.Brain.Info.ID + "."); } catch (Exception ex) { FollowerDragPlugin.Log.LogError((object)("Follower drag could not start: " + ex)); EndDrag(val, _originalPosition, placed: false, null); } } internal bool ShouldSuppressVanillaInteraction(Interactor interactor) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)interactor == (Object)null || (Object)(object)PlayerFarming.Instance == (Object)null || (Object)(object)interactor != (Object)(object)PlayerFarming.Instance.interactor) { return false; } if ((Object)(object)_draggedFollower != (Object)null) { return true; } if (!CanUseDragInput()) { return false; } if (!Input.GetMouseButtonDown(Mathf.Clamp(FollowerDragConfig.MouseButton.Value, 0, 2))) { return false; } if (!TryGetCursorWorld(out var world)) { return false; } Follower val = FindFollowerUnderCursor(world, useFallback: true); if ((Object)(object)val != (Object)null) { return IsSelectable(val); } return false; } private void ClearPrimaryVanillaInteraction() { PlayerFarming instance = PlayerFarming.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.interactor == (Object)null)) { Interactor interactor = instance.interactor; Interaction currentInteraction = interactor.CurrentInteraction; Interaction previousInteraction = interactor.PreviousInteraction; if ((Object)(object)currentInteraction != (Object)null) { currentInteraction.OnBecomeNotCurrent(instance); } if ((Object)(object)previousInteraction != (Object)null && (Object)(object)previousInteraction != (Object)(object)currentInteraction) { previousInteraction.OnBecomeNotCurrent(instance); } interactor.CurrentInteraction = null; interactor.PreviousInteraction = null; interactor.TempInteraction = null; if ((Object)(object)interactor.indicator != (Object)null) { interactor.HideIndicator(); } } } private Follower FindFollowerUnderCursor(Vector3 cursorWorld, bool useFallback) { //IL_0010: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) Follower val = null; float num = float.MaxValue; Follower val2 = null; float num2 = float.MaxValue; Collider2D[] array = Physics2D.OverlapPointAll(Vector2.op_Implicit(cursorWorld)); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] == (Object)null) { continue; } Follower componentInParent = ((Component)array[i]).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && IsInBase(componentInParent)) { if (TryGetFollowerVisualHit(componentInParent, cursorWorld, out var distance) && distance < num) { val = componentInParent; num = distance; } float num3 = Vector2.Distance(Vector2.op_Implicit(cursorWorld), Vector2.op_Implicit(((Component)componentInParent).transform.position)); if (num3 < num2) { val2 = componentInParent; num2 = num3; } } } if ((Object)(object)val != (Object)null) { return val; } if (Follower.Followers == null) { if (!((Object)(object)val2 != (Object)null) || HasFollowerVisual(val2)) { return null; } return val2; } for (int j = 0; j < Follower.Followers.Count; j++) { Follower val3 = Follower.Followers[j]; if (!((Object)(object)val3 == (Object)null) && IsInBase(val3) && TryGetFollowerVisualHit(val3, cursorWorld, out var distance2) && distance2 < num) { val = val3; num = distance2; } } if ((Object)(object)val != (Object)null) { return val; } if ((Object)(object)val2 != (Object)null && !HasFollowerVisual(val2)) { return val2; } if (!useFallback) { return null; } float value = FollowerDragConfig.HitRadius.Value; Follower result = null; float num4 = float.MaxValue; for (int k = 0; k < Follower.Followers.Count; k++) { Follower val4 = Follower.Followers[k]; if (!((Object)(object)val4 == (Object)null) && IsInBase(val4) && !HasFollowerVisual(val4)) { float num5 = Vector2.Distance(Vector2.op_Implicit(cursorWorld), Vector2.op_Implicit(((Component)val4).transform.position)); if (num5 <= value && num5 < num4) { result = val4; num4 = num5; } } } return result; } private bool TryGetFollowerVisualHit(Follower follower, Vector3 cursorWorld, out float distance) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_006a: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) distance = float.MaxValue; if (!TryGetFollowerVisualBounds(follower, out var bounds)) { return false; } if (cursorWorld.x < ((Bounds)(ref bounds)).min.x - 0.12f || cursorWorld.x > ((Bounds)(ref bounds)).max.x + 0.12f || cursorWorld.y < ((Bounds)(ref bounds)).min.y - 0.12f || cursorWorld.y > ((Bounds)(ref bounds)).max.y + 0.12f) { return false; } distance = Vector2.Distance(Vector2.op_Implicit(cursorWorld), new Vector2(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y)); return true; } private bool HasFollowerVisual(Follower follower) { Bounds bounds; return TryGetFollowerVisualBounds(follower, out bounds); } private bool TryGetFollowerVisualBounds(Follower follower, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) bounds = default(Bounds); if ((Object)(object)follower == (Object)null || (Object)(object)follower.Spine == (Object)null) { return false; } Renderer val = ((Component)follower.Spine).GetComponent(); if ((Object)(object)val == (Object)null) { val = ((Component)follower.Spine).GetComponentInChildren(true); } if (!((Object)(object)val == (Object)null) && val.enabled) { Bounds bounds2 = val.bounds; Vector3 size = ((Bounds)(ref bounds2)).size; if (!(((Vector3)(ref size)).sqrMagnitude <= 0.0001f)) { bounds = val.bounds; return true; } } return false; } private bool IsInBase(Follower follower) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 if ((Object)(object)follower != (Object)null && ((Behaviour)follower).isActiveAndEnabled && follower.Brain != null) { return (int)follower.Brain.Location == 1; } return false; } private bool IsSelectable(Follower follower) { if (!IsInBase(follower) || follower.Brain.Info == null) { return false; } if (!FollowerDragConfig.SkipProtectedFollowers.Value) { return true; } try { int iD = follower.Brain.Info.ID; bool flag = true; bool flag2 = true; bool flag3 = true; bool flag4 = true; bool flag5 = true; if (FollowerManager.FollowerLocked(ref iD, ref flag, ref flag2, ref flag3, ref flag4, ref flag5)) { return false; } return true; } catch (Exception ex) { DebugLog("Follower was skipped because its safety state could not be read: " + ex.Message); return false; } } private void UpdateDragTarget() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_draggedFollower == (Object)null) { return; } if (!TryGetCursorWorld(out var world)) { _targetTile = null; _targetIsValid = false; UpdateMarker(((Component)_draggedFollower).transform.position, valid: false); return; } _lastCursorWorld = world; PlacementRegion instance = PlacementRegion.Instance; TileGridTile val = null; if ((Object)(object)instance != (Object)null && instance.Grid != null && instance.Grid.Count > 0) { val = instance.GetClosestTileGridTileAtWorldPosition(world); } _targetTile = val; _targetIsValid = val != null && Vector3.Distance(val.WorldPosition, world) <= FollowerDragConfig.GridSnapRange.Value && !val.Occupied && !val.Obstructed && !val.ReservedForWaste; Vector3 draggedPosition = world + _grabOffset; draggedPosition.z = _originalPosition.z; SetDraggedPosition(draggedPosition); Vector3 center = val?.WorldPosition ?? world; center.z = _originalPosition.z; UpdateMarker(center, _targetIsValid); if (_targetIsValid) { Vector3 worldPosition = val.WorldPosition; worldPosition.z = _originalPosition.z; _lastValidPosition = worldPosition; } UpdateFloatingVisual(); } private void SetDraggedPosition(Vector3 position) { //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) //IL_001f: 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_005a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_draggedFollower == (Object)null) && !(Vector3.SqrMagnitude(((Component)_draggedFollower).transform.position - position) < 0.0001f)) { ((Component)_draggedFollower).transform.position = position; if (_draggedFollower.Brain != null) { _draggedFollower.Brain.LastPosition = position; } } } private void FinishDrag() { //IL_0027: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_draggedFollower == (Object)null)) { Follower draggedFollower = _draggedFollower; Vector3 val = (_targetIsValid ? _lastValidPosition : _originalPosition); WorkCandidate workCandidate = (FollowerDragConfig.AssignWorkOnDrop.Value ? FindNearestWorkCandidate(_targetIsValid ? val : _lastCursorWorld) : null); EndDrag(draggedFollower, val, _targetIsValid || workCandidate != null, workCandidate); } } private void EndDrag(Follower follower, Vector3 finalPosition, bool placed, WorkCandidate workCandidate) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) _draggedFollower = null; _targetTile = null; _targetIsValid = false; if ((Object)(object)follower != (Object)null) { try { EndFloatingVisual(follower); follower.ClearPath(); ((Component)follower).transform.position = finalPosition; if (follower.Brain != null) { follower.Brain.LastPosition = finalPosition; } follower.Drop(); ((MonoBehaviour)this).StartCoroutine(RestoreFollowerAfterDrop(follower, follower.Brain, workCandidate)); DebugLog((placed ? "Placed " : "Cancelled ") + "follower drag for " + follower.Brain.Info.ID + "."); } catch (Exception ex) { FollowerDragPlugin.Log.LogError((object)("Follower drag could not finish cleanly: " + ex)); try { follower.Brain.CompleteCurrentTask(); follower.State.CURRENT_STATE = (State)0; } catch { } } } DestroyVisuals(); SetCursorVisual(CursorVisual.Default); } private IEnumerator RestoreFollowerAfterDrop(Follower follower, FollowerBrain brain, WorkCandidate workCandidate) { yield return (object)new WaitForSecondsRealtime(0.4f); if ((Object)(object)follower != (Object)null) { try { follower.ResetStateAnimations(); } catch (Exception ex) { DebugLog("Follower animation reset failed after drag: " + ex.Message); } } if (brain != null && workCandidate != null && brain.CanWork) { try { FollowerTask val = workCandidate.CreateTask(); if (val != null) { brain.HardSwapToTask(val); DebugLog("Assigned follower " + brain.Info.ID + " to " + workCandidate.Kind.ToString() + " " + workCandidate.StructureId + "."); yield break; } } catch (Exception ex2) { DebugLog("Work assignment failed; returning follower to vanilla task selection: " + ex2.Message); } } if (brain != null && (int)brain.CurrentTaskType == 0) { brain.CheckChangeTask(); } } private WorkCandidate FindNearestWorkCandidate(Vector3 position) { //IL_0010: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_029e: Unknown result type (might be due to invalid IL or missing references) //IL_0311: 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_00c7: Invalid comparison between Unknown and I4 //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: 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_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: 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_01f0: Invalid comparison between Unknown and I4 float value = FollowerDragConfig.WorkSearchRadius.Value; float radiusSquared = value * value; WorkCandidate best = null; FollowerLocation val = (FollowerLocation)1; List allStructuresOfType = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType != null) { for (int i = 0; i < allStructuresOfType.Count; i++) { Structures_Tree val2 = allStructuresOfType[i]; if (val2 != null && ((StructureBrain)val2).Data != null && !val2.TreeChopped && !((StructureBrain)val2).Data.IsSapling) { ConsiderWorkCandidate(ref best, WorkKind.Tree, ((StructureBrain)val2).Data.ID, ((StructureBrain)val2).Data.Position, position, radiusSquared); } } } val = (FollowerLocation)1; List allStructuresOfType2 = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType2 != null) { for (int j = 0; j < allStructuresOfType2.Count; j++) { Structures_Waste val3 = allStructuresOfType2[j]; if (val3 != null && ((StructureBrain)val3).Data != null && !val3.ProgressFinished && (int)((StructureBrain)val3).Data.Type != 414) { ConsiderWorkCandidate(ref best, WorkKind.Waste, ((StructureBrain)val3).Data.ID, ((StructureBrain)val3).Data.Position, position, radiusSquared); } } } val = (FollowerLocation)1; List allStructuresOfType3 = StructureManager.GetAllStructuresOfType(ref val); val = (FollowerLocation)1; List allStructuresOfType4 = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType3 != null && allStructuresOfType4 != null) { for (int k = 0; k < allStructuresOfType3.Count; k++) { Structures_FarmerPlot val4 = allStructuresOfType3[k]; if (val4 == null || ((StructureBrain)val4).Data == null || !HasActionableFarmWork(val4)) { continue; } bool flag = val4.CanPlantSeed() || val4.CanWater() || val4.CanFertilize(); Structures_FarmerStation val5 = null; float num = 6.25f; for (int l = 0; l < allStructuresOfType4.Count; l++) { Structures_FarmerStation val6 = allStructuresOfType4[l]; if (val6 != null && ((StructureBrain)val6).Data != null) { float num2 = Vector3.Distance(((StructureBrain)val6).Data.Position, ((StructureBrain)val4).Data.Position); if (num2 <= num) { val5 = val6; num = num2; } } } if (val5 != null && (flag || (int)((StructureBrain)val5).Data.Type == 266)) { ConsiderWorkCandidate(ref best, WorkKind.Farm, ((StructureBrain)val5).Data.ID, ((StructureBrain)val4).Data.Position, position, radiusSquared); } } } val = (FollowerLocation)1; List allStructuresOfType5 = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType5 != null) { for (int m = 0; m < allStructuresOfType5.Count; m++) { Structures_Rubble val7 = allStructuresOfType5[m]; if (val7 != null && ((StructureBrain)val7).Data != null && !val7.ProgressFinished && val7.AvailableSlotCount > 0) { ConsiderWorkCandidate(ref best, WorkKind.Rubble, ((StructureBrain)val7).Data.ID, ((StructureBrain)val7).Data.Position, position, radiusSquared); } } } val = (FollowerLocation)1; List allStructuresOfType6 = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType6 != null) { for (int n = 0; n < allStructuresOfType6.Count; n++) { Structures_BuildSite val8 = allStructuresOfType6[n]; if (val8 != null && ((StructureBrain)val8).Data != null && !val8.ProgressFinished && !val8.IsObstructed) { ConsiderWorkCandidate(ref best, WorkKind.BuildSite, ((StructureBrain)val8).Data.ID, ((StructureBrain)val8).Data.Position, position, radiusSquared); } } } val = (FollowerLocation)1; List allStructuresOfType7 = StructureManager.GetAllStructuresOfType(ref val); if (allStructuresOfType7 != null) { for (int num3 = 0; num3 < allStructuresOfType7.Count; num3++) { Structures_BuildSiteProject val9 = allStructuresOfType7[num3]; if (val9 != null && ((StructureBrain)val9).Data != null && !val9.ProgressFinished) { ConsiderWorkCandidate(ref best, WorkKind.BuildProject, ((StructureBrain)val9).Data.ID, ((StructureBrain)val9).Data.Position, position, radiusSquared); } } } return best; } private static bool HasActionableFarmWork(Structures_FarmerPlot plot) { try { return plot.CanPlantSeed() || plot.CanWater() || plot.CanFertilize() || plot.CanPickCrop(); } catch { return false; } } private void ConsiderWorkCandidate(ref WorkCandidate best, WorkKind kind, int structureId, Vector3 candidatePosition, Vector3 releasePosition, float radiusSquared) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0045: Unknown result type (might be due to invalid IL or missing references) Vector3 val = candidatePosition - releasePosition; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > radiusSquared) && (best == null || !(sqrMagnitude >= best.Distance * best.Distance))) { best = new WorkCandidate { Kind = kind, StructureId = structureId, Position = candidatePosition, Distance = Mathf.Sqrt(sqrMagnitude) }; } } private bool TryGetCursorWorld(out Vector3 world) { //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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) world = Vector3.zero; Camera val = (((Object)(object)CameraManager.instance != (Object)null) ? CameraManager.instance.CameraRef : Camera.main); if ((Object)(object)val == (Object)null) { return false; } Plane val2 = default(Plane); ((Plane)(ref val2))..ctor(Vector3.forward, Vector3.zero); Ray val3 = val.ScreenPointToRay(Input.mousePosition); float num = default(float); if (!((Plane)(ref val2)).Raycast(val3, ref num)) { return false; } world = ((Ray)(ref val3)).GetPoint(num); world.z = 0f; return true; } private void CreateVisuals() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown DestroyVisuals(); GameObject val = new GameObject("FollowerDragTarget"); val.transform.SetParent(((Component)this).transform, false); _targetMarker = val.AddComponent(); _targetMarker.useWorldSpace = true; _targetMarker.loop = false; _targetMarker.positionCount = 5; _targetMarker.widthMultiplier = 0.06f; _targetMarker.numCapVertices = 2; ((Renderer)_targetMarker).sortingOrder = 500; _markerMaterial = CreateMarkerMaterial(); if ((Object)(object)_markerMaterial != (Object)null) { ((Renderer)_targetMarker).sharedMaterial = _markerMaterial; } } private Material CreateMarkerMaterial() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { return null; } return new Material(val) { hideFlags = (HideFlags)61 }; } private void UpdateMarker(Vector3 center, bool valid) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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) //IL_00d8: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_targetMarker == (Object)null)) { float num = FollowerDragConfig.MarkerSize.Value * 0.5f; Vector3 val = center + new Vector3(0f, num, -0.05f); Vector3 val2 = center + new Vector3(num, 0f, -0.05f); Vector3 val3 = center + new Vector3(0f, 0f - num, -0.05f); Vector3 val4 = center + new Vector3(0f - num, 0f, -0.05f); _targetMarker.SetPosition(0, val); _targetMarker.SetPosition(1, val2); _targetMarker.SetPosition(2, val3); _targetMarker.SetPosition(3, val4); _targetMarker.SetPosition(4, val); Color val5 = (valid ? new Color(0.2f, 1f, 0.35f, 0.95f) : new Color(1f, 0.2f, 0.2f, 0.95f)); _targetMarker.startColor = val5; _targetMarker.endColor = val5; } } private void DestroyVisuals() { if ((Object)(object)_targetMarker != (Object)null) { Object.Destroy((Object)(object)((Component)_targetMarker).gameObject); _targetMarker = null; } if ((Object)(object)_markerMaterial != (Object)null) { Object.Destroy((Object)(object)_markerMaterial); _markerMaterial = null; } } private void OnGUI() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_draggedFollower == (Object)null) && FollowerDragConfig.ShowPrompt.Value) { EnsureGuiStyles(); float num = Mathf.Min(520f, (float)Screen.width - 32f); Rect val = default(Rect); ((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, (float)Screen.height - 82f, num, 58f); string text = ((_draggedFollower.Brain != null && _draggedFollower.Brain.Info != null) ? _draggedFollower.Brain.Info.Name : "Follower"); string text2 = (_targetIsValid ? "Release to place" : "Move over an open plot tile"); GUI.Box(val, GUIContent.none, _panelStyle); GUI.Label(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 7f, ((Rect)(ref val)).width - 24f, ((Rect)(ref val)).height - 14f), "Crown drag: " + text + "\n" + text2 + " | Esc: cancel", _labelStyle); } } private void EnsureGuiStyles() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (_panelStyle == null) { _panelTexture = new Texture2D(1, 1, (TextureFormat)4, false); ((Object)_panelTexture).hideFlags = (HideFlags)61; _panelTexture.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.82f)); _panelTexture.Apply(); _panelStyle = new GUIStyle(GUI.skin.box); _panelStyle.normal.background = _panelTexture; _panelStyle.border = new RectOffset(8, 8, 8, 8); _panelStyle.padding = new RectOffset(8, 8, 6, 6); _labelStyle = new GUIStyle(GUI.skin.label); _labelStyle.alignment = (TextAnchor)4; _labelStyle.fontSize = 16; _labelStyle.normal.textColor = Color.white; } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } CancelCurrentDrag(); DestroyVisuals(); RestoreVanillaCursor(); DestroyCursorAssets(); if ((Object)(object)_panelTexture != (Object)null) { Object.Destroy((Object)(object)_panelTexture); _panelTexture = null; } } private static void DebugLog(string message) { if (FollowerDragConfig.DebugLogging.Value && FollowerDragPlugin.Log != null) { FollowerDragPlugin.Log.LogInfo((object)("[FollowerDrag] " + message)); } } } }