How should I manage entities when scene is offline


#1

Hi
In my game I am using Zay-ES with SqlEntityData.
After player sign up he should create a party or join to someone else party to play the game.

When all party members get disconnected (offline), the party gets disabled.

My question is, when all party members are offline, should I also disable the scene (that party was connected to it) and all bodies in that scene and all entities parented to those bodies in that scene so they should be no longer available in game systems.

For example in bullet physic system, should I remove the physic space (of the scene which got disabled) from memory or just keep it there in memory and just not update it ?


#2

What would be the reason to keep it around?

I’m trying to understand why this is a question. Like, what do you feel like the trade offs are?

Because without those the answer kind of feels obvious to me… so we must be missing a piece of information that prompted the question.


#3

Yes, I have a superior motivation from asking that question.

And it is about parented entities. I have items that are parented (ItemBuff) to the characters and stats which are parented (Buffed) to those items and I have systems which are listening to those entities.
So should I find all those entities and disable them when scene gets disabled and thus the characters/npcs in that scene and enable them when scene gets enabled ?


#4

Are the systems still doing work on those entities that aren’t even handling real things anymore?

I still feel like I’m missing something because to me it seems super obvious that you wouldn’t want your systems, etc. managing things for no one.

But perhaps the question is deeper and your servers are actually 24/7 MMO servers and you only want the systems to run for things that are actually enabled… but otherwise keep those things around in the database or whatever. In which case, you are probably missing a component.

But now I’m having to read way too much between the lines. And I’m afraid I’ve had a week of decision overload so I won’t be designing solutions today for N hypothetical targets.


#5

No, nothing is done on them after players get disconnected. They are sitting there for nothing.

So I am asking if I better to let them be there or I should disable them so they get removed from systems ? (yet they are persisted in database)
If I should disable them then what would be your suggestion ?
Should I use a component to flag only enabled entities perhaps something like an Active or Online component and whenever scene gets disabled I remove that component from entities and when scene gets enabled again I readd that component ?

Edit: Or I should uses a SceneID component on ALL entities and filter them based on enabled scene IDs ?


#6

Probably I can do something like this, not sure if It is good approach.

I can check when party state gets ACTIVE (means all party members are connected) then enable scene and bodies and items and buffs related to that scene by adding them an Online component.
And when party state gets INACTIVE I remove that component.

if (parties.applyChanges()) {
 for (Entity party: parties.getChangedEntities()) {
  int partyState = party.get(PartyState.class).getState();
  EntityId sceneId = party.get(ActiveScene.class).getSceneId();

  if (partyState == PartyStates.ACTIVE) {
   ed.setComponent(sceneId, new SceneState(SceneStates.ENABLED));
   Set < EntityId > bodies = ed.findEntities(Filters.fieldEquals(SpawnPosition.class, "sceneId", sceneId), SpawnPosition.class);
   for (EntityId bodyId: bodies) {
    ed.setComponent(bodyId, new Online());
    Set < EntityId > items = ed.findEntities(Filters.fieldEquals(ItemBuff.class, "target", bodyId), ItemBuff.class);
    for (EntityId itemId: items) {
     ed.setComponent(itemId, new Online());
     Set < EntityId > buffs = ed.findEntities(Filters.fieldEquals(Buff.class, "target", itemId), Buff.class);
     for (EntityId buffId: buffs) {
      ed.setComponent(buffId, new Online());
     }
    }
   }

  } else if (partyState == PartyStates.INACTIVE) {
   ed.setComponent(sceneId, new SceneState(SceneStates.DISABLED));
   Set < EntityId > bodies = ed.findEntities(Filters.fieldEquals(SpawnPosition.class, "sceneId", sceneId), SpawnPosition.class);
   for (EntityId bodyId: bodies) {
    ed.removeComponent(bodyId, Online.class);
    Set < EntityId > items = ed.findEntities(Filters.fieldEquals(ItemBuff.class, "target", bodyId), ItemBuff.class);
    for (EntityId itemId: items) {
     ed.removeComponent(itemId, Online.class);
     Set < EntityId > buffs = ed.findEntities(Filters.fieldEquals(Buff.class, "target", itemId), Buff.class);
     for (EntityId buffId: buffs) {
      ed.removeComponent(buffId, Online.class);
     }
    }
   }
  }
 }
}

#7

Just came up with new idea which will get rid of those nested for-loops in above approach.

So basically I can create a system, let me call it SceneManager or SceneHierarchySystem. It’s job is to keep a list of all entity IDs that are in the same scene.

Whenever players are disconnected (party is inactive) and scene gets disabled the SceneManager will save the list with all current entity IDs in the list into a file (ex, to a JSON file) in server and remove Online component from those entities.
Next time when players are connected and party gets active again, I will enable the scene and load that JSON file for that scene id and add Online component to all entities again.

I think this is way better approach.
I am eager to here your idea about this.

Edit:
Maybe Zay-ES should provide an internal mechanism for creating separate worlds.


#8

Why can’t you just have an Online component. Add it when something should be real and operate. Take it off again when not.

For the systems that only want to deal with online objects, include it in the components they watch for. Done.

also allows you to still have things like decay systems that ignore Online or not.


#9

I want to do that. My problem is how should I find those entities to add Online component to them when scene gets enabled again.
So I should either save the id’s in some where before disabling scene and removing Online component or find them using entity data using those nested loops.

Edit:
Note the reason I said to save id’s to file is to prevent them get lost if server gets shut down.


#10

How do you find the scene? Do they not have some connection to the scene?

If it’s all just a random bunch of unconnected crap then yeh, just leave them all resident all the time. Don’t worry about it.


#11

bodies are directly connected to scene with a SpawnPosition component which has a sceneId property so no problem for them. My concern is about those entities which are parented to bodies like items, stats,… They are not directly connected to scene so If I am going to find them I need to use nested searches.

Set < EntityId > bodies = ed.findEntities(Filters.fieldEquals(SpawnPosition.class, "sceneId", sceneId), SpawnPosition.class);
   for (EntityId bodyId: bodies) {
    ed.setComponent(bodyId, new Online());
    Set < EntityId > items = ed.findEntities(Filters.fieldEquals(ItemBuff.class, "target", bodyId), ItemBuff.class);
    for (EntityId itemId: items) {
     ed.setComponent(itemId, new Online());
     Set < EntityId > buffs = ed.findEntities(Filters.fieldEquals(Buff.class, "target", itemId), Buff.class);
     for (EntityId buffId: buffs) {
      ed.setComponent(buffId, new Online());
     }
    }
   }

Edit:

Is using those nested for-loops efficient (from performance point) ?


#12

Called rarely, though, eh?

You are going to pay the same cost no matter what… but this approach isolates it to enabling the scene. That seems like a pretty good place to stick the cost.


#13

Yes, once the scene gets enabled (to add Online component) and once it gets disabled (to remove Online component).

So I will use this nested search approach rather than saving ids to file.

Thanks