Concept: Requirements & Conditions

An option can carry requirements. They are objects, not code in the actor: UCrimsonInteractionCondition is an instanced, stateless predicate - read the context, answer, mutate nothing - authored inline on the option, on a container, or once in a UCrimsonInteractionConditionSet asset, and composed with And / Or / Not. The plugin decides what a failure means; a leaf only says whether the player qualifies and why not.

One evaluation path

  1. Gather. The target returns its options as before. Each option's Conditions and ConditionSets ride along.
  2. Evaluate all. UCrimsonInteractionCondition::EvaluateOption runs every condition in order and records each on the option's Requirements checklist (text + met). The FIRST unmet one decides the outcome: its FailureBehavior, failure title and reason.
  3. Apply. Hide drops the option before the ability filter. ShowInformational keeps it as a message: bInformational = true, the title replaces the text, the reason becomes SubText, and the option skips the ability filter entirely (a message needs no ability behind it).
  4. Present. The prompt shows the message without a key glyph and lists the checklist met / unmet; a press on an informational option fires nothing. The context menu's wrapper (UCrimsonContextAction_FromInteractionOption) applies the same result and lists it grayed with every unmet line as the reason.
  5. Re-check on the server. The client's option list is presentation. Before an interaction runs, CrimsonCore's handler and duration abilities re-gather the target's options on the server, keep those naming their own ability class, and refuse unless one of them passes. No option id travels: the ability class the wire already carries is the identity.

The result

FCrimsonInteractionConditionResultMeaning
bPassedEvery condition met.
FailureThe first unmet condition's behavior: ShowInformational or Hide.
Title / ReasonThe first unmet condition's failure title (empty keeps the option's text) and reason (becomes SubText).
RequirementsEvery condition, met or not, in order - the checklist. Each line's text comes from GetRequirementText(Context, bMet): the condition's RequirementText, else the leaf's own wording, else the reason while unmet and the class name while met.
A condition may only read what the instigator's client can see
The gather runs on the instigator's client for the prompt and on the server for the grant and the re-check, and both must agree. Replicated inventory, attributes, tags and replicated actor state are fine. A value that lives only on the server makes the prompt and the server disagree - the client shows Open and the server refuses. Mirror such state first.
Where leaves live
The base, the composites and the tag query ship in this plugin; a leaf that needs another system's knowledge lives in the code that joins the two (CrimsonCore ships an item check, an attribute compare and a team-attitude check), and CrimsonCore's owned stash turns its access policy into a condition so a refused player reads No Access (Owner: <Name>) instead of nothing.

See also

  • How-To: Gate an Interaction with Conditions
  • Concept: Scan, Gather, Filter, Broadcast
  • Concept: Multiplayer & Authority