// 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> >();
        }
Exemplo n.º 2
0
 void Start()
 {
     ES      = GetComponent <EventSource>();
     View    = GetComponent <PhotonView>();
     Request = new AllPlayersPhotonRequest <int?>()
     {
         View    = View,
         RPCName = "HashCheck",
         DetermineHasReturned = x => x.HasValue,
         SerialiseArgsArray   = false
     };
 }