1/**************************************************************************/
2/* area_3d.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "area_3d.h"
32
33#include "scene/scene_string_names.h"
34#include "servers/audio_server.h"
35
36void Area3D::set_gravity_space_override_mode(SpaceOverride p_mode) {
37 gravity_space_override = p_mode;
38 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE, p_mode);
39}
40
41Area3D::SpaceOverride Area3D::get_gravity_space_override_mode() const {
42 return gravity_space_override;
43}
44
45void Area3D::set_gravity_is_point(bool p_enabled) {
46 gravity_is_point = p_enabled;
47 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
48}
49
50bool Area3D::is_gravity_a_point() const {
51 return gravity_is_point;
52}
53
54void Area3D::set_gravity_point_unit_distance(real_t p_scale) {
55 gravity_point_unit_distance = p_scale;
56 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale);
57}
58
59real_t Area3D::get_gravity_point_unit_distance() const {
60 return gravity_point_unit_distance;
61}
62
63void Area3D::set_gravity_point_center(const Vector3 &p_center) {
64 gravity_vec = p_center;
65 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, p_center);
66}
67
68const Vector3 &Area3D::get_gravity_point_center() const {
69 return gravity_vec;
70}
71
72void Area3D::set_gravity_direction(const Vector3 &p_direction) {
73 gravity_vec = p_direction;
74 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, p_direction);
75}
76
77const Vector3 &Area3D::get_gravity_direction() const {
78 return gravity_vec;
79}
80
81void Area3D::set_gravity(real_t p_gravity) {
82 gravity = p_gravity;
83 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY, p_gravity);
84}
85
86real_t Area3D::get_gravity() const {
87 return gravity;
88}
89
90void Area3D::set_linear_damp_space_override_mode(SpaceOverride p_mode) {
91 linear_damp_space_override = p_mode;
92 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE, p_mode);
93}
94
95Area3D::SpaceOverride Area3D::get_linear_damp_space_override_mode() const {
96 return linear_damp_space_override;
97}
98
99void Area3D::set_angular_damp_space_override_mode(SpaceOverride p_mode) {
100 angular_damp_space_override = p_mode;
101 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE, p_mode);
102}
103
104Area3D::SpaceOverride Area3D::get_angular_damp_space_override_mode() const {
105 return angular_damp_space_override;
106}
107
108void Area3D::set_linear_damp(real_t p_linear_damp) {
109 linear_damp = p_linear_damp;
110 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
111}
112
113real_t Area3D::get_linear_damp() const {
114 return linear_damp;
115}
116
117void Area3D::set_angular_damp(real_t p_angular_damp) {
118 angular_damp = p_angular_damp;
119 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
120}
121
122real_t Area3D::get_angular_damp() const {
123 return angular_damp;
124}
125
126void Area3D::set_priority(int p_priority) {
127 priority = p_priority;
128 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_PRIORITY, p_priority);
129}
130
131int Area3D::get_priority() const {
132 return priority;
133}
134
135void Area3D::set_wind_force_magnitude(real_t p_wind_force_magnitude) {
136 wind_force_magnitude = p_wind_force_magnitude;
137 if (is_inside_tree()) {
138 _initialize_wind();
139 }
140}
141
142real_t Area3D::get_wind_force_magnitude() const {
143 return wind_force_magnitude;
144}
145
146void Area3D::set_wind_attenuation_factor(real_t p_wind_force_attenuation_factor) {
147 wind_attenuation_factor = p_wind_force_attenuation_factor;
148 if (is_inside_tree()) {
149 _initialize_wind();
150 }
151}
152
153real_t Area3D::get_wind_attenuation_factor() const {
154 return wind_attenuation_factor;
155}
156
157void Area3D::set_wind_source_path(const NodePath &p_wind_source_path) {
158 wind_source_path = p_wind_source_path;
159 if (is_inside_tree()) {
160 _initialize_wind();
161 }
162}
163
164const NodePath &Area3D::get_wind_source_path() const {
165 return wind_source_path;
166}
167
168void Area3D::_initialize_wind() {
169 real_t temp_magnitude = 0.0;
170 Vector3 wind_direction(0., 0., 0.);
171 Vector3 wind_source(0., 0., 0.);
172
173 // Overwrite with area-specified info if available
174 if (!wind_source_path.is_empty()) {
175 Node *wind_source_node = get_node_or_null(wind_source_path);
176 ERR_FAIL_NULL_MSG(wind_source_node, "Path to wind source is invalid: '" + wind_source_path + "'.");
177 Node3D *wind_source_node3d = Object::cast_to<Node3D>(wind_source_node);
178 ERR_FAIL_NULL_MSG(wind_source_node3d, "Path to wind source does not point to a Node3D: '" + wind_source_path + "'.");
179 Transform3D global_transform = wind_source_node3d->get_transform();
180 wind_direction = -global_transform.basis.get_column(Vector3::AXIS_Z).normalized();
181 wind_source = global_transform.origin;
182 temp_magnitude = wind_force_magnitude;
183 }
184
185 // Set force, source and direction in the physics server.
186 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR, wind_attenuation_factor);
187 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_SOURCE, wind_source);
188 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_DIRECTION, wind_direction);
189 PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE, temp_magnitude);
190}
191
192void Area3D::_body_enter_tree(ObjectID p_id) {
193 Object *obj = ObjectDB::get_instance(p_id);
194 Node *node = Object::cast_to<Node>(obj);
195 ERR_FAIL_NULL(node);
196
197 HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id);
198 ERR_FAIL_COND(!E);
199 ERR_FAIL_COND(E->value.in_tree);
200
201 E->value.in_tree = true;
202 emit_signal(SceneStringNames::get_singleton()->body_entered, node);
203 for (int i = 0; i < E->value.shapes.size(); i++) {
204 emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape);
205 }
206}
207
208void Area3D::_body_exit_tree(ObjectID p_id) {
209 Object *obj = ObjectDB::get_instance(p_id);
210 Node *node = Object::cast_to<Node>(obj);
211 ERR_FAIL_NULL(node);
212 HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id);
213 ERR_FAIL_COND(!E);
214 ERR_FAIL_COND(!E->value.in_tree);
215 E->value.in_tree = false;
216 emit_signal(SceneStringNames::get_singleton()->body_exited, node);
217 for (int i = 0; i < E->value.shapes.size(); i++) {
218 emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape);
219 }
220}
221
222void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
223 bool body_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
224 ObjectID objid = p_instance;
225
226 Object *obj = ObjectDB::get_instance(objid);
227 Node *node = Object::cast_to<Node>(obj);
228
229 HashMap<ObjectID, BodyState>::Iterator E = body_map.find(objid);
230
231 if (!body_in && !E) {
232 return; //likely removed from the tree
233 }
234
235 lock_callback();
236 locked = true;
237
238 if (body_in) {
239 if (!E) {
240 E = body_map.insert(objid, BodyState());
241 E->value.rid = p_body;
242 E->value.rc = 0;
243 E->value.in_tree = node && node->is_inside_tree();
244 if (node) {
245 node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree).bind(objid));
246 node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree).bind(objid));
247 if (E->value.in_tree) {
248 emit_signal(SceneStringNames::get_singleton()->body_entered, node);
249 }
250 }
251 }
252 E->value.rc++;
253 if (node) {
254 E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));
255 }
256
257 if (E->value.in_tree) {
258 emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
259 }
260
261 } else {
262 E->value.rc--;
263
264 if (node) {
265 E->value.shapes.erase(ShapePair(p_body_shape, p_area_shape));
266 }
267
268 bool in_tree = E->value.in_tree;
269 if (E->value.rc == 0) {
270 body_map.remove(E);
271 if (node) {
272 node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
273 node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
274 if (in_tree) {
275 emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
276 }
277 }
278 }
279 if (node && in_tree) {
280 emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
281 }
282 }
283
284 locked = false;
285 unlock_callback();
286}
287
288void Area3D::_clear_monitoring() {
289 ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal.");
290
291 {
292 HashMap<ObjectID, BodyState> bmcopy = body_map;
293 body_map.clear();
294 //disconnect all monitored stuff
295
296 for (const KeyValue<ObjectID, BodyState> &E : bmcopy) {
297 Object *obj = ObjectDB::get_instance(E.key);
298 Node *node = Object::cast_to<Node>(obj);
299
300 if (!node) { //node may have been deleted in previous frame or at other legitimate point
301 continue;
302 }
303 //ERR_CONTINUE(!node);
304
305 node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
306 node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
307
308 if (!E.value.in_tree) {
309 continue;
310 }
311
312 for (int i = 0; i < E.value.shapes.size(); i++) {
313 emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E.value.rid, node, E.value.shapes[i].body_shape, E.value.shapes[i].area_shape);
314 }
315
316 emit_signal(SceneStringNames::get_singleton()->body_exited, node);
317 }
318 }
319
320 {
321 HashMap<ObjectID, AreaState> bmcopy = area_map;
322 area_map.clear();
323 //disconnect all monitored stuff
324
325 for (const KeyValue<ObjectID, AreaState> &E : bmcopy) {
326 Object *obj = ObjectDB::get_instance(E.key);
327 Node *node = Object::cast_to<Node>(obj);
328
329 if (!node) { //node may have been deleted in previous frame or at other legitimate point
330 continue;
331 }
332 //ERR_CONTINUE(!node);
333
334 node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
335 node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
336
337 if (!E.value.in_tree) {
338 continue;
339 }
340
341 for (int i = 0; i < E.value.shapes.size(); i++) {
342 emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E.value.rid, node, E.value.shapes[i].area_shape, E.value.shapes[i].self_shape);
343 }
344
345 emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
346 }
347 }
348}
349
350void Area3D::_notification(int p_what) {
351 switch (p_what) {
352 case NOTIFICATION_EXIT_TREE: {
353 _clear_monitoring();
354 } break;
355
356 case NOTIFICATION_ENTER_TREE: {
357 _initialize_wind();
358 } break;
359 }
360}
361
362void Area3D::set_monitoring(bool p_enable) {
363 ERR_FAIL_COND_MSG(locked, "Function blocked during in/out signal. Use set_deferred(\"monitoring\", true/false).");
364
365 if (p_enable == monitoring) {
366 return;
367 }
368
369 monitoring = p_enable;
370
371 if (monitoring) {
372 PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), callable_mp(this, &Area3D::_body_inout));
373 PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), callable_mp(this, &Area3D::_area_inout));
374 } else {
375 PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), Callable());
376 PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), Callable());
377 _clear_monitoring();
378 }
379}
380
381void Area3D::_area_enter_tree(ObjectID p_id) {
382 Object *obj = ObjectDB::get_instance(p_id);
383 Node *node = Object::cast_to<Node>(obj);
384 ERR_FAIL_NULL(node);
385
386 HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id);
387 ERR_FAIL_COND(!E);
388 ERR_FAIL_COND(E->value.in_tree);
389
390 E->value.in_tree = true;
391 emit_signal(SceneStringNames::get_singleton()->area_entered, node);
392 for (int i = 0; i < E->value.shapes.size(); i++) {
393 emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape);
394 }
395}
396
397void Area3D::_area_exit_tree(ObjectID p_id) {
398 Object *obj = ObjectDB::get_instance(p_id);
399 Node *node = Object::cast_to<Node>(obj);
400 ERR_FAIL_NULL(node);
401 HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id);
402 ERR_FAIL_COND(!E);
403 ERR_FAIL_COND(!E->value.in_tree);
404 E->value.in_tree = false;
405 emit_signal(SceneStringNames::get_singleton()->area_exited, node);
406 for (int i = 0; i < E->value.shapes.size(); i++) {
407 emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape);
408 }
409}
410
411void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
412 bool area_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
413 ObjectID objid = p_instance;
414
415 Object *obj = ObjectDB::get_instance(objid);
416 Node *node = Object::cast_to<Node>(obj);
417
418 HashMap<ObjectID, AreaState>::Iterator E = area_map.find(objid);
419
420 if (!area_in && !E) {
421 return; //likely removed from the tree
422 }
423
424 lock_callback();
425 locked = true;
426
427 if (area_in) {
428 if (!E) {
429 E = area_map.insert(objid, AreaState());
430 E->value.rid = p_area;
431 E->value.rc = 0;
432 E->value.in_tree = node && node->is_inside_tree();
433 if (node) {
434 node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree).bind(objid));
435 node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree).bind(objid));
436 if (E->value.in_tree) {
437 emit_signal(SceneStringNames::get_singleton()->area_entered, node);
438 }
439 }
440 }
441 E->value.rc++;
442 if (node) {
443 E->value.shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
444 }
445
446 if (!node || E->value.in_tree) {
447 emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
448 }
449
450 } else {
451 E->value.rc--;
452
453 if (node) {
454 E->value.shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
455 }
456
457 bool in_tree = E->value.in_tree;
458 if (E->value.rc == 0) {
459 area_map.remove(E);
460 if (node) {
461 node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
462 node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
463 if (in_tree) {
464 emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
465 }
466 }
467 }
468 if (!node || in_tree) {
469 emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape);
470 }
471 }
472
473 locked = false;
474 unlock_callback();
475}
476
477bool Area3D::is_monitoring() const {
478 return monitoring;
479}
480
481TypedArray<Node3D> Area3D::get_overlapping_bodies() const {
482 TypedArray<Node3D> ret;
483 ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off.");
484 ret.resize(body_map.size());
485 int idx = 0;
486 for (const KeyValue<ObjectID, BodyState> &E : body_map) {
487 Object *obj = ObjectDB::get_instance(E.key);
488 if (obj) {
489 ret[idx] = obj;
490 idx++;
491 }
492 }
493
494 ret.resize(idx);
495 return ret;
496}
497
498bool Area3D::has_overlapping_bodies() const {
499 ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping bodies when monitoring is off.");
500 return !body_map.is_empty();
501}
502
503void Area3D::set_monitorable(bool p_enable) {
504 ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer3D::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
505
506 if (p_enable == monitorable) {
507 return;
508 }
509
510 monitorable = p_enable;
511
512 PhysicsServer3D::get_singleton()->area_set_monitorable(get_rid(), monitorable);
513}
514
515bool Area3D::is_monitorable() const {
516 return monitorable;
517}
518
519TypedArray<Area3D> Area3D::get_overlapping_areas() const {
520 TypedArray<Area3D> ret;
521 ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off.");
522 ret.resize(area_map.size());
523 int idx = 0;
524 for (const KeyValue<ObjectID, AreaState> &E : area_map) {
525 Object *obj = ObjectDB::get_instance(E.key);
526 if (obj) {
527 ret[idx] = obj;
528 idx++;
529 }
530 }
531 ret.resize(idx);
532 return ret;
533}
534
535bool Area3D::has_overlapping_areas() const {
536 ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping areas when monitoring is off.");
537 return !area_map.is_empty();
538}
539
540bool Area3D::overlaps_area(Node *p_area) const {
541 ERR_FAIL_NULL_V(p_area, false);
542 HashMap<ObjectID, AreaState>::ConstIterator E = area_map.find(p_area->get_instance_id());
543 if (!E) {
544 return false;
545 }
546 return E->value.in_tree;
547}
548
549bool Area3D::overlaps_body(Node *p_body) const {
550 ERR_FAIL_NULL_V(p_body, false);
551 HashMap<ObjectID, BodyState>::ConstIterator E = body_map.find(p_body->get_instance_id());
552 if (!E) {
553 return false;
554 }
555 return E->value.in_tree;
556}
557
558void Area3D::set_audio_bus_override(bool p_override) {
559 audio_bus_override = p_override;
560}
561
562bool Area3D::is_overriding_audio_bus() const {
563 return audio_bus_override;
564}
565
566void Area3D::set_audio_bus_name(const StringName &p_audio_bus) {
567 audio_bus = p_audio_bus;
568}
569
570StringName Area3D::get_audio_bus_name() const {
571 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
572 if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
573 return audio_bus;
574 }
575 }
576 return SceneStringNames::get_singleton()->Master;
577}
578
579void Area3D::set_use_reverb_bus(bool p_enable) {
580 use_reverb_bus = p_enable;
581}
582
583bool Area3D::is_using_reverb_bus() const {
584 return use_reverb_bus;
585}
586
587void Area3D::set_reverb_bus_name(const StringName &p_audio_bus) {
588 reverb_bus = p_audio_bus;
589}
590
591StringName Area3D::get_reverb_bus_name() const {
592 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
593 if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
594 return reverb_bus;
595 }
596 }
597 return SceneStringNames::get_singleton()->Master;
598}
599
600void Area3D::set_reverb_amount(float p_amount) {
601 reverb_amount = p_amount;
602}
603
604float Area3D::get_reverb_amount() const {
605 return reverb_amount;
606}
607
608void Area3D::set_reverb_uniformity(float p_uniformity) {
609 reverb_uniformity = p_uniformity;
610}
611
612float Area3D::get_reverb_uniformity() const {
613 return reverb_uniformity;
614}
615
616void Area3D::_validate_property(PropertyInfo &p_property) const {
617 if (p_property.name == "audio_bus_name" || p_property.name == "reverb_bus_name") {
618 String options;
619 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
620 if (i > 0) {
621 options += ",";
622 }
623 String name = AudioServer::get_singleton()->get_bus_name(i);
624 options += name;
625 }
626
627 p_property.hint_string = options;
628 } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") {
629 if (gravity_space_override == SPACE_OVERRIDE_DISABLED) {
630 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
631 } else {
632 if (gravity_is_point) {
633 if (p_property.name == "gravity_direction") {
634 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
635 }
636 } else {
637 if (p_property.name.begins_with("gravity_point_")) {
638 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
639 }
640 }
641 }
642 } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") {
643 if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) {
644 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
645 }
646 } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") {
647 if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) {
648 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
649 }
650 }
651}
652
653void Area3D::_bind_methods() {
654 ClassDB::bind_method(D_METHOD("set_gravity_space_override_mode", "space_override_mode"), &Area3D::set_gravity_space_override_mode);
655 ClassDB::bind_method(D_METHOD("get_gravity_space_override_mode"), &Area3D::get_gravity_space_override_mode);
656
657 ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area3D::set_gravity_is_point);
658 ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area3D::is_gravity_a_point);
659
660 ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance", "distance_scale"), &Area3D::set_gravity_point_unit_distance);
661 ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance"), &Area3D::get_gravity_point_unit_distance);
662
663 ClassDB::bind_method(D_METHOD("set_gravity_point_center", "center"), &Area3D::set_gravity_point_center);
664 ClassDB::bind_method(D_METHOD("get_gravity_point_center"), &Area3D::get_gravity_point_center);
665
666 ClassDB::bind_method(D_METHOD("set_gravity_direction", "direction"), &Area3D::set_gravity_direction);
667 ClassDB::bind_method(D_METHOD("get_gravity_direction"), &Area3D::get_gravity_direction);
668
669 ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &Area3D::set_gravity);
670 ClassDB::bind_method(D_METHOD("get_gravity"), &Area3D::get_gravity);
671
672 ClassDB::bind_method(D_METHOD("set_linear_damp_space_override_mode", "space_override_mode"), &Area3D::set_linear_damp_space_override_mode);
673 ClassDB::bind_method(D_METHOD("get_linear_damp_space_override_mode"), &Area3D::get_linear_damp_space_override_mode);
674
675 ClassDB::bind_method(D_METHOD("set_angular_damp_space_override_mode", "space_override_mode"), &Area3D::set_angular_damp_space_override_mode);
676 ClassDB::bind_method(D_METHOD("get_angular_damp_space_override_mode"), &Area3D::get_angular_damp_space_override_mode);
677
678 ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &Area3D::set_angular_damp);
679 ClassDB::bind_method(D_METHOD("get_angular_damp"), &Area3D::get_angular_damp);
680
681 ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &Area3D::set_linear_damp);
682 ClassDB::bind_method(D_METHOD("get_linear_damp"), &Area3D::get_linear_damp);
683
684 ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area3D::set_priority);
685 ClassDB::bind_method(D_METHOD("get_priority"), &Area3D::get_priority);
686
687 ClassDB::bind_method(D_METHOD("set_wind_force_magnitude", "wind_force_magnitude"), &Area3D::set_wind_force_magnitude);
688 ClassDB::bind_method(D_METHOD("get_wind_force_magnitude"), &Area3D::get_wind_force_magnitude);
689
690 ClassDB::bind_method(D_METHOD("set_wind_attenuation_factor", "wind_attenuation_factor"), &Area3D::set_wind_attenuation_factor);
691 ClassDB::bind_method(D_METHOD("get_wind_attenuation_factor"), &Area3D::get_wind_attenuation_factor);
692
693 ClassDB::bind_method(D_METHOD("set_wind_source_path", "wind_source_path"), &Area3D::set_wind_source_path);
694 ClassDB::bind_method(D_METHOD("get_wind_source_path"), &Area3D::get_wind_source_path);
695
696 ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
697 ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
698
699 ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area3D::set_monitoring);
700 ClassDB::bind_method(D_METHOD("is_monitoring"), &Area3D::is_monitoring);
701
702 ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area3D::get_overlapping_bodies);
703 ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area3D::get_overlapping_areas);
704
705 ClassDB::bind_method(D_METHOD("has_overlapping_bodies"), &Area3D::has_overlapping_bodies);
706 ClassDB::bind_method(D_METHOD("has_overlapping_areas"), &Area3D::has_overlapping_areas);
707
708 ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area3D::overlaps_body);
709 ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area3D::overlaps_area);
710
711 ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area3D::set_audio_bus_override);
712 ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area3D::is_overriding_audio_bus);
713
714 ClassDB::bind_method(D_METHOD("set_audio_bus_name", "name"), &Area3D::set_audio_bus_name);
715 ClassDB::bind_method(D_METHOD("get_audio_bus_name"), &Area3D::get_audio_bus_name);
716
717 ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
718 ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
719
720 ClassDB::bind_method(D_METHOD("set_reverb_bus_name", "name"), &Area3D::set_reverb_bus_name);
721 ClassDB::bind_method(D_METHOD("get_reverb_bus_name"), &Area3D::get_reverb_bus_name);
722
723 ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area3D::set_reverb_amount);
724 ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area3D::get_reverb_amount);
725
726 ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity);
727 ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity);
728
729 ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
730 ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
731 ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
732 ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
733
734 ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
735 ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
736 ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
737 ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
738
739 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
740 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
741 ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,100000,1,or_greater,or_less"), "set_priority", "get_priority");
742
743 ADD_GROUP("Gravity", "gravity_");
744 ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode");
745 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point");
746 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:m"), "set_gravity_point_unit_distance", "get_gravity_point_unit_distance");
747 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center");
748 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
749 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
750
751 ADD_GROUP("Linear Damp", "linear_damp_");
752 ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
753 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
754
755 ADD_GROUP("Angular Damp", "angular_damp_");
756 ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_angular_damp_space_override_mode", "get_angular_damp_space_override_mode");
757 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
758
759 ADD_GROUP("Wind", "wind_");
760 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_force_magnitude", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater"), "set_wind_force_magnitude", "get_wind_force_magnitude");
761 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_attenuation_factor", PROPERTY_HINT_RANGE, "0.0,3.0,0.001,or_greater"), "set_wind_attenuation_factor", "get_wind_attenuation_factor");
762 ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "wind_source_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_wind_source_path", "get_wind_source_path");
763
764 ADD_GROUP("Audio Bus", "audio_bus_");
765 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
766 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
767
768 ADD_GROUP("Reverb Bus", "reverb_bus_");
769 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enabled"), "set_use_reverb_bus", "is_using_reverb_bus");
770 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus_name", "get_reverb_bus_name");
771 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
772 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
773
774 BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED);
775 BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE);
776 BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE_REPLACE);
777 BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE);
778 BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE_COMBINE);
779}
780
781Area3D::Area3D() :
782 CollisionObject3D(PhysicsServer3D::get_singleton()->area_create(), true) {
783 set_gravity(9.8);
784 set_gravity_direction(Vector3(0, -1, 0));
785 set_monitoring(true);
786 set_monitorable(true);
787}
788
789Area3D::~Area3D() {
790}
791