import bpy, math
from mathutils import Vector
from math import sin, cos, pi

# ---------- Reset ----------
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
for datablocks in (bpy.data.meshes, bpy.data.curves, bpy.data.materials, bpy.data.cameras, bpy.data.lights):
    # Keep datablocks cleanup lightweight; remove unused generated data from the empty starting file.
    pass

scene = bpy.context.scene
# Remove old collections if any remain and create a tidy hierarchy.
for c in list(bpy.data.collections):
    if c.name != 'Collection':
        bpy.data.collections.remove(c)
root = scene.collection
base_collection = bpy.data.collections.get('Collection')
if base_collection:
    base_collection.name = 'Lantern_Hero'
    hero_coll = base_collection
else:
    hero_coll = bpy.data.collections.new('Lantern_Hero')
    root.children.link(hero_coll)
details_coll = bpy.data.collections.new('Lantern_Details')
root.children.link(details_coll)
env_coll = bpy.data.collections.new('Environment')
root.children.link(env_coll)
light_coll = bpy.data.collections.new('Lighting')
root.children.link(light_coll)

# ---------- Helpers ----------
def link_to(obj, coll):
    for c in list(obj.users_collection):
        c.objects.unlink(obj)
    coll.objects.link(obj)

def set_input(bsdf, names, value):
    for n in names:
        if n in bsdf.inputs:
            bsdf.inputs[n].default_value = value
            return True
    return False

def make_principled(name, base, metallic=0.0, roughness=0.4, emission=None, emission_strength=0.0,
                    transmission=0.0, ior=1.45, coat=0.0, coat_roughness=0.1):
    mat = bpy.data.materials.new(name)
    mat.use_nodes = True
    nt = mat.node_tree
    nodes = nt.nodes
    bsdf = nodes.get('Principled BSDF')
    set_input(bsdf, ['Base Color'], (*base, 1.0))
    set_input(bsdf, ['Metallic'], metallic)
    set_input(bsdf, ['Roughness'], roughness)
    set_input(bsdf, ['IOR'], ior)
    set_input(bsdf, ['Transmission Weight', 'Transmission'], transmission)
    set_input(bsdf, ['Coat Weight', 'Clearcoat'], coat)
    set_input(bsdf, ['Coat Roughness', 'Clearcoat Roughness'], coat_roughness)
    if emission is not None:
        set_input(bsdf, ['Emission Color', 'Emission'], (*emission, 1.0))
        set_input(bsdf, ['Emission Strength'], emission_strength)
    return mat

def add_mat(obj, mat):
    if obj.data and hasattr(obj.data, 'materials'):
        obj.data.materials.append(mat)

def smooth(obj):
    if hasattr(obj.data, 'polygons'):
        for p in obj.data.polygons:
            p.use_smooth = True

def add_bevel(obj, width, segments=3):
    if width <= 0: return
    mod = obj.modifiers.new('Soft machined edges', 'BEVEL')
    mod.width = width
    mod.segments = segments
    mod.limit_method = 'ANGLE'

def add_cyl(name, radius, depth, loc, mat, coll=hero_coll, vertices=64, bevel=0.0, rotation=(0,0,0), smooth_shade=True):
    bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=depth, end_fill_type='NGON', location=loc, rotation=rotation)
    obj = bpy.context.object
    obj.name = name
    link_to(obj, coll)
    add_mat(obj, mat)
    if smooth_shade: smooth(obj)
    add_bevel(obj, bevel, 3)
    return obj

def add_uv(name, loc, scale, mat, coll=hero_coll, segments=64, rings=32, smooth_shade=True):
    bpy.ops.mesh.primitive_uv_sphere_add(segments=segments, ring_count=rings, location=loc)
    obj = bpy.context.object
    obj.name = name
    obj.scale = scale
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    link_to(obj, coll)
    add_mat(obj, mat)
    if smooth_shade: smooth(obj)
    return obj

def add_cube(name, loc, dims, mat, coll=hero_coll, rotation=(0,0,0), bevel=0.0):
    bpy.ops.mesh.primitive_cube_add(location=loc, rotation=rotation)
    obj = bpy.context.object
    obj.name = name
    obj.dimensions = dims
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    link_to(obj, coll)
    add_mat(obj, mat)
    add_bevel(obj, bevel, 3)
    return obj

