287 lines
7.3 KiB
C#
287 lines
7.3 KiB
C#
namespace TPSBR
|
|
{
|
|
using UnityEngine;
|
|
using Fusion;
|
|
using Fusion.Addons.InterestManagement;
|
|
|
|
public struct PlayerStatistics : INetworkStruct
|
|
{
|
|
public PlayerRef PlayerRef;
|
|
public short ExtraLives;
|
|
public short Kills;
|
|
public short Deaths;
|
|
public short Score;
|
|
public TickTimer RespawnTimer;
|
|
public byte Position;
|
|
|
|
public byte KillsInRow;
|
|
public TickTimer KillsInRowCooldown;
|
|
public byte KillsWithoutDeath;
|
|
|
|
public bool IsValid => PlayerRef.IsRealPlayer;
|
|
public bool IsAlive { get { return _flags.IsBitSet(0); } set { _flags.SetBit(0, value); } }
|
|
public bool IsEliminated { get { return _flags.IsBitSet(1); } set { _flags.SetBit(1, value); } }
|
|
|
|
private byte _flags;
|
|
}
|
|
|
|
public sealed class Player : PlayerInterestManager, IPlayer, IContextBehaviour
|
|
{
|
|
// PUBLIC MEMBERS
|
|
|
|
public string UserID { get; private set; }
|
|
public string UnityID { get; private set; }
|
|
public string Nickname { get; private set; }
|
|
public SceneContext Context { get; set; }
|
|
public bool IsInitialized => _initCounter <= 0;
|
|
|
|
[Networked]
|
|
public Agent ActiveAgent { get; private set; }
|
|
[Networked]
|
|
public NetworkPrefabRef AgentPrefab { get; set; }
|
|
[Networked]
|
|
public PlayerStatistics Statistics { get; private set; }
|
|
|
|
// PRIVATE MEMBERS
|
|
|
|
[Networked]
|
|
private byte SyncToken { get; set; }
|
|
[Networked]
|
|
private NetworkString<_64> NetworkedUserID { get; set; }
|
|
[Networked]
|
|
private NetworkString<_32> NetworkedNickname { get; set; }
|
|
|
|
private byte _syncToken;
|
|
private Agent _activeAgent;
|
|
private PlayerRef _observePlayer;
|
|
private Vector3 _lastViewPosition;
|
|
private Vector3 _lastViewDirection;
|
|
private Agent _platformAgent;
|
|
private bool _playerDataSent;
|
|
private int _initCounter;
|
|
|
|
// PUBLIC METHODS
|
|
|
|
public void SetActiveAgent(Agent agent)
|
|
{
|
|
ActiveAgent = agent;
|
|
|
|
UpdateLocalState();
|
|
}
|
|
|
|
public void DespawnAgent()
|
|
{
|
|
if (Runner.IsServer == false)
|
|
return;
|
|
|
|
if (ActiveAgent != null && ActiveAgent.Object != null)
|
|
{
|
|
Runner.Despawn(ActiveAgent.Object);
|
|
ActiveAgent = null;
|
|
_activeAgent = null;
|
|
_platformAgent = null;
|
|
}
|
|
}
|
|
|
|
public void UpdateStatistics(PlayerStatistics statistics)
|
|
{
|
|
Statistics = statistics;
|
|
}
|
|
|
|
public void SetObservedPlayer(PlayerRef playerRef)
|
|
{
|
|
if (playerRef.IsRealPlayer == false)
|
|
{
|
|
playerRef = Object.InputAuthority;
|
|
}
|
|
|
|
if (playerRef == _observePlayer)
|
|
return;
|
|
|
|
RPC_SetObservedPlayer(playerRef);
|
|
}
|
|
|
|
public void Refresh()
|
|
{
|
|
PlayerStatistics statistics = Statistics;
|
|
statistics.PlayerRef = Object.InputAuthority;
|
|
Statistics = statistics;
|
|
}
|
|
|
|
public void OnReconnect(Player newPlayer)
|
|
{
|
|
UserID = newPlayer.UserID;
|
|
Nickname = newPlayer.Nickname;
|
|
NetworkedUserID = newPlayer.NetworkedUserID;
|
|
NetworkedNickname = newPlayer.NetworkedNickname;
|
|
AgentPrefab = newPlayer.AgentPrefab;
|
|
UnityID = newPlayer.UnityID;
|
|
}
|
|
|
|
// PlayerInterestManager INTERFACE
|
|
|
|
protected override void OnSpawned()
|
|
{
|
|
_syncToken = default;
|
|
_activeAgent = ActiveAgent;
|
|
_observePlayer = Object.InputAuthority;
|
|
_playerDataSent = false;
|
|
_initCounter = 10;
|
|
|
|
if (HasInputAuthority == true)
|
|
{
|
|
Context.LocalPlayerRef = Object.InputAuthority;
|
|
}
|
|
|
|
UpdateLocalState();
|
|
|
|
Runner.SetIsSimulated(Object, true);
|
|
}
|
|
|
|
protected override void OnDespawned(NetworkRunner runner, bool hasState)
|
|
{
|
|
DespawnAgent();
|
|
}
|
|
|
|
protected override void OnFixedUpdateNetwork()
|
|
{
|
|
UpdateLocalState();
|
|
|
|
if (_syncToken != default && Runner.IsForward == true)
|
|
{
|
|
_initCounter = Mathf.Max(0, _initCounter - 1);
|
|
}
|
|
|
|
if (IsProxy == true)
|
|
return;
|
|
|
|
var observedAgent = ActiveAgent;
|
|
|
|
var observedPlayer = Context.NetworkGame.GetPlayer(_observePlayer);
|
|
if (observedPlayer != null && observedPlayer.ActiveAgent != null && observedPlayer.ActiveAgent.Object != null)
|
|
{
|
|
observedAgent = observedPlayer.ActiveAgent;
|
|
}
|
|
|
|
var observedPlayerRef = observedAgent != null ? observedAgent.Object.InputAuthority : Object.InputAuthority;
|
|
|
|
if (HasStateAuthority == true)
|
|
{
|
|
ObservedPlayer = observedPlayerRef;
|
|
}
|
|
|
|
if (HasInputAuthority == true)
|
|
{
|
|
Context.ObservedAgent = observedAgent;
|
|
Context.ObservedPlayerRef = observedPlayerRef;
|
|
Context.LocalPlayerRef = Object.InputAuthority;
|
|
|
|
if (_playerDataSent == false && Runner.IsForward == true && Context.PlayerData != null)
|
|
{
|
|
var unityID = Context.PlayerData.UnityID != null ? Context.PlayerData.UnityID : string.Empty;
|
|
|
|
RPC_SendPlayerData(Context.PeerUserID, Context.PlayerData.Nickname, Context.PlayerData.AgentPrefab, unityID);
|
|
_playerDataSent = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool CanUpdatePlayerInterest(bool isUpdateRequested)
|
|
{
|
|
if (isUpdateRequested == true)
|
|
return true;
|
|
|
|
int interlacing = 50;
|
|
int currentTick = Runner.Tick;
|
|
|
|
if ((currentTick - LastUpdateTick) >= interlacing)
|
|
{
|
|
if ((currentTick % interlacing) == (Player.AsIndex % interlacing))
|
|
return true;
|
|
}
|
|
|
|
if (TryGetObservedPlayerView(out PlayerInterestView observedPlayerView) == true)
|
|
{
|
|
if (Vector3.SqrMagnitude(_lastViewPosition - observedPlayerView.CameraPosition) > 4.0f) // 2 meter distance change
|
|
return true;
|
|
if (Vector3.Dot(_lastViewDirection, observedPlayerView.CameraDirection) < 0.99f) // Roughly 8 degrees change
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected override void AfterPlayerInterestUpdate(bool success, PlayerInterestView playerView)
|
|
{
|
|
if (success == true)
|
|
{
|
|
_lastViewPosition = playerView.CameraPosition;
|
|
_lastViewDirection = playerView.CameraDirection;
|
|
}
|
|
}
|
|
|
|
// PRIVATE METHODS
|
|
|
|
private void UpdateLocalState()
|
|
{
|
|
if (_activeAgent != ActiveAgent)
|
|
{
|
|
_activeAgent = ActiveAgent;
|
|
_observePlayer = Object.InputAuthority;
|
|
|
|
if (_activeAgent != null)
|
|
{
|
|
InterestView = _activeAgent.InterestView;
|
|
}
|
|
}
|
|
|
|
if (_syncToken != SyncToken)
|
|
{
|
|
_syncToken = SyncToken;
|
|
|
|
UserID = NetworkedUserID.Value;
|
|
Nickname = NetworkedNickname.Value;
|
|
}
|
|
|
|
if (ReferenceEquals(_platformAgent, _activeAgent) == false && _activeAgent != null)
|
|
{
|
|
if (_activeAgent.Character.CharacterController.IsSpawned == true)
|
|
{
|
|
BRPlatformProcessor platformProcessor = GetComponent<BRPlatformProcessor>();
|
|
_activeAgent.Character.CharacterController.AddLocalProcessor(platformProcessor);
|
|
_platformAgent = _activeAgent;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority, Channel = RpcChannel.Reliable)]
|
|
private void RPC_SendPlayerData(string userID, string nickname, NetworkPrefabRef agentPrefab, string unityID)
|
|
{
|
|
#if UNITY_EDITOR
|
|
nickname += $" {Object.InputAuthority}";
|
|
#endif
|
|
|
|
++SyncToken;
|
|
if (SyncToken == default)
|
|
{
|
|
SyncToken = 1;
|
|
}
|
|
|
|
_syncToken = SyncToken;
|
|
|
|
UserID = userID;
|
|
Nickname = nickname;
|
|
NetworkedUserID = userID;
|
|
NetworkedNickname = nickname;
|
|
AgentPrefab = agentPrefab;
|
|
UnityID = unityID;
|
|
}
|
|
|
|
[Rpc(RpcSources.StateAuthority | RpcSources.InputAuthority, RpcTargets.StateAuthority | RpcTargets.InputAuthority, Channel = RpcChannel.Reliable)]
|
|
private void RPC_SetObservedPlayer(PlayerRef player)
|
|
{
|
|
_observePlayer = player;
|
|
}
|
|
}
|
|
}
|