561daa34fd
Fixes bug where compilation server will delete krom.js if it exists during first launch.
717 lines
27 KiB
Python
Executable file
717 lines
27 KiB
Python
Executable file
import glob
|
|
import json
|
|
import os
|
|
import shutil
|
|
import time
|
|
import stat
|
|
import subprocess
|
|
import threading
|
|
import webbrowser
|
|
import shlex
|
|
|
|
import bpy
|
|
|
|
import arm.assets as assets
|
|
from arm.exporter import ArmoryExporter
|
|
import arm.lib.make_datas
|
|
import arm.lib.server
|
|
import arm.log as log
|
|
import arm.make_logic as make_logic
|
|
import arm.make_renderpath as make_renderpath
|
|
import arm.make_state as state
|
|
import arm.make_world as make_world
|
|
import arm.utils
|
|
import arm.write_data as write_data
|
|
|
|
scripts_mtime = 0 # Monitor source changes
|
|
profile_time = 0
|
|
|
|
def run_proc(cmd, done):
|
|
def fn(p, done):
|
|
p.wait()
|
|
if done != None:
|
|
done()
|
|
p = subprocess.Popen(cmd)
|
|
threading.Thread(target=fn, args=(p, done)).start()
|
|
return p
|
|
|
|
def compile_shader_pass(res, raw_shaders_path, shader_name, defs, make_variants):
|
|
os.chdir(raw_shaders_path + '/' + shader_name)
|
|
|
|
# Open json file
|
|
json_name = shader_name + '.json'
|
|
with open(json_name) as f:
|
|
json_file = f.read()
|
|
json_data = json.loads(json_file)
|
|
|
|
fp = arm.utils.get_fp_build()
|
|
arm.lib.make_datas.make(res, shader_name, json_data, fp, defs, make_variants)
|
|
|
|
path = fp + '/compiled/Shaders'
|
|
c = json_data['contexts'][0]
|
|
for s in ['vertex_shader', 'fragment_shader', 'geometry_shader', 'tesscontrol_shader', 'tesseval_shader']:
|
|
if s in c:
|
|
shutil.copy(c[s], path + '/' + c[s].split('/')[-1])
|
|
|
|
def remove_readonly(func, path, excinfo):
|
|
os.chmod(path, stat.S_IWRITE)
|
|
func(path)
|
|
|
|
def export_data(fp, sdk_path):
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
print('\n' + '_' * 10 + ' [Armory] Compiling ' + '_' * 10)
|
|
if wrd.arm_verbose_output:
|
|
print('\nArmory v{0} ({1})'.format(wrd.arm_version, wrd.arm_commit))
|
|
print('OS: ' + arm.utils.get_os() + ', Target: ' + state.target + ', GAPI: ' + arm.utils.get_gapi() + ', Blender: ' + bpy.app.version_string)
|
|
|
|
# Clean compiled variants if cache is disabled
|
|
build_dir = arm.utils.get_fp_build()
|
|
if not wrd.arm_cache_build:
|
|
if os.path.isdir(build_dir + '/debug/html5-resources'):
|
|
shutil.rmtree(build_dir + '/debug/html5-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/krom-resources'):
|
|
shutil.rmtree(build_dir + '/krom-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/debug/krom-resources'):
|
|
shutil.rmtree(build_dir + '/debug/krom-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/windows-resources'):
|
|
shutil.rmtree(build_dir + '/windows-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/linux-resources'):
|
|
shutil.rmtree(build_dir + '/linux-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/osx-resources'):
|
|
shutil.rmtree(build_dir + '/osx-resources', onerror=remove_readonly)
|
|
if os.path.isdir(build_dir + '/compiled/Shaders'):
|
|
shutil.rmtree(build_dir + '/compiled/Shaders', onerror=remove_readonly)
|
|
|
|
raw_shaders_path = sdk_path + '/armory/Shaders/'
|
|
assets_path = sdk_path + '/armory/Assets/'
|
|
export_physics = bpy.data.worlds['Arm'].arm_physics != 'Disabled'
|
|
export_navigation = bpy.data.worlds['Arm'].arm_navigation != 'Disabled'
|
|
export_ui = bpy.data.worlds['Arm'].arm_ui != 'Disabled'
|
|
assets.reset()
|
|
|
|
# Build node trees
|
|
ArmoryExporter.import_traits = []
|
|
make_logic.build()
|
|
make_world.build()
|
|
make_renderpath.build()
|
|
|
|
# Export scene data
|
|
assets.embedded_data = sorted(list(set(assets.embedded_data)))
|
|
physics_found = False
|
|
navigation_found = False
|
|
ui_found = False
|
|
ArmoryExporter.compress_enabled = state.is_publish and wrd.arm_asset_compression
|
|
ArmoryExporter.optimize_enabled = state.is_publish and wrd.arm_optimize_data
|
|
if not os.path.exists(build_dir + '/compiled/Assets'):
|
|
os.makedirs(build_dir + '/compiled/Assets')
|
|
# have a "zoo" collection in the current scene
|
|
export_coll = bpy.data.collections.new("export_coll")
|
|
bpy.context.scene.collection.children.link(export_coll)
|
|
for scene in bpy.data.scenes:
|
|
if scene == bpy.context.scene: continue
|
|
for o in scene.collection.all_objects:
|
|
if o.type == "MESH" or o.type == "EMPTY":
|
|
if o.name not in export_coll.all_objects.keys():
|
|
export_coll.objects.link(o)
|
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
|
bpy.data.collections.remove(export_coll) # destroy "zoo" collection
|
|
|
|
for scene in bpy.data.scenes:
|
|
if scene.arm_export:
|
|
ext = '.lz4' if ArmoryExporter.compress_enabled else '.arm'
|
|
asset_path = build_dir + '/compiled/Assets/' + arm.utils.safestr(scene.name) + ext
|
|
ArmoryExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=depsgraph)
|
|
if ArmoryExporter.export_physics:
|
|
physics_found = True
|
|
if ArmoryExporter.export_navigation:
|
|
navigation_found = True
|
|
if ArmoryExporter.export_ui:
|
|
ui_found = True
|
|
assets.add(asset_path)
|
|
|
|
if physics_found == False: # Disable physics if no rigid body is exported
|
|
export_physics = False
|
|
|
|
if navigation_found == False:
|
|
export_navigation = False
|
|
|
|
if ui_found == False:
|
|
export_ui = False
|
|
|
|
if wrd.arm_ui == 'Enabled':
|
|
export_ui = True
|
|
|
|
modules = []
|
|
if wrd.arm_audio == 'Enabled':
|
|
modules.append('audio')
|
|
if export_physics:
|
|
modules.append('physics')
|
|
if export_navigation:
|
|
modules.append('navigation')
|
|
if export_ui:
|
|
modules.append('ui')
|
|
|
|
defs = arm.utils.def_strings_to_array(wrd.world_defs)
|
|
cdefs = arm.utils.def_strings_to_array(wrd.compo_defs)
|
|
|
|
if wrd.arm_verbose_output:
|
|
print('Exported modules:', modules)
|
|
print('Shader flags:', defs)
|
|
print('Compositor flags:', cdefs)
|
|
print('Khafile flags:', assets.khafile_defs)
|
|
|
|
# Render path is configurable at runtime
|
|
has_config = wrd.arm_write_config or os.path.exists(arm.utils.get_fp() + '/Bundled/config.arm')
|
|
|
|
# Write compiled.inc
|
|
shaders_path = build_dir + '/compiled/Shaders'
|
|
if not os.path.exists(shaders_path):
|
|
os.makedirs(shaders_path)
|
|
write_data.write_compiledglsl(defs + cdefs, make_variants=has_config)
|
|
|
|
# Write referenced shader passes
|
|
if not os.path.isfile(build_dir + '/compiled/Shaders/shader_datas.arm') or state.last_world_defs != wrd.world_defs:
|
|
res = {'shader_datas': []}
|
|
|
|
for ref in assets.shader_passes:
|
|
# Ensure shader pass source exists
|
|
if not os.path.exists(raw_shaders_path + '/' + ref):
|
|
continue
|
|
assets.shader_passes_assets[ref] = []
|
|
if ref.startswith('compositor_pass'):
|
|
compile_shader_pass(res, raw_shaders_path, ref, defs + cdefs, make_variants=has_config)
|
|
else:
|
|
compile_shader_pass(res, raw_shaders_path, ref, defs, make_variants=has_config)
|
|
|
|
# Workaround to also export non-material world shaders
|
|
res['shader_datas'] += make_world.shader_datas
|
|
|
|
arm.utils.write_arm(shaders_path + '/shader_datas.arm', res)
|
|
|
|
for ref in assets.shader_passes:
|
|
for s in assets.shader_passes_assets[ref]:
|
|
assets.add_shader(shaders_path + '/' + s + '.glsl')
|
|
for file in assets.shaders_external:
|
|
name = file.split('/')[-1].split('\\')[-1]
|
|
target = build_dir + '/compiled/Shaders/' + name
|
|
if not os.path.exists(target):
|
|
shutil.copy(file, target)
|
|
state.last_world_defs = wrd.world_defs
|
|
|
|
# Reset path
|
|
os.chdir(fp)
|
|
|
|
# Copy std shaders
|
|
if not os.path.isdir(build_dir + '/compiled/Shaders/std'):
|
|
shutil.copytree(raw_shaders_path + 'std', build_dir + '/compiled/Shaders/std')
|
|
|
|
# Write config.arm
|
|
resx, resy = arm.utils.get_render_resolution(arm.utils.get_active_scene())
|
|
if wrd.arm_write_config:
|
|
write_data.write_config(resx, resy)
|
|
|
|
# Write khafile.js
|
|
enable_dce = state.is_publish and wrd.arm_dce
|
|
import_logic = not state.is_publish and arm.utils.logic_editor_space() != None
|
|
write_data.write_khafilejs(state.is_play, export_physics, export_navigation, export_ui, state.is_publish, enable_dce, ArmoryExporter.import_traits, import_logic)
|
|
|
|
# Write Main.hx - depends on write_khafilejs for writing number of assets
|
|
scene_name = arm.utils.get_project_scene_name()
|
|
write_data.write_mainhx(scene_name, resx, resy, state.is_play, state.is_publish)
|
|
if scene_name != state.last_scene or resx != state.last_resx or resy != state.last_resy:
|
|
wrd.arm_recompile = True
|
|
state.last_resx = resx
|
|
state.last_resy = resy
|
|
state.last_scene = scene_name
|
|
|
|
def compile(assets_only=False):
|
|
wrd = bpy.data.worlds['Arm']
|
|
fp = arm.utils.get_fp()
|
|
os.chdir(fp)
|
|
|
|
# Set build command
|
|
target_name = state.target
|
|
|
|
node_path = arm.utils.get_node_path()
|
|
khamake_path = arm.utils.get_khamake_path()
|
|
cmd = [node_path, khamake_path]
|
|
|
|
kha_target_name = arm.utils.get_kha_target(target_name)
|
|
if kha_target_name != '':
|
|
cmd.append(kha_target_name)
|
|
|
|
# Custom exporter
|
|
if state.is_export:
|
|
item = wrd.arm_exporterlist[wrd.arm_exporterlist_index]
|
|
if item.arm_project_target == 'custom' and item.arm_project_khamake != '':
|
|
for s in item.arm_project_khamake.split(' '):
|
|
cmd.append(s)
|
|
|
|
ffmpeg_path = arm.utils.get_ffmpeg_path() # Path to binary
|
|
if ffmpeg_path != '':
|
|
cmd.append('--ffmpeg')
|
|
cmd.append(ffmpeg_path) # '"' + ffmpeg_path + '"'
|
|
|
|
state.export_gapi = arm.utils.get_gapi()
|
|
cmd.append('-g')
|
|
cmd.append(state.export_gapi)
|
|
|
|
if arm.utils.get_legacy_shaders() or 'ios' in state.target:
|
|
if 'html5' in state.target or 'ios' in state.target:
|
|
pass
|
|
else:
|
|
cmd.append('--shaderversion')
|
|
cmd.append('110')
|
|
elif 'android' in state.target or 'html5' in state.target:
|
|
cmd.append('--shaderversion')
|
|
cmd.append('300')
|
|
else:
|
|
cmd.append('--shaderversion')
|
|
cmd.append('330')
|
|
|
|
if '_VR' in wrd.world_defs:
|
|
cmd.append('--vr')
|
|
cmd.append('webvr')
|
|
|
|
if arm.utils.get_rp().rp_renderer == 'Raytracer':
|
|
cmd.append('--raytrace')
|
|
cmd.append('dxr')
|
|
dxc_path = fp + '/HlslShaders/dxc.exe'
|
|
subprocess.Popen([dxc_path, '-Zpr', '-Fo', fp + '/Bundled/raytrace.cso', '-T', 'lib_6_3', fp + '/HlslShaders/raytrace.hlsl']).wait()
|
|
|
|
if arm.utils.get_khamake_threads() > 1:
|
|
cmd.append('--parallelAssetConversion')
|
|
cmd.append(str(arm.utils.get_khamake_threads()))
|
|
|
|
compilation_server = False
|
|
|
|
cmd.append('--to')
|
|
if (kha_target_name == 'krom' and not state.is_publish) or (kha_target_name == 'html5' and not state.is_publish):
|
|
cmd.append(arm.utils.build_dir() + '/debug')
|
|
# Start compilation server
|
|
if kha_target_name == 'krom' and arm.utils.get_compilation_server() and not assets_only and wrd.arm_cache_build:
|
|
compilation_server = True
|
|
arm.lib.server.run_haxe(arm.utils.get_haxe_path())
|
|
else:
|
|
cmd.append(arm.utils.build_dir())
|
|
|
|
if not wrd.arm_verbose_output:
|
|
cmd.append("--quiet")
|
|
else:
|
|
print("Using project from " + arm.utils.get_fp())
|
|
print("Running: ", cmd)
|
|
|
|
#Project needs to be compiled at least once
|
|
#before compilation server can work
|
|
if not os.path.exists(arm.utils.build_dir() + '/debug/krom/krom.js') and not state.is_publish:
|
|
state.proc_build = run_proc(cmd, build_done)
|
|
else:
|
|
if assets_only or compilation_server:
|
|
cmd.append('--nohaxe')
|
|
cmd.append('--noproject')
|
|
state.proc_build = run_proc(cmd, assets_done if compilation_server else build_done)
|
|
|
|
|
|
def build(target, is_play=False, is_publish=False, is_export=False):
|
|
global profile_time
|
|
profile_time = time.time()
|
|
|
|
state.target = target
|
|
state.is_play = is_play
|
|
state.is_publish = is_publish
|
|
state.is_export = is_export
|
|
|
|
# Save blend
|
|
if arm.utils.get_save_on_build():
|
|
bpy.ops.wm.save_mainfile()
|
|
|
|
log.clear(clear_warnings=True)
|
|
|
|
# Set camera in active scene
|
|
active_scene = arm.utils.get_active_scene()
|
|
if active_scene.camera == None:
|
|
for o in active_scene.objects:
|
|
if o.type == 'CAMERA':
|
|
active_scene.camera = o
|
|
break
|
|
|
|
# Get paths
|
|
sdk_path = arm.utils.get_sdk_path()
|
|
raw_shaders_path = sdk_path + '/armory/Shaders/'
|
|
|
|
# Set dir
|
|
fp = arm.utils.get_fp()
|
|
os.chdir(fp)
|
|
|
|
# Create directories
|
|
wrd = bpy.data.worlds['Arm']
|
|
sources_path = 'Sources/' + arm.utils.safestr(wrd.arm_project_package)
|
|
if not os.path.exists(sources_path):
|
|
os.makedirs(sources_path)
|
|
|
|
# Save external scripts edited inside Blender
|
|
write_texts = False
|
|
for text in bpy.data.texts:
|
|
if text.filepath != '' and text.is_dirty:
|
|
write_texts = True
|
|
break
|
|
if write_texts:
|
|
area = bpy.context.area
|
|
old_type = area.type
|
|
area.type = 'TEXT_EDITOR'
|
|
for text in bpy.data.texts:
|
|
if text.filepath != '' and text.is_dirty and os.path.isfile(text.filepath):
|
|
area.spaces[0].text = text
|
|
bpy.ops.text.save()
|
|
area.type = old_type
|
|
|
|
# Save internal Haxe scripts
|
|
for text in bpy.data.texts:
|
|
if text.filepath == '' and text.name[-3:] == '.hx':
|
|
with open('Sources/' + arm.utils.safestr(wrd.arm_project_package) + '/' + text.name, 'w') as f:
|
|
f.write(text.as_string())
|
|
|
|
# Export data
|
|
export_data(fp, sdk_path)
|
|
|
|
if state.target == 'html5':
|
|
w, h = arm.utils.get_render_resolution(arm.utils.get_active_scene())
|
|
write_data.write_indexhtml(w, h, is_publish)
|
|
# Bundle files from include dir
|
|
if os.path.isdir('include'):
|
|
dest = '/html5/' if is_publish else '/debug/html5/'
|
|
for fn in glob.iglob(os.path.join('include', '**'), recursive=False):
|
|
shutil.copy(fn, arm.utils.build_dir() + dest + os.path.basename(fn))
|
|
|
|
def play_done():
|
|
state.proc_play = None
|
|
state.redraw_ui = True
|
|
log.clear()
|
|
|
|
def assets_done():
|
|
if state.proc_build == None:
|
|
return
|
|
result = state.proc_build.poll()
|
|
if result == 0:
|
|
# Connect to the compilation server
|
|
os.chdir(arm.utils.build_dir() + '/debug/')
|
|
cmd = [arm.utils.get_haxe_path(), '--connect', '6000', 'project-krom.hxml']
|
|
state.proc_build = run_proc(cmd, compilation_server_done)
|
|
else:
|
|
state.proc_build = None
|
|
state.redraw_ui = True
|
|
log.error('Build failed, check console')
|
|
|
|
def compilation_server_done():
|
|
if state.proc_build == None:
|
|
return
|
|
result = state.proc_build.poll()
|
|
if result == 0:
|
|
build_done()
|
|
else:
|
|
state.proc_build = None
|
|
state.redraw_ui = True
|
|
log.error('Build failed, check console')
|
|
|
|
def build_done():
|
|
print('Finished in ' + str(time.time() - profile_time))
|
|
if log.num_warnings > 0:
|
|
log.print_warn(f'{log.num_warnings} warnings occurred during compilation')
|
|
if state.proc_build is None:
|
|
return
|
|
result = state.proc_build.poll()
|
|
state.proc_build = None
|
|
state.redraw_ui = True
|
|
if result == 0:
|
|
bpy.data.worlds['Arm'].arm_recompile = False
|
|
build_success()
|
|
else:
|
|
log.error('Build failed, check console')
|
|
|
|
def patch():
|
|
if state.proc_build != None:
|
|
return
|
|
assets.invalidate_enabled = False
|
|
fp = arm.utils.get_fp()
|
|
os.chdir(fp)
|
|
asset_path = arm.utils.get_fp_build() + '/compiled/Assets/' + arm.utils.safestr(bpy.context.scene.name) + '.arm'
|
|
ArmoryExporter.export_scene(bpy.context, asset_path, scene=bpy.context.scene)
|
|
if not os.path.isdir(arm.utils.build_dir() + '/compiled/Shaders/std'):
|
|
raw_shaders_path = arm.utils.get_sdk_path() + '/armory/Shaders/'
|
|
shutil.copytree(raw_shaders_path + 'std', arm.utils.build_dir() + '/compiled/Shaders/std')
|
|
node_path = arm.utils.get_node_path()
|
|
khamake_path = arm.utils.get_khamake_path()
|
|
|
|
cmd = [node_path, khamake_path, 'krom']
|
|
cmd.extend(('--shaderversion', '330', '--parallelAssetConversion', '4',
|
|
'--to', arm.utils.build_dir() + '/debug', '--nohaxe', '--noproject'))
|
|
|
|
assets.invalidate_enabled = True
|
|
state.proc_build = run_proc(cmd, patch_done)
|
|
|
|
def patch_done():
|
|
js = 'iron.Scene.patch();'
|
|
write_patch(js)
|
|
state.proc_build = None
|
|
|
|
patch_id = 0
|
|
|
|
def write_patch(js):
|
|
global patch_id
|
|
with open(arm.utils.get_fp_build() + '/debug/krom/krom.patch', 'w') as f:
|
|
patch_id += 1
|
|
f.write(str(patch_id) + '\n')
|
|
f.write(js)
|
|
|
|
def runtime_to_target():
|
|
wrd = bpy.data.worlds['Arm']
|
|
if wrd.arm_runtime == 'Krom':
|
|
return 'krom'
|
|
else:
|
|
return 'html5'
|
|
|
|
def get_khajs_path(target):
|
|
if target == 'krom':
|
|
return arm.utils.build_dir() + '/debug/krom/krom.js'
|
|
else: # Browser
|
|
return arm.utils.build_dir() + '/debug/html5/kha.js'
|
|
|
|
def play():
|
|
global scripts_mtime
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
build(target=runtime_to_target(), is_play=True)
|
|
|
|
khajs_path = get_khajs_path(state.target)
|
|
if not wrd.arm_cache_build or \
|
|
not os.path.isfile(khajs_path) or \
|
|
assets.khafile_defs_last != assets.khafile_defs or \
|
|
state.last_target != state.target:
|
|
wrd.arm_recompile = True
|
|
|
|
state.last_target = state.target
|
|
|
|
# Trait sources modified
|
|
state.mod_scripts = []
|
|
script_path = arm.utils.get_fp() + '/Sources/' + arm.utils.safestr(wrd.arm_project_package)
|
|
if os.path.isdir(script_path):
|
|
new_mtime = scripts_mtime
|
|
for fn in glob.iglob(os.path.join(script_path, '**', '*.hx'), recursive=True):
|
|
mtime = os.path.getmtime(fn)
|
|
if scripts_mtime < mtime:
|
|
arm.utils.fetch_script_props(fn) # Trait props
|
|
fn = fn.split('Sources/')[1]
|
|
fn = fn[:-3] #.hx
|
|
fn = fn.replace('/', '.')
|
|
state.mod_scripts.append(fn)
|
|
wrd.arm_recompile = True
|
|
if new_mtime < mtime:
|
|
new_mtime = mtime
|
|
scripts_mtime = new_mtime
|
|
if len(state.mod_scripts) > 0: # Trait props
|
|
arm.utils.fetch_trait_props()
|
|
|
|
compile(assets_only=(not wrd.arm_recompile))
|
|
|
|
def build_success():
|
|
log.clear()
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
if state.is_play:
|
|
if wrd.arm_runtime == 'Browser':
|
|
# Start server
|
|
os.chdir(arm.utils.get_fp())
|
|
t = threading.Thread(name='localserver', target=arm.lib.server.run_tcp)
|
|
t.daemon = True
|
|
t.start()
|
|
html5_app_path = 'http://localhost:8040/' + arm.utils.build_dir() + '/debug/html5'
|
|
webbrowser.open(html5_app_path)
|
|
elif wrd.arm_runtime == 'Krom':
|
|
if wrd.arm_live_patch:
|
|
open(arm.utils.get_fp_build() + '/debug/krom/krom.patch', 'w').close()
|
|
krom_location, krom_path = arm.utils.krom_paths()
|
|
os.chdir(krom_location)
|
|
cmd = [krom_path, arm.utils.get_fp_build() + '/debug/krom', arm.utils.get_fp_build() + '/debug/krom-resources']
|
|
if arm.utils.get_os() == 'win':
|
|
cmd.append('--consolepid')
|
|
cmd.append(str(os.getpid()))
|
|
if wrd.arm_audio == 'Disabled':
|
|
cmd.append('--nosound')
|
|
state.proc_play = run_proc(cmd, play_done)
|
|
|
|
elif state.is_publish:
|
|
sdk_path = arm.utils.get_sdk_path()
|
|
target_name = arm.utils.get_kha_target(state.target)
|
|
files_path = os.path.join(arm.utils.get_fp_build(), target_name)
|
|
|
|
if (target_name == 'html5' or target_name == 'krom') and wrd.arm_minify_js:
|
|
# Minify JS
|
|
minifier_path = sdk_path + '/lib/armory_tools/uglifyjs/bin/uglifyjs'
|
|
if target_name == 'html5':
|
|
jsfile = files_path + '/kha.js'
|
|
else:
|
|
jsfile = files_path + '/krom.js'
|
|
args = [arm.utils.get_node_path(), minifier_path, jsfile, '-o', jsfile]
|
|
proc = subprocess.Popen(args)
|
|
proc.wait()
|
|
|
|
if target_name == 'krom':
|
|
# Copy Krom binaries
|
|
if state.target == 'krom-windows':
|
|
gapi = state.export_gapi
|
|
ext = '' if gapi == 'direct3d11' else '_' + gapi
|
|
krom_location = sdk_path + '/Krom/Krom' + ext + '.exe'
|
|
shutil.copy(krom_location, files_path + '/Krom.exe')
|
|
krom_exe = arm.utils.safestr(wrd.arm_project_name) + '.exe'
|
|
os.rename(files_path + '/Krom.exe', files_path + '/' + krom_exe)
|
|
elif state.target == 'krom-linux':
|
|
krom_location = sdk_path + '/Krom/Krom'
|
|
shutil.copy(krom_location, files_path)
|
|
krom_exe = arm.utils.safestr(wrd.arm_project_name)
|
|
os.rename(files_path + '/Krom', files_path + '/' + krom_exe)
|
|
krom_exe = './' + krom_exe
|
|
else:
|
|
krom_location = sdk_path + '/Krom/Krom.app'
|
|
shutil.copytree(krom_location, files_path + '/Krom.app')
|
|
game_files = os.listdir(files_path)
|
|
for f in game_files:
|
|
f = files_path + '/' + f
|
|
if os.path.isfile(f):
|
|
shutil.move(f, files_path + '/Krom.app/Contents/MacOS')
|
|
krom_exe = arm.utils.safestr(wrd.arm_project_name) + '.app'
|
|
os.rename(files_path + '/Krom.app', files_path + '/' + krom_exe)
|
|
|
|
# Rename
|
|
ext = state.target.split('-')[-1] # krom-windows
|
|
new_files_path = files_path + '-' + ext
|
|
os.rename(files_path, new_files_path)
|
|
files_path = new_files_path
|
|
|
|
if target_name == 'html5':
|
|
project_path = files_path
|
|
print('Exported HTML5 package to ' + project_path)
|
|
elif target_name.startswith('ios') or target_name.startswith('osx'): # TODO: to macos
|
|
project_path = files_path + '-build'
|
|
print('Exported XCode project to ' + project_path)
|
|
elif target_name.startswith('windows'):
|
|
project_path = files_path + '-build'
|
|
print('Exported Visual Studio 2017 project to ' + project_path)
|
|
elif target_name.startswith('android'):
|
|
project_path = os.path.join(files_path + '-build', arm.utils.safestr(wrd.arm_project_name))
|
|
print('Exported Android Studio project to ' + project_path)
|
|
elif target_name.startswith('krom'):
|
|
project_path = files_path
|
|
print('Exported Krom package to ' + project_path)
|
|
else:
|
|
project_path = files_path + '-build'
|
|
print('Exported makefiles to ' + project_path)
|
|
|
|
if arm.utils.get_arm_preferences().open_build_directory:
|
|
arm.utils.open_folder(project_path)
|
|
|
|
# Android build APK
|
|
if (arm.utils.get_project_android_build_apk()) and (len(arm.utils.get_android_sdk_root_path()) > 0):
|
|
print("\nBuilding APK")
|
|
# Check settings
|
|
path_sdk = arm.utils.get_android_sdk_root_path()
|
|
if len(path_sdk) > 0:
|
|
# Check Environment Variables - ANDROID_SDK_ROOT
|
|
if os.getenv('ANDROID_SDK_ROOT') == None:
|
|
# Set value from settings
|
|
os.environ['ANDROID_SDK_ROOT'] = path_sdk
|
|
else:
|
|
project_path = ''
|
|
|
|
# Build start
|
|
if len(project_path) > 0:
|
|
os.chdir(project_path) # set work folder
|
|
if arm.utils.get_os_is_windows():
|
|
state.proc_publish_build = run_proc(os.path.join(project_path, "gradlew.bat assembleDebug"), done_gradlew_build)
|
|
else:
|
|
cmd = shlex.split(os.path.join(project_path, "gradlew assembleDebug"))
|
|
state.proc_publish_build = run_proc(cmd, done_gradlew_build)
|
|
else:
|
|
print('\nBuilding APK Warning: ANDROID_SDK_ROOT is not specified in environment variables and "Android SDK Path" setting is not specified in preferences: \n- If you specify an environment variable ANDROID_SDK_ROOT, then you need to restart Blender;\n- If you specify the setting "Android SDK Path" in the preferences, then repeat operation "Publish"')
|
|
|
|
def done_gradlew_build():
|
|
if state.proc_publish_build == None:
|
|
return
|
|
result = state.proc_publish_build.poll()
|
|
if result == 0:
|
|
state.proc_publish_build = None
|
|
|
|
wrd = bpy.data.worlds['Arm']
|
|
path_apk = os.path.join(arm.utils.get_fp_build(), arm.utils.get_kha_target(state.target))
|
|
path_apk = os.path.join(path_apk + '-build', arm.utils.safestr(wrd.arm_project_name), "app", "build", "outputs", "apk", "debug")
|
|
|
|
print("\nBuild APK to " + path_apk)
|
|
# Open directory with APK
|
|
if arm.utils.get_android_open_build_apk_directory():
|
|
arm.utils.open_folder(path_apk)
|
|
# Running emulator
|
|
if wrd.arm_project_android_run_avd:
|
|
run_android_emulators(arm.utils.get_android_emulator_name())
|
|
state.redraw_ui = True
|
|
else:
|
|
state.proc_publish_build = None
|
|
state.redraw_ui = True
|
|
os.environ['ANDROID_SDK_ROOT'] = ''
|
|
log.error('Building the APK failed, check console')
|
|
|
|
def run_android_emulators(avd_name):
|
|
if len(avd_name.strip()) == 0:
|
|
return
|
|
print('\nRunning Emulator "'+ avd_name +'"')
|
|
path_file = arm.utils.get_android_emulator_file()
|
|
if len(path_file) > 0:
|
|
if arm.utils.get_os_is_windows():
|
|
run_proc(path_file + " -avd "+ avd_name, None)
|
|
else:
|
|
cmd = shlex.split(path_file + " -avd "+ avd_name)
|
|
run_proc(cmd, None)
|
|
else:
|
|
print('Update List Emulators Warning: File "'+ path_file +'" not found. Check that the variable ANDROID_SDK_ROOT is correct in environment variables or in "Android SDK Path" setting: \n- If you specify an environment variable ANDROID_SDK_ROOT, then you need to restart Blender;\n- If you specify the setting "Android SDK Path", then repeat operation "Publish"')
|
|
|
|
def clean():
|
|
os.chdir(arm.utils.get_fp())
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
# Remove build and compiled data
|
|
try:
|
|
if os.path.isdir(arm.utils.build_dir()):
|
|
shutil.rmtree(arm.utils.build_dir(), onerror=remove_readonly)
|
|
if os.path.isdir(arm.utils.get_fp() + '/build'): # Kode Studio build dir
|
|
shutil.rmtree(arm.utils.get_fp() + '/build', onerror=remove_readonly)
|
|
except:
|
|
print('Armory Warning: Some files in the build folder are locked')
|
|
|
|
# Remove compiled nodes
|
|
pkg_dir = arm.utils.safestr(wrd.arm_project_package).replace('.', '/')
|
|
nodes_path = 'Sources/' + pkg_dir + '/node/'
|
|
if os.path.isdir(nodes_path):
|
|
shutil.rmtree(nodes_path, onerror=remove_readonly)
|
|
|
|
# Remove khafile/Main.hx
|
|
if os.path.isfile('khafile.js'):
|
|
os.remove('khafile.js')
|
|
if os.path.isfile('Sources/Main.hx'):
|
|
os.remove('Sources/Main.hx')
|
|
|
|
# Remove Sources/ dir if empty
|
|
if os.path.exists('Sources/' + pkg_dir) and os.listdir('Sources/' + pkg_dir) == []:
|
|
shutil.rmtree('Sources/' + pkg_dir, onerror=remove_readonly)
|
|
if os.path.exists('Sources') and os.listdir('Sources') == []:
|
|
shutil.rmtree('Sources/', onerror=remove_readonly)
|
|
|
|
# To recache signatures for batched materials
|
|
for mat in bpy.data.materials:
|
|
mat.signature = ''
|
|
mat.arm_cached = False
|
|
|
|
# Restart compilation server
|
|
if arm.utils.get_compilation_server():
|
|
arm.lib.server.kill_haxe()
|
|
|
|
print('Project cleaned')
|