Skip to content

Commit 34fabfc

Browse files
committed
Initial commit
1 parent 14b3485 commit 34fabfc

40 files changed

Lines changed: 4078 additions & 0 deletions

Config/FilterPlugin.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[FilterPlugin]
2+
; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and
3+
; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively.
4+
;
5+
; Examples:
6+
; /README.txt
7+
; /Extras/...
8+
; /Binaries/ThirdParty/*.dll

FunctionHandler.uplugin

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"FileVersion": 3,
3+
"Version": 1,
4+
"VersionName": "1.0",
5+
"FriendlyName": "FunctionHandler",
6+
"CreatedBy": "PsinaDev",
7+
"Modules": [
8+
{
9+
"Name": "FunctionHandler",
10+
"Type": "Runtime",
11+
"LoadingPhase": "Default"
12+
},
13+
{
14+
"Name": "FunctionHandlerEditor",
15+
"Type": "Editor",
16+
"LoadingPhase": "Default"
17+
},
18+
{
19+
"Name": "FunctionHandlerUncooked",
20+
"Type": "UncookedOnly",
21+
"LoadingPhase": "Default"
22+
}
23+
],
24+
"Description": "",
25+
"Category": "Runtime",
26+
"CreatedByURL": "https://github.com/PsinaDev/",
27+
"DocsURL": "https://github.com/PsinaDev/FunctionHandler",
28+
"MarketplaceURL": "",
29+
"SupportURL": "https://github.com/PsinaDev/FunctionHandler/issues",
30+
"CanContainContent": false,
31+
"IsBetaVersion": false,
32+
"IsExperimentalVersion": false,
33+
"Installed": false
34+
}

README.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# FunctionHandler
2+
3+
**English** | [Русский](README.ru.md)
4+
5+
A serializable, data-driven function call system for Unreal Engine 5. Configure function calls in the editor with full parameter editing — execute them at runtime via `ProcessEvent`.
6+
7+
![Hero Banner](screenshots/hero_banner.png)
8+
9+
## Overview
10+
11+
**FunctionHandler** wraps a `UFunction` reference with stored parameter values into a single, serializable struct (`FFunctionHandler`). Instead of hardcoding function calls or wiring dozens of Blueprint nodes, you define *what* to call and *with what parameters* as data — then execute it whenever and wherever you need.
12+
13+
**Key features:**
14+
- Serializable `FFunctionHandler` struct — works with SaveGame, replication, data assets
15+
- Full property editors in Details panel (GameplayTag pickers, asset selectors, color pickers, etc.)
16+
- Custom K2 Nodes: **Execute Handler**, **Make Handler**, **Set/Get Handler Parameters**
17+
- Typed return value / out parameter support via custom Blueprint VM thunks
18+
- C++ template API: `UFunctionHandlerLibrary::SetParameter<T>()`
19+
- Zero runtime dependencies on editor modules
20+
21+
## Installation
22+
23+
1. Clone or download into your project's `Plugins/` directory
24+
2. Regenerate project files
25+
3. Enable the plugin in `.uproject` or via Edit → Plugins
26+
27+
**Modules:**
28+
29+
| Module | Type | Purpose |
30+
|--------|------|---------|
31+
| `FunctionHandler` | Runtime | Core struct, library, VM thunks |
32+
| `FunctionHandlerEditor` | Editor | Property customization |
33+
| `FunctionHandlerUncooked` | UncookedOnly | K2 Nodes, graph pin widgets |
34+
35+
## Quick Start
36+
37+
### Blueprint — Variable Workflow
38+
39+
1. Add a `FFunctionHandler` variable to your Blueprint
40+
2. In the Details panel, select **Target Class** and **Function**
41+
3. Configure parameters with native property editors
42+
4. Use **Execute Function by Handler** or **Execute Handler** node at runtime
43+
44+
![Variable Workflow](screenshots/variable_workflow.png)
45+
46+
### Blueprint — Make Handler Workflow
47+
48+
1. Place a **Make Function Handler** node
49+
2. Select Target Class in node details, pick a function from the dropdown
50+
3. Wire typed parameter inputs
51+
4. Connect output to **Execute Handler** for typed return values
52+
53+
![Make Handler Workflow](screenshots/make_handler_workflow.png)
54+
55+
### Blueprint — Set / Get Handler Parameters
56+
57+
Use **Set Handler Parameters** to batch-write all parameter values on an existing handler, and **Get Handler Parameters** to batch-read them back — both with fully typed pins.
58+
59+
![Batch Set Get](screenshots/batch_set_get.png)
60+
61+
### Blueprint — Set Single Parameter
62+
63+
1. Place a **Set Handler Parameter** node
64+
2. Connect a Handler variable or Make node
65+
3. Select parameter from the dropdown — Value pin automatically resolves to the correct type
66+
67+
![Set Parameter Node](screenshots/set_parameter_node.png)
68+
69+
### C++
70+
71+
```cpp
72+
#include "FunctionHandlerTypes.h"
73+
#include "FunctionHandlerLibrary.h"
74+
75+
// Create a handler
76+
FFunctionHandler Handler;
77+
Handler.TargetClass = UAbilityComponent::StaticClass();
78+
Handler.FunctionName = TEXT("AddState");
79+
80+
// Set parameters (type-safe)
81+
FGameplayTag Tag = FGameplayTag::RequestGameplayTag(TEXT("State.Active"));
82+
UFunctionHandlerLibrary::SetParameter(Handler, TEXT("State"), Tag);
83+
84+
// Execute on a target
85+
UFunctionHandlerLibrary::ExecuteFunctionByHandler(MyAbilityComponent, Handler);
86+
```
87+
88+
## Details Panel
89+
90+
The property customization provides a complete editing experience:
91+
92+
- **Target Class** picker with standard class selector
93+
- **Function** dropdown with search (filters delegates, internal functions)
94+
- **Parameter editors** — native UE property widgets for every parameter type
95+
- Hidden parameters (return value, pure out) are automatically filtered
96+
97+
![Details Panel](screenshots/details_panel.png)
98+
99+
## K2 Nodes
100+
101+
### Execute Function Handler
102+
103+
Executes a handler on a target object. Automatically generates **typed output pins** for return values and out parameters based on the connected handler's function signature.
104+
105+
**Features:**
106+
- Resolves function signature from connected variable (via CDO) or Make node
107+
- Typed return value and out-parameter pins
108+
- Reacts to Blueprint compilation, variable changes, and pin connections
109+
- Orange tint for visual distinction
110+
111+
### Make Function Handler
112+
113+
Creates a `FFunctionHandler` struct inline with typed input pins for each function parameter.
114+
115+
**Features:**
116+
- Target Class in node details
117+
- Function dropdown with search directly on the node
118+
- Typed input pins generated from function signature
119+
- Chains with Execute Handler for end-to-end typed workflow
120+
121+
### Set Handler Parameters
122+
123+
Batch-writes all parameter values on an existing handler with typed input pins. Resolves function signature from the connected handler — generates one input pin per parameter.
124+
125+
**Features:**
126+
- Typed input pins for every function parameter
127+
- Works with variable-based and Make-based handlers
128+
- Only writes parameters that have a connection or non-empty default
129+
130+
### Get Handler Parameters
131+
132+
Batch-reads all stored parameter values from a handler into typed output pins. The inverse of Set Handler Parameters.
133+
134+
**Features:**
135+
- Typed output pins for every function parameter
136+
- Only evaluates outputs that are actually connected
137+
- Useful for inspecting or forwarding handler state
138+
139+
### Set Handler Parameter
140+
141+
Sets a single parameter on an existing handler with a type-safe value pin.
142+
143+
**Features:**
144+
- Parameter dropdown on the node (populated from connected handler's function)
145+
- Wildcard Value pin resolves to the selected parameter's type
146+
- Works with both variable-based and Make-based handlers
147+
148+
## Architecture
149+
150+
```
151+
FFunctionHandler (USTRUCT)
152+
├── TargetClass: TSubclassOf<UObject>
153+
├── FunctionName: FName
154+
├── ParameterValues: TMap<FName, FString> ← ExportText/ImportText serialization
155+
├── ResolveFunction(UObject*) → UFunction*
156+
└── ResolveFunctionFromClass() → UFunction*
157+
158+
UFunctionHandlerLibrary (UCLASS)
159+
├── ExecuteFunctionByHandler() ← Simple fire-and-forget
160+
├── SetParameter<T>() ← C++ template setter
161+
├── InternalExecuteWithResult() ← Returns UFunctionCallResult*
162+
├── GetResultByName() ← CustomThunk, typed output
163+
├── InternalSetParameter() ← CustomThunk, typed input
164+
├── InternalGetParameter() ← CustomThunk, typed output from TMap
165+
└── InternalMakeFunctionHandler() ← Struct construction
166+
167+
UFunctionCallResult (UCLASS, Transient)
168+
├── ResultData: TSharedPtr<FStructOnScope> ← Owns the parameter buffer
169+
├── CachedFunction: TWeakObjectPtr<UFunction>
170+
└── GetBuffer() → uint8*
171+
```
172+
173+
### How It Works
174+
175+
1. **Editor time:** Property customization creates `FStructOnScope(UFunction*)`, imports stored values, displays via `IStructureDetailsView`. Changes export back to `TMap<FName, FString>`.
176+
177+
2. **Compile time:** K2 Nodes expand into chains of `InternalMakeFunctionHandler` → `InternalSetParameter` → `InternalExecuteWithResult` → `GetResultByName` calls. CustomThunks use `FProperty::ExportTextItem_Direct` / `ImportText_Direct` for type-safe conversion.
178+
179+
3. **Runtime:** `ExecuteFunctionByHandler` allocates a parameter frame (`FMemory::Malloc` + `InitializeStruct`), imports values from TMap via `ImportText_Direct`, calls `ProcessEvent`, cleans up.
180+
181+
### CustomThunk Implementation
182+
183+
The plugin uses UE's Blueprint VM `CustomThunk` mechanism for type-safe wildcard parameters:
184+
185+
- **`GetResultByName`** — Reads from `UFunctionCallResult` buffer using `FProperty::CopySingleValue`
186+
- **`InternalSetParameter`** — Exports typed value via `FProperty::ExportTextItem_Direct` into the handler's TMap
187+
- **`InternalGetParameter`** — Imports stored text from the handler's TMap back into a typed output via `FProperty::ImportText_Direct`
188+
189+
All follow the engine's `StepCompiledIn<FProperty>` pattern with explicit `MostRecentProperty` reset to avoid stale VM state.
190+
191+
## Requirements
192+
193+
- Unreal Engine 5.6+
194+
- C++17
195+
196+
## License
197+
198+
MIT

0 commit comments

Comments
 (0)