- Home /
Determining which Asset is connected to a GameObject.
I'm trying to write an editor script that sort of exports a Scene. For this it has to find out which asset a GameObject is created from. Is there a way to do this?
To explain a little bit more, let's say I've got a Prefab Assets/environment/barrel.prefab
, I drop this to the Scene so the scene has a GameObject barrel
. Now the script should be run over all GameObjects and if a GameObject is a prefab tell which prefab it is, thus in this example print something like:
barrel: Assets/environment/barrel.prefab
Why do I want this? My designer uses Unity Basic and we're making an iPhone game, for this I regularly have to import about 30 scenes to Unity iPhone. However the importer is so broken that about 10 scenes are messed up and only crashes Unity. Of course I filed several bug reports but this doesn't solve the problem for me. I already spend several days in time to fix scenes again and again to have them broken on next import again. As basically almost all the gameobjects in the scene are prefabs positioned I would think it shouldn't be too hard to make an exporter for this myself. Except I have to map the GameObjects to the assets somehow. I could try to determine it by the name of the GameObject as this normally matches the asset name, but this doesn't sound foolproof. That's why I'm hoping to get an answer here :-)
Answer by Lucas Meijer 1 · Jan 16, 2010 at 01:16 PM
Not sure what kind of assets you refer to, but you say you want to find out in which file a certain material lives that a MeshRenderer component on your GameObject uses, you could do:
Material m = myGameObject.renderer.material;
string AssetDatabase.GetAssetPath();
which will return something like "Assets/MyMaterials/RedSmokingHot.mat"
For GameObject, there's an additional step required. When you drag a prefab into your scene, copies of the gameobjects in the prefab will be created, and stored in the scene. These copies actually "remember" which gameobjects they were created from. Using GetAssetAtPath() on these copies won't give you anything, since these live in a scene. You can use EditorUtility.GetPrefabParent() to get the prefab-gameobject your scene-gameobject was created from. You can then call GetAssetPath() on that gameobject, which should result in something like "Assets/building.prefab"
Not all UnityEngine.Object types have an assetpath. Some live in a scenefile, others are generated at runtime, and are not saved anywhere. Some live in the assets folder in some way. i.e. Material live in .mat files, gameObjects live in .prefab files, etc.
PS For the adventurous, all these .mat and .prefab files are actually just generic containers for UnityEngine.Object's. These files can host more than one UnityEngine.Object, in fact you can do crazy stuff like add a gameobject to a materialfile using AssetDatabase.AddObjectToAsset()
Thanks for your answer but it doesn't work for GameObjects. I'll extend the description to make it clearer what I'm looking for.
Thanks, I extended my answer to explain how to achieve the same for gameobjects. Could you be so kind to post the case#'s of the bugs you logged against the editor crashing for you here? thnx.
Wow, it works! I used GetAssetPath before on all gameobjects in scene but that didn't work, but with the GetPrefabParent I do get results! Thanks, this is a lot better than my hack-around...
Case 312962 is the latest bug submission, have a few earlier case numbers but they are a bit double posts as the submitter app failed to post the project (is there a limit of 100$$anonymous$$B on a submitted zipfile?).
AddObjectToAsset() is very useful. I'm using it to save nested ScriptableObjects and it keeps the objects all nicely bundled in one file. But I have a question: Is there a RemoveObjectFromAsset? Or would I need to rebuild the asset from scratch without the object I want to remove?
Answer by Jessy · Jan 16, 2010 at 11:44 AM
I never got an answer. I don't think so.
Would be an amazing miss in the API. I searched through the editor classes and couldn't really find anything of use but can't believe there isn't something there.
Answer by Jaap Kreijkamp · Jan 18, 2010 at 12:32 AM
It seems it's just not possible at the moment, at least not through a public API function. For now I hacked a solution using the names of the GameObjects (they normally matches the names of the prefabs). For people interested I added the code below. It doesn't export everything, basically only prefabs and their parent gameobjects with their default values. The prefabs are only searched in the directories specified with the paths variable. Code isn't efficient, clearly written or documented, it just does what it needs to do for me.
using UnityEngine; using UnityEditor; using System.Collections; using System.IO;
public class JSimpleExporter { static Hashtable parents = new Hashtable(); static Hashtable prefabs = new Hashtable(); static string[] paths = new string[] { "JaapPrefabs/Environment", "JaapPrefabs/Effects/Environment", "JaapPrefabs/Enemies", "Levels" };
public static Transform FindPrefab(string name) {
Transform result = (Transform)prefabs[name];
if (result == null) {
foreach (string path in paths) {
Object objref = AssetDatabase.LoadAssetAtPath("Assets/" + path + "/" + name + ".prefab", typeof(Transform));
if (objref != null) {
prefabs.Add(name, objref);
result = (Transform) objref;
return result;
}
}
}
return result;
}
private static StreamWriter wrt;
static void Write(string str) {
wrt.WriteLine(str);
}
static string TransformStr(Transform t) {
Vector3 pos = t.position;
Vector3 rot = t.rotation.eulerAngles;
Vector3 scale = t.localScale;
return "" + pos.x + "," + pos.y + "," + pos.z + "," + rot.x + "," + rot.y + "," + rot.z + "," + scale.x + "," + scale.y + "," + scale.z;
}
static string GetPath(Transform t, bool isPrefab) {
if (t == null) return "";
if (parents[t] != null) return (string)parents[t];
string p = GetPath(t.parent, false);
p = p + "/" + t.name;
parents.Add(t, p);
if (!isPrefab) {
Write("#" + p + "," + TransformStr(t));
}
return p;
}
[MenuItem("Ctrl-J/MyExport")]
static void MyExport() {
FileInfo f = new FileInfo("Assets/export.txt");
wrt = f.CreateText();
parents = new Hashtable();
GameObject[] result = Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
foreach (GameObject go in result) {
Transform t = FindPrefab(go.name);
if (t != null) {
string path = GetPath(go.transform, true);
Write("@" + path + "," + AssetDatabase.GetAssetPath(t) + "," + TransformStr(t));
}
}
wrt.Close();
AssetDatabase.ImportAsset("Assets/export.txt");
}
static Transform GetParentChild(string path, out string childName) {
int p = path.LastIndexOf('/');
string p2 = path.Substring(0, p);
childName = path.Substring(p + 1);
GameObject go = GameObject.Find(p2);
if (go != null) {
return go.transform;
}
return null;
}
static string GetParam(ref string path) {
int delim = path.IndexOf(',');
if (delim < 0) {
string result = path;
path = "";
return result;
}
string result2 = path.Substring(0, delim);
path = path.Substring(delim + 1);
return result2;
}
static Vector3 GetVector3(ref string path) {
string p0 = GetParam(ref path);
string p1 = GetParam(ref path);
string p2 = GetParam(ref path);
return new Vector3(float.Parse(p0), float.Parse(p1), float.Parse(p2));
}
[MenuItem("Ctrl-J/MyImport")]
static void MyImport() {
FileInfo f = new FileInfo("Assets/export.txt");
if (f.Exists) {
StreamReader r = f.OpenText();
bool ready = false;
while (!ready) {
string l = r.ReadLine();
if (l == null) {
ready = true;
}
else if (l.StartsWith("#")) {
l = l.Substring(1);
string path = GetParam(ref l);
string name;
Transform parent = GetParentChild(path, out name);
GameObject go = new GameObject(name);
Transform got = go.transform;
got.parent = parent;
got.position = GetVector3(ref l);
got.rotation = Quaternion.Euler(GetVector3(ref l));
Vector3 ls = GetVector3(ref l);
got.localScale = ls;
} else if (l.StartsWith("@")) {
l = l.Substring(1);
string path = GetParam(ref l);
string name;
Transform parent = GetParentChild(path, out name);
string assetPath = GetParam(ref l);
Object objref = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Transform));
Transform t = (Transform) EditorUtility.InstantiatePrefab(objref);
EditorUtility.SetDirty(t);
t.name = name;
t.position = GetVector3(ref l);
t.rotation = Quaternion.Euler(GetVector3(ref l));
t.parent = parent;
Vector3 ls = GetVector3(ref l);
t.localScale = ls;
}
}
r.Close();
} else {
Debug.Log("Can't find 'Assets/export.txt'");
}
}
}