awacke1 commited on
Commit
039b051
·
verified ·
1 Parent(s): 7136196

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +36 -42
index.html CHANGED
@@ -1,7 +1,7 @@
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
- <title>Three.js Synced World (DB Backend)</title>
5
  <style>
6
  body { margin: 0; overflow: hidden; }
7
  canvas { display: block; }
@@ -20,7 +20,7 @@
20
  <script type="module">
21
  import * as THREE from 'three';
22
 
23
- // ... (Keep all variables: scene, camera, renderer, playerMesh, etc.) ...
24
  let scene, camera, renderer, playerMesh;
25
  let raycaster, mouse;
26
  const keysPressed = {};
@@ -28,67 +28,61 @@
28
  let newlyPlacedObjects = []; // For sessionStorage persistence between non-save reruns
29
  const placeholderPlots = new Set();
30
  const groundMeshes = {};
31
- const allRenderedObjects = {}; // Track all scene objects: id -> mesh/group
32
 
33
- const SESSION_STORAGE_KEY = 'unsavedDbWorldState_v2';
34
 
35
- // --- Access State from Streamlit ---
36
  const allInitialObjects = window.ALL_INITIAL_OBJECTS || []; // From DB
37
  const plotsMetadata = window.PLOTS_METADATA || []; // From DB
38
  const selectedObjectType = window.SELECTED_OBJECT_TYPE || "None";
39
  const plotWidth = window.PLOT_WIDTH || 50.0;
40
  const plotDepth = window.PLOT_DEPTH || 50.0;
41
 
 
42
  const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x55aa55, roughness: 0.9, metalness: 0.1, side: THREE.DoubleSide });
43
  const placeholderGroundMaterial = new THREE.MeshStandardMaterial({ color: 0x448844, roughness: 0.95, metalness: 0.1, side: THREE.DoubleSide });
44
 
45
-
46
- // --- init() function ---
47
  function init() {
48
- // ... (scene, camera, renderer setup as before) ...
49
- scene = new THREE.Scene(); scene.background = new THREE.Color(0xabcdef);
50
- const aspect = window.innerWidth / window.innerHeight; camera = new THREE.PerspectiveCamera(60, aspect, 0.1, 4000); camera.position.set(0, 15, 20); camera.lookAt(0, 0, 0); scene.add(camera);
51
- setupLighting(); setupInitialGround(); setupPlayer();
52
- raycaster = new THREE.Raycaster(); mouse = new THREE.Vector2();
53
- renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; document.body.appendChild(renderer.domElement);
54
 
55
- loadInitialObjects(); // Load from DB data
56
- restoreUnsavedState(); // Restore from SessionStorage
57
 
58
- // Event Listeners
59
  document.addEventListener('mousemove', onMouseMove, false); document.addEventListener('click', onDocumentClick, false); window.addEventListener('resize', onWindowResize, false); document.addEventListener('keydown', onKeyDown); document.addEventListener('keyup', onKeyUp);
60
-
61
- // Define global functions needed by Python
62
  window.teleportPlayer = teleportPlayer;
63
- window.getSaveDataAndPosition = getSaveDataAndPosition; // Ensure this is defined correctly below
64
- // window.resetNewlyPlacedObjects = resetNewlyPlacedObjects; // No longer needed
65
 
66
- console.log("Three.js Initialized (DB Backend v2). World ready.");
67
  animate();
68
  }
69
 
