# references # https://s-nako.work/2020/09/blender-error-attributeerror-_restrictcontext-object-has-no-attribute-view_layer/ # https://web.archive.org/web/20210925181415/https://blenderbrew.com/custom-application-templates-in-blender/ # elemental python modules blenxy needs # that the python interpreter to be used must have built in # python interpreter to be used has to be an external one (I am sick of the internal one) import bpy, importlib, sys, subprocess, os, shutil, io, copy import math, mathutils, warnings, struct, site, re, random from . import file_ops # uses os and shutil modules # elemental python modules blenxy needs # that the python interpreter probably does not have built in/needs to be updated NEEDED_MODULE_NAMES = ["pip", "lxml", "numpy"] # check which of the new modules needs to be installed def new_mod_check(mod_names): # variable to return rtn = [] # traverse into all the needed modules for mod_name in NEEDED_MODULE_NAMES: # try importing the module try: importlib.import_module(mod_name) except: rtn.append(mod_name) # done! return rtn # find python interpreter def find_python_interpreter(): # start.bat/start.sh sends the python interpreter # path as an argument to Blender the only argument it sends return sys.argv[2] # install given modules with pip but be sure to have pip first def new_mod_install(mod_names): # get python's interpreter binary path py_bin = find_python_interpreter() pip_install = [py_bin, "-B", "-m", "pip", "install", "--trusted-host", "pypi.python.org", "--trusted-host", "files.pythonhosted.org", "--trusted-host", "pypi.org", "-U", "--only-binary", ":all:"] # check if the pip module is available try: importlib.import_module("pip") except: # install pip with ensurepip subprocess.run([py_bin, "-B", "-m", "ensurepip"]) subprocess.run(pip_install + ["pip", "wheel", "setuptools"]) # install the rest of the modules if (mod_names != []): for mod_name in mod_names: # normal module installation subprocess.run(pip_install + [mod_name]) return True return False # all blenxy custom modules BLENXY_MODULES = ["basic_settings", # user settings blenxy has "collada_superbmd_import", # custom importer for SuperBMD collada files "collada_superbmd_export", # custom exporter for SuperBMD collada files "obj_kcl_export", # custom exporter for OBJ files (collision) "obj_neokclcreate_import", # custom importer for OBJ files (collision, NeoKCLCreate) "bck_import", # custom importer for SMG BCK files "bck_export", # custom exporter for SMG BCK files "bcsv_editing"] # custom interface for BCSV loading # function used to refresh blenxy's custom modules # so that they can be updated without closing blender @bpy.app.handlers.persistent def unload_blenxy_stuff(dummy): # execute the unregister functions from each module # these functions won't die if the stuff to unregister isn't there for mod_name in BLENXY_MODULES: mod = importlib.import_module("." + mod_name, __package__) mod.unregister() # reload the modules in case they were modified (dev stuff) for mod_name in BLENXY_MODULES: mod = importlib.import_module("." + mod_name, __package__) importlib.reload(mod) # register function that blender will call when the template is loaded def register(): # print the welcome print("\nWelcome to Blenxy!") print("Running on Blender: %s" % (bpy.app.version.__str__())) print("Using interpreter: %s\n" % (find_python_interpreter())) # "fix" python3.7/lib/python3.7/ctypes/__init__.py ctypes_path = importlib.__path__[0] # I assume this path is alright ctypes_path = file_ops.get_path_str(ctypes_path.replace("importlib", "ctypes") + "/__init__.py") f = open(ctypes_path, "r", encoding = "utf-8") all_lines = f.readlines() f.close() # comment this line out # https://projects.blender.org/blender/blender/issues/84752 needs_update = False for i in range(len(all_lines)): if ((all_lines[i].startswith("#") == False) and ("CFUNCTYPE(c_int)(lambda: None)" in all_lines[i])): all_lines[i] = "#" + all_lines[i] needs_update = True break # save the file if (needs_update): print("Patching %s..." % (ctypes_path)) f = open(ctypes_path, "w", encoding = "utf-8") for line in all_lines: f.write(line) f.close() # checking python modules if (new_mod_install(new_mod_check(NEEDED_MODULE_NAMES)) == True): print("New modules installed. Exiting...") exit(0) for mod_name in NEEDED_MODULE_NAMES: mod = importlib.import_module(mod_name) print("%s %s is installed!" % (mod_name, mod.__version__)) # add this function to load_post first bpy.app.handlers.load_post.append(unload_blenxy_stuff) # add the register functions to load_post for mod_name in BLENXY_MODULES: mod = importlib.import_module("." + mod_name, __package__) bpy.app.handlers.load_post.append(mod.register) # unregister function that blender will call when a new template is loaded def unregister(): # print the goodbye print("\nLeaving Blenxy!\n") # remove the stuff added to the load_post list bpy.app.handlers.load_post.remove(unload_blenxy_stuff) for mod_name in BLENXY_MODULES: mod = importlib.import_module("." + mod_name, __package__) for func in bpy.app.handlers.load_post: if (mod.__name__ in func.__module__): bpy.app.handlers.load_post.remove(func) break # execute module's unregister functions for mod_name in BLENXY_MODULES: mod = importlib.import_module("." + mod_name, __package__) mod.unregister()