Character Duplicate, Start Game when players are ready and nonrestrictive spawn.

This is my game logic:

- player joins game,
- finds and enters a room
- when room master clicks on start room, all player who has a player.customprop[IS_READ]

should load into a new scene(eg: MAP), with master. (more like you have to be ready to join a game even though you are in the room).

And if the game has already started and you ready up, the MAP will be loaded for you.




I have 2 main issues:

- when 1 spawn player, it duplicated it to the number of clients in the room (if i have 2 player, i will end up with 4 characters being spawn, and if i have 3 clients ready i will end up having 9 characters spawned).

- When game have started, and a new client join, photon actually spawns the characters in lobbby after PhotonNetwork.JoinRoom(roomName); not in MAP


psudo code
:RoomsCanvas.enabled
listAllCreatedRooms()
if (clickedOnAnyListedRoom)
PhotonNetwork.JoinRoom(roomName);
:LobbyCanvas.enables
if (masterClicksOnStartGame)
each (PlayerThatIsReady)
SceneManager.LoadSceneAsync("Map");
else
remain in LobbyCanvas.
if (ClickedOnReady && Map.isLoaded)
SceneManager.LoadSceneAsync("Map");

My question is how do i stop charaacter be spawned (x Number_Of_Clients_In_MAP) and how can i stop photon from spawning the players in :LobbyCanvas.enables once i join room


public class Lobby : LobbyInterface
{
[SerializeField] private GameObject loadingScreen;

private void OnJoinedRoom()
{
TeamBalancer.Push();
foreach (PhotonPlayer player in PhotonNetwork.playerList)
{
AddToList(player, true); // list player in room
}
}

private void OnPhotonPlayerConnected(PhotonPlayer photonPlayer)
{
AddToList(photonPlayer, false); // list player in room
}

private void OnPhotonPlayerDisconnected(PhotonPlayer photonPlayer)
{
//for replace we can loop through here
RemoveFromList(photonPlayer);

// Remove player ready count.
if ((bool) photonPlayer.CustomProperties[Constants.IS_READY])
{
Room room = PhotonNetwork.room;
room.SetCustomProperties(new Hashtable {
{Constants.IS_READY, (int) room.CustomProperties[Constants.IS_READY] - 1}
});
}
}

public void OnMasterClientSwitched(PhotonPlayer player)
{
AddToList(player, true); // list player in room
}

private void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps)
{
PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
Hashtable properties = playerAndUpdatedProps[1] as Hashtable;

if (properties.ContainsKey(Constants.IS_READY) && ! player.IsMasterClient)
{
AddToList(player, false);

Hashtable roomProp = PhotonNetwork.room.CustomProperties;
if ((bool) roomProp.ContainsKey(Constants.IS_PLAYING))
{
// start game if player is ready and game has already started.
if ((bool) roomProp[Constants.IS_PLAYING] && (bool) properties[Constants.IS_READY])
{
player.SetCustomProperties(new ExitGames.Client.Photon.Hashtable {
{Constants.IS_PLAYING, true},
});
LoadScene();
}
}
}
}

private void OnPhotonCustomRoomPropertiesChanged(Hashtable roomProp)
{
PhotonPlayer player = PhotonNetwork.player;
Hashtable playersProps = player.CustomProperties;

// a different script sets this property once the master clicks on start room
if (roomProp.ContainsKey(Constants.IS_PLAYING))
{
if ((bool) roomProp[Constants.IS_PLAYING] && (bool) playersProps[Constants.IS_READY])
{
player.SetCustomProperties(new ExitGames.Client.Photon.Hashtable {
{Constants.IS_PLAYING, true}
});

LoadScene();
}
}
}

private void LoadScene()
{
StartCoroutine(loadingScreen.GetComponent().LoadMap(mapName.text, roomDetails.roomSettings.map.icon));
}
Loading Script
public System.Collections.IEnumerator LoadMap(string mapName, Sprite icon)
{
gameObject.SetActive(true);
AsyncOperation async = SceneManager.LoadSceneAsync("Example");
while (!async.isDone)
{
progressBar.value = async.progress;
yield return null;
}
}

DDOL Script
private void Awake()
{
photonView = GetComponent();
player = PhotonNetwork.player;
SceneManager.sceneLoaded += OnSceneFinishedLoading;
}

private void OnSceneFinishedLoading(Scene scene, LoadSceneMode mode)
{
if (scene.name == "Example")
{
StartCoroutine(Wait());
}
}

private IEnumerator Wait()
{
// make sure everyone is in
yield return new WaitForSeconds(3);
photonView.RPC("SpwanPlayer", PhotonTargets.All, player.NickName);
}

[PunRPC] private void SpwanPlayer(string name)
{
Transform location = InMap.instance.GetSpawnTransform(Random.Range(0, 7));
GameObject GO = PhotonNetwork.Instantiate(Path.Combine("Male", "Default"), location.position, location.rotation, 0);
}

also i have PhotonNetwork.automaticallySyncScene = false;

Comments

  • Hi @chrys,

    OnSceneFinishedLoading will be called on each client, who has loaded any scene. If it is the 'Example' scene, every client will start the Coroutine 'Wait', whereat every client calls the RPC. In this RPC you are using PhotonNetwork.Instantiate. Means that each client forces each other client and himself to instantiate one object. You can try to surround the 'StartCoroutine' call with a PhotonNetwork.isMasterClient condition and see if this solves the problem. Adding this only the MasterClient will call this RPC, so that he and the other clients will call PhotonNetwork.Instantiate just one time each.
  • Thanks @Christian_Simon your solution works in stopping the duplicate, but when another player join when game has already started, it dosnt spawn the player.

    Also do you have any idea why it spawns the players in game when i join room(not join game)?
  • Instead of using PhotonTargets.All in the RPC call you could use PhotonTargets.AllBuffered. This way a late joining client will also receive the RPC call and will spawn his player object as well.
  • okay Thanks