Search Unity

Resolved Every script is being run twice and i don't know why (Photon)

Discussion in 'Scripting' started by joties, Jan 8, 2022.

  1. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    I'm using Photon to create a multiplayer game but something has gone wrong and I don't understand how or why.

    At first I had just a little "game" to try out stuff and get to learn how to use Photon properly.
    The "game" consisted of 3 scenes, the loading scene, the lobby scene and the game scene.
    In the game scene, every player currently in the room would get their own gameobject using:
    Code (CSharp):
    1. PhotonNetwork.Instantiate(playerPrefab.name, spawnPoint, Quaternion.identity);
    It all worked nicely and as intended until a made a few changes to the first 2 scenes.
    I'm not sure what change broke it because I wasn't testing the gamescene when editing the other scenes.

    When i add
    Code (CSharp):
    1. DontDestroyOnLoad(gameObject);
    to the scripts, 2 instances get created, so I'm assuming the initial instance gets deleted after it ran its code and then another gets created but I have no idea why.

    I use
    Code (CSharp):
    1. PhotonNetwork.Loadlevel(2)
    to transition into the game scene.
    The only selfmade script that is inside the scene is the player instantiation script.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Photon.Pun;
    5.  
    6. public class InstantiatePlayers : MonoBehaviour {
    7.     [SerializeField] private GameObject playerPrefab;
    8.  
    9.     private void Start() {
    10.         Vector2 spawnPoint = new Vector2(0, 0);
    11.         GameObject player = PhotonNetwork.Instantiate(playerPrefab.name, spawnPoint, Quaternion.identity);
    12.         Debug.Log("player instantiated: " + player);
    13.     }
    14. }
    I have no idea of any of what I just said is correct or even makes any sense.
    My miniscule brain isn't big enough to understand what the problem is so I'm asking you all for a little guidance

    Thanks in advance <3
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    When you do this, it just means it won't be destroyed when you change scenes.

    One would never actually "just do" the above except as part of a specific plan to adjust object lifetimes.

    It will be necessary for you to reason about the lifetime of objects involved in your game.

    This means you should be able to answer:

    - who instantiates various parts of the game (you? networking code? already in scene?)
    - how long should those things stick around (just this scene? forever? the length of the game?)

    It may be appropriate to mark certain of them as DontDestroyOnLoad() but the reason will be related to wanting an object to survive a full scene change.
     
  3. Deleted User

    Deleted User

    Guest

    Checkout Unity's stuff in relation to Photon as it might be useful.

    https://learn.unity.com/tutorial/setting-up-photon-unity-networking
    https://learn.unity.com/tutorial/configuring-object-ownership-in-networked-photon-applications
    https://learn.unity.com/tutorial/configuring-photon-rigidbody-views
    https://learn.unity.com/tutorial/configuring-photon-transform-views


    If you're not sure what something does you can often Google "Unity + thing" and it will get you to the docs. For example, if you Googled "Unity DontDestroyOnLoad" the first page shows the documentation, which itself provides a description.

    https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html

    "Do not destroy the target Object when loading a new scene".

    Have you followed the Photon tutorials?

    https://doc.photonengine.com/en-us/pun/current/demos-and-tutorials/pun-basics-tutorial/intro
     
  4. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    DontDestroyOnLoad is'nt actually part of the code I added it purely for testing purposes.
    I was really just trying anything that might tell me what the problem is and how to fix it
     
  5. Deleted User

    Deleted User

    Guest

    I'm not sure what your issue is then? Your issue only exists when you added the code for testing purposes or am I missing something.

    The issue is that two instances exist, right?... but this only happened after you added DontDestroyOnLoad to the script (which itself would not cause this issue because that's not how DontDestroyOnLoad works). But you only added that for testing purposes. So if you remove the test code does the issue still persist?

    I honestly think you should look at the links I provided and go through the tutorials/examples/walkthroughs to improve your understanding on how to use unity and photon together.
     
  6. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    The issue is that ever script gets ran twice.
    For example, if i have just a single script on an otherwise empty object with just a simple Debug.Log("test");
    I get "test" inside my console twice.
     
  7. Deleted User

    Deleted User

    Guest

    Even if you're not using photon? Just a simple script like this produces the same result?


    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. public class ExampleClass : MonoBehaviour
    5. {
    6.     private void Awake()
    7.     {
    8.         Debug.Log("test");
    9.     }
    10. }
    If so then that's not normal. You might have found a bug but I just checked and cant repro it myself. You sure the script isn't attached to anything else? otherwise it could be the other code that isn't yours doing something weird.
     
  8. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    I created a brand new gameobject and added a brand new script to it with the code in your reply inside.
    its still happened twice.
    Even after creating a new scene it still happened.
    I guess the problem is in the lobby scene I'm just not sure where.
     
  9. Deleted User

    Deleted User

    Guest

    You would need to either include additional scripts for anyone to be able to help figure it out or...

    1) Are you following a tutorial? if so just start from the beginning and go a bit slower.

    2) If you're just trying to yolo a multiplayer system together I would recommend reconsidering and using the provided tutorials and examples by both Unity and Photon or you're just going to run into another issue after a few hours.
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Don't use just that. Leverage everything it can do.

    Find the name out:

    Debug.Log("test" + name);


    And while you're at it, find the object itself:

    Debug.Log("test" + name, gameObject);


    Now do a
    Debug.Break();
    immediately after it.

    Now when the editor pauses, do NOT press STOP. Leaving the game running, go into the console and click each "test" entry. Look at which GameObject lights up in the scene.
     
  11. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    362
    It sounds as if you are creating a GameObject with DoNotDestroyOnLoad in the Lobby scene and thus it is carrying over to the Game scene
     
  12. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    This is the lobby script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6. using Photon.Pun;
    7. using Photon.Realtime;
    8.  
    9. public class LobbyManager : MonoBehaviourPunCallbacks {
    10.     public static LobbyManager instance;
    11.  
    12.     [SerializeField] private GameObject lobbyPanel;
    13.     [SerializeField] private InputField createInput;
    14.  
    15.     [SerializeField] private RoomItem roomItemPrefab;
    16.     [SerializeField] private Transform contentObject;
    17.     private List<RoomItem> roomItemsList = new List<RoomItem>();
    18.  
    19.     [SerializeField] private GameObject roomPanel;
    20.     [SerializeField] private Text roomName;
    21.  
    22.     [SerializeField] private PlayerItem playerItemPrefab;
    23.     [SerializeField] private Transform playerItemParent;
    24.     public List<PlayerItem> playerItems = new List<PlayerItem>();
    25.  
    26.     [SerializeField] private float timeBetweenUpdates;
    27.     private float nextUpdateTime;
    28.  
    29.     [SerializeField] private GameObject countdownScreen;
    30.  
    31.     private void Awake() {
    32.         instance = this;
    33.     }
    34.  
    35.     private void Start() {
    36.         PhotonNetwork.JoinLobby();
    37.     }
    38.  
    39.     private void Update() {
    40.         if (PhotonNetwork.LocalPlayer.ActorNumber != -1) {
    41.             if (PhotonNetwork.CurrentRoom.PlayerCount == PhotonNetwork.CurrentRoom.MaxPlayers) {
    42.                 StartCoroutine(StartCountdown());
    43.             }
    44.         }
    45.     }
    46.  
    47.     public void CreateRoom() {
    48.         if (createInput.text.Length >= 1) {
    49.             PhotonNetwork.CreateRoom(createInput.text, new RoomOptions() { MaxPlayers = 1} );
    50.         }
    51.     }
    52.  
    53.     public void JoinRoom(string _roomName) {
    54.         PhotonNetwork.JoinRoom(_roomName);
    55.     }
    56.  
    57.     public void OnClickLeaveRoom() {
    58.         PhotonNetwork.LeaveRoom();
    59.     }
    60.  
    61.     private void UpdateRoomList(List<RoomInfo> _list) {
    62.         foreach (RoomItem _item in roomItemsList) {
    63.             Destroy(_item.gameObject);
    64.         }
    65.         roomItemsList.Clear();
    66.  
    67.         foreach (RoomInfo _room in _list) {
    68.             RoomItem newRoom = Instantiate(roomItemPrefab, contentObject);
    69.             newRoom.SetRoomName(_room.Name);
    70.             roomItemsList.Add(newRoom);
    71.         }
    72.     }
    73.  
    74.     public override void OnRoomListUpdate(List<RoomInfo> _roomList) {
    75.         if (Time.time >= nextUpdateTime) {
    76.             UpdateRoomList(_roomList);
    77.             nextUpdateTime = Time.time + timeBetweenUpdates;
    78.         }
    79.     }
    80.  
    81.     private void UpdatePlayerList() {
    82.         foreach (PlayerItem _item in playerItems) {
    83.             Destroy(_item.gameObject);
    84.         }
    85.         playerItems.Clear();
    86.  
    87.         if (PhotonNetwork.CurrentRoom == null) {
    88.             return;
    89.         }
    90.  
    91.         foreach (KeyValuePair<int, Player> _player in PhotonNetwork.CurrentRoom.Players) {
    92.             PlayerItem playerItem = Instantiate(playerItemPrefab, playerItemParent);
    93.             playerItem.SetPlayerInfo(_player.Value);
    94.             playerItems.Add(playerItem);
    95.         }
    96.     }
    97.  
    98.     private IEnumerator StartCountdown() {
    99.         countdownScreen.SetActive(true);
    100.  
    101.         float countdownTimer = 5f;
    102.         while (countdownTimer > -0.5) {
    103.             countdownTimer -= Time.deltaTime;
    104.  
    105.             countdownScreen.GetComponentInChildren<Text>().text = "" + (Mathf.CeilToInt(countdownTimer));
    106.  
    107.             yield return null;
    108.         }
    109.  
    110.         StartGame();
    111.     }
    112.  
    113.  
    114.     // This is where the game scene gets loaded //
    115.     private void StartGame() {
    116.         PhotonNetwork.LoadLevel(2);
    117.     }
    118.  
    119.  
    120.     public override void OnJoinedRoom() {
    121.         lobbyPanel.SetActive(false);
    122.         roomPanel.SetActive(true);
    123.         roomName.text = "Room: " + PhotonNetwork.CurrentRoom.Name;
    124.  
    125.         UpdatePlayerList();
    126.  
    127.     }
    128.  
    129.     public override void OnLeftRoom() {
    130.         roomPanel.SetActive(false);
    131.         lobbyPanel.SetActive(true);
    132.     }
    133.  
    134.     public override void OnPlayerEnteredRoom(Player newPlayer) {
    135.         UpdatePlayerList();
    136.     }
    137.  
    138.     public override void OnPlayerLeftRoom(Player newPlayer) {
    139.         UpdatePlayerList();
    140.  
    141.         StopCoroutine(StartCountdown());
    142.         countdownScreen.SetActive(false);
    143.     }
    144.  
    145.     public override void OnConnectedToMaster() {
    146.         PhotonNetwork.JoinLobby();
    147.     }
    148. }
    149.  
    P.S. Thanks for all the help and sorry for being so unclear <3
     
  13. Deleted User

    Deleted User

    Guest

    ^

    Try debugging some specific info at different stages (when a player joins a room, on start, etc). I can't see anything obvious that would cause an issue to be honest.

    What happens if you leave the scene empty and run the game? If "nothing" then it's definitely something to do with how you are creating players. The debug log statements should help you pinpoint where the first duplicate debug log happens.
     
  14. joties

    joties

    Joined:
    Aug 26, 2020
    Posts:
    6
    I think I fixed it!!
    What I'm assuming happened, is because the moment there are enough players every frame is starting a new countdown coroutine (because its in update) which causes the the level to be loaded 2 times quickly after each other making every script run twice.

    This also explains why when an object is in "DontDestroyOnLoad" 2 instances exist and without it only 1.

    Even if this is not the reason of the error, the check to see if there is already a countdown coroutine running managed to fix it.

    Thank you all for you help and have a great day <3
     
  15. TKDHayk

    TKDHayk

    Joined:
    Dec 22, 2015
    Posts:
    131
    to the OP:

    if you have 2 instances of the game (eg a host (player1 )and a client (player2)), every script in your scene will run 2X since... there are 2 instances of the game.