Architecture¶
🇬🇧 English | 🇺🇦 Українська
Modules¶
| Module | Type | Responsibility | Dependencies |
|---|---|---|---|
| InteractionSystem | Runtime | Target contracts, filtering rules, the ray source, network requests, the claim ledger, project settings, the Blueprint grab target, grip math | Core, CoreUObject, Engine, GameplayTags, DeveloperSettings |
| InteractionSystemWorld | Runtime | Manipulation and profiles, grip points, bow, docking support, strikes, destruction, physics actors, master item, spear | Core, CoreUObject, Engine, GameplayTags, InteractionSystem; privately NetCore, Niagara |
| InteractionSystemDemo | Runtime | InteractionLab, SpearRange, VR Lab, Quest 2/OpenXR pawn, HUD, doors and example items | Core, CoreUObject, Engine, InputCore, InteractionSystem, InteractionSystemWorld, HeadMountedDisplay, XRBase, EnhancedInput, UMG, Slate, SlateCore |
| InteractionSystemDebug | Runtime | Console commands, the log of server answers and the debug panel; registers nothing in Shipping | Core, CoreUObject, Engine, InteractionSystem; privately InteractionSystemWorld, InputCore, UMG, Slate, SlateCore |
| InteractionSystemTests | Editor | Behavior and PIE network tests through the public API | Core, CoreUObject, Engine, GameplayTags, InputCore, UMG, UnrealEd, InteractionSystem, InteractionSystemWorld |
InteractionSystem <- InteractionSystemWorld <- InteractionSystemDemo
^ ^ <- InteractionSystemDebug
+---- InteractionSystemTests (public API only; Demo and Debug by name, without a dependency)
The core does not import World, UI libraries or editor modules. Rendering and the physical implementations of targets are outside the contract. Demo and Debug are leaf modules: nothing depends on them, so they can be removed (06, 15); the tests reach them only by class names and skip their checks if the module is absent. The pure rules FInteractionFilter, FInteractionRules and FInteractionGripMath do not touch the world or RPCs; the UE scene/trace/network adapter is UInteractorComponent. The plugin enables the dependent plugins EnhancedInput and XRBase.
There is no separate use-case class for every call forward: protocol boundaries are placed where responsibility changes. Creating components in a pawn/Blueprint and configuring targets is the composition root of a specific game.
Class roles¶
| Role | Class | Module |
|---|---|---|
| Action source: focus, requests, poses of one hand or camera | UInteractorComponent |
Core |
| Contract for an ordinary action and local focus | IInteractableInterface |
Core |
| Grab target contract | UInteractionGrabTargetComponent; the Blueprint variant UInteractionBlueprintGrabTargetComponent |
Core |
| Project network limits | UInteractionSystemSettings |
Core |
| Server ledger of the right to a target | UInteractionClaimSubsystem |
Core |
| Rules and math without the world | FInteractionFilter, FInteractionRules, FInteractionGripMath |
Core |
| Motion executor and the item's replicated snapshot | UInteractionManipulationComponent, UInteractionManipulationProfile, UInteractionGripPointComponent |
World |
| Linked actions | UInteractionBowComponent, UInteractionDockComponent |
World |
| Gameplay events without a damage decision | UInteractionStrikeComponent |
World |
| Simple gameplay reactions | UInteractionDestructibleComponent, impact damage of AInteractionPhysicsActor |
World |
| Ready-made actors | AInteractionPhysicsActor, AInteractionMasterItem, AInteractionSpearActor |
World |
| Debugging | UInteractionCheatManagerExtension, UInteractionDebugLibrary, the answer log and the panel |
Debug |
Data flows¶
Focus (local only)¶
Tick interactor
-> UpdateViewpoint (desktop) or the pose of the parent motion controller (VR)
-> RefreshFocus at FocusUpdateHz
-> TraceTarget(Grab); if no target is found -> TraceTarget(Interact)
-> SetFocus: OnFocusEnd(old) -> OnFocusStart(new) -> OnFocusChanged
Focus is not replicated and is never proof of permission: the server repeats the checks itself.
An action¶
Input -> RequestGrab / RequestInteraction / RequestRelease
-> CapturePoses (the pose packet of all hands of the pawn)
-> Server RPC on the pawn's interactor
-> ExecuteAction: interval, AcceptPoses, repeated TraceTarget, CanBeginGrip, TryClaim
-> BeginGrip | Interaction | Use | EndGrip
-> HeldGrip (replication) + ClientActionResult -> OnActionResult
Poses and item motion¶
Client: the first active interactor -> ServerUpdatePoses (PoseReplicationHz), each hand has its own sample number
Server: AcceptPoses -> validation of each sample separately -> server copies of the hands
Server: manipulation Tick (after the hands) -> SolveDesired -> SetWorldTransform or PhysicsHandle
-> State (quantized pose, push model) -> replication
Clients: smooth approach to State; the owner solves the pose themself (Direct) or predicts it (Physics)
Rest: tick once per IdleUpdateInterval; motion or the body waking -> every frame again
Linked actions¶
The bow reserves the arrow through ReserveLinked, becomes its external driver (SetExternalDriver) and sets the pose every tick (SetExternalPose). An intentional release of the arrow computes the velocity on the server, turns on simulation and calls OnShot. The docking support attaches a free part through AttachToSurface; a repeated grab removes the attachment.
Invariants¶
- One ledger of rights. Only
UInteractionClaimSubsystemdecides who holds an item. World components do not start their own registries: manipulation, the bow and the support use one claim graph. External systems may read the claimant but must not change ownership bypassingTryClaim/ReleaseClaim. - One motion "writer". The pose, scale, attachment and simulation of an item are changed only by its manipulation. That is why it turns off the owner's
ReplicateMovement, requires a non-replicated root (orUInteractionMeshComponent), andAInteractionPhysicsActorignoresOnRep_ReplicatedMovementandOnRep_AttachmentReplication. - The server decides gameplay. The client shows focus, but the right to act, physics, damage and the shot are decided on the server.
- A throw is only intentional. Only the reason
Releasedpasses velocities. Loss of tracking, cancellation, recenter and an invalid target release the item without a throw; a bow does not shoot without an intentional release. - Request identity.
HeldGripstores the target together withRequestId, so late answers do not cancel new requests. - Weak references. The ledger and the local focus sets do not extend the lifetime of actors and components.
Extension points¶
| You need | How |
|---|---|
| A door, button, switch | IInteractableInterface in Blueprint or C++ (11, 12) |
| An item taken with hands | UInteractionManipulationComponent on any actor or a subclass of AInteractionPhysicsActor |
| Different holding behavior | A Blueprint subclass of UInteractionBlueprintGrabTargetComponent or a C++ subclass of UInteractionGrabTargetComponent |
| A message to the player about a rejection | OnActionResult with EInteractionRejectReason |
| A reaction to grab, use, release, handle travel | The manipulation events OnGripStarted, OnGripEnded, OnUsed, OnHandleChanged |
| An item moves together with another actor | SetExternalDriver + SetExternalPose |
| Custom indication | The interactor's OnFocusChanged or the target's OnFocusStart/OnFocusEnd; AInteractionMasterItem is an example |
| A custom reaction to a physics actor's impact | Override OnComponentHitInternal in C++ |
| An edge strike | UInteractionStrikeComponent::OnStrike |
Update order¶
Everything runs on the game thread, without asynchronous tasks.
| Who | When it ticks |
|---|---|
UInteractorComponent |
TG_PrePhysics, every frame while active |
UInteractionManipulationComponent |
TG_PrePhysics; every frame while there is work, otherwise once per IdleUpdateInterval (0.5 s); during a grip — after the hands that hold it |
UInteractionBowComponent |
TG_PrePhysics, after the bow's manipulation; the arrow search once per 0.05 s |
UInteractionStrikeComponent |
TG_PostPhysics, only on the server, while the item is held; frames without item motion are skipped |
UInteractionDockComponent |
Once per 0.1 s on the server |
AInteractionMasterItem |
Once per 0.1 s, not on a dedicated server |
AInteractionSpearActor |
Only in flight, on the server |
What is not part of the plugin¶
Locomotion and teleport, your game's input mappings (the demo has its own), inventory, hand animation or IK, UI widgets (except the demo), the damage and health model (except the simple World reactions), saving state. These parts are left to the game: the plugin provides the extension points above.