More flexible approach of Asset and Scene Managing, or "If the Scene was a Resource"

What are you thinking about Game World approach where scene it is only small bunch of GameObjects that can be stored separately as a resource and can be loaded and unloaded in any time?

Unity already has something like this but:

  • Scene is NOT a resource! It cannot be simply unloaded from Game World that has may already loaded scenes.
  • We can not have a reference to the scene through which we can load, unload or check is scene loaded.
  • We can not have a Bundle that has many scenes in it ant some sort of root Bundle resource that references to each of it.
  • Light Mapping and Oclussion Culling data do not work for miltiple loaded scenes and we can’t manipulate it.

So my idea:

Asset Referece (AssetRef)
AssetRef type can store link to any asset in project and has abbility to load it, has info is asset loaded…
Unlike hard link i.e., public Texture2D myTexture, AssetRef only store some assetID and asset do not automatically loaded with the scene ( can be loaded if one script has hard link to it, and another AssetRef ).
AssetID can be key of global dictionary of all loaded assets; when AssetBundle was loaded all it asses will adds to global dictionary and thereafter become available for AssetRefs.

API of AssetRef can be like this:

class AssetRef<TAsset>
{
    Int32        privateInternalID;
    TAsset    Asset        { [internal call] } }  //null if not loaded or unloaded
    Boolean    IsLoaded        { [internal call] } }
    TAsset    Load            ( ) { [internalcall] }  //if an asset belongs to another bundle and bundle was not loaded before - throws exception. Do nothing if asset already loaded
    void        LoadAsync    ( ) { [internalcall] } //start loading, also throws exception
    TAsset    LoadIntoGameWorld        ( ) { [internalcall] }  //Avaliable for prefabs. Loads Prefab Into GameWorld so we do not need to instantiate it and [B]Unlike[/B] Load( ) have only one instance of it exactly in scene (no prototype in memory). Calling this function will always result in populating one more object in scene, either from the prototype (if such exists), or from disk.
    void        LoadIntoGameWorldAsync    ( ) { [internalcall] } //will load prefab into scene in any case except AssetNotFinded Exception
    Single    LoadProgress             { [internal call] }    //Can be used only if LoadAsync was called, otherwise returns 0 or 1.
    event        AssetLoaded Loaded       { add{ [internalcall] } remove{ [internalcall] } }; // event that raise when asset will be loaded.
}

Unity can provide predefined AssetRefs for standart assets:

  • Mesh → AssetRef → MeshRef
  • Texture2D → AssetRef → Texture2DRef
  • AnimationClip → AssetRef → AnimationClipRef
  • TextAsset → AssetRef → TextAssetRef
  • Material → AssetRef → MaterialRef
  • Font → AssetRef → FontRef
  • GameObject → AssetRef → PrefabRef //Prefabs can be referenced and loaded on demand, and then instantiated
  • …

AssetRef - actually means weak reference to Prefab, root GameObject of with contains CustomScript component.

You can use AssetRef like this:

class BigBossRoomManager: Monobehaviour
{
    public    PrefabRef[]    BigBosses;
    public    IEnumerator   SpawnBigBoss ( )  { yield return BigBosses[someCalculatedIndex].LoadIntoGameWorldAsync ( );  }
}

BigBosses is array of few BigBoss Prefabs each 10 - 100+ MB of resources and you want to spawn only one of them (based on some logic) and only when player goes near BigBoss room. LoadIntoGameWorldAsync used because we do not need to have one more instance in memory i.e. prefab prototype.

How GameWorld will be constructed

  • Unity GameWorld consists of Scenes and on game start it is Empty! No render settings data, light mapping, input manager settings… Just EMPTY
  • All GameWorld information stored in Components that belongs to GameObjects
  • Scene is Asset. So one more asset type Scene → AssetRef → SceneRef.
  • Any scene has only one root GameObject in witch it holds scene specific components, e.g., Scene, LightmapSettings, NavMeshSettings, RenderSettings, SceneSettings, InputManagerSettings. Some of it may be absent, e.g., RenderSettings - because of some render settings was loaded already and we do not want to change it. All other GameObjects lie under Scene root. Scene is a component that describes scene ( name, description… ) and has ad last one important api: Boolean AutoAwake; and void Awake( ) - that can be used for deferred loading Scene into GameWorld after loading into memory. Also it can manipulate how other scene specific components will behaviour after loading the scene and in runtime.
  • API Application.LoadScene/LoadSceneAdditive, DoNotDestoryOnLoad… is obsolete. Welkome SceneRef. Project has the only SceneRef to starting scene that will be loaded at game start, just how it has but not the first scene in build settings, and the reference to scene asset.
    To be able to load next scene you must have SceneRef to it and call Load(), LoadAsync(), LoadIntoGameWorld(), LoadIntoGameWorldAsync().
    For unloading scene just call Destroy( sceneObj.gameObject ); or if UT implement just Destroy( sceneObj );
    Calling SceneRef.Load/LoadAsync() will load scene but not awake it!
    Calling SceneRef.LoadIntoGameWorld/Async() will load scene and awake it if sceneObj.AutoAwake is true; Scene Transform can be modified between scene loaded into memory and scene awake (in that modification Static Object will be moved accordingly).
    GameWorld has reference to all scenes loaded into it, All Scenes loads only into root of GameWorld so any game world root is Scene (not sure that this constrain is needed).
  • So after all this Scenes look like any other Prefab that supports Nesting (which coming) just with specific components in it root GameObject. So even internally it can be implemented like Prefab.

