using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Logging; using FishNet.Managing.Server; using FishNet.Object; using FishNet.Object.Synchronizing; using UnityEngine; namespace FishNet.Component.Ownership { /// /// Adding this component allows any client to take ownership of the object and begin modifying it immediately. /// public class PredictedOwner : NetworkBehaviour { #region Public. /// /// True if the local client used TakeOwnership and is awaiting an ownership change. /// public bool TakingOwnership { get; private set; } /// /// Owner on client prior to taking ownership. This can be used to reverse a failed ownership attempt. /// public NetworkConnection PreviousOwner { get; private set; } = NetworkManager.EmptyConnection; #endregion #region Serialized. /// /// True if to enable this component. /// [Tooltip("True if to enable this component.")] [SyncVar(SendRate = 0f)] [SerializeField] private bool _allowTakeOwnership = true; /// /// Sets the next value for AllowTakeOwnership and synchronizes it. /// Only the server may use this method. /// /// Next value to use. [Server] public void SetAllowTakeOwnership(bool value) => _allowTakeOwnership = value; #endregion /// /// Called on the client after gaining or losing ownership. /// /// Previous owner of this object. public override void OnOwnershipClient(NetworkConnection prevOwner) { base.OnOwnershipClient(prevOwner); /* Unset taken ownership either way. * If the new owner it won't be used, * if no longer owner then another client * took it. */ TakingOwnership = false; PreviousOwner = base.Owner; } /// /// Takes ownership of this object to the local client and allows immediate control. /// [Client] public virtual void TakeOwnership() { if (!_allowTakeOwnership) return; //Already owner. if (base.IsOwner) return; NetworkConnection c = base.ClientManager.Connection; TakingOwnership = true; //If not server go through the server. if (!base.IsServer) { base.NetworkObject.SetLocalOwnership(c); ServerTakeOwnership(); } //Otherwise take directly without rpcs. else { OnTakeOwnership(c); } } /// /// Takes ownership of this object. /// [ServerRpc(RequireOwnership = false)] private void ServerTakeOwnership(NetworkConnection caller = null) { OnTakeOwnership(caller); } /// /// Called on the server when a client tries to take ownership of this object. /// /// Connection trying to take ownership. [Server] protected virtual void OnTakeOwnership(NetworkConnection caller) { //Client somehow disconnected between here and there. if (!caller.IsActive) return; //Feature is not enabled. if (!_allowTakeOwnership) return; //Already owner. if (caller == base.Owner) return; base.GiveOwnership(caller); /* No need to send a response back because an ownershipchange will handle changes. * Although if you were to override with this your own behavior * you could send responses for approved/denied. */ } } }