Advertisement

How to properly synchronize the gameworld to new players?

Started by March 21, 2016 07:48 PM
0 comments, last by hplus0603 8 years, 8 months ago

Hi guys,

I'm working on a 2D platformer / RPG mix using Java with LibGDX and Kryonet. I recently finished implementing a reliable UDP protocol and thought that I can now finally start implementing some gameplay but I somehow hit a wall that stops me from progressing further:

How do I properly synchronize all entities to a player who just connected?

Some additional context:

  • the game uses an entity component system architecture. Every networked entity has a network component which provides a unique id set by the server.
  • the game's world is divided into several maps. This narrows down the number entities relevant for replication without much hassle: Entities on the same map as the client should be replicated.
  • All entities are created by a factory using the entity's unique entity id to generate a copy of a "blueprint".
    One solution I thought of is to just send the entityID along with movement updates and create the entity if the client can't find the entity by network id. This works for simple cases but what if I have to set things like for example a player's name or equipment? I need a full state update for this, not just the default entity.
  • the current and super naive way of replicating entities: When a client enters a map I loop through specific types of entities (players, monsters, loot, projectiles,...) and send a "create" packet related to the entity type to the client. E.g.: for each monster I send a "create monster" packet telling the client what kind of monster it is and a full state update. For each player I send a "create Player" packet including information about the equipped items, the player's hairstyle, etc.
    I feel like this is a really bad way to handle this topic because I have to take care of every single entity type this way

Do you have any recommendations or know of best practices to properly handle this type of entity synchronization or "creation" without me handling each new entity type manually by writing additional packet types etc.?

Thanks for your help!

Networking and game simulation generally are designed to go hand in hand.

Thus, synchronization depends on how you do simulation.

For example, if you use deterministic lock-step simulation where everybody loads the same initial map, and then everybody simulates using the same inputs (the "1,500 Archers" or "RTS" game model) then you use one mechanism. Examples: Starcraft, Age of Empires, Torque Network Engine.

If you play an open world game where players can roam over hills and valleys, and only really interact with other players within 300 meters of them, and different players are expected to run simulation at different frame rates, you need a totally different (snapshot based) simulation mechanism. Examples; any Unreal Engine game.

Finally, if you let the clients just drive their simulation, and distribute it to other players, with lightweight rules checking on the server (to save having to simulate on the server,) you need yet another approach. Examples: EverQuest, World of Warcraft.

Now, assuming something more along the middle/later, and less along the earlier options, a standard way to start might be:

1) There is a "world state" on the server that contains a reference to all the static data (name/version of level file, etc.)

2) Objects that are created from a template, store what template they were created from, in addition to current values.

3) When a player connects, a "world view" object is created for that player connection.

4) Each network tick (10 times per second? 20?) for each player, you run the update algorithm:

- Check all world objects for whether they should be "in view" of this player based on position/occlusion/rules/whatever

- For world objects that should be visible, but aren't, add them to the world view, and mark them for "send spawn"

- For world objects that should not be visible, if they are currently visible, remove them from the world view, and mark a "send despawn" message for the user

- For world objects that are already visible, and should remain so, mark the object as "needs update"

- Now, bundle up all despawn and spawn messages. These may contain the initial object state updates, too.

- For modifiable objects (that may change after spawning) also send a delta between "template file values" and "current property values."

The client then just needs to provide the user input and the client figures out what the user should see.

There are a number of additions to this algorithm, having to do with saving bandwidth and being smarter about how you present things to users, and that'll take most of a book to discuss in depth :-) But if you start here, you'll be fine and can go down that path as and when needed.

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement