Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ItemPlacementComponent.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/Components", description: "")]
5
7{
8 [Attribute("{56EBF5038622AC95}Assets/Conflict/CanBuild.emat")]
9 protected ResourceName m_sCanBuildMaterial;
10
11 [Attribute("{14A9DCEA57D1C381}Assets/Conflict/CannotBuild.emat")]
13
14 [Attribute("{8FBC3A6E946F056E}Common/Materials/Default_Transparent.emat")]
16
17 protected int m_iEquipComplete;
18 protected int m_iTargetEntityNodeID;
19 protected bool m_bInEditor;
21 protected vector m_vCurrentMat[4];
25 protected SCR_PlaceableItemComponent m_PlaceableItem;
28 protected RplId m_TargetId;
30
31 static const string ACTION_CONTEXT_PLACEMENT = "CharacterPlacementContext";
32 static const string ACTION_NAME_PLACEMENT = "CharacterPlaceItem";
33 static const string ACTION_NAME_FORCE_PLACEMENT = "CharacterForcePlaceItem";
34 static const string ACTION_NAME_CHANGE_ITEM = "ChangePlacedItem";
35 static const string ACTION_NAME_CHANGE_VARIANT = "ChangedPlacedVariant";
36
37 //------------------------------------------------------------------------------------------------
45 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
46 void RPC_AskSetPlacementPosition(vector right, vector up, vector forward, vector position, RplId placeableId, RplId characterId)
47 {
48 RplComponent rplComponent = RplComponent.Cast(Replication.FindItem(placeableId));
49 if (!rplComponent)
50 return;
51
52 IEntity item = rplComponent.GetEntity();
54 if (!itemComponent)
55 return;
56
57 if (!characterId.IsValid())
58 return;
59
60 RplComponent characterRplComp = RplComponent.Cast(Replication.FindItem(characterId));
61 if (!characterRplComp)
62 return;
63
64 ChimeraCharacter placingCharacter = ChimeraCharacter.Cast(characterRplComp.GetEntity());
65 if (!placingCharacter)
66 return;
67
68 SCR_PlaceableItemComponent placebaleItemComp = SCR_PlaceableItemComponent.Cast(item.FindComponent(SCR_PlaceableItemComponent));
69 if (!placebaleItemComp)
70 return;
71
72 // +10% to compensate for minor movements that may come from the animations, as locally client evaluates the distance from the position at which he started the placement
73 float maxPlacementDistance = placebaleItemComp.GetMaxPlacementDistance() * 1.1;
74 if (SCR_PlaceableItemComponent.GetDistanceFromCharacter(placingCharacter, position, placebaleItemComp.GetDistanceMeasurementMethod()) > maxPlacementDistance)
75 return; // to ensure that someone isnt placing f.e. a explosive charge further than he should be able to
76
77 itemComponent.SetPlacementPosition(right, up, forward, position, characterId);
78 }
79
80 //------------------------------------------------------------------------------------------------
83 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
84 void RPC_AskPlaceItem(RplId placeableId)
85 {
86 RplComponent rplComponent = RplComponent.Cast(Replication.FindItem(placeableId));
87 if (!rplComponent)
88 return;
89
90 IEntity item = rplComponent.GetEntity();
92 if (!itemComponent)
93 return;
94
95 itemComponent.PlaceItem();
96 }
97
98 //------------------------------------------------------------------------------------------------
103 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
104 void RPC_AskPlaceItemWithParentChange(RplId placeableId, RplId targetId, int nodeId)
105 {
106 RplComponent rplComponent = RplComponent.Cast(Replication.FindItem(placeableId));
107 if (!rplComponent)
108 return;
109
110 IEntity item = rplComponent.GetEntity();
112 if (!itemComponent)
113 return;
114
115 if (targetId.IsValid())
116 itemComponent.PlaceItemWithParentChange(targetId, nodeId);
117 else
118 itemComponent.PlaceItem();
119 }
120
121 //------------------------------------------------------------------------------------------------
122 protected void UnregisterEvents(IEntity from)
123 {
124 ChimeraCharacter character = ChimeraCharacter.Cast(from);
125 if (!character)
126 return;
127
128 BaseWeaponManagerComponent weaponManager = character.GetWeaponManager();
129 if (weaponManager)
130 {
131 weaponManager.m_OnWeaponChangeCompleteInvoker.Remove(OnWeaponChangeEnded);
132 weaponManager.m_OnWeaponChangeStartedInvoker.Remove(OnWeaponChanged);
133 }
134
135 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
136 if (characterController)
137 characterController.GetOnPlayerDeathWithParam().Remove(OnCharacterDeath);
138
139 SCR_CompartmentAccessComponent compartmentAccessComponent = SCR_CompartmentAccessComponent.Cast(character.GetCompartmentAccessComponent());
140 if (compartmentAccessComponent)
141 {
142 compartmentAccessComponent.GetOnCompartmentEntered().Remove(OnComparmentEntered);
143 compartmentAccessComponent.GetOnCompartmentLeft().Remove(GetOnCompartmentLeft);
144 }
145 }
146
147 //------------------------------------------------------------------------------------------------
148 protected void RegisterEvents(IEntity to)
149 {
150 ChimeraCharacter character = ChimeraCharacter.Cast(to);
151 if (!character)
152 return;
153
154 BaseWeaponManagerComponent weaponManager = character.GetWeaponManager();
155 if (weaponManager)
156 {
157 weaponManager.m_OnWeaponChangeCompleteInvoker.Insert(OnWeaponChangeEnded);
158 weaponManager.m_OnWeaponChangeStartedInvoker.Insert(OnWeaponChanged);
159 }
160
161 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
162 if (characterController)
163 characterController.GetOnPlayerDeathWithParam().Insert(OnCharacterDeath);
164
165 SCR_CompartmentAccessComponent compartmentAccessComponent = SCR_CompartmentAccessComponent.Cast(character.GetCompartmentAccessComponent());
166 if (compartmentAccessComponent)
167 {
168 compartmentAccessComponent.GetOnCompartmentEntered().Insert(OnComparmentEntered);
169 compartmentAccessComponent.GetOnCompartmentLeft().Insert(GetOnCompartmentLeft);
170 }
171 }
172
173 //------------------------------------------------------------------------------------------------
175 {
176 m_PlacedItem = null;
177
178 ChimeraCharacter characterTo = ChimeraCharacter.Cast(to);
179 if (characterTo)
180 {
181 m_CompartmnetAccessComponent = SCR_CompartmentAccessComponent.Cast(characterTo.GetCompartmentAccessComponent());
182 m_PlacedItem = characterTo.GetCharacterController().GetRightHandItem();
183 }
184 else
185 {
187 }
188
189 // unregister from previous event handler
190 UnregisterEvents(from);
191
192 // register to new event handler
193 RegisterEvents(to);
194
195 ChimeraCharacter previousCharacter = ChimeraCharacter.Cast(from);
196 if (!previousCharacter)
197 return;
198
199 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(previousCharacter.GetCharacterController());
200 if (!characterController)
201 return;
202
203 characterController.m_OnItemUseEndedInvoker.Remove(OnPlacingEnded);
204 GetGame().GetCallqueue().Remove(ValidateTargetEntityExistance);
205 if (!characterController.IsUsingItem())
206 return;
207
208 CharacterAnimationComponent animationComponent = characterController.GetAnimationComponent();
209 if (!animationComponent)
210 return;
211
212 animationComponent.GetCommandHandler().CancelItemUse();
213
214 SCR_NotificationsComponent.SendLocal(ENotification.PLACEABLE_ITEM_CANT_PLACE_GENERIC); // show some generic information, just to be clear that his placement action has failed
215 }
216
217 //------------------------------------------------------------------------------------------------
219 protected void ForcePlaceItem()
220 {
221 if (m_eCantPlaceReason == ENotification.PLACEABLE_ITEM_CANT_PLACE_NOT_ENOUGH_SPACE)
223
225 }
226
227 //------------------------------------------------------------------------------------------------
229 protected void StartPlaceItem()
230 {
232 if (!character)
233 return;
234
235 if (m_eCantPlaceReason > 0)
236 {
237 SCR_NotificationsComponent.SendLocal(m_eCantPlaceReason);
238 return;
239 }
240
241 bool skipItemUsage;
242 if (m_PlaceableItem.OverrideStartPlaceAction(this, skipItemUsage))
243 {
244 if (m_eCantPlaceReason != 0)
245 {
246 SCR_NotificationsComponent.SendLocal(m_eCantPlaceReason);
247 return;
248 }
249
250 if (skipItemUsage)
251 {
252 OnPlacingEnded(m_PlacedItem, true, null);
253 return;
254 }
255 }
256
257 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
258 if (!characterController)
259 return;
260
261 characterController.SetDisableWeaponControls(true);
262 characterController.SetDisableMovementControls(true);
263
264 if (characterController.IsUsingItem())
265 return;
266
267 CharacterAnimationComponent animationComponent = character.GetAnimationComponent();
268 int itemActionId = animationComponent.BindCommand("CMD_Item_Action");
269 vector mat[4];
270 Math3D.MatrixCopy(m_vCurrentMat, mat);
271 PointInfo ptWS = new PointInfo();
272 mat[2] = (mat[3] - character.GetOrigin()).Normalized();
273 mat[1] = vector.Up;
274 mat[0] = Vector(mat[2][2], mat[2][1], -mat[2][0]);
275 ptWS.Set(null, "", mat);
276
278 params.SetEntity(m_PlacedItem);
279 params.SetAllowMovementDuringAction(false);
280 params.SetKeepInHandAfterSuccess(false);
281 params.SetCommandID(itemActionId);
282 params.SetCommandIntArg(1);
283 params.SetMaxAnimLength(15.0);
284 params.SetAlignmentPoint(ptWS);
285
286 DisablePreview(); // disable preview and suspend placement logic to prevent executing this
287 characterController.m_OnItemUseEndedInvoker.Insert(OnPlacingEnded); // subscribe to this invoker now, as there is always a chance that someone will be so fast that we will miss it
288
289 if (!characterController.TryUseItemOverrideParams(params))
290 OnPlacingEnded(m_PlaceableItem.GetOwner(), false, params); // if item usage has failed, we need to manually informs ourselves that placement has failed
292 GetGame().GetCallqueue().CallLater(ValidateTargetEntityExistance, 500, true); // used to locally check if the entity to which player wants to attach the object is still there
293
294 characterController.GetAnimationComponent().GetCommandHandler().AlignNewTurns();
295
296 }
297
298 //------------------------------------------------------------------------------------------------
299 protected void OnPlacingEnded(IEntity item, bool successful, ItemUseParameters animParams)
300 {
301 GetGame().GetCallqueue().Remove(ValidateTargetEntityExistance);
302
304 if (!controlledEntity)
305 return;
306
307 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(controlledEntity.GetCharacterController());
308 if (!characterController)
309 return;
310
311 RplComponent characterRplComp = controlledEntity.GetRplComponent();
312 if (!characterRplComp)
313 return;
314
315 characterController.SetDisableWeaponControls(true);
316 characterController.SetDisableMovementControls(true);
317
318 characterController.m_OnItemUseEndedInvoker.Remove(OnPlacingEnded);
319
320 if (!m_PlacedItem)
321 return;
322
323 if (!successful)
324 {
325 EnablePreview(item);
326 return;
327 }
328
329 SCR_InventoryStorageManagerComponent storageManager = SCR_InventoryStorageManagerComponent.Cast(characterController.GetInventoryStorageManager());
330 if (!storageManager)
331 return;
332
333 SCR_CharacterInventoryStorageComponent storage = storageManager.GetCharacterStorage();
334 if (!storage)
335 return;
336
337 RplComponent rplComponent = RplComponent.Cast(m_PlacedItem.FindComponent(RplComponent));
338 if (!rplComponent)
339 return;
340
342 if (placeableItem)
343 {
345 cb.m_PlaceableId = rplComponent.Id();
346 cb.m_TargetId = m_TargetId;
347 cb.m_iNodeId = m_iTargetEntityNodeID;
348 cb.m_bIsBeingAttachedToEntity = m_bIsBeingAttachedToEntity;
349
350 BaseContainer gameplaySettings = GetGame().GetGameUserSettings().GetModule("SCR_GameplaySettings");
351 bool autoEquipNext;
352 if (gameplaySettings && gameplaySettings.Get("m_bAutoEquipNextPlaceableItem", autoEquipNext) && !m_PlaceableItem.OverrideAutoEquipMechanism(cb.m_ChainedCallback, this, m_PlacedItem, autoEquipNext))
353 {
354 SCR_InvEquipAnyItemCB equipmentCallback = new SCR_InvEquipAnyItemCB();
355 if (storageManager.TryAssigningNextItemToQuickSlot(m_PlacedItem, equipCallback: equipmentCallback, equipNewItem: autoEquipNext))
356 cb.m_ChainedCallback = equipmentCallback;
357 }
358
359 Rpc(RPC_AskSetPlacementPosition, m_vCurrentMat[0], m_vCurrentMat[1], m_vCurrentMat[2], m_vCurrentMat[3], rplComponent.Id(), characterRplComp.Id());
360 if (storageManager.TryRemoveItemFromStorage(m_PlacedItem, placeableItem.GetParentSlot().GetStorage(), cb))
361 return;
362 }
363
364 if (!m_PlaceableItem.OverrideOnPlacingEnded(this))
366 }
367
368 //------------------------------------------------------------------------------------------------
374 void AskPlaceItem(RplId placeableId, RplId targetId, int nodeId, bool isBeingAttachedToEntity)
375 {
377 Rpc(RPC_AskPlaceItem, placeableId);
378 else if (targetId.IsValid())
379 Rpc(RPC_AskPlaceItemWithParentChange, placeableId, targetId, nodeId);
380 }
381
382 //------------------------------------------------------------------------------------------------
384 {
385 TraceParam param = new TraceParam();
386 param.Start = m_aCamDeploymentPosition[3];
387 param.End = param.Start + m_aCamDeploymentPosition[2] * m_PlaceableItem.GetMaxPlacementDistance();
388 param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
390 param.LayerMask = EPhysicsLayerPresets.Projectile;
391 BaseWorld world = GetOwner().GetWorld();
392 float traceDistance = world.TraceMove(param, FilterCallback);
393 IEntity tracedEntity = param.TraceEnt;
394
395 if (!tracedEntity && m_TargetId.IsValid())
396 {
397 m_eCantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_SURFACE_NO_LONGER_THERE;//entity to which we were attaching is no longer there
398 }
399 else if (tracedEntity)
400 {
401 RplComponent rplComp = RplComponent.Cast(tracedEntity.FindComponent(RplComponent));
402 if (!rplComp || rplComp.Id() != m_TargetId)
403 m_eCantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_SURFACE_NO_LONGER_THERE;//entity to which we were attaching is no longer there
404 else if (m_iTargetEntityNodeID != param.NodeIndex)
405 m_eCantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_DIFFERENT_SURFACE;//same entity but different part of it is now there
406 else
408 }
409
410 if (!m_PlacedItem)
411 m_eCantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_GENERIC; // we lost the reference so we need to abort the placement logic
412
413 if (m_eCantPlaceReason > 0)
414 {
416 if (!character)
417 return;
418
419 SCR_CharacterControllerComponent characterController = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
420 if (!characterController)
421 return;
422
423 if (!characterController.IsUsingItem())
424 {
425 GetGame().GetCallqueue().Remove(ValidateTargetEntityExistance);
426 }
427 else
428 {
429 CharacterAnimationComponent animationComponent = characterController.GetAnimationComponent();
430 if (!animationComponent)
431 return;
432
433 CharacterCommandHandlerComponent commandHandler = animationComponent.GetCommandHandler();
434 commandHandler.CancelItemUse();
435 SCR_NotificationsComponent.SendLocal(m_eCantPlaceReason);
436 GetGame().GetCallqueue().Remove(ValidateTargetEntityExistance);
437 }
438 }
439 }
440
441 //------------------------------------------------------------------------------------------------
445 {
446 m_PlacedItem = item;
447 }
448
449 //------------------------------------------------------------------------------------------------
453 void SetPreviewEntity(IEntity preview, bool deleteOldPreview = true)
454 {
455 if (deleteOldPreview && m_PreviewEntity)
456 delete m_PreviewEntity;
457
458 m_PreviewEntity = preview;
459 }
460
461 //------------------------------------------------------------------------------------------------
464 void SetPlaceableItemComponent(SCR_PlaceableItemComponent placeableItemComp)
465 {
466 m_PlaceableItem = placeableItemComp;
467 }
468
469 //------------------------------------------------------------------------------------------------
472 SCR_PlaceableItemComponent GetPlaceableItemComponent()
473 {
474 return m_PlaceableItem;
475 }
476
477 //------------------------------------------------------------------------------------------------
480 void EnablePlacement(bool enabled)
481 {
482 if (enabled)
483 {
484 GetGame().GetInputManager().AddActionListener(ACTION_NAME_PLACEMENT, EActionTrigger.DOWN, StartPlaceItem);
485 if (m_PlaceableItem && m_PlaceableItem.GetCanBeForcedPlaced())
486 GetGame().GetInputManager().AddActionListener(ACTION_NAME_FORCE_PLACEMENT, EActionTrigger.DOWN, ForcePlaceItem);
487
489 }
490 else
491 {
492 GetGame().GetInputManager().RemoveActionListener(ACTION_NAME_PLACEMENT, EActionTrigger.DOWN, StartPlaceItem);
493 GetGame().GetInputManager().RemoveActionListener(ACTION_NAME_FORCE_PLACEMENT, EActionTrigger.DOWN, ForcePlaceItem);
495 }
496 }
497
498 //------------------------------------------------------------------------------------------------
500 {
501 EnablePlacement(false);
502 delete m_PreviewEntity;
503 }
504
505 //------------------------------------------------------------------------------------------------
506 protected void EnablePreview(IEntity weapon)
507 {
508 m_PlaceableItem = SCR_PlaceableItemComponent.Cast(weapon.FindComponent(SCR_PlaceableItemComponent));
509 if (!m_PlaceableItem)
510 return;
511
512 EnablePlacement(true);
513
514 if (!m_PreviewEntity)
515 m_PreviewEntity = GetGame().SpawnEntity(GenericEntity, GetOwner().GetWorld());
516
517 m_PreviewEntity.SetObject(m_PlaceableItem.GetPreviewVobject(), string.Empty);
518 }
519
520 //------------------------------------------------------------------------------------------------
521 protected void OnComparmentEntered(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
522 {
524 }
525
526 //------------------------------------------------------------------------------------------------
527 protected void GetOnCompartmentLeft()
528 {
530 }
531
532 //------------------------------------------------------------------------------------------------
536 {
537 WeaponSlotComponent weaponSlot = WeaponSlotComponent.Cast(weaponComponent);
538 if (!weaponSlot)
539 return null;
540
541 return weaponSlot.GetWeaponEntity();
542 }
543
544 //------------------------------------------------------------------------------------------------
545 protected void OnWeaponChangeEnded(BaseWeaponComponent newWeaponSlot)
546 {
549 }
550
551 //------------------------------------------------------------------------------------------------
552 protected void OnWeaponChanged(BaseWeaponComponent newWeaponSlot)
553 {
554 DisablePreview(); // Automatically disable preview to handle cases where anim event could be missing
556 }
557
558 //------------------------------------------------------------------------------------------------
559 protected void OnCharacterDeath(SCR_CharacterControllerComponent characterController, IEntity killerEntity, notnull Instigator killer)
560 {
561 UnregisterEvents(characterController.GetOwner());
562 m_PlacedItem = null; // Reset this cached value
564 }
565
566 //------------------------------------------------------------------------------------------------
567 // Reacts to weapon changes of local character
568 protected void TogglePreview(IEntity weapon)
569 {
570 if (m_bInEditor || !weapon || !weapon.FindComponent(SCR_PlaceableItemComponent))
571 {
573 }
574 else
575 {
577 return;
578
581 if (characterController)
582 characterController.m_OnItemUseEndedInvoker.Dump();
583
584 EnablePreview(weapon);
585 }
586 }
587
588 //------------------------------------------------------------------------------------------------
589 protected override void EOnFrame(IEntity owner, float timeSlice)
590 {
591 if (m_CompartmnetAccessComponent.IsGettingIn())
592 {
594 return;
595 }
596
598 {
599 // This handles situations where f. e. land mines explode in characters hands
601 return;
602 }
603
604 GetGame().GetInputManager().ActivateContext(ACTION_CONTEXT_PLACEMENT);
605 CameraManager cameraManager = GetGame().GetCameraManager();
606 if (!cameraManager)
607 return;
608
609 CameraBase currentCamera = cameraManager.CurrentCamera();
610 if (!currentCamera)
611 return;
612
613 vector cameraMat[4];
614 currentCamera.GetTransform(cameraMat);
615 float maxPlacementDistance = m_PlaceableItem.GetMaxPlacementDistance();
616 SCR_EPlacementType placementType = m_PlaceableItem.GetPlacementType();
617
619 switch (placementType)
620 {
621 case SCR_EPlacementType.XZ_FIXED:
622 UseXZFixedPlacement(owner, maxPlacementDistance, cameraMat);
623 break;
624
625 case SCR_EPlacementType.XYZ:
626 UseXYZPlacement(owner, maxPlacementDistance, cameraMat);
627 break;
628 }
629
630 if (m_eCantPlaceReason == 0)
631 SCR_Global.SetMaterial(m_PreviewEntity, m_sCanBuildMaterial);
632 else if (m_eCantPlaceReason == ENotification.PLACEABLE_ITEM_CANT_PLACE_DISTANCE)
634 else
636 }
637
638 //------------------------------------------------------------------------------------------------
643 void UseXZFixedPlacement(IEntity owner, float maxPlacementDistance, vector cameraMat[4])
644 {
645 vector direction = cameraMat[2];
646 direction[1] = 0;
647 direction.Normalize();
648
650
651 // Trace against terrain and entities to detect item placement position
652 TraceParam param = new TraceParam();
653 param.Start = character.GetOrigin() + maxPlacementDistance * direction + vector.Up;
654 param.End = param.Start - 5 * vector.Up;
655 param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
656 param.Exclude = character;
657 param.LayerMask = EPhysicsLayerPresets.Projectile;
658 BaseWorld world = owner.GetWorld();
659 float traceDistance = world.TraceMove(param, FilterCallback);
660 m_PreviewEntity.GetTransform(m_vCurrentMat);
661 m_vCurrentMat[3] = param.Start + ((param.End - param.Start) * traceDistance);
662 vector up = param.TraceNorm;
663
664 SCR_EntityHelper.OrientUpToVector(up, m_vCurrentMat);
665 vector matCopy[4] = m_vCurrentMat;
666 m_PlaceableItem.OverridePreviewTransform(this, matCopy);
667 m_PreviewEntity.SetTransform(matCopy);
668 m_PreviewEntity.Update();
669
670 if (m_PlaceableItem.OverrideIsSurfaceValid(this, m_eCantPlaceReason, param.TraceEnt, m_vCurrentMat[3], param.TraceNorm, param.NodeIndex, param.ColliderIndex, param.SurfaceProps, param.TraceMaterial, param.ColliderName) && m_eCantPlaceReason != 0)
671 return;
672
673 ValidatePlacement(up, param.TraceEnt, world, character, m_eCantPlaceReason);
674 }
675
676 //------------------------------------------------------------------------------------------------
677 protected bool FilterCallback(IEntity e)
678 {
679 Physics physics = e.GetPhysics();
680 if (physics)
681 {
682 if ((physics.IsDynamic() || physics.IsKinematic()) && !m_PlaceableItem.CanAttachToDynamicObject())
683 return false;
684 }
685
686 return true;
687 }
688
689 //------------------------------------------------------------------------------------------------
694 void UseXYZPlacement(IEntity owner, float maxPlacementDistance, vector cameraMat[4])
695 {
696 // Trace against terrain and entities to detect item placement position
698 if (!character)
699 return;
700
701 TraceParam param = new TraceParam();
702 param.Start = character.EyePosition();
703 param.End = param.Start + cameraMat[2] * maxPlacementDistance;
704 param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
706 param.LayerMask = EPhysicsLayerPresets.Projectile;
707 BaseWorld world = owner.GetWorld();
708 float traceDistance = world.TraceMove(param, FilterCallback);
709 m_PreviewEntity.GetTransform(m_vCurrentMat);
710 m_vCurrentMat[3] = param.Start + ((param.End - param.Start) * traceDistance);
711 vector up = param.TraceNorm;
712 m_vCurrentMat[3] = m_vCurrentMat[3] + up * 0.01;
713
714 IEntity tracedEntity = param.TraceEnt;
715
716 if (traceDistance == 1) // Assume we didn't hit anything and snap item on the ground
717 {
718 // Trace against terrain and entities to detect new placement position
719 param.Start = param.End + vector.Up;
720 param.End = param.Start - vector.Up * 20;
721 param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
723 param.LayerMask = EPhysicsLayerPresets.Projectile;
724 float traceGroundDistance = world.TraceMove(param, FilterCallback);
725 m_PreviewEntity.GetTransform(m_vCurrentMat);
726 m_vCurrentMat[3] = param.Start + ((param.End - param.Start) * traceGroundDistance) + vector.Up * 0.01; // adding 1 cm to avoid collision with object under
727
728 if (traceGroundDistance < 1)
729 up = param.TraceNorm;
730
731 tracedEntity = param.TraceEnt;
732 }
733
734 SCR_EntityHelper.OrientUpToVector(up, m_vCurrentMat);
735 vector right = up * cameraMat[0];
736 vector forward = up * right;
737 right.Normalize();
738 forward.Normalize();
739 if (m_PlaceableItem.GetForwardAwayFromPlayer())
740 {
741 m_vCurrentMat[0] = -forward;
742 m_vCurrentMat[2] = -right;
743 }
744 else
745 {
746 m_vCurrentMat[0] = forward;
747 m_vCurrentMat[2] = right;
748 }
749
750#ifdef ENABLE_DIAG
751 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_ITEM_PLACEMENT_VISUALIZATION))
752 {
753 ShapeFlags shapeFlags = ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP | ShapeFlags.DOUBLESIDE | ShapeFlags.NOOUTLINE;
754 Shape.CreateArrow(m_vCurrentMat[3], m_vCurrentMat[3] + up * 0.5, 0.1, Color.BLUE, shapeFlags);
755 Shape.CreateArrow(m_vCurrentMat[3], m_vCurrentMat[3] + right * 0.5, 0.1, Color.ORANGE, shapeFlags);
756 Shape.CreateArrow(m_vCurrentMat[3], m_vCurrentMat[3] + forward * 0.5, 0.1, Color.GREEN, shapeFlags);
757 }
758#endif
759
760 vector matCopy[4] = m_vCurrentMat;
761 m_PlaceableItem.OverridePreviewTransform(this, matCopy);
762 m_PreviewEntity.SetTransform(matCopy);
763 m_PreviewEntity.Update();
764
765 // Reject based on distance from character
766 if (SCR_PlaceableItemComponent.GetDistanceFromCharacter(character, m_vCurrentMat[3], m_PlaceableItem.GetDistanceMeasurementMethod()) > maxPlacementDistance)
767 {
768 m_eCantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_DISTANCE;//this position is too far away
769 return;
770 }
771
772 m_iTargetEntityNodeID = param.NodeIndex;
773 m_aCamDeploymentPosition = cameraMat;
774 m_aCamDeploymentPosition[3] = character.EyePosition();
775 if (m_PlaceableItem.OverrideIsSurfaceValid(this, m_eCantPlaceReason, tracedEntity, m_vCurrentMat[3], param.TraceNorm, param.NodeIndex, param.ColliderIndex, param.SurfaceProps, param.TraceMaterial, param.ColliderName) && m_eCantPlaceReason != 0)
776 return;
777
778 ValidatePlacement(m_vCurrentMat[1], tracedEntity, world, character, m_eCantPlaceReason);
779 }
780
781 //------------------------------------------------------------------------------------------------
785 protected bool ValidateEntity(notnull IEntity entity)
786 {
787 Physics physics = entity.GetPhysics();
788 if (physics && physics.IsDynamic() && !m_PlaceableItem.CanAttachToDynamicObject())
789 return false;
790
791 // F. e. Slotted vehicle parts are physically static, but their main parent (vehicle) is not, we need to check that
792 IEntity mainEntity = entity.GetRootParent();
793 if (mainEntity && mainEntity != entity)
794 {
795 physics = mainEntity.GetPhysics();
796 if (physics && physics.IsDynamic() && !m_PlaceableItem.CanAttachToDynamicObject())
797 return false;
798 }
799
800 IEntity parent = entity;
801 array<typename> ignoredComponents = {};
802 m_PlaceableItem.GetIgnoredComponents(ignoredComponents);
803 while (parent)
804 {
805 physics = parent.GetPhysics();
806 if (physics && (physics.GetInteractionLayer() & m_PlaceableItem.GetIgnoredPhysicsLayers()))
807 return false;
808
809 if (ignoredComponents.IsEmpty())
810 {
811 parent = parent.GetParent();
812 continue;
813 }
814
815 foreach (typename comp : ignoredComponents)
816 {
817 if (parent.FindComponent(comp))
818 return false;
819 }
820 parent = parent.GetParent();
821 }
822
823 return true;
824 }
825
826 //------------------------------------------------------------------------------------------------
833 void ValidatePlacement(vector up, IEntity tracedEntity, BaseWorld world, IEntity character, out ENotification cantPlaceReason)
834 {
835 float maxAllowedTilt = m_PlaceableItem.GetMaxAllowedTilt();
836 if (maxAllowedTilt >= 0) // Early reject based on the angle of placement
837 {
838 float currentTilt = Math.Acos(vector.Dot(m_vCurrentMat[1], vector.Up)) * Math.RAD2DEG;
839 if (currentTilt > maxAllowedTilt)
840 {
842 cantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_TOO_STEEP;//angle too steep
843 return;
844 }
845 }
846
847 if (tracedEntity != m_TargetEntity)
848 {
850 m_TargetEntity = null;
851 m_TargetId = -1;
853
854 if (!ValidateEntity(tracedEntity)) // Reject on items with dynamic physics
855 {
856 cantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_GENERIC;//cant attach to this
857 return;
858 }
859
860 Physics entPhys = tracedEntity.GetPhysics();
861 if (m_PlaceableItem.GetAttachPlacedItemToTheSurfaceEntity() && entPhys && !(entPhys.GetInteractionLayer() & EPhysicsLayerDefs.Terrain))
863 }
864
865 array<IEntity> excludeArray = {};
866 excludeArray.Insert(m_PreviewEntity);
867 excludeArray.Insert(character);
868
869 // Reject based on bbox collision with surrounding objects - last check, as it's the most expensive one
870 // Check bbox
871 TraceOBB paramOBB = new TraceOBB();
872 if (m_PlaceableItem.OverrideSpaceValidation(this, m_vCurrentMat, cantPlaceReason))
873 {
874 if (cantPlaceReason != 0)
875 return;
876 }
877 else
878 {
879 Math3D.MatrixIdentity3(paramOBB.Mat);
880 paramOBB.Mat[0] = m_vCurrentMat[0];
881 paramOBB.Mat[1] = m_vCurrentMat[1];
882 paramOBB.Mat[2] = m_vCurrentMat[2];
883 paramOBB.Start = m_vCurrentMat[3] + 0.05 * paramOBB.Mat[1];
884 paramOBB.Flags = TraceFlags.ENTS;
885 paramOBB.ExcludeArray = excludeArray;
886 paramOBB.LayerMask = EPhysicsLayerPresets.Projectile;
887 m_PreviewEntity.GetBounds(paramOBB.Mins, paramOBB.Maxs);
888 world.TracePosition(paramOBB, TraceEntitiesCallback);
889 }
890
891#ifdef ENABLE_DIAG
892 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_ITEM_PLACEMENT_VISUALIZATION))
893 {
894 vector pos = m_vCurrentMat[3] + 0.05 * paramOBB.Mat[1];
895 ShapeFlags shapeFlags = ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP | ShapeFlags.DOUBLESIDE | ShapeFlags.NOOUTLINE;
896 Shape.CreateArrow(pos, pos + m_vCurrentMat[1] * 0.5, 0.1, Color.WHITE, shapeFlags);
897 Shape.CreateArrow(pos, pos + m_vCurrentMat[2] * 0.5, 0.1, Color.PINK, shapeFlags);
898 Shape.CreateArrow(pos, pos + m_vCurrentMat[0] * 0.5, 0.1, Color.YELLOW, shapeFlags);
899 }
900#endif
901
902 // collides with another entity
903 if (paramOBB.TraceEnt)
904 {
905 cantPlaceReason = ENotification.PLACEABLE_ITEM_CANT_PLACE_NOT_ENOUGH_SPACE;//not enough space
906 return;
907 }
908
909 if (tracedEntity && m_bIsBeingAttachedToEntity)
910 {
911 RplComponent rplComp = RplComponent.Cast(tracedEntity.FindComponent(RplComponent));
912 if (rplComp)
913 m_TargetId = rplComp.Id();
914 else
916 }
917 m_TargetEntity = tracedEntity;
918 }
919
920 //------------------------------------------------------------------------------------------------
924 bool TraceEntitiesCallback(notnull IEntity e, vector start = "0 0 0", vector dir = "0 0 0")
925 {
926 if (!e)
927 return false;
928
929 if (ChimeraCharacter.Cast(e.GetRootParent()))
930 return false;
931
932 return true;
933 }
934
935 //------------------------------------------------------------------------------------------------
936 protected void OnEditorOpened()
937 {
938 m_bInEditor = true;
940 }
941
942 //------------------------------------------------------------------------------------------------
943 protected void OnEditorClosed()
944 {
945 m_bInEditor = false;
947 }
948
949 //------------------------------------------------------------------------------------------------
951 {
952 manager.GetOnOpened().Insert(OnEditorOpened);
953 manager.GetOnClosed().Insert(OnEditorClosed);
954 }
955
956 //------------------------------------------------------------------------------------------------
957 protected override void OnPostInit(IEntity owner)
958 {
959 SetEventMask(owner, EntityEvent.INIT);
960 }
961
962 //------------------------------------------------------------------------------------------------
963 protected void InitEditorListeners()
964 {
966 if (!core)
967 return;
968
969 SCR_EditorManagerEntity editorManager = core.GetEditorManager();
970
971 if (!editorManager)
972 core.Event_OnEditorManagerInitOwner.Insert(RegisterToManagerInvokers);
973 else
974 RegisterToManagerInvokers(editorManager);
975 }
976
977 //------------------------------------------------------------------------------------------------
978 protected override void EOnInit(IEntity owner)
979 {
980 SCR_PlayerController playerController = SCR_PlayerController.Cast(GetOwner());
981 if (!playerController)
982 {
983 Print("SCR_ItemPlacementComponent is not attached to SCR_PlayerController!", LogLevel.WARNING);
984 return;
985 }
986
987 Math3D.MatrixIdentity4(m_vCurrentMat);
988
990
992 }
993
994 //------------------------------------------------------------------------------------------------
995 // constructor
1000 {
1001 m_iEquipComplete = GameAnimationUtils.RegisterAnimationEvent("EquipComplete");
1002#ifdef ENABLE_DIAG
1003 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_ITEM_PLACEMENT_VISUALIZATION, "", "Item placement debugs", "Character");
1004#endif
1005 }
1006}
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition DebugMenuID.c:4
ENotification
ArmaReforgerScripted GetGame()
Definition game.c:1398
SCR_CharacterControllerComponent GetCharacterController()
void EnablePreview(bool enabled, notnull SCR_ItemPlacementComponent placementComp)
void OnEditorClosed()
Method called when character has a shovel in hands and any editor mode is closed.
void OnEditorOpened()
Method called when character has a shovel in hands and any editor mode is opned.
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
vector direction
vector position
SCR_EPlacementType
void SCR_EditorManagerEntity(IEntitySource src, IEntity parent)
SCR_HelicopterControllerComponentClass gameplaySettings
void RPC_AskSetPlacementPosition(vector right, vector up, vector forward, vector position, RplId placeableId, RplId characterId)
int m_iTargetEntityNodeID
IEntity m_PreviewEntity
vector m_aCamDeploymentPosition[4]
void EnablePlacement(bool enabled)
bool m_bIsBeingAttachedToEntity
SCR_CompartmentAccessComponent m_CompartmnetAccessComponent
void OnPlacingEnded(IEntity item, bool successful, ItemUseParameters animParams)
void UseXYZPlacement(IEntity owner, float maxPlacementDistance, vector cameraMat[4])
vector m_vCurrentMat[4]
IEntity m_TargetEntity
void SetPlaceableItemComponent(SCR_PlaceableItemComponent placeableItemComp)
IEntity m_PlacedItem
void InitEditorListeners()
void SCR_ItemPlacementComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
ResourceName m_sCannotBuildMaterial
void RegisterEvents(IEntity to)
void DisablePreview()
void OnWeaponChanged(BaseWeaponComponent newWeaponSlot)
SCR_PlaceableItemComponent m_PlaceableItem
void GetOnCompartmentLeft()
bool ValidateEntity(notnull IEntity entity)
void AskPlaceItem(RplId placeableId, RplId targetId, int nodeId, bool isBeingAttachedToEntity)
void StartPlaceItem()
Callback method triggered by button press.
void OnComparmentEntered(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
SCR_PlaceableItemComponent GetPlaceableItemComponent()
void RegisterToManagerInvokers(SCR_EditorManagerEntity manager)
void ValidateTargetEntityExistance()
void UseXZFixedPlacement(IEntity owner, float maxPlacementDistance, vector cameraMat[4])
void SetPreviewEntity(IEntity preview, bool deleteOldPreview=true)
void RPC_AskPlaceItem(RplId placeableId)
void ValidatePlacement(vector up, IEntity tracedEntity, BaseWorld world, IEntity character, out ENotification cantPlaceReason)
ENotification m_eCantPlaceReason
void RPC_AskPlaceItemWithParentChange(RplId placeableId, RplId targetId, int nodeId)
void OnCharacterDeath(SCR_CharacterControllerComponent characterController, IEntity killerEntity, notnull Instigator killer)
void SetPlacedItem(IEntity item)
void TogglePreview(IEntity weapon)
bool FilterCallback(IEntity e)
bool TraceEntitiesCallback(notnull IEntity e, vector start="0 0 0", vector dir="0 0 0")
void OnWeaponChangeEnded(BaseWeaponComponent newWeaponSlot)
IEntity GetWeaponFromWeaponComponent(BaseWeaponComponent weaponComponent)
ResourceName m_sTransparentMaterial
void ForcePlaceItem()
Callback method triggered by button press.
Definition Color.c:13
Diagnostic and developer menu system.
Definition DiagMenu.c:18
proto external int ClearEventMask(notnull IEntity owner, int mask)
proto external int SetEventMask(notnull IEntity owner, int mask)
void Rpc(func method, void p0=NULL, void p1=NULL, void p2=NULL, void p3=NULL, void p4=NULL, void p5=NULL, void p6=NULL, void p7=NULL)
proto external Managed FindComponent(typename typeName)
proto external vector GetOrigin()
proto external Physics GetPhysics()
proto external BaseWorld GetWorld()
proto external IEntity GetParent()
proto external IEntity GetRootParent()
Definition Math.c:13
PointInfo - allows to define position.
Definition PointInfo.c:9
Main replication API.
Definition Replication.c:14
Replication item identifier.
Definition RplId.c:14
OnPlayerDeathWithParamInvoker GetOnPlayerDeathWithParam()
ScriptInvoker GetOnCompartmentEntered(bool createNew=true)
ScriptInvoker GetOnCompartmentLeft(bool createNew=true)
Core component to manage SCR_EditorManagerEntity.
SCR_EditorManagerEntity GetEditorManager()
static void SetMaterial(IEntity entity, ResourceName material, bool recursively=true)
Definition Functions.c:1793
void PlaceItemWithParentChange(RplId newParentRplId, int nodeId=-1)
Same as PlaceItem but with params that allow attaching the object to new parent entity.
void SetPlacementPosition(vector right, vector up, vector forward, vector position, RplId characterRplId)
Authority method used to change the position at which item will placed when removed from the inventor...
ref OnControlledEntityChangedPlayerControllerInvoker m_OnControlledEntityChanged
static IEntity GetLocalControlledEntity()
void EOnFrame(IEntity owner, float timeSlice)
proto external GenericEntity GetOwner()
Get owner entity.
void EOnInit(IEntity owner)
Instance of created debug visualizer.
Definition Shape.c:14
EPhysicsLayerPresets
Enum is filled by C++ by data in project config PhysicsSettings.LayerPresets.
Definition gameLib.c:19
SCR_EditableEntityComponent GetControlledEntity()
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
ShapeFlags
Definition ShapeFlags.c:13
SCR_FieldOfViewSettings Attribute
EntityEvent
Various entity events.
Definition EntityEvent.c:14
proto external PlayerController GetPlayerController()
EActionTrigger
void OnControlledEntityChanged(IEntity from, IEntity to)
Runs every time the controlled entity has been changed.
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
proto native vector Vector(float x, float y, float z)
TraceFlags
Definition TraceFlags.c:13