|
|
"use strict";(self.webpackChunkplaycanvas_game=self.webpackChunkplaycanvas_game||[]).push([[433],{433:(e,t,i)=>{i.r(t),i.d(t,{default:()=>a});class o{constructor(e){this.bounds=e.bounds||{width:10,height:10,depth:10},this.capacity=e.capacity||1/0,this.rules=e.rules||[],this.currentState=new Map,this.history=[],this.onStateChange=null,this.containerPosition={x:this.bounds.width/2,y:this.bounds.height/2,z:this.bounds.depth/2}}canAccommodate(e,t){const i=this.checkBounds(e,t),o=this.checkCapacity(e),s=this.checkRules(e,t);return i||(console.log(`[SharedSpace] Bounds check failed for ${e.id} at`,t),console.log("[SharedSpace] Container bounds:",this.bounds,"Container position:",this.containerPosition)),o||console.log(`[SharedSpace] Capacity check failed for ${e.id}`),s||console.log(`[SharedSpace] Rules check failed for ${e.id} at`,t),i&&o&&s}checkBounds(e,t){const i={minX:t.x-e.size.x/2,maxX:t.x+e.size.x/2,minY:t.y-e.size.y/2,maxY:t.y+e.size.y/2,minZ:t.z-e.size.z/2,maxZ:t.z+e.size.z/2},o={minX:this.containerPosition.x-this.bounds.width/2,maxX:this.containerPosition.x+this.bounds.width/2,minY:this.containerPosition.y-this.bounds.height/2,maxY:this.containerPosition.y+this.bounds.height/2,minZ:this.containerPosition.z-this.bounds.depth/2,maxZ:this.containerPosition.z+this.bounds.depth/2},s=i.minX>=o.minX&&i.maxX<=o.maxX&&i.minY>=o.minY&&i.maxY<=o.maxY&&i.minZ>=o.minZ&&i.maxZ<=o.maxZ;return console.log(`[SharedSpace] Bounds check for ${e.id}:`),console.log(" Object bounds:",i),console.log(" Container bounds:",o),console.log(" Result:",s),s}checkCapacity(e){return this.getCurrentVolume()+e.size.x*e.size.y*e.size.z<=this.capacity}checkRules(e,t){for(const i of this.rules)if(!this.applyRule(i,e,t))return!1;return!0}applyRule(e,t,i){switch(e){case"no_overlap":return this.checkNoOverlap(t,i);case"gravity_simulation":return this.checkGravitySupport(t,i);default:return!0}}checkNoOverlap(e,t){const i=this.getObjectBounds(e,t);for(const[e,t]of this.currentState){const e=this.getObjectBounds(t.object,t.position);if(this.boundsOverlap(i,e))return!1}return!0}checkGravitySupport(e,t){if(t.y<=e.size.y/2+.1)return!0;const i=t.y-e.size.y/2-.1;for(const[o,s]of this.currentState){const o=s.object,n=s.position,a=n.y+o.size.y/2;if(Math.abs(a-i)<.2&&this.horizontalOverlap(e,t,o,n))return!0}return!1}horizontalOverlap(e,t,i,o){const s=t.x-e.size.x/2,n=t.x+e.size.x/2,a=t.z-e.size.z/2,c=t.z+e.size.z/2,r=o.x-i.size.x/2,l=o.x+i.size.x/2,d=o.z-i.size.z/2,p=o.z+i.size.z/2;return!(n<r||s>l||c<d||a>p)}getObjectBounds(e,t){return{minX:t.x-e.size.x/2,maxX:t.x+e.size.x/2,minY:t.y-e.size.y/2,maxY:t.y+e.size.y/2,minZ:t.z-e.size.z/2,maxZ:t.z+e.size.z/2}}boundsOverlap(e,t){return!(e.maxX<t.minX||e.minX>t.maxX||e.maxY<t.minY||e.minY>t.maxY||e.maxZ<t.minZ||e.minZ>t.maxZ)}addObject(e,t){return!!this.canAccommodate(e,t)&&(this.currentState.set(e.id,{object:e,position:t,timestamp:Date.now()}),this.updateSpace(),!0)}removeObject(e){const t=this.currentState.delete(e);return t&&this.updateSpace(),t}updateSpace(){this.history.push({state:new Map(this.currentState),timestamp:Date.now()}),this.onStateChange&&this.onStateChange(this.currentState)}getCurrentVolume(){let e=0;for(const[t,i]of this.currentState){const t=i.object;e+=t.size.x*t.size.y*t.size.z}return e}getUtilization(){return this.getCurrentVolume()/this.capacity}}class s{constructor(e,t){this.id=e,this.size=t.size||{x:1,y:1,z:1},this.weight=t.weight||1,this.constraints=t.constraints||[],this.interactions=t.interactions||[],this.state="available",this.entity=null,this.material=t.material||null,this.color=t.color||new pc.Color(.5,.5,.5)}interactsWith(e,t){return this.interactions.some(i=>i.applies(e,t))}createEntity(e,t){if(this.entity=t.create(this.id,{components:{model:{type:"box"},collision:{type:"box",halfExtents:[this.size.x/2,this.size.y/2,this.size.z/2]},rigidbody:{type:"static"}},scale:[this.size.x,this.size.y,this.size.z],tags:["puzzle_object","interactive"]}),this.entity.model){const e=new pc.StandardMaterial;e.diffuse=this.color,e.update(),this.entity.model.meshInstances.forEach(t=>t.material=e)}return this.entity}}class n{constructor(e){this.space=new o(e.space),this.objects=e.objects.map(e=>new s(e.id,e)),this.objectives=e.objectives||[],this.currentScore=0,this.isComplete=!1,this.draggedObject=null,this.app=null,this.space.onStateChange=e=>{this.evaluateObjectives(),this.calculateScore()}}initialize(e,t,i){this.app=e,this.parentEntity=i,this.createSpaceVisualization(t),this.objects.forEach(i=>{i.createEntity(e,t),i.entity&&(this.parentEntity.addChild(i.entity),this.setupObjectInteraction(i))}),this.arrangeInitialObjects()}createSpaceVisualization(e){if(this.containerEntity=e.create("puzzle_container",{components:{model:{type:"box"},collision:{type:"box",halfExtents:[this.space.bounds.width/2,this.space.bounds.height/2,this.space.bounds.depth/2]}},scale:[this.space.bounds.width,this.space.bounds.height,this.space.bounds.depth],position:[this.space.bounds.width/2,this.space.bounds.height/2,this.space.bounds.depth/2],tags:["puzzle_container"]}),this.containerEntity.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.2,.3,.4),e.opacity=.3,e.blendType=pc.BLEND_NORMAL,e.update(),this.containerEntity.model.meshInstances.forEach(t=>t.material=e)}this.parentEntity.addChild(this.containerEntity),this.createPlacementGrid(e)}createPlacementGrid(e){const t=.5,i=this.containerEntity.getPosition(),o=this.space.bounds,s=Math.floor(o.width/t)+1;for(let n=0;n<s;n++){const s=n*t-o.width/2,a=e.create(`grid_line_x_${n}`,{components:{model:{type:"box"}},scale:[.05,.05,o.depth],position:[i.x+s,i.y-o.height/2+.02,i.z],tags:["grid_indicator"]});if(a.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.8,.9,.8),e.opacity=.6,e.blendType=pc.BLEND_NORMAL,e.update(),a.model.meshInstances.forEach(t=>t.material=e)}this.parentEntity.addChild(a)}const n=Math.floor(o.depth/t)+1;for(let s=0;s<n;s++){const n=s*t-o.depth/2,a=e.create(`grid_line_z_${s}`,{components:{model:{type:"box"}},scale:[o.width,.05,.05],position:[i.x,i.y-o.height/2+.02,i.z+n],tags:["grid_indicator"]});if(a.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.8,.9,.8),e.opacity=.6,e.blendType=pc.BLEND_NORMAL,e.update(),a.model.meshInstances.forEach(t=>t.material=e)}this.parentEntity.addChild(a)}}arrangeInitialObjects(){const e=this.space.bounds.height;let t=this.objects.length/2*-3;this.objects.forEach((i,o)=>{if(i.entity){const o=e+2;i.entity.setPosition(t,o,-this.space.bounds.depth-2),t+=3}})}setupObjectInteraction(e){e.entity&&(e.entity.puzzle=this,e.entity.puzzleObject=e,this.app.systems.interaction&&e.entity.addComponent("interaction",{onInteract:()=>this.startDrag(e.id)}))}startDrag(e){const t=this.objects.find(t=>t.id===e);t&&"available"===t.state&&(this.draggedObject=t,t.state="dragging",this.app.fire&&this.app.fire("puzzle:drag_start",{object:t}))}updateDrag(e){if(!this.draggedObject||!this.draggedObject.entity)return;this.draggedObject.entity.setPosition(e.x,e.y,e.z);const t=this.space.canAccommodate(this.draggedObject,e);this.showValidityFeedback(t)}completeDrop(e){if(!this.draggedObject)return console.log("[SharedSpacePuzzle] completeDrop called but no draggedObject"),!1;console.log(`[SharedSpacePuzzle] Attempting to place ${this.draggedObject.id} at`,e);const t=this.attemptPlacement(this.draggedObject.id,e);if(console.log("[SharedSpacePuzzle] Placement result:",t),t)this.draggedObject.state="placed",console.log(`[SharedSpacePuzzle] Firing placement_success event for ${this.draggedObject.id}`),this.app.fire&&this.app.fire("puzzle:placement_success",{object:this.draggedObject,position:e});else{if(this.draggedObject.state="available",this.draggedObject.entity&&this.draggedObject.entity.model&&this.draggedObject.entity.model.meshInstances){const e=this.draggedObject.entity.model.meshInstances[0].material;e.emissive=new pc.Color(0,0,0),e.opacity=1,e.blendType=pc.BLEND_NONE,e.update()}this.app.fire&&this.app.fire("puzzle:placement_failed",{object:this.draggedObject,position:e})}return this.draggedObject=null,t}showValidityFeedback(e){if(this.draggedObject&&this.draggedObject.entity)try{if(this.draggedObject.entity.model&&this.draggedObject.entity.model.meshInstances){const t=this.draggedObject.entity.model.meshInstances[0].material;e?(t.emissive=new pc.Color(0,.5,0),t.opacity=.8):(t.emissive=new pc.Color(.5,0,0),t.opacity=.8),t.blendType=pc.BLEND_NORMAL,t.update(),console.log(`[SharedSpace] Visual feedback: ${e?"VALID":"INVALID"} placement for ${this.draggedObject.id}`)}}catch(e){console.error("[SharedSpace] Error updating visual feedback:",e)}}attemptPlacement(e,t){const i=this.objects.find(t=>t.id===e);if(!i)return!1;if(this.space.addObject(i,t)){if(i.entity&&(i.entity.setPosition(t.x,t.y,t.z),i.entity.model&&i.entity.model.meshInstances)){const e=i.entity.model.meshInstances[0].material;e.emissive=new pc.Color(0,0,0),e.opacity=1,e.blendType=pc.BLEND_NONE,e.update()}return!0}return!1}evaluateObjectives(){this.objectives.forEach(e=>{switch(e.type){case"fit_all_items":e.completed=this.space.currentState.size===this.objects.length;break;case"efficiency":const t=this.space.getUtilization();e.completed=t>=e.target,e.progress=t}}),this.isComplete=this.objectives.every(e=>e.completed),this.isComplete&&this.app.fire&&this.app.fire("puzzle:completed",{puzzle:this})}calculateScore(){this.currentScore=0,this.currentScore+=10*this.space.currentState.size;const e=this.space.getUtilization();return this.currentScore+=Math.floor(100*e),this.currentScore}getStatus(){return{placedObjects:this.space.currentState.size,totalObjects:this.objects.length,utilization:this.space.getUtilization(),score:this.currentScore,isComplete:this.isComplete,objectives:this.objectives.map(e=>({type:e.type,description:e.description,completed:e.completed,progress:e.progress}))}}}const a={id:"puzzle_test",title:"Shared Space Puzzle Test",type:"scene",async build(e,t,i){console.log("[PuzzleTestScene] Building puzzle test scene...");const o=i.create("puzzle_test_root",{position:[0,0,0],tags:["scene_root"]}),s={space:{bounds:{width:6,height:4,depth:4},capacity:96,rules:["no_overlap","gravity_simulation"]},objects:[{id:"book_red",size:{x:2,y:.3,z:1.5},weight:1,color:new pc.Color(.8,.2,.2)},{id:"book_blue",size:{x:2,y:.3,z:1.5},weight:1,color:new pc.Color(.2,.2,.8)},{id:"laptop",size:{x:3,y:.2,z:2},weight:2,color:new pc.Color(.3,.3,.3)},{id:"box_small",size:{x:1.5,y:1.5,z:1.5},weight:1,color:new pc.Color(.6,.4,.2)},{id:"cylinder_tool",size:{x:.8,y:2,z:.8},weight:1,color:new pc.Color(.5,.7,.3)},{id:"flat_panel",size:{x:3,y:.1,z:2.5},weight:1,color:new pc.Color(.7,.7,.2)}],objectives:[{type:"fit_all_items",description:"Pack all items in the container",completed:!1},{type:"efficiency",target:.7,description:"Use at least 70% of container space",completed:!1,progress:0}]};this.puzzle=new n(s),this.puzzle.initialize(e,i,o);const a=i.create("instruction_panel",{components:{model:{type:"box"},collision:{type:"box",halfExtents:[3,1,.1]}},position:[0,3,-8],scale:[6,2,.2],tags:["instruction_panel"]});if(a.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.1,.1,.2),e.emissive=new pc.Color(.05,.05,.1),e.update(),a.model.meshInstances.forEach(t=>t.material=e)}o.addChild(a);const c=i.create("progress_display",{components:{model:{type:"box"},collision:{type:"box",halfExtents:[2,.5,.1]}},position:[8,2,0],scale:[4,1,.2],tags:["progress_display"]});if(c.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.2,.3,.2),e.update(),c.model.meshInstances.forEach(t=>t.material=e)}o.addChild(c);const r=i.create("drag_mode_indicator",{components:{model:{type:"box"},collision:{type:"box",halfExtents:[2,.4,.1]}},position:[8,.5,0],scale:[4,.8,.2],tags:["drag_mode_indicator"]});if(r.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.1,.2,.4),e.emissive=new pc.Color(.05,.1,.2),e.update(),r.model.meshInstances.forEach(t=>t.material=e)}o.addChild(r);const l=i.create("reset_button",{components:{model:{type:"box"},collision:{type:"box",halfExtents:[1,.5,.5]},rigidbody:{type:"static"}},position:[-8,1,0],scale:[2,1,1],tags:["interactive","reset_button"]});if(l.model){const e=new pc.StandardMaterial;e.diffuse=new pc.Color(.6,.2,.2),e.emissive=new pc.Color(.2,.05,.05),e.update(),l.model.meshInstances.forEach(t=>t.material=e)}o.addChild(l);const d=i.createLight("point",{color:new pc.Color(1,1,1),intensity:2,range:20,position:[0,8,0]});o.addChild(d);const p=i.createLight("point",{color:new pc.Color(.8,.9,1),intensity:.8,range:15,position:[10,5,10]});return o.addChild(p),o},objectives:[{id:"puzzle_tutorial",name:"Puzzle Tutorial",description:"Drag objects to the container floor. Objects must align with the bottom grid to be valid. Use SPACE to change drag modes.",type:"simple",autoStart:!0,rewards:{experience:10}},{id:"place_all_items",name:"Pack All Items",description:"Fit all 6 objects into the container",type:"counter",target:6,progress:0,prerequisites:["puzzle_tutorial"],rewards:{experience:50}},{id:"achieve_efficiency",name:"Efficient Packing",description:"Achieve at least 70% space utilization",type:"simple",prerequisites:["place_all_items"],rewards:{experience:100,skillPoints:1}}],onLoad(e,t){console.log("[PuzzleTestScene] Puzzle test scene loaded");const i=t.getSystem("objectivemanager");console.log("[PuzzleTestScene] onLoad - ObjectManager:",i),console.log("[PuzzleTestScene] onLoad - ObjectManager type:",typeof i),console.log("[PuzzleTestScene] onLoad - Has defineObjective method:",i&&"function"==typeof i.defineObjective),i&&"function"==typeof i.defineObjective&&(i.clearAllObjectives(),this.objectives.forEach(e=>{i.defineObjective(e.id,e)}),i.startObjective("puzzle_tutorial"));const o=e.root.findByTag("scene_root")[0];o&&this.puzzle&&(e.interactionController&&(console.log("[PuzzleTestScene] Temporarily disabling default interaction controller"),e.off("update",e.interactionController.update,e.interactionController),this.defaultInteractionDisabled=!0),this.setupDragDropMechanics(e),this.interactionHandler=i=>{this.handleInteraction(i,e,t)},o.multiRoom&&o.multiRoom.setSceneInteractionHandler(this.interactionHandler),this.setupPuzzleEvents(e,t),e.fire("ui:notification",{text:"Drag objects to container floor! Must align with bottom grid. Press SPACE to change drag mode.",type:"info",duration:5e3}))},setupDragDropMechanics(e){this.app=e,this.isDragging=!1,this.draggedEntity=null,this.dragOffset=new pc.Vec3,this.dragPlaneNormal=null,this.dragPlanePoint=null,this.dragMode="XZ",this.camera=e.root.findByName("Camera")||e.root.findByTag("camera")[0]||e.root.findByTag("main_camera")[0],console.log("[PuzzleTestScene] Setting up drag drop mechanics, camera found:",!!this.camera),e.keyboard&&e.keyboard.on(pc.EVENT_KEYDOWN,e=>{e.key===pc.KEY_SPACE&&this.toggleDragMode()}),e.mouse&&(e.mouse.on(pc.EVENT_MOUSEDOWN,t=>{t.button===pc.MOUSEBUTTON_LEFT&&(console.log("[PuzzleTestScene] Mouse down at:",t.x,t.y),this.startDragFromInput(t.x,t.y,e))}),e.mouse.on(pc.EVENT_MOUSEMOVE,t=>{this.isDragging&&this.updateDragFromInput(t.x,t.y,e)}),e.mouse.on(pc.EVENT_MOUSEUP,t=>{t.button===pc.MOUSEBUTTON_LEFT&&this.isDragging&&this.endDragFromInput(e)})),e.touch&&(e.touch.on(pc.EVENT_TOUCHSTART,t=>{if(1===t.touches.length){const i=t.touches[0];console.log("[PuzzleTestScene] Touch start at:",i.x,i.y),this.startDragFromInput(i.x,i.y,e),t.event.preventDefault()}}),e.touch.on(pc.EVENT_TOUCHMOVE,t=>{if(this.isDragging&&1===t.touches.length){const i=t.touches[0];this.updateDragFromInput(i.x,i.y,e),t.event.preventDefault()}}),e.touch.on(pc.EVENT_TOUCHEND,t=>{this.isDragging&&(this.endDragFromInput(e),t.event.preventDefault())})),this.showDragModeIndicator()},toggleDragMode(){"XZ"===this.dragMode?this.dragMode="XY":"XY"===this.dragMode?this.dragMode="YZ":this.dragMode="XZ",console.log(`[PuzzleTestScene] Drag mode switched to: ${this.dragMode} plane`),this.showDragModeIndicator()},showDragModeIndicator(){let e,t;switch(this.dragMode){case"XZ":e="HORIZONTAL DRAG",t="Move objects left/right and forward/back";break;case"XY":e="VERTICAL DRAG (Front View)",t="Move objects up/down and left/right";break;case"YZ":e="VERTICAL DRAG (Side View)",t="Move objects up/down and forward/back";break;default:e="UNKNOWN MODE",t="Unknown drag mode"}this.app&&this.app.fire&&this.app.fire("ui:notification",{text:`${e}: ${t}`,type:"info",duration:2500}),this.updateModeIndicator(this.dragMode,this.app),this.app&&this.app.fire&&this.app.fire("puzzle:mode_change",{mode:this.dragMode})},showBriefingInstructions(){const e=["π― PUZZLE OBJECTIVE: Pack all 6 objects into the container","","π¦ PLACEMENT RULES:","β’ Objects must align with the bottom grid to be valid","β’ Objects cannot overlap or float above the container floor","β’ Use the grid lines as visual guides for positioning","","πΉοΈ DRAG CONTROLS:","β’ SPACE - Cycle through drag modes:"," - Horizontal: Move left/right and forward/back"," - Vertical (Front): Move up/down and left/right"," - Vertical (Side): Move up/down and forward/back","","π‘ TIPS:","β’ Try different drag modes to position objects precisely","β’ Look for the green grid indicator showing valid placement area","β’ Objects will change color during dragging to show validity"].join("\n");this.app&&this.app.fire&&this.app.fire("ui:notification",{text:e,type:"info",duration:8e3})},updateModeIndicator(e,t){const i=t.root.findByTag("drag_mode_indicator")[0];if(i&&i.model&&i.model.meshInstances){const t=i.model.meshInstances[0].material;switch(e){case"XZ":t.diffuse=new pc.Color(.2,.4,.1),t.emissive=new pc.Color(.1,.2,.05);break;case"XY":t.diffuse=new pc.Color(.1,.2,.4),t.emissive=new pc.Color(.05,.1,.2);break;case"YZ":t.diffuse=new pc.Color(.4,.2,.1),t.emissive=new pc.Color(.2,.1,.05)}t.update()}},startDragFromInput(e,t,i){try{const o=this.camera;if(!o||!o.camera)return void console.warn("[PuzzleTestScene] No camera available for raycast");console.log("[PuzzleTestScene] Starting drag from input:",e,t);const s=o.camera.screenToWorld(e,t,o.camera.nearClip),n=o.camera.screenToWorld(e,t,o.camera.farClip);if(!s||!n||void 0===s.x||void 0===n.x)return void console.error("[PuzzleTestScene] Invalid screenToWorld results:",{ray:s,rayEnd:n});const a=(new pc.Vec3).copy(n).sub(s);if(!a||void 0===a.x||void 0===a.y||void 0===a.z)return void console.error("[PuzzleTestScene] Invalid ray vector before normalization:",a);const c=a.length();if(0===c||!isFinite(c))return void console.error("[PuzzleTestScene] Zero or invalid length ray vector:",a,"length:",c);const r=a.normalize();if(!(r&&void 0!==r.x&&void 0!==r.y&&void 0!==r.z&&isFinite(r.x)&&isFinite(r.y)&&isFinite(r.z)))return void console.error("[PuzzleTestScene] Invalid ray direction after normalization:",r);console.log("[PuzzleTestScene] Ray:",s,"Dir:",r);const l=this.raycastForPuzzleObject(s,r,i);console.log("[PuzzleTestScene] Hit entity:",l?.name,"has puzzleObject:",!!l?.puzzleObject),l&&l.puzzleObject&&this.startDragEntity(l,s,r)}catch(e){console.error("[PuzzleTestScene] Error in startDragFromInput:",e)}},raycastForPuzzleObject(e,t,i){try{if(i.systems.rigidbody&&i.systems.rigidbody.raycastFirst&&"undefined"!=typeof Ammo)try{const o=e.clone().add(t.clone().scale(100)),s=i.systems.rigidbody.raycastFirst(e,o);if(s&&s.entity&&s.entity.tags.has("puzzle_object"))return console.log("[PuzzleTestScene] Physics raycast hit:",s.entity.name),s.entity}catch(e){console.warn("[PuzzleTestScene] Physics raycast failed, using manual method:",e.message)}let o=null,s=1/0;const n=i.root.findByTag("puzzle_object");return console.log("[PuzzleTestScene] Found",n.length,"puzzle objects for manual raycast"),n.forEach(i=>{try{const n=i.getPosition(),a=i.getLocalScale(),c=.8*Math.max(a.x,a.y,a.z),r=n.clone().sub(e).dot(t);if(r>0){const a=e.clone().add(t.clone().scale(r)),l=n.distance(a);console.log("[PuzzleTestScene] Testing entity:",i.name,"distance to ray:",l.toFixed(2),"radius:",c.toFixed(2)),l<=c&&r<s&&(s=r,o=i,console.log("[PuzzleTestScene] New closest entity:",i.name))}}catch(e){console.warn("[PuzzleTestScene] Error processing entity:",i.name,e)}}),o}catch(e){return console.error("[PuzzleTestScene] Error in raycastForPuzzleObject:",e),null}},startDragEntity(e,t,i){try{if(!e.puzzleObject)return;if(!(t&&i&&void 0!==t.x&&void 0!==t.y&&void 0!==t.z&&void 0!==i.x&&void 0!==i.y&&void 0!==i.z&&isFinite(t.x)&&isFinite(t.y)&&isFinite(t.z)&&isFinite(i.x)&&isFinite(i.y)&&isFinite(i.z)))return void console.error("[PuzzleTestScene] Invalid ray parameters for drag:",{rayStart:t,rayDir:i});this.isDragging=!0,this.draggedEntity=e;const o=e.getPosition();if(!o||void 0===o.x)return console.error("[PuzzleTestScene] Invalid object position for drag:",o),this.isDragging=!1,void(this.draggedEntity=null);let s;switch(this.dragMode){case"XZ":default:s=new pc.Vec3(0,1,0);break;case"XY":s=new pc.Vec3(0,0,1);break;case"YZ":s=new pc.Vec3(1,0,0)}const n=o.clone(),a=new pc.Vec3;let c=!1;try{const e=(new pc.Vec3).copy(n).sub(t),o=i.dot(s);if(Math.abs(o)>1e-4){const n=e.dot(s)/o;a.copy(t).add(i.clone().scale(n)),c=!0}else console.warn("[PuzzleTestScene] Ray parallel to plane, cannot intersect"),c=!1}catch(e){console.error("[PuzzleTestScene] Manual plane intersection error:",e),c=!1}c&&void 0!==a.x?(this.dragOffset.copy(o).sub(a),this.dragPlaneNormal=s.clone(),this.dragPlanePoint=n.clone()):(console.warn("[PuzzleTestScene] Plane intersection failed, using zero offset"),this.dragOffset.set(0,0,0),this.dragPlaneNormal=s.clone(),this.dragPlanePoint=o.clone()),this.puzzle.startDrag(e.puzzleObject.id)}catch(e){console.error("[PuzzleTestScene] Error in startDragEntity:",e),this.isDragging=!1,this.draggedEntity=null}},updateDragFromInput(e,t,i){try{if(!this.isDragging||!this.draggedEntity||!this.camera)return;const i=this.camera;if(!i.camera)return;const o=i.camera.screenToWorld(e,t,i.camera.nearClip),s=i.camera.screenToWorld(e,t,i.camera.farClip);if(!o||!s||void 0===o.x||void 0===s.x)return void console.warn("[PuzzleTestScene] Invalid screenToWorld results in drag update:",{ray:o,rayEnd:s});const n=(new pc.Vec3).copy(s).sub(o).normalize();if(!n||void 0===n.x||0===n.length())return void console.warn("[PuzzleTestScene] Invalid ray direction in drag update:",n);const a=new pc.Vec3;let c=!1;try{if(this.dragPlaneNormal&&this.dragPlanePoint&&o&&n){const e=(new pc.Vec3).copy(this.dragPlanePoint).sub(o),t=n.dot(this.dragPlaneNormal);if(Math.abs(t)>1e-4){const i=e.dot(this.dragPlaneNormal)/t;a.copy(o).add(n.clone().scale(i)),c=!0}}}catch(e){console.error("[PuzzleTestScene] Manual plane intersection error in updateDrag:",e),c=!1}if(c&&void 0!==a.x){const e=a.add(this.dragOffset);this.puzzle.updateDrag(e)}}catch(e){console.error("[PuzzleTestScene] Error in updateDragFromInput:",e)}},endDragFromInput(e){try{if(!this.isDragging||!this.draggedEntity)return;const e=this.draggedEntity.getPosition();this.puzzle.completeDrop(e),this.isDragging=!1,this.draggedEntity=null}catch(e){console.error("[PuzzleTestScene] Error in endDragFromInput:",e)}},returnToOriginalPosition(){if(!this.draggedEntity)return;const e=this.draggedEntity.puzzleObject,t=this.puzzle.objects.findIndex(t=>t.id===e.id),i=this.puzzle.objects.length/2*-3+3*t;this.draggedEntity.setPosition(i,0,-this.puzzle.space.bounds.depth-3)},setupPuzzleEvents(e,t){const i=t.getSystem("objectivemanager");e.on("ui:request_instructions",()=>{this.showBriefingInstructions()}),e.on("puzzle:placement_success",o=>{const s=this.puzzle.getStatus();console.log("[PuzzleTestScene] Placement success! Status:",s),console.log("[PuzzleTestScene] ObjectManager exists:",!!i),console.log("[PuzzleTestScene] ObjectManager type:",typeof i),console.log("[PuzzleTestScene] ObjectManager methods:",i?Object.keys(i):"null"),console.log("[PuzzleTestScene] Has defineObjective method:",i&&"function"==typeof i.defineObjective),e.fire("ui:notification",{text:`Placed ${o.object.id}! Progress: ${s.placedObjects}/${s.totalObjects}`,type:"success",duration:2e3}),i&&1===s.placedObjects&&i.isObjectiveActive("puzzle_tutorial")&&(console.log("[PuzzleTestScene] Completing tutorial objective"),i.completeObjective("puzzle_tutorial"),i.startObjective("place_all_items")),i&&i.isObjectiveActive("place_all_items")&&(console.log("[PuzzleTestScene] Updating place_all_items objective with progress:",s.placedObjects),i.updateObjective("place_all_items",s.placedObjects)),i&&s.placedObjects===s.totalObjects&&i.isComplete("place_all_items")&&(console.log("[PuzzleTestScene] Starting efficiency objective"),i.startObjective("achieve_efficiency"),this.checkEfficiencyObjective(e,t,s)),this.updateProgressDisplay(e,s)}),e.on("puzzle:placement_failed",t=>{e.fire("ui:notification",{text:`Cannot place ${t.object.id} here!`,type:"error",duration:2e3})}),e.on("puzzle:completed",i=>{const o=this.puzzle.getStatus();e.fire("ui:notification",{text:`Puzzle Complete! Score: ${o.score} - Efficiency: ${Math.round(100*o.utilization)}%`,type:"success",duration:5e3}),this.checkEfficiencyObjective(e,t,o)})},checkEfficiencyObjective(e,t,i){const o=t.getSystem("objectivemanager");o&&o.isObjectiveActive("achieve_efficiency")&&i.utilization>=.7&&(o.completeObjective("achieve_efficiency"),e.fire("ui:notification",{text:`Excellent! ${Math.round(100*i.utilization)}% efficiency achieved!`,type:"success",duration:4e3}))},updateProgressDisplay(e,t){const i=e.root.findByTag("progress_display")[0];if(i&&i.model){const e=i.model.meshInstances[0].material,o=t.placedObjects/t.totalObjects;e.diffuse=new pc.Color(.2+.3*o,.3+.4*o,.2),t.isComplete&&(e.emissive=new pc.Color(.1,.3,.1)),e.update()}},handleInteraction(e,t,i){console.log("[PuzzleTestScene] Interaction with:",e),"reset_button"===e&&this.resetPuzzle(t)},resetPuzzle(e){this.puzzle&&(this.puzzle.space.currentState.clear(),this.puzzle.objects.forEach(e=>{if(e.state="available",e.entity){const t=e.entity.model.meshInstances[0].material;t.emissive=new pc.Color(0,0,0),t.update()}}),this.puzzle.arrangeInitialObjects(),this.puzzle.objectives.forEach(e=>{e.completed=!1,e.progress=0}),this.puzzle.isComplete=!1,this.puzzle.currentScore=0,e.fire("ui:notification",{text:"Puzzle reset! Try again.",type:"info",duration:2e3}),this.updateProgressDisplay(e,this.puzzle.getStatus()))},onUnload(e,t){console.log("[PuzzleTestScene] Cleaning up puzzle test scene..."),e.mouse&&(e.mouse.off(pc.EVENT_MOUSEDOWN),e.mouse.off(pc.EVENT_MOUSEMOVE),e.mouse.off(pc.EVENT_MOUSEUP)),e.touch&&(e.touch.off(pc.EVENT_TOUCHSTART),e.touch.off(pc.EVENT_TOUCHMOVE),e.touch.off(pc.EVENT_TOUCHEND)),e.keyboard&&e.keyboard.off(pc.EVENT_KEYDOWN),e.off("puzzle:placement_success"),e.off("puzzle:placement_failed"),e.off("puzzle:completed"),e.off("ui:request_instructions"),this.defaultInteractionDisabled&&e.interactionController&&(console.log("[PuzzleTestScene] Re-enabling default interaction controller"),e.on("update",e.interactionController.update,e.interactionController),this.defaultInteractionDisabled=!1),this.interactionHandler=null,this.puzzle=null}}}}]); |