Compare commits

...

2 Commits

Author SHA1 Message Date
henrique 9cd6d13ca3 plugin nao funciona. deixando apenas codigo. 2 months ago
henrique 538245279e novos 2 months ago

@ -1,88 +0,0 @@
import os
import urllib.request
import shutil
from pymxs import runtime as rt
# ==========================================
# CONFIGURAÇÕES DO GITEA - IMMERSE GAMES
# ==========================================
GITEA_RAW_URL = "https://git.immersegame.com/vr4life_public/vr4life-3dmax-plugin/raw/branch/main/"
GITEA_TOKEN = "3831a0da2f87e391f41f4649d48498136a1903c9"
# Caminho onde os scripts são instalados (Documentos)
user_scripts_dir = rt.getDir(rt.name("userScripts"))
PLUGIN_DIR = os.path.join(user_scripts_dir, "VR4Life_Plugin").replace("\\", "/")
FILES_TO_DOWNLOAD = [
"vr4life_ui.py",
"vr4life_engine.py",
"vr4life_cloud.py",
"run_vr4life.py",
"vr4life_updater.py",
"install_vr4life.py",
"vr4life.mnx",
"version.txt"
]
def install_from_cloud():
rt.clearListener()
print("=== DEBUG DE CAMINHOS VR4LIFE ===")
print(f"Diretório de destino dos Pythons: {PLUGIN_DIR}")
if not os.path.exists(PLUGIN_DIR):
os.makedirs(PLUGIN_DIR)
try:
for file_name in FILES_TO_DOWNLOAD:
remote_url = f"{GITEA_RAW_URL}{file_name}?token={GITEA_TOKEN}"
local_path = os.path.join(PLUGIN_DIR, file_name).replace("\\", "/")
req = urllib.request.Request(remote_url)
req.add_header("Authorization", "token " + GITEA_TOKEN)
response = urllib.request.urlopen(req)
if file_name.endswith(".mnx"):
with open(local_path, "wb") as f:
f.write(response.read())
print(f"MNX baixado para: {local_path}")
else:
remote_code = response.read().decode('utf-8')
with open(local_path, "w", encoding="utf-8") as f:
f.write(remote_code)
print(f"Script baixado para: {local_path}")
# --- INSTALAÇÃO DO MENU ---
pasta_macros = rt.pathConfig.getDir(rt.name("userMacros"))
pasta_enu = os.path.dirname(pasta_macros)
pasta_ui_usuario = os.path.join(pasta_enu, "en-US", "UI")
if not os.path.exists(pasta_ui_usuario):
os.makedirs(pasta_ui_usuario)
# AGORA GARANTIMOS QUE O PATH DE ORIGEM É O PLUGIN_DIR
origem_mnx = os.path.join(PLUGIN_DIR, "vr4life.mnx")
destino_mnx = os.path.join(pasta_ui_usuario, "vr4life.mnx")
print(f"Tentando copiar MNX da origem: {origem_mnx}")
print(f"Para o destino final: {destino_mnx}")
if os.path.exists(origem_mnx):
shutil.copy2(origem_mnx, destino_mnx)
print(">>> Cópia do MNX realizada com sucesso!")
else:
print("!!! ERRO: O arquivo vr4life.mnx não foi encontrado na pasta PLUGIN_DIR após o download.")
# Executa o instalador local
install_script = os.path.join(PLUGIN_DIR, "install_vr4life.py").replace("\\", "/")
if os.path.exists(install_script):
print(f"Executando script de instalação: {install_script}")
rt.python.ExecuteFile(install_script)
rt.messageBox("Instalação Online concluída. Verifique o Listener para o log de caminhos.", title="VR4Life")
except Exception as e:
print(f"ERRO TÉCNICO: {str(e)}")
rt.messageBox(f"Falha na instalação: {str(e)}", title="Erro")
if __name__ == "__main__":
install_from_cloud()

@ -1,7 +0,0 @@
name "Instalador VR4Life"
version 1.0
extract to "$temp\VR4Life_Install"
run "run_installer.ms"
drop "run_installer.ms"

