Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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
3
Question by HenTeMon · Oct 11, 2014 at 01:25 PM · cloneduplicatefolderdependencies

Can I duplicate folder with internal dependencies between objects?

Hi guys!

I have a folder with some prefabs, materials, textures and etc. Prefabs refers to textures in this folder. Can I clone this folder with saving local dependencies? For example: Folder is named "Assets/BaseFolder". And prefab "Assets/BaseFolder/preFab" refers to "Assets/BaseFolder/texture". I need to Copy "Assets/BaseFolder" to "Assets/CloneFolder", so that "Assets/CloneFolder/preFab" refer to "Assets/CloneFolder/texture".

By default, when I dublicate folder - dependencies refers to the old resources with old paths.

I can do it manually in editor for every object. But I have many objects and many dependencies, and I need to automate this process.

Does anyone have any ideas?

Thanks for any answer, Vlad

Comment
Add comment · Show 1
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 Rosie-Posie · Oct 18, 2014 at 06:59 PM 0
Share

Hey Vlad, im running into the same problem, if you happened to have found a solution, please let me know, i'm pretty desperate!

4 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by dandrea · May 30, 2018 at 03:02 PM

I've just had the same problem. In 22 years of industry, that's the first time I see a program where you duplicate something and the internal dependencies aren't properly redirected to the adequate duplicates.! I considered writing something in Unity for a while, but I ended up deciding for an easier (although not elegant) hack that will do the trick, as long as you're using visible meta files as the version control mode.

I wrote a python script that changes the guids of the assets as well as the internal references in materials and prefabs. I'm using python 3.5 on this one, but it should work on later versions as well. Have a back-up of the project folder, for I've tested it enough for my own personal use only.

>> USE AT YOUR OWN RISK <<

Usage: python scriptname.py -i foldername

I pulled a copy of the folder I wanted to duplicate out of the project, renamed it and ran the script. As it doesn't affect guid references that are not found inside the folder itself, when you move the renamed folder to the project , Unity correctly matches the external references. :-)

Just to make sure you've read it: >> USE AT YOUR OWN RISK <<

 import fnmatch
 import os
 import argparse
 import uuid
 
 # PARAMETERS
 parser = argparse.ArgumentParser(description='Rearrange a Unity\'s project folder guids.')
 parser.add_argument('-i, --input',  metavar='FOLDER', type=str, nargs=1, required=True, dest='input_folder',
                     help='input folder')
 args = parser.parse_args()
 input_folder = None if args.input_folder is None else args.input_folder[0]
 if not os.path.isdir(input_folder):
     print('ERROR: Path not found.')
     quit(1)
 
 # SCAN FILES
 
 register_list = []
 print('')
 metas = dict()
 mats = []
 prefabs = []
 for root, folders, files in os.walk(input_folder):
     for fname in files:
         if fnmatch.fnmatch(fname, '*.meta'):
             metaname = root + os.sep + fname
             file = open(metaname, 'r')
             for line in file:
                 elements = line.split(': ')
                 if elements[0] == 'guid':
                     id = elements[1].replace('\n', '')
                     metas.update({id: [metaname, uuid.uuid4().hex]})
             file.close()
         if fnmatch.fnmatch(fname, '*.mat'):
             mats += [root + os.sep + fname]
         if fnmatch.fnmatch(fname, '*.prefab'):
             prefabs += [root + os.sep + fname]
 
 # CHANGE METAS
 
 for k, v in metas.items():
     file = open(v[0], 'r')
     met = file.readlines()
     for i, l in enumerate(met):
         if 'guid:' in l:
             met[i] = l.replace(k, v[1])
 
     file.close()
     file = open(v[0], 'w')
     file.writelines(met)
     file.close()
 
 #CHANGE PREFABS AND MATERIALS
 
 for pname in prefabs + mats:
     file = open(pname, 'r')
     changed = False
     prefab = file.readlines()
     for i, l in enumerate(prefab):
         if 'guid:' in l:
             key = None
             for k in metas.keys():
                 if k in l:
                     key = k
                     changed = True
             if key is not None:
                 prefab[i] = l.replace(key, metas[key][1])
                 print(prefab[i], end='')
                 print(key, '->', metas[key][1])
             else:
                 print(prefab[i])
     file.close()
     if changed:
         file = open(pname, 'w')
         file.writelines(prefab)
         file.close()
 



Comment
Add comment · Show 4 · 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 aaronfranke · Aug 30, 2019 at 06:28 AM 0
Share

Traceback (most recent call last): File ".\scriptname.py", line 49, in file = open(v[0], 'w') PermissionError: [Errno 13] Permission denied:

avatar image dandrea · Aug 30, 2019 at 06:05 PM 0
Share

@aaronfranke The error kind of self explains itself. The script assumes you can write to the folder. Either you don't have write permission or the file is being held by some other process.

What's your operational system?

$$anonymous$$ake a copy of the folder to outside the Unity's project folder beforehand. Run the script. Only then you move it back. And use it at your own risk.

avatar image aaronfranke · Aug 30, 2019 at 09:52 PM 0
Share

OS is Windows, I usually use Linux but in this case I'm doing VR development. I did make a copy outside and Unity was and is closed, but it still fails.

avatar image dandrea aaronfranke · Aug 31, 2019 at 05:06 PM 0
Share

¯\_(ツ)_/¯.

I have no idea, since I can't reproduce.

But really: the script is simple and readable. You should have no big problem figuring out what's wrong. For instance. Wrong filenames, perhaps?

avatar image
1

Answer by odintk45 · Mar 19, 2021 at 10:11 AM

