Skip to content

Commit

Permalink
feat: add support for mobile dragging and multiple resource packs
Browse files Browse the repository at this point in the history
  • Loading branch information
me4502 committed Jan 9, 2021
1 parent 320d2f0 commit f8ef99a
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 19 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: enginehub
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,43 @@
# SchematicWebViewer
An NPM package to facilitate importing and viewing of modern Minecraft schematics.

Originally by [cpdt](https://github.com/cpdt) and was available [here](https://github.com/me4502/WorldEditGolf/tree/master/3d_test).
Originally by [cpdt](https://github.com/cpdt) and was available [here](https://github.com/me4502/WorldEditGolf/tree/master/3d_test).

## Usage

This library requires a **complete** Minecraft resource pack in order to function. This means a resource pack that include **all** models, blockstates, and textures. As most resource packs only include what they have changed, they do not fit this criteria. Luckily, the Minecraft client jar file is formatted in the same way as a resource pack.

To use this on your site, create a canvas element in your HTML that is able to be queried in the JavaScript.

```html
<canvas id="schematicRenderer", width=500, height=500></canvas>
```

```javascript
renderSchematic(document.querySelector('#schematicRenderer'), SCHEMATIC_FILE, {
size: 500,
renderArrow: false,
renderBars: false,
jarUrl:
['url to resource pack']
});
```

The `renderSchematic` function takes a few options.

The first argument is the canvas element to render to.

The second argument is a schematic file encoded in Base64. The schematic format must be supported by [SchematicJS](https://github.com/EngineHub/SchematicJS).

The final argument is an options object that allows configuring various settings about how the schematic is rendered. The following properties are on the object,

```typescript
interface SchematicRenderOptions {
size: string; // The size of the canvas viewport
jarUrl?: string | string[]; // A resource pack URL, or a list of resource pack URLs in priority order
renderBars?: boolean; // Whether a grid should be rendered
renderArrow?: boolean; // Whether an arrow to show direction should be rendered
orbit?: boolean; // Whether the view should automatically rotate when not being dragged by the user
antialias?: boolean; // Whether antialiasing should be enabled
}
```
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@enginehub/schematicwebviewer",
"version": "2.0.3",
"version": "2.1.0",
"description": "A web viewer for modern Minecraft schematics",
"main": "dist/index.js",
"files": [
Expand All @@ -11,7 +11,7 @@
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
"postinstall": "patch-package",
"start": "parcel test/test.html --port 3000"
"start": "parcel test/test.html --port 3000 --host 0.0.0.0"
},
"repository": {
"type": "git",
Expand Down
33 changes: 33 additions & 0 deletions src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,34 @@ export async function renderSchematic(
e.preventDefault();
};

const touchdownCallback = (e: TouchEvent) => {
isDragging = true;
dragButton = -1;
const touch = e.touches.item(0);

dragStartX = touch.clientX;
dragStartY = touch.clientY;
e.preventDefault();
};
const touchmoveCallback = (e: TouchEvent) => {
if (!isDragging) {
return;
}

const touch = e.touches.item(0);
const deltaX = touch.clientX - dragStartX;
const deltaY = touch.clientY - dragStartY;
dragStartX = touch.clientX;
dragStartY = touch.clientY;

scene.rotation.y += deltaX / 100;
scene.rotation.x += deltaY / 100;

if (!orbit) {
render();
}
};

const mousemoveCallback = (e: MouseEvent) => {
if (!isDragging) {
return;
Expand Down Expand Up @@ -274,10 +302,15 @@ export async function renderSchematic(
e.preventDefault();
return false;
});
canvas.addEventListener('touchstart', touchdownCallback);

document.body.addEventListener('mousemove', mousemoveCallback);
document.body.addEventListener('mouseup', mouseupCallback);

document.body.addEventListener('touchmove', touchmoveCallback);
document.body.addEventListener('touchcancel', mouseupCallback);
document.body.addEventListener('touchend', mouseupCallback);

let lastTime = performance.now();
function render() {
if (hasDestroyed) {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface SchematicHandles {

export interface SchematicRenderOptions {
size: number;
jarUrl?: string;
jarUrl?: string | string[];
renderBars?: boolean;
renderArrow?: boolean;
orbit?: boolean;
Expand Down
61 changes: 48 additions & 13 deletions src/resource/resourceLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,29 @@ export interface ResourceLoader {
getResourceString: (name: string) => Promise<string> | undefined;
}

let zipPromise: Promise<JSZip> = undefined;
let zip: JSZip = undefined;
let zipPromise: Promise<JSZip | JSZip[]> = undefined;
let zip: JSZip | JSZip[] = undefined;

async function loadZip(jarUrl: string) {
const zipFile = await (await fetch(jarUrl)).blob();
const zip = await JSZip.loadAsync(zipFile);
async function loadZip(jarUrl: string | string[]) {
if (Array.isArray(jarUrl)) {
return await Promise.all(
jarUrl.map(async url => {
const zipFile = await (await fetch(url)).blob();
const zip = await JSZip.loadAsync(zipFile);

return zip;
return zip;
})
);
} else {
const zipFile = await (await fetch(jarUrl)).blob();
const zip = await JSZip.loadAsync(zipFile);

return zip;
}
}

export async function getResourceLoader(
jarUrl: string
jarUrl: string | string[]
): Promise<ResourceLoader> {
if (!zip) {
if (!zipPromise) {
Expand All @@ -32,9 +43,21 @@ export async function getResourceLoader(
if (blobCache.has(name)) {
return blobCache.get(name);
} else {
const data = await zip
.file(`assets/minecraft/${name}`)
?.async('blob');
let data: Blob;
if (Array.isArray(zip)) {
for (const zipFile of zip) {
data = await zipFile
.file(`assets/minecraft/${name}`)
?.async('blob');
if (data) {
break;
}
}
} else {
data = await zip
.file(`assets/minecraft/${name}`)
?.async('blob');
}
if (!data) {
blobCache.set(name, undefined);
return undefined;
Expand All @@ -49,9 +72,21 @@ export async function getResourceLoader(
if (stringCache.has(name)) {
return stringCache.get(name);
} else {
const data = await zip
.file(`assets/minecraft/${name}`)
?.async('string');
let data: string;
if (Array.isArray(zip)) {
for (const zipFile of zip) {
data = await zipFile
.file(`assets/minecraft/${name}`)
?.async('string');
if (data) {
break;
}
}
} else {
data = await zip
.file(`assets/minecraft/${name}`)
?.async('string');
}
stringCache.set(name, data);
return data;
}
Expand Down
4 changes: 2 additions & 2 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ window.addEventListener('load', () => {
renderArrow: false,
renderBars: false,
jarUrl:
'https://corsanywhere.minidigger.me/https://launcher.mojang.com/v1/objects/1952d94a0784e7abda230aae6a1e8fc0522dba99/client.jar'
['https://corsanywhere.minidigger.me/https://launcher.mojang.com/v1/objects/1952d94a0784e7abda230aae6a1e8fc0522dba99/client.jar']
});

renderSchematic(
document.querySelector('#second'),
SIMPLE_SCHEM,
{
size: 250,
jarUrl: 'https://corsanywhere.minidigger.me/https://launcher.mojang.com/v1/objects/1952d94a0784e7abda230aae6a1e8fc0522dba99/client.jar',
jarUrl: ['https://corsanywhere.minidigger.me/https://launcher.mojang.com/v1/objects/1952d94a0784e7abda230aae6a1e8fc0522dba99/client.jar'],
renderArrow: false,
renderBars: false
}
Expand Down

0 comments on commit f8ef99a

Please sign in to comment.