353 lines
18 KiB
C#
353 lines
18 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using UnityEngine;
|
|
using Ashwild.Audio;
|
|
using Ashwild.Harvesting;
|
|
using Ashwild.Interaction;
|
|
using Ashwild.Inventory;
|
|
|
|
namespace Ashwild.Player
|
|
{
|
|
public static class PlayerEvents
|
|
{
|
|
// ============================================================
|
|
// State (single source of truth — read by everyone)
|
|
// ============================================================
|
|
|
|
public static bool IsDead { get; private set; }
|
|
public static bool IsGrounded { get; private set; } = true;
|
|
public static bool IsCrouching { get; private set; }
|
|
public static bool IsSprinting { get; private set; }
|
|
public static bool IsSliding { get; private set; }
|
|
public static bool IsOnSlope { get; private set; }
|
|
public static bool IsInventoryOpen { get; private set; }
|
|
public static bool IsPaused { get; private set; }
|
|
|
|
// True when a networked session is live (host or client).
|
|
public static bool IsOnline { get; private set; }
|
|
// True when this instance owns the server (host = server + local client).
|
|
public static bool IsHost { get; private set; }
|
|
// Shareable code of the current session (host SteamID64). Empty when offline.
|
|
public static string SessionCode { get; private set; } = string.Empty;
|
|
|
|
// The interactable the player is currently aiming at (null when none).
|
|
public static IInteractable HoveredInteractable { get; private set; }
|
|
|
|
// Single source of truth for "the player must not respond to input right now".
|
|
// Used by locomotion, camera, tools and interaction so they all agree.
|
|
public static bool InputLocked => IsDead || IsInventoryOpen || IsPaused;
|
|
|
|
// ============================================================
|
|
// Input events
|
|
// ============================================================
|
|
|
|
public static event Action<Vector2> MoveInput;
|
|
public static event Action<Vector2> LookInput;
|
|
public static event Action JumpPressed;
|
|
public static event Action<bool> SprintHeld;
|
|
public static event Action CrouchPressed;
|
|
public static event Action AttackPressed;
|
|
public static event Action InteractPressed;
|
|
public static event Action DropPressed;
|
|
public static event Action InventoryTogglePressed;
|
|
public static event Action<int> HotbarSlotPressed;
|
|
public static event Action<float> HotbarScroll;
|
|
public static event Action CancelPressed; // UI "Cancel" (Escape) — back / pause / close
|
|
|
|
// ============================================================
|
|
// Locomotion events
|
|
// ============================================================
|
|
|
|
public static event Action<bool, float> GroundedChanged; // isGrounded, impactSpeed
|
|
public static event Action<bool, Vector3> SlopeChanged;
|
|
public static event Action<PhysicsMaterial> GroundMaterialChanged;
|
|
public static event Action<Vector3> VelocityChanged;
|
|
public static event Action<float> YawChanged;
|
|
public static event Action Jumped;
|
|
public static event Action<bool> CrouchChanged;
|
|
public static event Action<bool> SprintChanged;
|
|
public static event Action<float, Vector3> CapsuleHeightChanged;
|
|
public static event Action<float> CameraHeightChanged;
|
|
public static event Action<float> LandingStunStarted;
|
|
public static event Action LandingStunEnded;
|
|
public static event Action SlideStarted;
|
|
public static event Action SlideEnded;
|
|
public static event Action<int> MultiJumpPerformed;
|
|
|
|
// ============================================================
|
|
// Stats events
|
|
// ============================================================
|
|
|
|
public static event Action<float, float> HealthChanged;
|
|
public static event Action<float, float> HungerChanged;
|
|
public static event Action<float, float> ThirstChanged;
|
|
public static event Action<float, DamageType> Damaged;
|
|
public static event Action<float> FallDamageApplied;
|
|
public static event Action<float> StarvationTick;
|
|
public static event Action<float> DehydrationTick;
|
|
|
|
// ============================================================
|
|
// Inventory events
|
|
// ============================================================
|
|
|
|
public static event Action<int> InventorySlotChanged;
|
|
public static event Action<int> SelectedHotbarSlotChanged;
|
|
public static event Action<ItemData, int> ItemAdded;
|
|
public static event Action<ItemData, int> ItemDropped;
|
|
public static event Action<ItemData> ItemConsumed;
|
|
public static event Action<ItemData, int> ItemPickedUp;
|
|
public static event Action<ItemData> HeldItemChanged;
|
|
public static event Action<bool> InventoryOpenChanged;
|
|
public static event Action<bool> GamePausedChanged;
|
|
|
|
// ============================================================
|
|
// Interaction events
|
|
// ============================================================
|
|
|
|
public static event Action<IInteractable> InteractableHoverChanged; // null = nothing hovered
|
|
|
|
// ============================================================
|
|
// Tools events
|
|
// ============================================================
|
|
|
|
public static event Action AttackSwung;
|
|
public static event Action<Harvestable, float> HarvestableHit;
|
|
public static event Action EquipAnimComplete;
|
|
public static event Action UnequipAnimComplete;
|
|
|
|
// ============================================================
|
|
// Cooking events
|
|
// ============================================================
|
|
|
|
public static event Action<ItemData> FoodPlacedToCook; // the raw item placed on a station
|
|
public static event Action<ItemData> FoodCookedReady; // the cooked result is ready to take
|
|
public static event Action<ItemData> FuelAdded; // the fuel item consumed to feed a station
|
|
|
|
// ============================================================
|
|
// Audio events
|
|
// ============================================================
|
|
|
|
public static event Action<SurfaceSoundProfile> SurfaceChanged;
|
|
public static event Action<SurfaceSoundProfile, float> FootstepTriggered;
|
|
|
|
// ============================================================
|
|
// Lifecycle events
|
|
// ============================================================
|
|
|
|
public static event Action Died;
|
|
public static event Action Respawned;
|
|
public static event Action<bool> DeathChanged;
|
|
|
|
// ============================================================
|
|
// Network / session events
|
|
// ============================================================
|
|
|
|
public static event Action SessionStarting; // host/join requested, before transport is up
|
|
public static event Action<string> SessionStarted; // host is up — payload is the shareable code
|
|
public static event Action<string> SessionJoining; // local client connecting to a code
|
|
public static event Action SessionJoined; // local client connected to a host
|
|
public static event Action SessionStopped; // session fully torn down (offline again)
|
|
public static event Action<string> SessionError; // human-readable failure reason
|
|
public static event Action<int> RemotePlayerCountChanged; // number of *other* connected clients
|
|
public static event Action LocalPlayerSpawned; // the local owned player NetworkObject is ready
|
|
public static event Action<ulong, string, string> InviteReceived; // inviter SteamID64, inviter name, connect code
|
|
|
|
// ============================================================
|
|
// Raisers — state is updated automatically here so consumers
|
|
// can rely on PlayerEvents.IsX matching the latest event.
|
|
// ============================================================
|
|
|
|
public static void RaiseMoveInput(Vector2 v) { Log(nameof(MoveInput)); MoveInput?.Invoke(v); }
|
|
public static void RaiseLookInput(Vector2 v) { LookInput?.Invoke(v); }
|
|
public static void RaiseJumpPressed() { Log(nameof(JumpPressed)); JumpPressed?.Invoke(); }
|
|
public static void RaiseSprintHeld(bool b) { Log(nameof(SprintHeld)); SprintHeld?.Invoke(b); }
|
|
public static void RaiseCrouchPressed() { Log(nameof(CrouchPressed)); CrouchPressed?.Invoke(); }
|
|
public static void RaiseAttackPressed() { Log(nameof(AttackPressed)); AttackPressed?.Invoke(); }
|
|
public static void RaiseInteractPressed() { Log(nameof(InteractPressed)); InteractPressed?.Invoke(); }
|
|
public static void RaiseDropPressed() { Log(nameof(DropPressed)); DropPressed?.Invoke(); }
|
|
public static void RaiseInventoryTogglePressed() { Log(nameof(InventoryTogglePressed)); InventoryTogglePressed?.Invoke(); }
|
|
public static void RaiseHotbarSlotPressed(int i) { Log(nameof(HotbarSlotPressed)); HotbarSlotPressed?.Invoke(i); }
|
|
public static void RaiseHotbarScroll(float f) { HotbarScroll?.Invoke(f); }
|
|
public static void RaiseCancelPressed() { Log(nameof(CancelPressed)); CancelPressed?.Invoke(); }
|
|
|
|
public static void RaiseGroundedChanged(bool grounded, float impactSpeed)
|
|
{
|
|
IsGrounded = grounded;
|
|
Log(nameof(GroundedChanged));
|
|
GroundedChanged?.Invoke(grounded, impactSpeed);
|
|
}
|
|
public static void RaiseSlopeChanged(bool onSlope, Vector3 normal)
|
|
{
|
|
IsOnSlope = onSlope;
|
|
SlopeChanged?.Invoke(onSlope, normal);
|
|
}
|
|
public static void RaiseGroundMaterialChanged(PhysicsMaterial m) { GroundMaterialChanged?.Invoke(m); }
|
|
public static void RaiseVelocityChanged(Vector3 v) { VelocityChanged?.Invoke(v); }
|
|
public static void RaiseYawChanged(float y) { YawChanged?.Invoke(y); }
|
|
public static void RaiseJumped() { Log(nameof(Jumped)); Jumped?.Invoke(); }
|
|
public static void RaiseCrouchChanged(bool b)
|
|
{
|
|
IsCrouching = b;
|
|
Log(nameof(CrouchChanged));
|
|
CrouchChanged?.Invoke(b);
|
|
}
|
|
public static void RaiseSprintChanged(bool b)
|
|
{
|
|
IsSprinting = b;
|
|
Log(nameof(SprintChanged));
|
|
SprintChanged?.Invoke(b);
|
|
}
|
|
public static void RaiseCapsuleHeightChanged(float h, Vector3 c) { CapsuleHeightChanged?.Invoke(h, c); }
|
|
public static void RaiseCameraHeightChanged(float h) { CameraHeightChanged?.Invoke(h); }
|
|
public static void RaiseLandingStunStarted(float d) { Log(nameof(LandingStunStarted)); LandingStunStarted?.Invoke(d); }
|
|
public static void RaiseLandingStunEnded() { Log(nameof(LandingStunEnded)); LandingStunEnded?.Invoke(); }
|
|
public static void RaiseSlideStarted()
|
|
{
|
|
IsSliding = true;
|
|
Log(nameof(SlideStarted));
|
|
SlideStarted?.Invoke();
|
|
}
|
|
public static void RaiseSlideEnded()
|
|
{
|
|
IsSliding = false;
|
|
Log(nameof(SlideEnded));
|
|
SlideEnded?.Invoke();
|
|
}
|
|
public static void RaiseMultiJumpPerformed(int i) { Log(nameof(MultiJumpPerformed)); MultiJumpPerformed?.Invoke(i); }
|
|
|
|
public static void RaiseHealthChanged(float c, float m) { HealthChanged?.Invoke(c, m); }
|
|
public static void RaiseHungerChanged(float c, float m) { HungerChanged?.Invoke(c, m); }
|
|
public static void RaiseThirstChanged(float c, float m) { ThirstChanged?.Invoke(c, m); }
|
|
public static void RaiseDamaged(float a, DamageType t) { Log(nameof(Damaged)); Damaged?.Invoke(a, t); }
|
|
public static void RaiseFallDamageApplied(float a) { Log(nameof(FallDamageApplied)); FallDamageApplied?.Invoke(a); }
|
|
public static void RaiseStarvationTick(float a) { StarvationTick?.Invoke(a); }
|
|
public static void RaiseDehydrationTick(float a) { DehydrationTick?.Invoke(a); }
|
|
|
|
public static void RaiseInventorySlotChanged(int i) { InventorySlotChanged?.Invoke(i); }
|
|
public static void RaiseSelectedHotbarSlotChanged(int i) { Log(nameof(SelectedHotbarSlotChanged)); SelectedHotbarSlotChanged?.Invoke(i); }
|
|
public static void RaiseItemAdded(ItemData d, int q) { Log(nameof(ItemAdded)); ItemAdded?.Invoke(d, q); }
|
|
public static void RaiseItemDropped(ItemData d, int q) { Log(nameof(ItemDropped)); ItemDropped?.Invoke(d, q); }
|
|
public static void RaiseItemConsumed(ItemData d) { Log(nameof(ItemConsumed)); ItemConsumed?.Invoke(d); }
|
|
public static void RaiseItemPickedUp(ItemData d, int q) { Log(nameof(ItemPickedUp)); ItemPickedUp?.Invoke(d, q); }
|
|
public static void RaiseHeldItemChanged(ItemData d) { Log(nameof(HeldItemChanged)); HeldItemChanged?.Invoke(d); }
|
|
public static void RaiseInventoryOpenChanged(bool b)
|
|
{
|
|
IsInventoryOpen = b;
|
|
Log(nameof(InventoryOpenChanged));
|
|
InventoryOpenChanged?.Invoke(b);
|
|
}
|
|
public static void RaiseGamePaused(bool b)
|
|
{
|
|
IsPaused = b;
|
|
Log(nameof(GamePausedChanged));
|
|
GamePausedChanged?.Invoke(b);
|
|
}
|
|
|
|
public static void RaiseInteractableHoverChanged(IInteractable target)
|
|
{
|
|
HoveredInteractable = target;
|
|
Log(nameof(InteractableHoverChanged));
|
|
InteractableHoverChanged?.Invoke(target);
|
|
}
|
|
|
|
public static void RaiseAttackSwung() { Log(nameof(AttackSwung)); AttackSwung?.Invoke(); }
|
|
public static void RaiseHarvestableHit(Harvestable h, float d) { Log(nameof(HarvestableHit)); HarvestableHit?.Invoke(h, d); }
|
|
public static void RaiseEquipAnimComplete() { EquipAnimComplete?.Invoke(); }
|
|
public static void RaiseUnequipAnimComplete() { UnequipAnimComplete?.Invoke(); }
|
|
|
|
public static void RaiseFoodPlacedToCook(ItemData raw) { Log(nameof(FoodPlacedToCook)); FoodPlacedToCook?.Invoke(raw); }
|
|
public static void RaiseFoodCookedReady(ItemData cooked) { Log(nameof(FoodCookedReady)); FoodCookedReady?.Invoke(cooked); }
|
|
public static void RaiseFuelAdded(ItemData fuel) { Log(nameof(FuelAdded)); FuelAdded?.Invoke(fuel); }
|
|
|
|
public static void RaiseSurfaceChanged(SurfaceSoundProfile p) { SurfaceChanged?.Invoke(p); }
|
|
public static void RaiseFootstepTriggered(SurfaceSoundProfile p, float v) { FootstepTriggered?.Invoke(p, v); }
|
|
|
|
public static void RaiseDied()
|
|
{
|
|
IsDead = true;
|
|
Log(nameof(Died));
|
|
Died?.Invoke();
|
|
DeathChanged?.Invoke(true);
|
|
}
|
|
public static void RaiseRespawned()
|
|
{
|
|
IsDead = false;
|
|
IsCrouching = false;
|
|
IsSliding = false;
|
|
IsSprinting = false;
|
|
Log(nameof(Respawned));
|
|
Respawned?.Invoke();
|
|
DeathChanged?.Invoke(false);
|
|
}
|
|
|
|
public static void RaiseSessionStarting() { Log(nameof(SessionStarting)); SessionStarting?.Invoke(); }
|
|
public static void RaiseSessionStarted(string code)
|
|
{
|
|
IsOnline = true;
|
|
IsHost = true;
|
|
SessionCode = code ?? string.Empty;
|
|
Log(nameof(SessionStarted));
|
|
SessionStarted?.Invoke(SessionCode);
|
|
}
|
|
public static void RaiseSessionJoining(string code)
|
|
{
|
|
SessionCode = code ?? string.Empty;
|
|
Log(nameof(SessionJoining));
|
|
SessionJoining?.Invoke(SessionCode);
|
|
}
|
|
public static void RaiseSessionJoined()
|
|
{
|
|
IsOnline = true;
|
|
IsHost = false;
|
|
Log(nameof(SessionJoined));
|
|
SessionJoined?.Invoke();
|
|
}
|
|
public static void RaiseSessionStopped()
|
|
{
|
|
IsOnline = false;
|
|
IsHost = false;
|
|
SessionCode = string.Empty;
|
|
ResetPlayerState();
|
|
Log(nameof(SessionStopped));
|
|
SessionStopped?.Invoke();
|
|
}
|
|
|
|
// Clears the transient, player-local state so a brand-new session/player starts clean.
|
|
// The static bus tracks the LOCAL player only; without this, dying or opening the
|
|
// inventory and then leaving a session would leave stale flags set for the next one.
|
|
private static void ResetPlayerState()
|
|
{
|
|
IsDead = false;
|
|
IsGrounded = true;
|
|
IsCrouching = false;
|
|
IsSprinting = false;
|
|
IsSliding = false;
|
|
IsOnSlope = false;
|
|
IsInventoryOpen = false;
|
|
IsPaused = false;
|
|
HoveredInteractable = null;
|
|
}
|
|
public static void RaiseSessionError(string reason) { Log(nameof(SessionError)); SessionError?.Invoke(reason); }
|
|
public static void RaiseRemotePlayerCountChanged(int count) { Log(nameof(RemotePlayerCountChanged)); RemotePlayerCountChanged?.Invoke(count); }
|
|
public static void RaiseLocalPlayerSpawned() { Log(nameof(LocalPlayerSpawned)); LocalPlayerSpawned?.Invoke(); }
|
|
|
|
/// <summary>
|
|
/// A friend invited the local player to their session (delivered by Steam). Carries the
|
|
/// inviter's SteamID64, display name, and the connect code used to join their room.
|
|
/// </summary>
|
|
public static void RaiseInviteReceived(ulong inviterSteamId, string inviterName, string connectCode)
|
|
{
|
|
Log(nameof(InviteReceived));
|
|
InviteReceived?.Invoke(inviterSteamId, inviterName, connectCode);
|
|
}
|
|
|
|
[Conditional("PLAYER_EVENT_LOG")]
|
|
private static void Log(string evtName)
|
|
{
|
|
UnityEngine.Debug.Log($"[PlayerEvents] {evtName}");
|
|
}
|
|
}
|
|
|
|
public enum DamageType { Generic, Fall, Starvation, Dehydration, Combat }
|
|
}
|