Quickstart — Blueprint Usage
Create a named Stream once, keep using that Stream for the gameplay system that owns it, use Sequential calls for “next result” behavior or Keyed calls for stable semantic decisions, and centralize your game’s Stream IDs and Decision Keys in a small Blueprint Function Library.
This guide shows the simplest way to start using Probability Director in Blueprint and keep using it correctly as your game grows.
The main idea is:
Create a Stream once | vUse that Stream for gameplay decisions | vKeep using the same Stream while its owning GameInstance lives | vRemove it only when that Stream's lifecycle is actually finishedProbability Director has no hidden default Stream.
1. The Basic Blueprint Workflow
Section titled “1. The Basic Blueprint Workflow”For most Blueprint gameplay:
1. Create Stream2. Check that creation succeeded3. Use Sequential or Keyed operations4. Check each operation's Status/Result5. Keep using the same registered Stream6. Remove Stream only when you genuinely no longer need itYou normally do not need to manually get a Probability Director subsystem Target.
Probability Director’s normal Blueprint nodes use the current World Context automatically.
2. Where Should I Create Streams?
Section titled “2. Where Should I Create Streams?”Create long-lived gameplay Streams at a stable initialization point.
Good places include:
- Your GameInstance-derived Blueprint initialization.
- A persistent gameplay manager.
- An authoritative system that clearly owns that Stream.
Avoid creating a new Stream every time you need one random result.
Game starts | +--> Create Stream: Combat.Damage +--> Create Stream: Loot.DropTable +--> Create Stream: World.EncountersThen later:
Attack -> use Combat.Damage
Open Chest -> use Loot.DropTable
Encounter Check -> use World.EncountersAttack -> Create Combat.Damage -> Roll -> Remove Combat.Damage
Attack -> Create Combat.Damage -> Roll -> Remove Combat.DamageA Stream is intended to have a meaningful gameplay lifetime.
3. Streams Survive Map Changes with the GameInstance
Section titled “3. Streams Survive Map Changes with the GameInstance”Probability Director is GameInstance-scoped.
That means a registered Stream belongs to the current GameInstance rather than one individual map.
For a normal playthrough:
GameInstance | +--> Combat.Damage +--> Loot.DropTable +--> World.Encounters
Map A -> uses those Streams
Map B -> uses the same StreamsDo not recreate long-lived Streams simply because the player changed maps.
4. Create Your First Stream
Section titled “4. Create Your First Stream”Use:
Create Stream
Example:
Create Stream
Stream ID:Combat.Damage
Seed Source:Secure
Decision Mode:Sequential
Persistence Policy:EphemeralCreation registers the Stream.
It does not roll or consume random output.
5. Choose the Stream Settings
Section titled “5. Choose the Stream Settings”| Setting | Simple meaning |
|---|---|
| Stream ID | What gameplay system owns this random source |
| Seed Source | How the Stream begins |
| Decision Mode | How random decisions are addressed |
| Persistence Policy | What happens across save/load |
6. Choosing a Seed Source
Section titled “6. Choosing a Seed Source”| Need | Use |
|---|---|
| Normal fresh gameplay randomness | Secure |
| Reproducible testing/debugging | Fixed |
| Approved imported-state workflow | Imported |
Secure example
Section titled “Secure example”Loot.DropTableSeed Source: SecureUse this for normal gameplay when you do not need a visible reproducible seed.
Fixed example
Section titled “Fixed example”Test.CombatSeed Source: FixedFixed Seed: 12345Use this when you want to reproduce the same compatible sequence.
7. Choosing Sequential or Keyed
Section titled “7. Choosing Sequential or Keyed”The simplest rule is:
| Your question | Use |
|---|---|
| “Give me the next random result.” | Sequential |
| “Give me the result for this exact gameplay decision.” | Keyed |
8. Sequential Example
Section titled “8. Sequential Example”Create:
Stream:Combat.Damage
Decision Mode:SequentialThen every damage roll uses that same Stream:
Attack 1 -> Resolve Sequential Numeric Dice Total
Attack 2 -> Resolve Sequential Numeric Dice Total
Attack 3 -> Resolve Sequential Numeric Dice TotalSequential mode is sensitive to call order.
Adding another advancing random call can change later results.
9. Keyed Example
Section titled “9. Keyed Example”Create:
Stream:Loot.World
Decision Mode:KeyedFor one chest:
Namespace:Loot
Stable Subject ID:Chest.Forest.0042
Decision:Rarity
Occurrence:0Use that Decision Key with the Keyed operation.
The same compatible key intentionally gives the same deterministic result.
10. When to Change Occurrence
Section titled “10. When to Change Occurrence”If one semantic subject needs several distinct deterministic results, change Occurrence.
Example:
| Item pick | Occurrence |
|---|---|
| First item | 0 |
| Second item | 1 |
| Third item | 2 |
Do not expect Probability Director to increment a hidden Keyed counter for you.
There is no hidden Keyed occurrence cursor.
11. Use Stable Decision Key Values
Section titled “11. Use Stable Decision Key Values”Good:
Namespace: LootStable Subject ID: Chest.World01.Room12.Chest04Decision: RarityOccurrence: 0Avoid:
Stable Subject ID: BP_Chest_C_2147481250or anything based on:
- Pointer values.
- Memory addresses.
- Temporary Actor numbering.
- Array positions that can change.
Use gameplay meaning, not process identity.
12. First Sequential Dice Example
Section titled “12. First Sequential Dice Example”A simple Blueprint flow:
Create Stream Stream ID: Combat.Damage Seed Source: Secure Decision Mode: Sequential | vMake Standard Numeric Dice Pipeline Standard Die: D20 Quantity: 1 | vResolve Sequential Numeric Dice Total Stream ID: Combat.Damage Flat Modifier: +5 | vCheck Status | +--> Success | +--> use final resultDo not use the output as if the operation succeeded until you check the returned status/result.
13. First Keyed Example
Section titled “13. First Keyed Example”A typical Keyed flow:
Create Stream Stream ID: Loot.World Decision Mode: Keyed | vBuild Decision Key Namespace: Loot Stable Subject ID: Chest.Forest.0042 Decision: Rarity Occurrence: 0 | vCall the Keyed operation Stream ID: Loot.World Decision Key: above | vCheck Status | +--> Success | +--> use result14. Reuse the Same Stream
Section titled “14. Reuse the Same Stream”Once:
Combat.Damageis registered, keep using it.
You do not need to call Create Stream before every Roll.
A good ownership pattern is:
Initialization -> Create Combat.Damage
Gameplay -> use Combat.Damage hundreds/thousands of times
Shutdown / true lifecycle end -> Remove Combat.Damage if needed15. Verify a Stream Exists
Section titled “15. Verify a Stream Exists”Use:
Has Stream
Example:
Has Stream Stream ID: Combat.Damage | +--> True | -> continue | +--> False -> handle setup problemHas Stream is useful for checking lifecycle problems.
Do not use it as a reason to silently create Streams everywhere in the project.
Prefer one clear owner.
16. Inspect the Registered Configuration
Section titled “16. Inspect the Registered Configuration”Use:
Get Stream Configuration
This is useful when something behaves differently than expected.
For example:
I thought
Loot.Worldwas Keyed, but my Keyed calls are failing.
Check the actual registered configuration.
Look for:
- Seed Source.
- Decision Mode.
- Persistence Policy.
Treat the registered configuration as authoritative.
17. List Registered Streams
Section titled “17. List Registered Streams”Use:
Get Stream IDs
This is mainly useful for:
- Debug tools.
- Developer menus.
- Verifying initialization.
- Finding what exists in the current GameInstance.
Normal gameplay should usually already know which Stream IDs it owns.
18. Remove a Stream
Section titled “18. Remove a Stream”Use:
Remove Stream
only when the Stream’s real gameplay lifecycle ends.
Example:
Temporary game mode begins -> Create GameMode.SpecialEvent
Temporary game mode ends -> Remove GameMode.SpecialEventDo not remove a long-lived Stream just because:
- A level changed.
- One Actor was destroyed.
- One roll finished.
- A UI closed.
19. Recommended Stream Organization
Section titled “19. Recommended Stream Organization”Use semantic Stream IDs.
| System | Suggested Stream |
|---|---|
| Damage | Combat.Damage |
| Criticals | Combat.Critical |
| Loot | Loot.DropTable |
| Encounters | World.Encounters |
| NPC names | NPC.Names |
| AI decisions | AI.Decisions |
Avoid one giant:
Game.Randomfor everything unless shared call-order coupling is actually what you want.
20. Why Separate Streams?
Section titled “20. Why Separate Streams?”Suppose Combat and Loot share one Sequential Stream:
Combat RollLoot RollCombat RollAdding another Loot call can change later Combat results.
Separate Streams:
Combat.DamageLoot.DropTablekeep those systems independent.
21. Blueprint Function Libraries for Your Game
Section titled “21. Blueprint Function Libraries for Your Game”As your game grows, do not scatter raw Stream IDs and Decision Key conventions through hundreds of Blueprints.
Create your own project Blueprint Function Library.
Example name:
BFL_GameProbabilityUse it to centralize:
- Stream IDs.
- Stream initialization.
- Common Decision Keys.
- Common Dice configurations.
- Common Probability Director operations.
- Project-specific error handling.
22. Creating a Blueprint Function Library
Section titled “22. Creating a Blueprint Function Library”In the Content Browser:
Add -> Blueprint Class -> All Classes -> Blueprint Function LibraryName it:
BFL_GameProbabilityNow add reusable functions.
23. BFL Example — Stream ID Helpers
Section titled “23. BFL Example — Stream ID Helpers”Instead of typing:
Combat.Damagein many Blueprints, create:
Get Combat Damage Stream IDwhich always returns:
Combat.DamageDo the same for:
Get Loot Stream IDGet Encounter Stream IDGet NPC Name Stream IDThis reduces spelling mistakes and makes renaming easier.
24. BFL Example — Initialize Game Streams
Section titled “24. BFL Example — Initialize Game Streams”Create a function:
Initialize Probability StreamsInside:
Has Stream: Combat.Damage | +--> False -> Create Stream Combat.Damage Secure Sequential <chosen persistence>Repeat for the Streams your game owns.
Then your startup logic can simply call:
Initialize Probability Streamsonce.
25. Why Use Has Stream Inside Initialization?
Section titled “25. Why Use Has Stream Inside Initialization?”Initialization code is sometimes called more than once during development.
Using:
Has Streaminside one centralized initializer lets you avoid accidental duplicate registration attempts.
This is different from hiding Stream creation all over gameplay.
Good:
One BFL initialization function -> checks -> creates expected StreamsAvoid:
Every random gameplay function -> Has Stream -> Create if missing -> RollThe second pattern hides lifecycle bugs.
26. BFL Example — Combat Roll Wrapper
Section titled “26. BFL Example — Combat Roll Wrapper”Instead of wiring a full Dice pipeline in every weapon Blueprint, create:
Roll Standard Weapon DamageInputs might be:
Number of DiceDie TypeFlat ModifierInside your BFL:
Get Combat Damage Stream ID | vMake Standard Numeric Dice Pipeline | vResolve Sequential Numeric Dice Total | vCheck result | vReturn project-friendly resultNow weapon Blueprints call one project-specific function.
27. Why Wrap Probability Director in Your Own BFL?
Section titled “27. Why Wrap Probability Director in Your Own BFL?”Probability Director is generic, your game is not.
A project BFL can turn:
Resolve Sequential Numeric Dice Totalinto:
Roll Weapon Damageor turn:
Keyed Distribution Sampleinto:
Choose Chest RarityThis makes gameplay graphs easier to understand.
28. Keep the BFL Thin
Section titled “28. Keep the BFL Thin”Your BFL should organize your game’s usage.
It should not recreate Probability Director.
Good BFL responsibilities:
- Store common IDs.
- Build common configs.
- Build Decision Keys.
- Call Probability Director nodes.
- Translate results into game-specific outputs.
- Log/handle expected project failures.
Avoid:
- Implementing your own PRNG.
- Reimplementing Dice math.
- Hiding every error.
- Creating a new Stream on every call.
29. BFL Example — Chest Decision Key
Section titled “29. BFL Example — Chest Decision Key”Create:
Make Chest Loot Decision KeyInputs:
Chest Stable IDDecisionOccurrenceInternally:
Namespace = LootStable Subject ID = Chest Stable IDDecision = requested decisionOccurrence = requested occurrenceThen all chest Blueprints use the same Key convention.
30. BFL Example — Stable Chest Loot
Section titled “30. BFL Example — Stable Chest Loot”Your chest Blueprint can become:
Event Generate Loot | +--> Make Chest Loot Decision Key | Stable ID: Chest.Forest.0042 | Decision: Rarity | Occurrence: 0 | +--> Sample Keyed Loot operation Stream: Loot.WorldThe chest does not need to know how every key field is standardized.
31. Do Not Cache a Global Subsystem in Blueprint
Section titled “31. Do Not Cache a Global Subsystem in Blueprint”Normal Probability Director Blueprint nodes are target-free.
Their hidden World Context resolves the correct GameInstance-scoped subsystem.
Avoid creating:
GlobalProbabilityDirectorSubsystemand assuming it is valid forever.
This matters especially in PIE and multi-PIE.
32. Older Target-Based Nodes
Section titled “32. Older Target-Based Nodes”Older direct Target-based Probability Director nodes may still load for compatibility with existing serialized assets.
For new Blueprint work, prefer the target-free World Context nodes.
This keeps the correct GameInstance resolution automatic.
33. Persistence Policy
Section titled “33. Persistence Policy”Choose persistence intentionally.
| Policy | Simple meaning |
|---|---|
| Ephemeral | Do not restore this Stream |
| PersistState | Continue approved state across save/load |
| RotateOnSave | Rotate/commit state only after successful save |
Do not choose persistence based only on Seed Source.
For example:
Fixeddoes not automatically mean:
PersistStateSee Persistence and Save Game Integration before choosing production save behavior.
34. Testing with Fixed Streams
Section titled “34. Testing with Fixed Streams”Fixed Streams are excellent for debugging.
Example:
Stream: Test.DamageFixed Seed: 12345SequentialRun:
RollRollRollRecord the results.
Restart from the same clean setup and repeat the exact call order.
You should get the same compatible deterministic sequence.
35. Testing with Secure Streams
Section titled “35. Testing with Secure Streams”After deterministic testing, use Secure for the normal gameplay path when that is your intended design.
Remember:
- Secure internal state is private.
- Inspector exports do not make the Stream reproducible.
- Secure RNG does not encrypt save files.
36. Runtime Inspector
Section titled “36. Runtime Inspector”During PIE:
Tools -> Probability Director Runtime InspectorUse it to check:
- Does the Stream exist?
- Is it Secure or Fixed?
- Is it Sequential or Keyed?
- What Persistence Policy is active?
- Did a retained Sequential operation advance?
- Which sanitized Decision Key was used?
The Inspector is read-only.
37. Common Problem — “Stream Not Found”
Section titled “37. Common Problem — “Stream Not Found””Symptoms
Section titled “Symptoms”A Probability Director operation fails because the Stream does not exist.
| Check | Why |
|---|---|
| Did Create Stream run? | Stream may never have been registered |
| Exact Stream ID spelling? | IDs must match |
| Correct GameInstance? | Streams are GameInstance-scoped |
| Was it removed? | Remove Stream is explicit |
| Did gameplay call too early? | Use stable initialization |
Typical bad order:
Roll -> Create StreamCorrect order:
Create Stream -> later Roll38. Common Problem — Duplicate Stream Creation
Section titled “38. Common Problem — Duplicate Stream Creation”Initialization is being run repeatedly.
Better solution
Section titled “Better solution”Centralize creation:
Initialize Probability Streamsand optionally use:
Has Streaminside that one initialization path.
Do not scatter “create if missing” logic throughout gameplay.
39. Common Problem — Keyed Result Keeps Repeating
Section titled “39. Common Problem — Keyed Result Keeps Repeating”This may be correct.
Check:
NamespaceStable Subject IDDecisionOccurrenceIf all are the same, the deterministic result is expected to repeat.
If you wanted the next separate occurrence, change:
Occurrenceexplicitly.
40. Common Problem — Keyed Result Changes Unexpectedly
Section titled “40. Common Problem — Keyed Result Changes Unexpectedly”Compare the keys.
Did any of these change?
- Namespace.
- Stable Subject ID.
- Decision.
- Occurrence.
Also confirm you are using the same registered Stream and compatible deterministic contract.
41. Common Problem — Sequential Results Changed After Adding Code
Section titled “41. Common Problem — Sequential Results Changed After Adding Code”If you added another advancing random call earlier in the same Stream, later Sequential results can shift.
Example:
Old:A -> B -> C
New:A -> X -> B -> CIf X advances the Stream, B and C can change.
Possible solutions:
- Accept the new sequence.
- Put unrelated systems on separate Streams.
- Use Keyed mode for decisions that should not depend on unrelated call order.
42. Common Problem — Stream Recreated on Every Map
Section titled “42. Common Problem — Stream Recreated on Every Map”Probability Director is GameInstance-scoped.
If the GameInstance is still the same, long-lived Streams can continue across map travel.
Move creation to a more persistent owner instead of each Level Blueprint.
43. Common Problem — Using Output Without Checking Status
Section titled “43. Common Problem — Using Output Without Checking Status”Do not assume the output value means success.
A zero, false, or default value may be a valid output.
Always use the operation’s returned Status/Result contract.
Pattern:
Call operation | +--> Success | -> use output | +--> Failure -> handle/report problem44. Common Problem — One Stream for Everything
Section titled “44. Common Problem — One Stream for Everything”If unrelated systems share one Sequential Stream, their call order affects each other.
Split them by responsibility.
Instead of:
Game.Randomprefer:
Combat.DamageLoot.DropTableWorld.Encounters45. Common Problem — BFL Silently Creates Missing Streams
Section titled “45. Common Problem — BFL Silently Creates Missing Streams”Avoid a helper like:
Roll Damage -> if Combat.Damage missing automatically create itThis can hide initialization bugs.
Better:
Initialize Probability Streamsowns creation.
Then:
Roll Damageexpects Combat.Damage to exist and reports failure if it does not.
46. Recommended Blueprint Project Layout
Section titled “46. Recommended Blueprint Project Layout”A simple organization:
Blueprints/ Game/ BP_MyGameInstance
Probability/ BFL_GameProbability BFL_GameDecisionKeys
Combat/ ...
Loot/ ...BP_MyGameInstance or another persistent owner initializes Streams.
BFL_GameProbability provides game-specific wrappers.
BFL_GameDecisionKeys centralizes semantic Key conventions if the project has many Keyed systems.
47. Recommended First Setup
Section titled “47. Recommended First Setup”Step 1
Section titled “Step 1”Create:
BFL_GameProbabilityStep 2
Section titled “Step 2”Add helpers for:
Combat.DamageLoot.DropTableStep 3
Section titled “Step 3”Add:
Initialize Probability StreamsStep 4
Section titled “Step 4”Call that initialization from a stable GameInstance/persistent manager path.
Step 5
Section titled “Step 5”Build one simple wrapper:
Roll Combat DamageStep 6
Section titled “Step 6”Start PIE and open:
Tools → Director Suite → Runtime Inspectors → Probability Director Runtime InspectorStep 7
Section titled “Step 7”Confirm your Streams exist.
48. Quick Blueprint Reference
Section titled “48. Quick Blueprint Reference”| Need | Use |
|---|---|
| Register a Stream | Create Stream |
| Verify it exists | Has Stream |
| Read its config | Get Stream Configuration |
| List current Streams | Get Stream IDs |
| End its lifecycle | Remove Stream |
| Next random result | Sequential operation |
| Stable semantic result | Keyed operation |
| Multiple Keyed decisions with same identity | Explicit Occurrence |
| Normal fresh RNG | Secure |
| Reproducible test | Fixed |
| Inspect live Streams | Probability Director Runtime Inspector |
49. Recommended Rules
Section titled “49. Recommended Rules”- Create Streams intentionally.
- Create long-lived Streams once.
- Give every Stream one clear gameplay owner.
- Use separate Streams for unrelated Sequential systems.
- Use Sequential when call order matters.
- Use Keyed when semantic identity matters.
- Use explicit Occurrence for repeated Keyed decisions.
- Use your own BFL to centralize game conventions.
- Check operation status before using outputs.
- Use the Inspector to diagnose Runtime configuration—not to control gameplay.
50. Resolution Rules Data Assets
Section titled “50. Resolution Rules Data Assets”Create the asset through the normal workflow:
Create Data Asset -> Numeric Dice Resolution RulesFor example, configure Quantity = 2, DiePreset = D20, enable selection, and choose Keep Highest with count 1. Then use Resolve Sequential Numeric Rules Total with the already registered Stream ID.
The four V1.11 WorldContext nodes are:
- Resolve Sequential Numeric Rules Total
- Resolve Persistent Keyed Numeric Rules Total
- Resolve Sequential Numeric Rules Success Count
- Resolve Persistent Keyed Numeric Rules Success Count
Each node accepts the Rules Asset, Stream ID, FProbabilityNumericResolutionOverrides, and optional source-policy override (InheritConfiguredStream, RequireFixed, or RequireSecure). Persistent Keyed nodes additionally accept a valid FProbabilityDecisionKey; Sequential nodes do not expose that pin. The nodes return a rules error, existing runtime dice status, and the appropriate numeric result projection.
For a runtime modifier, set AdditionalFlatModifier. To contribute bias, set bHasAdditionalDiceBias and provide AdditionalDiceBiasPercent from -99 to +99. These values are applied per call and never mutate the shared asset. A source policy constrains the registered Stream; it does not create one.
See DataAssets.md and StreamsAndDecisionKeys.md.