Tanoda
TriggerEventGenerator.cs
Go to the documentation of this file.
1using System.Collections.Generic;
2using System.Linq;
3using System.Threading.Tasks;
4using NaughtyAttributes;
6using UnityEngine;
8#if UNITY_EDITOR
9using UnityEditor;
10#endif
11
12public class TriggerEventGenerator : MonoBehaviour
13{
14 private const string ColliderObjectPrefix = "TEG_";
15 [SerializeField] private float _divisionUnitLength = 1;
16 private int callbacks;
17 private int totalCallbacks;
18 public string expectedTrigger = "brush";
19 [Range(0, 1)] public float percentToTrigger = 0.1f;
20
21 public UnityEvent OnTrigger;
22
23 private void Awake()
24 {
25 if (OnTrigger == null) OnTrigger = new UnityEvent();
26 }
27
28 public async void Generate()
29 {
30 var colliderObjectName = $"{ColliderObjectPrefix}{gameObject.name}";
31 RemoveOldColliders(colliderObjectName);
32
33 var meshCollider = gameObject.AddComponent<MeshCollider>();
34 var bounds = meshCollider.bounds;
35
36 Vector3[] gridPositions;
37 int xDivisionCount, yDivisionCount, zDivisionCount;
38 BoundsDivider.Divide(bounds, _divisionUnitLength, out gridPositions, out xDivisionCount,
39 out yDivisionCount, out zDivisionCount);
40
41 var tmpColliders = new Collider[1];
42 var positionCount = gridPositions.Length;
43 var hasColliderPosition = new bool[xDivisionCount * yDivisionCount * zDivisionCount];
44 for (var i = 0; i < positionCount; i++)
45 {
46 var position = gridPositions[i];
47 if (Physics.OverlapSphereNonAlloc(position, _divisionUnitLength / 2f, tmpColliders) == 0) continue;
48
49 hasColliderPosition[i] = true;
50 }
51
52 var colliderObject = new GameObject(colliderObjectName);
53 colliderObject.transform.SetParent(transform);
54 var numberofcollidersnow = 0;
55 var newGoNum = 1;
56 while (hasColliderPosition.Any(p => p))
57 {
58 await Task.Delay(1);
59 var combineIndex = 0;
60 var combineCountMax = int.MinValue;
61 var xCombineEdgeCount = 0;
62 var yCombineEdgeCount = 0;
63 var zCombineEdgeCount = 0;
64 for (var i = 0; i < positionCount; i++)
65 {
66 if (!hasColliderPosition[i]) continue;
67
68 var checkIndex = i;
69 var xEdgeCount = 0;
70 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
71 {
72 checkIndex += zDivisionCount * yDivisionCount;
73 xEdgeCount++;
74
75 if (checkIndex % (zDivisionCount * yDivisionCount) == 0) break;
76 }
77
78 checkIndex = i;
79 var yEdgeCount = 0;
80 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
81 {
82 checkIndex += zDivisionCount;
83 yEdgeCount++;
84
85 if (checkIndex % (zDivisionCount * yDivisionCount) / zDivisionCount == 0) break;
86 }
87
88 checkIndex = i;
89 var zEdgeCount = 0;
90 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
91 {
92 checkIndex++;
93 zEdgeCount++;
94
95 if (checkIndex % zDivisionCount == 0) break;
96 }
97
98 var c = 0;
99 var resultX = 0;
100 var resultY = 0;
101 var resultZ = 0;
102 for (var x = 1; x <= xEdgeCount; x++)
103 for (var y = 1; y <= yEdgeCount; y++)
104 for (var z = 1; z <= zEdgeCount; z++)
105 {
106 if (!IsValidCubes(hasColliderPosition, i, x, y, z, yDivisionCount, zDivisionCount)) continue;
107
108 var count = x * y * z;
109 if (count < c) continue;
110
111 c = count;
112 resultX = x;
113 resultY = y;
114 resultZ = z;
115 }
116
117 xEdgeCount = resultX;
118 yEdgeCount = resultY;
119 zEdgeCount = resultZ;
120
121 var margeCount = xEdgeCount * yEdgeCount * zEdgeCount;
122 if (margeCount <= combineCountMax) continue;
123
124 combineIndex = i;
125 xCombineEdgeCount = xEdgeCount;
126 yCombineEdgeCount = yEdgeCount;
127 zCombineEdgeCount = zEdgeCount;
128 combineCountMax = margeCount;
129 }
130
131 for (var x = 0; x < xCombineEdgeCount; x++)
132 for (var y = 0; y < yCombineEdgeCount; y++)
133 for (var z = 0; z < zCombineEdgeCount; z++)
134 {
135 var index = combineIndex + zDivisionCount * yDivisionCount * x + zDivisionCount * y + z;
136 hasColliderPosition[index] = false;
137 }
138
139 var collider = colliderObject.AddComponent<BoxColliderExtended>();
140 collider.isTrigger = true;
141 collider.center = gridPositions[combineIndex] +
142 new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
143 _divisionUnitLength / 2f - Vector3.one * _divisionUnitLength / 2f;
144 collider.size = new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
145 _divisionUnitLength;
146 collider.OnTriggered.AddListener(Callback);
147 numberofcollidersnow++;
148 totalCallbacks++;
149 if (numberofcollidersnow >= 31)
150 {
151 newGoNum++;
152 colliderObject = new GameObject(colliderObjectName + $"_{newGoNum}");
153 colliderObject.transform.SetParent(transform);
154 numberofcollidersnow = 0;
155 }
156 }
157
158#if UNITY_EDITOR
159 DestroyImmediate(meshCollider);
160#endif
161 Destroy(meshCollider);
162 }
163
164
165 [Button]
166 public GameObject[] GenerateThreadLocking()
167 {
168 var colliderObjectName = $"{ColliderObjectPrefix}{gameObject.name}";
169 RemoveOldColliders(colliderObjectName);
170
171 var backupScale = transform.localScale;
172
173 var meshCollider = gameObject.AddComponent<MeshCollider>();
174 meshCollider.convex = true;
175 MeshCollider meshCollider2 = null;
176 var bounds = meshCollider.bounds;
177
178 var smallestSide = Macro.SmallestAxis(bounds.size);
179
180 Debug.Log("smallestSide: " + smallestSide);
181 if (1.5f / smallestSide > 1)
182 {
183 Debug.Log("scaling to: " + 1.5f / smallestSide);
184 transform.localScale *= 1.5f / smallestSide;
185 meshCollider2 = gameObject.AddComponent<MeshCollider>();
186 meshCollider2.convex = true;
187 bounds = meshCollider2.bounds;
188 }
189
190 Vector3[] gridPositions;
191 int xDivisionCount, yDivisionCount, zDivisionCount;
192 BoundsDivider.Divide(bounds, _divisionUnitLength, out gridPositions, out xDivisionCount,
193 out yDivisionCount, out zDivisionCount);
194
195 var tmpColliders = new Collider[1];
196 var positionCount = gridPositions.Length;
197 var hasColliderPosition = new bool[xDivisionCount * yDivisionCount * zDivisionCount];
198 for (var i = 0; i < positionCount; i++)
199 {
200 var position = gridPositions[i];
201 if (Physics.OverlapSphereNonAlloc(position, _divisionUnitLength / 2f, tmpColliders) == 0) continue;
202
203 hasColliderPosition[i] = true;
204 }
205
206 var colliderObject = new GameObject(colliderObjectName);
207 colliderObject.transform.SetParent(transform);
208 var numberofcollidersnow = 0;
209 var newGoNum = 1;
210 var retList = new List<GameObject>();
211 retList.Add(colliderObject);
212 while (hasColliderPosition.Any(p => p))
213 {
214 var combineIndex = 0;
215 var combineCountMax = int.MinValue;
216 var xCombineEdgeCount = 0;
217 var yCombineEdgeCount = 0;
218 var zCombineEdgeCount = 0;
219 for (var i = 0; i < positionCount; i++)
220 {
221 if (!hasColliderPosition[i]) continue;
222
223 var checkIndex = i;
224 var xEdgeCount = 0;
225 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
226 {
227 checkIndex += zDivisionCount * yDivisionCount;
228 xEdgeCount++;
229
230 if (checkIndex % (zDivisionCount * yDivisionCount) == 0) break;
231 }
232
233 checkIndex = i;
234 var yEdgeCount = 0;
235 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
236 {
237 checkIndex += zDivisionCount;
238 yEdgeCount++;
239
240 if (checkIndex % (zDivisionCount * yDivisionCount) / zDivisionCount == 0) break;
241 }
242
243 checkIndex = i;
244 var zEdgeCount = 0;
245 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
246 {
247 checkIndex++;
248 zEdgeCount++;
249
250 if (checkIndex % zDivisionCount == 0) break;
251 }
252
253 var c = 0;
254 var resultX = 0;
255 var resultY = 0;
256 var resultZ = 0;
257 for (var x = 1; x <= xEdgeCount; x++)
258 for (var y = 1; y <= yEdgeCount; y++)
259 for (var z = 1; z <= zEdgeCount; z++)
260 {
261 if (!IsValidCubes(hasColliderPosition, i, x, y, z, yDivisionCount, zDivisionCount)) continue;
262
263 var count = x * y * z;
264 if (count < c) continue;
265
266 c = count;
267 resultX = x;
268 resultY = y;
269 resultZ = z;
270 }
271
272 xEdgeCount = resultX;
273 yEdgeCount = resultY;
274 zEdgeCount = resultZ;
275
276 var margeCount = xEdgeCount * yEdgeCount * zEdgeCount;
277 if (margeCount <= combineCountMax) continue;
278
279 combineIndex = i;
280 xCombineEdgeCount = xEdgeCount;
281 yCombineEdgeCount = yEdgeCount;
282 zCombineEdgeCount = zEdgeCount;
283 combineCountMax = margeCount;
284 }
285
286 for (var x = 0; x < xCombineEdgeCount; x++)
287 for (var y = 0; y < yCombineEdgeCount; y++)
288 for (var z = 0; z < zCombineEdgeCount; z++)
289 {
290 var index = combineIndex + zDivisionCount * yDivisionCount * x + zDivisionCount * y + z;
291 hasColliderPosition[index] = false;
292 }
293
294 var collider = colliderObject.AddComponent<BoxColliderExtended>();
295 collider.isTrigger = true;
296 collider.center = gridPositions[combineIndex] +
297 new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
298 _divisionUnitLength / 2f - Vector3.one * _divisionUnitLength / 2f;
299 collider.size = new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
300 _divisionUnitLength;
301 collider.OnTriggered.AddListener(Callback);
302 numberofcollidersnow++;
303 totalCallbacks++;
304 if (numberofcollidersnow >= 31)
305 {
306 newGoNum++;
307 colliderObject = new GameObject(colliderObjectName + $"_{newGoNum}");
308 colliderObject.transform.SetParent(transform);
309 numberofcollidersnow = 0;
310 retList.Add(colliderObject);
311 }
312 }
313
314 transform.localScale = backupScale;
315
316#if UNITY_EDITOR
317 DestroyImmediate(meshCollider);
318 if (meshCollider2 != null) DestroyImmediate(meshCollider2);
319#endif
320 Destroy(meshCollider);
321 if (meshCollider2 != null) Destroy(meshCollider2);
322 return retList.ToArray();
323 }
324
325 public void Callback(Collider other, BoxColliderExtended sender)
326 {
327 if (other.name.Contains(expectedTrigger))
328 {
329 Debug.Log("callback fired!");
330 sender.enabled = false;
331 callbacks++;
332 if (callbacks >= totalCallbacks * percentToTrigger)
333 {
334 Debug.Log("callback Finished!");
335 OnTrigger?.Invoke();
336 RemoveOldColliders($"{ColliderObjectPrefix}{gameObject.name}");
337 Destroy(this);
338 }
339 }
340 }
341
342 void RemoveOldColliders(string colliderObjectName)
343 {
344 var child = transform.Find(colliderObjectName);
345 if (child != null)
346 {
347#if UNITY_EDITOR
348 if (!EditorApplication.isPlaying) DestroyImmediate(child.gameObject);
349#endif
350 Destroy(child.gameObject);
351 }
352
353 var i = 1;
354 while (true)
355 {
356 child = transform.Find(colliderObjectName + "_" + i);
357 if (child != null)
358 {
359#if UNITY_EDITOR
360 if (!EditorApplication.isPlaying) DestroyImmediate(child.gameObject);
361#endif
362 Destroy(child.gameObject);
363 i++;
364 }
365 else
366 {
367 return;
368 }
369 }
370 }
371
372 bool IsValidCubes(bool[] hasCollider, int index, int xEdgeCount, int yEdgeCount, int zEdgeCount, int yDivisionCount,
373 int zDivisionCount)
374 {
375 for (var x = 0; x < xEdgeCount; x++)
376 for (var y = 0; y < yEdgeCount; y++)
377 for (var z = 0; z < zEdgeCount; z++)
378 {
379 var i = index + x * yDivisionCount * zDivisionCount + y * zDivisionCount + z;
380 if (hasCollider[i]) continue;
381
382 return false;
383 }
384
385 return true;
386 }
387}
UnityEngine.UI.Button Button
Definition: Pointer.cs:7
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
Definition: Macro.cs:12
static float SmallestAxis(Vector3 v)
Definition: Macro.cs:185
void Callback(Collider other, BoxColliderExtended sender)
GameObject[] GenerateThreadLocking()