using System;
using System.Collections.Generic;
using UnityEngine;
using MLAPI.Messaging;
namespace MLAPI.RuntimeTests
{
///
/// Used in conjunction with the RpcQueueTest to validate:
/// - Sending and Receiving pipeline to validate that both sending and receiving pipelines are functioning properly.
/// - Usage of the ServerRpcParams.Send.UpdateStage and ClientRpcParams.Send.UpdateStage functionality.
/// - Rpcs receive will be invoked at the appropriate NetworkUpdateStage.
///
public class RpcPipelineTestComponent : NetworkBehaviour
{
///
/// Allows the external RPCQueueTest to begin testing or stop it
///
public bool PingSelfEnabled;
///
/// How many times will we iterate through the various NetworkUpdateStage values?
/// (defaults to 2)
///
public int MaxIterations = 2;
// Start is called before the first frame update
private void Start()
{
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Initialization;
m_ClientParams.Send.UpdateStage = NetworkUpdateStage.Update;
m_ServerParams.Receive.UpdateStage = NetworkUpdateStage.Initialization;
m_ClientParams.Receive.UpdateStage = NetworkUpdateStage.Initialization;
m_MaxStagesSent = (Enum.GetValues(typeof(NetworkUpdateStage)).Length) * MaxIterations;
//Start out with this being true (for first sequence)
m_ClientReceivedRpc = true;
}
///
/// Determine if we have iterated over more than our maximum stages we want to test
///
/// true or false (did we exceed the max iterations or not?)
public bool ExceededMaxIterations()
{
if (m_StagesSent.Count > m_MaxStagesSent && m_MaxStagesSent > 0)
{
return true;
}
return false;
}
///
/// Returns back whether the test has completed the total number of iterations
///
///
public bool IsTestComplete()
{
if (m_Counter >= MaxIterations)
{
return true;
}
return false;
}
private bool m_ClientReceivedRpc;
private int m_Counter = 0;
private int m_MaxStagesSent = 0;
private ServerRpcParams m_ServerParams;
private ClientRpcParams m_ClientParams;
private NetworkUpdateStage m_LastUpdateStage;
// Update is called once per frame
private void Update()
{
if (NetworkManager.Singleton.IsListening && PingSelfEnabled && m_ClientReceivedRpc)
{
//Reset this for the next sequence of rpcs
m_ClientReceivedRpc = false;
//As long as testing isn't completed, keep testing
if (!IsTestComplete() && m_StagesSent.Count < m_MaxStagesSent)
{
m_LastUpdateStage = m_ServerParams.Send.UpdateStage;
m_StagesSent.Add(m_LastUpdateStage);
PingMySelfServerRpc(m_StagesSent.Count, m_ServerParams);
switch (m_ServerParams.Send.UpdateStage)
{
case NetworkUpdateStage.Initialization:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.EarlyUpdate;
break;
case NetworkUpdateStage.EarlyUpdate:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.FixedUpdate;
break;
case NetworkUpdateStage.FixedUpdate:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PreUpdate;
break;
case NetworkUpdateStage.PreUpdate:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Update;
break;
case NetworkUpdateStage.Update:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PreLateUpdate;
break;
case NetworkUpdateStage.PreLateUpdate:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.PostLateUpdate;
break;
case NetworkUpdateStage.PostLateUpdate:
m_ServerParams.Send.UpdateStage = NetworkUpdateStage.Initialization;
break;
}
}
}
}
private readonly List m_ServerStagesReceived = new List();
private readonly List m_ClientStagesReceived = new List();
private readonly List m_StagesSent = new List();
///
/// Assures all update stages were in alginment with one another
///
/// true or false
public bool ValidateUpdateStages()
{
var validated = false;
if (m_ServerStagesReceived.Count == m_ClientStagesReceived.Count && m_ClientStagesReceived.Count == m_StagesSent.Count)
{
for (int i = 0; i < m_StagesSent.Count; i++)
{
var currentStage = m_StagesSent[i];
if (m_ServerStagesReceived[i] != currentStage)
{
Debug.Log($"ServerRpc Update Stage ({m_ServerStagesReceived[i]}) is not equal to the current update stage ({currentStage})");
return validated;
}
if (m_ClientStagesReceived[i] != currentStage)
{
Debug.Log($"ClientRpc Update Stage ({m_ClientStagesReceived[i]}) is not equal to the current update stage ({currentStage})");
return validated;
}
}
validated = true;
}
return validated;
}
///
/// Server side RPC for testing
///
/// server rpc parameters
[ServerRpc]
private void PingMySelfServerRpc(int currentCount, ServerRpcParams parameters = default)
{
Debug.Log($"{nameof(PingMySelfServerRpc)}: [HostClient][ServerRpc][{currentCount}] invoked during the {parameters.Receive.UpdateStage} stage.");
m_ClientParams.Send.UpdateStage = parameters.Receive.UpdateStage;
m_ServerStagesReceived.Add(parameters.Receive.UpdateStage);
PingMySelfClientRpc(currentCount, m_ClientParams);
}
///
/// Client Side RPC called by PingMySelfServerRPC to validate both Client->Server and Server-Client pipeline is working
///
/// client rpc parameters
[ClientRpc]
private void PingMySelfClientRpc(int currentCount, ClientRpcParams parameters = default)
{
Debug.Log($"{nameof(PingMySelfClientRpc)}: [HostServer][ClientRpc][{currentCount}] invoked during the {parameters.Receive.UpdateStage} stage. (previous output line should confirm this)");
m_ClientStagesReceived.Add(parameters.Receive.UpdateStage);
//If we reached the last update state, then go ahead and increment our iteration counter
if (parameters.Receive.UpdateStage == NetworkUpdateStage.PostLateUpdate)
{
m_Counter++;
}
m_ClientReceivedRpc = true;
}
}
}