Dynamic properties and UClass woes

Hello.

I am working on a system which requires variable number of properties per component. Due to this requirement we cannot use a fixed UObject/UComponent derived class. One way to solve this problem would be to use arrays, but that would not be a very clean solution and would add some extra effort to make it work with Blueprint system and make it look nice.

Right now, when we load our resource, we parse it, create component, extract properties / fields from our resource, then create custom UClass object and insert our fields as properties into this new UClass object. After that we replace component’s original UClass with our own.

This seems to work, more or less, and I have some follow up questions:

  1. Class field is a private member of UObjectBase, we do some hacking in order to replace it with our own. Any other approach?
  2. We insert our custom UProperty objects into UClass’s PropertyLink and Children lists. Is this correct approach?
  3. Dealing with UProperty offsets. The issue is, as I understand, that property’s offset is an offset from “this”. If that’s the case, why is offset a signed int? This design also forces us to store all propety values inside our component. Right now we just use a fixed size char buffer (say 64k) at the end of component and make sure our property offsets point to that buffer - this seems to work, but it’s a bit of a pain and a serious limitation. One solution would be to request a larger memory block and store properties at the end of that memory block, past the component layout, but that seems like a dangerous approach especially if users start using same approach to store meta data as well. Another solution would be to patch offset to be 64 bit int - in this case property would be able to be outside the component as pointer jump would be valid (with current 32 bit offsets, that’s not the case). Any recommendations? We would like to keep this Plugin side, with no UE core changes (unless this would be a valid pull request change).
  4. How to force editor to update details panel for active actor / component? When we patch properties, the details panel is not updated automatically. You have to click on an actor in order for it to be updated.
  5. Would there be any side effects with this approach (patching the class object per instance) - for example during serialization? We’ve avoided this problem by repatching the class information back, serializing and then restoring new object. But I am wondering if that’s unnecessary.

I very much appreciate any responses, thanks.

If you’re going down this route, I would strongly advise you have your custom classes be a type of Blueprint. Blueprints have all the code to handle the property links, editor code, runtime regeneration, etc. You probably want to look at how AnimBlueprint works, that generates various dynamic properties and subclasses generic blueprints. This will work much better and you can probably use most of your existing code. So I would make a “ResourceBlueprint” class or something and change it so the “compile” step reads out your resource file instead of from the editor graph that normal blueprints use.

If you use the blueprint method it will correctly calculate the class’s size based on the dynamic properties you have in it, so that will all just work as desired and you won’t have to keep your custom buffer. There’s no good reason that offset is a signed int instead of unsigned, but I don’t see how it being signed would affect the design, 31 bits should be enough for any sized object.

If anyone is interested in solution for #4 - I solved this problem by forcing editor to reselect the actor. Something like GEditor->SelectActor(MyActor, true, true);

If anyone is going down this route, make sure you call UObjectBase::SetClass to set your UClass to new object. This will patch the class information as well as unhash the old object and hash the new one (this is very important). You will have to deal with SetClass being private, but there are ways around that. Unfortunately, there’s a good reason for it to be private as this is definitely a dangerous behavior and should not be generally accessible.

Solution for #5 is pretty straight forward - and should work out of the box if you replace the UClass properly. Was not working for me because I did not unhash the old object / hash the new one.

Thank you for your reply! I am afraid that approach is not acceptable for us as we would like to have custom properties on components. Although I know there’s a way to do blue print components (looking at ScriptPlugin).

Right, I was merely curious regarding offset. It makes sense within the scope of current design. My point about 64 bit properties was not about the size of the object, but rather that would allow for “external” properties - since with 64 bit offset it would be able to point anywhere (to an arbitrary location).

Thanks.