@ -1 +0,0 @@
python.executeFile (getDir #temp + @"\VR4Life_Install\Instalador_Online_VR4Life.py")

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<MaxMenuTransformations>
<CreateTopLevelMenu Id="167d260c-f391-4e63-b6a9-4798fbfcadc5" Title="Vr4Life"/>
<CreateMenuAction MenuId="167d260c-f391-4e63-b6a9-4798fbfcadc5" Id="a37d867e-3d05-4859-9a55-70cd394c8e72" ActionId="647394-VR4Life_Launcher`Immerse Games"/>
<CreateMenuAction MenuId="167d260c-f391-4e63-b6a9-4798fbfcadc5" Id="8df661bf-5425-4fbf-9ee3-ac14cd067b0c" ActionId="647394-VR4Life_Launcher`Immerse Games"/>
<DeleteItem Id="8df661bf-5425-4fbf-9ee3-ac14cd067b0c"/>
<DeleteItem Id="a37d867e-3d05-4859-9a55-70cd394c8e72"/>
<CreateMenuAction MenuId="167d260c-f391-4e63-b6a9-4798fbfcadc5" Id="d66e56ef-ecf4-4758-923e-b7ce929e440c" ActionId="647394-VR4Life_Launcher`Immerse Games"/>
<CreateMenuAction MenuId="167d260c-f391-4e63-b6a9-4798fbfcadc5" Id="071a64d3-3fe9-4674-b58a-b5e3047e3109" ActionId="647394-VR4Life_Update`Immerse Games"/>
</MaxMenuTransformations>

@ -122,55 +122,169 @@ def optimize_geometry(ui):
def slice_large_objects(ui, from_auto=False):
if not ui.bake_items: return
thr = ui.spn_max_sz.value(); act = 0; rt.execute("max modify mode"); tgs = ui.get_processable_items()
fn = []; pn = [d['name'] for d in tgs]
for d in ui.bake_items:
if d['name'] not in pn: fn.append(d['name'])
tot = len(tgs); ui.pb.setMaximum(tot); ui.pb.setValue(0)
thr = ui.spn_max_sz.value()
act = 0
rt.execute("max modify mode")
tgs = ui.get_processable_items()
pn = [d['name'] for d in tgs]
fn = [d['name'] for d in ui.bake_items if d['name'] not in pn]
tot = len(tgs)
ui.pb.setMaximum(tot)
ui.pb.setValue(0)
for i, d in enumerate(tgs):
if ui._is_cancelled: break
ui.pb.setFormat(f"Cortando ({i+1}/{tot}): {d['name']}..."); ui.pb.setValue(i); QtWidgets.QApplication.processEvents()
chk = [d['name']]; sc = 0
ui.pb.setFormat(f"Cortando ({i+1}/{tot}): {d['name']}...")
ui.pb.setValue(i)
QtWidgets.QApplication.processEvents()
chk = [d['name']]
sc = 0
while len(chk) > 0 and sc < 300:
QtWidgets.QApplication.processEvents()
if ui._is_cancelled: break
cn = chk.pop(0); o = rt.getNodeByName(cn)
if not o: continue
cn = chk.pop(0)
o = rt.getNodeByName(cn)
if not o or not rt.isValidNode(o):
continue
md = max(abs(o.max.x - o.min.x), abs(o.max.y - o.min.y), abs(o.max.z - o.min.z))
if md > thr:
ax = "X" if md == abs(o.max.x - o.min.x) else "Y" if md == abs(o.max.y - o.min.y) else "Z"
ms = """(
ms = f"""(
fn bsp objN ax = (
local o = getNodeByName objN; if o == undefined or not (canConvertTo o Editable_Poly) do return #()
if not isKindOf o Editable_Poly do try(convertToPoly o)catch(); if not isKindOf o Editable_Poly do return #()
local v = polyop.getNumVerts o; if v > 0 do ( try(o.weldThreshold = 0.001)catch(); try(polyop.weldVertsByThreshold o #{{1..v}})catch() )
CenterPivot o; local o2 = copy o name:(uniqueName (o.name + "_F"))
local o = getNodeByName objN
if o == undefined or not (canConvertTo o Editable_Poly) do return #()
if not isKindOf o Editable_Poly do try(convertToPoly o)catch()
if not isKindOf o Editable_Poly do return #()
local v = polyop.getNumVerts o
if v > 0 do ( try(o.weldThreshold = 0.001)catch(); try(polyop.weldVertsByThreshold o #{{1..v}})catch() )
CenterPivot o
local o2 = copy o name:(uniqueName (o.name + "_F"))
local rot = if ax == "X" then eulerAngles 0 90 0 else if ax == "Y" then eulerAngles 90 0 0 else eulerAngles 0 0 0
local s1 = SliceModifier(); s1.Slice_Type = 2; s1.slice_plane.rotation = rot; addModifier o s1; try(addModifier o (Cap_Holes()))catch(); collapseStack o
local s2 = SliceModifier(); s2.Slice_Type = 3; s2.slice_plane.rotation = rot; addModifier o2 s2; try(addModifier o2 (Cap_Holes()))catch(); collapseStack o2
if not isKindOf o Editable_Poly do try(convertToPoly o)catch(); if not isKindOf o2 Editable_Poly do try(convertToPoly o2)catch()
local f1 = if isValidNode o then polyop.getNumFaces o else 0; local f2 = if isValidNode o2 then polyop.getNumFaces o2 else 0
local r = #(); if f1 < 5 then try(delete o)catch() else append r o.name; if f2 < 5 then try(delete o2)catch() else append r o2.name; return r
); bsp "{0}" "{1}"
)""".format(cn, ax)
if not isKindOf o Editable_Poly do try(convertToPoly o)catch()
if not isKindOf o2 Editable_Poly do try(convertToPoly o2)catch()
local r = #()
if isValidNode o then (
if (polyop.getNumFaces o) < 1 then try(delete o)catch() else append r o.name
)
if isValidNode o2 then (
if (polyop.getNumFaces o2) < 1 then try(delete o2)catch() else append r o2.name
)
return r
)
bsp "{cn}" "{ax}"
)"""
try:
n_p = rt.execute(ms)
if n_p and len(n_p) > 1:
act += 1
for p in n_p:
po = rt.getNodeByName(p)
if po:
pd = max(abs(po.max.x - po.min.x), abs(po.max.y - po.min.y), abs(po.max.z - po.min.z))
if pd >= md * 0.98: fn.append(p)
else: chk.append(p)
if n_p is not None:
n_p_list = list(n_p)
if len(n_p_list) > 1:
act += 1
for p in n_p_list:
po = rt.getNodeByName(p)
if po and rt.isValidNode(po):
pd = max(abs(po.max.x - po.min.x), abs(po.max.y - po.min.y), abs(po.max.z - po.min.z))
if pd >= md * 0.98:
fn.append(p)
else:
chk.append(p)
else:
# Se falhou em pegar o node pelo nome (nomes duplicados), forçamos a string
fn.append(p)
elif len(n_p_list) == 1:
fn.append(n_p_list[0])
else:
for p in n_p: fn.append(p) if n_p else fn.append(cn)
except: fn.append(cn)
else: fn.append(cn)
fn.append(cn)
except Exception as e:
print(f"Erro ao fatiar {cn}: {str(e)}")
fn.append(cn)
else:
fn.append(cn)
sc += 1
ui.pb.setValue(tot); ui.pb.setFormat("Fatiador Concluído!")
rt.clearSelection(); sel = [rt.getNodeByName(n) for n in fn if rt.getNodeByName(n)]; rt.select(sel)
if act > 0: load_selection(ui)
ui.pb.setValue(tot)
ui.pb.setFormat("Fatiador Concluído! Limpando a cena...")
rt.clearSelection()
final_sel = []
# 1. Filtra a lista oficial do script
for n in fn:
o = rt.getNodeByName(n)
if o and rt.isValidNode(o):
try:
if rt.canConvertTo(o, rt.Editable_Poly):
if rt.getPolygonCount(o)[0] > 0:
final_sel.append(o)
else:
rt.delete(o)
except: pass
# ========================================================
# 🕵️‍♂️ MÓDULO DETETIVE: COMPARA SCRIPT vs CENA REAL
# ========================================================
print("\n" + "="*50)
print("🕵️‍♂️ DETETIVE VR4LIFE: RELATÓRIO PÓS-FATIAMENTO")
print("="*50)
script_names = [o.name for o in final_sel if rt.isValidNode(o)]
print(f"-> Objetos validados na lista do Script: {len(script_names)}")
# Varre a cena buscando toda a geometria que existe agora
ms_all_geo = "for o in objects where superclassof o == GeometryClass and classof o != TargetObject collect o.name"
cena_names = list(rt.execute(ms_all_geo))
print(f"-> Geometrias reais encontradas na Cena: {len(cena_names)}")
# Encontra quem está na cena mas ficou de fora do script
perdidos = [n for n in cena_names if n not in script_names]
print(f"-> Diferença (Objetos perdidos): {len(perdidos)}")
if perdidos:
print("\n🚨 LISTA DE SUSPEITOS:")
for p in perdidos:
po = rt.getNodeByName(p)
if po and rt.isValidNode(po):
try:
faces = rt.getPolygonCount(po)[0] if rt.canConvertTo(po, rt.Editable_Poly) else "N/A"
t_x = abs(po.max.x - po.min.x)
t_y = abs(po.max.y - po.min.y)
t_z = abs(po.max.z - po.min.z)
maior_eixo = max(t_x, t_y, t_z)
print(f" [!] NOME: {p}")
print(f" Faces: {faces} | Maior Eixo: {maior_eixo:.1f} | Dims: ({t_x:.1f}, {t_y:.1f}, {t_z:.1f})")
# Se eles são válidos, nós resgatamos eles à força para a seleção final!
if faces != "N/A" and faces > 0:
final_sel.append(po)
print(" >> STATUS: Resgatado e adicionado à lista!")
except Exception as e:
print(f" >> ERRO ao ler suspeito: {e}")
else:
print("✅ Nenhum objeto foi perdido no processo!")
print("="*50 + "\n")
# ========================================================
if final_sel:
rt.select(final_sel)
if act > 0:
load_selection(ui)
def prepare_mesh(ui):
tgs = ui.get_processable_items(); tot = len(tgs); ui.pb.setMaximum(tot); ui.pb.setValue(0); rt.execute("max modify mode")
@ -261,4 +375,11 @@ def upd_res_col(ui):
elif r == 512: d['item'].setForeground(3, QtGui.QColor(0, 255, 0))
elif r == 1024: d['item'].setForeground(3, QtGui.QColor(255, 165, 0))
else: d['item'].setForeground(3, QtGui.QColor(255, 50, 50))
except: pass
except: pass
def get_processable_items(ui):
valid_items = []
for d in ui.bake_items:
obj = rt.getNodeByName(d['name'])
if obj: valid_items.append(d)
return valid_items
Loading…
Cancel
Save