70
- // --- setupLighting(), setupInitialGround(), createGroundPlane(), setupPlayer() ---
71
- // ... (Keep these functions exactly as in the previous version) ...
72
- function setupLighting() { const a=new THREE.AmbientLight(0xffffff,0.5); scene.add(a); const d=new THREE.DirectionalLight(0xffffff,1.0); d.position.set(50,150,100); d.castShadow=true; d.shadow.mapSize.width=4096; d.shadow.mapSize.height=4096; d.shadow.camera.near=0.5; d.shadow.camera.far=500; d.shadow.camera.left=-150; d.shadow.camera.right=150; d.shadow.camera.top=150; d.shadow.camera.bottom=-150; d.shadow.bias=-0.001; scene.add(d); }
73
- function setupInitialGround() { plotsMetadata.forEach(p => {createGroundPlane(p.grid_x,p.grid_z,false);}); if(plotsMetadata.length===0) {createGroundPlane(0,0,false);} }
74
- function createGroundPlane(gx,gz,isPlaceholder) { const k=`<span class="math-inline">\{gx\}\_</span>{gz}`; if(groundMeshes[k]) return; const geo=new THREE.PlaneGeometry(plotWidth,plotDepth); const mat=isPlaceholder?placeholderGroundMaterial:groundMaterial; const mesh=new THREE.Mesh(geo,mat); mesh.rotation.x=-Math.PI/2; mesh.position.y=-0.05; mesh.position.x=gx*plotWidth+plotWidth/2; mesh.position.z=gz*plotDepth+plotDepth/2; mesh.receiveShadow=true; mesh.userData.gridKey=k; scene.add(mesh); groundMeshes[k]=mesh; if(isPlaceholder){placeholderPlots.add(k);} }
75
- function setupPlayer() { const g=new THREE.CapsuleGeometry(0.4,0.8,4,8); const m=new THREE.MeshStandardMaterial({color:0x0000ff,roughness:0.6}); playerMesh=new THREE.Mesh(g,m); playerMesh.position.set(plotWidth/2,0.8,plotDepth/2); playerMesh.castShadow=true; playerMesh.receiveShadow=true; scene.add(playerMesh); }
76
-
77
 
78
- // --- loadInitialObjects(), clearAllRenderedObjects(), createAndPlaceObject() ---
79
- // ... (Keep these functions exactly as in the previous version - ensuring createAndPlaceObject adds to allRenderedObjects) ...
80
- function loadInitialObjects() { console.log(`Loading ${allInitialObjects.length} initial objects.`); clearAllRenderedObjects(); allInitialObjects.forEach(d => { createAndPlaceObject(d, false); }); console.log("Finished initial load."); }
81
- function clearAllRenderedObjects() { Object.values(allRenderedObjects).forEach(o => scene.remove(o)); for (const k in allRenderedObjects) delete allRenderedObjects[k]; newlyPlacedObjects = []; /* Important: clear this too when reloading all */ }
82
- function createAndPlaceObject(objData, isNewObjectForSession) { let obj=null; switch (objData.type) { case "Simple House": obj=createSimpleHouse(); break; case "Tree": obj=createTree(); break; case "Rock": obj=createRock(); break; case "Fence Post": obj=createFencePost(); break; default: return null; } if (obj) { obj.userData.obj_id = objData.obj_id || obj.userData.obj_id; if (allRenderedObjects[obj.userData.obj_id]) return null; if(objData.position&&objData.position.x!==undefined){obj.position.set(objData.position.x,objData.position.y,objData.position.z);}else if(objData.pos_x!==undefined){obj.position.set(objData.pos_x,objData.pos_y,objData.pos_z);} if(objData.rotation){obj.rotation.set(objData.rotation._x,objData.rotation._y,objData.rotation._z,objData.rotation._order||'XYZ');}else if(objData.rot_x!==undefined){obj.rotation.set(objData.rot_x,objData.rot_y,objData.rot_z,objData.rot_order||'XYZ');} scene.add(obj); allRenderedObjects[obj.userData.obj_id] = obj; if(isNewObjectForSession){newlyPlacedObjects.push(obj);} return obj; } return null; }
 
83
 
84
- // --- saveUnsavedState(), restoreUnsavedState(), clearUnsavedSessionState() ---
85
- // ... (Keep these sessionStorage functions exactly as in the previous version) ...
86
- function saveUnsavedState() { try { const d = newlyPlacedObjects.map(o => ({obj_id:o.userData.obj_id, type:o.userData.type, position:{x:o.position.x,y:o.position.y,z:o.position.z}, rotation:{_x:o.rotation.x,_y:o.rotation.y,_z:o.rotation.z,_order:o.rotation.order}})); sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(d)); } catch(e) { console.error("Session save error:", e); } }
87
- function restoreUnsavedState() { try { const s=sessionStorage.getItem(SESSION_STORAGE_KEY); if(s) { const d=JSON.parse(s); if(Array.isArray(d)) { let c=0; d.forEach(o => { if(createAndPlaceObject(o, true)) c++;}); console.log(`Restored ${c} unsaved objects.`); } } } catch(e) { console.error("Session restore error:", e); sessionStorage.removeItem(SESSION_STORAGE_KEY); } }
88
- // function clearUnsavedSessionState() { sessionStorage.removeItem(SESSION_STORAGE_KEY); newlyPlacedObjects = []; console.log("Cleared unsaved session state."); } // Might be useful later
89
-
90
- // --- Object Creation Functions ---
91
- // ... (Keep these exactly as before, ensuring they assign userData.type and userData.obj_id) ...
92
  function createObjectBase(type) { return { userData: { type: type, obj_id: THREE.MathUtils.generateUUID() } }; }
