Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Leslie-Young · Apr 25, 2013 at 05:56 PM · gameobjectprefab

Is there a way to tell when a prefab is duplicated?

I have created a component which generates a GUID which allows me to know what prefab a GameObject instance came from, but when a prefab is duplicated the new prefab simply use the same id as the previous one (which is to be expected). So I would like to know if there is a way to detect when prefabs and objects in general are duplicated so that I can generate a new id.

 public class GUID : MonoBehaviour 
 {
     public string idString = System.Guid.NewGuid().ToString("N");
 
     private System.Guid _id;
     public System.Guid ID
     {
         get 
         {
             if (_id == System.Guid.Empty && !string.IsNullOrEmpty(idString))
             {
                 _id = new System.Guid(idString);
             }
             return _id;
         }
     }
 }
 
 [CustomEditor(typeof(GUID))]
 public class GUIDInspector : Editor 
 {
     public override void OnInspectorGUI()
     {
         GUID guid = target as GUID;
         GUILayout.Label("ID: " + guid.ID.ToString("N"));
         GUILayout.Label("ST: " + guid.idString);
     }
 }

Some more info on why I need this. This will be part of a system where I need to keep a player inventory/bag and know what prefab to spawn if he drops something form the bag. When a player pick up an item I simply save the GUID to the list of items in the bag while I remove the original GameObject from the world. I have a GameObject in the scene which carry a reference to all the item prefabs so that I can simply use that to find the prefab I want to instantiate. Later I need to expand on this idea to also work for a game save/load system and will have to generate unique IDs for objects in the scene too.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Univerb Gaming · Apr 26, 2013 at 09:35 AM

Every prefab copied somewhere is bound to either have a different name, time stamp or time stamped meta file produced by unity.

Is it not possible to combine your GUID along with an md5 hash of prefab name + time stamp information extracted from the prefab, meta file or perhaps both and use this as your new identifier?

Thinking about this, filename and path MD5'd should work too.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Apr 26, 2013 at 10:01 AM 0
Share

timestamp is not very reliable especially when transferred via a versioning system or simply copied to another PC. The filename (including the assetpath) would work, but it will glue the asset to this path. Also the main problem was when do you change this information? If it's stored in a string on the prefab it will be cloned when the prefab is duplicated. At runtime you don't have the asset information, so it need to be set at edit time.

avatar image Leslie-Young · Apr 26, 2013 at 10:59 AM 0
Share

I've used this idea to do something like this. The "objectId" is something I'm still playing around with and will be needed for a save/load system later. This code seems to be working pretty well for the rpefabs and the id will only change if the prefab is renamed.

 public class GUID : $$anonymous$$onoBehaviour 
 {
     public string prefabId;
     public string objectId;
 }
 
 [CustomEditor(typeof(GUID))]
 public class GUIDInspector : Editor 
 {
     public void OnEnable()
     {
         CheckPrefabId(target);
         CheckObjectId(target);
     }
 
     public static void CheckPrefabId(Object target)
     {
         // apply only to prefabs and prefab intance
         PrefabType t = PrefabUtility.GetPrefabType(target);
         if (t == PrefabType.Prefab || t == PrefabType.PrefabInstance || t == PrefabType.$$anonymous$$odelPrefab || t == PrefabType.$$anonymous$$odelPrefabInstance)
         {
             GUID guid = target as GUID;
             Object parent = PrefabUtility.GetPrefabParent(target);
             string id = AssetDatabase.GetAssetPath(parent ? parent : target);
             id = UniRPGUtil.Get$$anonymous$$d5Hash(id);
             if (string.IsNullOrEmpty(guid.prefabId) || !id.Equals(guid.prefabId))
             {
                 guid.prefabId = id;
                 EditorUtility.SetDirty(target);
             }
         }
     }
 
     public static void CheckObjectId(Object target)
     {
         // do not apply to prefabs
         PrefabType t = PrefabUtility.GetPrefabType(target);
         if (t == PrefabType.None || t == PrefabType.PrefabInstance || t == PrefabType.$$anonymous$$odelPrefabInstance)
         {
             GUID guid = target as GUID;
             string id = guid.name + guid.transform.position.ToString("F4");
             id = UniRPGUtil.Get$$anonymous$$d5Hash(id);
             if (string.IsNullOrEmpty(guid.objectId) || !id.Equals(guid.objectId))
             {
                 guid.objectId = id;
                 EditorUtility.SetDirty(target);
             }
         }
     }
 
     public override void OnInspectorGUI()
     {
         GUID guid = target as GUID;
         GUILayout.Label("Prefab ID: " + guid.prefabId);
         GUILayout.Label("Object ID: " + guid.objectId);
     }
 }

For the thing I'm doing I'm thinking I can have some global setup thing running which does a final sanity check on the prefab and object Ids to make sure they are set and correctly set. It will be a button on an editor window which is part of the bigger picture concerning this whole system.

avatar image
0

Answer by Bunny83 · Apr 26, 2013 at 08:15 AM

If i got your right you just need this at edit time to give each prefab a unique ID. In this case you can try using the "quite new" AssetModificationProcessor.

This works for me:

 //C#
 using UnityEngine;
 using UnityEditor;
 using System.Collections;
 using System.Collections.Generic;
 
 public class DetectDuplicates : AssetModificationProcessor
 {
     public static List<string> newAssets = new List<string>();
     static void OnWillCreateAsset(string aMetaAssetPath)
     {
         string assetPath = aMetaAssetPath.Substring(0,aMetaAssetPath.Length-5);
         newAssets.Add(assetPath);
     }
 }
 
 class DetectDuplicatesPostprocessor : AssetPostprocessor
 {
     static void OnPostprocessAllAssets(string[] importedAssets,string[] deletedAssets,string[] movedAssets,string[] movedFromAssetPaths)
     {
         if (DetectDuplicates.newAssets.Count == 0)
             return;
         foreach (var str in importedAssets)
         {
             if (DetectDuplicates.newAssets.Contains(str))
             {
                 GameObject obj = AssetDatabase.LoadAssetAtPath(str,typeof(GameObject)) as GameObject;
                 if (obj == null)
                     continue;
                 var comp = obj.GetComponent<YourPrefabComponent>();
                 if (comp == null)
                     continue;
                 comp.GenerateNewPrefabID();
             }
         }
         DetectDuplicates.newAssets.Clear();
     }
 }

In my sample the component attached to the prefab is named "YourPrefabComponent" and it has a public function called GenerateNewPrefabID. This Postprocessor will execute this function if the asset it newly created.

How it works:

The AssetModificationProcessor gets informed when Unity will create a new meta file (for a new asset). I just strip the .meta and save the filename as "new asset" in a List.

When the asset is finally created and imported the AssetPostprocessor will take care of "postprocessing" the actual asset if it's in the list.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Leslie-Young · Apr 26, 2013 at 11:05 AM 0
Share

I needa study this and see if I can't come up with a cleaner solution using this and what I've done so far.

avatar image Firestar9114 · Mar 11, 2019 at 07:43 PM 0
Share

O$$anonymous$$G, you are a lifesaver. I spent so long trying to figure this out. Is everything from this guaranteed to be a prefab, or do I still need to do a check with PrefabStageUtility to check if the stage is null in 2018.3?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

15 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Acessing scripts in other game objects with prefabs, without using GameObject.Find 1 Answer

How do I assign a prefab reference to a private variable? 1 Answer

Reinitialize prefab 0 Answers

How to save/load references to components and prefabs 1 Answer

Determine if game object is tyoepf One Prefab 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges