Advice on handling destructible "crates"

Hello,

I'm kind of new to developing online multiplayer games, but I have to say after experimenting with PUN and doing some research on these forums, I can say online multiplayer is no longer the much-feared 8-headed monster it once was :)

I have a question regarding a specific scenario: in my game scene, there are about 500 destructible (but non-movable, non-attacking) objects with hitpoints, being instantiated. Basically they're stuff like supply crates and canisters etc that give the player loot when destroyed. These objects need to be in sync between the 4 maximum players per room including players that enter mid-game, in terms of their hitpoints and whether they are already destroyed. The placement and exact number of these objects are random, but I have an array with all the locations of these objects at game start. I estimate each of these objects to be destroyed/shot at probably once every 10 seconds or so.

The way I see it, there are 3 ways I can accomplish this:
1. Using the room properties hashtable. Pros: gets updated automatically for each player entering the room, no issues with transferring RPC if master client disconnects. Con: I'm not sure if 500 entries of vector2, plus the hitpoints of each object, is too much for a room properties hashtable to handle?

2. Unbuffered RPC: Possibly an option - the hitpoints of each object is tracked by the current master client, and whenever a new player joins, the master client RPCs the entire array to the new player. However, I'm not sure if this will cause the master client to lag big time whenever a new player joins. Buffered RPC is not really an option because of the changing hitpoints state of each object

3. Network instantiate each of those 500 objects, and use OnPhotonSerializeView with Unreliable On Change. However, this is too close to comfort to the 999 viewID limit if I decide to expand the number of these destructable objects later. Plus, I read on one of the forum answers that even with "unreliable on change", the 999 viewID limitation is there for a reason, so perhaps having a few hundred network-instantiated game objects isn't a good idea.

Could someone provide some advice on which method seems to be the most workable? Again, I'm not looking for definite answers but I just didn't want to spend weeks down a route only to find out that I shouldn't have started with that method. Again, these are object that don't move or attack, but do have some hitpoint associated with them.

Many thanks, and I really appreciate this extremely useful multiplayer platform!

Comments

  • Thanks for the nice words :)

    In all cases where something gets randomly generated, I would check if you couldn't do it by synchronizing the seed, instead of the generated values.
    By design, Random should generate the same sequence of random numbers when you initiate it with the same seed value. That could get rid of the position values and replace it with an integer seed.

    Each item can have a PhotonView or simply an ID given through the generator. Those IDs can be used to sync the health per item.

    Who will update the health values? Is there concurrent access? Can any hit update a value? Or does the Master Client accumulate the values and save them?

    If the IDs are short, you should be able to put each item's health into a room property. You can define the rules how to update them as you wish but (sadly) you can't add/substract from those values with SetCustomProperties, so any set is absolute.
    Based on the seed, I would also generate the initial health value. Only set properties for objects that have lower than the initial value. In general, this means that way fewer than "all" properties are being set.
  • Thanks for the pointers, Tobias.

    I'll probably modify the procedural engine so it can produce a deterministic level based on a random seed. Your comment about random seeds also gave me other ideas too, like using the random seed to generate random events in the game (or when we need to create a randomly-generated cluster of missiles, for example) so everything is in sync.

    As for the health values of the supply crates - hit detection is done by the client who fired the bullet, not through the master client. Basically, the controllable character fires a real bullet (locally instantiated), while the uncontrollable characters fire locally-instantiated blanks - no damage, just visual effect. So, any real bullet will be able to damage the crates.

    My current plan is to have the crates instantiated locally, and send out an RPC call when hit, to sync up its hitpoints to all other local instances of that crate for each player. I understand that under network conditions this might create ambiguity of who fired the "killing shot" for the crate, but in my game that is not quite as important. The crate hitpoints table can then be stored/updated in the room properties hashtable.

    The other option would be to network-instantiate the crates. If I do that I'll probably spawn the crates in-game to avoid having too many of those up at the same time.

    Anyway, I really appreciate the pointers! If you see anything wrong with my line of thought, please let me know. If not, I should be good to go :)
  • It sounded like you could create the crates in the deterministic level generator too. That should enable you to ID each, so you can easily send hit events referring to a crate.
    I thought about using buffered RPCs for the hits. At least if there are just a few ones. When a crate is destroyed, you could clean the buffer of the hits related to it and instead add the "destroyed crate" into a property.
    This is a wild mix but it covers things relatively effectively. And best of all: It enables everyone to shoot crates, no matter when. You just clean up destroyed crates from time to time on the master client (e.g.).

    Actually, PUN does not yet enable you to do this as RPC. You have to go a level deeper and use RaiseEvent and handle IDs and such yourself. It shouldn't be too hard and I can probably guide you a bit more if you like to explore the idea.
  • That's an interesting idea, as you mentioned, clearing the buffered RPC once the crate is destroyed and marking it as destroyed in the room properties.

    In the next few days I think I'll try out a couple of the ideas discussed, and post the results here. After we do some playtesting we'll know if the current methods are adequate, or if a more efficient method is needed.

    Again, I really appreciate the help. You guys rock!
  • :D
    Thanks.
    Looking forward to the results!
  • Ok - long overdue summary of what we eventually did for our game, but here it is.

    Overall, we're pretty happy with PUN. It didn't take long at all to come up with a fully functioning 4-player multiplayer game, with a game lobby and the ability to set up and join games (honestly, we probably spent more time working on the lobby UI design and implementation compared to the networking aspects of the lobby)

    Here's what we eventually used.
    - We rewrote our procedural engine to be deterministic based on a few random seeds. This way we only had to pass a few integers to new people entering the game. The integers were stored in the custom room properties hash table. This helped saved tremendous amount of bandwidth when new players join. I'd say for large procedural maps, that's probably the only way to go.

    - For the crates, at the end we just generated them dynamically during gameplay. Since we were keeping track on which parts of the map were unexplored, generating the crates ahead of time was fairly straightforward. In this way, we limited the number of photon-instantiated scene objects in the game to just about 20-30 at one time. And since they were photon-instantiated and observed, their hitpoints were automatically updated for new players who joined.

    - There a bunch of other stuff that we didn't expect to spend much time on, but eventually turned into time-sinks :) They mainly are "ownership" of the mobs, determining hits and deducting hitpoints and general tweaking of the engine to make it as smooth as possible. We did learn one thing though - if things seemed choppy under reasonable network conditions, it usually something is wrong and we were transferring way more data than we thought we were.

    I might spend some time writing up some of these pointers on our dev blog - I'll send a link out when it's ready.
    Cheers
  • Thanks for the head up! It's good to read how you implemented stuff and what worked for you.
    I am looking forward to read the article when you have the time to post one.
  • WilliamG wrote:
    Ok - long overdue summary of what we eventually did for our game, but here it is.
    Overall, we're pretty happy with PUN. It didn't take long at all to come up with a fully functioning 4-player multiplayer game...

    Thanks for the summary saved me some time, Also thanks Tobias for the pointers.