78bfdf2828
# Conflicts: # Assets/External/Animated PBR Chest Demo/Materials/WoodChest.mat # Packages/com.distantlands.cozy.core/Content/Integration/Import for BiRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for HDRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for URP.unitypackage.meta
125 lines
4.6 KiB
C#
125 lines
4.6 KiB
C#
using UnityEngine;
|
|
using Ashwild.Interaction;
|
|
using Ashwild.Inventory;
|
|
using Ashwild.Player;
|
|
|
|
namespace Ashwild.Network
|
|
{
|
|
/// <summary>
|
|
/// The single component for every world pickup — scattered ground items, hand-placed items, and
|
|
/// runtime drops alike. A WorldObject backed by the PickableRegistry: scene pickups self-register
|
|
/// with a baked id (>= 0); drops are spawned by the registry with a negative id.
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class Pickable : WorldObject, IInteractable
|
|
{
|
|
#region Serialized Fields
|
|
|
|
[Header("Item")]
|
|
[SerializeField] private ItemData itemData;
|
|
[SerializeField] private int quantity = 1;
|
|
|
|
[Header("Interaction")]
|
|
[SerializeField] private string interactionVerb = "Pick up";
|
|
|
|
#endregion
|
|
|
|
#region Public API
|
|
|
|
/// <summary>
|
|
/// The item this pickup grants.
|
|
/// </summary>
|
|
public ItemData ItemData => itemData;
|
|
|
|
/// <summary>
|
|
/// How many of the item this pickup grants.
|
|
/// </summary>
|
|
public int Quantity => quantity;
|
|
|
|
/// <summary>
|
|
/// Crosshair label such as "Pick up Wood".
|
|
/// </summary>
|
|
public string InteractionPrompt =>
|
|
itemData != null ? $"{interactionVerb} {itemData.ItemName}" : interactionVerb;
|
|
|
|
/// <summary>
|
|
/// Configures a runtime drop instance (called by the registry on each client after spawn).
|
|
/// </summary>
|
|
public void InitializeAsDrop(int dropId, ItemData data, int qty)
|
|
{
|
|
SetId(dropId);
|
|
itemData = data;
|
|
quantity = qty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// IInteractable entry point — runs on the interacting (owner) client.
|
|
/// </summary>
|
|
public void Interact() => Pickup();
|
|
|
|
/// <summary>
|
|
/// Asks the registry (server) to claim this pickup for the local player. Aborts while the player
|
|
/// is building (the hammer's placement/demolition would otherwise let an interact press snatch an
|
|
/// item mid-build), if already claimed, or if the local inventory is full.
|
|
///
|
|
/// A full inventory is announced rather than ignored: silently doing nothing on a press is
|
|
/// indistinguishable from a broken pickup, and that ambiguity is what hid the real bugs. A scene
|
|
/// pickup the registry never accepted (missing or duplicate baked id) is refused here too, with
|
|
/// the reason spelled out — the server would drop the request anyway.
|
|
///
|
|
/// The grab animation fires here, once every refusal is behind us but before the server has
|
|
/// answered: the hand must reach out on the press, not a round-trip later. A refused pickup
|
|
/// therefore never animates, and a granted one animates immediately.
|
|
/// </summary>
|
|
public void Pickup()
|
|
{
|
|
if (PlayerEvents.IsBuilding) return;
|
|
|
|
if (itemData == null)
|
|
{
|
|
Debug.LogError($"[Pickable] '{name}' has no ItemData assigned.", this);
|
|
return;
|
|
}
|
|
if (PickableRegistry.Instance == null)
|
|
{
|
|
Debug.LogError("[Pickable] No PickableRegistry in the scene.", this);
|
|
return;
|
|
}
|
|
if (PickableRegistry.Instance.IsClaimed(Id)) return;
|
|
|
|
if (Id >= 0 && !PickableRegistry.Instance.IsRegistered(Id))
|
|
{
|
|
Debug.LogError($"[Pickable] '{name}' (id {Id}) is not tracked by the registry — the server " +
|
|
"would drop this pickup. Check the console for an id error at startup.", this);
|
|
return;
|
|
}
|
|
|
|
// Client-side pre-check so we don't claim something we can't hold.
|
|
if (PlayerInventory.Instance != null && !PlayerInventory.Instance.CanFit(itemData, quantity))
|
|
{
|
|
PlayerEvents.RaiseInteractionRefused("Inventory full");
|
|
return;
|
|
}
|
|
|
|
PlayerEvents.RaiseGrabPerformed();
|
|
PickableRegistry.Instance.RequestPickupServerRpc(Id);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WorldObject
|
|
|
|
/// <summary>
|
|
/// Only scene pickups self-register; drops are registered by the registry on spawn.
|
|
/// </summary>
|
|
protected override bool ShouldAutoRegister => Id >= 0;
|
|
|
|
/// <summary>
|
|
/// This pickup belongs to the PickableRegistry.
|
|
/// </summary>
|
|
protected override WorldObjectRegistry GetRegistry() => PickableRegistry.Instance;
|
|
|
|
#endregion
|
|
}
|
|
}
|