Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a114ab1
feat: implement trigger area component
kuruk-mm Dec 14, 2025
0767d86
add CL_PLAYER collision layer
kuruk-mm Dec 14, 2025
3f56ce6
detect any entity also
kuruk-mm Dec 14, 2025
6920cca
optimizations, and implement pooling
kuruk-mm Dec 14, 2025
e5eaaa0
add global object pool manager
kuruk-mm Dec 14, 2025
533ed0d
refactor: apply clippy fixes and reduce log verbosity
kuruk-mm Dec 14, 2025
74b2f01
refactor: use callback monitor
kuruk-mm Dec 14, 2025
80ba58b
fix crash, check object is valid
kuruk-mm Dec 14, 2025
5a533f5
fix panic
kuruk-mm Dec 14, 2025
7a73e4c
feat: add remote avatar detection and scene-aware trigger areas
kuruk-mm Dec 17, 2025
cdb0f48
perf: optimize trigger area avatar scene detection
kuruk-mm Dec 17, 2025
59dc0c3
refactor: simplify trigger area scene-awareness with physics enable/d…
kuruk-mm Dec 17, 2025
d5bc330
Merge remote-tracking branch 'origin/main' into feat/trigger-area
kuruk-mm Dec 17, 2025
8fd54e4
fix: apply clippy match_ref_pats lint fix
kuruk-mm Dec 17, 2025
c9fe2f6
perf: use HashMap for pending trigger events by scene ID
kuruk-mm Dec 17, 2025
04cbf33
fix: ignore AvatarShape entities in trigger area detection
kuruk-mm Dec 18, 2025
efff416
fix: disable trigger detection for AvatarShape (scene NPCs)
kuruk-mm Dec 18, 2025
cc500c2
refactor: simplify trigger detection for avatars
kuruk-mm Dec 18, 2025
f9dae0b
Merge branch 'main' into feat/trigger-area
kuruk-mm Dec 18, 2025
cfa7aa2
refactor: use explicit remove_trigger_detection() for AvatarShapes
kuruk-mm Dec 18, 2025
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
2 changes: 1 addition & 1 deletion godot/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pointing/emulate_touch_from_mouse=true
3d_render/layer_20="OUTLINE_SYSTEM_DEPTH"
3d_physics/layer_1="CL_POINTER"
3d_physics/layer_2="CL_PHYSICS"
3d_physics/layer_3="CL_RESERVED1"
3d_physics/layer_3="CL_PLAYER"
3d_physics/layer_4="CL_RESERVED2"
3d_physics/layer_5="CL_RESERVED3"
3d_physics/layer_6="CL_RESERVED4"
Expand Down
25 changes: 25 additions & 0 deletions godot/src/decentraland_components/avatar/avatar.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ const WEARABLE_NAME_PREFIX = "__"
@export var hide_name: bool = false
@export var non_3d_audio: bool = false

# Entity info for trigger area detection (set by avatar_shape.rs for scene avatars)
var dcl_scene_id: int = -1
var dcl_entity_id: int = -1
var is_local_player: bool = false

# Public
var avatar_id: String = ""
var hidden: bool = false
Expand Down Expand Up @@ -53,6 +58,7 @@ var wearable_promises = null

@onready var avatar_modifier_area_detector = $avatar_modifier_area_detector
@onready var click_area = $ClickArea
@onready var trigger_detector = %TriggerDetector


func _ready():
Expand Down Expand Up @@ -90,6 +96,25 @@ func _ready():
click_area.set_meta("is_avatar", true)
click_area.set_meta("avatar_id", avatar_id)

# Trigger detection is setup later via setup_trigger_detection() when entity info is available


## Setup trigger detection for this avatar.
## Call this after the avatar is created with the appropriate entity info.
## - For local player: scene_id=-1, entity_id=SceneEntityId.PLAYER (0x10000)
## - For remote avatars: scene_id=-1, entity_id=assigned entity from avatar_scene.rs
## - For scene avatars (NPCs): scene_id and entity_id from the scene
func setup_trigger_detection(p_scene_id: int, p_entity_id: int) -> void:
dcl_scene_id = p_scene_id
dcl_entity_id = p_entity_id

# Set metadata on TriggerDetector so trigger_area.rs can identify this avatar
trigger_detector.set_meta("dcl_scene_id", dcl_scene_id)
trigger_detector.set_meta("dcl_entity_id", dcl_entity_id)

# Enable the collision shape
trigger_detector.get_node("CollisionShape3D").disabled = false


