Player/PlayerInteract.cs
using Clover.Carriable;
using Clover.Components;
using Clover.Data;
using Clover.Interactable;
using Clover.Inventory;
using Clover.Items;
using Clover.Npc;
using Clover.Ui;
namespace Clover.Player;
[Title( "Player Interact" )]
[Icon( "inventory" )]
[Category( "Clover/Player" )]
public class PlayerInteract : Component
{
[RequireComponent] public PlayerCharacter Player { get; set; }
private IInteract _currentInteractable;
[Property] public BoxCollider InteractCollider { get; set; }
[Property] public GameObject Cursor { get; set; }
[Property] public SoundEvent UseFailSound { get; set; }
[Property] public SoundEvent PickUpFailSound { get; set; }
public GameObject InteractionTarget { get; set; }
protected override void OnAwake()
{
if ( IsProxy ) return;
if ( Cursor != null )
{
Cursor.Parent = null;
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if ( Cursor.IsValid() )
{
Cursor.Destroy();
}
}
public bool CanInteract()
{
if ( Player.ItemPlacer.IsPlacing || Player.ItemPlacer.IsMoving ) return false;
if ( Player.InCutscene ) return false;
if ( Player.VehicleRider.Vehicle.IsValid() ) return false;
if ( InteractionTarget.IsValid() )
{
if ( InteractionTarget.GetComponent<BaseNpc>().IsValid() ) return false;
}
if ( Player.Equips.TryGetEquippedItem<BaseCarriable>( Equips.EquipSlot.Tool, out var tool ) &&
tool.ShouldDisableMovement() ) return false;
return true;
}
public bool CanPickUp()
{
if ( Player.Equips.TryGetEquippedItem<BaseCarriable>( Equips.EquipSlot.Tool, out var tool ) &&
tool.ShouldDisableMovement() ) return false;
return true;
}
public bool HasInteractable()
{
return FindInteractable() != null;
}
protected override void OnFixedUpdate()
{
if ( IsProxy ) return;
if ( !CanInteract() )
{
return;
}
var interactable = FindInteractable();
var moveable = FindMoveable();
var pickupableNode = GetPickupableNode();
if ( Input.Pressed( "use" ) )
{
if ( interactable != null )
{
_currentInteractable = interactable;
_currentInteractable.StartInteract( Player );
if ( !Networking.IsHost )
{
using ( Rpc.FilterInclude( Connection.Host ) )
{
_currentInteractable.StartInteractHost( Player );
}
}
Input.Clear( "use" );
}
else
{
Log.Warning( "No interactable found" );
// Notifications.Instance.AddNotification( Notifications.NotificationType.Warning, "No interactable found" );
Sound.Play( UseFailSound, WorldPosition );
}
return;
}
else if ( Input.Released( "use" ) )
{
if ( _currentInteractable != null )
{
_currentInteractable.FinishInteract( Player );
if ( !Networking.IsHost )
{
using ( Rpc.FilterInclude( Connection.Host ) )
{
_currentInteractable.FinishInteractHost( Player );
}
}
_currentInteractable = null;
Input.Clear( "use" );
}
return;
}
if ( Input.Pressed( "pickup" ) && CanPickUp() )
{
if ( pickupableNode != null )
{
if ( pickupableNode.CanPickup( Player ) )
{
pickupableNode.OnPickup( Player );
return;
}
}
Log.Warning( "No pickupable node found" );
Sound.Play( PickUpFailSound, WorldPosition );
return;
}
/*if ( Input.Pressed( "move" ) )
{
if ( !Player.World.Data.DisableItemPlacement )
{
if ( moveable.IsValid() )
{
Log.Info( "Moving..." );
Mouse.Visible = true;
Player.ItemPlacer.StartMovingPlacedItem( moveable.GetComponent<WorldItem>() );
Input.Clear( "move" );
}
else
{
Mouse.Visible = false;
Log.Warning( "No interactable found" );
// Notifications.Instance.AddNotification( Notifications.NotificationType.Warning, "No interactable found" );
Sound.Play( UseFailSound, WorldPosition );
}
}
return;
}*/
GameObject target = null;
if ( interactable is Component interactableComponent )
{
target = interactableComponent.GameObject;
}
else if ( moveable.IsValid() )
{
target = moveable;
}
else if ( pickupableNode is Component pickupableNodeComponent && pickupableNode.CanPickup( Player ) )
{
target = pickupableNodeComponent.GameObject;
}
if ( target != null )
{
if ( target.Components.TryGet<WorldItem>( out var worldItem ) )
{
worldItem.ItemHighlight.Enabled = true;
}
}
if ( Cursor.IsValid() && Cursor.Enabled )
{
var gridPosition = Player.GetAimingGridPosition();
var worldPosition = WorldManager.Instance.ActiveWorld.ItemGridToWorld( gridPosition );
Cursor.WorldPosition = worldPosition;
}
}
public IPickupable GetPickupableNode()
{
var touchingItems = InteractCollider.Touching;
foreach ( var collider in touchingItems )
{
if ( collider.GameObject.Components.TryGet<IPickupable>( out var pickupable ) )
{
return pickupable;
}
}
return null;
}
/*public WorldItem GetWorldItemFromInteract()
{
foreach ( var collider in InteractCollider.Touching )
{
var checkGameObject = collider.GameObject;
while ( checkGameObject != null )
{
if ( checkGameObject.Components.TryGet<IInteract>( out var interactable ) )
{
if ( checkGameObject.Components.TryGet<WorldItem>( out var worldItem ) )
{
return worldItem;
}
}
checkGameObject = checkGameObject.Parent;
}
}
return null;
}*/
public IInteract FindInteractable()
{
foreach ( var collider in InteractCollider.Touching )
{
/*var checkGameObject = collider.GameObject;
while ( checkGameObject != null )
{
if ( checkGameObject.Components.TryGet<IInteract>( out var interactable ) )
{
return interactable;
}
checkGameObject = checkGameObject.Parent;
}*/
/*if ( collider.GameObject.Components.TryGet<IInteract>( out var interactable,
FindMode.EverythingInSelfAndAncestors ) )
{
return interactable;
}*/
var components = collider.GameObject.Components.GetAll<IInteract>( FindMode.EverythingInSelfAndAncestors );
foreach ( var component in components )
{
if ( component.CanInteract( Player ) )
{
return component;
}
}
}
// Log.Info( "# Reached root, no interactable found." );
return null;
}
public GameObject FindMoveable()
{
foreach ( var collider in InteractCollider.Touching )
{
var worldItem = collider.GameObject.Components.Get<WorldItem>( FindMode.EverythingInSelfAndAncestors );
if ( worldItem != null && worldItem.CanPickup( Player ) )
{
return collider.GameObject;
}
}
return null;
}
}