Files
Emberwild/Assets/GAME/Script/Network/SessionPresenceNotifier.cs
2026-07-04 09:33:53 +02:00

98 lines
3.6 KiB
C#

using FishNet.Object;
using FishNet.Object.Synchronizing;
using Steamworks;
using UnityEngine;
namespace Ashwild.Network
{
/// <summary>
/// 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.
/// </summary>
[DisallowMultipleComponent]
public class SessionPresenceNotifier : NetworkBehaviour
{
#region Networked State
/// <summary>
/// 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.
/// </summary>
private readonly SyncVar<string> displayName = new SyncVar<string>();
#endregion
#region Network Lifecycle
/// <summary>
/// On the owning client, publishes the local Steam persona name so the server can announce the join.
/// </summary>
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());
}
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// Server-side: records the owner's name and announces the join once to the current observers.
/// </summary>
[ServerRpc]
private void SubmitPresenceServerRpc(string persona)
{
displayName.Value = persona;
AnnounceJoinObserversRpc(persona);
}
/// <summary>
/// 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.
/// </summary>
[ObserversRpc]
private void AnnounceJoinObserversRpc(string persona)
{
if (base.IsOwner) return;
SessionPresenceEvents.RaisePlayerJoined(persona);
}
#endregion
}
}