93
  function createSimpleHouse() { const base = createObjectBase("Simple House"); const group = new THREE.Group(); Object.assign(group, base); const mat1=new THREE.MeshStandardMaterial({color:0xffccaa,roughness:0.8}), mat2=new THREE.MeshStandardMaterial({color:0xaa5533,roughness:0.7}); const m1=new THREE.Mesh(new THREE.BoxGeometry(2,1.5,2.5),mat1); m1.position.y=0.75;m1.castShadow=true;m1.receiveShadow=true;group.add(m1); const m2=new THREE.Mesh(new THREE.ConeGeometry(1.8,1,4),mat2); m2.position.y=1.5+0.5;m2.rotation.y=Math.PI/4;m2.castShadow=true;m2.receiveShadow=true;group.add(m2); return group; }
94
- function createTree() { const base=createObjectBase("Tree"); const group=new THREE.Group(); Object.assign(group,base); const mat1=new THREE.MeshStandardMaterial({color:0x8B4513,roughness:0.9}), mat2=new THREE.MeshStandardMaterial({color:0x228B22,roughness:0.8}); const m1=new THREE.Mesh(new THREE.CylinderGeometry(0.3,0.4,2,8),mat1); m1.position.y=1; m1.castShadow=true;m1.receiveShadow=true;group.add(m1); const m2=
 
 
 
 
 
 
 
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
+ <title>Three.js Synced World (DB Backend v2)</title>
5
  <style>
6
  body { margin: 0; overflow: hidden; }
7
  canvas { display: block; }
 
20
  <script type="module">
21
  import * as THREE from 'three';
22
 
23
+ // --- Variables ---
24
  let scene, camera, renderer, playerMesh;
25
  let raycaster, mouse;
26
  const keysPressed = {};
 
28
  let newlyPlacedObjects = []; // For sessionStorage persistence between non-save reruns
29
  const placeholderPlots = new Set();
30
  const groundMeshes = {};
31
+ const allRenderedObjects = {}; // Tracks all current objects by ID: id -> mesh/group
32
 
33
+ const SESSION_STORAGE_KEY = 'unsavedDbWorldState_v3'; // New key for safety
34
 
35
+ // --- State from Python ---
36
  const allInitialObjects = window.ALL_INITIAL_OBJECTS || []; // From DB
37
  const plotsMetadata = window.PLOTS_METADATA || []; // From DB
38
  const selectedObjectType = window.SELECTED_OBJECT_TYPE || "None";
39
  const plotWidth = window.PLOT_WIDTH || 50.0;
40
  const plotDepth = window.PLOT_DEPTH || 50.0;
41
 
42
+ // --- Materials ---
43
  const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x55aa55, roughness: 0.9, metalness: 0.1, side: THREE.DoubleSide });
44
  const placeholderGroundMaterial = new THREE.MeshStandardMaterial({ color: 0x448844, roughness: 0.95, metalness: 0.1, side: THREE.DoubleSide });
45
 
46
+ // --- Initialization ---
 
47
  function init() {
48
+ scene = new THREE.Scene(); scene.background = new THREE.Color(0xabcdef);
49
+ const aspect = window.innerWidth / window.innerHeight; camera = new THREE.PerspectiveCamera(60, aspect, 0.1, 4000); camera.position.set(plotWidth / 2, 15, plotDepth / 2 + 20); camera.lookAt(plotWidth / 2, 0, plotDepth/2); scene.add(camera);
50
+ setupLighting(); setupInitialGround(); setupPlayer();
51
+ raycaster = new THREE.Raycaster(); mouse = new THREE.Vector2();
52
+ renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; document.body.appendChild(renderer.domElement);
 
53
 
54
+ loadInitialObjects(); // Load from DB data passed by Python
55
+ restoreUnsavedState(); // Restore objects placed THIS session before last reload
56
 
57
+ // Event Listeners & Global functions
58
  document.addEventListener('mousemove', onMouseMove, false); document.addEventListener('click', onDocumentClick, false); window.addEventListener('resize', onWindowResize, false); document.addEventListener('keydown', onKeyDown); document.addEventListener('keyup', onKeyUp);
 
 
59
  window.teleportPlayer = teleportPlayer;
60
+ window.getSaveDataAndPosition = getSaveDataAndPosition;
 
61
 
62
+ console.log("Three.js Initialized (DB Backend v3). World ready.");
63
  animate();
64
  }
