Moving custom scene graph component code breaks subtype(component) references silently

Summary

[TLDR: moving code to another module makes the moved component disappear on every entity or entity prefab that was using it. This makes moving code an absolute nigthmare that breaks everything. How can i prevent this. I am constantly needing to move code. Coding everything in one giant module seems to prevent the problem but is no viable option. What is the solution to relocating code breaking everything without a trace?]

The way verse is structured in modules and how modules are either created in verse or are folders from the content browser in the editor and designing a proper access structure with those modules is quite challanging. I often find myself needing to move scenegraph component code to a different module, which breaks all existing prefabs using that code. This causes great pain as i have to remember and manually check which entity prefab is now broken because moving component code makes the component just disappear in the prefab. This constantly breaks my game and needs pushed changes and takes a lot of time. Constantly.

So i tried to come up with a way to automate an error prevention with the tools im given. So i created a “requires” component that should contain every component type the owning prefab uses and look for it. If that component is not there because it is missing, it should trigger an error. This does not do the trick though. See steps to reproduce.

The relocation of code also impacts the array referencing the component type. Meaning the checking for the relocated component is broken itself after the relocation. It actually would have worked, if there were any form of validation check for the array in the requires component checking for broken references, because the VERSE_DEAD_… does name the component that was at that array entry. That would easily allow me to just go through all the errors and reapply the components named in the broken reference. But it does not raise any error, it just disconnects the session on a time out error.

SO: with my requires component, i gained the ability to backtrace what components disappeared after moving them, because the type array still names the missing reference types, but since no error is raised, i still need to remember manually find every single entity that has a requires component and check their entries for validity. So i am gaining nearly nothing.

I think that relocating code is a constant need. But if all scene graph, entity prefabs and component references are completely broken after relocating code, it is extremely frustrating for me to develop in UEFN.

Please select what you are reporting on:

Unreal Editor for Fortnite

What Type of Bug are you experiencing?

Stability

Steps to Reproduce

  • Create a component like the example below (requires)
  • Create a new test component test_component:=class<final_super>(component){}
  • Put that requires on an entity prefab and assign test_component in the array and save the prefab
  • Move the code of test_component to a different module and compile
  • This causes a “VERSE_DEAD_{missing_component}…” reference set in the array instead of the test_component.
  • This is not raised as an error in any validation check. When you compile, push and launch session, while the broken prefab is in the scene trying to execute its OnBeginSimulation(), the session will not leave the “connecting…” screen and end up with a time out error sending you back in the lobby

requires:=class<final_super>(component){
@editable
ObjectName:string
@editable
RequiredComponents:subtype(component)

OnBeginSimulation<override>():void={
    (super:)OnBeginSimulation()
    for(Index->Comp:RequiredComponents):
        if(not Entity.FindDescendantEntitiesWithComponent(Comp).First[]):#returns first found component of the generator
            Err("Entity: {ObjectName} has a required component missing at index {Index}")
}

}

Expected Result

  • Some error message during validation that there is a dead verse reference that needs to be corrected because you moved code

Observed Result

See steps to reproduce

Platform(s)

PC

@Jimbohalo10 maybe this is helpful to you in any way

hi @HootyTooty ,

Voted it up. As an Indie Developer it looks good, but whether Epic decide to add this to UEFN validation is a long process.

We cannot add any Verse plugin essentially its closed to non-official extensions

I guess the core message im trying to send is:

If there was any trace of a component that is missing because the code moved just like the VERSE_DEAD_… error has the missing components name, and an error message triggering when this happens. I have everything i need to quickly fix the missing components. No problem there and minimum work.

But the fact that the missing component just disappears and triggers no error at all has me going through every single entity and check if it is broken or not. That is sustainable at all.

I made a “required” component that uses a hardcoded array of required components and their required amount. Due do it being hardcoded, every single entity need their own sub implementation, but it an entity prefab driven approach it is somewhat managable, and the hardcoded nature makes relocated code throw an error if the “required” component cannot find the relocated components anymore. The name is there to identitfy the entity that is incorrectly setup.