def add_torus(name, major, minor, z, mat, coll=hero_coll, rotation=(0,0,0), major_segments=96, minor_segments=16):
    bpy.ops.mesh.primitive_torus_add(major_segments=major_segments, minor_segments=minor_segments,
                                     major_radius=major, minor_radius=minor, location=(0,0,z), rotation=rotation)
    obj = bpy.context.object
    obj.name = name
    link_to(obj, coll)
    add_mat(obj, mat)
    smooth(obj)
    return obj

def add_open_tube(name, radius, zmin, zmax, mat, coll=hero_coll, segments=96):
    verts=[]; faces=[]
    for z in (zmin, zmax):
        for i in range(segments):
            a=2*pi*i/segments
            verts.append((radius*cos(a), radius*sin(a), z))
    for i in range(segments):
        j=(i+1)%segments
        faces.append((i,j,segments+j,segments+i))
    me=bpy.data.meshes.new(name+'Mesh')
    me.from_pydata(verts,[],faces); me.update()
    obj=bpy.data.objects.new(name,me)
    coll.objects.link(obj)
    add_mat(obj,mat)
    # A thin physical wall gives the chimney believable edges and exports as geometry.
    sol=obj.modifiers.new('Thin glass wall','SOLIDIFY'); sol.thickness=0.018; sol.offset=0
    bevel= obj.modifiers.new('Glass edge softness','BEVEL'); bevel.width=0.008; bevel.segments=2
    return obj

def add_lathe(name, profile, mat, coll=hero_coll, segments=96):
    # profile is ordered from bottom to top as (radius,z), side surface of revolution.
    verts=[]; faces=[]
    for r,z in profile:
        for i in range(segments):
            a=2*pi*i/segments
            verts.append((r*cos(a), r*sin(a), z))
    for j in range(len(profile)-1):
        for i in range(segments):
            ni=(i+1)%segments
            a=j*segments+i; b=j*segments+ni; c=(j+1)*segments+ni; d=(j+1)*segments+i
            faces.append((a,b,c,d))
    me=bpy.data.meshes.new(name+'Mesh'); me.from_pydata(verts,[],faces); me.update()
    obj=bpy.data.objects.new(name,me); coll.objects.link(obj); add_mat(obj,mat); smooth(obj)
    return obj

def add_curve_mesh(name, points, bevel_depth, mat, coll=hero_coll, bevel_resolution=5):
    cu=bpy.data.curves.new(name+'Curve','CURVE')
    cu.dimensions='3D'; cu.resolution_u=24; cu.bevel_depth=bevel_depth; cu.bevel_resolution=bevel_resolution; cu.resolution_u=16
    sp=cu.splines.new('POLY'); sp.points.add(len(points)-1)
    for p,co in zip(sp.points,points): p.co=(*co,1.0)
    obj=bpy.data.objects.new(name,cu); coll.objects.link(obj); add_mat(obj,mat)
    bpy.context.view_layer.objects.active=obj; obj.select_set(True)
    bpy.ops.object.convert(target='MESH')
    obj=bpy.context.object; smooth(obj)
    obj.select_set(False)
    return obj

def add_area(name, loc, energy, size, color, target=(0,0,2), coll=light_coll):
    ld=bpy.data.lights.new(name+'Data','AREA'); ld.energy=energy; ld.shape='DISK'; ld.size=size; ld.color=color
    obj=bpy.data.objects.new(name,ld); coll.objects.link(obj); obj.location=loc
    obj.rotation_euler=(Vector(target)-obj.location).to_track_quat('-Z','Y').to_euler()
    return obj

def add_point(name, loc, energy, color, radius=0.25, coll=light_coll):
    ld=bpy.data.lights.new(name+'Data','POINT'); ld.energy=energy; ld.color=color; ld.shadow_soft_size=radius
    obj=bpy.data.objects.new(name,ld); coll.objects.link(obj); obj.location=loc
    return obj

