1 /*************************************************************************/
2 /* proximity_group.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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 "proximity_group.h"
32
33 #include "core/math/math_funcs.h"
34
clear_groups()35 void ProximityGroup::clear_groups() {
36
37 Map<StringName, uint32_t>::Element *E;
38
39 {
40 const int size = 16;
41 StringName remove_list[size];
42 E = groups.front();
43 int num = 0;
44 while (E && num < size) {
45
46 if (E->get() != group_version) {
47 remove_list[num++] = E->key();
48 };
49
50 E = E->next();
51 };
52 for (int i = 0; i < num; i++) {
53
54 groups.erase(remove_list[i]);
55 };
56 };
57
58 if (E) {
59 clear_groups(); // call until we go through the whole list
60 };
61 };
62
update_groups()63 void ProximityGroup::update_groups() {
64
65 if (grid_radius == Vector3(0, 0, 0))
66 return;
67
68 ++group_version;
69
70 Vector3 pos = get_global_transform().get_origin();
71 Vector3 vcell = pos / cell_size;
72 int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) };
73
74 add_groups(cell, group_name, 0);
75
76 clear_groups();
77 };
78
add_groups(int * p_cell,String p_base,int p_depth)79 void ProximityGroup::add_groups(int *p_cell, String p_base, int p_depth) {
80
81 p_base = p_base + "|";
82 if (grid_radius[p_depth] == 0) {
83
84 if (p_depth == 2) {
85 _new_group(p_base);
86 } else {
87 add_groups(p_cell, p_base, p_depth + 1);
88 };
89 };
90
91 int start = p_cell[p_depth] - grid_radius[p_depth];
92 int end = p_cell[p_depth] + grid_radius[p_depth];
93
94 for (int i = start; i <= end; i++) {
95
96 String gname = p_base + itos(i);
97 if (p_depth == 2) {
98 _new_group(gname);
99 } else {
100 add_groups(p_cell, gname, p_depth + 1);
101 };
102 };
103 };
104
_new_group(StringName p_name)105 void ProximityGroup::_new_group(StringName p_name) {
106
107 const Map<StringName, uint32_t>::Element *E = groups.find(p_name);
108 if (!E) {
109 add_to_group(p_name);
110 };
111
112 groups[p_name] = group_version;
113 };
114
_notification(int p_what)115 void ProximityGroup::_notification(int p_what) {
116
117 switch (p_what) {
118
119 case NOTIFICATION_EXIT_TREE:
120 ++group_version;
121 clear_groups();
122 break;
123 case NOTIFICATION_TRANSFORM_CHANGED:
124 update_groups();
125 break;
126 };
127 };
128
broadcast(String p_name,Variant p_params)129 void ProximityGroup::broadcast(String p_name, Variant p_params) {
130
131 Map<StringName, uint32_t>::Element *E;
132 E = groups.front();
133 while (E) {
134
135 get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
136 E = E->next();
137 };
138 };
139
_proximity_group_broadcast(String p_name,Variant p_params)140 void ProximityGroup::_proximity_group_broadcast(String p_name, Variant p_params) {
141
142 if (dispatch_mode == MODE_PROXY) {
143
144 get_parent()->call(p_name, p_params);
145 } else {
146
147 emit_signal("broadcast", p_name, p_params);
148 };
149 };
150
set_group_name(const String & p_group_name)151 void ProximityGroup::set_group_name(const String &p_group_name) {
152
153 group_name = p_group_name;
154 };
155
get_group_name() const156 String ProximityGroup::get_group_name() const {
157
158 return group_name;
159 };
160
set_dispatch_mode(DispatchMode p_mode)161 void ProximityGroup::set_dispatch_mode(DispatchMode p_mode) {
162
163 dispatch_mode = p_mode;
164 };
165
get_dispatch_mode() const166 ProximityGroup::DispatchMode ProximityGroup::get_dispatch_mode() const {
167
168 return dispatch_mode;
169 };
170
set_grid_radius(const Vector3 & p_radius)171 void ProximityGroup::set_grid_radius(const Vector3 &p_radius) {
172
173 grid_radius = p_radius;
174 };
175
get_grid_radius() const176 Vector3 ProximityGroup::get_grid_radius() const {
177
178 return grid_radius;
179 };
180
_bind_methods()181 void ProximityGroup::_bind_methods() {
182
183 ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup::set_group_name);
184 ClassDB::bind_method(D_METHOD("get_group_name"), &ProximityGroup::get_group_name);
185 ClassDB::bind_method(D_METHOD("set_dispatch_mode", "mode"), &ProximityGroup::set_dispatch_mode);
186 ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup::get_dispatch_mode);
187 ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup::set_grid_radius);
188 ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup::get_grid_radius);
189 ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast);
190 ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast);
191
192 ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
193 ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
194 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
195
196 ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
197
198 BIND_ENUM_CONSTANT(MODE_PROXY);
199 BIND_ENUM_CONSTANT(MODE_SIGNAL);
200 };
201
ProximityGroup()202 ProximityGroup::ProximityGroup() {
203
204 group_version = 0;
205 dispatch_mode = MODE_PROXY;
206
207 cell_size = 1.0;
208 grid_radius = Vector3(1, 1, 1);
209 set_notify_transform(true);
210 };
211
~ProximityGroup()212 ProximityGroup::~ProximityGroup(){
213
214 };
215