Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
trigger.c
Go to the documentation of this file.
1
3{
4 ref OLinkT insider; // DEPRECATED
5
7 protected Object m_Object;
8
10 int timeStamp;
11
14
17
19 {
20 insider = new OLinkT(obj);
21 m_Object = obj;
22 }
23
25 {
26 }
27
29 {
30 return m_Object;
31 }
32};
33
34#ifdef DIAG_DEVELOPER
35typedef Param7<vector, vector, vector, vector, float, string, array<ref TriggerInsider>> DebugTriggerInfo;
36#endif
37
40{
42 const int TIMEOUT = 1000;
44 ref array<ref TriggerInsider> m_insiders;
45
46 #ifdef DIAG_DEVELOPER
47 bool m_Local;//is this trigger spawning on client only ?
48 string m_DebugAreaType;
49 ref array<ref TriggerInsider> m_dbgInsiders;
50 #endif
51
53 private void Trigger()
54 {
55 SetEventMask(EntityEvent.INIT /*| EntityEvent.TOUCH*/ | EntityEvent.FRAME | EntityEvent.ENTER | EntityEvent.LEAVE );
56 SetFlags(EntityFlags.TRIGGER, false);
57
58 m_insiders = new array<ref TriggerInsider>;
59 }
60
62 private void ~Trigger()
63 {
64 #ifdef DIAG_DEVELOPER
65 CleanupDebugShapes(dbgTargets);
66 #endif
67 }
68
74 override void EOnInit(IEntity other, int extra)
75 {
76 SetExtents("-2 -4 -2", "2 4 2");
77 }
78
80 /*override void EOnTouch(IEntity other, int extra)
81 {
82 Object obj;
83 if (Class.CastTo(obj, other) && CanAddObjectAsInsider(obj))
84 AddInsider(obj);
85 }*/
86
88 override void EOnFrame(IEntity other, float timeSlice)
89 {
90 UpdateInsiders(TIMEOUT);
91 }
92
94 override void EOnEnter(IEntity other, int extra)
95 {
96 Object obj;
97 if (Class.CastTo(obj, other) && CanAddObjectAsInsider(obj))
98 AddInsider(obj);
99 }
100
102 override void EOnLeave(IEntity other, int extra)
103 {
104 Object obj;
105 if (Class.CastTo(obj, other))
107 }
109
110
116 void SetExtents(vector mins, vector maxs)
117 {
118 SetCollisionBox(mins, maxs);
119 }
120
122 float GetRadius(vector min, vector max)
123 {
124 return GetCollisionRadius();
125 }
126
128 array<ref TriggerInsider> GetInsiders()
129 {
130 return m_insiders;
131 }
132
134 TriggerInsider GetInsiderForObject(Object object)
135 {
136 TriggerInsider ins;
137
138 for ( int n = 0; n < m_insiders.Count(); ++n )
139 {
140 ins = m_insiders[n];
141 if (ins.GetObject() == object)
142 return ins;
143 }
144
145 return null;
146 }
147
149 int GetInsiderIndexForObject(Object object)
150 {
151 TriggerInsider ins;
152
153 for ( int n = 0; n < m_insiders.Count(); ++n )
154 {
155 ins = m_insiders[n];
156 if (ins.GetObject() == object)
157 return n;
158 }
159
160 return -1;
161 }
163
164
169 override protected void OnEnterBeginEvent(TriggerInsider insider)
170 {
171 // Call the old event for backwards compatibility
172 OnEnter(insider.GetObject());
173 }
174
175 override protected void OnLeaveBeginEvent(TriggerInsider insider)
176 {
177 // Call the old event for backwards compatibility
178 OnLeave(insider.GetObject());
179 }
181
182
187 void OnEnter(Object obj) {}
188
189 void OnLeave(Object obj) {}
191
192
198 protected bool CanAddObjectAsInsider(Object object)
199 {
200 return true;
201 }
202
204 protected bool ShouldRemoveInsider(TriggerInsider insider)
205 {
206 return false;
207 }
208
211 {
212 return false;
213 }
215
216
223 {
224 return new TriggerInsider(obj);
225 }
226
228 protected void AddInsider(Object obj)
229 {
230 if ( !obj )
231 return;
232
233 // Already in?
234 if ( GetInsiderForObject( obj ) )
235 {
236 Error(string.Format("[WARNING] :: [Trigger] :: [%1] :: Insider (%2) is already inside.", GetDebugName(this), GetDebugName(obj)));
237 return;
238 }
239
240 // New Object entered! Fill the data.
241 TriggerInsider insider = CreateInsider(obj);
242 insider.timeStamp = g_Game.GetTime();
243 insider.timeEntered = g_Game.GetTickTime();
244 insider.lastUpdated = insider.timeEntered;
245
246 // Don't add if it is going to be removed anyways..
247 if ( ShouldRemoveInsider(insider) || ShouldRemoveInsiderNoLeave(insider) )
248 return;
249
250 // Keep track of the Object as long as it is inside the Trigger
251 int index = m_insiders.Insert(insider);
252
253 // Call the enter event to signal this Object entered
254 Enter(insider);
255 obj.OnEnterTrigger(this);
256
257 #ifdef TRIGGER_DEBUG_NORMAL
258 Debug.TriggerLog(string.Format("%1: inserted at index %2", GetDebugName(obj), index), "Trigger", "", "AddInsider", GetDebugName(this));
259 #endif
260 }
261
263 protected void RemoveInsider(TriggerInsider insider, int index = -1)
264 {
265 Leave(insider);
266 insider.GetObject().OnLeaveTrigger(this);
267
268 #ifdef TRIGGER_DEBUG_NORMAL
269 Debug.TriggerLog(string.Format("%1: removing at index %2", GetDebugName(insider.GetObject()), index), "Trigger", "", "RemoveInsider", GetDebugName(this));
270 #endif
271
272 if (index >= 0)
273 m_insiders.Remove(index);
274 else
275 m_insiders.RemoveItemUnOrdered(insider);
276 }
277
279 protected void RemoveInsiderByObject(Object object)
280 {
281 TriggerInsider ins;
282 for ( int n = 0; n < m_insiders.Count(); ++n )
283 {
284 ins = m_insiders[n];
285 if (ins.GetObject() == object)
286 {
287 RemoveInsider(ins, n);
288 return;
289 }
290 }
291
292 // As EOnLeave can call this, it is perfectly valid that this Object is not found on Script side
293 // because of "ShouldRemoveInsider" and "ShouldRemoveInsiderNoLeave"
294 }
295
297 protected void UpdateInsiders(int timeout)
298 {
299 #ifdef DIAG_DEVELOPER
300 DebugSendDmgTrigger();
301 #endif
302
303 // Don't do anything if there aren't any insiders
304 if ( m_insiders.Count() == 0 )
305 return;
306
307 // Mark the beginning of the update loop
308 StayStart(m_insiders.Count());
309
310 // Iterate over the current insiders, backwards because we are deleting
311 for ( int n = m_insiders.Count() - 1; n >= 0 ; --n)
312 {
313 TriggerInsider insider = m_insiders.Get(n);
314 Object obj = insider.GetObject();
315
316 // Check if the Object still exists or should be removed without calling OnLeaveEvent
317 if ( !obj || ShouldRemoveInsiderNoLeave(insider) )
318 {
319 #ifdef TRIGGER_DEBUG_BASIC
320 Debug.TriggerLog(string.Format("%1: removed with no Leave.", GetDebugName(obj)), "Trigger", "", "UpdateInsiders", GetDebugName(this));
321 #endif
322
323 m_insiders.Remove(n);
324 continue;
325 }
326
327 // Check if Object left the Trigger or should be removed regardless
328 if ( ShouldRemoveInsider(insider) )
329 {
330 RemoveInsider(insider, n);
331 continue;
332 }
333
334 // Call the OnStayEvent, Object is still inside the Trigger and can be updated
335 // Pass in the time since the Object was last updated (or entered)
336 float currentTime = g_Game.GetTickTime();
337 Stay(insider, currentTime - insider.lastUpdated);
338 insider.lastUpdated = currentTime;
339 }
340
341 // Mark the end of the update loop
342 StayFinish();
343 }
345
350 override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx)
351 {
352 super.OnRPC(sender, rpc_type, ctx);
353
354 #ifdef DIAG_DEVELOPER
355 switch (rpc_type)
356 {
357 case ERPCs.DIAG_TRIGGER_DEBUG:
358 DebugTriggerInfo data = new DebugTriggerInfo(vector.Zero, vector.Zero, vector.Zero, vector.Zero, 0, "", null);
359
360 if (ctx.Read(data))
361 DebugDmgTrigger(data.param1, data.param2, data.param3, data.param4, data.param5, data.param6, data.param7);
362 break;
363 }
364 #endif
365 }
366
367#ifdef DIAG_DEVELOPER
368 void DebugSendDmgTrigger()
369 {
370 vector minmax[2];
371 GetCollisionBox(minmax);
372
373 DebugTriggerInfo data = new DebugTriggerInfo(vector.Zero, vector.Zero, vector.Zero, vector.Zero, 0, "", null);
374 data.param1 = GetWorldPosition();
375 data.param2 = GetOrientation();
376 data.param3 = minmax[0];
377 data.param4 = minmax[1];
378 data.param5 = GetCollisionRadius();
379 data.param6 = m_DebugAreaType;
380 data.param7 = m_insiders;
381
382 if (GetGame().IsMultiplayer() && GetGame().IsServer())
383 PluginDiagMenuServer.SendDataToSubscribersServer(this, ESubscriberSystems.TRIGGERS, ERPCs.DIAG_TRIGGER_DEBUG, data, false);
384 else if (!GetGame().IsMultiplayer() || m_Local)
385 DebugDmgTrigger(data.param1, data.param2, data.param3, data.param4, data.param5, data.param6, data.param7);
386 }
387
388 protected ref array<Shape> dbgTargets = new array<Shape>();
389
390 void DebugDmgTrigger( vector pos, vector orientation, vector min, vector max, float radius, string dmgType, array<ref TriggerInsider> insiders)
391 {
392 CleanupDebugShapes(dbgTargets);
393
394 bool enableDebug = DiagMenu.GetBool(DiagMenuIDs.TRIGGER_DEBUG);
395 if (enableDebug)
396 {
397 if (GetGame().IsMultiplayer() && GetGame().IsServer())
398 {
399 return;
400 }
401
402 vector w_pos, w_pos_sphr, w_pos_lend;
403
404 w_pos = pos;
405 // sphere pos tweaks
406 w_pos_sphr = w_pos;
407 // line pos tweaks
408 w_pos_lend = w_pos;
409
410 //Find way to change colour of box depending on ammoType in a more elegant fashion
411 m_DebugAreaType = dmgType;
412 Shape dbgShape;
413
414 switch ( m_DebugAreaType )
415 {
416 case "FireDamage":
417 dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_RED_A);
418 break;
419
420 case "BarbedWireHit":
421 dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_BLUE_A);
422 break;
423
424 default:
425 dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_GREEN_A);
426 break;
427 }
428
429 if (GetGame().IsMultiplayer() || GetGame().IsServer())
430 m_dbgInsiders = insiders;
431
432 if (m_dbgInsiders.Count() > 0)
433 {
434 //Change colour to make state clearer
435 dbgShape.SetColor(COLOR_YELLOW_A);
436
437 for (int i = 0; i < m_dbgInsiders.Count(); i++)
438 {
439 EntityAI insider_EAI = EntityAI.Cast(m_dbgInsiders[i].GetObject());
440 if (insider_EAI)
441 {
442 vector insiderPos = insider_EAI.GetWorldPosition() + "0 0.1 0";
443 dbgTargets.Insert(Debug.DrawArrow(w_pos, insiderPos));
444 }
445 }
446 }
447 }
448 }
449
450 protected Shape DrawDebugShape(vector pos, vector min, vector max, float radius, int color)
451 {
452 Shape dbgShape;
453
454 switch (GetTriggerShape())
455 {
456 case TriggerShape.BOX:
457 dbgShape = Debug.DrawBoxEx(min, max, color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
458
459 vector mat[4];
460 GetTransform(mat);
461 dbgShape.CreateMatrix(mat);
462 dbgShape.SetMatrix(mat);
463 break;
464 case TriggerShape.CYLINDER:
465 dbgShape = Debug.DrawCylinder(pos, radius, max[1], color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
466 break;
467 case TriggerShape.SPHERE:
468 dbgShape = Debug.DrawSphere(pos, radius, color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
469 break;
470 default:
471 ErrorEx("TriggerShape not found", ErrorExSeverity.WARNING);
472 break;
473 }
474
475 dbgTargets.Insert(dbgShape);
476
477 return dbgShape;
478 }
479
480 protected void CleanupDebugShapes(array<Shape> shapes)
481 {
482 foreach (Shape shape : shapes)
483 {
484 Debug.RemoveShape(shape);
485 }
486
487 shapes.Clear();
488 }
489
490#endif
492};
void DrawDebugShape()
vector GetOrientation()
Super root of all classes in Enforce script.
Definition enscript.c:11
Definition debug.c:2
The class that will be instanced (moddable)
Definition gameplay.c:389
Serialization general interface. Serializer API works with:
Definition serializer.c:56
void Enter(TriggerInsider insider)
void Leave(TriggerInsider insider)
void StayStart(int nrOfInsiders)
void Stay(TriggerInsider insider, float deltaTime)
Scripted Trigger.
override void OnLeave(Object obj)
Definition hologram.c:1586
void OnLeave(Object obj)
Definition trigger.c:189
TriggerInsider CreateInsider(Object obj)
Used for easily overriding TriggerInsider creation without rewriting AddInsider.
Definition trigger.c:222
void OnEnter(Object obj)
Definition trigger.c:187
void RemoveInsider(TriggerInsider insider, int index=-1)
Removing of TriggerInsider.
Definition trigger.c:263
void OnLeaveBeginEvent(TriggerInsider insider)
Definition trigger.c:175
bool ShouldRemoveInsider(TriggerInsider insider)
Condition whether a TriggerInsider should still be updated or not (checked in update loop and before ...
Definition trigger.c:204
void UpdateInsiders(int timeout)
Definition hologram.c:1595
override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx)
Definition trigger.c:350
bool CanAddObjectAsInsider(Object object)
Condition whether an Object can be added as TriggerInsider (checked before calling AddInsider)
Definition trigger.c:198
void OnEnterBeginEvent(TriggerInsider insider)
Definition trigger.c:169
void RemoveInsiderByObject(Object object)
Removing of TriggerInsider through Object.
Definition trigger.c:279
void AddInsider(Object obj)
Adding of new TriggerInsider.
Definition trigger.c:228
bool ShouldRemoveInsiderNoLeave(TriggerInsider insider)
Condition whether a TriggerInsider should still be updated or not, skips OnLeaveEvent (checked in upd...
Definition trigger.c:210
The object which is in a trigger and its metadata.
Object m_Object
Object that data belongs to.
Definition trigger.c:7
void ~TriggerInsider()
Definition trigger.c:24
float lastUpdated
Last time the object was updated in seconds, is used for calculating deltaTime.
Definition trigger.c:16
Object GetObject()
Definition trigger.c:28
float timeEntered
Time the object was first seen in seconds.
Definition trigger.c:13
void TriggerInsider(Object obj)
Definition trigger.c:18
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
DayZGame g_Game
Definition dayzgame.c:3868
override string GetDebugName()
DiagMenuIDs
Definition ediagmenuids.c:2
ERPCs
Definition erpcs.c:2
Link< Object > OLinkT
Definition gameplay.c:1516
proto native CGame GetGame()
const int COLOR_BLUE_A
Definition constants.c:71
const int COLOR_RED_A
Definition constants.c:69
const int COLOR_YELLOW_A
Definition constants.c:72
const int COLOR_GREEN_A
Definition constants.c:70
ErrorExSeverity
Definition endebug.c:62
void Error(string err)
Messagebox with error message.
Definition endebug.c:90
enum ShapeType ErrorEx
proto native void SetFlags(ShapeFlags flags)
ShapeFlags
Definition endebug.c:126
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
EntityEvent
Entity events for event-mask, or throwing event from code.
Definition enentity.c:45
EntityFlags
Entity flags.
Definition enentity.c:115
proto native vobject GetObject(string name)
Loads object from data, or gets it from cache. Object must be released when not used.
float GetRadius()
Definition radialmenu.c:372
proto native void SetCollisionBox(vector mins, vector maxs)
Sets collision box for object.
TriggerShape