diff --git a/LICENSE b/LICENSE index 3e3bcc1..97960b9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,27 @@ MIT License +Copyright (c) 2024 Legends Modding + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +MIT License + Copyright (c) 2023 Mojang Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md new file mode 100644 index 0000000..a2e38a6 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Minecraft Legends Blockbench Plugin + +Allows users to export both "Bedrock" format models(cubes) and "Generic" format models(meshes) to a JSON file readable by Minecraft Legends. + +Originally by House of How, improved by Miclee. diff --git a/Source/package-lock.json b/Source/package-lock.json index aae4e99..e67aad1 100644 --- a/Source/package-lock.json +++ b/Source/package-lock.json @@ -7,8 +7,10 @@ "": { "name": "blockbenchplugins", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "dependencies": { + "@types/three": "^0.169.0", + "three": "^0.169.0", "typescript": "^4.9.5" }, "devDependencies": { @@ -27,6 +29,12 @@ "node": ">=6.0.0" } }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, "node_modules/@types/jquery": { "version": "3.5.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", @@ -42,12 +50,38 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "node_modules/@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.169.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.169.0.tgz", + "integrity": "sha512-oan7qCgJBt03wIaK+4xPWclYRPG9wzcg7Z2f5T8xYTNEF95kh0t0lklxLLYBDo7gQiGLYzE6iF4ta7nXF2bcsw==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, "node_modules/@types/tinycolor2": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", "dev": true }, + "node_modules/@types/webxr": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.20.tgz", + "integrity": "sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==", + "license": "MIT" + }, "node_modules/@vue/compiler-sfc": { "version": "2.7.14", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz", @@ -59,6 +93,12 @@ "source-map": "^0.6.1" } }, + "node_modules/@webgpu/types": { + "version": "0.1.49", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.49.tgz", + "integrity": "sha512-NMmS8/DofhH/IFeW+876XrHVWel+J/vdcFCHLDqeJgkH9x0DeiwjVd8LcBdaxdG/T7Rf8VUAYsA8X1efMzLjRQ==", + "license": "BSD-3-Clause" + }, "node_modules/blockbench-types": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/blockbench-types/-/blockbench-types-4.6.1.tgz", @@ -73,12 +113,31 @@ "wintersky": "^1.2.1" } }, + "node_modules/blockbench-types/node_modules/three": { + "version": "0.129.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.129.0.tgz", + "integrity": "sha512-wiWio1yVRg2Oj6WEWsTHQo5eSzYpEwSBtPSi3OofNpvFbf26HFfb9kw4FZJNjII4qxzp0b1xLB11+tKkBGB1ZA==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "dev": true }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "license": "MIT" + }, "node_modules/molangjs": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/molangjs/-/molangjs-1.6.2.tgz", @@ -156,10 +215,10 @@ } }, "node_modules/three": { - "version": "0.129.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.129.0.tgz", - "integrity": "sha512-wiWio1yVRg2Oj6WEWsTHQo5eSzYpEwSBtPSi3OofNpvFbf26HFfb9kw4FZJNjII4qxzp0b1xLB11+tKkBGB1ZA==", - "dev": true + "version": "0.169.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.169.0.tgz", + "integrity": "sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==", + "license": "MIT" }, "node_modules/tinycolor2": { "version": "1.6.0", @@ -214,6 +273,11 @@ "integrity": "sha512-q5PNg/Bi1OpGgx5jYlvWZwAorZepEudDMCLtj967aeS7WMont7dUZI46M2XwcIQqvUlMxWfdLFu4S/qSxeUu5g==", "dev": true }, + "@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==" + }, "@types/jquery": { "version": "3.5.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", @@ -229,12 +293,35 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==" + }, + "@types/three": { + "version": "0.169.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.169.0.tgz", + "integrity": "sha512-oan7qCgJBt03wIaK+4xPWclYRPG9wzcg7Z2f5T8xYTNEF95kh0t0lklxLLYBDo7gQiGLYzE6iF4ta7nXF2bcsw==", + "requires": { + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, "@types/tinycolor2": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", "dev": true }, + "@types/webxr": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.20.tgz", + "integrity": "sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==" + }, "@vue/compiler-sfc": { "version": "2.7.14", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz", @@ -246,6 +333,11 @@ "source-map": "^0.6.1" } }, + "@webgpu/types": { + "version": "0.1.49", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.49.tgz", + "integrity": "sha512-NMmS8/DofhH/IFeW+876XrHVWel+J/vdcFCHLDqeJgkH9x0DeiwjVd8LcBdaxdG/T7Rf8VUAYsA8X1efMzLjRQ==" + }, "blockbench-types": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/blockbench-types/-/blockbench-types-4.6.1.tgz", @@ -258,6 +350,14 @@ "typescript": "^4.9.5", "vue": "^2.6.14", "wintersky": "^1.2.1" + }, + "dependencies": { + "three": { + "version": "0.129.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.129.0.tgz", + "integrity": "sha512-wiWio1yVRg2Oj6WEWsTHQo5eSzYpEwSBtPSi3OofNpvFbf26HFfb9kw4FZJNjII4qxzp0b1xLB11+tKkBGB1ZA==", + "dev": true + } } }, "csstype": { @@ -266,6 +366,16 @@ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", "dev": true }, + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, + "meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==" + }, "molangjs": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/molangjs/-/molangjs-1.6.2.tgz", @@ -308,10 +418,9 @@ "dev": true }, "three": { - "version": "0.129.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.129.0.tgz", - "integrity": "sha512-wiWio1yVRg2Oj6WEWsTHQo5eSzYpEwSBtPSi3OofNpvFbf26HFfb9kw4FZJNjII4qxzp0b1xLB11+tKkBGB1ZA==", - "dev": true + "version": "0.169.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.169.0.tgz", + "integrity": "sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==" }, "tinycolor2": { "version": "1.6.0", diff --git a/Source/package.json b/Source/package.json index f6435b7..b5db60b 100644 --- a/Source/package.json +++ b/Source/package.json @@ -1,9 +1,11 @@ { "name": "blockbenchplugins", "version": "1.0.0", - "description": "Blockbench plugin to export bedrock models to Minecraft Legends", + "description": "Blockbench plugin to export Bedrock and Generic models to Minecraft Legends", "main": "index.js", "dependencies": { + "@types/three": "^0.169.0", + "three": "^0.169.0", "typescript": "^4.9.5" }, "scripts": { @@ -13,7 +15,11 @@ "devDependencies": { "blockbench-types": "^4.6.1" }, - "keywords": [], - "author": "HouseOfHow", - "license": "ISC" -} + "keywords": ["blockbench", "polymesh"], + "contributors": [ + "HouseOfHow", + "Mojang", + "Legends Modding" + ], + "license": "MIT" +} \ No newline at end of file diff --git a/Source/src/minecraftLegendsExporter.ts b/Source/src/minecraftLegendsExporter.ts index 9e62141..a4323d0 100644 --- a/Source/src/minecraftLegendsExporter.ts +++ b/Source/src/minecraftLegendsExporter.ts @@ -1,4 +1,3 @@ -//ONLY WORKS ON BEDROCK ENTITY!!!! //All the @ts-ignore are due to blockbench-types not being as up to date as the blockbench source (function () { var codec: Codec = new Codec('minecraftLegends', { @@ -9,7 +8,7 @@ compile(scale: any) { let bones: any = []; // Converted Minecraft Legends bones - // Turns a Group (blockbensh bone) into a Minecraft Legends bone including any locators in that bone. + // Turns a Group (BlockBench bone) into a Minecraft Legends bone including any locators in that bone. function addBone(group: Group) { // Find all locators for this bone let locators: Locator[] = []; @@ -77,6 +76,15 @@ return; addBone(group); }) + + // Process existing Blockbench meshes + function collectMeshes() { + let old_meshes = []; + Mesh.all.forEach(mesh => { + old_meshes.push(mesh); + }) + return old_meshes; + } // Convert all exportable cubes into Blockbench Meshes. // Cubes are defined by their center and size, and Meshes are defined by vertices and faces. @@ -142,13 +150,14 @@ }) new_meshes.push(mesh); }) + return new_meshes; } // Minecraft Legends Meshes let compiledMeshes: any = []; - // Converts a Blockbensh Mesh into a Minecraft Legends Mesh. + // Converts a BlockBench Mesh into a Minecraft Legends Mesh. // A Minecraft Legends Mesh is a skinned mesh, defined by vertices and triangles, where the vertices // are specified in the bind pose. // Each vertex here has a single bone with a bone weight of 1. @@ -253,7 +262,9 @@ compiledMeshes.push(compliedMesh) } - + collectMeshes().forEach((m: Mesh) => { + addMesh(m); + }) // Convert cubes to Minecraft Legends Meshes convertCubesToMeshes().forEach((m: Mesh) => { addMesh(m); @@ -347,7 +358,6 @@ name: 'Minecraft Legends Exporter', icon: 'icon-format_block', category: 'export', - condition: () => Format.id == "bedrock" || Format.id == "bedrock_old", click: function () { if (codec.export !== undefined) { codec.export(); diff --git a/Source/tsconfig.json b/Source/tsconfig.json index b8c34fe..dda73b1 100644 --- a/Source/tsconfig.json +++ b/Source/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES6", + "target": "ES2017", "skipLibCheck": true, "outDir": "build" }, diff --git a/minecraftLegendsExporter.js b/minecraftLegendsExporter.js index 61a3c5c..cf6f0ff 100644 --- a/minecraftLegendsExporter.js +++ b/minecraftLegendsExporter.js @@ -1,13 +1,3 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -//ONLY WORKS ON BEDROCK ENTITY!!!! //All the @ts-ignore are due to blockbench-types not being as up to date as the blockbench source (function () { var codec = new Codec('minecraftLegends', { @@ -16,7 +6,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge remember: false, compile(scale) { let bones = []; // Converted Minecraft Legends bones - // Turns a Group (blockbensh bone) into a Minecraft Legends bone including any locators in that bone. + // Turns a Group (BlockBench bone) into a Minecraft Legends bone including any locators in that bone. function addBone(group) { // Find all locators for this bone let locators = []; @@ -77,6 +67,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge return; addBone(group); }); + // Process existing Blockbench meshes + function collectMeshes() { + let old_meshes = []; + Mesh.all.forEach(mesh => { + old_meshes.push(mesh); + }); + return old_meshes; + } // Convert all exportable cubes into Blockbench Meshes. // Cubes are defined by their center and size, and Meshes are defined by vertices and faces. // So this will create 8 vertices and 6 faces per cube. @@ -144,7 +142,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } // Minecraft Legends Meshes let compiledMeshes = []; - // Converts a Blockbensh Mesh into a Minecraft Legends Mesh. + // Converts a BlockBench Mesh into a Minecraft Legends Mesh. // A Minecraft Legends Mesh is a skinned mesh, defined by vertices and triangles, where the vertices // are specified in the bind pose. // Each vertex here has a single bone with a bone weight of 1. @@ -232,6 +230,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; compiledMeshes.push(compliedMesh); } + collectMeshes().forEach((m) => { + addMesh(m); + }); // Convert cubes to Minecraft Legends Meshes convertCubesToMeshes().forEach((m) => { addMesh(m); @@ -264,60 +265,57 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge include_alpha: { label: 'Alpha Test', type: 'checkbox', value: true }, include_animations: { label: 'codec.common.export_animations', type: 'checkbox', value: true } }, - export() { - return __awaiter(this, void 0, void 0, function* () { - if (Object.keys(this.export_options).length) { - if ((yield this.promptExportOptions()) === null) { - return; - } - } - let options; - options = Object.assign(this.getExportOptions(), options); - // Scale the model to fit Minecraft Legends ratio - options.scale = options.scale / 16; - if (options.include_animations) { - let form = {}; - let keys = []; - let animations = Blockbench.Animation.all.slice(); - if (Format.animation_files) - animations.sort((a1, a2) => a1.path.hashCode() - a2.path.hashCode()); - animations.forEach(animation => { - // @ts-ignore - let key = animation.name; - keys.push(key); - form[key.hashCode()] = { label: key, type: 'checkbox', value: true }; - }); - let dialog = new Dialog({ - id: 'animation_export', - title: 'dialog.animation_export.title', - form, - onConfirm(form_result) { - dialog.hide(); - keys = keys.filter((key) => form_result ? [key.hashCode()] : Number); - MassExport(options, keys); - } - }); - form.select_all_none = { - type: 'buttons', - buttons: ['generic.select_all', 'generic.select_none'], - click(index) { - let values = {}; - keys.forEach(key => values[key.hashCode()] = (index == 0)); - dialog.setFormValues(values); - } - }; - dialog.show(); - } - else { - MassExport(options, undefined); + async export() { + if (Object.keys(this.export_options).length) { + if (await this.promptExportOptions() === null) { + return; } - }); + } + let options; + options = Object.assign(this.getExportOptions(), options); + // Scale the model to fit Minecraft Legends ratio + options.scale = options.scale / 16; + if (options.include_animations) { + let form = {}; + let keys = []; + let animations = Blockbench.Animation.all.slice(); + if (Format.animation_files) + animations.sort((a1, a2) => a1.path.hashCode() - a2.path.hashCode()); + animations.forEach(animation => { + // @ts-ignore + let key = animation.name; + keys.push(key); + form[key.hashCode()] = { label: key, type: 'checkbox', value: true }; + }); + let dialog = new Dialog({ + id: 'animation_export', + title: 'dialog.animation_export.title', + form, + onConfirm(form_result) { + dialog.hide(); + keys = keys.filter((key) => form_result ? [key.hashCode()] : Number); + MassExport(options, keys); + } + }); + form.select_all_none = { + type: 'buttons', + buttons: ['generic.select_all', 'generic.select_none'], + click(index) { + let values = {}; + keys.forEach(key => values[key.hashCode()] = (index == 0)); + dialog.setFormValues(values); + } + }; + dialog.show(); + } + else { + MassExport(options, undefined); + } }, export_action: new Action('export_minecraftLegends', { name: 'Minecraft Legends Exporter', icon: 'icon-format_block', category: 'export', - condition: () => Format.id == "bedrock" || Format.id == "bedrock_old", click: function () { if (codec.export !== undefined) { codec.export();