My solution:

  • copy the directory

  • recursively retrieve the guid of all the files contained in the .meta of the destination folder

  • generate a correspondence table between the original guid (that I just got) and the new ones that I get thanks to GUID.Generate

  • replace the original guid with the new ones in all files

This procedure allows you to simply perform a deep copy of an entire folder.

This code can surely be improved and optimized, but it is functional.

         public static void CopyDirectoryDeep(string sourcePath, string destinationPath)
         {
             CopyDirectoryRecursively(sourcePath, destinationPath);
 
             List<string> metaFiles = GetFilesRecursively(destinationPath, (f) => f.EndsWith(".meta"));
             List<(string originalGuid, string newGuid)> guidTable = new List<(string originalGuid, string newGuid)>();
 
             foreach (string metaFile in metaFiles)
             {
                 StreamReader file = new StreamReader(metaFile);
                 file.ReadLine();
                 string guidLine = file.ReadLine();
                 file.Close();
                 string originalGuid = guidLine.Substring(6, guidLine.Length - 6);
                 string newGuid = GUID.Generate().ToString().Replace("-", "");
                 guidTable.Add((originalGuid, newGuid));
             }
 
             List<string> allFiles = GetFilesRecursively(destinationPath);
 
             foreach (string fileToModify in allFiles)
             {
                 string content = File.ReadAllText(fileToModify);
 
                 foreach (var guidPair in guidTable)
                 {
                     content = content.Replace(guidPair.originalGuid, guidPair.newGuid);
                 }
 
                 File.WriteAllText(fileToModify, content);
             }
 
             AssetDatabase.Refresh();
         }
 
         private static void CopyDirectoryRecursively(string sourceDirName, string destDirName)
         {
             DirectoryInfo dir = new DirectoryInfo(sourceDirName);
 
             DirectoryInfo[] dirs = dir.GetDirectories();
 
             if (!Directory.Exists(destDirName))
             {
                 Directory.CreateDirectory(destDirName);
             }
 
             FileInfo[] files = dir.GetFiles();
             foreach (FileInfo file in files)
             {
                 string temppath = Path.Combine(destDirName, file.Name);
                 file.CopyTo(temppath, false);
             }
 
             foreach (DirectoryInfo subdir in dirs)
             {
                 string temppath = Path.Combine(destDirName, subdir.Name);
                 CopyDirectoryRecursively(subdir.FullName, temppath);
             }
         }
 
         private static List<string> GetFilesRecursively(string path, Func<string, bool> criteria = null, List<string> files = null)
         {
             if (files == null)
             {
                 files = new List<string>();
             }
 
             files.AddRange(Directory.GetFiles(path).Where(f =>criteria == null || criteria(f)));
 
             foreach (string directory in Directory.GetDirectories(path))
             {
                 GetFilesRecursively(directory, criteria, files);
             }
 
             return files;
         }

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 Tortuap · Sep 03, 2021 at 10:46 AM 0
Share

Perfect solution thank you !

avatar image Bunny83 · Sep 04, 2021 at 08:46 AM 0
Share

You may want to call AssetDatabase.StartAssetEditing befor you start copying and call AssetDatabase.StopAssetEditing once you're done to prevent any issues during the process. Note that you probably should wrap all your code in a try-finally block to ensure StopAssetEditing is called at the end.

 public static void CopyDirectoryDeep(string sourcePath, string destinationPath)
 {
     try
     {
         AssetDatabase.StartAssetEditing();
         
         // the original code goes here
         
     }
     finally
     {
         AssetDatabase.StopAssetEditing();
     }
 }


If you have a lot of large files you may want to add EditorUtility.DisplayProgressBar in between your code to update the progress and call EditorUtility.ClearProgressBar also in the finally block to give visual feedback. Instead of DisplayProgressBar you can also use DisplayCancelableProgressBar which allows the user to click the cancel button. The method would return true if the action should be cancelled. So it's still your responsiblility what you do when the user clicks cancel. In this case you probably want to undo everything and get rid of the already created new folder since the process was interrupted in between. Though this is all just optional.

avatar image
0

Answer by drudiverse · Oct 18, 2014 at 07:44 PM

sounds like you need to write arrays or file strings to reference many prefabs, because otherwise they just save with scene views if you save them in the player. you have to copy them with unity explorer window and then they all have file names, prefab names texture names. a texture should refer to a variable or an image file. you have to be familiar with accessing prefabs in unity. straings can code file names, you can add them togther in loops to deal with just one string being different in batches of prefabs.

the example with quotes was confusing... texture isnt prefab?

Comment
Add comment · 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
0

Answer by HenTeMon · Oct 19, 2014 at 09:49 AM

There is many unity objects, who refer to another.

It is not only prefabs. For example, Animator controller refer to animations. Scene refer to prefabs. Prefab refer to textures, materials, etc. I can change these links in unity editor (refer to objects with same names, but in another folder), manually, each individually. But I don't know how do that for multiple objects in editor, or script.

When I copy prefab and texture to another folder - it refer to texture from old folder. I need, that prefab refer to texture in new folder.

I am not sure, what you mean. Are you propose to make connections between objects through "Resources" class or analog?

Comment
Add comment · 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

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

9 People are following this question.

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

Related Questions

How can you duplicat folders and not share old dependencies? 1 Answer

clone object make a new script 0 Answers

How to reset a component on duplication? 4 Answers

How can I duplicate an object and place it randomly near the original ? 0 Answers

How to have a cloned/duplicated enemy react the same way the original does? 1 Answer


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