Merge remote-tracking branch 'origin/feat/inport-props' into feat/craft-discovery

# 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
This commit is contained in:
2026-07-25 19:42:26 +02:00
954 changed files with 999772 additions and 26193 deletions
@@ -60,29 +60,43 @@ namespace Ashwild.Network
/// <summary>
/// Owner-side entry: tells the server the local player hit a harvestable. The server applies
/// the (client-computed) damage, grants loot, broadcasts feedback, and handles depletion.
///
/// The two ways this can go wrong are reported back to the requesting player instead of being
/// swallowed: an id the server does not track (a scene object with a missing or duplicate id) and
/// a connection whose inventory cannot be resolved. Both used to end in a bare `return` — the
/// player saw their hit land and gained nothing, with no trace anywhere on their machine. Losing
/// the race against another player is the one case left unreported, since the object disappearing
/// says it plainly enough.
/// </summary>
[ServerRpc(RequireOwnership = false)]
public void RequestHitServerRpc(int id, float damage, ushort toolItemId, Vector3 hitDirection, NetworkConnection conn = null)
public void RequestHitServerRpc(int id, float damage, ushort toolItemId, NetworkConnection conn = null)
{
if (IsInactive(id)) return;
if (!TryGetObject(id, out WorldObject obj) || obj is not Harvestable harvestable) return;
if (!TryGetObject(id, out WorldObject obj) || obj is not Harvestable harvestable)
{
ReportFailure(conn, id, "no harvestable is registered with this id on the server");
return;
}
PlayerInventory inventory = ResolveInventory(conn);
if (inventory == null)
{
ReportFailure(conn, id, "the requesting player's inventory could not be resolved — the loot would be lost");
return;
}
if (!health.TryGetValue(id, out float hp)) hp = harvestable.MaxHealth;
hp -= damage;
health[id] = hp;
// Grant the rolled loot to the hitting player.
ItemData tool = ItemDatabase.Instance != null ? ItemDatabase.Instance.GetItem(toolItemId) : null;
PlayerInventory inventory = ResolveInventory(conn);
if (inventory != null)
{
foreach ((ItemData item, int quantity) in harvestable.RollDrops(tool))
inventory.GrantItemFromServer(item, quantity);
}
foreach ((ItemData item, int quantity) in harvestable.RollDrops(tool))
inventory.GrantItemFromServer(item, quantity);
// Feedback for everyone except the hitter (who already played it locally for responsiveness).
int hitterClientId = conn != null ? conn.ClientId : -1;
PlayHitObserversRpc(id, hitDirection, hitterClientId);
PlayHitObserversRpc(id, hitterClientId);
if (hp <= 0f)
{
@@ -101,11 +115,11 @@ namespace Ashwild.Network
/// Plays the hit feedback on every client except the one who threw the hit.
/// </summary>
[ObserversRpc]
private void PlayHitObserversRpc(int id, Vector3 hitDirection, int hitterClientId)
private void PlayHitObserversRpc(int id, int hitterClientId)
{
if (LocalConnection != null && LocalConnection.ClientId == hitterClientId) return;
if (TryGetObject(id, out WorldObject obj) && obj is Harvestable harvestable)
harvestable.PlayHitEffect(hitDirection);
harvestable.PlayHitEffect();
}
#endregion