Advertisement
Guest User

Untitled

a guest
Jan 13th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.83 KB | None | 0 0
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18.  
  19. bl_info = {
  20. 'name': 'Save As Game Engine Runtime',
  21. 'author': 'Mitchell Stokes (Moguri)',
  22. 'version': (0, 3, 1),
  23. "blender": (2, 61, 0),
  24. 'location': 'File > Export',
  25. 'description': 'Bundle a .blend file with the Blenderplayer',
  26. 'warning': '',
  27. 'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.6/Py/'\
  28. 'Scripts/Game_Engine/Save_As_Runtime',
  29. 'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
  30. 'func=detail&aid=23564',
  31. 'category': 'Game Engine'}
  32.  
  33. import bpy
  34. import os
  35. import sys
  36. import shutil
  37. import tempfile
  38.  
  39.  
  40. def CopyPythonLibs(dst, overwrite_lib, report=print):
  41. import platform
  42.  
  43. # use python module to find pytohn's libpath
  44. src = os.path.dirname(platform.__file__)
  45.  
  46. # dst points to lib/, but src points to current python's library path, eg:
  47. # '/usr/lib/python3.2' vs '/usr/lib'
  48. # append python's library dir name to destination, so only python's
  49. # libraries would be copied
  50. if os.name == 'posix':
  51. dst = os.path.join(dst, os.path.basename(src))
  52.  
  53. if os.path.exists(src):
  54. write = False
  55. if os.path.exists(dst):
  56. if overwrite_lib:
  57. shutil.rmtree(dst)
  58. write = True
  59. else:
  60. write = True
  61. if write:
  62. shutil.copytree(src, dst, ignore=lambda dir, contents: [i for i in contents if i == '__pycache__'])
  63. else:
  64. report({'WARNING'}, "Python not found in %r, skipping pythn copy" % src)
  65.  
  66.  
  67. def WriteAppleRuntime(player_path, output_path, copy_python, overwrite_lib):
  68. # Enforce the extension
  69. if not output_path.endswith('.app'):
  70. output_path += '.app'
  71.  
  72. # Use the system's cp command to preserve some meta-data
  73. os.system('cp -R "%s" "%s"' % (player_path, output_path))
  74.  
  75. bpy.ops.wm.save_as_mainfile(filepath=os.path.join(output_path, "Contents/Resources/game.blend"),
  76. relative_remap=False,
  77. compress=False,
  78. copy=True,
  79. )
  80.  
  81. # Python doesn't need to be copied for OS X since it's already inside blenderplayer.app
  82.  
  83.  
  84. def WriteRuntime(player_path, output_path, copy_python, overwrite_lib, copy_dlls, report=print):
  85. import struct
  86.  
  87. # Check the paths
  88. if not os.path.isfile(player_path) and not(os.path.exists(player_path) and player_path.endswith('.app')):
  89. report({'ERROR'}, "The player could not be found! Runtime not saved")
  90. return
  91.  
  92. # Check if we're bundling a .app
  93. if player_path.endswith('.app'):
  94. WriteAppleRuntime(player_path, output_path, copy_python, overwrite_lib)
  95. return
  96.  
  97. # Enforce "exe" extension on Windows
  98. if player_path.endswith('.exe') and not output_path.endswith('.exe'):
  99. output_path += '.exe'
  100.  
  101. # Get the player's binary and the offset for the blend
  102. file = open(player_path, 'rb')
  103. player_d = file.read()
  104. offset = file.tell()
  105. file.close()
  106.  
  107. # Create a tmp blend file (Blenderplayer doesn't like compressed blends)
  108. tempdir = tempfile.mkdtemp()
  109. blend_path = os.path.join(tempdir, bpy.path.clean_name(output_path))
  110. bpy.ops.wm.save_as_mainfile(filepath=blend_path,
  111. relative_remap=False,
  112. compress=False,
  113. copy=True,
  114. )
  115. blend_path += '.blend'
  116.  
  117. # Get the blend data
  118. blend_file = open(blend_path, 'rb')
  119. blend_d = blend_file.read()
  120. blend_file.close()
  121.  
  122. # Get rid of the tmp blend, we're done with it
  123. os.remove(blend_path)
  124. os.rmdir(tempdir)
  125.  
  126. # Create a new file for the bundled runtime
  127. output = open(output_path, 'wb')
  128.  
  129. # Write the player and blend data to the new runtime
  130. print("Writing runtime...", end=" ")
  131. output.write(player_d)
  132. output.write(blend_d)
  133.  
  134. # Store the offset (an int is 4 bytes, so we split it up into 4 bytes and save it)
  135. output.write(struct.pack('B', (offset>>24)&0xFF))
  136. output.write(struct.pack('B', (offset>>16)&0xFF))
  137. output.write(struct.pack('B', (offset>>8)&0xFF))
  138. output.write(struct.pack('B', (offset>>0)&0xFF))
  139.  
  140. # Stuff for the runtime
  141. output.write(b'BRUNTIME')
  142. output.close()
  143.  
  144. print("done")
  145.  
  146. # Make the runtime executable on Linux
  147. if os.name == 'posix':
  148. os.chmod(output_path, 0o755)
  149.  
  150. # Copy bundled Python
  151. blender_dir = os.path.dirname(bpy.app.binary_path)
  152. runtime_dir = os.path.dirname(output_path)
  153.  
  154. if copy_python:
  155. print("Copying Python files...", end=" ")
  156. py_folder = os.path.join(bpy.app.version_string.split()[0], "python", "lib")
  157. dst = os.path.join(runtime_dir, py_folder)
  158. CopyPythonLibs(dst, overwrite_lib, report)
  159. print("done")
  160.  
  161. # And DLLs
  162. if copy_dlls:
  163. print("Copying DLLs...", end=" ")
  164. for file in [i for i in os.listdir(blender_dir) if i.lower().endswith('.dll')]:
  165. src = os.path.join(blender_dir, file)
  166. dst = os.path.join(runtime_dir, file)
  167. shutil.copy2(src, dst)
  168.  
  169. print("done")
  170.  
  171. from bpy.props import *
  172.  
  173.  
  174. class SaveAsRuntime(bpy.types.Operator):
  175. bl_idname = "wm.save_as_runtime"
  176. bl_label = "Save As Game Engine Runtime"
  177. bl_options = {'REGISTER'}
  178.  
  179. if sys.platform == 'darwin':
  180. # XXX, this line looks suspicious, could be done better?
  181. blender_bin_dir = '/' + os.path.join(*bpy.app.binary_path.split('/')[0:-4])
  182. ext = '.app'
  183. else:
  184. blender_bin_path = bpy.app.binary_path
  185. blender_bin_dir = os.path.dirname(blender_bin_path)
  186. ext = os.path.splitext(blender_bin_path)[-1].lower()
  187.  
  188. default_player_path = os.path.join(blender_bin_dir, 'blenderplayer' + ext)
  189. player_path = StringProperty(
  190. name="Player Path",
  191. description="The path to the player to use",
  192. default=default_player_path,
  193. subtype='FILE_PATH',
  194. )
  195. filepath = StringProperty(
  196. subtype='FILE_PATH',
  197. )
  198. copy_python = BoolProperty(
  199. name="Copy Python",
  200. description="Copy bundle Python with the runtime",
  201. default=True,
  202. )
  203. overwrite_lib = BoolProperty(
  204. name="Overwrite 'lib' folder",
  205. description="Overwrites the lib folder (if one exists) with the bundled Python lib folder",
  206. default=False,
  207. )
  208.  
  209. # Only Windows has dlls to copy
  210. if ext == '.exe':
  211. copy_dlls = BoolProperty(
  212. name="Copy DLLs",
  213. description="Copy all needed DLLs with the runtime",
  214. default=True,
  215. )
  216. else:
  217. copy_dlls = False
  218.  
  219. def execute(self, context):
  220. import time
  221. start_time = time.clock()
  222. print("Saving runtime to %r" % self.filepath)
  223. WriteRuntime(self.player_path,
  224. self.filepath,
  225. self.copy_python,
  226. self.overwrite_lib,
  227. self.copy_dlls,
  228. self.report,
  229. )
  230. print("Finished in %.4fs" % (time.clock()-start_time))
  231. return {'FINISHED'}
  232.  
  233. def invoke(self, context, event):
  234. if not self.filepath:
  235. ext = '.app' if sys.platform == 'darwin' else os.path.splitext(bpy.app.binary_path)[-1]
  236. self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ext)
  237.  
  238. wm = context.window_manager
  239. wm.fileselect_add(self)
  240. return {'RUNNING_MODAL'}
  241.  
  242.  
  243. def menu_func(self, context):
  244. self.layout.operator(SaveAsRuntime.bl_idname)
  245.  
  246.  
  247. def register():
  248. bpy.utils.register_module(__name__)
  249.  
  250. bpy.types.INFO_MT_file_export.append(menu_func)
  251.  
  252.  
  253. def unregister():
  254. bpy.utils.unregister_module(__name__)
  255.  
  256. bpy.types.INFO_MT_file_export.remove(menu_func)
  257.  
  258.  
  259. if __name__ == "__main__":
  260. register()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement