diff --git a/.dockerignore b/.dockerignore index 58f7af5..22c147d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,3 +3,4 @@ dist/ **/build/ .gradle/ run/ +node_modules/ diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9dc3fae..c25d801 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -7,9 +7,19 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Build with Docker + - name: Build docs + run: cd docs && ./build.sh + + - name: Deploy docs + #if: github.ref == 'refs/heads/master' + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: docs/dist + + - name: Build mod run: ./build.sh + - name: Set deployment variables id: variables uses: actions/github-script@0.9.0 diff --git a/.gitignore b/.gitignore index 16d46c7..9807c3b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ run/ tools/.cached-pages/ tools/.debug/ .env +node_modules/ diff --git a/README.md b/README.md index 33d29c7..8f7f84b 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Originally created in 2015, the Lucky Block is a mod for Minecraft which has sin - [Download Lucky Block](https://www.curseforge.com/minecraft/mc-mods/lucky-block) +- [Docs](https://alexsocha.github.io/luckyblock) - [Minecraft Forum](https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-mods/1292247-lucky-block-mod-drops-items-spawns-mobs-structures) - [Planet Minecraft](https://www.planetminecraft.com/mod/lucky-block/) diff --git "a/\\" "b/\\" new file mode 100644 index 0000000..d4f4e34 --- /dev/null +++ "b/\\" @@ -0,0 +1,52 @@ +import * as R from 'ramda'; +import * as glob from 'glob'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as mkdirp from 'mkdirp'; +import * as jsyaml from 'js-yaml'; +import * as handlebars from 'handlebars'; +import { promisify } from 'util'; + +const baseDir = __dirname; +const distDir = path.join(__dirname, 'dist'); +const globAsync = promisify(glob); + +const readData = async (): Promise<{}> => { + return await R.reduce( + async (acc, filePath) => { + const contents = await fs.promises.readFile(filePath, 'utf-8'); + const data = jsyaml.safeLoad(contents) as object; + return { ...(await acc), ...data }; + }, + {}, + await globAsync(path.join(baseDir, 'src/data/*.yaml')) + ); +}; + +const render = async () => { + const hbs = handlebars.create(); + + // read yaml data + const data = await readData(); + + // register partials + await R.forEach(async (filePath) => { + const fileName = path.basename(filePath, '.html'); + hbs.registerPartial(fileName, await fs.promises.readFile(filePath, 'utf-8')); + }, await globAsync(path.join(baseDir, 'src/partials/*.html'))); + + // render handlebars templates + await fs.promises.mkdir(distDir) + await R.forEach(async (filePath) => { + const contents = await fs.promises.readFile(filePath, 'utf-8'); + const rendered = hbs.compile(contents)(data); + + const distFilePath = path.join(distDir, path.relative('src', filePath)); + await mkdirp(path.dirname(distFilePath)); + await fs.promises.writeFile(distFilePath, rendered, 'utf-8'); + }, await globAsync(path.join(baseDir, 'src/*.md'))); + + await fs.promises.copyFile(path.join(baseDir, 'src/index.html'), path.join(distDir, 'index.html')); +}; + +render(); diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 0000000..e79d1c1 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,8 @@ +FROM node:10-alpine as build +WORKDIR /app + +COPY package*.json . +RUN npm ci + +COPY . . +RUN npm run build diff --git a/docs/build.sh b/docs/build.sh new file mode 100755 index 0000000..60faf80 --- /dev/null +++ b/docs/build.sh @@ -0,0 +1,3 @@ +docker build . -t luckyblock-docs +container_id=$(docker create luckyblock-docs) +docker cp $container_id:/app/dist/. ./dist/ diff --git a/docs/build.ts b/docs/build.ts new file mode 100644 index 0000000..a6685a8 --- /dev/null +++ b/docs/build.ts @@ -0,0 +1,53 @@ +import * as R from 'ramda'; +import * as glob from 'glob'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as mkdirp from 'mkdirp'; +import * as jsyaml from 'js-yaml'; +import * as handlebars from 'handlebars'; +import { promisify } from 'util'; + +const baseDir = __dirname; +const distDir = path.join(__dirname, 'dist'); +const globAsync = promisify(glob); + +const readData = async (): Promise<{}> => { + return await R.reduce( + async (acc, filePath) => { + const contents = await fs.promises.readFile(filePath, 'utf-8'); + const data = jsyaml.safeLoad(contents) as object; + return { ...(await acc), ...data }; + }, + {}, + await globAsync(path.join(baseDir, 'src/data/*.yaml')) + ); +}; + +const render = async () => { + const hbs = handlebars.create(); + + // read yaml data + const data = await readData(); + + // register partials + await R.forEach(async (filePath) => { + const fileName = path.basename(filePath, '.html'); + hbs.registerPartial(fileName, await fs.promises.readFile(filePath, 'utf-8')); + }, await globAsync(path.join(baseDir, 'src/partials/*.html'))); + + await fs.promises.mkdir(distDir) + + // render handlebars templates + await R.forEach(async (filePath) => { + const contents = await fs.promises.readFile(filePath, 'utf-8'); + const rendered = hbs.compile(contents)(data); + + const distFilePath = path.join(distDir, path.relative('src', filePath)); + await mkdirp(path.dirname(distFilePath)); + await fs.promises.writeFile(distFilePath, rendered, 'utf-8'); + }, await globAsync(path.join(baseDir, 'src/*.md'))); + + await fs.promises.copyFile(path.join(baseDir, 'src/index.html'), path.join(distDir, 'index.html')); +}; + +render(); diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 0000000..3e3f53a --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,642 @@ +{ + "name": "luckyblock-website-docs", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "luckyblock-website-docs", + "version": "1.0.0", + "dependencies": { + "glob": "7.1.6", + "handlebars": "4.7.6", + "js-yaml": "3.14.0", + "marked": "1.1.0", + "mkdirp": "1.0.4", + "ramda": "0.27.0" + }, + "devDependencies": { + "@types/glob": "7.1.2", + "@types/js-yaml": "3.12.5", + "@types/mkdirp": "1.0.1", + "@types/ramda": "0.27.7", + "ts-node": "8.10.2", + "typescript": "3.9.6" + } + }, + "node_modules/@types/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/js-yaml": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz", + "integrity": "sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/mkdirp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", + "integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "14.0.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", + "integrity": "sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA==", + "dev": true + }, + "node_modules/@types/ramda": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.7.tgz", + "integrity": "sha512-qt8hYaKfgWE84S6elC8MokRza8sEVkmJqPUbKcl4qVhzryK4eya5ykucgNzzHFJt9hwDYpjtA8h7w2/VT/Gnqg==", + "dev": true, + "dependencies": { + "ts-toolbelt": "^6.3.3" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/marked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.0.tgz", + "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA==", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 8.16.2" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ramda": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz", + "integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/ts-toolbelt": { + "version": "6.13.34", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.13.34.tgz", + "integrity": "sha512-ikZwSUPO+fW+OUnyER1KCG58khTi51Di3+iVdhkK7UshqkL0Ir749B2TQ44o/khkKvDSOMzF8NuVkQLycDXnsg==", + "dev": true + }, + "node_modules/typescript": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", + "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@types/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/js-yaml": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz", + "integrity": "sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mkdirp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", + "integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.0.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", + "integrity": "sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA==", + "dev": true + }, + "@types/ramda": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.7.tgz", + "integrity": "sha512-qt8hYaKfgWE84S6elC8MokRza8sEVkmJqPUbKcl4qVhzryK4eya5ykucgNzzHFJt9hwDYpjtA8h7w2/VT/Gnqg==", + "dev": true, + "requires": { + "ts-toolbelt": "^6.3.3" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "marked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.0.tgz", + "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "ramda": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz", + "integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "ts-toolbelt": { + "version": "6.13.34", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.13.34.tgz", + "integrity": "sha512-ikZwSUPO+fW+OUnyER1KCG58khTi51Di3+iVdhkK7UshqkL0Ir749B2TQ44o/khkKvDSOMzF8NuVkQLycDXnsg==", + "dev": true + }, + "typescript": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz", + "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==", + "dev": true + }, + "uglify-js": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..a60d8c9 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,24 @@ +{ + "name": "luckyblock-website-docs", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "npx ts-node build.ts" + }, + "dependencies": { + "glob": "7.1.6", + "js-yaml": "3.14.0", + "marked": "1.1.0", + "mkdirp": "1.0.4", + "handlebars": "4.7.6", + "ramda": "0.27.0" + }, + "devDependencies": { + "@types/glob": "7.1.2", + "@types/js-yaml": "3.12.5", + "@types/mkdirp": "1.0.1", + "@types/ramda": "0.27.7", + "ts-node": "8.10.2", + "typescript": "3.9.6" + } +} diff --git a/docs/src/_sidebar.md b/docs/src/_sidebar.md new file mode 100644 index 0000000..473140a --- /dev/null +++ b/docs/src/_sidebar.md @@ -0,0 +1,6 @@ +- [Configuration files](/) +- [Outcomes](outcomes.md) +- [Property values](property-values.md) +- [Combined outcomes](combined-outcomes.md) +- [Custom data tags](custom-data-tags.md) +- [Add-ons](add-ons.md) diff --git a/docs/src/add-ons.md b/docs/src/add-ons.md new file mode 100644 index 0000000..fd3d022 --- /dev/null +++ b/docs/src/add-ons.md @@ -0,0 +1,101 @@ +# Add-ons + +Add-ons add new blocks and items similar to the standard ones, but with custom outcomes. + +## Installing + +1. Run Minecraft at least once with the Lucky Block mod installed. +2. Place the add-on file/folder in `.minecraft/addons/lucky/` +3. Run Minecraft again, now with the add-on installed. + +When using an add-on on a server, the add-on must installed on both the server and the client due to the custom textures. + +## Creating + +The file structure of an add-on is very similar to the standard [configuration files](configuration-files), but with additional assets. Add-ons can be distributed as a folder, `.zip` archive (preferred), or `.jar` archive. + +``` +{add-on name}{.zip,.jar,folder} +plugin_init.txt +drops.txt +sword_drops.txt +bow_drops.txt +potion_drops.txt +properties.txt +recipes.txt +natural_gen.txt +luck_crafting.txt +structures.txt +structures/... +assets/lucky/textures/blocks +assets/lucky/textures/blocks/custom_lucky_block.png +assets/lucky/textures/items/custom_lucky_bow_standby.png +assets/lucky/textures/items/custom_lucky_bow_pulling_0.png +assets/lucky/textures/items/custom_lucky_bow_pulling_1.png +assets/lucky/textures/items/custom_lucky_bow_pulling_2.png +assets/lucky/textures/items/custom_lucky_potion.png +assets/lucky/textures/items/custom_lucky_sword.png +assets/lucky/models/item/custom_lucky_bow_pulling_0.json +assets/lucky/models/item/custom_lucky_bow_pulling_1.json +assets/lucky/models/item/custom_lucky_bow_pulling_2.json +assets/lucky/models/item/custom_lucky_sword.json +assets/lucky/models/item/custom_lucky_block.json +assets/lucky/models/item/custom_lucky_bow.json +assets/lucky/models/item/custom_lucky_potion.json +assets/lucky/models/block/custom_lucky_block.json +assets/lucky/blockstates/custom_lucky_block.json +assets/lucky/lang/en_us.json +pack.mcmeta +``` + +**Instructions** + +- Download the template add-on (below) to get started. +- Edit `plugin_init.txt` to specify the ID of the new block and (optionally) items. If an item is omitted, it won't be added to the game and you can ignore all configuration files related to it. + ``` + block_id=custom_lucky_block + sword_id=custom_lucky_sword + bow_id=custom_lucky_bow + potion_id=custom_lucky_potion + ``` +- Rename all of the files containing the word `custom` to match the new IDs. +- Edit each `.json` in `blockstates`/`models` and update the IDs within. You could potentially do a find-and-replace on the word `custom`. + - These files can also be used to create custom models. +- Open `en_us.json` and update both the IDs and in-game display names. + ``` + { + "block.lucky.custom_lucky_block": "Custom Lucky Block", + "item.lucky.custom_lucky_sword": "Custom Lucky Sword", + "item.lucky.custom_lucky_bow": "Custom Lucky Bow", + "item.lucky.custom_lucky_potion": "Custom Lucky Potion" + } + ``` + - You can also add translations for other languages. +- Update the texture `.png` files. +- Leave the file `pack.mcmeta` unchanged. Add-ons are loaded in a similar way to resource packs, and an error message will appear if this file doesn't exist. Otherwise it serves no purpose. +- Use the remaining configuration files customize the add-on as you like. +- When referencing the ID of the new block/items, use the prefix `lucky:`. + +## Template add-on + +{{!-- server-side rendering --}} + + + + + + + + + + \{{#each projects.custom-lucky-block-java}} + + + + + + + + \{{/each}} + +
VersionMinecraft VersionLucky Block VersionLink
\{{{this.version}}}\{{{this.dependencies.minecraft.formattedVersionRange}}}\{{{this.dependencies.lucky-block.formattedVersionRange}}}Download
diff --git a/docs/src/combined-outcomes.md b/docs/src/combined-outcomes.md new file mode 100644 index 0000000..e04dc24 --- /dev/null +++ b/docs/src/combined-outcomes.md @@ -0,0 +1,47 @@ +# Combined outcomes + +## Groups + +Groups are simply a combination of multiple outcomes, all of which take place at the same time. Each outcome is separated by a semicolon `;`, e.g. + +``` +group(type=item,ID=diamond;type=entity,ID=pig) +``` + +You can also specify the number of outcomes that should be selected. Each outcome has an equal chance, though the same one will never be selected twice. + +``` +group:2:(type=item,ID=iron_sword;type=item,ID=iron_pickaxe,type=item,ID=iron_axe) +``` + +Groups can also be nested within groups: + +``` +group(ID=wooden_sword;group:1:(type=entity,ID=creeper;type=entity,ID=zombie)) +``` + +## Luck level + +- Property: `@luck` + +Luck level is and additional property which describes how 'lucky' an outcome is, in the range `-2..2`. When the luck property of the source block/item/etc is increased/decreased, outcomes with a higher/lower luck level become more likely. The default luck level is `0`. Below is a rough guide for all of the levels: + +- `-2`: Very unlucky. Might kill the player or do great damage. +- `-1`: Unlucky. Does something that the player would not want, or something completely useless. +- `0`: Neutral. Not bad, not useless, but fairly average. +- `1`: Lucky. Something that the player would be happy to receive. +- `2`: Very lucky. The best thing the player could hope for. + +``` +ID=diamond,amount=4@luck=1 +``` + +## Chance + +- Property: `@chance` + +Chance is an additional property which describes how likely the outcome is to be chosen. By default, all outcomes are equally likely. Using `@chance=0.5` makes an outcome half as likely, while `@chance=4` makes it 4 times as likely. + +``` +type=entity,ID=Wither@luck=-2@chance=0.1 +``` diff --git a/docs/src/configuration-files.md b/docs/src/configuration-files.md new file mode 100644 index 0000000..f4d33e5 --- /dev/null +++ b/docs/src/configuration-files.md @@ -0,0 +1,241 @@ +# Configuration files + +The Lucky Block configuration files can be found in the `.minecrat/config/lucky/version-{...}`, after you run the mod at least once. + +## Properties + +- File: `properties.txt` + +{{> properties-table properties=properties }} + +## Luck crafting + +- File: `luck_crafting.txt` + +Certain items can affect the 'luck' of a Lucky Block or Lucky Potion when combined in a crafting table. This skews the probability of positive/negative outcomes, with values ranging from -100 to 100. These items are specified here, using the format. + +``` +[item]=[-100..100] +``` + +For example: + +``` +diamond=12 +spider_eye=-10 +pufferfish=-15 +``` + +## Natural generation + +- File: `natural_gen.txt` + +The Lucky Block can generate naturally in the Minecraft world, and across all dimensions. Every entry in this file is a standard Lucky Block [outcome](outcomes), which will occur naturally within the world. Dimensions are separated by `>{dimension_id}` + +While not a requirement, the file should only contain outcomes that place Lucky Blocks in the world. This includes either directly placing a Lucky Block or using a custom structure. Lastly, the outcomes should not use any properties related to the player, as they are not initiated by a player. + +### Spawnrate + +Each outcome has a one in `spawnrate` chance of ocuring per chunk (16x16 block region). Therefore, higher spawnrates mean that the outcome is less likely to occur. To specify the spawnrate of a outcome, use the [@chance](combined_outcomes#chance) property. Note that this usage of the chance property is not related to the regular usage (e.g. in `drops.txt`). Also note that `@luck` has no effect. + +> If two outcomes have the same spawnrate, the overall chance of generation will double. If a spawnrate of 1/200 (@chance=200) is desired, and there are two possible outcomes, it would be appropriate to give each a spawnrate of 1/400 (@chance=400). + +The location of the spawn will usually be on the surface layer of the world, as long as a valid surface is found. If this is not possible, e.g. in an ocean biome, the spawn may occur in an underground cave. + +### Example + +``` +>minecraft:overworld +type=structure,ID=gen_struct_1@chance=400 +type=structure,ID=gen_struct_2@chance=400 + +>minecraft:the_nether +type=block,ID=lucky:lucky_block@chance=35 + +>minecraft:the_end +type=block,ID=lucky:lucky_block@chance=25 +``` + +In the overworld, this spawn one of two structures. The overall surface spawnrate is 1/200. In the Nether and the End, only single Lucky Blocks will spawn. Note the much higher spawnrates (1/35 and 1/25), due to the difficulty of navigating these dimensions. + +## Structures + +- Files: `structures.txt`, `*.luckystruct`, `*.schematic` + +Structures structures are first configured in a separate `/structures`, which contains all structures as either `.schematic` or `.luckystruct` files. In the main directory, the file `structures.txt` is used to specify additional properties for each structure. + +You can export `.schematic` structures from Minecraft directly. + +### .luckystruct structures + +**Advantages** + +- Easier to edit +- Support Lucky Block [hash variables](property-values#hash_variables) + +You can also use these structures as an overlay on top of `.schematic` structures, to configure detailed elements such as entities and block entities. + +**Format** + +The file is divided into three sections, `>properties`, `>blocks` and `>entities`. Firstly, the length, width and height of the structure are specified under the `>properties` section. + +``` +>properties +length=5 +height=2 +width=3 +``` + +Then, every block in the structure is listed under the `>blocks` section. Air blocks do not need to be listed, as any position in the structure without a block will default to air. + +``` +x,y,z,id,state*,tile entity* +``` + +_\* Optional_ + +These properties are the same as in the [block outcome](outcomes#block), though the XYZ coordinates are relative to the structure's internal structure coordinate system. + +Below is an example of a structure containing a custom Lucky Block which, when opened, will display the message `Hello there, {name of the player}`. + +``` +>blocks +4,0,1,lucky:lucky_block,,(Drops=["type=message,ID=\"Hello there, #pName\""]) +``` + +Finally, entities are specified below the `>entities` section. + +``` +x,y,z,id,data* +``` + +_\* Optional_ + +These properties are the same as in the [entity outcome](outcomes#entity), but again with relative coordinates. + +### structures.txt + +This file lists all of the available structures, and configures additional properties for each. + +{{> properties-table properties=outcomes.structure_definition }} + +**Block mode** + +| Mode | Descriptions | +| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `replace` | Blocks in the world are replaced by those added to form the structure. This applies for all blocks. | +| `overlay` | Blocks in the world are replaced by those added form the structure, with the exception of air blocks. Air blocks in the structure will not be added to the world. | +| `air` | Every block in the structure, except for air, will be added to the world as air. Therefore, the structure define a 'hole' that will be made in the world. | + +**Structure coordinates** + +To make working with structures easier, it's recommended that you: + +- Build the structure facing north (in the negative z direction). +- If the structure's rotation is relative to the player's direction, build it the way it will appear when the player is facing north. + +When the structure is generated without rotation, the structure coordinate `(0,0,0)` will appear in the bottom, east-most, north-most corner. The coordinate `(centerX,centerY,centerZ)` will always appear in the position where the outcome was initiated. + +**Example** + +Imagine a container ship structure with a width of 50, height of 50, and length of 100, which appears to be traveling in the north direction. When the structure is generated, we want the player to be on the ship. To achieve this we will: + +- Set `centerX` to `50 / 2 = 25` and `centerZ` to `100 / 2 = 50`, so that the player is in the middle of the ship. +- Set `centerY` to `21`, so that the ship is submerged (assuming the deck is at level `20`). + +``` +(structures.txt) +file=ship.shematic,ID=ship,centerX=25,centerY=20,centerZ=50 +``` + +To generate the structure, we will include a rotation relative to the direction that the player is facing: + +``` +(drops.txt) +type=structure,ID=ship,pos=#pPos,rotation=#pDirect +``` + +Now let's say that we instead want to generate the ship so that it's travelling towards the player. Below is an example configuration which uses the same structure file: + +``` +(structures.txt) +file=ship.shematic,ID=ship,centerX=25,centerY=5,centerZ=-10 + +(drops.txt) +type=structure,ID=ship,pos=#pPos,rotation=#pDirect+2 +``` + +The ship is now gently submerged, and the center point has been moved in front of it. When generated, a 180 degree rotation is applied relative to the player, so that two are facing each other. + +## Lucky Block outcomes + +- File: `drops.txt` + +Defines the outcomes that the Lucky Block performs, one per line. See [outcomes](outcomes), [property values](property-values), and [combined outcomes](combined-outcomes) for detailed syntax. + +## Lucky Sword outcomes + +- File: `sword_drops.txt` + +Defines the outcomes that the Lucky Sword performs, in the same format as `drops.txt`. The Lucky Sword will always cause damage to entities, regardless of its additional effects. It's attack damage is the same as an iron sword, with twice the duration of a diamond sword. Additional actions should be rare, which can be enforced by including a 'nothing' action: + +``` +type=nothing@luck=0@chance=20 +``` + +> The majority of the outcomes should be positive (for the player using it). The `type=nothing` outcome should have the lowest luck, so that when the luck of the sword is increased through crafting, the frequency of additional effects is also increased. + +## Lucky Bow outcomes + +- File: `bow_drops.txt` + +Defines the outcomes that the Lucky Bow performs, in the same format as `drops.txt`. The Lucky Bow should always shoot a projectile, and its position/motion should be set using the `#bowPos`/`#bowMotion` hash variables. For example, a regular arrow: + +``` +type=entity,ID=Arrow,pos=#bowPos,NBTTag=(Motion=#bowMotion,Color=-1)@luck=0@chance=20 +``` + +To perform custom outcomes on impact, you can use the [lucky projectile](block-items-entities#lucky-projectile). For example: + +type=entity,ID=LuckyProjectile,pos=#bowPos,NBTTag=(Motion=#bowMotion,item=(id=tnt),drops=["type=explosion"]) + +## Lucky Potion outcomes + +- File: `potion_drops.txt` + +Defines the outcomes that the Lucky Potion performs, in the same format as `drops.txt`. The Lucky Potion should always perform a custom outcome. You should also include a splash potion animation each time, such as: + +``` +type=particle,ID=splashpotion,potion=strength +``` + +> Since a Lucky Potion can be used both as a weapon and a defense, make sure to clearly mark outcomes using `@luck=-2..2`. This way, when the its luck is modified through crafting, it will serve a different purpose. + +## Common + +- File: all + +**Comments** + +Any line beginning with a forward slash `/` will be ignored, and treated as a comment. + +``` +/ items +type=item,ID=diamond +ID=emerald + +/ entities +type=entity,ID=Pig +type=entity,ID=Cow +``` + +**Multiline** + +You can split a long line into multiple lines using a backslash `\`. + +``` +group(type=entity,ID=Zombie,amount=40,posOffset=#circleOffset(8,10); \ +type=entity,ID=Creeper,amount=10,posOffset=#circleOffset(8,10); \ +type=entity,ID=Skeleton,amount=30,posOffset=#circleOffset(8,10); \ +type=entity,ID=Spider,amount=20,posOffset=#circleOffset(8,10)) +``` diff --git a/docs/src/custom-data-tags.md b/docs/src/custom-data-tags.md new file mode 100644 index 0000000..d7b56ff --- /dev/null +++ b/docs/src/custom-data-tags.md @@ -0,0 +1,40 @@ +# Custom data tags + +## Lucky Block + +The Lucky Block includes a custom block entity, in the format: + +- Luck: `integer` (optional). The luck of the block, which is usually modified through crafting. +- Drops: `["outcome 1", "outcome 2", ...]` (optional). A list of custom outcomes. If specified, this will override the default outcomes. Only one is chosen each time. + +With Minecraft commands, you can create custom Lucky Blocks: + +``` +/setblock ~ ~ ~ lucky:lucky_block{Luck:50,Drops:["type=item,ID=stick","type=item,ID=diamond"]} +``` + +## Lucky items + +The Lucky Sword, Lucky Bow, and Lucky Potion have the same data tag as the Lucky Block. + +``` +/give @a lucky:lucky_sword{Luck:10,Drops:["type=nothing@chance=10","type=effect,ID=special_fire,target=hitEntity,duration=10"]} +``` + +## Lucky Projectile + +The Lucky Projectile is a special entity which performs outcomes on impact. It is most commonly used by the Lucky Bow, and its appearance can be customised to any any item. Its data is in the format: + +- item: The item used for the appearance of the projectile. + - id: `text`. The item ID. + - tag: `Compound NBT tag` (optional). Additional item data. +- trail (optional): The outcomes that will occur while the projectile is alive. + - frequency: `float`. How frequently the outcomes will occur, in [game ticks](https://minecraft.gamepedia.com/Tick) (0.05 seconds). A value less than one will cause multiple outcomes per tick. + - drops: `["outcome 1", "outcome 2", ...]`. A list of trail outcomes. Only one is chosen each time. +- drops: `["outcome 1", "outcome 2", ...]`. A list of outcomes that will occur on impact. Only one is chosen each time. + +An example projectile that the Lucky Bow might shoot: + +``` +type=entity,ID=LuckyProjectile,pos=#bowPos,NBTTag=(Motion=#bowMotion,item=(id=water_bucket),trail=(frequency=0.5,drops=["type=particle,ID=splash"]),impact=["type=block,ID=flowing_water"] +``` diff --git a/docs/src/data/hash-vars.yaml b/docs/src/data/hash-vars.yaml new file mode 100644 index 0000000..9dba7d5 --- /dev/null +++ b/docs/src/data/hash-vars.yaml @@ -0,0 +1,166 @@ +hash_vars: + standard: + - name: '#bPos, #bPosX, #bPosY, #bPosZ' + return_type: '`(integer,integer,integer)` \| `integer`' + description: The position at which the outcome occured, rounded to the nearest block. `#bPos` returns an `(x,y,z)` tuple, while `bPos{X,Y,Z}` returns each component separately. + example: type=entity,ID=Zombie,posX=#bPosX+5 + + - name: '#pPos, #pPosX, #pPosY, #pPosZ' + return_type: '`(float,float,float)` \| `float`' + description: The position of the player who initiated the outcome, rounded to the nearest block. `#pPos` returns an `(x,y,z)` tuple, while `pPos{X,Y,Z}` returns each component separately. + example: type=block,ID=anvil,posY=#posY+10 + + - name: '#ePos, #ePosX, #ePosY, #ePosZ' + return_type: '`(float,float,float)` \| `float`' + description: The position of the entity hit (e.g. by the Lucky Sword or Lucky Projectile), rounded to the Nearest block. `#pPos` returns an `(x,y,z)` tuple, while `ePos{X,Y,Z}` returns each component separately. + example: type=explosion,delay=5,pos=#ePos + + - name: '#{b,p,e}ExactPos, #{b,p,e}ExactPos{X,Y,Z}' + return_type: '`(float,float,float)` \| `float`' + description: Same as the previous position variables, but without rounding. + example: type=entity,ID=Zombie,pos=#pExactPos + + - name: '#bowPos' + return_type: '`(float,float,float)`' + description: Returns the position which should be given to an entity shot from the Lucky Bow. + example: type=entity,ID=Arrow,pos=#bowPos,NBTTag=(Motion=#bowMotion) + + - name: '#circeOffset' + args: 'min: `float`[, max: `float`]' + return_type: '`(float,0,float)`' + description: Returns circular position offset. The points will always be evenly spaced, depending on the `amount` property, and will randomly lie within a (min, max) radius. + example: type=entity,ID=Pig,amount=20,posOffset=#circleOffset(2,3) + + - name: '#pName' + return_type: '`text`' + description: The name of the player who initiated the outcome. + example: 'type=message,ID="Hello there, #pName"' + + - name: '#UUID' + return_type: '`UUID`' + description: The UUID of the player who initiated the outcome. + example: type=entity,ID=EntityHorse,NBTTag=(OwnerUUID=#pUUID) + + - name: '#pPitch' + return_type: '`-90..90`' + description: The pitch of the player who initiated the outcome. Pitch 90 = down, pitch -90 = up. + example: type=entity,ID=arrow,NBTTag=(Motion=#motionFromDirection(#pYaw,#pPitch+#rand(-10,10),1.0)),amount=10 + + - name: '#pYaw' + return_type: '`0..360`' + description: The yaw of the player who initiated the outcome. Yaw 0 = south, yaw 180 = north. + example: id=head,NBTTag=(Rotation=[#pYaw+180f,0f]) + + - name: '#pDirect' + return_type: '`0` \| `1` \| `2` \| `3`' + description: The direction the player is facing, rounded to the nearest X/Z axis. 0 = north, 1 = east, 2 = south, 3 = west. + example: type=structure,ID=ship,rotation=#pDirect + + - name: '#rand' + args: 'min: `integer`, max: `integer`' + return_type: '`integer`' + description: Selects a random integer in the given range, inclusive. + example: type=block,ID=anvil,posOffsetY=#rand(5,10) + + - name: '#rand' + args: 'min: `float`, max: `float`' + return_type: '`float`' + description: Selects a random float in the given range, inclusive. + example: type=entity,ID=bat,posOffsetY=#rand(0.0,5.0),amount=30 + + - name: '#randPosNeg' + args: 'min: `integer`, max: `integer`' + return_type: '`integer`' + description: Selects a random integer in the given range, inclusive, with a 50% chance of being negative. + example: type=block,ID=lava,posOffsetY=-1,posOffsetX=#randPosNeg(1,3),posOffsetZ=#randPosNeg(1,3),amount=10 + + - name: '#randPosNeg' + args: 'min: `float`, max: `float`' + return_type: '`float`' + description: Selects a random float in the given range, inclusive, with a 50% chance of being negative. + example: type=entity,ID=egg,NBTTag=(Motion=#motionFromDirection(#pYaw,#randPosNeg(10,20),1.0)),amount=20 + + - name: '#randList' + args: 'value1, value2, ...' + return_type: 'One of the values in the list' + description: Selects a random value from the given list. + example: type=item,ID=#randList(gold_ingot,diamond) + + - name: '#time' + return_type: '`0..24000`' + description: The current [world time](https://minecraft.gamepedia.com/Daylight_cycle). + example: type=time,ID=#time+1000 + + - name: '#randColor' + return_type: '[Dye ID](https://minecraft.gamepedia.com/Dye#ID)' + description: Selects a random color. + example: type=block,ID=#randColor_terracotta + + - name: '#randPotion' + return_type: '[Status effect ID](https://minecraft.gamepedia.com/Status_effect)' + description: Selects a random status effect. + example: type=item,ID=potion,NBTTag=(Potion=#randPotion) + + - name: '#randSpawnEgg' + return_type: '[Spawn egg ID](https://minecraft.gamepedia.com/Spawn_Egg#ID)' + description: Selects a random spawn egg. + example: type=item,ID=#randSpawnEgg + + nbt: + - name: '#luckySwordEnchantments, #luckyAxeEnchantments, #luckyToolEnchantments, #luckyBowEnchantments, #luckyFishingRodEnchantments, #luckyCrossbowEnchantments, #luckyTridentEnchantments' + return_type: '`[(id=enchantment_id, lvl=integer), ...]`' + description: Selects random enchantments for each item catagory. + example: type=item,ID=diamond_axe,NBTTag=(ench=#luckyAxeEnchantments) + + - name: '#luckyHelmetEnchantments, #luckyChestplateEnchantments, #luckyLeggingsEnchantments, #luckyBootsEnchantments' + return_type: '`[(id=enchantment_id, lvl=integer), ...]`' + description: Selects random enchantments for each armor catagory. + example: type=item,ID=iron_boots,NBTTag=(ench=#luckyBootsEnchantments) + + - name: '#chestLootTable' + args: 'name: [loot table name](https://minecraft.gamepedia.com/Loot_table#List_of_loot_tables)' + return_type: '[Loot table tag](https://minecraft.gamepedia.com/Loot_table#Tags)' + example: type=block,ID=chest,tileEntity=(Items=#chestLootTable("chests/spawn_bonus_chest")) + + - name: '#randEnchantment' + return_type: '`(id=enchantment_id, lvl=integer)`' + description: Selects a single random enchantment. Most commonly used for enchanted books. + example: type=item,ID=enchanted_book,NBTTag=(StoredEnchantments=#randomEnchantment) + + - name: '#randFireworksRocket' + return_type: '[Fireworks item tag](https://minecraft.gamepedia.com/Firework_Rocket#Item_data)' + description: Creates a random fireworks rocket. + examples: + - type=item,ID=fireworks,NBTTag=#randFireworksRocket + - type=entity,ID=FireworksRocketEntity,NBTTag=(LifeTime=20,FireworksItem=#randFireworksRocket) + + - name: '#randLaunchMotion' + args: '[power: `float`, pitch: `0..90`]' + return_type: '`[double,double,double]`' + description: Returns an `[x,y,z]` motion tag which can be given to an entity, launching it upwards with the given power. The yaw angle is randomly chosen, while pitch is specified as an angle between the y axis (pitch 0 = up). The default inputs are `(0.9,15)`. + example: type=entity,ID=tnt,amount=10,NBTTag=(Fuse=50,Motion=#randLaunchMotion(1.5,12) + + - name: '#motionFromDirection' + args: 'yaw: `0..360`, pitch: `-90..90`, power: `float`' + return_type: '`[double,double,double]`' + description: Converts a direction and power into an `[x,y,z]` motion tag which can be given to an entity. Yaw 0 = south, yaw 180 = north, pitch -90 = down, pitch 90 = up. + example: type=entity,ID=egg,posY=#pExactPosY+0.4,NBTTag=(Motion=#motionFromDirection(#pYaw,#pPitch,0.5)) + + - name: '#bowMotion' + args: '[power: `float`, angleOffset: `0..90`]' + return_type: '`[double,double,double]`' + description: Returns an `[x,y,z]` motion tag which should be given to an entity shot from the Lucky Bow. The power is a multiplier of the default bow power, and the offset is chosen randomly in both the pitch and yaw direction. The default inputs are `(1.0,0.0)` + example: type=entity,ID=tnt,pos=#bowPos,NBTTag=(Motion=#bowMotion(2.5)) + + structure: + - name: '{#sPos, #sPosX, #sPosY, #sPosZ}' + args: 'x, y, z' + return_type: 'An integer or float `(x,y,z)` tuple' + description: Converts the given structure coordinates to the corresponding world coordinates of the generated structure. The input is an `(x,y,z)` tuple, in relative structure coordinates. `#sPos` will output the corresponding `(x,y,z)` tuple in world coordinates, while `#sPos{X,Y,Z}` will output each component separately. The output will use `float` values if one of the input coordinates is a `float`, and otherwise `integer` values. + example: 1,0,1,lucky:lucky_block,0,tileEntity=(Drops=["type=entity,ID=Zombie,pos=#sPos(2.5,0,2.5))"]) + + - name: '#drop' + args: 'property name' + return_type: '`any`' + description: Gets the value of a property that the structure was generated with. This is often used to create further structures with the same properties. + example: 1,0,1,lucky:lucky_block,0,tileEntity=(Drops=["type=structure,ID=inner,pos=#drop(pos),rotation=#drop(rotation))"]) diff --git a/docs/src/data/outcomes.yaml b/docs/src/data/outcomes.yaml new file mode 100644 index 0000000..00e98c4 --- /dev/null +++ b/docs/src/data/outcomes.yaml @@ -0,0 +1,313 @@ +outcomes: + common: + - name: type + type: '`text`' + default: '`item`' + description: The type of the outcome. All other properties, except for base properties, will depend on the type. + example: type=message,ID="Hello" + + - name: pos, posX, posY, posZ + type: '`(integer, integer, integer)` \| `integer`' + default: The position at which the outcome was initiated + description: Sets the position at which the outcome will occur. Use `pos` to set all coordinates at once, or `pos{X,Y,Z}` to set each separately. + examples: + - type=entity,ID=Zombie,posY=255 + - type=entity,ID=Zombie,pos=(40,64,-90) + + - name: posOffset, posOffsetX, posOffsetY, posOffsetZ + type: '`(integer, integer, integer)` \| `integer`' + default: '`0`' + description: Offsets the position of the outcome. Use `posOffset` to set all coordinates at once, or `posOffset{X,Y,Z}` to set each separately. Note that in many cases you can use e.g. `posY=#bPosY+10` to acheive the same result. + examples: + - type=entity,ID=Sheep,posOffsetY=10 + - type=entity,ID=Sheep,amount=20,posOffset=#circleOffset(5) + + - name: amount + type: '`integer`' + default: '`1`' + description: Specifies the number of times the outcome will be repeated. All properties will remain the same for each instance of the outcome, unless the properties are randomized (see `reinitialize`). + example: type=item,ID=diamond,amount=10 + + - name: reinitialize + type: '`true`\|`false`' + default: '`true`' + description: Used when the amount property is greater than one. This will specify whether each instance of the outcome should have its properties re-randomized. If set to `false`, random properties will only be chosen for the first instance of the outcome, and subsequent outcomes will use those properties. + example: type=item,ID=dye,damage=#rand(0,15),amount=10,reinitialize=false + + - name: delay + type: '`float`' + default: '`0`' + description: Delays the occurrence of the outcome. The delay is specified in seconds, and the outcome will take place once the time has passed. + example: type=item,ID=gold_block,delay=5 + + - name: postDelayInit + type: '`true`\|`false`' + default: '`true`' + description: Whether a delayed outcome will be initialized after the delay (`true`), or immediately (`false). This will affect when [hash variables](property-values#hash-variables) are evaluated. + example: type=entity,ID=Zombie,pos=#pPos,delay=5,postDelayInit=false + + item: + - name: ID + type: '[Item ID](https://minecraft.gamepedia.com/Java_Edition_data_value#Items)' + default: '`text`' + description: The ID of the item. + example: type=item,ID=diamond_sword + + - name: NBTTag + type: '[NBT Tag](property-values#nbt-tags)' + default: '`()`' + description: Used to specify the NBT Tag of an item. This property stores additional data about the item, a full list of item NBT Tags can be found here. + example: type=item,ID=potion,NBTTag=(Potion="fire_resistance") + + block: + - name: ID + type: '[Block ID](https://minecraft.gamepedia.com/Java_Edition_data_value#Blocks)' + description: The ID of the block. + example: type=block,ID=pumpkin + + - name: state + type: '[NBT Tag](property-values#nbt-tags)' + default: '`()`' + description: The [block state](https://minecraft.gamepedia.com/Block_states). + example: type=block,ID=cauldron,state=(level=3) + + - name: tileEntity + type: '[NBT Tag](property-values#nbt-tags)' + default: '`()`' + description: Sets the [block entity](https://minecraft.gamepedia.com/Block_entity). + example: type=block,ID=sign,tileEntity=(Text2="{\"text\":\"Hello\",\"color\":\"blue\"}") + + - name: blockUpdate + type: '`true`\|`false`' + default: '`true`' + description: Whether the block should be updated once placed. If enabled, water will flow, blocks that cannot stay (e.g. torches in air) will be dropped, and other updates will take place. + example: type=block,ID=water,blockUpdate=false + + entity: + - name: ID + type: '[Entity ID](https://minecraft.gamepedia.com/Java_Edition_data_value#Entities)' + default: '`text`' + description: The ID of the entity. + example: type=entity,ID=Zombie + + - name: NBTTag + type: '[NBT Tag](property-values#nbt-tags)' + default: '`()`' + description: Sets additional entity properties + example: type=item,ID=Pig,NBTTag=(CustomName="Sam") + + structure_definition: + - name: ID + type: '`text`' + description: The ID that the structure can be referenced by. + example: ID=house,file=my_house.schematic + + - name: file + type: '`text`' + description: Specifies the relative path to the structure file. + example: ID=ship,file=my_structs/ship.schematic + + - name: centerX, centerY, centerZ + type: '`integer`' + default: '`width/2`,`0`,`length/2`' + description: Used to specify the center point of the structure, relative to the structure's coordinate system. This point will appear at exactly the world position where the structure is generated, and rotations will occur around `centerX` and `centerZ`. Note that these values can be negative, and do not strictly have to be within structure's coordinate box. + example: ID=ship,file=...,centerX=4,centerY=1,centerZ=2 + + - name: blockMode + type: '`replace`\|`overlay`\|`air`' + default: '`replace`' + description: Use to specify how the blocks in this structure should act with the blocks already in the world. Refer to the table below. + example: ID=ship,file=ship_inner.luckystruct,blockMode=overlay + + - name: blockUpdate + type: '`true`\|`false`' + default: '`true`' + description: Whether the blocks in the structure should be updated once placed. + example: ID=water_sculpture,file=water.luckystruct,blockUpdate=false + + - name: overlayStruct + type: 'Structure ID' + default: None + description: The ID of a different structure that will be overlaid onto this one. The other structure must have been previously configured in the file. While not a requirement, the other structure should usually have `blockMode=overlay`. This is commonly used for `.schematic` structures which require a `.luckystruct` overlay to configure the finer details, such as entities and block entities. + example: ID=ship_inner,file=ship_inner.luckystruct + ID=ship,file=ship.shematic,overlayStruct=ship_inner + + structure: + - name: ID + type: '[Structure ID](config_files#structures)' + description: The ID of a structure defined in `structures.txt`. + example: type=structure,ID=ship + + - name: rotation + type: '`integer`' + default: '`0`' + description: The number of times the structure should be rotated by 90 degrees, clockwise. The rotation will occur around the structure's centerX and centerZ. + example: type=structure,ID=ship,rotation=3 + + command: + - name: command + type: '[Command](https://minecraft.gamepedia.com/Commands)' + description: The full command text. + example: type=command,ID="/say Hello" + + - name: commandSender + type: The name of a player, or a selector + default: '`@a`' + description: The sender of the command. + example: type=command,commandSender=PlayerInDistress,ID="/tell @a Here is a message from PlayerInDistress" + + - name: displayOutput + type: '`true`\|`false`' + default: '`false`' + description: Whether the output of the command should be displayed in the chat. + + difficulty: + - name: ID + type: '`peaceful`\|`easy`\|`normal`\|`hard`' + description: The world [difficulty level](https://minecraft.gamepedia.com/Difficulty). + example: type=difficulty,ID=hard + + time: + - name: ID + type: '`0..24000`\|`day`\|`night`' + description: The world [time](https://minecraft.gamepedia.com/Daylight_cycle). + example: type=time,ID=night + + effect: + - name: ID + type: '[Status effect ID](https://minecraft.gamepedia.com/Status_effect)' + description: The ID of the status effect + example: type=effect,ID=slowness + + - name: duration + type: '`integer`' + default: '`30`' + description: The number of seconds the effect will last for. + + - name: amplifier + type: '`0..255`' + default: '`0`' + description: The effect amplifier, which is one less than the number displayed (e.g. Strength III has an amplifier of 2). + example: type=effect,ID=strength,amplifier=2 + + - name: target + type: '`none`\|`player`\|`hitEntity`' + default: '`none`' + description: Whether the effect should be given to the player who initiated it, or to the entity that was hit (only applies to the Lucky Sword and [Lucky Projectile](custom-data-tags#lucky-projectile)). + example: type=effect,ID=blindness,target=hitEntity + + - name: range + type: '`integer`' + default: '`4`' + description: If `target=none`, the effect will be applied all entities within this range. + example: type=effect,ID=instant_damage,range=10 + + - name: excludePlayer + type: '`true`\|`false`' + default: '`false`' + description: If `target=none`, this determines whether the player who initiated the effect should be excluded. + example: type=effect,ID=poison,exludePlayer=true + + special_effect: + - id: special_fire + extra_args: + - name: duration + type: '`integer`' + description: Sets an entity on fire for the given number of seconds. + example: type=effect,ID=special_fire,duration=5 + + - id: special_knockback + extra_args: + - name: power + type: '`float`' + - name: directionYaw + type: '`0..360`' + - name: directionPitch + type: '`-90..90`' + description: Pushes the entity away in a given direction (yaw 0 = south, pitch 90 = down) with a given power. By default, the angles are calculated away from the source of the effect. + example: type=effect,ID=special_knockback,ragne=4,power=2.5 + + explosion: + - name: radius + type: '`integer`' + default: '`4`' + description: The size of the explosion. For reference, a creeper explosion has radius 3, TNT has 4, and a charged creeper has 6 + example: type=explosion,radius=7 + + - name: fire + type: '`true`\|`false`' + default: '`false`' + description: Whether the explosion will set blocks on fire, in the same way as a charged creeper. + example: type=explosion,fire=true + + fill: + - name: ID + type: '[Block ID](https://minecraft.gamepedia.com/Java_Edition_data_value#Blocks)' + description: The ID of the block. + example: type=fill,ID=lava,size=(3,3,3) + + - name: state + type: '[NBT Tag](property-values#nbt-tags)' + default: '`()`' + description: The [block state](https://minecraft.gamepedia.com/Block_states). + example: type=fill,ID=cake,state=(bites=4),size=(3,1,3) + + - name: size, width, height, length + type: '`(integer, integer, integer)` \| `integer`' + default: '`(1,1,1)`' + description: The size of the fill area. Use `size` to set all dimensions at once, or `length`/`width`/`height` to set each separately. When facing north, the initial outcome position will appear in the bottom, north-most, west-most corner of the fill area. + example: type=fill,ID=air,size=(5,3,5) + + - name: pos2, pos2X, pos2Y, pos2Z + type: '`(integer, integer, integer)` \| `integer`' + description: 'An alternative way of setting the fill area, so that each dimension is defined by two points: the inital outcome position and the one given here. Use `pos2` to set all coordinates at once, or `pos2{X,Y,Z}` to set each separately.' + example: type=fill,ID=air,posOffset=(-1,0,-1),pos2=(#pPosX+1,#pPosY-10,#pPosZ+1) + + message: + - name: ID + type: '`text`' + description: The message text. + example: 'type=message,ID="Hello, #pName"' + + particle: + - name: ID + type: '[Particle ID](https://minecraft.gamepedia.com/Particles)' + description: The ID of the particle. + example: type=particle,ID=heart + + - name: size, width, height, length + type: '`(float, float, float)` \| `float`' + default: '`(0,0,0)`' + description: The size of the box in which the particle can spawn. + example: type=particle,ID=note,particleAmount=20,height=3 + + - name: particleAmount + type: '`integer`' + description: The number of particles that will be created. Note that this is more efficient than `amount`. + example: type=particle,ID=smoke,posX=#pPos,size=(0.5,1,0.5),particleAmount=200 + + special_particle: + - id: splashpotion + extra_args: + - name: potion + type: '[Status effect ID](https://minecraft.gamepedia.com/Status_effect)' + description: The breaking animation of a splash potion (with sound). + example: type=particle,ID=splashpotion,potion=night_vision + + sound: + - name: ID + type: '[Sound ID](https://minecraft.gamepedia.com/Sounds.json#Sound_events)' + description: The sound resource ID. + example: type=sound,ID=mob.pig.say + + - name: volume + type: '`float`' + default: '`1.0`' + description: The volume at which the sound will be played. + example: type=sound,ID=block.bell.use,volume=3.0 + + - name: pitch + type: '`1.0..2.0`' + default: '`1.0`' + description: The pitch at which the sound will be played. + example: type=sound,ID=block.note_block.harp,pitch=1.5 diff --git a/docs/src/data/properties.yaml b/docs/src/data/properties.yaml new file mode 100644 index 0000000..9f73e45 --- /dev/null +++ b/docs/src/data/properties.yaml @@ -0,0 +1,17 @@ +properties: + - name: doDropsOnRightClick + minVersion: 11 + type: '`true`\|`false`' + default: '`false`' + description: Do drops when the Lucky Block is right clicked. + + - name: doDropsOnCreativeMode + maxVersion: 5 + type: '`true`\|`false`' + default: '`false`' + description: Do drops when the Lucky Block is broken on creative mode. + + - name: showUpdateMessage + type: '`true`\|`false`' + default: '`false`' + description: Show a chat message when a new version of the mod is available. diff --git a/docs/src/index.html b/docs/src/index.html new file mode 100644 index 0000000..8ee906c --- /dev/null +++ b/docs/src/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + +
+ + + + diff --git a/docs/src/outcomes.md b/docs/src/outcomes.md new file mode 100644 index 0000000..5f1fb99 --- /dev/null +++ b/docs/src/outcomes.md @@ -0,0 +1,121 @@ +# Outcomes + +## Base properties + +These properties apply to all outcome types. + +{{> drop-properties-table properties=outcomes.common }} + +## Item + +- `type=item` + +Drops an item. + +{{> drop-properties-table properties=outcomes.item }} + +## Block + +- `type=block` + +Places a block. + +{{> drop-properties-table properties=outcomes.block }} + +## Entity + +- `type=entity` + +Spawns an entity. + +{{> drop-properties-table properties=outcomes.entity }} + +## Structure + +- `type=structure` + +Generates a structure, which has been [preconfigured](configuration-files#structurestxt). + +{{> drop-properties-table properties=outcomes.structure }} + +## Command + +- `type=command` + +Runs a Minecraft command. + +{{> drop-properties-table properties=outcomes.command }} + +## Difficulty + +- `type=difficulty` + +Sets the difficulty level of the world. This can be used to ensure that monsters spawn. + +{{> drop-properties-table properties=outcomes.difficulty }} + +## Effect + +- `type=effect` + +Gives a status effect to the player and/or surrounding entities. + +{{> drop-properties-table properties=outcomes.effect }} + +### Special effect + +Special effects are non-standard effects added by the mod. + +{{> special-id-table ids=outcomes.special_effect }} + +## Explosion + +- `type=explosion` + +Creates an explosion. + +{{> drop-properties-table properties=outcomes.explosion }} + +## Fill + +- `type=fill` + +Fills an area blocks. + +{{> drop-properties-table properties=outcomes.fill }} + +## Message + +- `type=message` + +Shows a message in the chat. + +{{> drop-properties-table properties=outcomes.message }} + +## Particle + +- `type=particle` + +Creates one or more particles. + +{{> drop-properties-table properties=outcomes.message }} + +### Special particle + +Special particles are particles/animations which exist game by default, but don't have standard IDs. They may also be accompanied by a sound. + +{{> special-id-table ids=outcomes.special_particle }} + +## Sound + +- `type=sound` + +Plays a Minecraft sound. + +{{> drop-properties-table properties=outcomes.sound }} + +## Nothing + +- `type=nothing` + +Does nothing. Mainly used for the Lucky Sword when no additional effect is desired. diff --git a/docs/src/partials/drop-properties-table.html b/docs/src/partials/drop-properties-table.html new file mode 100644 index 0000000..38513ad --- /dev/null +++ b/docs/src/partials/drop-properties-table.html @@ -0,0 +1,53 @@ + + + + + + + + + {{#each properties}} + + + + + + + + {{/each}} + +
NameTypeDefaultDescription/Examples
{{{this.name}}} + {{#if this.minVersion}}≥ v{{this.minVersion}}{{/if}} + {{#if this.maxVersion}}≤ v{{this.maxVersion}}{{/if}} + + +{{{this.type}}} + + + +{{{this.default}}} + + +
+ +{{{this.description}}} + +
+ {{#if this.examples}} +
+ {{#each this.examples}} +
+ {{{this}}} + {{/each}} +
+ {{else if this.example}} +
+
+ {{{this.example}}} +
+ {{/if}} +
+
+ + + diff --git a/docs/src/partials/properties-table.html b/docs/src/partials/properties-table.html new file mode 100644 index 0000000..b1ed286 --- /dev/null +++ b/docs/src/partials/properties-table.html @@ -0,0 +1,40 @@ + + + + + + + + + {{#each properties}} + + + + + + + + {{/each}} + +
NameTypeDefaultDescription
{{{this.name}}} + {{#if this.minVersion}}≥ v{{this.minVersion}}{{/if}} + {{#if this.maxVersion}}≤ v{{this.maxVersion}}{{/if}} + + +{{{this.type}}} + + + +{{{this.default}}} + + +
+ +{{{this.description}}} + +
+
+
+ + + diff --git a/docs/src/partials/special-id-table.html b/docs/src/partials/special-id-table.html new file mode 100644 index 0000000..07f7afa --- /dev/null +++ b/docs/src/partials/special-id-table.html @@ -0,0 +1,43 @@ + + + + + + + + {{#each ids}} + + + + + + + {{/each}} + +
IDExtra ProperiesDescription/Examples
{{{this.id}}} + +
    + {{#each this.extra_args}} +
  • + +{{{this.name}}}: {{{this.type}}} + +
  • + {{/each}} +
+
+
+ +{{{this.description}}} + +
+ {{#if this.example}} +
+
+ {{{this.example}}} +
+ {{/if}} +
+ + + diff --git a/docs/src/partials/template-var-table.html b/docs/src/partials/template-var-table.html new file mode 100644 index 0000000..3fa30e5 --- /dev/null +++ b/docs/src/partials/template-var-table.html @@ -0,0 +1,52 @@ + + + + + + + + {{#each templateVars}} + + + + + + + {{/each}} + +
NameReturn TypeDescription/Examples
+{{#if this.args}} + +{{{this.name}}}(_{{{this.args}}}_) + +{{else}} +{{{this.name}}} +{{/if}} + + +{{{this.return_type}}} + + +
+ +{{{this.description}}} + +
+ {{#if this.examples}} +
+ {{#each this.examples}} +
+ {{{this}}} + {{/each}} +
+ {{else if this.example}} +
+
+ {{{this.example}}} +
+ {{/if}} +
+
+ + + diff --git a/docs/src/property-values.md b/docs/src/property-values.md new file mode 100644 index 0000000..344626a --- /dev/null +++ b/docs/src/property-values.md @@ -0,0 +1,87 @@ +# Property values + +## Value types + +| Type | Examples | Description | +| --------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `integer` | `5`, `-7`, `200` | A positive or negative whole number. | +| `float` | `0.4`, `-180.0`, `-20F` `400f` | A positive or negative floating point number. | +| `true`\|`false` | `true`, `false` | A conditional boolean value. | +| `text` | `lucky:lucky_block`, `"Hi, how are you?"` | A text value. | +| `NBT Tag` | `(title="My Book", pages=["page 1", "page 2"])` | Data in [Minecraft NBT format](https://minecraft.gamepedia.com/NBT_format), specified using [custom syntax](proprty-types#nbt-tags). | + +> Numerical values can include at most one algebraic operation using the symbols `+`, `-`, `*`, `/`, e.g. `posY=#pPosY+10`. + +## Quotes \& backslashes + +When specifying a text value, quotes are usually not be needed. By convention, quotes should not be used for IDs and other one-word properties, but should be used for text containing multiple words. However, quotes are needed when: + +- The value of the text can be interpreted as any other data type, such as a number (e.g. "5"). A +- The text contains any of the following symbols: `, ; ( ) [ ] { }`. + +You can also use a backslash `\` to cancel special symbols, including quotes within quotes. The two examples below are equivalent: + +``` +type=block,ID=lucky:lucky_block,NBTTag=(Drops=["type=message,ID=\"Hello, how are you?\""]) + +type=block,ID=lucky:lucky_block,NBTTag=(Drops=["type=message,ID=Hello\, how are you?"]) +``` + +## Hash variables + +Hash variables allow properties to have dynamic values, which are either random or determined by the current state of the game. + +### Standard variables + +The variables can be used in most places. + +{{> template-var-table templateVars=hash_vars.standard }} + +### NBT variables + +The variables can be used in NBT tags. + +{{> template-var-table templateVars=hash_vars.nbt }} + +### Structure variables + +These variables can only be used within `.luckystruct` structure files. They provide useful information about the context in which the structure is generated. + +{{> template-var-table templateVars=hash_vars.structure }} + +### Cancelling + +> As of version 1.8.0-2, hash variables are automatically cancelled within quotes and `.luckystruct` files. You can disable this behaviour using `[#]`. Previously, you needed to manually cancel the hash using `'#'`. + +In certain cases, such as when using a hash variable in `.luckystruct` structures or in custom NBT tags, you don't want the variable to be evaluated immediately. Instead, you want to preserve it until the outcome is actually performed. + +Fortunately, hash variables will not be evaluated in these cases by default. The example below will place a Lucky Block which, when opened, will spawn a pig above the player at their current location. + +``` +type=block,ID=lucky:lucky_block,NBTTag=(Drops=["type=entity,ID=Pig,posY=#pPosY+10"]) +``` + +This behaviour can be disabled using `[#]`. The example below will spawn the pig above the location the player was in when opening the first block. + +``` +type=block,ID=lucky:lucky_block,NBTTag=(Drops=["type=entity,ID=Pig,posY=[#]pPosY+10"]) +``` + +## NBT Tags + +NBT tags are used for storing additional properties for items, blocks, entities, etc. When used in outcomes, the custom syntax is as follows: + +| Tag type | Format | Example | +| ------------ | ------------------------------------------ | ---------------------------------- | +| `string` | `name="value"` | `Name="Special Item"` | +| `int` | `name=integer` | `lvl=3` | +| `boolean` | `name={true,false}` | `sparke=true` | +| `float` | `name={float}F` | `size=3.29F` | +| `double` | `name={double}D` \| `name=integer.integer` | `size=2D` \| `size=2.0` | +| `byte` | `name={byte}D` | `length=3B` | +| `short` | `name={short}S` | `length=523S` | +| `long` | `name={long}L` | `length=2876439L` | +| `int_array` | `name=integer:integer:...` | `nums=372:35:97` | +| `byte_array` | `name={byte}B:{byte}B:...` | `nums=6B:4B:8B` | +| `compound` | `name=(name=value,name=value,...)` | `tag=(id="diamond_sword",count=2)` | +| `list` | `name=[value,value,...]` | `Motion=[2.5,1.9,3.0]` | diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 0000000..71c8a99 --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "moduleResolution": "node", + "strict": true + } +}