# ---------- Materials ----------
metal = make_principled('Enamelled forest-green metal', (0.018,0.055,0.043), metallic=0.88, roughness=0.24, coat=0.28, coat_roughness=0.18)
metal_dark = make_principled('Darkened steel underside', (0.009,0.015,0.016), metallic=0.92, roughness=0.28, coat=0.12, coat_roughness=0.2)
brass = make_principled('Aged warm brass trim', (0.20,0.070,0.018), metallic=0.90, roughness=0.25, coat=0.16, coat_roughness=0.2)
brass_light = make_principled('Brass highlight edges', (0.38,0.14,0.035), metallic=0.94, roughness=0.19, coat=0.24, coat_roughness=0.16)
black = make_principled('Vent slot black', (0.002,0.003,0.003), metallic=0.35, roughness=0.42)
inner_metal = make_principled('Burner inner metal', (0.025,0.018,0.012), metallic=0.75, roughness=0.3)
glass = make_principled('Smoked green glass', (0.16,0.38,0.25), metallic=0.0, roughness=0.075, transmission=0.93, ior=1.46, coat=0.22, coat_roughness=0.08)
glass_edge = make_principled('Glass edge tint', (0.10,0.32,0.19), metallic=0.08, roughness=0.16, transmission=0.68, ior=1.45)
glow_outer = make_principled('Amber mantle glow', (1.0,0.075,0.008), metallic=0.0, roughness=0.2, emission=(1.0,0.075,0.008), emission_strength=5.2)
glow_inner = make_principled('Hot yellow heart', (1.0,0.40,0.035), metallic=0.0, roughness=0.15, emission=(1.0,0.27,0.015), emission_strength=12.0)
wick_mat = make_principled('Charred wick', (0.003,0.002,0.001), metallic=0.2, roughness=0.5)
back_mat = make_principled('Calm midnight backdrop', (0.005,0.010,0.020), metallic=0.02, roughness=0.52)
# Subtle geometry-backed pool for a readable GLB presentation; actual point light does the main work.
pool_mats=[]
for idx,(c,s) in enumerate([((0.10,0.018,0.004),0.040),((0.070,0.012,0.003),0.026),((0.045,0.008,0.002),0.016),((0.025,0.005,0.001),0.008)]):
    pool_mats.append(make_principled('Warm light pool %02d'%idx,c,roughness=0.92,emission=(1.0,0.10,0.008),emission_strength=s))

# ---------- Environment cyclorama ----------
# A broad floor flowing into a vertical dark sweep keeps the product shot calm and horizon-free.
profile=[(-14.0,0.0),(2.35,0.0),(2.70,0.035),(3.05,0.14),(3.38,0.34),(3.66,0.68),(3.86,1.10),(3.98,1.60),(4.02,2.20),(4.02,9.5)]
verts=[]; faces=[]
for y,z in profile:
    verts.extend([(-12.0,y,z),(12.0,y,z)])
for j in range(len(profile)-1):
    a=2*j; b=2*j+1; c=2*(j+1)+1; d=2*(j+1)
    faces.append((a,b,c,d))
me=bpy.data.meshes.new('CycloramaMesh'); me.from_pydata(verts,[],faces); me.update()
backdrop=bpy.data.objects.new('Cyclorama_Backdrop',me); env_coll.objects.link(backdrop); add_mat(backdrop,back_mat)

# ---------- Lantern base ----------
add_cyl('Foot plate',1.08,0.16,(0,0,0.10),metal_dark,bevel=0.055)
add_torus('Foot rolled rim',0.97,0.075,0.17,brass,major_segments=96)
add_cyl('Lower base skirt',0.94,0.20,(0,0,0.28),metal,bevel=0.045)
add_torus('Lower brass band',0.86,0.070,0.38,brass,major_segments=96)
# Slightly tapered body, made from a lathed profile for manufactured shaping.
add_lathe('Fuel reservoir body',[(0.83,0.35),(0.87,0.42),(0.84,0.72),(0.77,0.86)],metal,segments=96)
add_torus('Reservoir top rolled edge',0.775,0.060,0.85,brass_light,major_segments=96)
add_cyl('Glass seat plate',0.75,0.13,(0,0,0.91),metal_dark,bevel=0.025)
add_torus('Glass lower retaining ring',0.725,0.060,1.00,brass,major_segments=96)
# Bottom feet/shadow pads make the lantern sit on the ground rather than float.
for i in range(3):
    a=2*pi*i/3 + pi/2
    add_cube('Rubber foot %d'%i,(0.72*cos(a),0.72*sin(a),0.035),(0.28,0.22,0.07),black,coll=details_coll,rotation=(0,0,a),bevel=0.025)

