98 lines
3.6 KiB
C#
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
|
|
}
|
|
}
|