fixing some chunking issues
This commit is contained in:
parent
a8a903d581
commit
1f306485a8
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,4 +27,5 @@ dist-ssr
|
||||
|
||||
BearMetal/
|
||||
resources/
|
||||
!**/*/resources/
|
||||
!**/*/resources/
|
||||
test.ts
|
63
pack_versions/57.json
Normal file
63
pack_versions/57.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"version": "48",
|
||||
"mcVersion": "^1.21.3",
|
||||
"schema": {
|
||||
"pack.mcmeta": "json",
|
||||
"pack.png": "image/png",
|
||||
"data": {
|
||||
"<namespace>": {
|
||||
"function": "function",
|
||||
"structure": {
|
||||
"DataVersion": "int",
|
||||
"size": ["int", "int", "int"],
|
||||
"palette": [{
|
||||
"name": "blockId",
|
||||
"properties": ["string"]
|
||||
}],
|
||||
"palettes": [
|
||||
[{
|
||||
"name": "blockId",
|
||||
"properties": ["string"]
|
||||
}]
|
||||
],
|
||||
"blocks": [{
|
||||
"state": "int",
|
||||
"pos": ["int", "int", "int"],
|
||||
"nbt": "nbt"
|
||||
}],
|
||||
"entities": [{
|
||||
"pos": ["double", "double", "double"],
|
||||
"blockPos": ["int", "int", "int"],
|
||||
"nbt": "nbt"
|
||||
}]
|
||||
},
|
||||
"tags": "tags",
|
||||
"advancment": {
|
||||
"parent": "advancment",
|
||||
"display": {
|
||||
"icon": {
|
||||
"id": "itemId",
|
||||
"count": "int",
|
||||
"components": ["itemComponent"]
|
||||
},
|
||||
"title": "jsonString",
|
||||
"description": "jsonString",
|
||||
"frame": "frame",
|
||||
"background": "resource",
|
||||
"show_toast": "bool",
|
||||
"announce_to_chat": "bool",
|
||||
"hidden": "bool"
|
||||
},
|
||||
"criteria": "criteria",
|
||||
"requirements": ["criterion_name"],
|
||||
"rewards": {
|
||||
"experience": "int",
|
||||
"function": "function",
|
||||
"loot": ["loot_table"],
|
||||
"recipes": ["recipe"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ import { Router } from "./router.ts";
|
||||
import { getPackVersion } from "./util/packVersion.ts";
|
||||
import { createTagRoutes } from "./tags/routes.ts";
|
||||
import { createResourcesRoutes } from "./resources/routes.ts";
|
||||
import { readDirDirs } from "./util/readDir.ts";
|
||||
import { unzipResources } from "./resources/unzip.ts";
|
||||
|
||||
const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./";
|
||||
|
||||
@ -31,6 +33,7 @@ sockpuppet.addHandler((req: Request) => {
|
||||
// });
|
||||
|
||||
const router = new Router();
|
||||
|
||||
router.route("/api/dir")
|
||||
.get(async () => {
|
||||
using store = new BearMetalStore();
|
||||
@ -208,6 +211,15 @@ router.route("/api/pack/version")
|
||||
store.get("packlocation") + "/pack.mcmeta",
|
||||
JSON.stringify(packMetaJson),
|
||||
);
|
||||
const packVersionSchema = Deno.readTextFileSync(
|
||||
installPath + "pack_versions/" + version + ".json",
|
||||
);
|
||||
const packVersionSchemaJson = JSON.parse(packVersionSchema);
|
||||
packVersionSchemaJson.mcVersion = store.get("mcVersion");
|
||||
const versionResourceDir = await readDirDirs(installPath + "resources/");
|
||||
if (!versionResourceDir.includes(version)) {
|
||||
unzipResources();
|
||||
}
|
||||
} catch (e: any) {
|
||||
return new Response(e, { status: 500 });
|
||||
}
|
||||
@ -226,6 +238,25 @@ router.route("/api/versions")
|
||||
createTagRoutes(router);
|
||||
createResourcesRoutes(router);
|
||||
|
||||
router.route("/api/stream/test")
|
||||
.get(() => {
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const enc = new TextEncoder();
|
||||
controller.enqueue(enc.encode("Hello"));
|
||||
controller.enqueue(enc.encode(", "));
|
||||
controller.enqueue(enc.encode("World!"));
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
return new Response(stream, {
|
||||
headers: {
|
||||
"content-type": "text/plain",
|
||||
"x-content-type-options": "nosniff",
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
sockpuppet.addHandler((req: Request) => {
|
||||
if (new URL(req.url).pathname.startsWith("/api")) return;
|
||||
|
||||
|
@ -2,13 +2,7 @@ import { encodeBase64 } from "@std/encoding/base64";
|
||||
import { readDirFiles } from "../util/readDir.ts";
|
||||
import { createIsometricCube } from "./renderer.ts";
|
||||
|
||||
interface BlockItem {
|
||||
name: string;
|
||||
resourceLocation: string;
|
||||
images: string[];
|
||||
}
|
||||
|
||||
export const readBlocks = async (path: string) => {
|
||||
export const readBlocks = async (path: string, read?: (b: BlockItem, i: number) => void) => {
|
||||
const blocks: BlockItem[] =
|
||||
(await readDirFiles(path + "/assets/minecraft/blockstates"))
|
||||
.map((b) => ({
|
||||
@ -300,10 +294,16 @@ export const readBlocks = async (path: string) => {
|
||||
block.images.push(await createIsometricCube(b64, b64, b64));
|
||||
}
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
for (const block of blocks) {
|
||||
read?.(block, i);
|
||||
i++;
|
||||
}
|
||||
return blocks;
|
||||
};
|
||||
|
||||
export const readItems = async (path: string) => {
|
||||
export const readItems = async (path: string, read?: (b: BlockItem) => void) => {
|
||||
const items: BlockItem[] =
|
||||
(await readDirFiles(path + "/assets/minecraft/models/item")).map((i) => ({
|
||||
name: i.replace(".json", ""),
|
||||
@ -348,6 +348,7 @@ export const readItems = async (path: string) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
read?.(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { ensureDir } from "@std/fs/ensure-dir";
|
||||
import type { Router } from "../router.ts";
|
||||
import { readDirDirs } from "../util/readDir.ts";
|
||||
import { versionCompat } from "../util/versionCompat.ts";
|
||||
import { readBlocks } from "./readers.ts";
|
||||
import { readBlocks, readItems } from "./readers.ts";
|
||||
|
||||
export const createResourcesRoutes = (router: Router) => {
|
||||
router.route("/api/resources/:path*")
|
||||
@ -10,38 +11,92 @@ export const createResourcesRoutes = (router: Router) => {
|
||||
if (!path) {
|
||||
return new Response("no path provided", { status: 400 });
|
||||
}
|
||||
|
||||
const format = ctx.url.searchParams.get("format");
|
||||
if (!format) {
|
||||
return new Response("no format provided", { status: 400 });
|
||||
}
|
||||
|
||||
const packVersion = await Deno.readTextFile(
|
||||
"./pack_versions/" + format + ".json",
|
||||
);
|
||||
const packVersionJson = JSON.parse(packVersion);
|
||||
const mcVersion = packVersionJson.mcVersion;
|
||||
|
||||
await ensureDir("./resources");
|
||||
const resourceVersions = await readDirDirs("./resources");
|
||||
console.log("resourceVersions", resourceVersions);
|
||||
|
||||
for (const resourceVersion of resourceVersions) {
|
||||
if (versionCompat(resourceVersion, mcVersion)) {
|
||||
const resourcePath = "./resources/" + resourceVersion;
|
||||
const splitPath = path.split("/");
|
||||
switch (splitPath[0]) {
|
||||
case "block":
|
||||
case "blocks": {
|
||||
return new Response(
|
||||
JSON.stringify(await readBlocks(resourcePath)),
|
||||
let items: BlockItem[] = [];
|
||||
|
||||
const batch = (
|
||||
controller: ReadableStreamDefaultController,
|
||||
res: BlockItem,
|
||||
) => {
|
||||
items.push(res);
|
||||
if (items.length > 4) {
|
||||
controller.enqueue(
|
||||
new TextEncoder().encode(JSON.stringify(items) + "\n"),
|
||||
);
|
||||
items = [];
|
||||
}
|
||||
case "item":
|
||||
case "items": {
|
||||
return new Response(
|
||||
JSON.stringify(await readBlocks(resourcePath)),
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return new Response("invalid path", { status: 400 });
|
||||
}
|
||||
}
|
||||
};
|
||||
const body = new ReadableStream({
|
||||
async start(controller) {
|
||||
switch (path) {
|
||||
case "block":
|
||||
case "blocks": {
|
||||
await readBlocks(resourcePath, (res, i) => {
|
||||
console.log(i);
|
||||
batch(controller, res);
|
||||
});
|
||||
controller.close();
|
||||
break;
|
||||
}
|
||||
case "item":
|
||||
case "items": {
|
||||
await readItems(resourcePath, (res) => {
|
||||
batch(controller, res);
|
||||
});
|
||||
controller.close();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
controller.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return new Response(body, {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"access-control-allow-origin": "*",
|
||||
},
|
||||
});
|
||||
|
||||
// const resourcePath = "./resources/" + resourceVersion;
|
||||
// const splitPath = path.split("/");
|
||||
// switch (splitPath[0]) {
|
||||
// case "block":
|
||||
// case "blocks": {
|
||||
// return new Response(
|
||||
// JSON.stringify(await readBlocks(resourcePath)),
|
||||
// );
|
||||
// }
|
||||
// case "item":
|
||||
// case "items": {
|
||||
// return new Response(
|
||||
// JSON.stringify(await readBlocks(resourcePath)),
|
||||
// );
|
||||
// }
|
||||
// default: {
|
||||
// return new Response("invalid path", { status: 400 });
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -6,6 +6,7 @@ import { namespaceAtom, useNamespace } from "../../../atoms/namespace.ts";
|
||||
import { Loader } from "../../../components/loader.tsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { NewTagModal } from "./newTagModal.tsx";
|
||||
import { ResourceList } from "../../resourceList.tsx";
|
||||
|
||||
export const TagRouter = () => {
|
||||
return (
|
||||
@ -33,7 +34,7 @@ function TagList() {
|
||||
<div>
|
||||
<ul>
|
||||
</ul>
|
||||
<Resources />
|
||||
<ResourceList />
|
||||
{false && (
|
||||
<ul class="flex flex-col gap-2">
|
||||
<li>
|
||||
@ -133,24 +134,3 @@ function TagEditor() {
|
||||
);
|
||||
}
|
||||
|
||||
function Resources() {
|
||||
const { data, isLoading } = useSWR<{ name: string; images: string[] }[]>(
|
||||
`/api/resources/blocks?format=48`,
|
||||
fetchJson,
|
||||
);
|
||||
if (isLoading || !data) {
|
||||
return <Loader msg="Your hard drive is full of... interesting things." />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{data.map((resource) => (
|
||||
<li>
|
||||
{resource.name}
|
||||
<img class="min-w-12 max-h-16" src={resource.images[0]} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
33
src/components/resourceList.tsx
Normal file
33
src/components/resourceList.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import { useRemoteStream } from "../hooks/useStream.ts";
|
||||
|
||||
export const ResourceList = () => {
|
||||
// const [resources, setResources] = useState<BlockItem[]>([]);
|
||||
// // useRemoteStream("/api/stream/test", (e) => {
|
||||
// useRemoteStream("http://localhost:8000/api/resources/blocks?format=57", (e: string) => {
|
||||
// try {
|
||||
// JSON.parse(e);
|
||||
// } catch (err) {
|
||||
// return console.log(e);
|
||||
// }
|
||||
// setResources((resources) => [...resources, ...JSON.parse(e) as BlockItem[]]);
|
||||
// }, (e) => console.log(e));
|
||||
|
||||
const [resources, isLoading, error] = useRemoteStream<BlockItem>('http://localhost:8000/api/resources/blocks?format=57');
|
||||
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
if (error) return <div>Error: {error}</div>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{resources?.map((resource) => (
|
||||
<li>
|
||||
{resource.name}
|
||||
<img class="min-w-6 max-w-8" src={resource.images[0]} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,42 +1,49 @@
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
export const useStream = <T>(
|
||||
stream: ReadableStream<T>,
|
||||
onData: (data: T) => void,
|
||||
onError: (err: Error) => void,
|
||||
) => {
|
||||
const reader = stream.getReader();
|
||||
const read = async () => {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
reader.releaseLock();
|
||||
return;
|
||||
}
|
||||
onData(value);
|
||||
read();
|
||||
};
|
||||
read();
|
||||
};
|
||||
export const useRemoteStream = <T = string>(url: string, transformer?: (e: string) => T) : [T[], boolean, string | null] => {
|
||||
const [items, setItems] = useState<T[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
export const useRemoteStream = <T>(
|
||||
url: string,
|
||||
onData: (data: T) => void,
|
||||
onError: (err: Error) => void,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const res = await fetch(url);
|
||||
res.body?.pipeThrough(new TextDecoderStream())
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
write(chunk) {
|
||||
controller.enqueue(chunk);
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
useStream(stream, onData, onError);
|
||||
}, [url]);
|
||||
};
|
||||
const abortController = new AbortController();
|
||||
|
||||
async function fetchStream() {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
signal: abortController.signal
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
if (!response.body) throw new Error('ReadableStream not supported');
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const chunk = decoder.decode(value);
|
||||
const batchItems = chunk.trim().split('\n')
|
||||
.filter(line => line.length > 0)
|
||||
.map(line => transformer?.(line) ?? JSON.parse(line))
|
||||
.flat();
|
||||
|
||||
setItems(prev => [...prev, ...batchItems]);
|
||||
}
|
||||
} catch (err:any) {
|
||||
if (err?.name === 'AbortError') return;
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchStream();
|
||||
return () => abortController.abort();
|
||||
}, [])
|
||||
|
||||
return [items, isLoading, error];
|
||||
}
|
||||
|
||||
|
7
types.ts
7
types.ts
@ -3,5 +3,12 @@ declare global {
|
||||
url: URL;
|
||||
state: Record<string, unknown>;
|
||||
params: Record<string, string | undefined>;
|
||||
headers?: Headers,
|
||||
}
|
||||
|
||||
interface BlockItem {
|
||||
name: string;
|
||||
resourceLocation: string;
|
||||
images: string[];
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ export default defineConfig({
|
||||
"/api": {
|
||||
target: "http://localhost:8000",
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
"/puppet": {
|
||||
target: "http://localhost:8000",
|
||||
@ -29,4 +30,11 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: [
|
||||
"server",
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user