using System; using System.Threading; using Cysharp.Threading.Tasks; using RebootKit.Engine.Foundation; using RebootKit.Engine.Main; using RebootKit.Engine.Simulation; using Unity.Netcode; namespace RebootKit.Engine.Network { public abstract class NetworkPlayerController : NetworkBehaviour { static readonly Logger s_Logger = new Logger(nameof(NetworkPlayerController)); ulong m_ActorIDToPossess; public Actor PossessedActor { get; private set; } public void PossessActor(Actor actor) { if (!IsServer) { s_Logger.Error("PossessActor can only be called on the server."); return; } if (actor == null) { s_Logger.Error("Cannot possess a null actor."); return; } PossessActorRpc(actor.ActorID, RpcTarget.Everyone); } [Rpc(SendTo.SpecifiedInParams)] void PossessActorRpc(ulong actorID, RpcParams rpcParams) { if (PossessedActor is not null) { OnUnpossessActor(PossessedActor); } WaitForActorToSpawnThenPossessAsync(actorID, destroyCancellationToken).Forget(); } async UniTask WaitForActorToSpawnThenPossessAsync(ulong actorID, CancellationToken cancellationToken) { Actor actor = null; while (actor == null) { actor = RR.FindSpawnedActor(actorID); await UniTask.WaitForSeconds(0.5f, cancellationToken: cancellationToken); if (cancellationToken.IsCancellationRequested) { return; } } PossessedActor = actor; OnPossessActor(actor); } public void UnPossessActor() { if (!IsServer) { s_Logger.Error("UnPossessActor can only be called on the server."); return; } if (PossessedActor == null) { return; } UnPossessActorRpc(RpcTarget.Everyone); } [Rpc(SendTo.SpecifiedInParams)] void UnPossessActorRpc(RpcParams rpcParams) { if (PossessedActor is not null) { OnUnpossessActor(PossessedActor); PossessedActor = null; } } protected virtual void OnPossessActor(Actor actor) { } protected virtual void OnUnpossessActor(Actor actor) { } } }