- Home /
How to check if an object is asset in build runtime (Not in Editor) ?
Ok. This has been asked many times in different formats. I thought I made it work with some kind of implementation. After years of experimenting, I still don't have a perfectly working solution.
I REALLY need to know if an object is a prefab/asset or it's a scene object(or created at runtime) and I need this info in the build runtime. Not in Editor (via UnityEditor namespace).
I am looking for a method similar to these and can be used in build runtime:
UnityEditor.AssetDatabase.Contains()
UnityEditor.PrefabUtility.GetPrefabType() == PrefabType.Prefab
Question: Does anyone have any idea about how to get this kind of information in build runtime?
For those who want to know why I need this: I'm the developer of a 3rd class library which can send a message (a method call) to some scripts (I call them receivers) who belong to the user of my library and I want to exclude the prefabs from receiving that message. The message must be sent only to the scene objects (or objects created at runtime). Since those objects are not part of my library, I can't keep track of instantiations of them.
I wanna fav this page, how do i do that? I've been workin with Unity for the past 3-4 years now, Ive build many things but never actually released anything as of yet. my goal is large, and time consu$$anonymous$$g. There are some details i would like to reference back to.
Thanks.
There is a start shaped button under "up vote" and "down vote" buttons on the left side of the question.
Answer by Xtro · Feb 20, 2019 at 02:48 PM
I have been using this extension method for long time now. Maybe I should I it here as an answer:
public static class TransformExtensions
{
public static bool IsPrefab(this Transform This) => !This.gameObject.scene.IsValid();
}
Answer by FortisVenaliter · Aug 31, 2017 at 09:25 PM
Nope, not possible natively. Once a scene starts, there basically are no prefabs in it. Everything becomes it's own instance with no prefab connection. That information simply isn't needed by the engine at that point.
But... there is one way you might be able to finagle it... As far as I know, the Start() function is never called on prefabs. Only on active scripts on active objects in an active scene. So, you could set a flag in Start() saying it's okay to receive these messages. Unfortunately, that would preclude your messages from being sent to objects that have been inactive since the start of the scene.
I am not talking about prefabs added to the scene manually in the editor. I am talking about the actual prefab objects waiting in the memory just to be instantiated at a random point in time.
Example: Car is a prefab in the project. You have a reference to Car prefab in Street scene. A script in Street scene waits user input then instantiate Car prefab with a new name like PlayerCar or EnemyCar. Until the script instantiated PlayerCar and EnemyCar objects using Car prefab, the Car prefab was waiting in the memory doing nothing.
What I want to do in my class library is: Get a list of cars from the programmer. Send a message to the cars in the list by skipping prefabs. So PlayerCar and EnemyCar would receive the message and Car wouldn't.
Since I am developing a 3rd party library, I don't have any control about the scripts attached to car objects and I don't know what's included in the list co$$anonymous$$g from the programmer.
Answer by Bunny83 · Sep 01, 2017 at 01:12 AM
Most what @FortisVenaliter said in his answer is correct. Conceptionally the only difference between a gameobject in the scene and a prefab is that the prefab is not added to any rendering / processing lists. So they don't get any callbacks and are considered as "not part of the scene". Besides that there's no difference between an instance and a prefab. At runtime there is no assetdatabase. It's only required / used by the editor.
The AssetDatabase is just a management tool of the editor that tracks all assets in a project. However in a build Unity only includes used / referenced things.
The only thing you can check is if a GameObject is part of any scene or not. Since the introduction of the new SceneManager every GameObject has a scene property. Note that this property seems to always return a Scene object. You have to check it's IsValid() method to determine is this object belongs to a scene or not.
Note dynamically instantiated objects usually have a negative instance ID. Serialized objects have a positive ID. Dynamically created / instantiated objects do belong to the current loaded scene when you check it's scene property.
GameObject[] allFoundGameObjects = Resources.FindObjectsOfTypeAll (typeof(GameObject)) as GameObject[];
foreach (var item in allFoundGameObjects) {
if (item.hideFlags == HideFlags.None && item.scene.rootCount > 0) {
//we find all GameObjects in hierarchy
}
if (item.hideFlags == HideFlags.None && item.scene.rootCount == 0) {
// we find all prefabs
}
}
IsValid() and negative instance ID thing sounds useful. I'll try those.
Scene.IsValid()
gives inconsistent results, at least in 2018.3 in my testing.
I suspect that Scene.IsValid may return true when in prefab edit mode. But even if that's the case, my reason of using it as a prefab check is for runtime only and in the runtime, prefab edit mode is not a valid case.
$$anonymous$$aybe I should test it on 2018.3 properly.
Thank you for your comment.
Answer by Firestar9114 · Feb 20, 2019 at 10:52 AM
So this seems to do the trick in 2018.3: PrefabStageUtility.GetPrefabStage()
unfortunately, it is listed as experimental and subject to change... https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage.html You can then use this to update a boolean in editor-scripting prior to runtime, and check that bool safely at runtime.
Uhm, the namespace is UnityEditor.Experimental.Scene$$anonymous$$anagement
. So it's still just an editor class which can't be used at runtime. Note that when you test inside the editor, the editor functionality is available. However when you build your game you will get errors.
Yes, but you can set a boolean in the editor prior to run-time, which can be safely checked at run-time. I forgot to mention this initially and updated my original comment.
Well, the question was specifically to test if an object reference is a prefab or an instance at runtime. The PrefabUtility exists for along time which could already be used at edit time. The OP has actually mentioned it in the question. However this is also an editor class.
Setting a boolean doesn't help much. If you store that boolean on the prefab itself it would be true in instances as well after calling Instantiate. You would need to store that information in a central place. However in this case you can simply manually manage your prefabs by dragging them into an array.
Actually i never was in need to identify an arbitrary object as prefab since you usually track your prefab references in some way. Also in most cases you track your instances as well.
Your answer
Follow this Question
Related Questions
Can anyone help with creating Prefabs for procedural meshes 1 Answer
cannot load GameObject Prefabs using Resources.Load in Android 0 Answers
Getting Prefab Icon from AssetDatabase 0 Answers
Unity 4 PrefabUtility.InstantiatePrefab problem in OnPostprocessModel 0 Answers
PrefabUtility - Check if Changes have been made to Prefab? 3 Answers