forked from LeenkxTeam/LNXSDK
Patch_2
This commit is contained in:
@ -586,6 +586,298 @@ def play_done():
|
||||
log.clear()
|
||||
live_patch.stop()
|
||||
|
||||
|
||||
_viewport_processes = {}
|
||||
|
||||
def _generate_viewport_id(space_data=None):
|
||||
"""Generate a unique viewport ID from space_data pointer or random."""
|
||||
if space_data is not None:
|
||||
try:
|
||||
return hex(space_data.as_pointer())[-6:]
|
||||
except:
|
||||
pass
|
||||
import random
|
||||
return hex(random.randint(0, 0xFFFFFF))[2:].zfill(6)
|
||||
|
||||
def _get_viewport_shmem_name(viewport_id):
|
||||
"""Get shared memory name for a specific viewport."""
|
||||
return f"KROM_VIEWPORT_FB_{viewport_id}"
|
||||
|
||||
def _kill_viewport_process(viewport_id):
|
||||
"""Kill a specific viewport's Krom process."""
|
||||
global _viewport_processes
|
||||
|
||||
if viewport_id in _viewport_processes:
|
||||
proc = _viewport_processes[viewport_id]
|
||||
try:
|
||||
proc.terminate()
|
||||
proc.wait(timeout=2)
|
||||
except:
|
||||
try:
|
||||
proc.kill()
|
||||
except:
|
||||
pass
|
||||
del _viewport_processes[viewport_id]
|
||||
|
||||
def _kill_all_viewport_processes():
|
||||
"""Kill all viewport Krom processes."""
|
||||
global _viewport_processes
|
||||
|
||||
for viewport_id in list(_viewport_processes.keys()):
|
||||
_kill_viewport_process(viewport_id)
|
||||
|
||||
if lnx.utils.get_os() == 'win':
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['tasklist', '/FI', 'IMAGENAME eq Krom.exe', '/FO', 'CSV', '/NH'],
|
||||
capture_output=True, text=True, timeout=5
|
||||
)
|
||||
if 'Krom.exe' in result.stdout:
|
||||
subprocess.run(['taskkill', '/F', '/IM', 'Krom.exe'],
|
||||
capture_output=True, timeout=5)
|
||||
import time
|
||||
time.sleep(0.3)
|
||||
except:
|
||||
pass
|
||||
|
||||
def run_viewport_runtime(viewport_id, width=1920, height=1080):
|
||||
"""Launch a viewport which gets its own Krom process with unique shared memory."""
|
||||
global _viewport_processes
|
||||
|
||||
if 'Lnx' not in bpy.data.worlds:
|
||||
log.warn('No Lnx world found - cannot start viewport server')
|
||||
return None, None
|
||||
|
||||
_kill_viewport_process(viewport_id)
|
||||
|
||||
shmem_name = _get_viewport_shmem_name(viewport_id)
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
krom_location, krom_path = lnx.utils.krom_paths()
|
||||
path = lnx.utils.get_fp_build() + '/debug/krom'
|
||||
path_resources = path + '-resources'
|
||||
|
||||
if not os.path.exists(path + '/krom.js'):
|
||||
log.warn(f'Krom build not found at {path}/krom.js - build project first')
|
||||
return None, None
|
||||
|
||||
os.chdir(krom_location)
|
||||
|
||||
cmd = [krom_path, path, path_resources]
|
||||
if lnx.utils.get_os() == 'win':
|
||||
cmd.append('--consolepid')
|
||||
cmd.append(str(os.getpid()))
|
||||
if wrd.lnx_audio == 'Disabled':
|
||||
cmd.append('--nosound')
|
||||
|
||||
cmd.append('--viewport-server')
|
||||
cmd.append('--shmem')
|
||||
cmd.append(shmem_name)
|
||||
cmd.append('--viewport-width')
|
||||
cmd.append(str(width))
|
||||
cmd.append('--viewport-height')
|
||||
cmd.append(str(height))
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(cmd)
|
||||
_viewport_processes[viewport_id] = proc
|
||||
log.info(f'Started: {viewport_id} (shmem={shmem_name})')
|
||||
return proc, shmem_name
|
||||
except Exception as e:
|
||||
log.error(f'Failed to start viewport runtime: {e}')
|
||||
return None, None
|
||||
|
||||
def stop_viewport_runtime(viewport_id):
|
||||
"""Stop a specific viewport's Krom process."""
|
||||
_kill_viewport_process(viewport_id)
|
||||
|
||||
_viewport_build_in_progress = False
|
||||
_viewport_pending_launches = [] # List of (viewport_id, width, height) tuples
|
||||
_viewport_proc_build = None # Separate process tracker for viewport builds
|
||||
|
||||
def build_viewport(viewport_id, width=1920, height=1080):
|
||||
"""Build project for viewport"""
|
||||
global _viewport_build_in_progress, _viewport_pending_launches, profile_time
|
||||
|
||||
wrd = bpy.data.worlds.get('Lnx')
|
||||
if not wrd:
|
||||
log.warn('No Lnx world found - cannot build for viewport')
|
||||
return
|
||||
|
||||
krom_js_path = lnx.utils.get_fp_build() + '/debug/krom/krom.js'
|
||||
if os.path.exists(krom_js_path) and not wrd.lnx_recompile:
|
||||
log.info(f'Using cached viewport build for {viewport_id}')
|
||||
run_viewport_runtime(viewport_id, width, height)
|
||||
return
|
||||
|
||||
pending_entry = (viewport_id, width, height)
|
||||
if pending_entry not in _viewport_pending_launches:
|
||||
_viewport_pending_launches.append(pending_entry)
|
||||
log.info(f'Queued viewport {viewport_id} for launch after build')
|
||||
|
||||
# If a build is already in progress and there is an actual build process, wait
|
||||
# _viewport_proc_build checks viewport ,not state.proc_build (which is for play button)
|
||||
if _viewport_build_in_progress:
|
||||
if _viewport_proc_build is not None and _viewport_proc_build.poll() is None:
|
||||
# log.info(f'Build in progress: {viewport_id} - launching when ready')
|
||||
return
|
||||
else:
|
||||
log.info(f'Resetting stale viewport build state')
|
||||
_viewport_build_in_progress = False
|
||||
|
||||
_viewport_build_in_progress = True
|
||||
profile_time = time.time()
|
||||
|
||||
log.info(f'Starting viewport build for {len(_viewport_pending_launches)} viewport(s)')
|
||||
|
||||
# Set viewport mode flags but not the is_play flag meant for external launcher
|
||||
state.is_viewport = True
|
||||
state.viewport_width = width
|
||||
state.viewport_height = height
|
||||
state.target = 'krom'
|
||||
state.is_play = False # NOT play mode
|
||||
state.is_publish = False
|
||||
state.is_export = False
|
||||
|
||||
log.clear(clear_warnings=True, clear_errors=True)
|
||||
|
||||
sdk_path = lnx.utils.get_sdk_path()
|
||||
fp = lnx.utils.get_fp()
|
||||
os.chdir(fp)
|
||||
|
||||
sources_path = 'Sources/' + lnx.utils.safestr(wrd.lnx_project_package)
|
||||
if not os.path.exists(sources_path):
|
||||
os.makedirs(sources_path)
|
||||
|
||||
log.info('Exporting scene data...')
|
||||
export_data(fp, sdk_path)
|
||||
|
||||
log.info('Starting Krom compilation for viewport...')
|
||||
compile_viewport(assets_only=(not wrd.lnx_recompile))
|
||||
|
||||
def compile_viewport(assets_only=False):
|
||||
"""Compile for viewport mode using separate process tracking."""
|
||||
global _viewport_proc_build
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
fp = lnx.utils.get_fp()
|
||||
os.chdir(fp)
|
||||
|
||||
node_path = lnx.utils.get_node_path()
|
||||
khamake_path = lnx.utils.get_khamake_path()
|
||||
cmd = [node_path, khamake_path, 'krom']
|
||||
|
||||
ffmpeg_path = lnx.utils.get_ffmpeg_path()
|
||||
if ffmpeg_path not in (None, ''):
|
||||
cmd.append('--ffmpeg')
|
||||
cmd.append(ffmpeg_path)
|
||||
|
||||
cmd.append('-g')
|
||||
cmd.append(lnx.utils.get_gapi())
|
||||
cmd.append('--shaderversion')
|
||||
cmd.append('330')
|
||||
|
||||
if lnx.utils.get_khamake_threads() != 1:
|
||||
cmd.append('--parallelAssetConversion')
|
||||
cmd.append(str(lnx.utils.get_khamake_threads()))
|
||||
|
||||
cmd.append('--to')
|
||||
cmd.append(lnx.utils.build_dir() + '/debug')
|
||||
|
||||
if not wrd.lnx_verbose_output:
|
||||
cmd.append("--quiet")
|
||||
|
||||
if assets_only:
|
||||
cmd.append('--nohaxe')
|
||||
cmd.append('--noproject')
|
||||
|
||||
log.info(f'Running: {" ".join(cmd)}')
|
||||
_viewport_proc_build = run_proc(cmd, viewport_build_done)
|
||||
|
||||
def viewport_build_done():
|
||||
"""Called when viewport build completes - launches all pending Krom processes."""
|
||||
global _viewport_build_in_progress, _viewport_pending_launches, _viewport_proc_build
|
||||
|
||||
log.info('Viewport compilation finished')
|
||||
|
||||
if _viewport_proc_build is None:
|
||||
_viewport_build_in_progress = False
|
||||
return
|
||||
|
||||
result = _viewport_proc_build.poll()
|
||||
_viewport_proc_build = None
|
||||
_viewport_build_in_progress = False
|
||||
state.redraw_ui = True
|
||||
|
||||
if result == 0:
|
||||
bpy.data.worlds['Lnx'].lnx_recompile = False
|
||||
|
||||
if _viewport_pending_launches:
|
||||
pending = _viewport_pending_launches.copy()
|
||||
_viewport_pending_launches.clear()
|
||||
log.info(f'Launching {len(pending)} Krom instance(s)')
|
||||
for viewport_id, width, height in pending:
|
||||
run_viewport_runtime(viewport_id, width, height)
|
||||
else:
|
||||
log.info('No pending viewports to launch')
|
||||
else:
|
||||
_viewport_pending_launches.clear()
|
||||
log.error('Viewport build failed, check console')
|
||||
|
||||
def play_viewport(viewport_id, width=1920, height=1080):
|
||||
"""Launch Krom in a viewport"""
|
||||
global _viewport_build_in_progress, _viewport_pending_launches, _viewport_proc_build
|
||||
|
||||
if not viewport_id:
|
||||
return
|
||||
|
||||
if 'Lnx' not in bpy.data.worlds:
|
||||
return
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
|
||||
krom_js_path = lnx.utils.get_fp_build() + '/debug/krom/krom.js'
|
||||
if os.path.exists(krom_js_path) and not wrd.lnx_recompile:
|
||||
run_viewport_runtime(viewport_id, width, height)
|
||||
return
|
||||
|
||||
pending_entry = (viewport_id, width, height)
|
||||
if pending_entry not in _viewport_pending_launches:
|
||||
_viewport_pending_launches.append(pending_entry)
|
||||
|
||||
if _viewport_build_in_progress:
|
||||
if _viewport_proc_build is not None and _viewport_proc_build.poll() is None:
|
||||
log.info(f'Build in progress, viewport {viewport_id} will launch when ready')
|
||||
return
|
||||
else:
|
||||
_viewport_build_in_progress = False # Reset stale state
|
||||
|
||||
_viewport_build_in_progress = True
|
||||
|
||||
sdk_path = lnx.utils.get_sdk_path()
|
||||
fp = lnx.utils.get_fp()
|
||||
os.chdir(fp)
|
||||
|
||||
sources_path = 'Sources/' + lnx.utils.safestr(wrd.lnx_project_package)
|
||||
if not os.path.exists(sources_path):
|
||||
os.makedirs(sources_path)
|
||||
|
||||
# export data same as play() but without setting state.is_play
|
||||
state.target = 'krom'
|
||||
state.is_publish = False
|
||||
state.is_export = False
|
||||
export_data(fp, sdk_path)
|
||||
|
||||
compile_viewport(assets_only=(not wrd.lnx_recompile))
|
||||
|
||||
|
||||
def stop_viewport(viewport_id=None):
|
||||
"""Stop a specific viewport or all viewports."""
|
||||
if viewport_id:
|
||||
_kill_viewport_process(viewport_id)
|
||||
else:
|
||||
_kill_all_viewport_processes()
|
||||
|
||||
def assets_done():
|
||||
if state.proc_build == None:
|
||||
return
|
||||
@ -761,6 +1053,17 @@ def build_success():
|
||||
cmd.append(str(pid))
|
||||
if wrd.lnx_audio == 'Disabled':
|
||||
cmd.append('--nosound')
|
||||
if state.is_viewport:
|
||||
cmd.append('--viewport-server')
|
||||
cmd.append('--shmem')
|
||||
if state.viewport_id:
|
||||
cmd.append(f'KROM_VIEWPORT_FB_{state.viewport_id}')
|
||||
else:
|
||||
cmd.append('KROM_VIEWPORT_FB')
|
||||
cmd.append('--viewport-width')
|
||||
cmd.append(str(state.viewport_width))
|
||||
cmd.append('--viewport-height')
|
||||
cmd.append(str(state.viewport_height))
|
||||
|
||||
elif state.target.startswith(('windows-hl', 'linux-hl', 'macos-hl')):
|
||||
log.info(f"Runtime Hashlink/C target: {state.target}")
|
||||
|
||||
Reference in New Issue
Block a user