bpy_do_linking.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. # BPY ( WITH IN BLENDER )
  4. #################################################################
  5. # This file is running with in Blender to link assets from their
  6. # AST files into the animation files. And make library overrides.
  7. # NOTE: It's using BPY module which is not available outside of
  8. # blender. So in order to test any changes to it. You have to
  9. # run it with in Blender. Or Using blender -P <your_script>.
  10. # See blender --help for details.
  11. #################################################################
  12. import bpy
  13. import os
  14. # The main problem with running from with in blender is that we
  15. # have no access to all the outside modules. And this script
  16. # will be there on it's own. So it need a way of knowing where
  17. # are the assets.
  18. blendpath = bpy.data.filepath # Animation file path
  19. folder = blendpath[:blendpath.rfind("/")] # Animation shot folder
  20. pf = folder[:folder.rfind("/rnd/")] # Project's folder
  21. # In order for VCStudio or Blender-Organizer to know what is going
  22. # on I use print(). It's not going to be outputted into terminal.
  23. # since we are piping everything directly into VCStudio. Which is
  24. # going to parse those lines to give the user some graphical feed
  25. # back.
  26. print("BLENDPATH : ", blendpath)
  27. print("FOLDER : ", folder)
  28. print("PROJECT FOLDER : ", pf)
  29. # Now we are going to abort the process if there is no file in the
  30. # shot folder that has the info about the linked data. autolink.data
  31. if os.path.exists(folder+"/extra/autolink.data"):
  32. print("FOUND AUTOLINK.DATA YEY :)")
  33. # Now let's parse the extra/autolink.data file
  34. df = open(folder+"/extra/autolink.data" , "r")
  35. df = df.read()
  36. # These 2 values will be our location in the blender space since
  37. # I don't think any user wants all of their assets to be in the
  38. # same exact spot.
  39. movey = 0
  40. movex = 0
  41. # We need to get our mode first. Because the user might want to
  42. # just link. Or make the old proxy.
  43. mode = "link"
  44. for num, line in enumerate(df.split("\n")):
  45. if line.startswith("Mode : "):
  46. mode = line[7:]
  47. # Let's see if there any lines that say what we want to link.
  48. for num, line in enumerate(df.split("\n")):
  49. if line.startswith("Link : "):
  50. # So here is out item. ( asset ). NOTE: THe item in
  51. # autolink.data will have /dev/ added to the begining
  52. # like all links in Blender-Organizer.
  53. item = line[7:]
  54. print("\nLINKING ITEM : "+item)
  55. # Now let's see if the asset also has an autolink.data
  56. # configured. Because if not. Script would not know what
  57. # to link.
  58. itemsdf = pf+item+"/autolink.data"
  59. if os.path.exists(itemsdf):
  60. print("FOUND "+item+"'S AUTOLINK.DATA :)")
  61. # Now let's parse the autolink.data of the asset.
  62. idf = open(itemsdf, "r")
  63. idf = idf.read()
  64. # We need to find 2 types of data. What collections
  65. # to link. Since not all of them are nessesary. And
  66. # whether to do library-overrides.
  67. # At the time of Blender-Organizer library-overrides
  68. # was still a very unstable thing. So I was going
  69. # proxies. Now I don't want to break backward compati-
  70. # bility with Blender-Organizer. So we are going to
  71. # read the full list of Proxies. And if they exist
  72. # we are going to use library override instead. So
  73. # keep in mind. They called proxies in the script. But
  74. # they are library-overrides.
  75. linkdata = [] # Lits of colletions to link
  76. proxydata = [] # Lits of "Proxies" so to speak.
  77. for iline in idf.split("\n"):
  78. if iline.startswith("Link : "):
  79. linkdata.append(iline[7:])
  80. elif iline.startswith("Proxy : "):
  81. proxydata.append(iline[8:])
  82. print("LINKDATA ", linkdata)
  83. print("PROXYDATA ", proxydata)
  84. # Okay. Now we got both lists. Let's see if there is
  85. # an asset blend file. Because for any reason it might
  86. # not exists.
  87. astblend = pf+"/ast/"+item[5:]+".blend"
  88. print("AST BLEND : "+astblend)
  89. if os.path.exists(astblend):
  90. print("YAY FOUND THE BLENDFILE :)")
  91. # We found our asset blend file. So now let's do
  92. # the linking.
  93. for collection in linkdata:
  94. print("ATTEMPTING TO LINK : "+collection)
  95. # Now let's try actually doing it.
  96. try:
  97. with bpy.data.libraries.load(astblend, link=True) as (data_from, data_to):
  98. data_to.collections = [c for c in data_from.collections if c == collection]
  99. for num2, new_coll in enumerate(data_to.collections):
  100. print("TRYING LINKING ", new_coll.name)
  101. try:
  102. if new_coll.name:
  103. instance = bpy.data.objects.new(new_coll.name, None)
  104. instance.instance_type = 'COLLECTION'
  105. instance.instance_collection = new_coll
  106. bpy.context.scene.collection.objects.link(instance)
  107. if not item[5:].startswith("loc"):
  108. bpy.data.objects[collection].location[1] = movey
  109. bpy.data.objects[collection].location[0] = movex
  110. # So here we already linked our data. And placed the
  111. # objects. Next we want to do library-overrides.
  112. if proxydata and mode == "override":
  113. # With library overrides there is one little problem.
  114. # It nullifies the location. Because the location is
  115. # now also overriden.
  116. bpy.data.objects[collection].select_set(True)
  117. bpy.context.view_layer.objects.active = bpy.data.objects[collection]
  118. bpy.ops.object.make_override_library()
  119. # So after we do the override we need to change the
  120. # location again.
  121. if not item[5:].startswith("loc"):
  122. bpy.data.objects[proxydata[0]].location[1] = movey
  123. bpy.data.objects[proxydata[0]].location[0] = movex
  124. # And while we are on it. In the Blender-Organizer
  125. # linker there was one inconvinience that you had
  126. # to hide the rig from viewport since if not you will
  127. # have both linked and proxy rig drawn on screen at
  128. # the same time. So let's unhide it.
  129. bpy.data.objects[proxydata[0]].hide_viewport = False
  130. # Also while we are here. Let's use the size of the
  131. # rig to offset it's location instead of 5. If the
  132. # rig exists.
  133. movey = movey + bpy.data.objects[proxydata[0]].dimensions.y+1
  134. if movey > 25:
  135. movey = 0
  136. movex = movex + 5
  137. elif proxydata and mode == "proxy":
  138. # Now the used could select to do it the old way.
  139. # using a proxy. Then this is the way.
  140. for proxymake in proxydata:
  141. print("TRYING PROXING ", proxymake)
  142. try:
  143. ob = bpy.context.scene.objects[new_coll.name]
  144. ob.select_set(True)
  145. bpy.context.view_layer.objects.active = ob
  146. bpy.ops.object.proxy_make(object=proxymake)
  147. except Exception as e:
  148. print("PROXY FAILED ", proxymake)
  149. print(e, "ERROR IN PROXY")
  150. movey = movey + 5
  151. if movey > 25:
  152. movey = 0
  153. movex = movex + 5
  154. else:
  155. # If ther is no library - override enabled. The instance
  156. # empty has a size of 0. So this same dimension thing
  157. # would not work here. :(. I might come up with something
  158. # later.
  159. movey = movey + 5
  160. if movey > 25:
  161. movey = 0
  162. movex = movex + 5
  163. # Now I want to save the file. BUT. In the old way of
  164. # doing it I made a mistake to save without checking
  165. # that all paths should be RELATIVE. And so copying the
  166. # project to another computer bloke all the files.
  167. bpy.ops.file.make_paths_relative()
  168. bpy.ops.wm.save_mainfile()
  169. # So ther is 2 line now when saving.
  170. # Now I'd like to print out the current fraction of
  171. # the linking progress done. So I could make a progress
  172. # bar in the VCStudio.
  173. print("FRACTION:", (num+1)/len(df.split("\n")))
  174. except Exception as e:
  175. print(e, "ERROR IN LINING")
  176. except Exception as e:
  177. print(e, "ERROR IN GENERAL")
  178. else:
  179. print("NO BLENDFILE DOEN'T EXIST :(")
  180. else:
  181. print("NO "+item+"'S AUTOLINK.DATA :(")
  182. else:
  183. print("NO AUTOLINK.DATA SORRY :(")
  184. print("FINISHED")