1
\$\begingroup\$

Imagine having a big room (4000w x 4000h) which contains players and items (world objects). The room is spatially partitioned in a 10 x 10 grid for collision detection and changes in the viewport of the player.

enter image description here

  • Green rectangle: Item
  • Red rectangle: Player viewport

At the moment, on the server, every player contains a list of all world objects in his current viewport. When the player changes his position, new items are found in the viewport, compared with his current list of visible objects and the changes are send to the client. His current visible list is updated with the new found objects

HashSet<WorldObject> changes = new HashSet<>(foundObjects);
changes.removeAll(player.getVisibleObjects());

The client maintains a list of all entities that it has seen, renders them in the world and waits for new input.

Now my problem arise when another player picks up an item, it notifies the surrounding players, update the local list of items accordingly and stops rendering the item. This works fine. But players outside the viewport are not notified about these changes, so once they are in the grid, they will still see the item being rendered.

How are these kind of problems commonly solved? Is my approach good?

\$\endgroup\$
  • \$\begingroup\$ Who is responsible for telling the players which items become visible when they approach a partition that had been outside their view? Has that party not been informed of the collection of this item, or is it not passing along that information to new arrivals? \$\endgroup\$ – DMGregory May 8 at 12:44
  • \$\begingroup\$ The server is responsible for notifying the world state to new players. A player is assigned a random position in the room and receive the world state (objects in the viewport). When the players moves (and every x seconds), it finds and calculates new objects in the viewport and syncs it with the player. \$\endgroup\$ – XverhelstX May 8 at 12:51
  • \$\begingroup\$ So is your server not being told that the item was picked up, or is it somehow not passing that information along to the next player to happen by? \$\endgroup\$ – DMGregory May 8 at 12:53
  • \$\begingroup\$ The client predicts the pickup, the server detects the collision and passes it to the queue to notify surrounding players. My main concern is keeping players up to date who are not notified (e.g they are on other side of the map, but they saw the object in the past - so it's still being rendered/in the client entity list - to reduce the bandwidth and payload being sent) \$\endgroup\$ – XverhelstX May 8 at 12:58
  • 1
    \$\begingroup\$ Clients need to forget about objects they've seen in the past when they move out of range of where they saw it, and get updated from the server with objects that they are near. The server can diff between what the client knows and only send objects that have changed. The notifies surrounding players should be automatically handled by a generalized proximity-based check on the server, not a specialized call at an event happening. In this way even a new player on the map will get proximity-based appropriate updates without special handling or overhead. \$\endgroup\$ – Patrick Hughes May 9 at 0:07
2
\$\begingroup\$

One way you can solve this is to store a "last modified" timestamp for each block on the server, and a "last seen" timestamp for each block in a client's local cache.

When someone makes a change in a block, the server records the timestamp at which that change occurred, and sends it to each nearby player as part of the update telling them what changed. The clients record that timestamp as their last seen modification for that block.

When a client tells the server that it intends to move into range of a new set of blocks, it sends its "last seen" timestamp for each of those blocks. (You can reserve a prehistoric timestamp value to represent "I've never seen this block / it's been evicted from my cache")

The server can then compare those against its "last modified" timestamp to determine whether anything has changed in that block in the meantime, and send back only data for blocks that have changed. The other blocks are safe to load from cache without modification, since they haven't changed since the client's last visit.

\$\endgroup\$
  • \$\begingroup\$ Ideally the server holds the master copy of what each client knows and when the client requests the move then the server can send a delta directly instead of needing all the back-and-forth talk. Separately, because the server knows about all the objects and knows when they change (i.e. picked up by a player) it can send updates to players in range. First order of business should be the usual warning to "Never Trust The Client" and from that many interactions become simpler... \$\endgroup\$ – Patrick Hughes May 9 at 23:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.