Continue Blender Web parity task handoff
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-23 05:47:21 -04:00
parent 0a22992a13
commit 9f43244982
962 changed files with 60772 additions and 297 deletions

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python3
import hashlib,json,os,pathlib,shutil,sys,tempfile,bpy
ARMATURE_NAME="WebGapArmatureSwitchDirectionArmature";OBJECT_NAME="WebGapArmatureSwitchDirectionObject";ROOT_BONE="WebGapArmatureSwitchDirectionRoot";CHILD_BONE="WebGapArmatureSwitchDirectionChild";OTHER_BONE="WebGapArmatureSwitchDirectionOther"
def ensure():
o=bpy.data.objects.get(OBJECT_NAME);a=bpy.data.armatures.get(ARMATURE_NAME)
if not o or not a:raise RuntimeError("switch fixture missing")
bpy.context.view_layer.objects.active=o;o.select_set(True)
if o.mode!="EDIT":bpy.ops.object.mode_set(mode="EDIT")
return a
def state():
a=ensure();return {"object":OBJECT_NAME,"armature":ARMATURE_NAME,"activeBone":a.edit_bones.active.name if a.edit_bones.active else None,"bones":[{"name":b.name,"selected":bool(b.select),"parent":b.parent.name if b.parent else None,"connected":bool(b.use_connect),"head":[round(float(x),6) for x in b.head],"tail":[round(float(x),6) for x in b.tail]} for b in a.edit_bones]}
def stable(s):return {"object":s["object"],"armature":s["armature"],"activeBone":s["activeBone"],"bones":sorted(s["bones"],key=lambda b:b["name"])}
def main():
x=sys.argv[sys.argv.index("--")+1:];
if len(x)!=2:raise SystemExit("usage")
f,out=(pathlib.Path(v).resolve() for v in x);bpy.ops.wm.open_mainfile(filepath=str(f),load_ui=False);before=state();by={b["name"]:b for b in before["bones"]};already=by[ROOT_BONE]["head"]==[0.0,1.0,0.0] and by[ROOT_BONE]["tail"]==[0.0,0.0,0.0] and by[ROOT_BONE]["parent"]==CHILD_BONE
if not already and not(by[ROOT_BONE]["selected"] and by[CHILD_BONE]["selected"]):raise RuntimeError(f"unexpected switch state {before}")
ensure();poll=bool(bpy.ops.armature.switch_direction.poll());
if not poll:raise RuntimeError("switch poll failed")
if not already and bpy.ops.armature.switch_direction()!={"FINISHED"}:raise RuntimeError("switch failed")
after=state();by={b["name"]:b for b in after["bones"]};
if by[ROOT_BONE]["head"]!=[0.0,1.0,0.0] or by[ROOT_BONE]["tail"]!=[0.0,0.0,0.0] or by[ROOT_BONE]["parent"]!=CHILD_BONE or by[CHILD_BONE]["head"]!=[0.0,2.0,0.0] or by[CHILD_BONE]["tail"]!=[0.0,1.0,0.0]:raise RuntimeError(f"switch mismatch {after}")
bpy.ops.object.mode_set(mode="OBJECT");fd,t=tempfile.mkstemp(prefix="m16-switch-reopen-",suffix=".blend");os.close(fd);tp=pathlib.Path(t)
try:
bpy.ops.wm.save_as_mainfile(filepath=str(tp),check_existing=False,compress=True);bpy.ops.wm.open_mainfile(filepath=str(tp),load_ui=False);re=state();
if stable(re)!=stable(after):raise RuntimeError("switch save/reopen drift")
shutil.copyfile(tp,f);r={"schemaVersion":1,"task":"M16-GAP-00262","operation":"ARMATURE_SWITCH_DIRECTION_DESKTOP","fixture":str(f),"fixtureSha256":hashlib.sha256(f.read_bytes()).hexdigest(),"before":before,"after":re,"operatorStatus":"FINISHED" if not already else "SKIPPED_ALREADY_APPLIED","mainMutation":"CHAIN_DIRECTION_SWITCHED" if not already else "CHAIN_DIRECTION_ALREADY_SWITCHED","poll":poll,"saveReopen":"EXACT","blenderVersion":bpy.app.version_string};out.parent.mkdir(parents=True,exist_ok=True);out.write_text(json.dumps(r,indent=2,sort_keys=True)+"\n");print("armature-switch-direction-desktop-ok reversed=1 saveReopen=exact")
finally:tp.unlink(missing_ok=True)
if __name__=="__main__":
try:main()
except Exception as e:print(f"armature-switch-direction-desktop-failed: {e}");raise SystemExit(1)