func on_chat_message(address: String, message: String, _timestamp: float):
if avatar_id != address:
Expand Down
14 changes: 14 additions & 0 deletions godot/src/decentraland_components/avatar/avatar.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@ height = 0.1

[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_mwwx3"]

[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_trigger"]
radius = 0.25
height = 1.5

[node name="Avatar" type="DclAvatar"]
script = ExtResource("1_mwwx3")

Expand Down Expand Up @@ -899,6 +903,16 @@ bus = &"Scene"

[node name="Avatar_SFXs" parent="." instance=ExtResource("7_xt6ge")]

[node name="TriggerDetector" type="StaticBody3D" parent="."]
unique_name_in_owner = true
collision_layer = 4
collision_mask = 0

[node name="CollisionShape3D" type="CollisionShape3D" parent="TriggerDetector"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
shape = SubResource("CapsuleShape3D_trigger")
disabled = true

[node name="ClickArea" type="Area3D" parent="."]
unique_name_in_owner = true
collision_layer = 536870912
Expand Down
4 changes: 4 additions & 0 deletions godot/src/logic/player/player.gd
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ func _ready():
if own_click_area:
own_click_area.queue_free()

# Setup trigger detection for local player's avatar
# scene_id=-1 (not a scene NPC), entity_id=1 (SceneEntityId::PLAYER)
avatar.setup_trigger_detection(-1, 1)


func _on_player_profile_changed(new_profile: DclUserProfile):
var new_version = new_profile.get_profile_version()
Expand Down
6 changes: 3 additions & 3 deletions godot/src/logic/player/player.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ radius = 0.25
height = 1.5

[node name="Player" type="CharacterBody3D"]
collision_layer = 0
collision_layer = 4
collision_mask = 2
script = ExtResource("1_5bfm2")

Expand All @@ -28,8 +28,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
shape = SubResource("CapsuleShape3D_pxti1")

[node name="camera_mode_area_detector" parent="." instance=ExtResource("2_rco65")]
collision_layer = 2147483904
collision_mask = 2147483904
collision_layer = 2147483908
collision_mask = 2147483908

[node name="Mount" type="SpringArm3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.71, 0)
Expand Down
8 changes: 6 additions & 2 deletions lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ struct Component {

const PROTO_FILES_BASE_DIR: &str = "src/dcl/components/proto/";
const COMPONENT_BASE_DIR: &str = "src/dcl/components/proto/decentraland/sdk/components/";
const GROW_ONLY_SET_COMPONENTS: [&str; 3] =
["PointerEventsResult", "VideoEvent", "AvatarEmoteCommand"];
const GROW_ONLY_SET_COMPONENTS: [&str; 4] = [
"PointerEventsResult",
"VideoEvent",
"AvatarEmoteCommand",
"TriggerAreaResult",
];

pub fn snake_to_pascal(input: &str) -> String {
input
Expand Down
10 changes: 10 additions & 0 deletions lib/src/avatars/avatar_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,16 @@ impl AvatarScene {
new_avatar.connect("emote_triggered".into(), emote_triggered_callable);

self.base_mut().add_child(new_avatar.clone().upcast());

// Setup trigger detection with the assigned entity_id
// scene_id=-1 means this is a remote avatar (not a scene NPC)
// NOTE: This must be called AFTER add_child so that _ready() has been called
// and the @onready trigger_detector variable is initialized
new_avatar.call(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question here: as far i understood we won't be setting up triggers for non-primary players nor npc avatar. should we comment this line?

"setup_trigger_detection".into(),
&[(-1_i32).to_variant(), entity_id.as_i32().to_variant()],
);

self.avatar_godot_scene
.insert(entity_id, new_avatar.clone());

Expand Down
7 changes: 7 additions & 0 deletions lib/src/scene_runner/components/avatar_shape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ pub fn update_avatar_shape(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
new_avatar_shape.set_name(GString::from("AvatarShape"));
node_3d.add_child(new_avatar_shape.clone().upcast());

// Setup trigger detection for scene avatar (NPC)
// scene_id from the scene, entity_id from the entity
new_avatar_shape.call(
"setup_trigger_detection".into(),
&[scene.scene_id.0.to_variant(), entity.as_i32().to_variant()],
);

new_avatar_shape.call_deferred(
"async_update_avatar".into(),
&[new_avatar_data.to_variant(), avatar_name.to_variant()],
Expand Down
1 change: 1 addition & 0 deletions lib/src/scene_runner/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod raycast;
pub mod realm_info;
pub mod text_shape;
pub mod transform_and_parent;
pub mod trigger_area;
pub mod tween;
pub mod ui;
pub mod video_player;
Expand Down
Loading
Loading