# Vent slots around the lower metal reservoir.
for i in range(10):
    a=2*pi*i/10 + pi/10
    r=0.842
    add_cube('Lower vent slot %02d'%i,(r*cos(a),r*sin(a),0.58),(0.065,0.20,0.16),black,coll=details_coll,rotation=(0,0,a),bevel=0.018)

# Burner collar, wick, and inner cage.
add_cyl('Burner cup',0.43,0.12,(0,0,1.08),inner_metal,bevel=0.025)
add_torus('Burner brass lip',0.39,0.040,1.145,brass_light,major_segments=72)
add_cyl('Wick chimney',0.19,0.32,(0,0,1.26),inner_metal,bevel=0.018)
add_cyl('Charred wick',0.075,0.22,(0,0,1.45),wick_mat,bevel=0.012,vertices=48)
# A small ring around the mantle gives the glow a convincing mechanical origin.
add_torus('Mantle lower collar',0.32,0.035,1.48,brass,major_segments=72)
add_torus('Mantle upper collar',0.31,0.032,2.47,brass,major_segments=72)

# ---------- Glass enclosure and luminous core ----------
add_open_tube('Glass chimney',0.705,1.02,2.86,glass,segments=96)
add_torus('Glass top retaining ring',0.715,0.058,2.87,brass,major_segments=96)
# Secondary faint edge rings are glass-toned and catch the key light.
add_torus('Glass lower edge highlight',0.706,0.022,1.06,glass_edge,coll=details_coll,major_segments=96,minor_segments=12)
add_torus('Glass upper edge highlight',0.706,0.022,2.82,glass_edge,coll=details_coll,major_segments=96,minor_segments=12)
# Warm core: a broad mantle plus a hotter center, both actual emissive geometry.
add_uv('Glowing mantle',(0,0,1.96),(0.315,0.315,0.66),glow_outer,coll=hero_coll,segments=64,rings=32)
add_cyl('Luminous inner tube',0.215,0.98,(0,0,1.96),glow_inner,coll=hero_coll,vertices=64,bevel=0.06)
add_uv('Hot mantle heart',(0,-0.005,1.98),(0.20,0.20,0.48),glow_inner,coll=details_coll,segments=48,rings=24)
# A few slender inner guard wires silhouette the glowing mantle.
for i in range(6):
    a=2*pi*i/6
    add_cyl('Inner mantle guard %02d'%i,0.018,0.95,(0.34*cos(a),0.34*sin(a),1.97),brass,coll=details_coll,vertices=24,bevel=0.006)

# ---------- Protective metal frame ----------
# Six evenly spaced upright ribs make the lantern immediately recognizable from an orbit.
frame_angles=[0,60,120,180,240,300]
for i,deg in enumerate(frame_angles):
    a=math.radians(deg)
    r=0.785
    add_cyl('Protective frame upright %02d'%i,0.052,1.90,(r*cos(a),r*sin(a),1.94),brass,coll=hero_coll,vertices=40,bevel=0.012)
# Heavy upper/lower guard hoops.
add_torus('Lower guard hoop',0.775,0.052,1.16,brass_light,major_segments=96)
add_torus('Upper guard hoop',0.775,0.052,2.73,brass_light,major_segments=96)
# Small collars at rib ends, a typical lantern construction detail.
for i,deg in enumerate(frame_angles):
    a=math.radians(deg); r=0.785
    add_uv('Lower rib collar %02d'%i,(r*cos(a),r*sin(a),1.17),(0.085,0.085,0.070),brass_light,coll=details_coll,segments=24,rings=12)
    add_uv('Upper rib collar %02d'%i,(r*cos(a),r*sin(a),2.72),(0.085,0.085,0.070),brass_light,coll=details_coll,segments=24,rings=12)

