Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 90 additions & 1 deletion docs/networkGame/props_player.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ sidebar_position: 2

# Props and player network management

The player and every generic prop replicate their state to nearby players through the
**same** mechanism: the game server sends property updates to Horizon, which keeps an
authoritative copy of each object and forwards the changes to the clients in range. The
player is simply an object of type `player` — there is no longer a player-specific update
path.

Which properties are actually replicated (and how far / how often) is **not** decided in
your GDScript: it is declared in a per-type **definition file**. See
[Replication definition files](#replication-definition-files) below — read
it first, because a property that is not declared there will silently never reach the
clients.

## Player management

### Update properties
Expand Down Expand Up @@ -45,9 +57,15 @@ To do that, call the function *server_send_properties_to_client*.
For example:

```
client_send_action_to_server({"health": 80})
server_send_properties_to_client({"health": 80})
```

:::warning[Declare the property first]
`health` will only reach the clients if it is listed in the player definition file
(`player_def.json`). A property that is not whitelisted there is dropped silently. See
[Replication definition files](#replication-definition-files).
:::

#### Client receives update

The client receives all properties modified in the function *client_channel_data_update*, such as the new position and health.
Expand Down Expand Up @@ -195,3 +213,74 @@ Be careful, the int value sent by the server is a float when it arrives, so you

To delete a prop, the function *_exit_tree* sends the signal to the client, and the client deletes the scene; it's automatic!


## Replication definition files

Emitting `hs_server_prop_update` (props) or `server_send_properties_to_client` (player) is
**not enough** for a property to reach the clients. Horizon only replicates the properties
that are **declared** for that object type, in a definition file.

These files live in the Horizon plugins, one per object type:

```
horizonserver/ds_genericprops/props/<type>_def.json
```

where `<type>` is the prop's `type_name` (e.g. `box`, `miningrock`, `player`).

Example (`box_def.json`):

```json
{
"channels": [
{
"zone": 0,
"distance": 150.0,
"frequency": 30.0,
"properties": ["position", "rotation", "opened", "parent_id"]
},
{
"zone": 6,
"distance": 153.0,
"frequency": 3.0,
"properties": ["scenename"]
}
]
}
```

Each entry in `channels` is a replication **zone**:

- `distance` — clients within this radius (meters) of the object receive this zone's properties.
- `frequency` — how many times per second this zone is replicated (use a high rate for fast-changing data like `position`, a low rate for rarely-changing data).
- `properties` — the **whitelist**: only these property names are replicated.

:::danger[The whitelist is silent]
A property you send that is **not** listed in any zone is dropped without any error. The
client simply keeps its default value (empty string, `0`, ...). Symptom: the object behaves
correctly on the server but is wrong on the other clients. Whenever you add a new replicated
property, **add it to the type's `_def.json`** (and rebuild Horizon).
:::

:::warning[Keep creation properties in the same zone]
A client instantiates an object as soon as it receives its `scenename`. If `scenename` is in
a farther zone than `position`/`parent_id`, a client standing *between* the two distances
receives the scene **without** its placement and spawns the object at the world origin
`(0,0,0)`. Keep `scenename`, `position` and `parent_id` within the **same** `distance`.
:::


## Spawning a prop from the game server

If the game server creates a prop at runtime (not through the normal spawn flow), registering
it in Horizon is **not** enough: Horizon's replication is players-only and does not echo the
object back to the game server, so the prop would have no server-side body (it floats / can't
be interacted with until a reconnect reloads it from persistence).

Create it **both** in Horizon (for the other clients) **and** locally on the game server. The
helper does both:

```
NetworkOrchestrator.spawn_prop_authoritative(data) # data must hold "uuid" and "type"
```

Loading