summaryrefslogtreecommitdiff
path: root/__init__.py
blob: 0e6316ce59c33f84ae901520b1842c59622303df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# 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()