How to use:

  • create a subclass of sgc_required for your specific enitity. (here: my_entity)
  • fill the array with required component subclasses and their amount
  • attatch the component to its entity/ prefab

What this achieves:

  • if you setup the requires component incorrectly, it will trigger errors so long until you have the current structure of your entity documented correctly. E.g a message like this could appear “Entity: {My_Entity} has {2} of {1} required components at index {0}” meaning: you set only 1 required amount in the tuple array but there are actually 2 of this component on your entity. So if that is the desired case, you set the required amount to 2 or correct the existing components.
    -After this your setup is working.
    -If you now move code it will first trigger a compilation error because the requires component most likely cannot find your moved code on its own. So you know that there will be an issue. After fixing your compilation error to the relocated component, the prefab entity will be broken because the relocated components will be deleted silently from your entity. But since you implemented the requires component for your important entity prefabs, it will now tell you what component is missing and how many of them used to be there on the entity prefab with the given name.
  • it is not perfect as you still need to figure out how to repair your entity component setup, but this makes it 100000 times more easy to fix missing component problems cause by relocating code.
  • And if the error triggers when you did not move code, you most likely changed your prefab’s component stucture and need to update the requires component implementation. This can be a bit extra work, but very much worth the error checking functionality that comes with it in my opinion.

sgc_requires :=class<final_super><abstract>(component){
    @editable
    ObjectName:string

    @editable
    RequiredComponents:[]tuple(subtype(component),int)


    OnBeginSimulation<override>():void={
        (super:)OnBeginSimulation()
        for(Index->Comp:RequiredComponents):
            if(CompAmount:=Entity.FindDescendantEntitiesWithComponent(Comp(0)).Length(), not CompAmount=Comp(1)):
                Err("Entity: {ObjectName} has {CompAmount} of {Comp(1)} required components at index {Index}")
    }
}


sgc_requires_my_entity:=class(sgc_requires){

    @editable
    ObjectName<override>:string="My Entity"

    @editable #array of specific components required for this entity
    RequiredComponents<override>:[]tuple(subtype(component),int)=array{
        (sgc_requires_my_entity,1)
        #...
    }
}


(Generator:generator(t) where t:type).Length()<reads>:int=
        for (Item : Generator) { Item }.Length

To make this work with deeper entity prefab hierarchy structures.
EITHER:
use a single requires component on the deepest entity prefab documenting the entire structure. If you use a mixed approach, it might happen that a parent prefab finds components of the children and falsely triggers improper setup errors.
OR:
use one requires component per inherited prefab and only document the added components. This allows to follow the prefab abstraction workflow with your requires component, checking each prefab at its inheritance level.

I just thought about the case where a child prefab overrides a component with a subtype. Then this should not be documented in the child prefab because the parent will look for the overidden component. This is an edge case that needs to be considered when using this workflow. So simply adding all changes per entity hirarchy level only works for added not overridden components.

Yet i just thought about another issue where the rquired amount might be triggering an error falsely because a child prefab could add another component of the same type. This is due to the FindDescendants.. function. Checking requirement for only the owning entity via getcomponent seems not viable since it requires an implementation per entity.

Therefore i guess you can only have one requires component on leaf nodes in the entity prefab hierarchy, preventing the use of prefab hierarchy abstraction. This is a rather big impact on benefits of this workflow…

I think i found a better way to tackle the issue of relocating code:

  • I know when i am about to relocate code
  • I dont know what entities and prefabs use the code i want to move
  • so i temporarily add code to the component i am about to move to trigger an invalidation error for every entity using that component. Something like this
    @editable
    Invalitation:concrete_subtype(entity)
  • Then, after pushing changes, the message log will show all the invalid entities using the component.
  • Then i write down every entity and location for every invalid component and remove it.
  • After that, i have a list of entities and locations where the new relocated component must be added
  • Then i relocate the component
  • Then i add the moved component back to all entities according to the list.

This way i can track what needs fixing before relocating code and have a somewhat robust way of reapplying the component to all the errors.

1 Like

FORT-1104589 has been ‘Backlogged’. This is an issue that is in a queue to be addressed.