65
 
66
+ // --- Setup Functions ---
67
+ function setupLighting() { const a=new THREE.AmbientLight(0xffffff,0.5); scene.add(a); const d=new THREE.DirectionalLight(0xffffff,1.0); d.position.set(50,150,100); d.castShadow=true; d.shadow.mapSize.width=4096; d.shadow.mapSize.height=4096; d.shadow.camera.near=0.5; d.shadow.camera.far=500; d.shadow.camera.left=-150; d.shadow.camera.right=150; d.shadow.camera.top=150; d.shadow.camera.bottom=-150; d.shadow.bias=-0.001; scene.add(d); }
68
+ function setupInitialGround() { plotsMetadata.forEach(p => {createGroundPlane(p.grid_x,p.grid_z,false);}); if(plotsMetadata.length===0) {createGroundPlane(0,0,false);} }
69
+ function createGroundPlane(gx,gz,isPlaceholder) { const k=`<span class="math-inline">\{gx\}\_</span>{gz}`; if(groundMeshes[k]) return; const geo=new THREE.PlaneGeometry(plotWidth,plotDepth); const mat=isPlaceholder?placeholderGroundMaterial:groundMaterial; const mesh=new THREE.Mesh(geo,mat); mesh.rotation.x=-Math.PI/2; mesh.position.y=-0.05; mesh.position.x=gx*plotWidth+plotWidth/2; mesh.position.z=gz*plotDepth+plotDepth/2; mesh.receiveShadow=true; mesh.userData.gridKey=k; scene.add(mesh); groundMeshes[k]=mesh; if(isPlaceholder){placeholderPlots.add(k);} }
70
+ function setupPlayer() { const g=new THREE.CapsuleGeometry(0.4,0.8,4,8); const m=new THREE.MeshStandardMaterial({color:0x0000ff,roughness:0.6}); playerMesh=new THREE.Mesh(g,m); playerMesh.position.set(plotWidth/2, 0.8, plotDepth/2); playerMesh.castShadow=true; playerMesh.receiveShadow=true; scene.add(playerMesh); }
 
 
71
 
72
+ // --- Object Loading / State Management ---
73
+ function loadInitialObjects() { console.log(`Loading ${allInitialObjects.length} initial objects from DB.`); clearAllRenderedObjects(); allInitialObjects.forEach(d => { createAndPlaceObject(d, false); }); console.log("Finished initial DB object load."); }
74
+ function clearAllRenderedObjects() { console.log("Clearing all rendered objects..."); Object.values(allRenderedObjects).forEach(o => {if (o.parent) {o.parent.remove(o);/* Dispose geometry/material here if memory becomes an issue */}}); for (const k in allRenderedObjects) delete allRenderedObjects[k]; newlyPlacedObjects = []; } // Clear session tracker too on full load
75
+ function createAndPlaceObject(objData, isNewObjectForSession) { let obj=null; switch(objData.type){case "Simple House":obj=createSimpleHouse();break; case "Tree":obj=createTree();break; case "Rock":obj=createRock();break; case "Fence Post":obj=createFencePost();break; default: console.warn("Unknown type:", objData.type); return null;} if(obj){ obj.userData.obj_id=objData.obj_id||obj.userData.obj_id; if(allRenderedObjects[obj.userData.obj_id]){ console.warn(`Duplicate obj ID load skipped: ${obj.userData.obj_id}`); return null;} if(objData.position&&objData.position.x!==undefined){obj.position.set(objData.position.x,objData.position.y,objData.position.z);}else if(objData.pos_x!==undefined){obj.position.set(objData.pos_x,objData.pos_y,objData.pos_z);}else{obj.position.set(0,0.5,0);} if(objData.rotation){obj.rotation.set(objData.rotation._x,objData.rotation._y,objData.rotation._z,objData.rotation._order||'XYZ');}else if(objData.rot_x!==undefined){obj.rotation.set(objData.rot_x,objData.rot_y,objData.rot_z,objData.rot_order||'XYZ');} scene.add(obj); allRenderedObjects[obj.userData.obj_id]=obj; if(isNewObjectForSession){newlyPlacedObjects.push(obj);} return obj; } return null; }
76
+ function saveUnsavedState() { try { const d = newlyPlacedObjects.map(o => ({obj_id:o.userData.obj_id, type:o.userData.type, position:{x:o.position.x,y:o.position.y,z:o.position.z}, rotation:{_x:o.rotation.x,_y:o.rotation.y,_z:o.rotation.z,_order:o.rotation.order}})); sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(d)); } catch(e) { console.error("Session save error:", e); } }
77
+ function restoreUnsavedState() { try { const s=sessionStorage.getItem(SESSION_STORAGE_KEY); if(s) { const d=JSON.parse(s); if(Array.isArray(d)) { let c=0; d.forEach(o => { if(createAndPlaceObject(o, true)) c++;}); console.log(`Restored ${c} unsaved objects from session.`); } } } catch(e) { console.error("Session restore error:", e); sessionStorage.removeItem(SESSION_STORAGE_KEY); } }
78
 
