Class GGEntityAccessPolicy extends Resource
An access policy determines whether an [param actor] is allowed to access an [param object].
An access policy evaluates whether a player/client identified by its
This access policy only defines the interface and always return
In a multiplayer scenario, the host's [GGEntityAccessManager] can receive requests to open a context from any client. A fully implemented access policy should consider these checks:
- ✓ Validate that the
At a minimum, you should validate that the
You'll want to ensure that the
Much like the
For example, let's say the (character)
Asynchronous Access Policies.
The
remote_peer_id is allowed to control the (character) actor, and that the actor is allowed to access an object. This access policy only defines the interface and always return
false and prevent any access. You should extend this class and implement your validation logic according to your game's needs. In a multiplayer scenario, the host's [GGEntityAccessManager] can receive requests to open a context from any client. A fully implemented access policy should consider these checks:
- ✓ Validate that the
actor is valid. At a minimum, you should validate that the
actor character exists and represents a valid character. For example, you might have a specific character class: [codeblock] func _is_actor_valid(actor: Node) -> bool: return ( is_instance_valid(actor) and actor is MyCustomCharacterBody2D ) [/codeblock] - ✓ Validate that the remote_sender_id owns the actor. You'll want to ensure that the
actor belongs to the client identified by its remote_sender_id. For example, if you have stored the peer_id of the client when creating the character you can then use it to verify ownership: [codeblock] func _is_actor_owned_by_remote_sender(actor: Node, remote_sender_id: int) -> bool: return ( owner_peer_id in actor and ( # for clients, the peer_id should match actor.owner_peer_id == remote_sender_id or ( # for the host, it's peer id 1 but remote id 0 remote_sender_id == 0 and actor.owner_peer_id == 1 ) ) ) [/codeblock] - ✓ Validate that the object is valid. Much like the
actor, an object could be any [Node]. You'll want to narrow it down to ensure the object being accessed actually represents an accessible object. For example, every object may be in a "game_objects" node group: [codeblock] func _is_object_valid(object: Node) -> bool: return ( is_instance_valid(object) and object.is_in_group("game_objects") ) [/codeblock] - ✓ Validate that the actor is allowed to access the object. For example, let's say the (character)
actor is on team 2, and is only allowed to access a storage box object on the same team: [codeblock] func _can_actor_access_object(actor: Node, object: Node) -> bool: return ( "team_id" in actor and "team_id" in object and actor.team_id == object.team_id ) [/codeblock] Assembling the parts then results in: [codeblock] func open( manager: GGEntityAccessManager, actor: Node, object: Node, remote_sender_id: int ) -> bool: return ( _is_actor_valid(actor) and _is_actor_owned_by_remote_sender(actor, remote_sender_id) and _is_object_valid(object) and _can_actor_access_object(actor, object) ) [/codeblock] Asynchronous Access Policies.
The
open() and close() methods are awaited by the [GGEntityAccessManager], so they're allowed to perform logic asynchronously. For example, an advanced use case is having the access policy prompt the client to enter a PIN or password to access a storage box before the access policy returns true.# Methods
## Called when the [param manager] validates whether the [param actor] is allowed to access the [param object] as requested by the client identified by its [param remote_sender_id].func open(manager: GGEntityAccessManageractor: Nodeobject: Noderemote_sender_id: int) -> bool## Called when the [param manager] closes a context for the [param actor] to access the [param object].func close(manager: GGEntityAccessManageractor: Nodeobject: Noderemote_sender_id: int) -> bool