Too many photonViews is bad. So how do you do it?

I am running into a problem where it is throwing an error saying I have too many scene objects.

Then I see threads saying too many photoviews are bad..

So how do I do this?

My game has a lot of enemies, lets say 100 on the map. That is 100 photonViews, it needs it because it updates position, hp, etc.

It also has resource nodes, which also has hp and I am photon instantiating them so it also must have a photonView. This is around 500 on the map.

If I dont use photonViews for these, how do I update their position, hp?
If I use RPC calls and add/remove a local copy, that means I have to keep track of every single instance and update accordingly which doesn't seem very effective.

What is the correct way of doing this?

Can I just increase the photonView limit?

Comments

  • PUN is not made to update lots of objects via PhotonViews. The idea is to have a simple way to sync objects but this doesn't scale that well.

    I assume resource nodes are fixed per map? You can assign IDs to those and send updates about them via RaiseEvent or through one PhotonView.
  • They are not fixed, they are generated.

    I came from unet and used network identity without a problem. Kinda sucks that the equivalent (photonview) has this limitation..

    So I am assuming that PUN is for tiny to small multiplayer games that doesn't have much syncing.. anything normal, pun isn't the choice?

    What I dont understand is, why is there a limit? If there is a photonview on the object, but it is set to sync on change, it shouldn't have any issues if the object only changes once a while right? Does the photonview sync periodically even if there is no change to the object?

    Kind of sad that I may have to go back to unet with all these limitations.
  • When you have a lot of objects, it really depends on how you do stuff and what the objects have to sync.
    For PUN we simply decided it's enough to have up to 1000 objects per player. When you would be updating all of them, the clients would likely overload anyways.

    Now that we have "unreliable on change" as sync option, there could be more, potentially.
    The limitation is client side in PUN and thus it can be changed. We marked the places where this happens with some comments saying something like "limits photonviews". I can check for details but not now.

    By the way: We suggest making your generation fully deterministic. This way, each client can generate the map from a much (much!) smaller seed value. This would still allow to ID objects any way you like.


    Can you describe what kind of game you do?
    We made some assumptions for PUN, what kind of game we can support. Most of the limitations it has are client-defined.
  • What about the limit of scene objects?
    PhotonNetwork.InstantiateSceneObject <- that is creating a scene object right? Or does that contribute to the player object count?

    Yes, I totally agree that updating all 1000 objects would overload, but only if they were being updated all at once. But it shouldn't be any different than using RPC if only a few objects would be syncing seldom at times.

    My game is a 2d platformer like minecraft. The zone is 120x120 tiles and resources are scattered throughout the map. Maybe 500 resources per zone.
    Ideally, every resources with be a photonview that only updates when it needs to update.
    ie: when it is being harvested, and when it is spawned/destroyed. So at max, only 4 resources would be syncing at a given time (4 players, 1 harvesting 1 node each)

    There are enemies as well, maybe under 100. These have to be photonView and there is no way of it not being one otherwise it gets too messy.

    When player opens another zone, new set of resources/enemies are generated so another 600 objects. And this is when I got that limit error.

    From my game's standpoint, over the limit shouldn't pose any threat because majority of my objects (resources) are only updated when spawned/destroy/harvested. Only spawning/destroy all 600 objects at a time would potentially be a problem but if the limit was 1000 then it should be fine.

    Any how.. I have changed my resources to be local objects and syncing are done via RPC calls with object id. But I just don't know if sync calls would be missed sometimes.
  • Tobias
    Tobias admin
    edited August 2016
    It sounds like you're making some progress now and that your experimentation helps with the understanding of PUN.

    PhotonNetwork.InstantiateSceneObject - that is creating a scene object right? Or does that contribute to the player object count?


    Scene objects are instantiated this way, yes. And they have their own range of viewIDs, which is using the fact there is no player 0 (meaning: 1..999 or whatever you modified the upper limit to).

    While RPCs are always distinct messages, which are sent on their own, the updates sent via OnPhotonSerializeView() can be aggregated and thus might have a little less overhead. Also, the observe options of a PhotonView, enable you to send updates unreliable, which is not possible with RPCs.

    Overall, RPCs are less effective for frequent updates but OK for infrequent ones.
    When you have lots of units/items/entities, the quantity alone means that it makes sense to optimize this part of the communication. As every game is different in that regard, we can only provide a foundation for that. Have a look at RaiseEvent, which is similar to RPC but without the reference to a PhotonView.

  • The problem with local objects is I have to manage it.
    ie:
    Create a tree, user destroys a tree, new player joins, new player should not create the tree because it was destroyed.

    Every local object needs to have their state cached on the master client right now because new players need to be aware of it.

    With InstantiateSceneObject, this was all done automatically as they were scene objects.

    Is there an easy way to remove a specific buffer from the buffer?
    ie:
    create tree rpc call, added to buffers. when i destroy the tree, is it possible to remove that specific buffer so new players don't create it? It will save me a alot of work if this is possible..
  • Not sure if this helps, I am fairly new to photon. However I am not new to distributed systems and state.
    It seems like what you need is not a PhotonView on every object, rather, when a new player joins he should receive something akin to an Append Only Datatype that has a representation of what has occurred. After generating the map, just replay the events.
    This is similar to how Databases work with WAL's and how eventual consistency works with CRDT's.

    I hope I helped, and if your interested am open to explaining it further.

    Disclaimer, I have literally no experience with photon, just a ton with servers.
  • Yes that is what I need. Please explain more if you can.
  • Ok, so at the expense of memory or disk space, you create a structure known as an Append Only Log and record all actions in that log, this should be done on the server. in Pseudo Code
    LogFormat = { action: Enum.ActionTypes, target: <uid or some attribute to get unique target> } AOLog = new Array(); // server receives message that player destroyed tree server.receive(msg); if (msg is a destroy message) { AOLog.push({action:ActionTypes.Removed , target: msg.target}) }

    At the end of doing all this you end up with
    [ { action: ActionTypes.Removed, target: "resource_ore_0001" }, { action: ActionTypes.Removed, target: "resource_tree_0001" }, { action: ActionTypes.Respawned, target: "resource_ore_0001" }, { action: ActionTypes.Damaged, target: "resource_ore_0002", value: 20 } ] // Etcetera

    It is up to you to figure out what needs to be stored in this datastructure, and what doesnt, to keep it as small as possible. There are ways to FLATTEN this structure by determining events that are no longer relevent like DAMAGE DAMAGE REMOVE, you can essentially backtrack and remove those DAMAGE events.

    Finally you add a replay feature to your generator and say

    generator.generateMap(seed); generator.replayLog(network.getFromServer(ALog));

    Here is a link to a LinkedIn article on the topic, not sure how good the article is, but it should suffice.
    https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
  • Again, the above is not perfectly suited to your solution, this solves more of a question of,
    "Since I have been gone, how has the state of the map changed" then "Now that I am here, I will use a photonview or some other network primitive to see all other changes.

  • I am just beginning my photon journey, but once I learn more, I will be able to give you more information. Hope any of what I said is at least somewhat helpfull, or at least educational.
    Feel free to email me at michael.hernandez1988@gmail.com
  • btw, this type of datastructure is also effective for real time compressed saved game.