Files
2026-03-03 05:27:03 +05:00

400 lines
15 KiB
C#

using UnityEngine;
using UHFPS.Input;
using UHFPS.Tools;
using ThunderWire.Attributes;
using static UHFPS.Runtime.InteractableItem;
namespace UHFPS.Runtime
{
[InspectorHeader("Interact Controller")]
public class InteractController : PlayerComponent
{
[Header("Raycast")]
public float RaycastRange = 3f;
public float HoldDistance = 4f;
public float HoldPointCreationTime = 0.5f;
public LayerMask CullLayers;
public Layer InteractLayer;
[Header("Settings")]
public bool ShowLootedText;
public bool ShowDefaultPickupIcon;
public Sprite DefaultPickupIcon;
[Header("Interact Settings")]
public InputReference UseAction;
public InputReference ExamineAction;
[Header("Interact Texts")]
public GString InteractText;
public GString ExamineText;
public GString LootText;
public GameObject RaycastObject => raycastObject;
public Vector3 LocalHitpoint => localHitpoint;
private Inventory inventory;
private GameManager gameManager;
private PlayerStateMachine player;
private GameObject raycastObject;
private GameObject interactableObject;
private Transform holdPointObject;
private bool isPressed;
private bool isHolding;
private bool isDynamic;
private bool isTimed;
private bool showInteractInfo = true;
private IInteractTimed timedInteract;
private float reqHoldTime;
private float holdTime;
private bool isHoldPointCreated;
private float holdPointCreateTime;
private Vector3 localHitpoint;
private void Awake()
{
inventory = Inventory.Instance;
gameManager = GameManager.Instance;
player = PlayerCollider.GetComponent<PlayerStateMachine>();
}
private void Start()
{
InteractText.SubscribeGlocMany();
ExamineText.SubscribeGlocMany();
LootText.SubscribeGloc();
}
public void EnableInteractInfo(bool state)
{
if (!state) gameManager.InteractInfoPanel.HideInfo();
showInteractInfo = state;
}
private void Update()
{
if (!isEnabled && !isHolding) return;
Ray playerAim = MainCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
if(GameTools.Raycast(playerAim, out RaycastHit hit, RaycastRange, CullLayers, InteractLayer))
{
raycastObject = hit.collider.gameObject;
if (!isHolding)
{
interactableObject = raycastObject;
localHitpoint = interactableObject.transform.InverseTransformPoint(hit.point);
}
if (showInteractInfo) OnInteractGUI();
}
else
{
if (isTimed)
{
gameManager.ShowInteractProgress(false, 0f);
timedInteract = null;
reqHoldTime = 0f;
holdTime = 0f;
isTimed = false;
}
gameManager.InteractInfoPanel.HideInfo();
raycastObject = null;
}
if (InputManager.ReadButton(Controls.USE))
{
isHolding = true;
if (interactableObject)
{
if (!isPressed)
{
foreach (var interactStartPlayer in interactableObject.GetComponents<IInteractStartPlayer>())
{
interactStartPlayer.InteractStartPlayer(transform.root.gameObject);
}
foreach (var interactStart in interactableObject.GetComponents<IInteractStart>())
{
interactStart.InteractStart();
}
if(interactableObject.TryGetComponent(out IInteractTimed timedInteract))
{
if (!timedInteract.NoInteract)
{
this.timedInteract = timedInteract;
reqHoldTime = timedInteract.InteractTime;
isTimed = true;
}
}
if(interactableObject.TryGetComponent(out IStateInteract stateInteract))
{
StateParams stateParams = stateInteract.OnStateInteract();
if(stateParams != null) player.ChangeState(stateParams.stateKey, stateParams.stateData);
}
if (interactableObject.TryGetComponent(out DynamicObject dynamicObject))
{
if ((dynamicObject.interactType == DynamicObject.InteractType.Mouse || dynamicObject.lockPlayer) && !dynamicObject.isLocked)
{
gameManager.FreezePlayer(true);
isDynamic = true;
}
}
Interact(interactableObject);
isPressed = true;
}
if (!isHoldPointCreated)
{
if (holdPointCreateTime >= HoldPointCreationTime)
{
if (RaycastObject != null)
{
GameObject holdPointObj = new GameObject("HoldPoint");
holdPointObj.transform.parent = RaycastObject.transform;
holdPointObj.transform.position = RaycastObject.transform.TransformPoint(localHitpoint);
holdPointObject = holdPointObj.transform;
}
isHoldPointCreated = true;
}
holdPointCreateTime += Time.deltaTime;
}
foreach (var interactHold in interactableObject.GetComponents<IInteractHold>())
{
interactHold.InteractHold(hit.point);
}
}
}
else if (isPressed)
{
if (isTimed)
{
gameManager.ShowInteractProgress(false, 0f);
timedInteract = null;
reqHoldTime = 0f;
holdTime = 0f;
}
if (interactableObject)
{
foreach (var interactStop in interactableObject.GetComponents<IInteractStop>())
{
interactStop.InteractStop();
}
}
isTimed = false;
isPressed = false;
}
else
{
if (isDynamic)
{
gameManager.FreezePlayer(false);
isDynamic = false;
}
if (holdPointObject)
{
Destroy(holdPointObject.gameObject);
holdPointObject = null;
}
holdPointCreateTime = 0;
interactableObject = null;
isHoldPointCreated = false;
isHolding = false;
}
if(isPressed && isTimed)
{
if (holdTime < reqHoldTime)
{
holdTime += Time.deltaTime;
float progress = Mathf.InverseLerp(0f, reqHoldTime, holdTime);
gameManager.ShowInteractProgress(true, progress);
}
else
{
gameManager.ShowInteractProgress(false, 0f);
timedInteract.InteractTimed();
timedInteract = null;
reqHoldTime = 0f;
holdTime = 0f;
isTimed = false;
}
}
if(isPressed && holdPointObject && interactableObject)
{
float distance = Vector3.Distance(MainCamera.transform.position, holdPointObject.position);
if (distance > HoldDistance)
{
if (interactableObject)
{
foreach (var interactStop in interactableObject.GetComponents<IInteractStop>())
{
interactStop.InteractStop();
}
}
interactableObject = null;
isPressed = false;
}
}
}
private void OnInteractGUI()
{
if (interactableObject == null)
return;
string titleText = null;
string button1Text = null;
string button2Text = null;
InputReference button1Action = UseAction;
InputReference button2Action = ExamineAction;
if (interactableObject.TryGetComponent(out IInteractTitle interactMessage))
{
TitleParams messageParams = interactMessage.InteractTitle();
titleText = messageParams.title ?? null;
button1Text = messageParams.button1 ?? null;
button2Text = messageParams.button2 ?? null;
}
if (interactableObject.TryGetComponent(out InteractableItem interactable))
{
if (interactable.InteractableType == InteractableTypeEnum.InventoryItem)
{
if (interactable.UseInventoryTitle)
{
Item item = interactable.PickupItem.GetItem();
titleText ??= item.Title;
}
else
{
titleText ??= interactable.InteractTitle;
}
button1Text ??= InteractText;
button2Text ??= interactable.ExamineType != ExamineTypeEnum.None ? ExamineText : null;
}
else if (interactable.InteractableType == InteractableTypeEnum.GenericItem || interactable.InteractableType == InteractableTypeEnum.InventoryExpand)
{
titleText ??= interactable.InteractTitle;
button1Text ??= InteractText;
button2Text ??= interactable.ExamineType != ExamineTypeEnum.None ? ExamineText : null;
}
else if (interactable.InteractableType == InteractableTypeEnum.ExamineItem)
{
titleText ??= interactable.InteractTitle;
button1Text ??= ExamineText;
button1Action = ExamineAction;
}
}
titleText ??= interactableObject.name;
button1Text ??= InteractText;
InteractContext button1 = null;
if (!string.IsNullOrEmpty(button1Text))
{
button1 = new()
{
InputAction = button1Action,
InteractName = button1Text
};
}
InteractContext button2 = null;
if (!string.IsNullOrEmpty(button2Text))
{
button2 = new()
{
InputAction = button2Action,
InteractName = button2Text
};
}
gameManager.InteractInfoPanel.ShowInfo(new()
{
ObjectName = titleText,
Contexts = new[] { button1, button2 }
});
}
public void Interact(GameObject interactObj)
{
if(interactObj.TryGetComponent(out InteractableItem interactable))
{
bool isAddedToInventory = false;
int shortcutId = -1;
if (interactable.InteractableType == InteractableTypeEnum.InventoryItem)
{
isAddedToInventory = inventory.AddItem(interactable.PickupItem.GUID, interactable.Quantity, interactable.ItemCustomData, out var addedItem);
if (isAddedToInventory && interactable.AutoShortcut)
{
shortcutId = inventory.AutoShortcut(addedItem);
}
}
if (interactable.InteractableType == InteractableTypeEnum.InventoryExpand)
{
inventory.ExpandInventory(interactable.SlotsToExpand, interactable.ExpandRows);
isAddedToInventory = true;
}
if (isAddedToInventory)
{
if (interactable.MessageType == MessageTypeEnum.Alert)
{
string pickupText = ShowLootedText ? LootText + " " + interactable.ItemName : interactable.ItemName;
if (shortcutId >= 0) pickupText += $"\nPress {shortcutId + 1} to Equip";
if (ShowDefaultPickupIcon)
{
gameManager.ShowItemPickupMessage(pickupText, DefaultPickupIcon, interactable.MessageTime);
}
else
{
var pickupIcon = interactable.PickupItem.GetItem().Icon;
gameManager.ShowItemPickupMessage(pickupText, pickupIcon, interactable.MessageTime);
}
}
else if (interactable.MessageType == MessageTypeEnum.Hint)
{
gameManager.ShowHintMessage(interactable.HintMessage, interactable.MessageTime);
}
}
if(isAddedToInventory || interactable.InteractableType == InteractableTypeEnum.GenericItem)
{
interactable.OnInteract();
}
}
}
private void OnDrawGizmos()
{
if(interactableObject != null && isHoldPointCreated)
{
Vector3 pointPos = interactableObject.transform.TransformPoint(localHitpoint);
Gizmos.color = Color.red.Alpha(0.5f);
Gizmos.DrawSphere(pointPos, 0.03f);
}
}
}
}