using System.Collections.Generic; using UnityEngine; using System.Collections; using System; using Hashtable = ExitGames.Client.Photon.Hashtable; /// Finds out which PickupItems are not spawned at the moment and send this to new players. /// Attach this component to a single GameObject in the scene, not to all PickupItems. [RequireComponent(typeof(PhotonView))] public class PickupItemSyncer : Photon.MonoBehaviour { public bool IsWaitingForPickupInit; private const float TimeDeltaToIgnore = 0.2f; public void OnPhotonPlayerConnected(PhotonPlayer newPlayer) { if (PhotonNetwork.isMasterClient) { this.SendPickedUpItems(newPlayer); } } public void OnJoinedRoom() { Debug.Log("Joined Room. isMasterClient: " + PhotonNetwork.isMasterClient + " id: " + PhotonNetwork.player.ID); // this client joined the room. let's see if there are players and if someone has to inform us about pickups this.IsWaitingForPickupInit = !PhotonNetwork.isMasterClient; if (PhotonNetwork.playerList.Length >= 2) { this.Invoke("AskForPickupItemSpawnTimes", 2.0f); } } public void AskForPickupItemSpawnTimes() { if (this.IsWaitingForPickupInit) { if (PhotonNetwork.playerList.Length < 2) { Debug.Log("Cant ask anyone else for PickupItem spawn times."); this.IsWaitingForPickupInit = false; return; } // find a another player (than the master, who likely is gone) to ask for the PickupItem spawn times PhotonPlayer nextPlayer = PhotonNetwork.masterClient.GetNext(); if (nextPlayer == null || nextPlayer.Equals(PhotonNetwork.player)) { nextPlayer = PhotonNetwork.player.GetNext(); //Debug.Log("This player is the Master's next. Asking this client's 'next' player: " + ((nextPlayer != null) ? nextPlayer.ToStringFull() : "")); } if (nextPlayer != null && !nextPlayer.Equals(PhotonNetwork.player)) { this.photonView.RPC("RequestForPickupItems", nextPlayer); // you could restart this invoke and try to find another player after 4 seconds. but after a while it doesnt make a difference anymore //this.Invoke("AskForPickupItemSpawnTimes", 2.0f); } else { Debug.Log("No player left to ask"); this.IsWaitingForPickupInit = false; } } } [PunRPC] [Obsolete("Use RequestForPickupItems(PhotonMessageInfo msgInfo) with corrected typing instead.")] public void RequestForPickupTimes(PhotonMessageInfo msgInfo) { RequestForPickupItems(msgInfo); } [PunRPC] public void RequestForPickupItems(PhotonMessageInfo msgInfo) { if (msgInfo.sender == null) { Debug.LogError("Unknown player asked for PickupItems"); return; } SendPickedUpItems(msgInfo.sender); } /// Summarizes all PickupItem ids and spawn times for new players. Calls RPC "PickupItemInit". /// The player to send the pickup times to. It's a targetted RPC. private void SendPickedUpItems(PhotonPlayer targetPlayer) { if (targetPlayer == null) { Debug.LogWarning("Cant send PickupItem spawn times to unknown targetPlayer."); return; } double now = PhotonNetwork.time; double soon = now + TimeDeltaToIgnore; PickupItem[] items = new PickupItem[PickupItem.DisabledPickupItems.Count]; PickupItem.DisabledPickupItems.CopyTo(items); List valuesToSend = new List(items.Length * 2); for (int i = 0; i < items.Length; i++) { PickupItem pi = items[i]; if (pi.SecondsBeforeRespawn <= 0) { valuesToSend.Add(pi.ViewID); valuesToSend.Add((float)0.0f); } else { double timeUntilRespawn = pi.TimeOfRespawn - PhotonNetwork.time; if (pi.TimeOfRespawn > soon) { // the respawn of this item is not "immediately", so we include it in the message "these items are not active" for the new player Debug.Log(pi.ViewID + " respawn: " + pi.TimeOfRespawn + " timeUntilRespawn: " + timeUntilRespawn + " (now: " + PhotonNetwork.time + ")"); valuesToSend.Add(pi.ViewID); valuesToSend.Add((float)timeUntilRespawn); } } } Debug.Log("Sent count: " + valuesToSend.Count + " now: " + now); this.photonView.RPC("PickupItemInit", targetPlayer, PhotonNetwork.time, valuesToSend.ToArray()); } [PunRPC] public void PickupItemInit(double timeBase, float[] inactivePickupsAndTimes) { this.IsWaitingForPickupInit = false; // if there are no inactive pickups, the sender will send a list of 0 items. this is not a problem... for (int i = 0; i < inactivePickupsAndTimes.Length / 2; i++) { int arrayIndex = i*2; int viewIdOfPickup = (int)inactivePickupsAndTimes[arrayIndex]; float timeUntilRespawnBasedOnTimeBase = inactivePickupsAndTimes[arrayIndex + 1]; PhotonView view = PhotonView.Find(viewIdOfPickup); PickupItem pi = view.GetComponent(); if (timeUntilRespawnBasedOnTimeBase <= 0) { pi.PickedUp(0.0f); } else { double timeOfRespawn = timeUntilRespawnBasedOnTimeBase + timeBase; Debug.Log(view.viewID + " respawn: " + timeOfRespawn + " timeUntilRespawnBasedOnTimeBase:" + timeUntilRespawnBasedOnTimeBase + " SecondsBeforeRespawn: " + pi.SecondsBeforeRespawn); double timeBeforeRespawn = timeOfRespawn - PhotonNetwork.time; if (timeUntilRespawnBasedOnTimeBase <= 0) { timeBeforeRespawn = 0.0f; } pi.PickedUp((float) timeBeforeRespawn); } } } }