79
+ // --- Object Creation Primitives (Ensure userData includes obj_id) ---
 
 
 
 
 
 
 
80
  function createObjectBase(type) { return { userData: { type: type, obj_id: THREE.MathUtils.generateUUID() } }; }
81
  function createSimpleHouse() { const base = createObjectBase("Simple House"); const group = new THREE.Group(); Object.assign(group, base); const mat1=new THREE.MeshStandardMaterial({color:0xffccaa,roughness:0.8}), mat2=new THREE.MeshStandardMaterial({color:0xaa5533,roughness:0.7}); const m1=new THREE.Mesh(new THREE.BoxGeometry(2,1.5,2.5),mat1); m1.position.y=0.75;m1.castShadow=true;m1.receiveShadow=true;group.add(m1); const m2=new THREE.Mesh(new THREE.ConeGeometry(1.8,1,4),mat2); m2.position.y=1.5+0.5;m2.rotation.y=Math.PI/4;m2.castShadow=true;m2.receiveShadow=true;group.add(m2); return group; }
82
+ function createTree() { const base=createObjectBase("Tree"); const group=new THREE.Group(); Object.assign(group,base); const mat1=new THREE.MeshStandardMaterial({color:0x8B4513,roughness:0.9}), mat2=new THREE.MeshStandardMaterial({color:0x228B22,roughness:0.8}); const m1=new THREE.Mesh(new THREE.CylinderGeometry(0.3,0.4,2,8),mat1); m1.position.y=1; m1.castShadow=true;m1.receiveShadow=true;group.add(m1); const m2=new THREE.Mesh(new THREE.IcosahedronGeometry(1.2,0),mat2); m2.position.y=2.8; m2.castShadow=true;m2.receiveShadow=true;group.add(m2); return group; }
83
+ function createRock() { const base=createObjectBase("Rock"); const mat=new THREE.MeshStandardMaterial({color:0xaaaaaa,roughness:0.8,metalness:0.1}); const rock=new THREE.Mesh(new THREE.IcosahedronGeometry(0.7,0),mat); Object.assign(rock,base); rock.position.y=0.35; rock.rotation.set(Math.random()*Math.PI, Math.random()*Math.PI, 0); rock.castShadow=true;rock.receiveShadow=true; return rock; }
84
+ function createFencePost() { const base=createObjectBase("Fence Post"); const mat=new THREE.MeshStandardMaterial({color:0xdeb887,roughness:0.9}); const post=new THREE.Mesh(new THREE.BoxGeometry(0.2,1.5,0.2),mat); Object.assign(post,base); post.position.y=0.75; post.castShadow=true;post.receiveShadow=true; return post; }
85
+
86
+ // --- Event Handlers ---
87
+ function onMouseMove(event) { mouse.x=(event.clientX/window.innerWidth)*2-1; mouse.y=-(event.clientY/window.innerHeight)*2+1; }
88
+ function onDocumentClick(event) { if (selectedObjectType==='None') return; const grounds=Object.values(groundMeshes); if (grounds.length===0) return; raycaster.setFromCamera(mouse,