Using PulseFoundation in a Pulse plugin
PulseFoundation is the only Pulse plugin another Pulse plugin may depend on. This page lists what a Pulse plugin takes from PulseFoundation instead of own code, and what it adds so it fits the other plugins.
Dependency
```json title=”
```csharp title="<Module>.Build.cs"
PublicDependencyModuleNames.Add("PulseFoundation");
List PulseFoundation in the Build.cs of every module that uses its types, also when a module it depends on already lists it publicly: the include paths are passed on, but the linker needs the direct dependency (otherwise unresolved external symbol ... UPulseDeveloperSettings or Pulse::Serialization::...). Modules whose public headers use PulseFoundation types (a settings class deriving from UPulseDeveloperSettings, a component implementing IPulseDebugSnapshotProvider) list it in PublicDependencyModuleNames.
Name the minimum PulseFoundation version in the plugin’s README and check it in code where needed: static_assert(PULSE_FOUNDATION_VERSION_AT_LEAST(1, 0), "...").
Fab packages
On Fab, a Pulse plugin comes with its own copy of PulseFoundation: renamed modules (PulseSkill_PulseFoundation, …) and its content under /<Plugin>/Foundation (see Fab packages and separate plugins). The package builder renames the dependencies in the plugin’s Build.cs and .uplugin, so they keep the name PulseFoundation. In code:
- Never write the plugin, module or content names of PulseFoundation as text. Use
Pulse::Foundation::GetHostPluginName(), the module interfaces (IPulseFoundationEditor::Get(), …) andPulse::Foundation::MakeContentPath(), e.g. for default asset paths in a settings constructor:MakeContentPath(TEXT("UI/Textures/T_PulseUI_Icon_Check.T_PulseUI_Icon_Check")). - A plugin that gets a Fab package adds its lines to the reverse redirect block of
DefaultPulseFoundation.iniand to the product list of the specPulseFoundation.Distribution. - Build the plugin with
RunUAT BuildPluginbefore a release. It compiles the files one by one, like Fab does, and finds missing includes that the unity files of a project build hide.
Replace own copies
| Own code | PulseFoundation |
|---|---|
SaveDataToBytes / LoadDataFromBytes with SerializeTaggedProperties | Pulse::Serialization::StructToBytes / ReadVersioned (same byte format) |
Own import report with TArray<FString> Messages | FPulseImportReport (derive or embed) |
| Controller / player state / pawn lookups | Pulse::Player::*, FindComponentOnPlayer |
UDeveloperSettings with category “Pulse” | UPulseDeveloperSettings |
| Own handle structs | FPulseHandle (or wrap it) |
| Own instanced struct “one per type” lists | FPulseInstancedStructSet / Pulse::Structs |
| Own view model resolver for “owning player” | UMVVMPulsePlayerViewModel + UPulsePlayerViewModelResolver |
| Test world setup in specs | Pulse::Testing::FTestWorld |
| Report recorder / JSON report files | FPulseReportRecorder + FPulseReportPolicy |
Keep public functions that other plugins or games call; forward them to PulseFoundation and mark them UE_DEPRECATED.
Add
- Broadcast events that others may react to loosely on
Pulse.Message.<Plugin>.<Event>with a payload struct, in addition to the native and dynamic events. - Implement
IPulseDebugSnapshotProvideron the plugin’s main components and subsystems. - Record
PULSE_DEBUG_EVENTs for what happens (started, finished, rejected and why). - Add a
FPulseReportPolicyto the settings when the plugin has multi-step processes, and report them. - Move player-facing options into a
UPulsePlayerSettingssubclass. - Add cheats as a
UPulseCheatExtensionsubclass.