mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2024-12-15 02:59:55 +08:00
Merge pull request #61 from LucasDower/schem-exporter
Added .schem exporter, closes #60
This commit is contained in:
commit
3377872cd4
65
package-lock.json
generated
65
package-lock.json
generated
@ -15,7 +15,8 @@
|
|||||||
"jpeg-js": "^0.4.4",
|
"jpeg-js": "^0.4.4",
|
||||||
"pngjs": "^6.0.0",
|
"pngjs": "^6.0.0",
|
||||||
"prismarine-nbt": "^1.6.0",
|
"prismarine-nbt": "^1.6.0",
|
||||||
"twgl.js": "^4.19.1"
|
"twgl.js": "^4.19.1",
|
||||||
|
"varint-array": "^0.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
@ -23,6 +24,7 @@
|
|||||||
"@types/obj-file-parser": "^0.5.0",
|
"@types/obj-file-parser": "^0.5.0",
|
||||||
"@types/pngjs": "^6.0.1",
|
"@types/pngjs": "^6.0.1",
|
||||||
"@types/prompt": "^1.1.2",
|
"@types/prompt": "^1.1.2",
|
||||||
|
"@types/varint": "^6.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||||
"@typescript-eslint/parser": "^5.9.1",
|
"@typescript-eslint/parser": "^5.9.1",
|
||||||
"adm-zip": "^0.5.9",
|
"adm-zip": "^0.5.9",
|
||||||
@ -1435,6 +1437,15 @@
|
|||||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
|
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/varint": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/varint/-/varint-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-2jBazyxGl4644tvu3VAez8UA/AtrcEetT9HOeAbqZ/vAcRVL/ZDFQjSS7rkWusU5cyONQVUz+nwwrNZdMva4ow==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/yargs": {
|
"node_modules/@types/yargs": {
|
||||||
"version": "16.0.4",
|
"version": "16.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
||||||
@ -6638,6 +6649,14 @@
|
|||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/struct": {
|
||||||
|
"version": "0.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/struct/-/struct-0.0.11.tgz",
|
||||||
|
"integrity": "sha512-zhCBDK3POhX5y1IUTr5JXY7l9Esjdi1WkhZBjZEJU8ewpwsa95l+PtLCMrYIu8VxDFCb7vr2CnuQDxDEj2K63g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sumchecker": {
|
"node_modules/sumchecker": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
@ -7105,6 +7124,20 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/varint-array": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/varint-array/-/varint-array-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-mUtmdj8Ic9LO6Vu+AgRtPP8tPBmnliJ7xbRRabwvW+qRVkOYlp/7o3Ga27Wq7xr8KcR6W1GDe+gmm/5hCtqEMQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"struct": "0.0.11",
|
||||||
|
"varint": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/varint-array/node_modules/varint": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow=="
|
||||||
|
},
|
||||||
"node_modules/w3c-hr-time": {
|
"node_modules/w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
@ -8489,6 +8522,15 @@
|
|||||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
|
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/varint": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/varint/-/varint-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-2jBazyxGl4644tvu3VAez8UA/AtrcEetT9HOeAbqZ/vAcRVL/ZDFQjSS7rkWusU5cyONQVUz+nwwrNZdMva4ow==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "16.0.4",
|
"version": "16.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
||||||
@ -12486,6 +12528,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"struct": {
|
||||||
|
"version": "0.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/struct/-/struct-0.0.11.tgz",
|
||||||
|
"integrity": "sha512-zhCBDK3POhX5y1IUTr5JXY7l9Esjdi1WkhZBjZEJU8ewpwsa95l+PtLCMrYIu8VxDFCb7vr2CnuQDxDEj2K63g=="
|
||||||
|
},
|
||||||
"sumchecker": {
|
"sumchecker": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
@ -12818,6 +12865,22 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"varint-array": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/varint-array/-/varint-array-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-mUtmdj8Ic9LO6Vu+AgRtPP8tPBmnliJ7xbRRabwvW+qRVkOYlp/7o3Ga27Wq7xr8KcR6W1GDe+gmm/5hCtqEMQ==",
|
||||||
|
"requires": {
|
||||||
|
"struct": "0.0.11",
|
||||||
|
"varint": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"varint": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"w3c-hr-time": {
|
"w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
"@types/obj-file-parser": "^0.5.0",
|
"@types/obj-file-parser": "^0.5.0",
|
||||||
"@types/pngjs": "^6.0.1",
|
"@types/pngjs": "^6.0.1",
|
||||||
"@types/prompt": "^1.1.2",
|
"@types/prompt": "^1.1.2",
|
||||||
|
"@types/varint": "^6.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||||
"@typescript-eslint/parser": "^5.9.1",
|
"@typescript-eslint/parser": "^5.9.1",
|
||||||
"adm-zip": "^0.5.9",
|
"adm-zip": "^0.5.9",
|
||||||
@ -59,6 +60,7 @@
|
|||||||
"jpeg-js": "^0.4.4",
|
"jpeg-js": "^0.4.4",
|
||||||
"pngjs": "^6.0.0",
|
"pngjs": "^6.0.0",
|
||||||
"prismarine-nbt": "^1.6.0",
|
"prismarine-nbt": "^1.6.0",
|
||||||
"twgl.js": "^4.19.1"
|
"twgl.js": "^4.19.1",
|
||||||
|
"varint-array": "^0.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ import { Schematic } from './schematic_exporter';
|
|||||||
import { Litematic } from './litematic_exporter';
|
import { Litematic } from './litematic_exporter';
|
||||||
import { ASSERT } from '../util';
|
import { ASSERT } from '../util';
|
||||||
import { ObjExporter } from './obj_exporter';
|
import { ObjExporter } from './obj_exporter';
|
||||||
|
import { SchemExporter } from './schem_exporter';
|
||||||
|
|
||||||
export type TExporters = 'schematic' | 'litematic' | 'obj';
|
export type TExporters = 'schematic' | 'litematic' | 'obj' | 'schem';
|
||||||
|
|
||||||
export class ExporterFactory {
|
export class ExporterFactory {
|
||||||
public static GetExporter(voxeliser: TExporters): IExporter {
|
public static GetExporter(voxeliser: TExporters): IExporter {
|
||||||
@ -15,6 +16,8 @@ export class ExporterFactory {
|
|||||||
return new Litematic();
|
return new Litematic();
|
||||||
case 'obj':
|
case 'obj':
|
||||||
return new ObjExporter();
|
return new ObjExporter();
|
||||||
|
case 'schem':
|
||||||
|
return new SchemExporter();
|
||||||
default:
|
default:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { BlockMesh } from '../block_mesh';
|
import { BlockMesh } from '../block_mesh';
|
||||||
import { Vector3 } from '../vector';
|
import { Vector3 } from '../vector';
|
||||||
import { IExporter } from './base_exporter';
|
import { IExporter } from './base_exporter';
|
||||||
|
import { saveNBT } from '../util/nbt_util';
|
||||||
|
|
||||||
import fs from 'fs';
|
import { NBT, TagType } from 'prismarine-nbt';
|
||||||
import { NBT, TagType, writeUncompressed } from 'prismarine-nbt';
|
|
||||||
import * as zlib from 'zlib';
|
|
||||||
|
|
||||||
type BlockID = number;
|
type BlockID = number;
|
||||||
type long = [number, number];
|
type long = [number, number];
|
||||||
@ -187,17 +186,7 @@ export class Litematic extends IExporter {
|
|||||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
||||||
|
|
||||||
const nbt = this._convertToNBT(blockMesh);
|
const nbt = this._convertToNBT(blockMesh);
|
||||||
|
saveNBT(nbt, filePath);
|
||||||
const outBuffer = fs.createWriteStream(filePath);
|
|
||||||
const newBuffer = writeUncompressed(nbt, 'big');
|
|
||||||
|
|
||||||
zlib.gzip(newBuffer, (err, buffer) => {
|
|
||||||
if (!err) {
|
|
||||||
outBuffer.write(buffer);
|
|
||||||
outBuffer.end();
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
82
src/exporters/schem_exporter.ts
Normal file
82
src/exporters/schem_exporter.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { NBT, TagType } from 'prismarine-nbt';
|
||||||
|
import { LOG } from '../util';
|
||||||
|
import { Vector3 } from '../vector';
|
||||||
|
import { BlockMesh } from '../block_mesh';
|
||||||
|
import { IExporter } from './base_exporter';
|
||||||
|
import { saveNBT } from '../util/nbt_util';
|
||||||
|
|
||||||
|
const varintarray = require('varint-array');
|
||||||
|
|
||||||
|
export class SchemExporter extends IExporter {
|
||||||
|
public override getFormatFilter() {
|
||||||
|
return {
|
||||||
|
name: this.getFormatName(),
|
||||||
|
extensions: ['schem'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override getFormatName() {
|
||||||
|
return 'Sponge Schematic';
|
||||||
|
}
|
||||||
|
|
||||||
|
public override getFileExtension(): string {
|
||||||
|
return 'schem';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SCHEMA_VERSION = 2;
|
||||||
|
private static DATA_VERSION = 3105; // 3105 => 1.19, TODO: Remove hardcoded value
|
||||||
|
|
||||||
|
public override export(blockMesh: BlockMesh, filePath: string): boolean {
|
||||||
|
const bounds = blockMesh.getVoxelMesh().getBounds();
|
||||||
|
const sizeVector = bounds.getDimensions().add(1);
|
||||||
|
|
||||||
|
// https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-3.md#paletteObject
|
||||||
|
// const blockMapping: BlockMapping = {};
|
||||||
|
const test: {[name: string]: { type: TagType, value: any }} = {
|
||||||
|
'minecraft:air': { type: TagType.Int, value: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
let blockIndex = 1;
|
||||||
|
for (const blockName of blockMesh.getBlockPalette()) {
|
||||||
|
const namespacedBlockName = 'minecraft:' + blockName; // FIXME: All block names should be namespaced on import
|
||||||
|
// ASSERT(!(namespacedBlockName in blockMapping));
|
||||||
|
// blockMapping[namespacedBlockName] = blockIndex;
|
||||||
|
test[namespacedBlockName] = { type: TagType.Int, value: blockIndex };
|
||||||
|
++blockIndex;
|
||||||
|
}
|
||||||
|
LOG(test);
|
||||||
|
|
||||||
|
// const paletteObject = SchemExporter._createBlockStatePalette(blockMapping);
|
||||||
|
const blockData = new Array<number>(sizeVector.x * sizeVector.y * sizeVector.z).fill(0);
|
||||||
|
for (const block of blockMesh.getBlocks()) {
|
||||||
|
const indexVector = Vector3.sub(block.voxel.position, bounds.min);
|
||||||
|
const bufferIndex = SchemExporter._getBufferIndex(sizeVector, indexVector);
|
||||||
|
const namespacedBlockName = 'minecraft:' + block.blockInfo.name;
|
||||||
|
blockData[bufferIndex] = test[namespacedBlockName].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nbt: NBT = {
|
||||||
|
type: TagType.Compound,
|
||||||
|
name: 'Schematic',
|
||||||
|
value: {
|
||||||
|
Version: { type: TagType.Int, value: SchemExporter.SCHEMA_VERSION },
|
||||||
|
DataVersion: { type: TagType.Int, value: SchemExporter.DATA_VERSION },
|
||||||
|
Width: { type: TagType.Short, value: sizeVector.x },
|
||||||
|
Height: { type: TagType.Short, value: sizeVector.y },
|
||||||
|
Length: { type: TagType.Short, value: sizeVector.z },
|
||||||
|
PaletteMax: { type: TagType.Int, value: blockIndex },
|
||||||
|
Palette: { type: TagType.Compound, value: test },
|
||||||
|
BlockData: { type: TagType.ByteArray, value: varintarray.encode(blockData) },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
LOG(nbt);
|
||||||
|
saveNBT(nbt, filePath);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _getBufferIndex(dimensions: Vector3, vec: Vector3) {
|
||||||
|
return vec.x + (vec.z * dimensions.x) + (vec.y * dimensions.x * dimensions.z);
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,8 @@ import { StatusHandler } from '../status';
|
|||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { NBT, TagType, writeUncompressed } from 'prismarine-nbt';
|
import { NBT, TagType } from 'prismarine-nbt';
|
||||||
import * as zlib from 'zlib';
|
import { saveNBT } from '../util/nbt_util';
|
||||||
|
|
||||||
export class Schematic extends IExporter {
|
export class Schematic extends IExporter {
|
||||||
private _convertToNBT(blockMesh: BlockMesh) {
|
private _convertToNBT(blockMesh: BlockMesh) {
|
||||||
@ -92,17 +92,7 @@ export class Schematic extends IExporter {
|
|||||||
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
this._sizeVector = Vector3.sub(bounds.max, bounds.min).add(1);
|
||||||
|
|
||||||
const nbt = this._convertToNBT(blockMesh);
|
const nbt = this._convertToNBT(blockMesh);
|
||||||
|
saveNBT(nbt, filePath);
|
||||||
const outBuffer = fs.createWriteStream(filePath);
|
|
||||||
const newBuffer = writeUncompressed(nbt, 'big');
|
|
||||||
|
|
||||||
zlib.gzip(newBuffer, (err, buffer) => {
|
|
||||||
if (!err) {
|
|
||||||
outBuffer.write(buffer);
|
|
||||||
outBuffer.end();
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -171,9 +171,10 @@ export class UI {
|
|||||||
label: 'Export',
|
label: 'Export',
|
||||||
elements: {
|
elements: {
|
||||||
'export': new ComboBoxElement<TExporters>('File format', [
|
'export': new ComboBoxElement<TExporters>('File format', [
|
||||||
{ id: 'litematic', displayText: 'Litematic' },
|
{ id: 'litematic', displayText: 'Litematic (.litematic)' },
|
||||||
{ id: 'schematic', displayText: 'Schematic' },
|
{ id: 'schematic', displayText: 'Schematic (.schematic)' },
|
||||||
{ id: 'obj', displayText: 'Wavefront OBJ' },
|
{ id: 'obj', displayText: 'Wavefront OBJ (.obj)' },
|
||||||
|
{ id: 'schem', displayText: 'Sponge Schematic (.schem)' },
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
elementsOrder: ['export'],
|
elementsOrder: ['export'],
|
||||||
|
@ -21,6 +21,12 @@ export class UIMessageBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addItem(...messages: string[]) {
|
||||||
|
for (const message of messages) {
|
||||||
|
this._messages.push('• ' + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public toString(): string {
|
public toString(): string {
|
||||||
return this._messages.join('<br>');
|
return this._messages.join('<br>');
|
||||||
}
|
}
|
||||||
|
21
src/util/nbt_util.ts
Normal file
21
src/util/nbt_util.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { ASSERT } from '../util';
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import { NBT, writeUncompressed } from 'prismarine-nbt';
|
||||||
|
import zlib from 'zlib';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
export function saveNBT(nbt: NBT, filepath: string) {
|
||||||
|
ASSERT(path.isAbsolute(filepath), '[saveNBT]: filepath is not absolute');
|
||||||
|
|
||||||
|
const outBuffer = fs.createWriteStream(filepath);
|
||||||
|
const newBuffer = writeUncompressed(nbt, 'big');
|
||||||
|
|
||||||
|
zlib.gzip(newBuffer, (err, buffer) => {
|
||||||
|
if (!err) {
|
||||||
|
outBuffer.write(buffer);
|
||||||
|
outBuffer.end();
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user