Maintaining Local State on Ownership Change
If a local script’s entity transfers ownership, the script’s runtime state is lost. This can cause issues for entities where the local state is important to maintain, such as for entities with a limited number of uses. For example, a gun may have a current and limited amount of ammunition, which should be maintained as it is grabbed, and ownership of the gun is changed.
To ensure state information is passed from one player to another when an entity transfers ownership, you can override the transferOwnership
and receiveOwnership
functions to specify data to pass when ownership of the object changes. In this manner, when the gun is picked up by a new player, it has the same amount of ammunition as when the previous player dropped it.
Note: Components require a custom State
type for data transferred when ownership of the entity changes. You should define this State
type and include its definition in your Component<Props, State>
definition. An example is provided below.
transferOwnership(fromPlayer: Player, toPlayer: Player): State
Specifies the data to transfer when ownership of an entity in Local Execution mode is changed.
Parameters
fromPlayer
- The Player sending the entity.
toPlayer
- The Player receiving the entity.
Return Type
A serialized State object containing the data to transfer.
receiveOwnership(state: State | null, fromPlayer: Player, toPlayer: Player)
Handles setting the data transferred when ownership of an entity in Local Execution mode is changed.
Parameters
state
- A serialized State object containing the data to transfer.fromPlayer
- The Player sending the entity.toPlayer
- The Player receiving the entity.
Return Type
Void
- You must handle the edge case when the local state isn’t transferred, such as the previous owner disconnecting from Horizon during a power or connectivity outage. In these cases, there’s no guarantee that the entity’s local state is transferred.
- The maximum size of state information that can be transferred is capped at 63kB. Transfers that are larger generate an error.
The following example illustrates how you can override the transferOwnership
and receiveOwnership
functions with the local entity’s ownership is transferred.
import * as hz from 'horizon/core';
type Props = { initialAmmo: number };
type State = { ammo: number };
class WeaponWithAmmo extends hz.Component<Props, State> {
static propsDefinition = {
initialAmmo: { type: hz.PropTypes.Number, default: 20 },
};
// local state that would normally be lost on ownership transfer
private ammo: number = 0;
start(): void {
// set local value for ammo
this.ammo = this.props.initialAmmo;
// imagine there's some event here that decreases ammo over time
};
// this is called on the new owner's instance of the script
// after it starts up and receives state from the previous owner.
receiveOwnership(
state: State | null,
fromPlayer: hz.Player,
toPlayer: hz.Player,
): void {
if (state != null) {
this.ammo = state.ammo;
};
};
// this is called on the previous owner's instance of the script
// to let it export its local state and send it over to the new owner.
transferOwnership(
fromPlayer: hz.Player,
toPlayer: hz.Player,
): State {
return { ammo: this.ammo };
};
};
hz.Component.register(WeaponWithAmmo);