# ---------- Top housing ----------
add_cyl('Top shoulder plate',0.90,0.18,(0,0,2.98),metal,bevel=0.035)
add_torus('Top shoulder brass edge',0.845,0.060,2.91,brass,major_segments=96)
# A rounded vented dome profile.
add_lathe('Vented top dome',[(0.87,3.03),(0.86,3.11),(0.79,3.23),(0.66,3.34),(0.48,3.42),(0.28,3.47)],metal,segments=96)
add_torus('Dome lower rolled edge',0.865,0.045,3.08,brass_light,major_segments=96)
# Raised chimney cap and concentric crown rings.
add_cyl('Chimney neck',0.27,0.18,(0,0,3.53),metal_dark,bevel=0.025)
add_torus('Chimney cap lower ring',0.28,0.045,3.61,brass,major_segments=72)
add_cyl('Chimney crown',0.34,0.09,(0,0,3.67),metal,bevel=0.025)
add_torus('Chimney crown rim',0.31,0.038,3.72,brass_light,major_segments=72)
# Dark rectangular ventilation slots around the dome, angled with the radius.
for i in range(8):
    a=2*pi*i/8 + pi/8
    r=0.68
    # The slot blocks sit just proud of the dome as dark negative accents.
    add_cube('Dome vent slot %02d'%i,(r*cos(a),r*sin(a),3.285),(0.055,0.16,0.16),black,coll=details_coll,rotation=(0,0,a),bevel=0.014)

# ---------- Carry handle ----------
# A real curved metal bail, converted to a mesh for dependable GLB export.
handle_pts=[]
R=1.16; cz=3.05
for i in range(37):
    t=pi - pi*i/36
    handle_pts.append((R*cos(t),0.0,cz+R*sin(t)))
handle=add_curve_mesh('Bail carry handle',handle_pts,0.085,metal,coll=hero_coll,bevel_resolution=5)
# Brass pivot bosses on the sides of the top housing, axis along Y.
for side in (-1,1):
    x=side*0.90
    add_cyl('Handle pivot boss %s'%('L' if side<0 else 'R'),0.13,0.30,(x,0,3.02),brass_light,coll=details_coll,vertices=48,bevel=0.025,rotation=(pi/2,0,0))
    add_torus('Handle pivot ring %s'%('L' if side<0 else 'R'),0.13,0.025,3.02,brass,coll=details_coll,rotation=(pi/2,0,0),major_segments=48,minor_segments=10)
# Subtle grip sleeve at the crown of the bail (a short dark rubberized section).
add_cyl('Handle top grip',0.105,0.34,(0,0,4.19),black,coll=details_coll,vertices=40,bevel=0.028,rotation=(0,pi/2,0))

# ---------- Ground light pool geometry ----------
# Concentric, very low-level emission rings supplement the physically lit pool and remain readable in GLB.
rings=[0.0,0.72,1.32,1.95,2.75]
verts=[(0,0,0.009)]
for r in rings[1:]:
    for i in range(96):
        a=2*pi*i/96
        verts.append((r*cos(a),r*sin(a),0.009))
faces=[]; mids=[]
# center fan
for i in range(96):
    faces.append((0,1+i,1+(i+1)%96)); mids.append(0)
# ring bands
for band in range(1,len(rings)-1):
    start0=1+(band-1)*96; start1=1+band*96
    for i in range(96):
        j=(i+1)%96
        faces.append((start0+i,start1+i,start1+j,start0+j)); mids.append(band)
me=bpy.data.meshes.new('LightPoolMesh'); me.from_pydata(verts,[],faces); me.update()
pool=bpy.data.objects.new('Soft warm pool on ground',me); env_coll.objects.link(pool)
for m in pool_mats: me.materials.append(m)
for poly,idx in zip(me.polygons,mids): poly.material_index=min(idx,len(pool_mats)-1)

# ---------- Lighting ----------
# Warm source inside the glass: soft enough for a broad pool but strong enough to read as a lantern.
add_point('Lantern warm source',(0,0,1.82),420,(1.0,0.20,0.045),radius=0.34)
add_point('Lower amber bounce',(0,0,0.92),105,(1.0,0.12,0.025),radius=0.48)
# Large, cool softboxes reveal the green enamel and brass without washing out the warmth.
add_area('Cool left softbox',(-4.5,-4.8,6.6),720,4.6,(0.34,0.46,0.62),target=(0,0,2.0))
add_area('Blue rim softbox',(4.5,3.0,5.8),900,3.2,(0.16,0.27,0.46),target=(0,0,2.25))
add_area('Front fill',(4.5,-5.5,3.8),260,4.0,(0.34,0.38,0.42),target=(0,0,1.8))
# A weak warm overhead reflection keeps the dome readable.
add_area('Warm top reflection',(-1.5,0.8,7.5),260,3.0,(0.72,0.25,0.08),target=(0,0,2.8))

# ---------- Camera ----------
def look_at(obj, target):
    obj.rotation_euler=(Vector(target)-obj.location).to_track_quat('-Z','Y').to_euler()
