Better support for prefab-like interaction
Is your feature request related to a problem? Please describe.
When working with complex assets such as avatars, worlds, etc, often one has to make changes outside of Resonite. Once these changes have been made, re-importing and transferring any Resonite-specific modifications, such as dynamic bones, scripting, etc, can be an incredibly laborious task. Other dedicated editors, as they are able to interact with the filesystem, solve this problem by detecting changes to the files on disk, and keep the concept of the "original" data separate from changes layered on top in the scene heirarchy. Resonite does not have the luxury of this kind of filesystem interaction, but I believe it can still implement the end result of clean re-importing.
Describe the solution you'd like
I believe Resonite could implement this through a mechanism of, given two slot hierarchies, having a feature in which the user is able to transfer one hierarchy "over" the other. If we transfer hierarchy B over hierarchy A, then slots and components in A that are not present in B should be preserved, but any matching slot transforms/components should be overridden by B. This may be imperfect, but I believe it to be a path of lest resistance to implement, and would greatly improve user experience.
Some challenges brought about by this approach:
- Any solution to this would have to treat complex fields such as blend shapes, rig data, etc with a "by name" approach
- Components are not necessarily unique, a strategy for merging them safely would likely be somewhat complex, but could use some heuristics, such as sharing references to the "same" slot, same/similar values or order, etc. I believe this to be the weakest area of this approach
- Could help to introduce some internal data as "this component came from a file" vs allowing fully free form merge, or even have it be part of the file import prompts for scene/mesh/avatar data
Describe alternatives you've considered
There's likely many possible approaches with their own pros and cons, but another approach I've considered would be as follows:
Introduce a typed "Prefab" component that takes a file url, whatever other type-specific inputs are necessary. When this component is spawned, data changes, etc, it will populate the hierarchy of the slot it is attached to with imported data. We additionally introduce a read-only "from prefab" field to slots/components. This field, when true, acts as a pseudo-non-persistent type behavior, which is to say no direct changes to "from prefab" slots and components is persisted on save, HOWEVER, new components or children slots added to "from prefab" slots, drives from these to prefab elements, etc, ARE persisted as part of the prefab component's internal data, and re-attached when it is once again spawned or a re-import is triggered from updates to its data. When this prefab component is destroyed, it should unlink itself from its associated "from prefab" items, making them "real"
Additional Context
zangooseoo
During mesh importation, assets are converted into Resonite native formats- as such, I do not believe it would be easy to set things up such that if an external file is detected, those modifications are instantly made visible in-engine. We'd effectively have to have a mechanism to read, detect, and dynamically re-import the modified asset file on the filesystem- and I'm uncertain if that is something we could (or would even want to do).
Based on the solution you've described as wanting above though- it sounds to me like a generalized prefab system should meet your needs? For that #417 has more activity, and has been previously referenced by Frooxius.
I do not believe it would be easy to set things up such that if an external file is detected, those modifications are instantly made visible in-engine
I don't think there's any expectation that it'd be tied to a local file, I was speaking from my frame of reference of using other more traditional game engines, but it might make sense to have some form of interaction with in-game raw file assets. Ex, given some "prefab" context in the inspector, you could drop a raw file onto it and have changes propagate over what was previously there (while preserving additions/overrides/etc such as dynamic bones or material changes), or similar behavior with the idea of merging existing, instanced slot hierarchies together.
Looking at #417, I agree with their assessment that this ticket was more focused on the idea of updating an existing asset (ex avatars) than instancing objects and iterating on a world, however I personally believe a good prefab system would address both needs. I'm not sure I fundamentally see a difference in what is being asked for as much as how the request is being framed.
I'm not opposed to merging requests, especially as it seems to be a recurring ask, as long as the needs of these various versions of this request are being documented and considered.
Seeking input from @Frooxius if there are any aspects of this issue that make it sufficiently distinct to stand on its own compared to similar issues like #417.
I don't fully understand what this would bring over just having a proper Prefab support.
Having heuristics that can merge two arbitrary hierarchies is something that can explode in complexity very quickly, because there's a lot of ambiguity - how do you determine if two components are meant to be the same component? However you set it up, it's going to lead to weird behaviors - if you change enough stuff on one component, suddenly merging it actually splits it in two and breaks things - how do you deal with the component having dependencies? Or trying to drive something?
What if you add a new component and remove old one, but they have enough shared info that the system thinks they should be merged, even though they can't? How do you determine which of the fields win? Components can do arbitrarily complex things - how do you determine which field of which component is the "correct" one to be passed into the merged state - especially when you don't even know what these fields do? You'd either have to do "winner takes all" and just pick one or the other (which can have its own cascading effects if there are other components that depend on the specifics of one of them and the system ends up picking the other one) or try to get some hybrid state, which might just end up being garbage.
These kinds of things become unmanageable very quickly, especially if you want to do it for absolutely arbitrary hierarchies and end up big time sinks, as you try to patch up all the wrong and undesired behaviors, with more and more popping up.
Having a more structured system like Prefabs makes these things a lot more "sane", because it provides the supporting framework for determining what changed and what didn't.
I don't fully understand what this would bring over just having a proper Prefab support.
The functionality I and many other users are used to coming from engines like unity are that if I simply copy a file over another, ex when I make an update to my avatar, it will simply re-import while doing its best effort to preserve any changes I've made. That was the main use case that motivated me to making this ticket, and something that is still a major pain point for updating my avatars, maps, etc in Resonite.
If I ever update my avatar, such as making adjustments to weight painting, adding new bones or blend shapes, there is a potentially large amount of work I have to do to update it in-game, including transferring any systems, menus, or other additional content. The same problems are true for worlds I make, where I will typically make the world or portion of world in blender, with the intent of uploading both to Resonite and VRChat.
I personally try to design both assets and in-game content to minimize the amount of work I have to do in these cases, but it's still significantly more than what I have to do when updating VRC versions of my content, and I assume most content is not made with Resonite's limitations in mind.
What if you add a new component and remove old one, but they have enough shared info that the system thinks they should be merged, even though they can't?
Other platforms like Unity track this, and removal of components from an instanced prefab is non-destructive. Merging of slots without prefab context is not a requirement (though it'd be nice if possible), but simply a possible solution. I already cover the limitations of that approach and alternatives in the original post of this ticket, and as the team has many times requested, I'm not trying to prescribe a specific solution.
"proper Prefab support" should still cover the need of easing the merging of asset changes made offline, as well as updating live instances (as is seemingly the focus of #417), regardless of how this is approached.
I see. That actually makes this a fair bit different. If this is scoped to updating existing hierarchy from a re-imported file, that's something that can be implemented and that's manageable.
My main issue is that the original description was very general, taking any two hierarchies and transferring them over to another. Making this work with an arbitrary hierarchy puts this into the realm of complexity explosion, but if it's more narrowly scoped, then we could implement this for that purpose.
This makes it more in line with things like the rig transfer tool.
If I ever update my avatar, such as making adjustments to weight painting, adding new bones or blend shapes, there is a potentially large amount of work I have to do to update it in-game, including transferring any systems, menus, or other additional content. The same problems are true for worlds I make, where I will typically make the world or portion of world in blender, with the intent of uploading both to Resonite and VRChat.
Actually, there is a tool for this! The Rig Mesh Transfer Tool. It has some bugs (see #332), but it's pretty much intended for this use-case. If there is something it currently doesn't cover, I'd suggest that as an addition to that tool.
Resonite as a development environment is unique in a number of ways. Some techniques from other engines map well, but some workflows might not transfer 1:1. But when you talk about change tracking and potentially merging, that does more broadly sound more like version control to me, and version control for prefabs (once those are supported) is planned!
See #1212 for that:
Once Prefab system is introduced, it will need a way to update the instances of the Prefab and determine when update is okay to happen (e.g. when non-breaking changes happen) and when not (e.g. when new major version of the prefab is released)
As for avatars in particular, I think improving the existing tools would already help for much faster and more dynamic workflows. If that's your main concern, I do suggest upvoting the issue about improving the Rig Mesh Transfer Tool, if it would work it would remove a massive friction point in regards to avatar creation.
My main issue is that the original description was very general, taking any two hierarchies and transferring them over to another.
The original request was made without any context or dependence on an existing prefab system, and proposes the idea of a prefab component as an alternate solution. Resolving the workflow friction is what's most important, regardless of the approach taken.
The Rig Mesh Transfer Tool
I am quite well acquainted with this tool and it's quite frankly not useful. This is likely better suited to discussion in more focused ticket(s) for that tool, but it frequently just fails to work and gives little to no feedback as to why. It has basically no interface and does not work in an intuitive way. It's also not suited to the case of updating worlds/world assets that are not rigged. Also, there's cases that're more advanced that it won't handle, ex addition or removal of meshes, or sufficiently "different" changes to the rig.
version control for prefabs (once those are supported) is planned!
nice :D
@gentlecolts I'd like to reiterate, what you seem to be asking for is essentially a more generalized version of rig transfer tool - not only this tool needs to transfer rig, but also other components.
This is essentially what we'd do - expand and rework that tooling, so it can handle more things. We can do things to improve the robustness of it and make it easier to use.
If it's focused on imports, we can instrument the imported data with some things to make it a bit easier. But it also might be easier to just unify this with the prefab system - we turn anything that's imported into a prefab and then you have instances of it. That will make updating that import easier.
I'm not 100 % sure on which way to go with this yet, that's something I'd need to think about some more.
but it frequently just fails to work and gives little to no feedback as to why
Please do take a look at #332. Arti and myself put a bunch of work into doing a deep-dive into exactly how it fails, and what use-cases it doesn't currently suit very well. We came to the conclusion that it's actually like, 90% of the way there, just unfortunately the missing 10% make it unapplicable for the vast majority of use-cases it would be perfect for. When that tool gets fixed / improved avatar work probably gets a magnitude easier. If you find your issues with the tool in there, make sure to give it a thumbs up.