A collection of generic, utility functionality & useful info for my personal projects in Unreal Engine 5.
Code is currently implemented in a series of Unreal modules, all provided under one plugin. If any single piece of functionality proves to be useful and worth making standalone, it may be moved to its own plugin & module in the future.
Clone this repository in to your Plugins directory
git submodule add github.com/vaeryn-uk/vul Plugins/Vul
Then add this to your project's .uproject file:
// ...
"Plugins": [
// ...,
{
"Name": "Vul",
"Enabled": true
}
]
// ...
The Vul plugin provides some template classes that use dynamic_cast outside of the UE UObject system.
Enable RTTI in any module that defines tooltip data or widgets (usually your game module) for this to compile.
Note: RTTI is only enabled for Win64 in VulRuntime, so features within this library that rely on RTTI
will not work on Android/Linux. See USE_RTTI throughout the source code for limitations.
It is possible that RTTI usage is dropped in the future, which would enable Android/Linux support.
// in MyGameModule.build.cs
// ...
bUseRTTI = Target.Platform == UnrealTargetPlatform.Win64;
// ...
This requirement is introduced by Vul's tooltip implementation. If you don't use this, you may not need to enable RTTI in your modules.
You will also need the UnrealYAML project: https://github.com/jwindgassen/UnrealYAML
git submodule add https://github.com/jwindgassen/UnrealYAML Plugins/UnrealYAML
Note: extra functionality we need is currently added to this library in a fork: https://github.com/vaeryn-uk/UnrealYAML.
.uproject file:
{
"Name": "UnrealYAML",
"Enabled": true,
"TargetAllowList": [
"Editor"
]
},
The widely followed style guide by Allar that I recommend: https://github.com/Allar/ue5-style-guide
The included .gitattributes and .gitignore files are a useful starting point for Unreal projects using Git as a version control system.
The ignore files prevents committing big/unintended files, such as as engine cache files or built binaries.
The attributes file configures asset files, such as images or models, to be tracked by Git LFS to reduce storage requirements.
An overview of some of the functionality provided by this plugin.
Data table sources allow for importing files into Unreal's Data Tables. This offers the following features over & above native UE data table functionality:
- YAML data files, which tend to be more user-friendly & more concise than JSON.
- Support for multiple files feeding in to one data table, rather than needing a huge, single JSON file.
- Also support for a single file feeding in to to different data tables, allowing for game-semantic structuring of YAML files.
- Test operation to verify what will happen before performing a real import.
- Specify
meta="VulRowName"in aUPROPERTYto have the import automatically populate the row name in to the struct directly. Useful for identity/equality checks on row structs.
- Data table wrapper to coordinate access to data table rows, see
UVulDataRepository. - A reference type in row structs that allow for convenient access to other rows, see
FVulDataPtr. These pointers are initialized with enough information to fetch the referenced row without needing to go back through the repository.FVulDataPtrand its typed version,TVulDataPtr, provides a bunch of features as a general-use pointer type for rows, so we use this as the only type returned from the repository.
- See
MyProject.ps1, which contains theImportGameDataaction demonstrating how repositories can be synchronized from a Python script to save booting the editor & needing to manually reimport.
TVulMeasure and TVulNumber provide functionality for representing and modifying numeric
values in game logic, such as health and stats in an RPG system.
TVulCharacterStat is similar to above, but is simplified for stats that have modifications
bucketed by defined sources, which are each tracked independently.
The VulRuntime::Enum namespace provides some utility functionality for working with UEnums in your
code.
VulEnumTable allows you to combine a config/data-table-driven approach connected to explicit
enum definitions in your code to yield benefits of generic config-driven functionality with the
freedom to safely hard-code functionality to well-known enum values.
There are two implementations available:
TVulDataPtrEnumTable(recommended) which integrates withUVulDataRepositoryfunctionality which supports references to other tables in your enum rows.TVulEnumDataTableis simpler and integrates withUDataTables directly.
A UVulLevelManager can be configured from Vul's project settings, see UVulRuntimeSettings::LevelSettings.
This subsystem will manage levels on game start, and it will coordinate the streaming of
data in and out, with a loading screen that will be displayed whilst this occurs. Additional
support is provided for useful functionality such as hooking in to when levels are loaded and automatically
spawning widgets when certain levels are shown, based on the LevelData assets that are configured in level
settings.
UVulLevelManager makes a best attempt to support loading non-root levels from the editor. If it detects
that you're booting a level that's not the configured RootLevel, it will initialize actors and hooks in
the same way as if it were being loaded during normal gameplay.
Levels can be marked as cinematic levels, see UVulLevelData::SequenceSettings. In this case, the level
manager will play the cinematic and immediately move on to another level when it's completed.
Synchronized level transitions are supported in networked games. The server remains authoritative over level changes, while clients automatically follow and report their load progress.
Level synchronization is handled via a lightweight replicated actor (AVulLevelNetworkData) that exists on the server (primary) and on each client (follower). This actor exposes the current level, any in-progress level load request and basic readiness state, relying on replication to communicate & coordinate the synchronized loading of levels.
When the server initiates a level change:
- The target level and request state are replicated to clients.
- Clients stream the level locally and report completion back to the server.
- The server waits until all required clients are ready before finalizing the transition.
- Once the transition is complete, the active level state is replicated back to clients, allowing loading screens to be dismissed and level-specific initialization to proceed in sync.
Spawned actors created during a managed level load are tracked and replicated so clients can reliably resolve their corresponding instances after the transition, providing a framework for RPC calls outside the standard PlayerController model.
Caveat The current networked level loading implementation is functional but not robust. It has known edge cases, limited fault tolerance and likely many bugs under real-world network conditions. It should be considered experimental and is due a significant rewrite before being reliable for production use.
UVulDeveloperSettings provides an extension to project-specific settings for your game with the ability
to mark certain settings' values ignored if a "developer mode" flag is enabled. Useful for quickly switching
values for something you're developing now, and reverting back to the normal settings without needing to reconfigure
everything.
You will need the DeveloperSettings module enabled in your Project.Build.cs file to extend & use this
feature.
See TVulRngManager for more information.
- See
FVulActorUtilfor a bunch of C++ helpers for writing actor-interacting code. This serves both as code that can be used, but also a form of documentation of how to work with actors. TVulComponentCollectionis a data type for conveniently working with zero or more components that share tag.FVulNiagaraCollectioncan be used for Niagara components, but also serves as example of our collection's use.
FVulUiNotification and TVulNotificationCollection provide an efficient creation and storage
of temporary notifications to a player. This provides functionality such as:
- Configuration for how long each notification displays for.
- Automatic widget creation & removal once the notification expires.
- Simple API to replace existing content.
- Extensibility for implementation of different notification types;
FVulHeadlineNotificationis the provided implementation.
UVulTextNotificationComponent can be attached to actor to render text to the screen at their position.
This uses the TVulNotificationCollection above, using a standard notification implementation, FVulTextNotification,
which can render text & icons.
A reusable variation of a border widget that allows defining multiple, overlaid borders in its style definition.
See UVulMultiBorder.
UVulAnimatedHighlight wraps content, providing a highlighting effect when the content is hovered.
Intended to be used alongside tooltip functionality.
Contains content that is shown/hidden when a connected button is pushed. See UVulCollapsedPanel.
UVulTooltipSubsystem provides a simple API for displaying a tooltip to the user as they interact
with the world/interface. This is implemented independently of Unreal's native tooltip support for now,
but maybe integrated later if a need arises.
To use this, create a widget class and implement IVulTooltipWidget in C++, then create
a widget UMG blueprint that extends it and select the UMG in Vul Runtime's project settings as the
widget class to use.
Once configured, UVulTooltipSubsystem can be called (see VulRuntime::Tooltip(WorldCtx)) to show and
hide a tooltip per player. When showing the tooltip, you must provide a tooltip data instance
(which extends FVulTooltipData). This allows you to define what data can be displayed in a tooltip and
provides a structured system for consistent tooltips across your game.
UVulTooltipUserWidget is provided to save writing tooltip-triggering logic for widgets that
should trigger a tooltip when hovered. If you extend this, all you need to do is define the tooltip
data that widget will trigger.
This tooltip system also integrates with Vul's Rich Text support.
UVulRichTextBlock seeks to simplify customization and workflows when using Unreal's rich text system.
This encapsulates a bunch of boilerplate code and allows your project to extend this widget class
to customize available rich text support across your entire project. Use your extending class in all
places where text is used in the UI.
The approach is an extension of Unreal's CommonUI.
See the code in UVulRichTextBlock for customization documentation, but as a quick setup overview:
- As per CommonUI, configure relevant settings:
Common UI Editor->Template Text Style. This will be applied as the rich text default style override for newly created rich text blocks.- Create a BP that extends
UCommonUIRichTextData - Select this in
Common UI Framework->Default Rich Text Data Class - If you want icon support, create a data table with a row structure of
FVulRichTextIconDefinition.- Set this table in Vul library settings,
IconSet. - Use syntax
<vi i=\"<row-name>\"</>to render icons - Optionally override
UVulRichTextIconto further customize appearance, then select your override in Vul library settings. Note currently widget blueprints extensions of this icon widget do not work; they must be in C++. - These icons extend Rich Text Icons with support for color and background configuration.
- Set this table in Vul library settings,
- You may define a rich text styles table as per CommonUI, although the Vul rich text support doesn't utilize or enhance this in any way.
- Create a widget blueprint with parent
UVulRichTextTooltipWrapper. This is used whenever we replace rich text markup with something with a tooltip.- Set this Vul's project settings'
Rich Text Tooltip Wrapper.
- Set this Vul's project settings'
- Review
UVulRichTextBlockcomments, and override relevant methods to add rich text support specific for your project.
A property that allows you to control spacing between elements in a container that can
be seamlessly switched between horizontal and vertical boxes. See FVulElementSpacer.
This editor functionality aims to improve the creation & maintenance of a consistent
set of styles for CommonUI UI components. For example, your project may have primary,
secondary and danger buttons. These three styles would be defined as variations in
a generator, then you can use the in-editor Generate functionality to create or
update the corresponding button styles. This takes the manual work out of updating
all of your styles, and provides a single editor pane where all your style diffferences
are listed in place.
Generators provided:
VulButtonStyleGeneratorVulTextStyleGeneratorVulBorderStyleGenerator
Note that generators only allow variation of a small subset of available properties right now. These may be expanded as use-cases arise.
FVulField and its related components provide an alternative approach to parts of the Unreal Header Tool
and the reflection system. They make heavy use of templates and modern C++ concepts.
Use these components to describe and serialize your C++ types, allowing more flexibility than the
constraints typically associated with USTRUCT, UCLASS, and similar macros.
TVulCopyOnWritePtr is useful to avoid unnecessary copying of data in scenarios where you are often reading
but sometimes copying.
TVulAdaptiveLootModel provides an implementation of rolling random rewards. The implementation provides
information allowing you to easily implement loot systems that tend towards coherent builds. I.e. as a player
acquires loot of a particular build or strategy, complimentary loot to that style is more likely to come.