Finalize work on the dump controller switching

This commit is contained in:
Michal Pikulski
2025-12-15 10:18:43 +01:00
parent b14fdfbe68
commit 5b33eb8fbb
9 changed files with 211 additions and 1258 deletions

View File

@@ -6,7 +6,6 @@ using UnityEngine.Events;
using System.Threading.Tasks;
using Core;
using Core.Lifecycle;
using Utils;
namespace Interactions
{
@@ -146,7 +145,14 @@ namespace Interactions
await DispatchEventAsync(InteractionEventType.InteractionStarted, playerRef);
// 5. Orchestrate character movement
await MoveCharactersAsync(playerRef);
bool movementSucceeded = await MoveCharactersAsync(playerRef);
// If movement was cancelled, stop the interaction flow
if (!movementSucceeded)
{
Logging.Debug($"[Interactable] Interaction cancelled due to movement failure on {gameObject.name}");
return;
}
// 6. Virtual hook: Arrival reaction
OnInteractingCharacterArrived();
@@ -280,130 +286,37 @@ namespace Interactions
#region Character Movement Orchestration
/// <summary>
/// Orchestrates character movement based on characterToInteract setting.
/// Delegates movement to the interacting character's controller.
/// Each controller implements its own movement behavior based on this interactable's settings.
/// </summary>
private async Task MoveCharactersAsync(PlayerTouchController playerRef = null)
/// <returns>True if movement succeeded, false if cancelled or failed</returns>
private async Task<bool> MoveCharactersAsync(PlayerTouchController playerRef = null)
{
if (_interactingCharacter == null)
{
Logging.Debug($"[Interactable] No interacting character found. Aborting interaction.");
interactionInterrupted.Invoke();
await DispatchEventAsync(InteractionEventType.InteractionInterrupted, playerRef);
return;
return false;
}
// If characterToInteract is None, skip movement
if (characterToInteract == CharacterToInteract.None)
{
return; // Continue to arrival
return true; // Continue to arrival
}
// Move the appropriate character based on characterToInteract setting
if (characterToInteract == CharacterToInteract.Trafalgar)
{
await MoveCharacterAsync(_interactingCharacter, CharacterToInteract.Trafalgar, playerRef);
}
else if (characterToInteract == CharacterToInteract.Pulver)
{
await MoveCharacterAsync(_interactingCharacter, CharacterToInteract.Pulver, playerRef);
}
else if (characterToInteract == CharacterToInteract.Both)
{
await MoveCharacterAsync(_interactingCharacter, CharacterToInteract.Trafalgar, playerRef); // Move first character to range
await MoveFollowerAsync(playerRef); // Then move follower to interaction point
}
}
/// <summary>
/// Moves a character controller to the interaction point or custom target.
/// Works with any controller implementing IInteractingCharacter.
/// </summary>
private async Task MoveCharacterAsync(IInteractingCharacter character, CharacterToInteract targetCharacterType, PlayerTouchController playerRef = null)
{
if (character == null)
{
Logging.Warning("[Interactable] Cannot move null character");
return;
}
Vector3 stopPoint = transform.position; // Default to interactable position
bool customTargetFound = false;
// Check for a CharacterMoveToTarget component
CharacterMoveToTarget[] moveTargets = GetComponentsInChildren<CharacterMoveToTarget>();
foreach (var target in moveTargets)
{
if (target.characterType == targetCharacterType || target.characterType == CharacterToInteract.Both)
{
stopPoint = target.GetTargetPosition();
customTargetFound = true;
break;
}
}
// If no custom target, use default distance
if (!customTargetFound)
{
Vector3 interactablePos = transform.position;
Vector3 characterPos = character.transform.position;
float stopDistance = targetCharacterType == CharacterToInteract.Pulver
? GameManager.Instance.PlayerStopDistance
: GameManager.Instance.PlayerStopDistanceDirectInteraction;
stopPoint = MovementUtilities.CalculateStopPosition(interactablePos, characterPos, stopDistance);
}
// Use MovementUtilities to handle movement
bool arrived = await MovementUtilities.MoveToPositionAsync(character, stopPoint);
// Delegate to controller - let it decide how to handle the interaction
bool arrived = await _interactingCharacter.MoveToInteractableAsync(this);
if (!arrived)
{
_ = HandleInteractionCancelledAsync(playerRef);
}
}
/// <summary>
/// Moves the follower to the interaction point or custom target.
/// </summary>
private async Task MoveFollowerAsync(PlayerTouchController playerRef = null)
{
if (FollowerController == null)
return;
// Check for a CharacterMoveToTarget component for Pulver or Both
Vector3 targetPosition = transform.position;
CharacterMoveToTarget[] moveTargets = GetComponentsInChildren<CharacterMoveToTarget>();
foreach (var target in moveTargets)
{
if (target.characterType == CharacterToInteract.Pulver || target.characterType == CharacterToInteract.Both)
{
targetPosition = target.GetTargetPosition();
break;
}
Logging.Debug($"[Interactable] Movement cancelled for {gameObject.name}");
await HandleInteractionCancelledAsync(playerRef);
return false;
}
// Wait for follower to arrive
var tcs = new TaskCompletionSource<bool>();
void OnFollowerArrivedLocal()
{
if (FollowerController != null)
{
FollowerController.OnPickupArrived -= OnFollowerArrivedLocal;
}
// Tell follower to return to player if we have a PlayerTouchController reference
if (FollowerController != null && playerRef != null)
{
FollowerController.ReturnToPlayer(playerRef.transform);
}
tcs.TrySetResult(true);
}
FollowerController.OnPickupArrived += OnFollowerArrivedLocal;
FollowerController.GoToPoint(targetPosition);
await tcs.Task;
return true;
}
/// <summary>