cam_data=bpy.data.cameras.new('Hero camera data'); cam=bpy.data.objects.new('Hero camera',cam_data); light_coll.objects.link(cam)
cam.location=(6.2,-9.4,5.25); cam_data.lens=58; cam_data.sensor_width=36
look_at(cam,(0,0,2.12))
cam_data.dof.use_dof=True; cam_data.dof.focus_object=None; cam_data.dof.focus_distance=(Vector(cam.location)-Vector((0,0,1.95))).length; cam_data.dof.aperture_fstop=6.3
scene.camera=cam

# ---------- World/render/compositor ----------
world=bpy.data.worlds.new('Midnight studio world') if not bpy.data.worlds else bpy.data.worlds[0]
scene.world=world; world.use_nodes=True
bg=world.node_tree.nodes.get('Background'); bg.inputs['Color'].default_value=(0.0025,0.006,0.014,1); bg.inputs['Strength'].default_value=0.035
scene.render.engine='BLENDER_EEVEE_NEXT'  # temporary for fast scene validation; final is switched to Cycles below
scene.render.resolution_x=1536; scene.render.resolution_y=1536; scene.render.resolution_percentage=100
scene.render.image_settings.file_format='PNG'; scene.render.film_transparent=False
scene.render.image_settings.color_mode='RGBA'
scene.render.filepath='/tmp/camping_lantern_preview.png'
# Color management suited to warm emissive light and dark metal.
try:
    scene.view_settings.look='AgX - Medium High Contrast'
except:
    try: scene.view_settings.look='Medium High Contrast'
    except: pass
scene.view_settings.exposure=0.0
# Compositor glow is native to both Eevee and Cycles and is deliberately restrained.
scene.use_nodes=True
nt=scene.node_tree; nt.nodes.clear()
rl=nt.nodes.new('CompositorNodeRLayers'); rl.location=(-280,0)
gl=nt.nodes.new('CompositorNodeGlare'); gl.glare_type='FOG_GLOW'; gl.quality='HIGH'; gl.threshold=1.1; gl.size=7; gl.mix=-0.86; gl.location=(0,0)
comp=nt.nodes.new('CompositorNodeComposite'); comp.location=(240,0)
nt.links.new(rl.outputs['Image'],gl.inputs['Image']); nt.links.new(gl.outputs['Image'],comp.inputs['Image'])

# Render settings for the benchmark's native-fidelity capture.
scene.render.engine='BLENDER_EEVEE_NEXT'
scene.render.resolution_percentage=100
# Keep final engine explicitly Cycles in the saved scene, as requested by the benchmark.
scene.render.engine='CYCLES'
scene.cycles.samples=64
scene.cycles.use_denoising=True
scene.cycles.max_bounces=8
scene.cycles.diffuse_bounces=3
scene.cycles.glossy_bounces=4
scene.cycles.transmission_bounces=8
scene.cycles.transparent_max_bounces=8
# Prefer GPU if configured by the host, without failing on CPU-only installations.
try:
    scene.cycles.device='GPU'
except:
    pass

# Organize and annotate the scene.
scene['hero_prop']='Classic camping lantern with emissive mantle, glass chimney, protective brass frame, and bail handle'
scene['lighting_note']='Warm point source inside glass plus cool studio softboxes and a subtle ground pool'
for obj in bpy.data.objects:
    if obj.type == 'MESH':
        obj.select_set(False)
# Select hero and set a useful active object.
hero=bpy.data.objects.get('Glowing mantle')
if hero:
    hero.select_set(True); bpy.context.view_layer.objects.active=hero

# Save the complete scene.
bpy.ops.wm.save_as_mainfile(filepath='/tmp/camping_lantern.blend')
result={'objects':len(bpy.data.objects),'materials':len(bpy.data.materials),'camera':scene.camera.name,'engine':scene.render.engine,'file':'/tmp/camping_lantern.blend'}


Traceback (most recent call last):
  File "<repo>\.runner\blender-mcp-v1.0.0\addon\mcp_to_blender_server.py", line 230, in _execute_code
    exec(code, namespace)
    ~~~~^^^^^^^^^^^^^^^^^
  File "<string>", line 352, in <module>
TypeError: bpy_struct: item.attr = val: enum "BLENDER_EEVEE_NEXT" not found in ('BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'CYCLES')