using FishNet.Object;
using FishNet.Object.Synchronizing;
using Steamworks;
using UnityEngine;
namespace Ashwild.Network
{
///
/// Announces this player's arrival and departure to every other client's presence feed. Lives on
/// the networked player prefab (like PlayerNameTag) and is NOT owner-gated — remote copies must run
/// it so they can report their own despawn as a "left".
///
/// Join is server-driven: the owner submits its Steam name, the server stores it and fires a
/// one-shot ObserversRpc to whoever is watching right now. Because the RPC isn't buffered, a client
/// joining a busy room never replays the joins that happened before it arrived — no startup burst.
/// Leave is client-detected: when a player's copy despawns (disconnect), each remaining client reads
/// the replicated name and reports it. The feed UI itself suppresses the departure storm that fires
/// when the local player is the one leaving the session.
///
[DisallowMultipleComponent]
public class SessionPresenceNotifier : NetworkBehaviour
{
#region Networked State
///
/// The owner's display name, written by the server so every client can label this player's
/// "left" message once the copy despawns and the owner is already gone.
///
private readonly SyncVar displayName = new SyncVar();
#endregion
#region Network Lifecycle
///
/// On the owning client, publishes the local Steam persona name so the server can announce the join.
///
public override void OnStartClient()
{
base.OnStartClient();
if (!base.IsOwner) return;
if (!SteamManager.Initialized)
{
Debug.LogError($"[SessionPresence] '{name}' — Steam not initialized, cannot announce join.", this);
return;
}
SubmitPresenceServerRpc(SteamFriends.GetPersonaName());
}
///
/// A player's copy is despawning on this client. On non-owner copies that means a remote player
/// left the session, so report it; the owner never reports its own departure. Gated on the local
/// client still running so that OUR own disconnect — which despawns every copy at once — doesn't
/// announce the whole room leaving.
///
public override void OnStopClient()
{
base.OnStopClient();
if (base.IsOwner || !base.IsClientStarted) return;
string playerName = displayName.Value;
if (!string.IsNullOrEmpty(playerName))
SessionPresenceEvents.RaisePlayerLeft(playerName);
}
#endregion
#region Replication
///
/// Server-side: records the owner's name and announces the join once to the current observers.
///
[ServerRpc]
private void SubmitPresenceServerRpc(string persona)
{
displayName.Value = persona;
AnnounceJoinObserversRpc(persona);
}
///
/// Fires on every client observing this player at join time; each reports it to its feed,
/// except the owner who shouldn't be told they joined their own session.
///
[ObserversRpc]
private void AnnounceJoinObserversRpc(string persona)
{
if (base.IsOwner) return;
SessionPresenceEvents.RaisePlayerJoined(persona);
}
#endregion
}
}