[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1348] trunk/py/scripts/addons/ game_engine_save_as_runtime.py: == Save Game As Runtime ==

Mitchell Stokes mogurijin at gmail.com
Tue Jan 4 08:48:47 CET 2011


Revision: 1348
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-extensions&revision=1348
Author:   moguri
Date:     2011-01-04 08:48:47 +0100 (Tue, 04 Jan 2011)

Log Message:
-----------
== Save Game As Runtime ==
  * Fixed OS X support (finds a good default path for the player and can make runtimes)
  * Enforce extensions on OS X (.app) and Windows (.exe)
  * Added Copy Python option to copy the bundled Python to the runtime directory
  * Added Overwrite 'lib' option to choose whether Copy Python will overwrite a pre-existing 'lib' directory in the runtime directory
  * Added Copy DLLs option (Win32 only) to copy DLL files from the Blender binary directory to the runtime directory
  * Cleaned up the code to handle compressed blend files.

Modified Paths:
--------------
    trunk/py/scripts/addons/game_engine_save_as_runtime.py

Modified: trunk/py/scripts/addons/game_engine_save_as_runtime.py
===================================================================
--- trunk/py/scripts/addons/game_engine_save_as_runtime.py	2011-01-04 05:12:49 UTC (rev 1347)
+++ trunk/py/scripts/addons/game_engine_save_as_runtime.py	2011-01-04 07:48:47 UTC (rev 1348)
@@ -19,9 +19,9 @@
 bl_addon_info = {
     'name': 'Save As Runtime',
     'author': 'Mitchell Stokes (Moguri)',
-    'version': (0, 2, 2),
-    'blender': (2, 5, 4),
-    'api': 31667,
+    'version': (0, 3, 0),
+    'blender': (2, 5, 6),
+    'api': 34057,
     'location': 'File > Export',
     'description': 'Bundle a .blend file with the Blenderplayer',
     'warning': '',
@@ -33,27 +33,54 @@
 
 import bpy
 import os
+import sys
+import shutil
 
 
-def WriteAppleRuntime(player_path, output_path):
+def WriteAppleRuntime(player_path, output_path, copy_python, overwrite_lib):
+    # Enforce the extension
+    if not output_path.endswith('.app'):
+        output_path += '.app'
+
     # Use the system's cp command to preserve some meta-data
     os.system('cp -R "%s" "%s"' % (player_path, output_path))
     
-    bpy.ops.save_as_mainfile(filepath=output_path+"/Contents/Resources/game.blend", copy=True)
+    bpy.ops.wm.save_as_mainfile(filepath=output_path+"/Contents/Resources/game.blend", copy=True)
+    
+    # Copy bundled Python
+    blender_dir = os.path.dirname(bpy.app.binary_path)
+    
+    if copy_python:
+        print("Copying Python files...", end=" ")
+        src = os.path.join(blender_dir, bpy.app.version_string.split()[0], "python", "lib")
+        dst = os.path.join(output_path, "Contents", "MacOS", "lib")
+        
+        if os.path.exists(dst):
+            if overwrite_lib:
+                shutil.rmtree(dst)
+                shutil.copytree(src, dst, ignore=lambda dir, contents: [i for i in contents if i.endswith('.pyc')])
+        else:
+            shutil.copytree(src, dst, ignore=lambda dir, contents: [i for i in contents if i.endswith('.pyc')])
+        
+        print("done")
 
 
-def WriteRuntime(player_path, output_path):
+def WriteRuntime(player_path, output_path, copy_python, overwrite_lib, copy_dlls):
     import struct
 
     # Check the paths
-    if not os.path.isfile(player_path):
+    if not os.path.isfile(player_path) and not(os.path.exists(player_path) and player_path.endswith('.app')):
         print("The player could not be found! Runtime not saved.")
         return
     
     # Check if we're bundling a .app
     if player_path.endswith('.app'):
-        WriteAppleRuntime(player_path, output_path)
+        WriteAppleRuntime(player_path, output_path, copy_python, overwrite_lib)
         return
+        
+    # Enforce "exe" extension on Windows
+    if player_path.endswith('.exe') and not output_path.endswith('.exe'):
+        output_path += '.exe'
     
     # Get the player's binary and the offset for the blend
     file = open(player_path, 'rb')
@@ -61,24 +88,16 @@
     offset = file.tell()
     file.close()
     
-    # Create a tmp blend file
+    # Create a tmp blend file (Blenderplayer doesn't like compressed blends)
     blend_path = bpy.path.clean_name(output_path)
-    bpy.ops.wm.save_as_mainfile(filepath=blend_path, copy=True)
+    bpy.ops.wm.save_as_mainfile(filepath=blend_path, compress=False, copy=True)
     blend_path += '.blend'
     
-    
-    # Get the blend data (if compressed, uncompress the blend before embedding it)
+    # Get the blend data
     blend_file = open(blend_path, 'rb')
-    head = blend_file.read(7)
-    blend_file.seek(0)
-    if head[0:2] == b'\x1f\x8b':  # gzip magic
-        import gzip
-        blend_file.close()
-        blend_file = gzip.open(blend_path, 'rb')
     blend_d = blend_file.read()
     blend_file.close()
 
-    
     # Get rid of the tmp blend, we're done with it
     os.remove(blend_path)
     
@@ -86,6 +105,7 @@
     output = open(output_path, 'wb')
     
     # Write the player and blend data to the new runtime
+    print("Writing runtime...", end=" ")
     output.write(player_d)
     output.write(blend_d)
     
@@ -99,11 +119,40 @@
     output.write(b'BRUNTIME')
     output.close()
     
+    print("done")
+    
     # Make the runtime executable on Linux
     if os.name == 'posix':
         os.chmod(output_path, 0o755)
+        
+    # Copy bundled Python
+    blender_dir = os.path.dirname(bpy.app.binary_path)
+    runtime_dir = os.path.dirname(output_path)
+    
+    if copy_python:
+        print("Copying Python files...", end=" ")
+        src = os.path.join(blender_dir, bpy.app.version_string.split()[0], "python", "lib")
+        dst = os.path.join(runtime_dir, "lib")
+        
+        if os.path.exists(dst):
+            if overwrite_lib:
+                shutil.rmtree(dst)
+                shutil.copytree(src, dst, ignore=lambda dir, contents: [i for i in contents if i.endswith('.pyc')])
+        else:
+            shutil.copytree(src, dst, ignore=lambda dir, contents: [i for i in contents if i.endswith('.pyc')])
+        
+        print("done")
 
+    # And DLLs
+    if copy_dlls:
+        print("Copying DLLs...", end=" ")
+        for file in [i for i in os.listdir(blender_dir) if i.endswith('.dll')]:
+            src = os.path.join(blender_dir, file)
+            dst = os.path.join(runtime_dir, file)
+            shutil.copy2(src, dst)
 
+        print("done")
+
 from bpy.props import *
 
 
@@ -112,20 +161,35 @@
     bl_label = "Save As Runtime"
     bl_options = {'REGISTER'}
     
-    blender_bin_path = bpy.app.binary_path
-    blender_bin_dir = os.path.dirname(blender_bin_path)
-    ext = os.path.splitext(blender_bin_path)[-1]
+    if sys.platform == 'darwin':
+        blender_bin_dir = '/'+os.path.join(*bpy.app.binary_path.split('/')[0:-4])
+        ext = '.app'
+    else:
+        blender_bin_path = bpy.app.binary_path
+        blender_bin_dir = os.path.dirname(blender_bin_path)
+        ext = os.path.splitext(blender_bin_path)[-1]
     
     default_player_path = os.path.join(blender_bin_dir, 'blenderplayer' + ext)
     player_path = StringProperty(name="Player Path", description="The path to the player to use", default=default_player_path)
     filepath = StringProperty(name="Output Path", description="Where to save the runtime", default="")
+    copy_python = BoolProperty(name="Copy Python", description="Copy bundle Python with the runtime", default=True)
+    overwrite_lib = BoolProperty(name="Overwrite 'lib' folder", description="Overwrites the lib folder (if one exists) with the bundled Python lib folder", default=False)
+
+    # Only Windows has dlls to copy
+    if ext == '.exe':
+        copy_dlls = BoolProperty(name="Copy DLLs", description="Copy all needed DLLs with the runtime", default=True)
+    else:
+        copy_dlls = False
     
     def execute(self, context):
         import time
         start_time = time.clock()
         print("Saving runtime to", self.properties.filepath)
         WriteRuntime(self.properties.player_path,
-                    self.properties.filepath)
+                    self.properties.filepath,
+                    self.properties.copy_python,
+                    self.properties.overwrite_lib,
+                    self.copy_dlls)
         print("Finished in %.4fs" % (time.clock()-start_time))
         return {'FINISHED'}
                     
@@ -137,7 +201,7 @@
 
 def menu_func(self, context):
 
-    ext = os.path.splitext(bpy.app.binary_path)[-1]
+    ext = '.app' if sys.platform == 'darwin' else os.path.splitext(bpy.app.binary_path)[-1]
     default_blend_path = bpy.data.filepath.replace(".blend", ext)
     self.layout.operator(SaveAsRuntime.bl_idname, text=SaveAsRuntime.bl_label).filepath = default_blend_path
 




More information about the Bf-extensions-cvs mailing list