world setup

This commit is contained in:
Emmaline Autumn 2024-10-18 22:05:01 -06:00
parent 7e4d854685
commit 89502213c4
11 changed files with 346 additions and 92 deletions

View File

@ -1,9 +1,9 @@
{
"tasks": {
"dev": "deno run -A --node-modules-dir npm:vite & deno run --allow-net --allow-read --allow-write --allow-env --watch ./main.ts",
"dev": "deno run -A --node-modules-dir npm:vite & deno run --allow-net --allow-read --allow-write --allow-env --watch ./server/main.ts",
"build": "deno run -A --node-modules-dir npm:vite build",
"preview": "deno run -A --node-modules-dir npm:vite preview",
"serve": "deno run --allow-net --allow-read --allow-write --allow-env ./main.ts"
"serve": "deno run --allow-net --allow-read --allow-write --allow-env ./server/main.ts"
},
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable", "deno.ns"],
@ -17,9 +17,11 @@
"@cgg/sockpuppet/client": "../sockpuppet.ts/client/mod.ts",
"@deno/vite-plugin": "npm:@deno/vite-plugin@^1.0.0",
"@preact/preset-vite": "npm:@preact/preset-vite@^2.9.1",
"@std/fs": "jsr:@std/fs@^1.0.4",
"@std/http": "jsr:@std/http@^1.0.8",
"autoprefixer": "npm:autoprefixer@^10.4.20",
"babel-plugin-transform-hook-names": "npm:babel-plugin-transform-hook-names@^1.0.2",
"less": "npm:less@^4.2.0",
"postcss": "npm:postcss@^8.4.47",
"preact": "npm:preact@^10.24.3",
"react-router-dom": "npm:react-router-dom@^6.27.0",

94
deno.lock generated
View File

@ -18,6 +18,7 @@
"npm:@types/node@*": "22.5.4",
"npm:autoprefixer@^10.4.20": "10.4.20_postcss@8.4.47",
"npm:babel-plugin-transform-hook-names@^1.0.2": "1.0.2_@babel+core@7.25.8",
"npm:less@^4.2.0": "4.2.0",
"npm:postcss@^8.4.47": "8.4.47",
"npm:preact@^10.24.3": "10.24.3",
"npm:react-router-dom@^6.27.0": "6.27.0_react@18.3.1_react-dom@18.3.1__react@18.3.1",
@ -111,7 +112,7 @@
"debug",
"gensync",
"json5",
"semver"
"semver@6.3.1"
]
},
"@babel/generator@7.25.7": {
@ -136,7 +137,7 @@
"@babel/helper-validator-option",
"browserslist",
"lru-cache@5.1.1",
"semver"
"semver@6.3.1"
]
},
"@babel/helper-module-imports@7.25.7": {
@ -394,7 +395,7 @@
"kolorist",
"magic-string",
"node-html-parser",
"source-map",
"source-map@0.7.4",
"stack-trace",
"vite"
]
@ -623,6 +624,12 @@
"convert-source-map@2.0.0": {
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"copy-anything@2.0.6": {
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
"dependencies": [
"is-what"
]
},
"cross-spawn@7.0.3": {
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dependencies": [
@ -699,6 +706,12 @@
"entities@4.5.0": {
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
"errno@0.1.8": {
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dependencies": [
"prr"
]
},
"esbuild@0.21.5": {
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dependencies": [
@ -803,6 +816,9 @@
"globals@11.12.0": {
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"graceful-fs@4.2.11": {
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"has-flag@3.0.0": {
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
},
@ -815,6 +831,15 @@
"he@1.2.0": {
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"iconv-lite@0.6.3": {
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": [
"safer-buffer"
]
},
"image-size@0.5.5": {
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ=="
},
"is-binary-path@2.1.0": {
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dependencies": [
@ -842,6 +867,9 @@
"is-number@7.0.0": {
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-what@3.14.1": {
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="
},
"isexe@2.0.0": {
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
@ -867,6 +895,21 @@
"kolorist@1.8.0": {
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="
},
"less@4.2.0": {
"integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==",
"dependencies": [
"copy-anything",
"errno",
"graceful-fs",
"image-size",
"make-dir",
"mime",
"needle",
"parse-node-version",
"source-map@0.6.1",
"tslib"
]
},
"lilconfig@2.1.0": {
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="
},
@ -897,6 +940,13 @@
"@jridgewell/sourcemap-codec"
]
},
"make-dir@2.1.0": {
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dependencies": [
"pify@4.0.1",
"semver@5.7.2"
]
},
"merge2@1.4.1": {
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
},
@ -907,6 +957,9 @@
"picomatch"
]
},
"mime@1.6.0": {
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"minimatch@9.0.5": {
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dependencies": [
@ -930,6 +983,13 @@
"nanoid@3.3.7": {
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="
},
"needle@3.3.1": {
"integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==",
"dependencies": [
"iconv-lite",
"sax"
]
},
"node-html-parser@6.1.13": {
"integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==",
"dependencies": [
@ -961,6 +1021,9 @@
"package-json-from-dist@1.0.1": {
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
},
"parse-node-version@1.0.1": {
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA=="
},
"path-key@3.1.1": {
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
@ -983,6 +1046,9 @@
"pify@2.3.0": {
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
},
"pify@4.0.1": {
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
},
"pirates@4.0.6": {
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="
},
@ -1038,6 +1104,9 @@
"preact@10.24.3": {
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="
},
"prr@1.0.1": {
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
},
"queue-microtask@1.2.3": {
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
@ -1074,7 +1143,7 @@
"read-cache@1.0.0": {
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
"dependencies": [
"pify"
"pify@2.3.0"
]
},
"readdirp@3.6.0": {
@ -1123,12 +1192,21 @@
"queue-microtask"
]
},
"safer-buffer@2.1.2": {
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sax@1.4.1": {
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"scheduler@0.23.2": {
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"dependencies": [
"loose-envify"
]
},
"semver@5.7.2": {
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
},
"semver@6.3.1": {
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
},
@ -1147,6 +1225,9 @@
"source-map-js@1.2.1": {
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
},
"source-map@0.6.1": {
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map@0.7.4": {
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
},
@ -1253,6 +1334,9 @@
"ts-interface-checker@0.1.13": {
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
},
"tslib@2.8.0": {
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
},
"undici-types@6.19.8": {
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
@ -1308,12 +1392,14 @@
"workspace": {
"dependencies": [
"jsr:@bearmetal/store@^0.0.4",
"jsr:@std/fs@^1.0.4",
"jsr:@std/http@^1.0.8",
"npm:@babel/plugin-transform-react-jsx-development@^7.25.7",
"npm:@deno/vite-plugin@1",
"npm:@preact/preset-vite@^2.9.1",
"npm:autoprefixer@^10.4.20",
"npm:babel-plugin-transform-hook-names@^1.0.2",
"npm:less@^4.2.0",
"npm:postcss@^8.4.47",
"npm:preact@^10.24.3",
"npm:react-router-dom@^6.27.0",

View File

@ -5,6 +5,9 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Preact + TS</title>
<style lang="less">
@import './src/index.less';
</style>
</head>
<body>
<div id="app"></div>

66
main.ts
View File

@ -1,66 +0,0 @@
import { SockpuppetPlus } from "@cgg/sockpuppet";
import { serveDir } from "@std/http/file-server";
import { BearMetalStore } from "@bearmetal/store";
const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./";
const sockpuppet = new SockpuppetPlus();
sockpuppet.addHandler((req: Request) => {
if (new URL(req.url).pathname.startsWith("/api")) return;
return serveDir(req, {
fsRoot: installPath + "dist",
});
});
sockpuppet.addHandler(async (req: Request) => {
if (!new URL(req.url).pathname.startsWith("/api")) return;
const store = new BearMetalStore();
console.log("API", req.url);
const API_DIR_ROUTE = new URLPattern({
pathname: "/api/dir",
search: "?list",
});
const match = API_DIR_ROUTE.exec(req.url);
if (!match) return;
switch (req.method) {
case "GET": {
const mcPath = store.get("mcPath") as string;
if (mcPath) {
for await (const file of Deno.readDir(mcPath)) {
if (file.isDirectory && file.name.startsWith("saves")) {
const worlds: string[] = [];
for await (const world of Deno.readDir(mcPath + "/" + file.name)) {
if (world.isDirectory) {
worlds.push(world.name);
}
}
return new Response(JSON.stringify({ worlds, mcPath }), {
status: 200,
});
}
}
}
return new Response(JSON.stringify({ mcPath }), {
status: mcPath ? 200 : 500,
});
}
case "POST": {
const formData = await req.formData();
const dir = formData.get("dir") as string;
if (!dir) return new Response(null, { status: 400 });
Deno.env.set("MC_PATH", dir);
const mcPath = Deno.env.get("MC_PATH");
if (!mcPath) return new Response(null, { status: 500 });
return new Response(null, { status: 200 });
}
default:
return new Response(null, { status: 405 });
}
});

135
server/main.ts Normal file
View File

@ -0,0 +1,135 @@
import { SockpuppetPlus } from "@cgg/sockpuppet";
import { serveDir, serveFile } from "@std/http/file-server";
import { BearMetalStore } from "@bearmetal/store";
import { ensureDir } from "@std/fs";
const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./";
const sockpuppet = new SockpuppetPlus();
sockpuppet.addHandler(async (req: Request) => {
console.log(req.url);
const url = new URL(req.url);
if (!url.pathname.startsWith("/images")) return;
return serveFile(req, url.searchParams.get("location") as string);
});
sockpuppet.addHandler((req: Request) => {
if (new URL(req.url).pathname.startsWith("/api")) return;
return serveDir(req, {
fsRoot: installPath + "dist",
});
});
sockpuppet.addHandler(async (req: Request) => {
if (!new URL(req.url).pathname.startsWith("/api")) return;
const store = new BearMetalStore();
const API_DIR_ROUTE = new URLPattern({
pathname: "/api/dir",
});
const match = API_DIR_ROUTE.exec(req.url);
if (!match) return;
switch (req.method) {
case "GET": {
const mcPath = store.get("mcPath") as string;
if (mcPath) {
const worlds: {
world: string;
icon: string;
path: string;
}[] = [];
try {
for await (const file of Deno.readDir(mcPath)) {
if (file.isDirectory && file.name.startsWith("saves")) {
for await (
const world of Deno.readDir(mcPath + "/" + file.name)
) {
if (world.isDirectory) {
for await (
const f of Deno.readDir(
mcPath + "/" + file.name + "/" + world.name,
)
) {
if (f.name.endsWith(".dat")) {
worlds.push({
world: world.name,
icon: Deno.realPathSync(
mcPath + "/" + file.name + "/" + world.name +
"/icon.png",
),
path: Deno.realPathSync(
mcPath + "/" + file.name + "/" + world.name,
),
});
}
}
}
}
}
}
} catch (e: any) {
store.set("mcPath", "");
return new Response(e, { status: 500 });
}
return new Response(JSON.stringify({ worlds, mcPath }), {
status: 200,
});
}
return new Response(JSON.stringify({ mcPath }), {
status: mcPath ? 200 : 500,
});
}
case "POST": {
const formData = await req.formData();
const dir = formData.get("mcPath") as string;
if (!dir) return new Response(null, { status: 400 });
store.set("mcPath", dir);
if (!store.get("mcPath")) return new Response(null, { status: 500 });
return new Response(null, { status: 200 });
}
default:
return new Response(null, { status: 405 });
}
});
sockpuppet.addHandler(async (req: Request) => {
if (!new URL(req.url).pathname.startsWith("/api")) return;
const store = new BearMetalStore();
const API_WORLD_ROUTE = new URLPattern({
pathname: "/api/world",
});
const match = API_WORLD_ROUTE.exec(req.url);
if (!match) return;
switch (req.method) {
case "GET": {
return new Response(store.get<string>("world").split("/").pop() || "", {
status: 200,
});
}
case "POST": {
const worldPath = await req.text();
if (!worldPath) return new Response(null, { status: 400 });
const mcPath = store.get("mcPath") as string;
if (!mcPath) {
return new Response("Tried to set world, but MC path is not set.", {
status: 500,
});
}
const realWorldPath = Deno.realPathSync(worldPath);
store.set("world", realWorldPath);
store.set("packlocation", realWorldPath + "/datapacks/bmp_dev");
await ensureDir(store.get("packlocation") as string);
return new Response(null, { status: 200 });
}
}
});

View File

@ -1,13 +1,14 @@
import { BrowserRouter,Routes,Route } from "react-router-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Home } from "./views/home.tsx";
import { Editor } from "./views/editor.tsx";
export function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" Component={Home} />
<Route path="/editor" Component={Editor} />
</Routes>
</BrowserRouter>
)
);
}

View File

@ -6,13 +6,27 @@
:root {
@apply dark:bg-mixed-600 bg-primary-100 text-dark-600 dark:text-white;
}
* {
box-sizing: border-box;
}
body, #app, html {
body,
#app,
html {
@apply h-full;
}
button {
@apply bg-primary-600 text-white rounded-md px-4 py-2 font-bold;
}
input,
select {
@apply bg-white text-dark-600 rounded-md px-4 py-2 font-bold;
&:not(:last-child) {
@apply mr-2;
}
}
}

View File

@ -1,5 +1,4 @@
import { render } from 'preact'
import { App } from './app.tsx'
import './index.css'
import { render } from "preact";
import { App } from "./app.tsx";
render(<App />, document.getElementById('app') as HTMLElement)
render(<App />, document.getElementById("app") as HTMLElement);

3
src/views/editor.tsx Normal file
View File

@ -0,0 +1,3 @@
export const Editor = () => {
return <div>Editor</div>;
};

View File

@ -1,25 +1,99 @@
import { useEffect, useState } from "preact/hooks";
import { useNavigate } from "react-router-dom";
export function Home() {
const [loading, setLoading] = useState(true);
const [mcPath, setMcPath] = useState("");
const [worlds, setWorlds] = useState<{
world: string;
icon: string;
path: string;
}[]>([]);
const fetchWorlds = async () => {
const res = await fetch("/api/dir");
const json = await res.json();
setMcPath(json.mcPath);
setWorlds(json.worlds);
setLoading(false);
};
useEffect(() => {
document.title = "BearMetal Packer";
fetch("/api/dir").then(res => res.json()).then(data => {
setMcPath(data);
setLoading(false);
});
fetchWorlds();
}, []);
const submitMcPath = async (event: SubmitEvent) => {
setLoading(true);
event.preventDefault();
const form = new FormData(event.target as HTMLFormElement);
const res = await fetch("/api/dir", {
method: "POST",
body: form,
});
if (res.status === 200) {
fetchWorlds();
} else setLoading(false);
};
const nav = useNavigate();
const setWorld = async (worldPath: string) => {
setLoading(true);
const res = await fetch("/api/world", {
method: "POST",
body: worldPath,
});
if (res.status === 200) {
nav("/editor");
} else setLoading(false);
};
return (
<div class="grid h-full">
<div class="place-self-center text-center">
<div class="place-self-center text-center max-h-96 bg-primary-400 rounded-lg p-4 overflow-scroll">
<h1 class="text-3xl">Welcome BearMetal Packer</h1>
<p>An all in one toolkit to build datapacks for Minecraft.</p>
<p>Hold tight, we're doing some heavy lifting.</p>
{loading ? <p>Hold tight, we're doing some heavy lifting.</p> : (
<>
{mcPath
? (
<>
<p>Minecraft directory set to {mcPath}</p>
<p>Worlds:</p>
<ul class="w-full even:bg-black/5">
{worlds.map((world) => (
<li
class="flex gap-4 items-center cursor-pointer"
onClick={() => setWorld(world.path)}
>
<img
src={"/images?location=" + world.icon}
class="w-16 h-16"
/>
{world.world}
</li>
))}
</ul>
</>
)
: (
<>
<p>No Minecraft directory set, please set now:</p>
<form method="POST" onSubmit={submitMcPath}>
<input
type="text"
name="mcPath"
placeholder="Minecraft directory"
/>
<button type="submit">Set</button>
</form>
</>
)}
</>
)}
</div>
</div>
)
}
);
}

View File

@ -16,12 +16,15 @@ export default defineConfig({
"/api": {
target: "http://localhost:8000",
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ""),
},
"/puppet": {
target: "http://localhost:8000",
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/puppet/, ""),
ws: true,
},
"/images": {
target: "http://localhost:8000",
changeOrigin: true,
ws: true,
},
},