Also will be great to have ComponentRef where TComponent: MonoIDBehaviour…
MonoIDBehaviour is component that has unique ID and on Awake store itself in global dictionary of scene objects.
So we can reference Components cross scene. ComponentRefObj.Component will be available when Scene with that component was loaded and Awaked :slight_smile:

For Endless Worlds Unity can provide API for moveing scenes e.g. GameWorld.MoveCenterOfWorld( Scene scene );, this call can move transforms of all GameWorld roots, so specified scene become in center of the world (need to move static objects, may be change something in collisions, physics, particle systems…, and procide Callback GameWorldCenter moved for side systems e.g. Bullet Physics).
After that manipulation (that can be huge) all global positions of Objects will be set relative to specified scene and Float precision do not affect logic in objects of this scene :slight_smile:

Pros.:

  • Scenes becomes assets, so it can simply be loaded and we always have reference to it root object. (No need workaround or hardcode for searching just loaded scene)
  • No more hardcode like Application.LoadScene( “Literal” ) or Resource.Load(“Literal”), scenes and assets can be easily renamed or moved in project and nothing will be broken.
  • One AssetBundle can has many scenes, prefabs and any other assets in it, and root asset can have references to each of them. So we can load only root asset and know which assets we just loaded dynamically, e.g. what new scenes we can go to :slight_smile: without actually loading any asset except root.
  • We can create something like enemy database that can store all enemies of game and load and spawn part of them by some logic without memory overhead.
  • Scenes can be implemented just lake Prefabs with Nesting support. Less code base, less bugs, more flexibility, more simplicity, easier to understand how it works.
  • Support for Lightmaps and Oclussion Culling for additively loaded scenes
  • transform.root will always reference on root Scene Object where is scene component, and maybe custom game specific component that responsible for scene logic.

Cons.:

  • Can’t see any of them. May be some body else can see?

If I’am not the only who want such scene and asset management in Unity than maybe we can see it in Unity 5.0 :slight_smile:

It will be great if Unity System Architect says what he thinking about this.

Any Suggestions? Thoughts?
Do you want to have such a system?

feedback link: http://feedback.unity3d.com/unity/all-categories/1/hot/active/more-flexible-approach-of-asset-

I’m a little confused as to what you can’t do now (beyond the lightmaps issue). I can see several different ways that you could make your own weak reference system but the core principles would be:

  • The asset handle would probably need to be strings. I’m not a fan of string literals but there’s no real way to get away from them with loose object coupling in a user friendly manner.
  • Any object that wants to support a weak reference system would have a call into the reference tracker in their awake and another in the OnDestroy.
  • All objects would need to live in the Resources folder so that they’re not stripped from the build (or in their own unique scene).
  • Create empty gameobjects that act as containers, you’re free to move these containers around and destroy them. You’ll need to be diligent that all instantiated objects go under the correct parent container, but it’s not too hard.

It can be automated and Yes your are right asset references can be done and I have done it already. But creating it do not looks nice and not everyone scripter can do it.

This feature I have done year ago but it also do not nice because dublication object and load sone scene twice can break all scene.
and again don’t everyone scripter can implement it.

I do not want to load all assets into scene manually or load all woth forst scene. Its absolutely unacceptable.
But it can be done with asset bundles and lot of work. And again don’t everyone scripter can implement it.

Scenes has may static object that do not move after loading, so this can not be implemented at all.

I wrote this post not because all this can not be done in Unity (part of it can not), but because most of users don’t have such features and can not implement it for himself, because of lack of time or experience.

And Unity will be more flaxable from the box if AssetReferences will be implemented as part of Engine and Scenes cease to be a specific Asset.

AssetRef seems like a good idea to me.

Also i think the concept of move scene at load time in this thread make ssense. I believe it would be beneficial to add more parameters to scene load functions, which for example let you offset all objects at load time.

ComponentRef is the same as just having direct references, so not much use in that.

2 Likes

I have implement cross scene component references for games.
So when I load some game Scene I can check is that specific component is loaded with some another scene and if it is use it.

It is useful when I have big world and some locked door is placed in one Scene but control panel that unlock it in another. With cross scene references control panel can reference Door directly and this will work easily when both scenes loaded.

ComponentRef is that idea proposed to be out of the box for Unity :slight_smile:

only thing you have to be careful of is dangling references. When you create those references, those objects won’t get cleaned up and could result in memory leaks if not properly managed.

I saw the video about multi scene editing and I wanted to ask for exactly that. But in that case, you would need to have those offsets in editor, too.
I tried several things and came to the conclusion that positions are stored relatively to the parent, so having things far away isn’t a problem when they are in a movable parent, at least ingame. But in editor, the position of the additively loadable scene would be too far away for precise movements.

My solution is to register these object in global dictionary on Awake and unregister OnDestroy and my ComponentRef is just key to that global dictionary and it access target through it.

So ComponentRef.Value can in any time become null or have real value.

You might want to look into the WeakReference class as it allows you to keep track of the object without actually referencing it.

WeakReference does not help there.
I need to have reference even if object was never existed and once it born my reference refer to it and when it die my reference become null :slight_smile:

And additionally it must be saved into scene and editor workflow with it must be the same as with normal references. The only thing that differ is that we need to load two scenes into GameWorld to link objects cross scene.

Now I have my own solution for loading and unloading scenes, and multi scene editing, soon we will see built in one