Loading data for new players

I picked up PUN+ and did a little messing around to familiarize myself - got the basics of a pre-game lobby/chat room going. Chat and updating the active player list is sent via RPC.

I did have a basic use-case question as I'm delving more into it (and the answer to this should help inform many similar things - as it relates to new players picking up game variables that you would normally get from the server):

Say in this lobby, any player has the ability to create a new team by clicking a button. So that team creation message gets sent out over RPC to everyone in the room and instructs them to create a new UI panel. However what happens when someone new joins the room? They won't have gotten those RPC calls and thus they won't see any of the teams created before they came in.

What is the best way to handle this type of situation?

Off the top of my head I would think of querying the current Master Client upon joining the room, and checking how many teams he has (and who's in those teams, the score, etc) and instantiating the appropriate number of panels and then populating them. Even though the Master Client could change if the original MC drops out, the current MC seems like it would always have the most current state of the game, if set up correctly - as they would have to be in-game to be "passed the torch" so to speak?

Still, this feels somewhat, flimsy I guess - maybe it's just me getting used to not having the concept of an authoritative server. Is there a better/preferred way to handle this?

For instance, to sync active players, I have the RPC pull directly from the PhotonNetwork.playerList, so new players always know the current active players in the room - but I'm not sure if this method would work for custom properties in my game like "Teams"

[RPC]
void UpdatePlayerList(PhotonMessageInfo info) {
string[] newPlayerList = new string[PhotonNetwork.playerList.Length];

for (int i = 0; i < PhotonNetwork.playerList.Length; i++) {
newPlayerList = PhotonNetwork.playerList.name;
}
dfListbox activePlayersListbox = UI.RoomLobbyPanel.Find <dfListbox>("listbox_ActivePlayers");
activePlayersListbox.Items = newPlayerList;
}

Cheers,
Jesse

Comments

  • Hey Jesse,
    Cool to read you got the basics going already.

    I'd say the best way to implement team-organization (in a room) would be to use Custom Properties per player. The key method for that is:
    PhotonNetwork.player.SetCustomProperties(Hashtable props);
    This sets "this" player's custom properties. Make sure to use the "Photon Hashtable" via "using Hashtable = ExitGames.Client.Photon.Hashtable;".

    Props set this way will be synced and all players (even those who join later) will know the properties of the others. Each PhotonPlayer in the PhotonNetwork.playerList has a property "customProperties", which is basically the aggregation of the props you set.
    Don't modify the content of PhotonPlayer.customProperties directly. This is not supported and will not sync.

    The props have to use string keys, so you could use "t" or "team". Each player can individually name the desired team. If users set the same team name, then they work together.

    If you have a max player count per team, you could track when users switched their team the last time. This way, you could drop players out of a full team, if they switched later than the others. Use the synced time: PhotonNetwork.time and store it in another property to keep order.

    I hope that helps.
  • Oh. And you don't need to use RPCs for the players list or any info about the players. You can put that into player properties as well.
    :)
  • Ok, interesting note on teams, and custom properties thanks this helps!

    I have another general case that maybe wouldn't be handled so easy in properties:

    Say when the game starts, I need to instantiate a random number of powerups at random/procedural locations. These powerups don't actively move around like players, but they can be "consumed" in which case they will despawn and re-appear after a cooldown timer.

    Again, trying to figure out how to handle the case where someone joins mid-game:

    New player upon joining needs to know the following things about the powerups:
    - Location of all powerups created at game start
    - the type of each powerup
    - The status of that powerup, Active or Inactive (and if inactive, how much is left on the cooldown timer, unless this is unnecesary as the Master Client would send out an RPC when the specific powerup becomes active again)

    Could these be handled via master client RPC's, or does each powerup need its own Photon View and be tracked in OnPhotonSerializeView?

    If the former, what would I need to consider if the master client disconnected mid-game?

    Thanks for all the help, it's very useful!
  • Hello.

    I will soon work on the power ups in my own game, and what I'm thinking (just my two cents, I did not test this yet) is to use PhotonNetwork.InstantiateSceneObject.

    This way, your power up is just an object in the scene and all players can see it. When a player pick one up, HE sends an RPC to the other to say that he just picked it up. I was thinking (but again, not tested yet) about using PhotonTarget.AllViaServer as the target in the RPC call, to handle the case when two players claim to be the first to pick a powerup.

    So, i'm leaning toward the second solution you offered, because if you instantiate your powerups locally, when a player pick one up, you have to disable it in all the other client instead of disabling it in the scene as a sceneobject.

    About the respawn timer, well.. no idea on this one :/ maybe just a method in the controller of the powerup like this one :
    OnBeingPicked(){
        deactivate();
        sleep(x second);
        activate();
    }
    

    and the player picking it would go like
    OnPickingPowerUp(){
        if (activated) {
            powerup.OnBeingPicked();
        }
    }
    

    The syntax is probably not correct but you get the idea.
    Again, this is just my two cents, I've not tested it yet. As I will soon have to create some power ups, please give a feedback on how you decided to do.
  • Sorry about the late reply.
    This is a tricky topic and I can only offer my thoughts on it without a lot of expertise personally.

    Unless your game maps are procedural, you might want to place some GameObject in the scene to define the pickups in the map. Add a component which has the type, etc and create an Editor script that will assign IDs. You could (!) use PhotonViews but you definitely should set them to not observe anything. You basically just use the view's IDs then (and the Editor will assign those, starting with 1 per scene).
    If you want to generate pickups and they are not too numerous, you could instantiate them. Otherwise, you could also serialize their info to a byte[] and put those to the room properties.

    Once you know some ID per pickup, Kalissar's idea to send a "pickup" event to all via server is a simple way to determine who could pick up things. The server will send the "pickup item X" to all clients in the same order (which is the order in which those messages arrived at the server). So the first "pickup item X" is successful and all others fail.

    The next puzzle piece would be to remember a pickup and when the item refreshes. If players join late, you want to make the server remember pickups / spawn times but you also don't want to spam new players with updates.

    Again, the best solution depends a bit on the amount of items. If you have only a few in a room, you could simply set a property per item ID once it's picked up.
    Photon has a synchronized server time: PhotonNetwor.time. This could be used as "time when the item respawns" in a property and any client can easily respawn the item when it's time. When a new player joins, any item that has a respawn-time in the future will not be available.

    If you have dozens of pickups and lots of players taking them, you maybe just keep a state in any "live" player (based on the events everyone gets) and when a new one joins, send the spawn-times from the Master Client to the new player on join.
    Tricky here: If the Master Client leaves when someone joins simultaneously, the new Master Client might have to send the info. The new player could (e.g.) acknowledge (to everyone) that it's updated and ready to play now. You can also make the new player wait with the character instantiation until the info arrived. Any new Master Client can then check if the new player spawned a character or not and (in doubt) send the spawn times.