In the preview promotion video of UE5, a mechanism for modular development of GamePlay is introduced, which is similar to Mod to develop and manage game functions and resources. It is called "Game Feature". It can be enabled in UE4.27 and UE5. I think this new Gameplay Modualr form is great, so I do a technical pre research.
This article introduces the enabling process and operating mechanism of the Game Feature. At the end of the article, a Demo based on the Game Feature is implemented and shared. At present, there are still imperfections in the UE5 EA version, and the relevant contents will be supplemented with the update of the engine.
The problem to be solved by Game Feature is the modularization of Game Play. Some functions and associated resources are aggregated as a separate Feature, which can be loaded when needed and unloaded when not needed. Dynamically manage game runtime resources without relying on complete game resources at startup.
This is very similar to the hot update mechanism, because the Game Feature is essentially a group of resource packages, but the UE adds the function of dynamic execution logic on the basis of the resource package, which can easily add functions to the existing actors, even some ECS flavor. The implementation of UE's Game Feature is based on the Plugin system. Each Game Feature can be regarded as a Content Only plug-in, which manages a pile of resources and pluggable game logic, and manages the Feature's resources and behavior through GameFeatureData.
However, in the current implementation of UE, it seems that it is only regarded as a modular management mechanism and cannot be packaged separately. After research, the Game Feature can also be dynamically downloaded and enabled. I am based on HotPatcher The packaging of game features is realized. A Game Feature can be packaged separately, downloaded on demand and enabled in the game. It is feasible. An article will be written later to explain the implementation separately.
Enable and create
First open the Game Feature and Modular Feature plug-ins:
When enabled, GameFeature setting options will be available in the project settings:
You need to create a new plug-in for the GameFeature of the new project. You can see the plug-in template of the Game Feature(Content Only):
A plug-in will be created in the Plugins/GameFeatures directory of the project:
C:\Users\lipengzha\Documents\Unreal Projects\ThirdPerson_UE5\Plugins\GameFeatures>tree /a /f volume Windows Folder for PATH list The volume serial number is 0 C49-9EA3 C:. \---GF_Examles | GF_Examles.uplugin | +---Content | GF_Examles.uasset | \---Resources Icon128.png
Its uplugin contents are:
{ "FileVersion": 3, "Version": 1, "VersionName": "1.0", "FriendlyName": "GF_Examles", "Description": "", "Category": "Game Features", "CreatedBy": "", "CreatedByURL": "", "DocsURL": "", "MarketplaceURL": "", "SupportURL": "", "CanContainContent": true, "IsBetaVersion": false, "IsExperimentalVersion": false, "Installed": false, "ExplicitlyLoaded": true, "BuiltInInitialFeatureState": "Installed" }
And automatically create a GameFeatureData resource in the Content. Note that it must be the same as the plug-in Name:
In the EditPlugin option, you can set the initial state of the current Game Feature. Active will load by default when the engine starts:
If the Initial State of the Game Feature is Active, it will be loaded automatically when the engine starts. Call the stack:
A Game Feature has the following states:
/** The states a game feature plugin can be in before fully active */ enum class EGameFeaturePluginState : uint8 { Uninitialized, // Unset. Not yet been set up. UnknownStatus, // Initialized, but the only thing known is the URL to query status. CheckingStatus, // Transition state UnknownStatus -> StatusKnown. The status is in the process of being queried. StatusKnown, // The plugin's information is known, but no action has taken place yet. Uninstalling, // Transition state Installed -> StatusKnown. In the process of removing from local storage. Downloading, // Transition state StatusKnown -> Installed. In the process of adding to local storage. Installed, // The plugin is in local storage (i.e. it is on the hard drive) WaitingForDependencies, // Transition state Installed -> Registered. In the process of loading code/content for all dependencies into memory. Unmounting, // Transition state Registered -> Installed. The content file(s) (i.e. pak file) for the plugin is unmounting. Mounting, // Transition state Installed -> Registered. The content files(s) (i.e. pak file) for the plugin is getting mounted. Unregistering, // Transition state Registered -> Installed. Cleaning up data gathered in Registering. Registering, // Transition state Installed -> Registered. Discovering assets in the plugin, but not loading them, except a few for discovery reasons. Registered, // The assets in the plugin are known, but have not yet been loaded, except a few for discovery reasons. Unloading, // Transition state Loaded -> Registered. In the process of removing code/contnet from memory. Loading, // Transition state Registered -> Loaded. In the process of loading code/content into memory. Loaded, // The plugin is loaded into memory, but not registered with game systems and active. Deactivating, // Transition state Active -> Loaded. Currently unregistering with game systems. Activating, // Transition state Loaded -> Active. Currently registering plugin code/content with game systems. Active, // Plugin is fully loaded and active. It is affecting the game. MAX };
Common operations at the business end are:
- Load
- active
- Deactivate
- unload
If PluginURL needs to be passed when calling them, it is the path of the uplugin file, which can be obtained by passing the plug-in name in the following ways:
GameFeatureSubsystem->GetPluginURLForBuiltInPluginByName(PluginName,OutPluginURL);
These functions are not exposed to the blueprint and can be encapsulated (note the module dependencies of GameFeatures and Projects):
// .h UCLASS() class GAMEFEATUREUTILS_API UFlibGameFeature : public UBlueprintFunctionLibrary { GENERATED_UCLASS_BODY() public: UFUNCTION(BlueprintCallable) static bool GetPluginURLForBuiltInPluginByName(class UGameFeaturesSubsystem* Subsystem,const FString& PluginName, FString& OutPluginURL); UFUNCTION(BlueprintCallable) static void LoadGameFeature(class UGameFeaturesSubsystem* Subsystem,const FString& InFeature); UFUNCTION(BlueprintCallable) static void ActiveGameFeature(class UGameFeaturesSubsystem* Subsystem,const FString& InFeature); UFUNCTION(BlueprintCallable) static void LoadBuiltInGameFeaturePlugin(UGameFeaturesSubsystem* Subsystem,const FString& PluginName); UFUNCTION(BlueprintCallable) static void LoadBuiltInGameFeaturePlugins(UGameFeaturesSubsystem* Subsystem); UFUNCTION(BlueprintCallable) static void UnloadGameFeature(UGameFeaturesSubsystem* Subsystem,const FString& InFeature, bool bKeepRegistered = false); UFUNCTION(BlueprintCallable) static void DeactivateGameFeature(UGameFeaturesSubsystem* Subsystem,const FString& InFeature); static void OnStatus(const UE::GameFeatures::FResult& InStatus); UFUNCTION(BlueprintCallable,BlueprintPure,meta=(WorldContext="WorldContextObject")) static class UGameFrameworkComponentManager* GetGameFrameworkComponentManager(UObject* WorldContextObject); UFUNCTION(BlueprintCallable,meta=(WorldContext="WorldContextObject",DefaultToSelf="Owner")) static void AddReceiver(UObject* WorldContextObject,AActor* Owner); UFUNCTION(BlueprintCallable,meta=(WorldContext="WorldContextObject",DefaultToSelf="Owner")) static void RemoveReceiver(UObject* WorldContextObject,AActor* Owner); };
When editing in the engine, you can set the Feature to Active, so that it will be automatically loaded and displayed in the Content Browser when the engine starts. Otherwise, it will not be displayed and cannot be edited if it is not loaded.
Feature Actions
You can add actions and resources managed by the current GameFeature in the configuration of the Game Feature, which is also the most important to realize modularization.
Take Add Component as an example, you can automatically create a component on a specified class:
When the Feature is loaded and set to Active, the component will be automatically added to all instances of the specified Actor Class.
Note that you need to add yourself to the Receiver in the target Actor in advance:
When the Feature is deactivated, the component will be removed from the Actor, so custom functions can be performed in the BeginPlay/EndPlay of the component.
Based on the above function library, I created a UMG for testing and loading features:
Feature loading test: Created a BP_ The component of component and add it to BP_ On pawn, create and remove a UMG in BeginPlay/EndPlay of component:
Operation effect:
Game Features settings
Under project settings game features in UE5, you can set GameFeatureManagerClass to start gamefeatures in the project, where you can control which features are loaded.
We can also inherit UGameFeaturesProjectPolicies to implement our own controlled processes:
void UGameFeaturesUtilsProjectPolicies::InitGameFeatureManager() { UE_LOG(LogGameFeatures, Log, TEXT("Scanning for built-in game feature plugins")); auto AdditionalFilter = [&](const FString& PluginFilename, const FGameFeaturePluginDetails& PluginDetails, FBuiltInGameFeaturePluginBehaviorOptions& OutOptions) -> bool { return true; }; UGameFeaturesSubsystem::Get().LoadBuiltInGameFeaturePlugins(AdditionalFilter); }
The loading control of a Feature is realized by passing a predicate when LoadBuiltInGameFeaturePlugins is loaded. When loading a Feature, the callback will determine whether to load it:
void UGameFeaturesSubsystem::LoadBuiltInGameFeaturePlugin(const TSharedRef<IPlugin>& Plugin, FBuiltInPluginAdditionalFilters AdditionalFilter) { // ... bool bShouldProcess = AdditionalFilter(PluginDescriptorFilename, PluginDetails, BehaviorOptions); if (bShouldProcess) { UGameFeaturePluginStateMachine* StateMachine = GetGameFeaturePluginStateMachine(PluginURL, true); // ... } // ... }
pack
After the plug-in of Game Feature is created, restart the project, and you will be prompted to Add entry to PrimaryAssetTypesToScan. Click it to automatically add it to the Asset Manager of project settings. There will be the option of GameFeatureData to manage packaged gamefeatures:
During packaging, you need to set the Game Feature's Init State to registered to ensure that the Feature's plug-in will be loaded during packaging, otherwise the Feature cannot be packaged.
Demo
In order to show the usage of Game Feature, I made a Demo using the mechanism of Game Feature to realize an example of simple play:
- When a Feature is loaded, 30 pickable objects are created randomly in the scene
- Countdown 20s, players pick up objects in the scene
- Record points
- Clear all created actors at the end of the timing
All functions and resources are in GF_Feature is a plug-in of the Game Feature, that is, an independent module, so as to realize pluggability in the game.
Download the Demo: GameFeatureDemo_BlankUE5.7z