Skip to content

Bugfixes and refactor for LogWarning/Error/Note#359

Open
LindyHopperGT wants to merge 5 commits intoMothCocoon:5.xfrom
LindyHopperGT:FlowRefactorsAndBugfixes
Open

Bugfixes and refactor for LogWarning/Error/Note#359
LindyHopperGT wants to merge 5 commits intoMothCocoon:5.xfrom
LindyHopperGT:FlowRefactorsAndBugfixes

Conversation

@LindyHopperGT
Copy link
Contributor

Bug Fix - CancelAndWarnForUnflushedDeferredTriggers()

  • Null-guard ToNode and FromNode before dereferencing in UE_LOG. Prevents crash during abnormal termination when nodes are already destroyed.

Bug Fix - TryFindActorOwner()

  • Now correctly returns the Owner when it IS already an AActor, not just when it's a component. Fulfills the documented contract.

Refactor - LogError/LogWarning/LogNote

  • Extracted shared LogRuntimeMessage() helper. Three identical copy-pasted functions → one implementation with severity parameter.

## Core Type System
- FFlowPinConnectionPolicy: Flexible pin connectivity policy framework
- FFlowPinTypeMatchPolicy: Per-type matching rules with EFlowPinTypeMatchRules flags
- Standard policy presets: VeryRelaxed, Relaxed, Strict, VeryStrict

### Graph Schema & Pin Connectivity
- UFlowGraphSchema::ArePinTypesCompatible(): Policy-driven compatibility checking

### Flow Asset & Runtime
- FFlowPinConnectionPolicy integration in UFlowAsset (was in UFlowGraphSchema, editor only, and not easily configurable for projects)
- UFlowAsset::GetFlowPinConnectionPolicy(): Runtime policy access for instances

### Predicates & Data Validation
- Now supports all FFlowDataPinValue types
- Generic equality template: TryCheckResolvedValuesEqual<TFlowPinType>()
- Validation with operator/type compatibility checks

### Settings & Configuration
- FInstancedStruct-based policy selection in UFlowSettings
- Per-asset-subclass policy override capability
[Flow] Replaced the stubbed, nonfunctional preload mechanism in FlowGraph with a policy-driven, async-safe & per-project extendable system.

Core Interface (IFlowPreloadableInterface)

- Replaced ad-hoc PreloadContentAsync (TFunction callback) with PreloadContent() → EFlowPreloadResult (Completed / PreloadInProgress) and FlushContent().
- Async C++ nodes return PreloadInProgress and call NotifyPreloadComplete() from their completion delegate.
- Async Blueprint nodes override K2_PreloadContent and call NotifyPreloadComplete() on self.
- Sync nodes return Completed unchanged.

Policy System (FFlowPreloadPolicy, FFlowPinConnectionPolicy)

- Introduced FFlowPreloadPolicy instanced-struct policy controlling per-node preload timing (OnGraphInitialize, OnActivate, ManualOnly, Never) and flush timing (OnGraphDeinitialize, OnNodeFinish, ManualOnly, Never).
- UFlowSettings exposes default policies as nullable const T* accessors. UFlowAsset holds a resolved policy instance with check() validation.

Preload Helper (FFlowPreloadHelper / FFlowPreloadHelper_Standard)

- New instanced-struct helper allocated per-node at InitializeInstance for any node (or addon) implementing IFlowPreloadableInterface.
- Tracks PendingPreloadCount (not a simple bool) so node + multiple addon participants are counted atomically before any PreloadContent call fires — prevents premature AllPreloadsComplete.
- Lifecycle hooks: OnNodeInitializeInstance, OnNodeActivate, OnNodeCleanup, OnNodeDeinitializeInstance, OnNodeExecuteInput.
- Safety flush on DeinitializeInstance regardless of flush timing policy.

Context Pins

- Preloadable nodes gain Preload Content and Flush Content exec input pins and All Preloads Complete exec output pin automatically via GetContextInputs/GetContextOutputs.
- AllPreloadsComplete fires only when all participants (node + all preloadable addons) have reported completion.

AddOn Participation

- TryInitializePreloadHelper allocates a helper when any addon implements IFlowPreloadableInterface, even if the node itself does not.
- TriggerPreload / TriggerFlush iterate preloadable addons alongside the node.
- Added UFlowNodeAddOn::NotifyPreloadComplete() (BlueprintCallable) — delegates to owning node, mirroring the Finish/TriggerOutput pattern.

Implementing Nodes

UFlowNode_PlayLevelSequence
— stores FStreamableHandle, binds CreateWeakLambda → NotifyPreloadComplete(), returns PreloadInProgress;
FlushContent cancels the handle.
UFlowNode_ExecuteComponent
— delegates to component; PreloadInProgress from a component is guarded with ensureAlwaysMsgf (no callback path exists) and treated as Completed.
UFlowNode_SubGraph
— synchronous CreateSubFlow, returns Completed.

CR - ECalder, BJarvinen
// Often ExecuteInput is replaced rather than extended in subclasses.
// So any subclasses that implement the preload interface will want to call this function
// in their ExecuteInput() override.
if (DispatchExecuteInputToPreloadHelper(PinName))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a small suggestion.

  1. Declare DispatchExecuteInputToPreloadHelper as a FlowNodeBase virtual method
  2. Make it return false in the default implementation
  3. Keep the same implementation for FlowNode, like the one you have here
  4. Remove the DispatchExecuteInputToPreloadHelper call from the UFlowNode::ExecuteInput
  5. Place it under the UFlowNodeBase::ExecuteInputForSelfAndAddOns instead, so we may get something like this
void UFlowNodeBase::ExecuteInputForSelfAndAddOns(const FName& PinName)
{
	// AddOns can introduce input pins to Nodes without the Node being aware of the addition.
	// To ensure that Nodes and AddOns only get the input pins signaled that they expect,
	// we are filtering the PinName vs. the expected InputPins before carrying on with the ExecuteInput

	if (IsSupportedInputPinName(PinName) && !DispatchExecuteInputToPreloadHelper(PinName))
	{
		ExecuteInput(PinName);
	}

	for (UFlowNodeAddOn* AddOn : AddOns)
	{
		AddOn->ExecuteInputForSelfAndAddOns(PinName);
	}
}

There are two main reasons why I think it may work better:

  1. Preload/Flush are not just regular execution pins. We do not expect them to perform any additional logic except for managing the resources. In such a way, it will be easier to prevent human mistakes when we forget to protect the main execution block from being called by Preload/Flush pins
  2. As you mentioned here, sometimes ExecuteInput is replaced rather than extended in subclasses. And with this new approach, we don't need to duplicate the DispatchExecuteInputToPreloadHelper for such nodes

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants