fix: load all models/
This commit is contained in:
+36
-36
@@ -28,14 +28,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [64.2046, 1.3963, -66.2457],
|
"position": [64.2046, 1.3963, -66.2457],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-77.4301, 1.3912, -56.435],
|
"position": [-77.4301, 1.3912, -56.435],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [9.1941, 10.2941, 72.1876],
|
"position": [9.1941, 10.2941, 72.1876],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -77,21 +77,21 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-8.7053, 20.947, 57.5741],
|
"position": [-8.7053, 20.947, 57.5741],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-89.8978, 1.4012, -25.8285],
|
"position": [-89.8978, 1.4012, -25.8285],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [51.8989, 4.3513, -50.0921],
|
"position": [51.8989, 4.3513, -50.0921],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [34.9999, 1.4037, 93.9609],
|
"position": [34.9999, 1.4037, 93.9609],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -126,35 +126,35 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [38.7701, 19.0344, 0.8338],
|
"position": [38.7701, 19.0344, 0.8338],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [59.3076, 6.5206, 49.1125],
|
"position": [59.3076, 6.5206, 49.1125],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-89.2687, 2.6346, 16.7745],
|
"position": [-89.2687, 2.6346, 16.7745],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [17.8449, 19.0217, -19.9902],
|
"position": [17.8449, 19.0217, -19.9902],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [69.5646, 5.8304, -13.2384],
|
"position": [69.5646, 5.8304, -13.2384],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -168,28 +168,28 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [70.7249, 3.0111, -37.8449],
|
"position": [70.7249, 3.0111, -37.8449],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [38.1303, 19.7136, 34.2969],
|
"position": [38.1303, 19.7136, 34.2969],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-31.6587, 20.5164, -4.8425],
|
"position": [-31.6587, 20.5164, -4.8425],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [65.6865, 1.3944, 77.4458],
|
"position": [65.6865, 1.3944, 77.4458],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-1.7275, 1.4007, 102.2273],
|
"position": [-1.7275, 1.4007, 102.2273],
|
||||||
"rotation": [0, 0, 0],
|
"rotation": [0, 0, 0],
|
||||||
@@ -4207,21 +4207,21 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [13.7329, 23.9356, 47.3633],
|
"position": [13.7329, 23.9356, 47.3633],
|
||||||
"rotation": [3.1416, -0.5734, 3.1416],
|
"rotation": [3.1416, -0.5734, 3.1416],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [6.2307, 23.9356, 50.7095],
|
"position": [6.2307, 23.9356, 50.7095],
|
||||||
"rotation": [3.1416, -0.2657, 3.1416],
|
"rotation": [3.1416, -0.2657, 3.1416],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-1.9326, 23.9356, 51.6261],
|
"position": [-1.9326, 23.9356, 51.6261],
|
||||||
"rotation": [3.1416, 0.042, 3.1416],
|
"rotation": [3.1416, 0.042, 3.1416],
|
||||||
@@ -4235,14 +4235,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-17.1848, 23.9356, 46.0625],
|
"position": [-17.1848, 23.9356, 46.0625],
|
||||||
"rotation": [3.1416, 0.6575, 3.1416],
|
"rotation": [3.1416, 0.6575, 3.1416],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-22.8406, 23.9356, 40.105],
|
"position": [-22.8406, 23.9356, 40.105],
|
||||||
"rotation": [-3.1416, 0.9652, 3.1416],
|
"rotation": [-3.1416, 0.9652, 3.1416],
|
||||||
@@ -4263,14 +4263,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-26.2655, 23.9356, 16.4799],
|
"position": [-26.2655, 23.9356, 16.4799],
|
||||||
"rotation": [0, 1.2532, 0],
|
"rotation": [0, 1.2532, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-22.5343, 23.9356, 9.1615],
|
"position": [-22.5343, 23.9356, 9.1615],
|
||||||
"rotation": [0, 0.9454, 0],
|
"rotation": [0, 0.9454, 0],
|
||||||
@@ -4291,14 +4291,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-1.4024, 23.9356, -1.9435],
|
"position": [-1.4024, 23.9356, -1.9435],
|
||||||
"rotation": [0, 0.0223, 0],
|
"rotation": [0, 0.0223, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [6.7412, 23.9356, -0.8655],
|
"position": [6.7412, 23.9356, -0.8655],
|
||||||
"rotation": [0, -0.2855, 0],
|
"rotation": [0, -0.2855, 0],
|
||||||
@@ -4312,7 +4312,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [20.2026, 23.9356, 8.2103],
|
"position": [20.2026, 23.9356, 8.2103],
|
||||||
"rotation": [0, -0.9009, 0],
|
"rotation": [0, -0.9009, 0],
|
||||||
@@ -4368,7 +4368,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-7.324, 26.3756, 42.7182],
|
"position": [-7.324, 26.3756, 42.7182],
|
||||||
"rotation": [-3.1416, 0.3498, 3.1416],
|
"rotation": [-3.1416, 0.3498, 3.1416],
|
||||||
@@ -4389,14 +4389,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-18.9887, 26.3756, 30.4312],
|
"position": [-18.9887, 26.3756, 30.4312],
|
||||||
"rotation": [-3.1416, 1.273, 3.1416],
|
"rotation": [-3.1416, 1.273, 3.1416],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-19.8252, 26.3756, 24.6616],
|
"position": [-19.8252, 26.3756, 24.6616],
|
||||||
"rotation": [0, 1.5609, 0],
|
"rotation": [0, 1.5609, 0],
|
||||||
@@ -4417,14 +4417,14 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-12.1298, 26.3756, 9.568],
|
"position": [-12.1298, 26.3756, 9.568],
|
||||||
"rotation": [0, 0.6377, 0],
|
"rotation": [0, 0.6377, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [-6.9691, 26.3756, 6.856],
|
"position": [-6.9691, 26.3756, 6.856],
|
||||||
"rotation": [0, 0.33, 0],
|
"rotation": [0, 0.33, 0],
|
||||||
@@ -4445,7 +4445,7 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [9.8265, 26.3756, 9.0793],
|
"position": [9.8265, 26.3756, 9.0793],
|
||||||
"rotation": [0, -0.5932, 0],
|
"rotation": [0, -0.5932, 0],
|
||||||
@@ -4459,21 +4459,21 @@
|
|||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [16.9803, 26.3756, 18.1116],
|
"position": [16.9803, 26.3756, 18.1116],
|
||||||
"rotation": [0, -1.2087, 0],
|
"rotation": [0, -1.2087, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [18.1858, 26.3756, 23.8156],
|
"position": [18.1858, 26.3756, 23.8156],
|
||||||
"rotation": [0, -1.5164, 0],
|
"rotation": [0, -1.5164, 0],
|
||||||
"scale": [1, 1, 1]
|
"scale": [1, 1, 1]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "arbre",
|
"name": "pylone",
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"position": [17.6069, 26.3756, 29.6167],
|
"position": [17.6069, 26.3756, 29.6167],
|
||||||
"rotation": [3.1416, -1.3175, 3.1416],
|
"rotation": [3.1416, -1.3175, 3.1416],
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>test_model</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Index of /models/test_model/
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -269,52 +269,27 @@ export function EditorPage(): React.JSX.Element {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapNodes = await response.json();
|
const mapNodes: MapNode[] = await response.json();
|
||||||
|
|
||||||
const models = new Map<string, string>();
|
const models = new Map<string, string>();
|
||||||
|
|
||||||
try {
|
const uniqueModelNames = [
|
||||||
const traverseModels = async (path: string): Promise<void> => {
|
...new Set(mapNodes.map((n: MapNode) => n.name)),
|
||||||
try {
|
];
|
||||||
const response = await fetch(path);
|
console.log("Unique model names in map:", uniqueModelNames);
|
||||||
if (!response.ok) return;
|
|
||||||
const text = await response.text();
|
|
||||||
|
|
||||||
if (text.includes("index")) {
|
for (const modelName of uniqueModelNames) {
|
||||||
const modelUrl = path.replace(/\/$/, "") + "/model.glb";
|
try {
|
||||||
|
const modelUrl = `/models/${modelName}/model.gltf`;
|
||||||
const modelResponse = await fetch(modelUrl);
|
const modelResponse = await fetch(modelUrl);
|
||||||
if (modelResponse.ok) {
|
if (modelResponse.ok) {
|
||||||
const blob = await modelResponse.blob();
|
models.set(modelName, modelUrl);
|
||||||
const blobUrl = URL.createObjectURL(blob);
|
|
||||||
const pathParts = path.split("/").filter(Boolean);
|
|
||||||
const modelName = pathParts[pathParts.length - 1] || "";
|
|
||||||
models.set(modelName, blobUrl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const baseResponse = await fetch("/models/");
|
|
||||||
if (baseResponse.ok) {
|
|
||||||
const text = await baseResponse.text();
|
|
||||||
const lines = text.split("\n");
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.includes("href") && line.includes("/")) {
|
|
||||||
const match = line.match(/href="([^"]+)"/);
|
|
||||||
if (match && match[1]) {
|
|
||||||
const href = match[1];
|
|
||||||
if (href.endsWith("/")) {
|
|
||||||
await traverseModels(href);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("Could not scan models directory:", error);
|
|
||||||
}
|
}
|
||||||
|
console.log("Loaded models:", Array.from(models.keys()));
|
||||||
|
|
||||||
setSceneData({ mapNodes, models });
|
setSceneData({ mapNodes, models });
|
||||||
setHasMapJson(true);
|
setHasMapJson(true);
|
||||||
@@ -356,7 +331,7 @@ export function EditorPage(): React.JSX.Element {
|
|||||||
const models = new Map<string, string>();
|
const models = new Map<string, string>();
|
||||||
|
|
||||||
for (const [path, file] of fileMap.entries()) {
|
for (const [path, file] of fileMap.entries()) {
|
||||||
const modelMatch = path && path.match(/^\/models\/(.+)\/model\.glb$/);
|
const modelMatch = path && path.match(/^\/models\/(.+)\/model\.gltf$/);
|
||||||
if (modelMatch && modelMatch[1]) {
|
if (modelMatch && modelMatch[1]) {
|
||||||
const modelName = modelMatch[1];
|
const modelName = modelMatch[1];
|
||||||
const blobUrl = URL.createObjectURL(file);
|
const blobUrl = URL.createObjectURL(file);
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import { useEffect, useState, useMemo, useRef } from "react";
|
||||||
|
import { useGLTF } from "@react-three/drei";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { useOctreeGraphNode } from "@/hooks/useOctreeGraphNode";
|
||||||
|
import type { OctreeReadyHandler } from "@/types/3d";
|
||||||
|
|
||||||
|
interface MapNode {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
scale: [number, number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAP_JSON_PATH = "/map.json";
|
||||||
|
|
||||||
|
const clonedScenesCache = new Map<string, THREE.Group>();
|
||||||
|
|
||||||
|
interface GameMapProps {
|
||||||
|
onOctreeReady: OctreeReadyHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GameMap({ onOctreeReady }: GameMapProps): React.JSX.Element {
|
||||||
|
const [mapNodes, setMapNodes] = useState<MapNode[]>([]);
|
||||||
|
const [availableModels, setAvailableModels] = useState<Set<string>>(
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
|
|
||||||
|
useOctreeGraphNode(groupRef, onOctreeReady);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadMap = async () => {
|
||||||
|
try {
|
||||||
|
const nodesResponse = await fetch(MAP_JSON_PATH);
|
||||||
|
if (!nodesResponse.ok) {
|
||||||
|
console.warn("map.json not found");
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodes: MapNode[] = await nodesResponse.json();
|
||||||
|
setMapNodes(nodes);
|
||||||
|
|
||||||
|
const uniqueModelNames = [...new Set(nodes.map((n) => n.name))];
|
||||||
|
const available = new Set<string>();
|
||||||
|
|
||||||
|
for (const modelName of uniqueModelNames) {
|
||||||
|
try {
|
||||||
|
const modelUrl = `/models/${modelName}/model.gltf`;
|
||||||
|
const modelResponse = await fetch(modelUrl);
|
||||||
|
if (modelResponse.ok) {
|
||||||
|
available.add(modelName);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAvailableModels(available);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading map:", error);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadMap();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const nodesToRender = useMemo(() => {
|
||||||
|
return mapNodes.filter((node) => availableModels.has(node.name));
|
||||||
|
}, [mapNodes, availableModels]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group ref={groupRef}>
|
||||||
|
{nodesToRender.map((node, index) => (
|
||||||
|
<ModelInstance key={index} node={node} />
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ModelInstance({ node }: { node: MapNode }): React.JSX.Element {
|
||||||
|
const modelPath = `/models/${node.name}/model.gltf`;
|
||||||
|
const { scene } = useGLTF(modelPath);
|
||||||
|
|
||||||
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
|
|
||||||
|
const clonedScene = useMemo(() => {
|
||||||
|
if (!clonedScenesCache.has(modelPath)) {
|
||||||
|
const clone = scene.clone(true);
|
||||||
|
clonedScenesCache.set(modelPath, clone);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
return clonedScenesCache.get(modelPath)!;
|
||||||
|
}, [modelPath, scene]);
|
||||||
|
|
||||||
|
const instance = useMemo(() => {
|
||||||
|
const inst = clonedScene.clone(true);
|
||||||
|
inst.position.set(...node.position);
|
||||||
|
inst.rotation.set(...node.rotation);
|
||||||
|
inst.scale.set(...node.scale);
|
||||||
|
return inst;
|
||||||
|
}, [clonedScene, node.position, node.rotation, node.scale]);
|
||||||
|
|
||||||
|
return <primitive ref={groupRef} object={instance} />;
|
||||||
|
}
|
||||||
+2
-2
@@ -10,7 +10,7 @@ import { DebugCameraControls } from "@/utils/debug/scene/DebugCameraControls";
|
|||||||
import { DebugHelpers } from "@/utils/debug/scene/DebugHelpers";
|
import { DebugHelpers } from "@/utils/debug/scene/DebugHelpers";
|
||||||
import { Environment } from "@/world/Environment";
|
import { Environment } from "@/world/Environment";
|
||||||
import { Lighting } from "@/world/Lighting";
|
import { Lighting } from "@/world/Lighting";
|
||||||
import { Map } from "@/world/Map";
|
import { GameMap } from "@/components/game/GameMap";
|
||||||
import { PlayerComponent } from "@/world/player/PlayerComponent";
|
import { PlayerComponent } from "@/world/player/PlayerComponent";
|
||||||
import { TestScene } from "@/world/debug/TestScene";
|
import { TestScene } from "@/world/debug/TestScene";
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export function World(): React.JSX.Element {
|
|||||||
{cameraMode === "debug" ? <DebugCameraControls /> : null}
|
{cameraMode === "debug" ? <DebugCameraControls /> : null}
|
||||||
|
|
||||||
{sceneMode === "game" ? (
|
{sceneMode === "game" ? (
|
||||||
<Map onOctreeReady={setOctree} />
|
<GameMap onOctreeReady={setOctree} />
|
||||||
) : (
|
) : (
|
||||||
<TestScene onOctreeReady={setOctree} />
|
<TestScene onOctreeReady={setOctree} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user