← lab3.studioAn Unreal Engine plugin by Lab³ Studio
Smart Object
Claims
A reservation, negotiation, and interruption layer for Unreal Engine's SmartObjects system.
Smart Object Claims adds the layer the engine leaves out: a registry of who holds what and why, ownership you can actually verify, and a way for two agents to agree on an interaction before either commits to it. All of it usable from Blueprint and C++.
Why use it
The engine's Smart Object subsystem owns slot state, and it does that job well. What it doesn't tell you is who holds what, why, or whether your handle is still yours. This plugin adds exactly that layer and never duplicates the one below. Here's how the two compare:
Features
Note
A slot in the Claimed state is not necessarily claimed by you.
Check ownership with IsClaimCurrent, and bind OnClaimInvalidated to be notified when a claim is taken from its holder.
Getting Started
- Copy the SmartObjectClaims folder into your project's Plugins folder.
- In the Unreal Editor, go to Edit > Plugins and enable Smart Object Claims. The engine's SmartObjects plugin is the only requirement.
- Restart the editor. For C++ projects, regenerate project files and rebuild.
Blueprint
Use the Get Smart Claim Subsystem node from any world context, then call the following functions:
To receive events for a single Actor's Smart Objects, add a Smart Claim Listener component to that Actor.
C++
USmartClaimSubsystem* Claims = GetWorld()->GetSubsystem<USmartClaimSubsystem>();
FSmartClaimRequest Request;
Request.Claimant = MyPawn;
Request.ReasonTag = MyReasonTag;
Request.Priority = ESmartObjectClaimPriority::Normal;
// Optional: Request.Filter carries user tags, activity requirements, behavior classes.
// Optional: Request.UserData carries your user-data struct for selection conditions.
FSmartObjectClaimHandle Handle;
if (Claims->TryClaim(SmartObjectActor, Request, Handle) == ESmartClaimResult::Claimed)
{
// Optional: the token releases the claim automatically if MyPawn
// ends play or is destroyed.
USmartClaimToken* Token = Claims->CreateClaimToken(MyPawn, Handle);
}API Reference
The complete public surface. Every Blueprint function is a native UFUNCTION with the same name, so the Blueprint reference doubles as the C++ function list; the C++ reference covers what Blueprint cannot reach – the host integration seams, module setup, and the type vocabulary. Expand a class to see its functions.
Blueprint Reference
Claims
Registry queries
Watches and events
Offers
Interruption, authority, and diagnostics
Events
Functions and events
Functions
Functions
Functions and events
C++ Reference
Networking
Mutating claims is the server's job; reading them stays open to clients. When a client needs to claim something, add a SmartClaimNetGatewayComponent (from the optional SmartObjectClaimsNet module) to your PlayerController and call its request functions. Every request hands back a correlation ID, and the answer arrives on the matching delegate.
Actor references inside a request must be replicated Actors to resolve on the server, and a custom UserData struct travels only if it supports network serialization.
Configuration
You can configure the plugin in Project Settings > Plugins > Smart Object Claims. Each setting has a tested runtime effect and can be overridden per world on the subsystem.
Verification
This table is what the release gates actually verify - the right column is unverified, which is not the same as broken. You don't have to take our word for any of it: the 68-test automation suite ships inside the plugin and runs on your machine. Open Window > Test Automation, filter for SmartObjectClaims, and run - all 68 must pass. Or headless:
UnrealEditor-Cmd.exe YourProject.uproject -ExecCmds="Automation RunTests SmartObjectClaims" -TestExit="Automation Test Queue Empty" -unattended -NullRHI -logRegistry cost at 10,000 live claims
Measured on Win64 Development. The performance test logs the same numbers on whatever machine it runs on, so measure on your own hardware before you budget against these.
Design
Eleven decisions shape the plugin, and each one forbids something specific. Summaries below; the full record, prohibitions included, ships with the plugin as DESIGN.md.
USmartObjectSubsystem owns slot state. The plugin maintains a mirror of claims made through its own API, kept in sync by the engine's event delegates. When the mirror and the engine disagree, the engine is authoritative and the mirror re-synchronizes. No question about slot state is answered from the mirror alone.
Claiming a slot reserves it. A claim does not start a behavior, and claiming a slot on another agent's behalf does not commit that agent to anything. Two claimed slots do not mean an interaction has begun.
The invitee accepts, declines, or lets the offer time out. Every reservation is revalidated when the offer is accepted; if any reservation has been lost, the remainder is rolled back and the result is ReservationLost. Offers carry the same request contract as direct claims, including filters, priority, and custom user data.
InterruptSmartObjectUser asks the system running the interaction to stop at its own safe point. The core module does not depend on GameplayInteractions, GameplayTasks, or AIModule; an optional adapter module installs the interruption provider. With no provider installed, the call returns Unsupported.
A claim that is held but never becomes occupied is logged and broadcast after StaleClaimSeconds. Releasing it automatically would hide the leak that caused it and could race a holder that is legitimately slow to start.
There is no polling and no world scan. A claim watches its own object automatically; any other object is watched through an explicit lease. A lease can only be released by the caller that acquired it.
Release, ownership checks, token binding, and event matching all compare the full claim handle. No code path that decides ownership performs a lookup by slot alone.
The engine's native callback is a capture boundary. Events are applied and broadcast on the game thread, and the subject of each event is decided by its kind rather than by whichever claim holds the slot at delivery time. An event never combines fields from two claims.
A client that calls the subsystem directly is refused and the refusal is logged once per world. Client-initiated claims go through the optional SmartObjectClaimsNet gateway module, which validates that the requesting connection owns the agent it acts for. A request for another connection's agent returns NotOwnedByRequester.
Every setting configures a mechanism, and every setting has a tested runtime effect. Gameplay policy, such as when an agent should claim or interrupt, belongs to the host project.
A request carrying a schema version outside the supported range is refused with UnsupportedVersion. Additive API changes can land in 1.x releases; changes that rename, remove, or reshape the API wait for 2.0.
Support
The README, CHANGELOG, and design record ship inside the plugin package. For everything else, use the channels below.