WHAT
The Game Features and Modular Gameplay plugins help developers create standalone features for their projects. Building with these plugins keeps the project’s codebase clean and readable, and avoids accidental interactions or dependencies. This week on Inside Unreal, Senior Engine Programmer Mike Beach and Lead Engine Programmer Michael Noland will help us understand and discuss these new plugins!
WHO
Mike Beach - Senior Engine Programmer - @WhatsNawfix
Michael Noland - Lead Engine Programmer @joatski
Victor Brodin - Product Specialist - @victor1erp
This looks like something that could be useful for adding mod support.
Can these feature “plugins” be built and exported as standalone mods? Could you drop them inside a game’s folder and have it discover and load them dynamically or do they have to be cooked and included from the get-go?
Is there a way for GameplayFeatures to perform an action based on the presence of certain components on an actor?
I have a loot system wip that is about the lightest weight possible I believe, where I have a UAssetUserData derived meta data attached to certain static meshes or components. The user data specifies some information about the type of loot the object should generate. My loot system is a subsystem that maintains a mapping between the object paths and the generated loot. My player interaction logic asks the loot system if the item being aimed has loot associated with it. This could be any flavor of a static mesh component or instanced static mesh component that can be lootable through this system. I’ve made a concerted effort to have this system place no demands on what actor it must be, or what components it must have.
The only less than desirable piece is that right now I’m somewhat jankily using a spherical loot sensor to do overlap tests to ‘touch’ all these objects in order to seed the loot subsystem with their loot. If loot is generated, some material instance values are set to drive visual distinction of the object. I would love to use the feature system and have an action run on any static mesh component or instanced static mesh component that has my ULootableAssetUserData or ULootableInstancedAssetUserData, to ensure basically that these super light weight loot containers, represented only by static meshes or ISM, get seeded properly from their inception.
I would really like to be able to hook feature actions into component levels, and also to allow components to opt-in with the presence of an UAssetUserData type. This would let you avoid the need to derive from types in order to do things like UGameFrameworkComponentManager AddReciever/AddGameFrameworkComponentReceiver, and let you take advantage of the feature system on engine level actors/components in a data driven way.
This seems pretty useful, because as long as you require explicit registration via a derived class, you close the gameplay feature functionality to certain tools or workflows, such as harvest based blueprints, or some of the new UE5 tooling that generates ISMs.
Is there a way for GameplayFeatures to perform an action based on the presence of certain components on an actor?
What it sounds like you’re wanting is a UGameFrameworkComponentManager::AddExtensionHandler() at the component level, instead of for actors. That doesn’t exist currently.
The crux of this problem is going to come down when your action is ready to inspect an actor, will the component be present at that time? This becomes complicated if your components are dynamically added.
You could still use UGameFrameworkComponentManager::AddExtensionHandler(), and have a unique extension event that is sent from the component (for its owning actor). This way you can know that the actor for sure has the component. The problem here is scale – you’ll likely end up listening to way more actors than you need to (actors that don’t have the component). This may be fine, depending on the scale of your game, and the actor subclass you’re targeting.
In AncientGame, UGameFeatureAction_AddInputContextMapping has an example of how it uses extension handlers if you’re looking for a place to start.
The issue with these functions so far is that they are all keyed off a specific actor type. There isn’t currently any functionality to key into component types, across any actor type. In other words, ideally I don’t want to have to care about what actor type these components are on. I want to find any static mesh component or instanced static mesh component with a particular asset user data and run some logic on it with the gameplay system.
I built my loot system to key off of a user data asset so that any object could be a lootable. It supports static mesh components, instanced static mesh components, and skeletal mesh components.
ULootableAssetUserData : public UAssetUserData
The issue I’m grappling with here is that there isn’t a very clean way to perform some startup logic keyed off of component types with the game feature system, it’s all actor keyed.
The system currently is not at all dependent on these supported components being part of a specific actor type. This is a strength to the design of this system in my opinion. Static/Skeletal/ISM components can exist in the form most optimal to their display, and my loot system will still work for them. I’m trying to avoid moving backwards to an expectation of a specific parent actor type. This modular game feature seems like it would force that, so I’m wondering about the possibility of keying off of component types, not actor types, even engine component types in this case.
Otherwise I’ll need to use a different approach to finding and seeding all the lootable tagged objects.
TLDR: Can you add a way to key actions on component types, with no regard or requirement to the actor type(including engine components). This implies not having a requirement to opt-in, or perhaps the components would have an alternate way to opt in such as via the presence of a certain UAssetUserData
This looks like something that could be useful for adding mod support.
Can these feature “plugins” be built and exported as standalone mods? Could you drop them inside a game’s folder and have it discover and load them dynamically or do they have to be cooked and included from the get-go?
This isn’t supported out of the box, but it wouldn’t be a huge amount of work to get there. You’d still need to cook/package the mods (cooked games can’t load uncooked assets) but could do so as independent pak files. Then at game startup (or at some triggered point, e.g., selecting a mod browser in the game UI or whatever), you could enumerate the mods folder and mount the pak files, then tell the plugin manager and game feature subsystem to scan for plugins in there.
We probably won’t be adding an event broadcast to every component creation at the base engine level or something like that. We generally wouldn’t want to run O(NumComponents) logic all the time or even once per load, especially if you have e.g., 100k static mesh components, 2k gameplay relevant at all components, and only 50 that any given subsystem cares about.
You’ve got a bit of an awkward data model to match up, you’re trying to get all instances of components that reference a particular asset in effect with no other data to go off of (e.g., particular subclasses of the component itself), so ultimately you’re probably going to have to do a scan like that (and still have to worry about invalidation, e.g., someone calling SetStaticMesh dynamically which would change the reference and invalidate any acceleration structure you set up).
In any event, UGameFrameworkComponentManager is just one example pattern we’ve found to work well, you could create your own subsystem + registration action to e.g., have a ULootableComponent register and allow other things to either modify the actor owning the component, or the component directly or just keep track of them all), rather than have things derive from ALootableActor or something.
Thanks for your time. That’s what I was afraid of. The goal here is that I would like to find a solution that doesn’t necessitate losing the ability to instance render the visuals for these objects.
Honestly, if the PostEditChangeOwner of UAssetUserData took a UObject* of the owner, that simple change could give me a mechanism to register the relevent components in a way that doesn’t involve a huge expensive scan, and lets me hook into only what I need. Is that a reasonable change that could be made at the engine level? I can do it in a local engine build, but I’m not in a hurry to get off into custom engine land.
UActorComponent::PostInitProperties calls PostEditChangeOwner on the asset user data, so my ULootableAssetUserData could cast the owner and do the functionality I need to do.
Likewise, if UAssetUserData took an object reference, there could be an engine level user data subclass that provides a callback into the game feature system for a more generalized hook into the feature system.
UAssetUserData is on the asset, not the component/instance; there isn’t a copy per instance / ownership of it doesn’t change over time, it’s always the asset itself (PostEditChangeOwner is called when the outer asset is modified in the editor; though it doesn’t take an argument you can get to the asset (not the instance) via GetOuter() typically).
Say you’ve got MeshAssetA which in turn has UserDataA on it. If you create another static mesh component pointing to MeshAssetA (or call SetStaticMesh on an existing one), , another copy of UserDataA isn’t created / etc…
Using asset user data to store ‘static’ data like the number of hits or loot entry to roll when something is harvested sounds great, but it can’t be used to store varying per-instance data (e.g., how much HP this thing has left before being harvested). For that you’d need some other storage, which doesn’t have to be a specific actor, it could be, e.g., a sibling component that the looting/damage code looks for when it gets a hit result to your SMC or ISMC, or creates dynamically only as needed (e.g., when first hit).
Right, I understand. It’s static immutable data on the assets. But the AssetUserData on the actor component is instanced. Edit: technically not immutable, but not valid for most state
I’m using it as an immutable data store. I’m not storing state in them. I just need the owner within the PostEditChangeOwner (or a new function), just to do the equivilent of “hey loot subsystem, generate some loot for this object path(owner), using these parameters(from the user data)”
The loot subsystem stores those results, not the user data or owning component.
Components really shouldn’t have asset user data, I wasn’t aware that someone added that array to them TBH. The API for asset user data isn’t a good fit for things that are instanced like components, they don’t have the lifecycle events you’re expecting
Well it looks like they’ve been there for ages anyways, so /shrug
PostInitProperties() on the component calls PostEditChangeOwner, so you should be able to use GetOuter() in your impl of PostEditChangeOwner to get the owning component in the same way I’d suggested for an asset.
Ah, I didn’t try GetOuter. I had tried GetOwner and it was not defined. Silly me.
Thanks!
In light of that potential pathway to hooking in to the game feature system without a costly component scan, do you think it might be reasonable if game features could be defined that ran as a result of such a callback?
@Michael_Noland I know I’m a bit late to the party but I had a simple question - are there any plans to allow for better filtering of the content browser folders for gameplay features? Right now if I check “Show plugins” I get the game features and a zillion other engine plugins. Would it be possible to add a “Show Game Features” option there that will only show the game feature plugins?
Engine plugins are controlled by the “Show Engine Content” flag, so you can turn those off, and if you have some project specific plugins showing up that’ll never have content, you can edit their .uplugin to have “CanContainContent”: false
The idea to have an additional ‘show only the game feature plugins’ option is interesting though, but at that point probably those settings need to be an enum or something instead of a bunch of bools, and feature plugins are also basically invisible at the engine level, they’re done in a plugin as well (though hard-coding the GameFeatures prefix path wouldn’t feel too bad).
I’m not sure of the feasibility of this but could the top level Game Features plugin register an additional setting into the content browser visibility menu? Or perhaps a generic “Show only plugins in path X” filter?
I usually have Engine Content turned on to get access to some stuff like the default shape meshes or material functions from the engine content folder. Would it at least be possible to separate out “Show Engine Content” from “Shown Engine Plugins”?