Files
stylized-rock-generator/tests/test_ecogame_rock.py
D4rkst3randClaude Opus 4.8 f996832d75 Rock Gen 2.18.0: Material-Slots, Praefix Rock, Warnung bei zu grobem Erz-Mesh
Drei Rueckmeldungen von der Spielseite abgearbeitet.

1) Fehlende Material-Slots
   "Material zuweisen" stand auf Standard AUS, deshalb kamen alle Proben mit
   mats: [] an - Unreal legt dann nur einen Default-Slot an und die
   eingefrorene Konvention M_Rock_<Sorte> greift nicht. Jetzt Standard AN.
   Normale Steine rotieren durch M_Rock_Granite/Basalt/Sandstone/Mossy, das
   Erzfels-Set bekommt einen NEUTRALEN Slot M_Rock_Ore - ein Set fuer alle
   Erzsorten, die Sorte macht die Material-Instanz.

2) Namens-Drift Fels_ statt Rock_
   War ein Versehen, keine Absicht: der Standard-Praefix stammte noch aus der
   ersten Fassung, bevor die Konvention Rock_<Set>_<Groesse>_<NN> stand. Der
   Erz-Set-Knopf setzte "Rock" schon selbst, der allgemeine Standard nicht.
   Standard ist jetzt "Rock" - keine Asset-Zwillinge, keine Migration noetig.

3) Erzfelsen mit ~870 statt ~2700 Tris
   Nachgestellt: aus den Werkseinstellungen liefert der Set-Knopf 2590-2690
   Tris, die Automatik greift also. ~870 entstehen genau dann, wenn man den
   Erz-Haken setzt und den NORMALEN Erzeugen-Knopf nimmt - Werkseinstellung ist
   Decimate 0.20/0.50 statt 0.40/0.80. Das ist eine Bedienluecke, kein Fehler
   in der Automatik: die Dichte wird bewusst nur ueber den Set-Knopf gesetzt,
   damit niemandem seine Einstellungen unterm Hintern weggezogen werden.
   Deshalb warnt der Operator jetzt, wenn mit Erz-Haken ein Mesh unter 800
   Verts entsteht, und nennt den Knopf "Smooth & dicht" beim Namen. Sonst
   faellt das erst in UE auf und sieht dort nach einem Material-Fehler aus.

Tests halten den Vertrag jetzt fest: Auslieferungszustand (assign_material an,
Praefix Rock), neutraler Erz-Slot, Sorten-Slots bei normalen Steinen.
17 Tests bestehen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 14:08:21 +02:00

53 lines
2.4 KiB
Python

import bpy, sys, importlib.util, os, glob, tempfile, numpy as np
ADDON=r"A:\eco\stylized_rock_generator\stylized_rock_generator.py"
spec=importlib.util.spec_from_file_location("srg",ADDON)
m=importlib.util.module_from_spec(spec); sys.modules["srg"]=m; spec.loader.exec_module(m)
try: m.unregister()
except Exception: pass
m.register()
fails=[]
s=bpy.context.scene.rock_gen_settings
for o in list(bpy.data.objects): bpy.data.objects.remove(o, do_unlink=True)
# --- Namensschema ---
s.batch_count=3; s.subsurf_levels=3; s.use_modal=False; s.generate_lods=False
# Eingefrorene EcoGame-Konvention: Rock_<Set>_<Groesse>_<NN>.
s.name_prefix="Rock"; s.name_form="a"; s.name_class='L'
bpy.ops.object.generate_rocks_batch()
names=sorted(o.name for o in bpy.context.scene.objects if o.type=='MESH')
print("NAMEN:", names)
if not all(n.startswith("Rock_A_L") for n in names): fails.append("naming")
# Einzeln (ohne Nummer)
for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True)
s.batch_count=1
bpy.ops.object.generate_rocks_batch()
single=[o.name for o in bpy.context.scene.objects if o.type=='MESH']
print("EINZELN:", single)
if single and single[0]!="Rock_A_L": fails.append("naming_single")
print("LIGHTMAP-DEFAULT aus:", not m.RockGenSettings.bl_rna.properties['generate_lightmap_uv'].default)
# --- Bake: nur _albedo + _normal, AO drin ---
out=tempfile.mkdtemp()
s.bake_dir=out; s.bake_prefix="fels_a"; s.bake_resolution='512'
s.bake_color=True; s.bake_normal=True; s.bake_roughness=False; s.bake_ao=False
def run(ao_on, strength=1.0):
for f in glob.glob(os.path.join(out,"*.png")): os.remove(f)
s.bake_ao_into_albedo=ao_on; s.bake_ao_strength=strength
bpy.ops.object.bake_rock_textures()
files=sorted(os.path.basename(f) for f in glob.glob(os.path.join(out,"*.png")))
img=bpy.data.images.load(os.path.join(out,"fels_a_albedo.png"))
px=np.array(img.pixels[:],dtype=np.float32).reshape(-1,4)[:,:3]
bpy.data.images.remove(img)
return files, float(px.mean()), float(px.std())
f_on, mean_on, std_on = run(True)
f_off, mean_off, std_off = run(False)
print("DATEIEN:", f_on)
print("AO an : mean=%.4f std=%.4f" % (mean_on, std_on))
print("AO aus: mean=%.4f std=%.4f" % (mean_off, std_off))
if f_on != ["fels_a_albedo.png","fels_a_normal.png"]: fails.append("dateinamen")
if not (mean_on < mean_off): fails.append("ao_nicht_eingerechnet")
m.unregister()
print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))
sys.exit(1 if fails else 0)