I’m developing a serialization tool on top of Unity. Every time I create an object and want to deserialize data to it, I have to retrieve all components to provide them with sensible data. The soonest I can do this is on Awake and via GetComponents(). However, this isn’t as fast as I would like it to, when components per GO are high or there are too much GOs to deserialize.

Is there a faster way to get every component a GO have? I imagine you cannot cache them at editor (I presume the instances are generated once instantiated… makes sense…), and I don’t see any property on GameObject exposing the Component I need.

Note that I want to retrieve every component on my GameObject just after its instantiation (and wisely, in the same tick) – the objects won’t be residing on the scene at build time, but will be instantiated at some point of the execution

Thanks

Try this:

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class CacheComponents : MonoBehaviour
{
        public List<Component> components;
        public bool cacheNow;
       

        void Awake()
        {
             if(!Application.isPlaying)
                 Cache();
        }

        void Update()
        {
            if(cacheNow)
            {
               cacheNow = false;
               Cache();
            }
        }

        void Cache()
        {
             components = new List<Component>();
             foreach(var component in GetComponents<Component>())
             {
                  if(component != this) components.Add(component);
             }
        }

}

A partial and non so generic solution.

Before build you iterate between all Prefabs and objects in scene, then, attach a script that cache all information that you will need. For version 2, if you don’t want to dirt your objects you should catalog in a unique prefab, but you have a problem to identify wich object it is or for wich prefab (you can add a script with the id… ops, failed again :P).

If you need to interate between prefabas and scenes you can use this. It is a incrible usefull stuff to make dirt scripts and prepare your build.


Edited: Try to explain with code

Lets try, I will explain in code (not compiled :P)

This is your utility class that cache the components names

class ComponentsCache extends MonoBehaviour {
	static function GenareteCache(obj: GameObject) {
		  var gc = obj.GetComponent(ComponentsCache);
		  if (!gc) gc = obj.AddComponent(ComponentsCache);

		  var names: String[] = [c.name for (c in obj.GetComponents())];
		  gc.componentNames = names;
	}

	static function GetComponentNames(obj: GameObject) {
		 // if we have build time cached
		 var gc = obj.GetComponent(ComponentsCache);
		 if (gc) return gc.componentsNames;
		 
		 // if we don't have a cache, like in the editor or in objects created in runtime not derived from prefabs, we use the old fashion
		 return [c.name for (c in obj.GetComponents())];
	}
	
	var componentsNames: String[];
}

This is the code that you run on build time to cache all objects. Generally, for release only.

var ForAll = function() {
	// for all objects generate cache
	for (var obj in GameObject.FindObjectOfType(GameObject)) {
		ComponentsCache.GenerateCache(obj);
	}
}

EditorUtils.ForEachScene(function (sceneName: String) {
	// we are in a scene, execute for all
	ForAll();
	return true;
});

EditorUtils.ForEachPrefab(function (obj: GameObject) {
	// we are in a scene with prefab obj instantiated, execute for all
	ForAll();
	return true;
});

Now when you need at runtime the components names of any object you simple do

components = ComponentsCache.GetComponentNames(anyRuntimeObject)