You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RizzeProjectile/Assets/Scripts/Utilities/NetworkObjectBuffer.cs

158 lines
3.6 KiB
C#

using Fusion;
using UnityEngine;
namespace Projectiles
{
/// <summary>
/// Pre-spawns network object in advance so they can be immediately used on Input Authority without a spawn delay.
/// </summary>
public class NetworkObjectBuffer : NetworkBehaviour
{
// CONSTANTS
public const int CAPACITY = 8;
// PRIVATE MEMBERS
[SerializeField]
private NetworkObject _prefab;
[SerializeField, Range(1, CAPACITY)]
private int _bufferSize = CAPACITY;
[Networked, Capacity(CAPACITY)]
private NetworkArray<NetworkObject> _buffer { get; }
[Networked]
private int _bufferHead { get; set; }
private NetworkObject[] _localBuffer = new NetworkObject[CAPACITY];
// PUBLIC METHODS
public T Get<T>(Vector3 position, Quaternion rotation, PlayerRef inputAuthority) where T : NetworkBehaviour
{
var instance = Get(position, rotation, inputAuthority);
return instance != null ? instance.GetComponent<T>() : null;
}
public NetworkObject Get(Vector3 position, Quaternion rotation, PlayerRef inputAuthority)
{
var instance = _buffer[_bufferHead];
if (instance == null)
return null;
Runner.SetIsSimulated(instance, true);
instance.AssignInputAuthority(inputAuthority);
instance.transform.SetPositionAndRotation(position, rotation);
instance.gameObject.SetActive(true);
_buffer.Set(_bufferHead, null);
FillBuffer();
_bufferHead = (_bufferHead + 1) % _bufferSize;
return instance;
}
public override void Spawned()
{
FillBuffer();
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
ClearBuffer();
}
public override void Render()
{
if (HasStateAuthority == true)
return;
for (int i = 0; i < _bufferSize; i++)
{
var networkInstance = _buffer[i];
var localInstance = _localBuffer[i];
if (localInstance == networkInstance)
continue;
if (localInstance != null && localInstance.IsValid == true)
{
// Network instance was released so we need to activate
// object on all clients (including proxies) not only
// on those where Get method was called
localInstance.gameObject.SetActive(true);
#if UNITY_EDITOR
localInstance.name = _prefab.name;
#endif
}
_localBuffer[i] = networkInstance;
if (networkInstance != null)
{
// New instance was added to the buffer, we need to make sure
// that the object is inactive on all clients (including proxies)
networkInstance.gameObject.SetActive(false);
#if UNITY_EDITOR
networkInstance.name = $"(Buffered) {networkInstance.name}";
#endif
}
//var localName = localInstance != null ? localInstance.Id.ToString(): "null";
//var remoteName = networkInstance != null ? networkInstance.Id.ToString() : "null";
//Debug.Log($"{Runner.name} - {Object.InputAuthority} ({Time.frameCount}) - Changing local buffer on index {i} Local {localName} Network {remoteName}");
}
}
// PRIVATE METHODS
private void FillBuffer()
{
if (HasStateAuthority == false)
return;
for (int i = 0; i < _bufferSize; i++)
{
if (_buffer[i] == null)
{
_buffer.Set(i, PrepareInstance());
}
}
}
private void ClearBuffer()
{
if (HasStateAuthority == false)
{
_localBuffer.Clear();
return;
}
for (int i = 0; i < _bufferSize; i++)
{
if (_buffer[i] != null)
{
Runner.Despawn(_buffer[i]);
}
}
_buffer.Clear();
}
private NetworkObject PrepareInstance()
{
var instance = Runner.Spawn(_prefab, new Vector3(0f, -1000f, 0f));
Runner.SetIsSimulated(instance, false);
instance.gameObject.SetActive(false);
return instance;
}
}
}