// TODO Integrate a response timer to gather pings, can send an empty command to gather pings if needed, otherwise piggy back on existing commands // Keep track of and synchronise intervals at the end of which the commands are executed // Intervals are determined by the max ping over all clients // If a client fails to execute a command in the correct interval, it is broadcast that the command must be revert and replayed in the next interval instead // This too must a command that can fail // Must check that the next end of interval is not too close that the confirmation can't make it back in time // If so start a failure early to avoid letting the command sender deal with the failure a step later void Awake() { View = GetComponent <PhotonView>(); EM = GetComponent <EntityManager>() ?? FindObjectOfType <EntityManager>() ?? gameObject.AddComponent <EntityManager>(); ES = GetComponent <EventSource>() ?? FindObjectOfType <EventSource>() ?? gameObject.AddComponent <EventSource>(); NetworkInteractionTracker = new NetworkInteractionTracker(PingIntervalMS, RequestIndividualPlayerPing); IntervalTimer = GetComponent <IntervalTimer>() ?? FindObjectOfType <IntervalTimer>() ?? gameObject.AddComponent <IntervalTimer>(); PUNHasher = GetComponent <PUNHashChecker>() ?? FindObjectOfType <PUNHashChecker>() ?? gameObject.AddComponent <PUNHashChecker>(); PUNESRequester = GetComponent <PUNStateExchanger>() ?? FindObjectOfType <PUNStateExchanger>() ?? gameObject.AddComponent <PUNStateExchanger>(); PUNPauser = GetComponent <PUNGamePauser>() ?? FindObjectOfType <PUNGamePauser>() ?? gameObject.AddComponent <PUNGamePauser>(); PingSimulator = gameObject.AddComponent <PingSimulator>(); PingSimulator.Average = 500; PingSimulator.Variation = 200; //PingSimulator.enabled = false; // To disable // Does not pass value onto the original call, passes null instead which cancels it // The mod is then only applied through the RPC call where the filter is removed DistributeBetweenPlayersAsyncFilter = (e, a) => { if (e != null) { SendMod(e); } a.Invoke(null); }; if (PrintAllMods) { EM.Filters.Add((e, a) => { Debug.Log("Mod applied: " + e.GetType().Name); a.Invoke(e); }); } IntervalTimer.Init(ES, EM, DistributeBetweenPlayersAsyncFilter); IntervalTimer.OnStep += s => { }; DependentRequest = new AllPlayersPhotonRequest <bool>() { View = View, RPCName = "DoEntityDependentModWithConfirmation", DetermineHasReturned = x => x }; IndependentRequest = new AllPlayersPhotonRequest <bool>() { View = View, RPCName = "DoIndependentModWithConfirmation", DetermineHasReturned = x => x }; ReturnModSentByRequestID = new Dictionary <int, Action <int, bool> >(); }
void Start() { ES = GetComponent <EventSource>(); View = GetComponent <PhotonView>(); Request = new AllPlayersPhotonRequest <int?>() { View = View, RPCName = "HashCheck", DetermineHasReturned = x => x.HasValue, SerialiseArgsArray = false }; }