# THIS FILE IS A PART OF VCStudio # PYTHON 3 # BPY ( WITH IN BLENDER ) ################################################################# # This file is running with in Blender to link assets from their # AST files into the animation files. And make library overrides. # NOTE: It's using BPY module which is not available outside of # blender. So in order to test any changes to it. You have to # run it with in Blender. Or Using blender -P . # See blender --help for details. ################################################################# import bpy import os # The main problem with running from with in blender is that we # have no access to all the outside modules. And this script # will be there on it's own. So it need a way of knowing where # are the assets. blendpath = bpy.data.filepath # Animation file path folder = blendpath[:blendpath.rfind("/")] # Animation shot folder pf = folder[:folder.rfind("/rnd/")] # Project's folder # In order for VCStudio or Blender-Organizer to know what is going # on I use print(). It's not going to be outputted into terminal. # since we are piping everything directly into VCStudio. Which is # going to parse those lines to give the user some graphical feed # back. print("BLENDPATH : ", blendpath) print("FOLDER : ", folder) print("PROJECT FOLDER : ", pf) # Now we are going to abort the process if there is no file in the # shot folder that has the info about the linked data. autolink.data if os.path.exists(folder+"/extra/autolink.data"): print("FOUND AUTOLINK.DATA YEY :)") # Now let's parse the extra/autolink.data file df = open(folder+"/extra/autolink.data" , "r") df = df.read() # These 2 values will be our location in the blender space since # I don't think any user wants all of their assets to be in the # same exact spot. movey = 0 movex = 0 # We need to get our mode first. Because the user might want to # just link. Or make the old proxy. mode = "link" for num, line in enumerate(df.split("\n")): if line.startswith("Mode : "): mode = line[7:] # Let's see if there any lines that say what we want to link. for num, line in enumerate(df.split("\n")): if line.startswith("Link : "): # So here is out item. ( asset ). NOTE: THe item in # autolink.data will have /dev/ added to the begining # like all links in Blender-Organizer. item = line[7:] print("\nLINKING ITEM : "+item) # Now let's see if the asset also has an autolink.data # configured. Because if not. Script would not know what # to link. itemsdf = pf+item+"/autolink.data" if os.path.exists(itemsdf): print("FOUND "+item+"'S AUTOLINK.DATA :)") # Now let's parse the autolink.data of the asset. idf = open(itemsdf, "r") idf = idf.read() # We need to find 2 types of data. What collections # to link. Since not all of them are nessesary. And # whether to do library-overrides. # At the time of Blender-Organizer library-overrides # was still a very unstable thing. So I was going # proxies. Now I don't want to break backward compati- # bility with Blender-Organizer. So we are going to # read the full list of Proxies. And if they exist # we are going to use library override instead. So # keep in mind. They called proxies in the script. But # they are library-overrides. linkdata = [] # Lits of colletions to link proxydata = [] # Lits of "Proxies" so to speak. for iline in idf.split("\n"): if iline.startswith("Link : "): linkdata.append(iline[7:]) elif iline.startswith("Proxy : "): proxydata.append(iline[8:]) print("LINKDATA ", linkdata) print("PROXYDATA ", proxydata) # Okay. Now we got both lists. Let's see if there is # an asset blend file. Because for any reason it might # not exists. astblend = pf+"/ast/"+item[5:]+".blend" print("AST BLEND : "+astblend) if os.path.exists(astblend): print("YAY FOUND THE BLENDFILE :)") # We found our asset blend file. So now let's do # the linking. for collection in linkdata: print("ATTEMPTING TO LINK : "+collection) # Now let's try actually doing it. try: with bpy.data.libraries.load(astblend, link=True) as (data_from, data_to): data_to.collections = [c for c in data_from.collections if c == collection] for num2, new_coll in enumerate(data_to.collections): print("TRYING LINKING ", new_coll.name) try: if new_coll.name: instance = bpy.data.objects.new(new_coll.name, None) instance.instance_type = 'COLLECTION' instance.instance_collection = new_coll bpy.context.scene.collection.objects.link(instance) if not item[5:].startswith("loc"): bpy.data.objects[collection].location[1] = movey bpy.data.objects[collection].location[0] = movex # So here we already linked our data. And placed the # objects. Next we want to do library-overrides. if proxydata and mode == "override": # With library overrides there is one little problem. # It nullifies the location. Because the location is # now also overriden. bpy.data.objects[collection].select_set(True) bpy.context.view_layer.objects.active = bpy.data.objects[collection] bpy.ops.object.make_override_library() # So after we do the override we need to change the # location again. if not item[5:].startswith("loc"): bpy.data.objects[proxydata[0]].location[1] = movey bpy.data.objects[proxydata[0]].location[0] = movex # And while we are on it. In the Blender-Organizer # linker there was one inconvinience that you had # to hide the rig from viewport since if not you will # have both linked and proxy rig drawn on screen at # the same time. So let's unhide it. bpy.data.objects[proxydata[0]].hide_viewport = False # Also while we are here. Let's use the size of the # rig to offset it's location instead of 5. If the # rig exists. movey = movey + bpy.data.objects[proxydata[0]].dimensions.y+1 if movey > 25: movey = 0 movex = movex + 5 elif proxydata and mode == "proxy": # Now the used could select to do it the old way. # using a proxy. Then this is the way. for proxymake in proxydata: print("TRYING PROXING ", proxymake) try: ob = bpy.context.scene.objects[new_coll.name] ob.select_set(True) bpy.context.view_layer.objects.active = ob bpy.ops.object.proxy_make(object=proxymake) except Exception as e: print("PROXY FAILED ", proxymake) print(e, "ERROR IN PROXY") movey = movey + 5 if movey > 25: movey = 0 movex = movex + 5 else: # If ther is no library - override enabled. The instance # empty has a size of 0. So this same dimension thing # would not work here. :(. I might come up with something # later. movey = movey + 5 if movey > 25: movey = 0 movex = movex + 5 # Now I want to save the file. BUT. In the old way of # doing it I made a mistake to save without checking # that all paths should be RELATIVE. And so copying the # project to another computer bloke all the files. bpy.ops.file.make_paths_relative() bpy.ops.wm.save_mainfile() # So ther is 2 line now when saving. # Now I'd like to print out the current fraction of # the linking progress done. So I could make a progress # bar in the VCStudio. print("FRACTION:", (num+1)/len(df.split("\n"))) except Exception as e: print(e, "ERROR IN LINING") except Exception as e: print(e, "ERROR IN GENERAL") else: print("NO BLENDFILE DOEN'T EXIST :(") else: print("NO "+item+"'S AUTOLINK.DATA :(") else: print("NO AUTOLINK.DATA SORRY :(") print("FINISHED")