From 5198e698160483fcc2aaacb508cee63501d546a2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 18 May 2024 05:57:50 +0300 Subject: [PATCH 001/107] fix: correctly display item names in inventory GUI fix: fix opening nested inventory GUI on servers! --- README.MD | 4 ++++ src/globalState.ts | 6 +++--- src/inventoryWindows.ts | 27 +++++++++++++++++++++------ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/README.MD b/README.MD index ce368540..225cdda2 100644 --- a/README.MD +++ b/README.MD @@ -126,3 +126,7 @@ Press `Y` to set query parameters to url of your current game state. - [Minecraft Protocol](https://github.com/PrismarineJS/node-minecraft-protocol) - Makes connections to servers possible - [Peer.js](https://peerjs.com/) - P2P networking (when you open to wan) - [Three.js](https://threejs.org/) - Helping in 3D rendering + +### Alternatives + +- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [https://www.classicube.net/](https://www.classicube.net/server/play/?warned=true) diff --git a/src/globalState.ts b/src/globalState.ts index 1b0526f9..4b62f8d6 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -8,7 +8,7 @@ import type { OptionsGroupType } from './optionsGuiScheme' const notHideableModalsWithoutForce = new Set(['app-status']) -type Modal = ({ elem?: HTMLElement & Record } & { reactType?: string }) +type Modal = ({ elem?: HTMLElement & Record } & { reactType: string }) type ContextMenuItem = { callback; label } @@ -57,7 +57,7 @@ const showModalInner = (modal: Modal) => { } export const showModal = (elem: /* (HTMLElement & Record) | */{ reactType: string }) => { - const resolved = elem instanceof HTMLElement ? { elem: ref(elem) } : elem + const resolved = elem const curModal = activeModalStack.at(-1) if (/* elem === curModal?.elem || */(elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return if (curModal) defaultModalActions.hide(curModal) @@ -123,7 +123,7 @@ export type AppConfig = { defaultProxy?: string // defaultProxySave?: string // defaultVersion?: string - promoteServers?: Array<{ip, description, version?}> + promoteServers?: Array<{ ip, description, version?}> mapsProvider?: string } diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index d9fda1c7..d87d4008 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -123,6 +123,11 @@ export const onGameLoad = (onLoad) => { // todo hide up to the window itself! hideCurrentModal() }) + bot.on('respawn', () => { // todo validate logic against native client (maybe login) + if (lastWindow) { + hideCurrentModal() + } + }) customEvents.on('search', (q) => { if (!lastWindow) return @@ -316,10 +321,10 @@ export const getItemNameRaw = (item: Pick const getItemName = (slot: Item | null) => { const parsed = getItemNameRaw(slot) - if (!parsed || parsed['extra']) return + if (!parsed) return // todo display full text renderer from sign renderer const text = flat(parsed as MessageFormatPart).map(x => x.text) - return text + return text.join('') } export const renderSlotExternal = (slot) => { @@ -362,12 +367,15 @@ export const onModalClose = (callback: () => any) => { callback() unsubscribe() } - }) + }, true) } const implementedContainersGuiMap = { // todo allow arbitrary size instead! + 'minecraft:generic_9x1': 'ChestWin', + 'minecraft:generic_9x2': 'ChestWin', 'minecraft:generic_9x3': 'ChestWin', + 'minecraft:generic_9x4': 'Generic95Win', 'minecraft:generic_9x5': 'Generic95Win', // hopper 'minecraft:generic_5x1': 'HopperWin', @@ -401,22 +409,29 @@ export const openItemsCanvas = (type, _bot = bot as typeof bot | null) => { return inv } +let skipClosePacketSending = false const openWindow = (type: string | undefined) => { // if (activeModalStack.some(x => x.reactType?.includes?.('player_win:'))) { if (activeModalStack.length) { // game is not in foreground, don't close current modal - if (type) bot.currentWindow?.['close']() - return + if (type) { + skipClosePacketSending = true + hideCurrentModal() + } else { + bot.currentWindow?.['close']() + return + } } showModal({ reactType: `player_win:${type}`, }) onModalClose(() => { // might be already closed (event fired) - if (type !== undefined && bot.currentWindow) bot.currentWindow['close']() + if (type !== undefined && bot.currentWindow && !skipClosePacketSending) bot.currentWindow['close']() lastWindow.destroy() lastWindow = null as any miscUiState.displaySearchInput = false destroyFn() + skipClosePacketSending = false }) cleanLoadedImagesCache() const inv = openItemsCanvas(type) From 6375df15763c0bae6eb36a59801be43f6ad27384 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 18 May 2024 22:24:52 +0300 Subject: [PATCH 002/107] improve readme clarity --- README.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 225cdda2..af966101 100644 --- a/README.MD +++ b/README.MD @@ -120,7 +120,7 @@ Press `Y` to set query parameters to url of your current game state. ### Notable Things that Power this Project - [Mineflayer](https://github.com/PrismarineJS/mineflayer) - Handles all client-side communications with the server (including the builtin one) - forked -- [Flying Squid](https://github.com/prismarineJS/flying-squid) - The builtin server that makes single player possible! Here forked version is used. +- [Forked Flying Squid (Space Squid)](https://github.com/zardoy/space-squid) - The builtin offline server that makes single player & P2P possible! - [Prismarine Provider Anvil](https://github.com/PrismarineJS/prismarine-provider-anvil) - Handles world loading (region format) - [Prismarine Physics](https://github.com/PrismarineJS/prismarine-physics) - Does all the physics calculations - [Minecraft Protocol](https://github.com/PrismarineJS/node-minecraft-protocol) - Makes connections to servers possible @@ -129,4 +129,4 @@ Press `Y` to set query parameters to url of your current game state. ### Alternatives -- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [https://www.classicube.net/](https://www.classicube.net/server/play/?warned=true) +- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true) From 6bf1085fbe422b3e926fcb89e29da70ea2804c8d Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Sat, 18 May 2024 23:51:35 +0400 Subject: [PATCH 003/107] feat: Key binds screen (#108) --------- Co-authored-by: gguio Co-authored-by: Vitaly --- esbuild.mjs | 1 + package.json | 2 +- pnpm-lock.yaml | 10 +- src/controls.ts | 28 +- ...tation_console_controller_gamepad_icon.svg | 1 + src/customCommands.ts | 91 ++++ src/optionsGuiScheme.tsx | 23 +- src/react/KeybindingsCustom.tsx | 171 ++++++++ src/react/KeybindingsScreen.module.css | 88 ++++ src/react/KeybindingsScreen.tsx | 388 +++++++++++++++++- src/react/KeybindingsScreenApp.tsx | 51 --- src/react/KeybindingsScreenProvider.tsx | 50 +++ src/react/OptionsGroup.tsx | 2 +- src/react/globals.d.ts | 4 + ...tation_console_controller_gamepad_icon.svg | 1 + ...tation_console_controller_gamepad_icon.svg | 1 + ...square_console_controller_gamepad_icon.svg | 1 + ...iangle_console_controller_gamepad_icon.svg | 1 + src/react/storageProvider.ts | 13 + src/reactUi.tsx | 2 + src/screens.css | 1 + 21 files changed, 858 insertions(+), 72 deletions(-) create mode 100644 src/cross_playstation_console_controller_gamepad_icon.svg create mode 100644 src/customCommands.ts create mode 100644 src/react/KeybindingsCustom.tsx create mode 100644 src/react/KeybindingsScreen.module.css delete mode 100644 src/react/KeybindingsScreenApp.tsx create mode 100644 src/react/KeybindingsScreenProvider.tsx create mode 100644 src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg create mode 100644 src/react/storageProvider.ts diff --git a/esbuild.mjs b/esbuild.mjs index 1e8d6478..d68693d8 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -79,6 +79,7 @@ const buildOptions = { loader: { // todo use external or resolve issues with duplicating '.png': 'dataurl', + '.svg': 'dataurl', '.map': 'empty', '.vert': 'text', '.frag': 'text', diff --git a/package.json b/package.json index 4bbeaf81..6905a8b7 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.6", + "contro-max": "^0.1.7", "crypto-browserify": "^3.12.0", "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index beb0c0a9..dcacb13a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.6 - version: 0.1.6(typescript@5.5.0-beta) + specifier: ^0.1.7 + version: 0.1.7(typescript@5.5.0-beta) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -3811,8 +3811,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - contro-max@0.1.6: - resolution: {integrity: sha512-QsoOcAlbtNgkCGBvwKsh+GUVZ2c5zfMgYQCu+v4MplX5VolkWhMwAcEOBRxt8oENbnRXOKUGQr816Ey1G4/jpg==} + contro-max@0.1.7: + resolution: {integrity: sha512-HIYF1Dl50tUyTKaDsX+mPMDv2OjleNMVedYuBTX0n1wKNm9WxjWu2w74ATjz/8fHVL9GgmziIxAlFStd2je6kg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} convert-source-map@1.9.0: @@ -12851,7 +12851,7 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.6(typescript@5.5.0-beta): + contro-max@0.1.7(typescript@5.5.0-beta): dependencies: events: 3.3.0 lodash-es: 4.17.21 diff --git a/src/controls.ts b/src/controls.ts index 6dd47be2..6e38b90c 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -6,21 +6,24 @@ import { proxy, subscribe } from 'valtio' import { ControMax } from 'contro-max/build/controMax' import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types' import { stringStartsWith } from 'contro-max/build/stringUtils' +import { UserOverridesConfig } from 'contro-max/build/types/store' import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' import { openPlayerInventory } from './inventoryWindows' import { chatInputValueGlobal } from './react/Chat' import { fsState } from './loadSave' +import { customCommandsConfig } from './customCommands' +import { CustomCommand } from './react/KeybindingsCustom' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' -// todo move this to shared file with component -export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) + +export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig subscribe(customKeymaps, () => { - localStorage.keymap = JSON.parse(customKeymaps) + localStorage.keymap = JSON.stringify(customKeymaps) }) const controlOptions = { @@ -53,7 +56,8 @@ export const contro = new ControMax({ }, advanced: { lockUrl: ['KeyY'], - } + }, + custom: {} as Record, // waila: { // showLookingBlockRecipe: ['Numpad3'], // showLookingBlockUsages: ['Numpad4'] @@ -81,6 +85,8 @@ export const contro = new ControMax({ window.controMax = contro export type Command = CommandEventArgument['command'] +// updateCustomBinds() + export const setDoPreventDefault = (state: boolean) => { controlOptions.preventDefault = state } @@ -285,6 +291,20 @@ function cycleHotbarSlot (dir: 1 | -1) { bot.setQuickBarSlot(newHotbarSlot) } +// custom commands hamdler +const customCommandsHandler = (buttonData: { code?: string, button?: string, state: boolean }) => { + if (!buttonData.state || !isGameActive(true)) return + + const codeOrButton = buttonData.code ?? buttonData.button + const inputType = buttonData.code ? 'keys' : 'gamepad' + for (const value of Object.values(contro.userConfig!.custom)) { + if (value[inputType]?.includes(codeOrButton!)) { + customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) + } + } +} +contro.on('pressedKeyOrButtonChanged', customCommandsHandler) + contro.on('trigger', ({ command }) => { const willContinue = !isGameActive(true) alwaysPressedHandledCommand(command) diff --git a/src/cross_playstation_console_controller_gamepad_icon.svg b/src/cross_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d7d176e2 --- /dev/null +++ b/src/cross_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/customCommands.ts b/src/customCommands.ts new file mode 100644 index 00000000..eddfc89e --- /dev/null +++ b/src/customCommands.ts @@ -0,0 +1,91 @@ +import { guiOptionsScheme, tryFindOptionConfig } from './optionsGuiScheme' +import { options } from './optionsStorage' + +export const customCommandsConfig = { + chat: { + input: [ + { + type: 'text', + placeholder: 'Command to send e.g. gamemode creative' + } + ], + handler ([command]) { + bot.chat(`/${command.replace(/^\//, '')}`) + } + }, + setOrToggleSetting: { + input: [ + { + type: 'select', + // maybe title case? + options: Object.keys(options) + }, + { + type: 'select', + options: ['toggle', 'set'] + }, + ([setting = '', action = ''] = []) => { + const value = options[setting] + if (!action || value === undefined || action === 'toggle') return null + if (action === 'set') { + const getBase = () => { + const config = tryFindOptionConfig(setting as any) + if (config && 'values' in config) { + return { + type: 'select', + options: config.values + } + } + if (config?.type === 'toggle' || typeof value === 'boolean') { + return { + type: 'select', + options: ['true', 'false'] + } + } + if (config?.type === 'slider' || value.type === 'number') { + return { + type: 'number', + } + } + return { + type: 'text' + } + } + return { + ...getBase(), + placeholder: value + } + } + } + ], + handler ([setting, action, value]) { + if (action === 'toggle') { + const value = options[setting] + const config = tryFindOptionConfig(setting) + if (config && 'values' in config && config.values) { + const { values } = config + const currentIndex = values.indexOf(value) + const nextIndex = (currentIndex + 1) % values.length + options[setting] = values[nextIndex] + } else { + options[setting] = typeof value === 'boolean' ? !value : typeof value === 'number' ? value + 1 : value + } + } else { + options[setting] = value + } + } + }, + jsScripts: { + input: [ + { + type: 'text', + placeholder: 'JavaScript code to run in main thread (sensitive!)' + } + ], + handler ([code]) { + // eslint-disable-next-line no-new-func -- this is a feature, not a bug + new Function(code)() + } + }, + // openCommandsScreen: {} +} diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 1c92a39c..b847fe11 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -184,7 +184,16 @@ export const guiOptionsScheme: { custom () { return Keyboard & Mouse }, - // keybindings + }, + { + custom () { + return + }, mouseSensX: {}, mouseSensY: { min: -1, @@ -282,3 +291,15 @@ const Category = ({ children }) =>
{children}
+ +export const tryFindOptionConfig = (option: keyof AppOptions) => { + for (const group of Object.values(guiOptionsScheme)) { + for (const optionConfig of group) { + if (option in optionConfig) { + return optionConfig[option] + } + } + } + + return null +} diff --git a/src/react/KeybindingsCustom.tsx b/src/react/KeybindingsCustom.tsx new file mode 100644 index 00000000..bee991bf --- /dev/null +++ b/src/react/KeybindingsCustom.tsx @@ -0,0 +1,171 @@ +import { useEffect, useState, useContext } from 'react' +import { customCommandsConfig } from '../customCommands' +import { ButtonWithMatchesAlert, Context } from './KeybindingsScreen' +import Button from './Button' +import styles from './KeybindingsScreen.module.css' +import Input from './Input' + + +export type CustomCommand = { + keys: undefined | string[] + gamepad: undefined | string[] + type: string + inputs: any[] +} + +export type CustomCommandsMap = Record + +export default ( + { + customCommands, + updateCurrBind, + resetBinding, + }: { + customCommands: CustomCommandsMap, + updateCurrBind: (group: string, action: string) => void, + resetBinding: (group: string, action: string, inputType: string) => void, + } +) => { + const { userConfig, setUserConfig } = useContext(Context) + const [customConfig, setCustomConfig] = useState({ ...customCommands }) + + useEffect(() => { + setUserConfig({ ...userConfig, custom: { ...customConfig } }) + }, [customConfig]) + + const addNewCommand = (type: string) => { + // max key + 1 + const newKey = String(Math.max(...Object.keys(customConfig).map(Number).filter(key => !isNaN(key)), 0) + 1) + setCustomConfig(prev => { + const newCustomConf = { ...prev } + newCustomConf[newKey] = { + keys: undefined as string[] | undefined, + gamepad: undefined as string[] | undefined, + type, + inputs: [] as any[] + } + return newCustomConf + }) + } + + return <> +
+ {Object.entries(customCommandsConfig).map(([group, { input }]) => ( +
+
{group}
+ {Object.entries(customConfig).filter(([key, data]) => data.type === group).map((commandData, indexOption) => { + return + })} +
+ ))} +
+ +} + +const CustomCommandContainer = ( + { + indexOption, + commandData, + updateCurrBind, + setCustomConfig, + resetBinding, + groupData + } +) => { + const { userConfig } = useContext(Context) + + const [commandKey, { keys, gamepad, inputs }] = commandData + const [group, { input }] = groupData + + const setInputValue = (optionKey, indexInput, value) => { + setCustomConfig(prev => { + const newConfig = { ...prev } + newConfig[optionKey].inputs = [...prev[optionKey].inputs] + newConfig[optionKey].inputs[indexInput] = value + return newConfig + }) + } + + return
+ {input.map((obj, indexInput) => { + const config = typeof obj === 'function' ? obj(inputs) : obj + if (!config) return null + + return config.type === 'select' + ? + : setInputValue(commandKey, indexInput, e.target.value)} /> + })} +
+ { + userConfig?.['custom']?.[commandKey]?.keys ?
+
+} diff --git a/src/react/KeybindingsScreen.module.css b/src/react/KeybindingsScreen.module.css new file mode 100644 index 00000000..e8a9f69b --- /dev/null +++ b/src/react/KeybindingsScreen.module.css @@ -0,0 +1,88 @@ +.container { + overflow-x: auto; + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; +} + +@media (max-width: 590px) { + .container { + width: 90vw; + } +} + +.group { + display: flex; + flex-direction: column; + gap: 5px; +} + +.group-category { + font-size: 1rem; + text-align: center; + margin-top: 15px; + margin-bottom: 7px; + text-transform: capitalize; +} + +.actionBinds { + position: relative; + display: flex; +} + +.warning-container { + flex-basis: 25%; + display: flex; + flex-direction: column; + height: inherit; +} + +.actionName { + flex-basis: 30%; + margin-right: 5px; + flex-wrap: wrap; + align-self: center; + font-size: 10px; +} + +.undo-keyboard, +.undo-gamepad { + aspect-ratio: 1; +} + +.button { + width: 100%; + font-size: 7px; +} + +.margin-left { + margin-left: 25px; +} + +.matched-bind { + border: 1px solid red; + border-bottom: 1px solid red; +} + +.matched-bind-warning { + display: flex; + color: yellow; + font-family: inherit; + font-size: 5px; + width: fit-content; +} + +.matched-bind-warning a { + color: inherit; +} + +/* ~~~~ custom bindings styles */ + +.chat-command { + font: inherit; + color: white; + display: block; + height: 100%; + flex-grow: 1; +} diff --git a/src/react/KeybindingsScreen.tsx b/src/react/KeybindingsScreen.tsx index 19038a71..97126655 100644 --- a/src/react/KeybindingsScreen.tsx +++ b/src/react/KeybindingsScreen.tsx @@ -1,12 +1,382 @@ +import { useState, useEffect, useRef, createContext, useContext } from 'react' +import { UserOverridesConfig } from 'contro-max/build/types/store' +import { contro as controEx } from '../controls' +import { hideModal } from '../globalState' +import triangle from './ps_icons/playstation_triangle_console_controller_gamepad_icon.svg' +import square from './ps_icons/playstation_square_console_controller_gamepad_icon.svg' +import circle from './ps_icons/circle_playstation_console_controller_gamepad_icon.svg' +import cross from './ps_icons/cross_playstation_console_controller_gamepad_icon.svg' +import PixelartIcon from './PixelartIcon' +import KeybindingsCustom, { CustomCommandsMap } from './KeybindingsCustom' +import { BindingActionsContext } from './KeybindingsScreenProvider' +import Button from './Button' import Screen from './Screen' +import styles from './KeybindingsScreen.module.css' -export default ({ - onBack, - onReset, - onSet, - keybindings -}) => { - return -

Here you can change the keybindings for the game.

-
+ +type HandleClick = (group: string, action: string, index: number, type: string | null) => void + +type setBinding = (data: any, group: string, command: string, buttonIndex: number) => void + +export const Context = createContext( + { + isPS: false as boolean | undefined, + userConfig: controEx?.userConfig ?? {} as UserOverridesConfig | undefined, + setUserConfig (config) { }, + handleClick: (() => { }) as HandleClick, + parseBindingName (binding) { return '' as string }, + bindsMap: { keyboard: {} as any, gamepad: {} as any } + } +) + +export default ( + { + contro, + isPS, + }: { + contro: typeof controEx, + isPS?: boolean + } +) => { + const containerRef = useRef(null) + const bindsMap = useRef({ keyboard: {} as any, gamepad: {} as any }) + const { commands } = contro.inputSchema + const [userConfig, setUserConfig] = useState(contro.userConfig ?? {}) + const [awaitingInputType, setAwaitingInputType] = useState(null as null | 'keyboard' | 'gamepad') + const [groupName, setGroupName] = useState('') + const [actionName, setActionName] = useState('') + const [buttonNum, setButtonNum] = useState(0) + const { updateBinds } = useContext(BindingActionsContext) + const [customCommands, setCustomCommands] = useState(userConfig.custom as CustomCommandsMap ?? {}) + + const updateCurrBind = (group: string, action: string) => { + setGroupName(prev => group) + setActionName(prev => action) + } + + const handleClick: HandleClick = (group, action, index, type) => { + //@ts-expect-error + setAwaitingInputType(type) + updateCurrBind(group, action) + setButtonNum(prev => index) + } + + const setBinding: setBinding = (data, group, command, buttonIndex) => { + setUserConfig(prev => { + const newConfig = { ...prev } + newConfig[group] ??= {} + newConfig[group][command] ??= {} + + // keys and buttons should always exist in commands + const type = 'code' in data ? 'keys' : 'button' in data ? 'gamepad' : null + if (type) { + newConfig[group][command][type] ??= group === 'custom' ? [] : [...contro.inputSchema.commands[group][command][type]] + newConfig[group][command][type]![buttonIndex] = data.code ?? data.button + } + + return newConfig + }) + } + + const resetBinding = (group: string, command: string, inputType: string) => { + if (!userConfig?.[group]?.[command]) return + + setUserConfig(prev => { + const newConfig = { ...prev } + const prop = inputType === 'keyboard' ? 'keys' : 'gamepad' + newConfig[group][command][prop] = undefined + return newConfig + }) + } + + useEffect(() => { + updateBinds(userConfig) + setCustomCommands({ ...userConfig.custom as CustomCommandsMap }) + + updateBindMap() + }, [userConfig]) + + // const updateKeyboardBinding = (e: import('react').KeyboardEvent) => { + // if (!e.code || e.key === 'Escape' || !awaitingInputType) return + // setBinding({ code: e.code, state: true }, groupName, actionName, buttonNum) + // } + + const updateBinding = (data: any) => { + if ((!data.state && awaitingInputType) || !awaitingInputType) { + setAwaitingInputType(null) + return + } + if ('code' in data) { + if (data.code === 'Escape' || ['Mouse0', 'Mouse1', 'Mouse2'].includes(data.code)) { + setAwaitingInputType(null) + return + } + setBinding({ code: data.code, state: true }, groupName, actionName, buttonNum) + } + if ('button' in data) { + contro.enabled = false + void Promise.resolve().then(() => { contro.enabled = true }) + setBinding(data, groupName, actionName, buttonNum) + } + + setAwaitingInputType(null) + } + + const updateBindMap = () => { + bindsMap.current = { keyboard: {} as any, gamepad: {} as any } + if (commands) { + for (const [group, actions] of Object.entries(commands)) { + for (const [action, { keys, gamepad }] of Object.entries(actions)) { + if (keys) { + let currKeys + if (userConfig?.[group]?.[action]?.keys) { + currKeys = userConfig[group][action].keys + } else { + currKeys = keys + } + for (const [index, key] of currKeys.entries()) { + bindsMap.current.keyboard[key] ??= [] + if (!bindsMap.current.keyboard[key].some(obj => obj.group === group && obj.action === action && obj.index === index)) { + bindsMap.current.keyboard[key].push({ group, action, index }) + } + } + } + if (gamepad) { + let currButtons + if (userConfig?.[group]?.[action]?.gamepad) { + currButtons = userConfig[group][action].gamepad + } else { + currButtons = gamepad + } + if (currButtons.length > 0) { + bindsMap.current.gamepad[currButtons[0]] ??= [] + bindsMap.current.gamepad[currButtons[0]].push({ group, action, index: 0 }) + } + } + } + } + } + } + + // fill binds map + useEffect(() => { + updateBindMap() + }, []) + + useEffect(() => { + contro.on('pressedKeyOrButtonChanged', updateBinding) + + return () => { + contro.off('pressedKeyOrButtonChanged', updateBinding) + } + }, [groupName, actionName, awaitingInputType]) + + + return + + {awaitingInputType && } +
+ + + {Object.entries(commands).map(([group, actions], index) => { + if (group === 'custom') return null + return
+
{group}
+ {group === 'general' ? ( +
+ Note: Left, right and middle click keybindings are hardcoded and cannot be changed currently. +
+ ) : null} + {Object.entries(actions).map(([action, { keys, gamepad }]) => { + return
+
{parseActionName(action)}
+ +
+ })} +
+ })} + + +
+
+
+} + +export const ButtonWithMatchesAlert = ({ + group, + action, + index, + inputType, + keys, + gamepad, +}) => { + const { isPS, userConfig, handleClick, parseBindingName, bindsMap } = useContext(Context) + const [buttonSign, setButtonSign] = useState('') + + useEffect(() => { + const type = inputType === 'keyboard' ? 'keys' : 'gamepad' + + const customValue = userConfig?.[group]?.[action]?.[type]?.[index] + if (customValue) { + if (type === 'keys') { + setButtonSign(parseBindingName(customValue)) + } else { + setButtonSign(isPS && buttonsMap[customValue] ? buttonsMap[customValue] : customValue) + } + } else if (type === 'keys') { + setButtonSign(keys?.length ? parseBindingName(keys[index]) : '') + } else { + setButtonSign(gamepad?.[0] ? + isPS ? + buttonsMap[gamepad[0]] ?? gamepad[0] + : gamepad[0] + : '') + } + }, [userConfig, isPS]) + + return
+ + {userConfig?.[group]?.[action]?.[inputType === 'keyboard' ? 'keys' : 'gamepad']?.some( + key => Object.keys(bindsMap[inputType]).includes(key) + && bindsMap[inputType][key].length > 1 + && bindsMap[inputType][key].some( + prop => prop.index === index + && prop.group === group + && prop.action === action + ) + ) ? ( +
+ +
+ This bind is already in use. +
+
+ ) : null} +
+} + +export const AwaitingInputOverlay = ({ isGamepad }) => { + return
+
+ {isGamepad ? 'Press the button on the gamepad ' : 'Press the key, side mouse button '} + or ESC to cancel. +
+ +
+} + +const parseActionName = (action: string) => { + const parts = action.split(/(?=[A-Z])/) + parts[0] = parts[0].charAt(0).toUpperCase() + parts[0].slice(1) + return parts.join(' ') +} + +const parseBindingName = (binding: string | undefined) => { + if (!binding) return '' + const cut = binding.replaceAll(/(Numpad|Digit|Key)/g, '') + const parts = cut.split(/(?=[A-Z\d])/) + return parts.reverse().join(' ') +} + +const buttonsMap = { + 'A': cross, + 'B': circle, + 'X': square, + 'Y': triangle } diff --git a/src/react/KeybindingsScreenApp.tsx b/src/react/KeybindingsScreenApp.tsx deleted file mode 100644 index e0630eab..00000000 --- a/src/react/KeybindingsScreenApp.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useState } from 'react' -import { contro } from '../controls' -import Button from './Button' -import Screen from './Screen' - -export default () => { - const { commands } = contro.inputSchema - const [awaitingInputType, setAwaitingInputType] = useState(null as null | 'keyboard' | 'gamepad') - - // const - - return - {awaitingInputType && } -

Here you can change the keybindings for the game.

-
- {Object.entries(commands).map(([group, actions]) => { - return
-

{group}

- {Object.entries(actions).map(([action, { keys, gamepadButtons }]) => { - return
- - -
- })} -
- })} -
-
-} - -const AwaitingInputOverlay = ({ isGamepad }) => { - return
- {isGamepad ? 'Press the button on the gamepad' : 'Press the key'}. - Press ESC to cancel. -
-} diff --git a/src/react/KeybindingsScreenProvider.tsx b/src/react/KeybindingsScreenProvider.tsx new file mode 100644 index 00000000..97f04a62 --- /dev/null +++ b/src/react/KeybindingsScreenProvider.tsx @@ -0,0 +1,50 @@ +import { createContext, useState } from 'react' +import { contro } from '../controls' +import KeybindingsScreen from './KeybindingsScreen' +import { useIsModalActive } from './utilsApp' + + +export const updateBinds = (commands: any) => { + contro.inputSchema.commands.custom = Object.fromEntries(Object.entries(commands?.custom ?? {}).map(([key, value]) => { + return [key, { + keys: [], + gamepad: [], + type: '', + inputs: [] + }] + })) + + for (const [group, actions] of Object.entries(commands)) { + contro.userConfig![group] = Object.fromEntries(Object.entries(actions).map(([key, value]) => { + const newValue = { + keys: value?.keys ?? undefined, + gamepad: value?.gamepad ?? undefined, + } + + if (group === 'custom') { + newValue['type'] = (value).type + newValue['inputs'] = (value).inputs + } + + return [key, newValue] + })) + } +} + +const bindingActions = { + updateBinds +} + +export const BindingActionsContext = createContext(bindingActions) + +export default () => { + const [bindActions, setBindActions] = useState(bindingActions) + const isModalActive = useIsModalActive('keybindings') + + if (!isModalActive) return null + + const hasPsGamepad = [...(navigator.getGamepads?.() ?? [])].some(gp => gp?.id.match(/playstation|dualsense|dualshock/i)) // todo: use last used gamepad detection + return + + +} diff --git a/src/react/OptionsGroup.tsx b/src/react/OptionsGroup.tsx index bbfac00e..81df531b 100644 --- a/src/react/OptionsGroup.tsx +++ b/src/react/OptionsGroup.tsx @@ -3,7 +3,7 @@ import { options } from '../optionsStorage' import { OptionsGroupType, guiOptionsScheme } from '../optionsGuiScheme' import OptionsItems, { OptionMeta } from './OptionsItems' -const optionValueToType = (optionValue: any, item: OptionMeta) => { +export const optionValueToType = (optionValue: any, item: OptionMeta) => { if (typeof optionValue === 'boolean' || item.values) return 'toggle' if (typeof optionValue === 'number') return 'slider' if (typeof optionValue === 'string') return 'element' diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts index 842d27c4..108fae54 100644 --- a/src/react/globals.d.ts +++ b/src/react/globals.d.ts @@ -25,6 +25,10 @@ declare module '*.png' { const png: string export default png } +declare module '*.svg' { + const svg: string + export default svg +} interface PromiseConstructor { withResolvers (): { diff --git a/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg b/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d49af336 --- /dev/null +++ b/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg b/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d7d176e2 --- /dev/null +++ b/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg b/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..9f08790e --- /dev/null +++ b/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg b/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..a397c517 --- /dev/null +++ b/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/storageProvider.ts b/src/react/storageProvider.ts new file mode 100644 index 00000000..df97d228 --- /dev/null +++ b/src/react/storageProvider.ts @@ -0,0 +1,13 @@ +import { CustomCommand } from './KeybindingsCustom' + +type StorageData = { + customCommands: Record + // ... +} + +export const getStoredValue = (name: T): StorageData[T] | undefined => { + return localStorage[name] ? JSON.parse(localStorage[name]) : undefined +} +export const setStoredValue = (name: T, value: StorageData[T]) => { + localStorage[name] = JSON.stringify(value) +} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 9a79de34..e384fbfd 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -36,6 +36,7 @@ import Crosshair from './react/Crosshair' import ButtonAppProvider from './react/ButtonAppProvider' import ServersListProvider from './react/ServersListProvider' import GamepadUiCursor from './react/GamepadUiCursor' +import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' const RobustPortal = ({ children, to }) => { @@ -157,6 +158,7 @@ const App = () => { + diff --git a/src/screens.css b/src/screens.css index c4e7fe9b..32765506 100644 --- a/src/screens.css +++ b/src/screens.css @@ -33,6 +33,7 @@ margin-top: 35px; /* todo remove it but without it in chrome android the screen is not scrollable */ overflow: auto; + height: fit-content; /* todo I'm not sure about it */ /* margin-top: calc(100% / 6 - 16px); */ align-items: center; From 97ca34e8f93002d6e54e2c842d13cd4d7cd3ee0e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 19 May 2024 15:32:50 +0300 Subject: [PATCH 004/107] hotfix: input handler crash --- src/controls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index 6e38b90c..7d1e4cdf 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -297,7 +297,7 @@ const customCommandsHandler = (buttonData: { code?: string, button?: string, sta const codeOrButton = buttonData.code ?? buttonData.button const inputType = buttonData.code ? 'keys' : 'gamepad' - for (const value of Object.values(contro.userConfig!.custom)) { + for (const value of Object.values(contro.userConfig!.custom ?? {})) { if (value[inputType]?.includes(codeOrButton!)) { customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) } From 2bec255b7da0c9142c606cc3c0d9a93fd8cc4cba Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 05:47:38 +0300 Subject: [PATCH 005/107] fix: update flying-squid to respect time in saves! --- package.json | 2 +- pnpm-lock.yaml | 36 +++++-------------- .../viewer/lib/worldDataEmitter.ts | 1 + 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 6905a8b7..6e73b981 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.20", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.24", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcacb13a..6d784e17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.20 - version: '@zardoy/flying-squid@0.0.20(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.24 + version: '@zardoy/flying-squid@0.0.24(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.20': - resolution: {integrity: sha512-WyejZS2Upzv86g6Ez5Z/4Pd0ea9tkFL2itAj24UNpO7fyzxuTN2Ag1Ouvh+MSkCloXhR4E/yoER2krHW8vzwBw==} + '@zardoy/flying-squid@0.0.24': + resolution: {integrity: sha512-C+VNHyh9yYB7aG9OL6r9NR5bF73fyRQ0rHhkvvz901hLBZI3+5nOPdcA6XwJm9XX9BYStXbLTHp6shmo20JRHQ==} engines: {node: '>=8'} hasBin: true @@ -3274,9 +3274,6 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - asap@1.0.0: - resolution: {integrity: sha512-Ej9qjcXY+8Tuy1cNqiwNMwFRXOy9UwgTeMA8LxreodygIPV48lx8PU1ecFxb5ZeU1DpMKxiq6vGLTxcitWZPbA==} - asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} @@ -4551,9 +4548,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - event-promise@0.0.1: - resolution: {integrity: sha512-ouEmk2N0BalybPM0zmj3RHE93AX4p9hAIHZfbbqxolLChqCB6pcLDbYH6zZ8TaiFWImPHfs5kFnNpA0u9RdEaQ==} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -6801,9 +6795,6 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - promise@5.0.0: - resolution: {integrity: sha512-N2BfLz0Sigf7rsm5NnItRwTNqEDUF2ephwEXTcOAf2cO9NwZ9TnIjOmnQNtC0r70CV0S1+uc9mSMmFH7gxk87Q==} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -11443,8 +11434,7 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.10 - '@tootallnate/once@2.0.0': - optional: true + '@tootallnate/once@2.0.0': {} '@tweenjs/tween.js@18.6.4': {} @@ -11935,18 +11925,18 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.20(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.24(encoding@0.1.13)': dependencies: + '@tootallnate/once': 2.0.0 change-case: 4.1.2 colors: 1.4.0 diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687 emit-then: 2.0.0 - event-promise: 0.0.1 exit-hook: 2.2.1 flatmap: 0.0.3 long: 5.2.3 minecraft-data: 3.65.0 - minecraft-protocol: 1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 @@ -12212,8 +12202,6 @@ snapshots: arrify@1.0.1: {} - asap@1.0.0: {} - asn1.js@5.4.1: dependencies: bn.js: 4.12.0 @@ -13950,10 +13938,6 @@ snapshots: etag@1.8.1: {} - event-promise@0.0.1: - dependencies: - promise: 5.0.0 - event-target-shim@5.0.1: {} eventemitter2@6.4.7: {} @@ -16638,10 +16622,6 @@ snapshots: retry: 0.12.0 optional: true - promise@5.0.0: - dependencies: - asap: 1.0.0 - prompts@2.4.2: dependencies: kleur: 3.0.3 diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index f4ce9675..40cc3413 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -87,6 +87,7 @@ export class WorldDataEmitter extends EventEmitter { }, })) this.emitter.emit('renderDistance', this.viewDistance) + this.emitter.emit('time', bot.time.timeOfDay) }) // node.js stream data event pattern if (this.emitter.listenerCount('blockEntities')) { From 5e9423909167090b244b26b4493d8a6336d4751c Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 05:47:53 +0300 Subject: [PATCH 006/107] feat: big fix: rendering blocks for preflat versions (<1.13)! (#125) --- prismarine-viewer/buildMesherWorker.mjs | 2 + prismarine-viewer/viewer/lib/mesher/mesher.ts | 1 + prismarine-viewer/viewer/lib/mesher/models.ts | 76 +- prismarine-viewer/viewer/lib/mesher/world.ts | 39 +- prismarine-viewer/viewer/lib/viewer.ts | 4 +- .../viewer/prepare/generateTextures.ts | 5 + scripts/esbuildPlugins.mjs | 24 +- src/preflatMap.json | 1741 +++++++++++++++++ 8 files changed, 1880 insertions(+), 12 deletions(-) create mode 100644 src/preflatMap.json diff --git a/prismarine-viewer/buildMesherWorker.mjs b/prismarine-viewer/buildMesherWorker.mjs index 819324de..e9f6a16f 100644 --- a/prismarine-viewer/buildMesherWorker.mjs +++ b/prismarine-viewer/buildMesherWorker.mjs @@ -6,6 +6,7 @@ import path from 'path' import { fileURLToPath } from 'url' import fs from 'fs' import { dynamicMcDataFiles } from './buildMesherConfig.mjs' +import { mesherSharedPlugins } from '../scripts/esbuildPlugins.mjs' const allowedBundleFiles = ['legacy', 'versions', 'protocolVersions', 'features'] @@ -34,6 +35,7 @@ const buildOptions = { 'process.env.BROWSER': '"true"', }, plugins: [ + ...mesherSharedPlugins, { name: 'external-json', setup (build) { diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts index 0bcf7250..bc1d3bbb 100644 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ b/prismarine-viewer/viewer/lib/mesher/mesher.ts @@ -53,6 +53,7 @@ self.onmessage = ({ data }) => { if (data.config) { world ??= new World(data.config.version) world.config = {...world.config, ...data.config} + globalThis.world = world } if (data.type === 'mesherData') { diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index bfb96d11..40b82ea2 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -1,7 +1,9 @@ import { Vec3 } from 'vec3' import type { BlockStatesOutput } from '../../prepare/modelsBuilder' import { World } from './world' -import { Block } from 'prismarine-block' +import { WorldBlock as Block } from './world' +import legacyJson from '../../../../src/preflatMap.json' +import { versionToNumber } from '../../prepare/utils' const tints: any = {} let blockStates: BlockStatesOutput @@ -33,6 +35,53 @@ function prepareTints (tints) { }) } +const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks); +export function preflatBlockCalculation (block: Block, world: World, position: Vec3) { + const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0] + if (!type) return + switch (type) { + case 'directional': { + const isSolidConnection = !block.name.includes('redstone') && !block.name.includes('tripwire') + const neighbors = [ + world.getBlock(position.offset(0, 0, 1)), + world.getBlock(position.offset(0, 0, -1)), + world.getBlock(position.offset(1, 0, 0)), + world.getBlock(position.offset(-1, 0, 0)) + ] + // set needed props to true: east:'false',north:'false',south:'false',west:'false' + const props = {} + for (const [i, neighbor] of neighbors.entries()) { + const isConnectedToSolid = isSolidConnection ? (neighbor && !neighbor.transparent) : false + if (isConnectedToSolid || neighbor?.name === block.name) { + props[['south', 'north', 'east', 'west'][i]] = 'true' + } + } + return props + } + // case 'gate_in_wall': {} + case 'block_snowy': { + const aboveIsSnow = world.getBlock(position.offset(0, 1, 0))?.name === 'snow' + return { + snowy: `${aboveIsSnow}` + } + } + case 'door': { + // upper half matches lower in + const half = block.getProperties().half + if (half === 'upper') { + // copy other properties + const lower = world.getBlock(position.offset(0, -1, 0)) + if (lower?.name === block.name) { + return { + ...lower.getProperties(), + half: 'upper' + } + } + } + } + } +} + function tintToGl (tint) { const r = (tint >> 16) & 0xff const g = (tint >> 8) & 0xff @@ -349,7 +398,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr const aos: number[] = [] const neighborPos = position.plus(new Vec3(...dir)) - const baseLight = world.getLight(neighborPos) / 15 + const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 for (const pos of corners) { let vertex = [ (pos[0] ? maxx : minx), @@ -462,7 +511,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) { for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) { for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) { const block = world.getBlock(cursor)! - if (block.name.includes('_sign')) { + if (block.name.includes('_sign') || block.name === 'sign') { const key = `${cursor.x},${cursor.y},${cursor.z}` const props: any = block.getProperties() const facingRotationMap = { @@ -478,7 +527,24 @@ export function getSectionGeometry (sx, sy, sz, world: World) { } } const biome = block.biome.name - if (block.variant === undefined) { + + let preflatRecomputeVariant = !!(block as any)._originalProperties + if (world.preflat) { + const patchProperties = preflatBlockCalculation(block, world, cursor) + if (patchProperties) { + //@ts-ignore + block._originalProperties ??= block._properties + //@ts-ignore + block._properties = { ...block._originalProperties, ...patchProperties } + preflatRecomputeVariant = true + } else { + //@ts-ignore + block._properties = block._originalProperties ?? block._properties + //@ts-ignore + block._originalProperties = undefined + } + } + if (block.variant === undefined || preflatRecomputeVariant) { block.variant = getModelVariants(block) } @@ -592,7 +658,7 @@ function matchProperties (block: Block, /* to match against */properties: Record return true } -function getModelVariants (block: import('prismarine-block').Block) { +function getModelVariants (block: Block) { // air, cave_air, void_air and so on... // full list of invisible & special blocks https://minecraft.wiki/w/Model#Blocks_and_fluids if (block.name === '' || block.name === 'air' || block.name.endsWith('_air')) return [] diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/prismarine-viewer/viewer/lib/mesher/world.ts index 9a4f0ab3..5f3a281d 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/prismarine-viewer/viewer/lib/mesher/world.ts @@ -4,6 +4,7 @@ import { Block } from "prismarine-block" import { Vec3 } from 'vec3' import moreBlockDataGeneratedJson from '../moreBlockDataGenerated.json' import { defaultMesherConfig } from './shared' +import legacyJson from '../../../../src/preflatMap.json' const ignoreAoBlocks = Object.keys(moreBlockDataGeneratedJson.noOcclusions) @@ -17,7 +18,7 @@ function isCube (shapes) { return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 } -export type WorldBlock = Block & { +export type WorldBlock = Omit & { variant?: any // todo isCube: boolean @@ -30,14 +31,16 @@ export class World { columns = {} as { [key: string]: import('prismarine-chunk/types/index').PCChunk } blockCache = {} biomeCache: { [id: number]: mcData.Biome } + preflat: boolean constructor(version) { this.Chunk = Chunks(version) as any this.biomeCache = mcData(version).biomes + this.preflat = !mcData(version).supportFeature('blockStateId') this.config.version = version } - getLight (pos: Vec3, isNeighbor = false) { + getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { const { enableLighting, skyLight } = this.config if (!enableLighting) return 15 // const key = `${pos.x},${pos.y},${pos.z}` @@ -52,8 +55,17 @@ export class World { ) + 2 ) // lightsCache.set(key, result) - if (result === 2 && this.getBlock(pos)?.name.match(/_stairs|slab/)) { // todo this is obviously wrong - result = this.getLight(pos.offset(0, 1, 0)) + if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => x.match(/_stairs|slab|glass_pane/)) && !skipMoreChecks) { // todo this is obviously wrong + const lights = [ + this.getLight(pos.offset(0, 1, 0), undefined, true), + this.getLight(pos.offset(0, -1, 0), undefined, true), + this.getLight(pos.offset(0, 0, 1), undefined, true), + this.getLight(pos.offset(0, 0, -1), undefined, true), + this.getLight(pos.offset(1, 0, 0), undefined, true), + this.getLight(pos.offset(-1, 0, 0), undefined, true) + ].filter(x => x !== 2) + const min = Math.min(...lights) + result = min } if (isNeighbor && result === 2) result = 15 // TODO return result @@ -91,6 +103,8 @@ export class World { } getBlock (pos: Vec3): WorldBlock | null { + // for easier testing + if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) const key = columnKey(Math.floor(pos.x / 16) * 16, Math.floor(pos.z / 16) * 16) const column = this.columns[key] @@ -111,6 +125,23 @@ export class World { throw new Error('position is not reliable, use pos parameter instead of block.position') } }) + if (this.preflat) { + const namePropsStr = legacyJson.blocks[b.type + ':' + b.metadata] || legacyJson.blocks[b.type + ':' + '0'] + b.name = namePropsStr.split('[')[0] + const propsStr = namePropsStr.split('[')?.[1]?.split(']'); + if (propsStr) { + const newProperties = Object.fromEntries(propsStr.join('').split(',').map(x => { + let [key, val] = x.split('=') as any + if (!isNaN(val)) val = parseInt(val) + return [key, val] + })) + //@ts-ignore + b._properties = newProperties + } else { + //@ts-ignore + b._properties = {} + } + } } const block = this.blockCache[stateId] diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 65091f3e..2a240104 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -7,6 +7,7 @@ import EventEmitter from 'events' import { WorldRendererThree } from './worldrendererThree' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import { WorldRendererCommon, WorldRendererConfig, defaultWorldRendererConfig } from './worldrendererCommon' +import { versionToNumber } from '../prepare/utils' export class Viewer { scene: THREE.Scene @@ -76,7 +77,8 @@ export class Viewer { } setVersion (userVersion: string) { - const texturesVersion = getVersion(userVersion) + let texturesVersion = getVersion(userVersion) + if (versionToNumber(userVersion) < versionToNumber('1.13')) texturesVersion = '1.13.2' // we normalize to post-flatenning in mesher console.log('[viewer] Using version:', userVersion, 'textures:', texturesVersion) this.world.setVersion(userVersion, texturesVersion) this.entities.clear() diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts index 2a196ccb..dc838c65 100644 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ b/prismarine-viewer/viewer/prepare/generateTextures.ts @@ -5,6 +5,7 @@ import mcAssets from 'minecraft-assets' import fs from 'fs-extra' import { prepareMoreGeneratedBlocks } from './moreGeneratedBlocks' import { generateItemsAtlases } from './genItemsAtlas' +import { versionToNumber } from './utils' const publicPath = path.resolve(__dirname, '../../public') @@ -23,6 +24,10 @@ Promise.resolve().then(async () => { if (!mcAssets.versions.includes(version)) { throw new Error(`Version ${version} is not supported by minecraft-assets`) } + if (versionToNumber(version) < versionToNumber('1.13')) { + // we normalize data to 1.13 for pre 1.13 versions + continue + } const assets = mcAssets(version) const { warnings: _warnings } = await prepareMoreGeneratedBlocks(assets) _warnings.forEach(x => warnings.add(x)) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 999f9dc7..49547ea1 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -8,6 +8,7 @@ import MCProtocol from 'minecraft-protocol' import MCData from 'minecraft-data' import { throttle } from 'lodash-es' +const __dirname = dirname(new URL(import.meta.url).pathname) const { supportedVersions } = MCProtocol const prod = process.argv.includes('--prod') @@ -26,7 +27,7 @@ export const startWatchingHmr = () => { // 'dist/webglRendererWorker.js': 'webglRendererWorker', } for (const name of Object.keys(eventsPerFile)) { - const file = join('dist', name); + const file = join('dist', name) if (!fs.existsSync(file)) console.warn(`[missing worker] File ${name} does not exist`) fs.watchFile(file, () => { writeToClients({ replace: { type: eventsPerFile[name] } }) @@ -34,8 +35,27 @@ export const startWatchingHmr = () => { } } +/** @type {import('esbuild').Plugin[]} */ +const mesherSharedPlugins = [ + { + name: 'minecraft-data', + setup (build) { + build.onLoad({ + filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, + }, async (args) => { + const data = fs.readFileSync(join(__dirname, '../src/preflatMap.json'), 'utf8') + return { + contents: `module.exports = ${data}`, + loader: 'js', + } + }) + } + } +] + /** @type {import('esbuild').Plugin[]} */ const plugins = [ + ...mesherSharedPlugins, { name: 'strict-aliases', setup (build) { @@ -339,4 +359,4 @@ const plugins = [ }) ] -export { plugins, connectedClients as clients } +export { plugins, connectedClients as clients, mesherSharedPlugins } diff --git a/src/preflatMap.json b/src/preflatMap.json new file mode 100644 index 00000000..fdf2640f --- /dev/null +++ b/src/preflatMap.json @@ -0,0 +1,1741 @@ +{ + "blocks": { + "0:0": "air", + "1:0": "stone", + "1:1": "granite", + "1:2": "polished_granite", + "1:3": "diorite", + "1:4": "polished_diorite", + "1:5": "andesite", + "1:6": "polished_andesite", + "2:0": "grass_block[snowy=false]", + "3:0": "dirt", + "3:1": "coarse_dirt", + "3:2": "podzol[snowy=false]", + "4:0": "cobblestone", + "5:0": "oak_planks", + "5:1": "spruce_planks", + "5:2": "birch_planks", + "5:3": "jungle_planks", + "5:4": "acacia_planks", + "5:5": "dark_oak_planks", + "6:0": "oak_sapling[stage=0]", + "6:1": "spruce_sapling[stage=0]", + "6:2": "birch_sapling[stage=0]", + "6:3": "jungle_sapling[stage=0]", + "6:4": "acacia_sapling[stage=0]", + "6:5": "dark_oak_sapling[stage=0]", + "6:8": "oak_sapling[stage=1]", + "6:9": "spruce_sapling[stage=1]", + "6:10": "birch_sapling[stage=1]", + "6:11": "jungle_sapling[stage=1]", + "6:12": "acacia_sapling[stage=1]", + "6:13": "dark_oak_sapling[stage=1]", + "7:0": "bedrock", + "8:0": "water[level=0]", + "8:1": "water[level=1]", + "8:2": "water[level=2]", + "8:3": "water[level=3]", + "8:4": "water[level=4]", + "8:5": "water[level=5]", + "8:6": "water[level=6]", + "8:7": "water[level=7]", + "8:8": "water[level=8]", + "8:9": "water[level=9]", + "8:10": "water[level=10]", + "8:11": "water[level=11]", + "8:12": "water[level=12]", + "8:13": "water[level=13]", + "8:14": "water[level=14]", + "8:15": "water[level=15]", + "9:0": "water[level=0]", + "9:1": "water[level=1]", + "9:2": "water[level=2]", + "9:3": "water[level=3]", + "9:4": "water[level=4]", + "9:5": "water[level=5]", + "9:6": "water[level=6]", + "9:7": "water[level=7]", + "9:8": "water[level=8]", + "9:9": "water[level=9]", + "9:10": "water[level=10]", + "9:11": "water[level=11]", + "9:12": "water[level=12]", + "9:13": "water[level=13]", + "9:14": "water[level=14]", + "9:15": "water[level=15]", + "10:0": "lava[level=0]", + "10:1": "lava[level=1]", + "10:2": "lava[level=2]", + "10:3": "lava[level=3]", + "10:4": "lava[level=4]", + "10:5": "lava[level=5]", + "10:6": "lava[level=6]", + "10:7": "lava[level=7]", + "10:8": "lava[level=8]", + "10:9": "lava[level=9]", + "10:10": "lava[level=10]", + "10:11": "lava[level=11]", + "10:12": "lava[level=12]", + "10:13": "lava[level=13]", + "10:14": "lava[level=14]", + "10:15": "lava[level=15]", + "11:0": "lava[level=0]", + "11:1": "lava[level=1]", + "11:2": "lava[level=2]", + "11:3": "lava[level=3]", + "11:4": "lava[level=4]", + "11:5": "lava[level=5]", + "11:6": "lava[level=6]", + "11:7": "lava[level=7]", + "11:8": "lava[level=8]", + "11:9": "lava[level=9]", + "11:10": "lava[level=10]", + "11:11": "lava[level=11]", + "11:12": "lava[level=12]", + "11:13": "lava[level=13]", + "11:14": "lava[level=14]", + "11:15": "lava[level=15]", + "12:0": "sand", + "12:1": "red_sand", + "13:0": "gravel", + "14:0": "gold_ore", + "15:0": "iron_ore", + "16:0": "coal_ore", + "17:0": "oak_log[axis=y]", + "17:1": "spruce_log[axis=y]", + "17:2": "birch_log[axis=y]", + "17:3": "jungle_log[axis=y]", + "17:4": "oak_log[axis=x]", + "17:5": "spruce_log[axis=x]", + "17:6": "birch_log[axis=x]", + "17:7": "jungle_log[axis=x]", + "17:8": "oak_log[axis=z]", + "17:9": "spruce_log[axis=z]", + "17:10": "birch_log[axis=z]", + "17:11": "jungle_log[axis=z]", + "17:12": "oak_bark", + "17:13": "spruce_bark", + "17:14": "birch_bark", + "17:15": "jungle_bark", + "18:0": "oak_leaves[check_decay=false,decayable=true]", + "18:1": "spruce_leaves[check_decay=false,decayable=true]", + "18:2": "birch_leaves[check_decay=false,decayable=true]", + "18:3": "jungle_leaves[check_decay=false,decayable=true]", + "18:4": "oak_leaves[check_decay=false,decayable=false]", + "18:5": "spruce_leaves[check_decay=false,decayable=false]", + "18:6": "birch_leaves[check_decay=false,decayable=false]", + "18:7": "jungle_leaves[check_decay=false,decayable=false]", + "18:8": "oak_leaves[check_decay=true,decayable=true]", + "18:9": "spruce_leaves[check_decay=true,decayable=true]", + "18:10": "birch_leaves[check_decay=true,decayable=true]", + "18:11": "jungle_leaves[check_decay=true,decayable=true]", + "18:12": "oak_leaves[check_decay=true,decayable=false]", + "18:13": "spruce_leaves[check_decay=true,decayable=false]", + "18:14": "birch_leaves[check_decay=true,decayable=false]", + "18:15": "jungle_leaves[check_decay=true,decayable=false]", + "19:0": "sponge", + "19:1": "wet_sponge", + "20:0": "glass", + "21:0": "lapis_ore", + "22:0": "lapis_block", + "23:0": "dispenser[facing=down,triggered=false]", + "23:1": "dispenser[facing=up,triggered=false]", + "23:2": "dispenser[facing=north,triggered=false]", + "23:3": "dispenser[facing=south,triggered=false]", + "23:4": "dispenser[facing=west,triggered=false]", + "23:5": "dispenser[facing=east,triggered=false]", + "23:8": "dispenser[facing=down,triggered=true]", + "23:9": "dispenser[facing=up,triggered=true]", + "23:10": "dispenser[facing=north,triggered=true]", + "23:11": "dispenser[facing=south,triggered=true]", + "23:12": "dispenser[facing=west,triggered=true]", + "23:13": "dispenser[facing=east,triggered=true]", + "24:0": "sandstone", + "24:1": "chiseled_sandstone", + "24:2": "cut_sandstone", + "25:0": "note_block", + "26:0": "red_bed[facing=south,occupied=false,part=foot]", + "26:1": "red_bed[facing=west,occupied=false,part=foot]", + "26:2": "red_bed[facing=north,occupied=false,part=foot]", + "26:3": "red_bed[facing=east,occupied=false,part=foot]", + "26:8": "red_bed[facing=south,occupied=false,part=head]", + "26:9": "red_bed[facing=west,occupied=false,part=head]", + "26:10": "red_bed[facing=north,occupied=false,part=head]", + "26:11": "red_bed[facing=east,occupied=false,part=head]", + "26:12": "red_bed[facing=south,occupied=true,part=head]", + "26:13": "red_bed[facing=west,occupied=true,part=head]", + "26:14": "red_bed[facing=north,occupied=true,part=head]", + "26:15": "red_bed[facing=east,occupied=true,part=head]", + "27:0": "powered_rail[powered=false,shape=north_south]", + "27:1": "powered_rail[powered=false,shape=east_west]", + "27:2": "powered_rail[powered=false,shape=ascending_east]", + "27:3": "powered_rail[powered=false,shape=ascending_west]", + "27:4": "powered_rail[powered=false,shape=ascending_north]", + "27:5": "powered_rail[powered=false,shape=ascending_south]", + "27:8": "powered_rail[powered=true,shape=north_south]", + "27:9": "powered_rail[powered=true,shape=east_west]", + "27:10": "powered_rail[powered=true,shape=ascending_east]", + "27:11": "powered_rail[powered=true,shape=ascending_west]", + "27:12": "powered_rail[powered=true,shape=ascending_north]", + "27:13": "powered_rail[powered=true,shape=ascending_south]", + "28:0": "detector_rail[powered=false,shape=north_south]", + "28:1": "detector_rail[powered=false,shape=east_west]", + "28:2": "detector_rail[powered=false,shape=ascending_east]", + "28:3": "detector_rail[powered=false,shape=ascending_west]", + "28:4": "detector_rail[powered=false,shape=ascending_north]", + "28:5": "detector_rail[powered=false,shape=ascending_south]", + "28:8": "detector_rail[powered=true,shape=north_south]", + "28:9": "detector_rail[powered=true,shape=east_west]", + "28:10": "detector_rail[powered=true,shape=ascending_east]", + "28:11": "detector_rail[powered=true,shape=ascending_west]", + "28:12": "detector_rail[powered=true,shape=ascending_north]", + "28:13": "detector_rail[powered=true,shape=ascending_south]", + "29:0": "sticky_piston[extended=false,facing=down]", + "29:1": "sticky_piston[extended=false,facing=up]", + "29:2": "sticky_piston[extended=false,facing=north]", + "29:3": "sticky_piston[extended=false,facing=south]", + "29:4": "sticky_piston[extended=false,facing=west]", + "29:5": "sticky_piston[extended=false,facing=east]", + "29:8": "sticky_piston[extended=true,facing=down]", + "29:9": "sticky_piston[extended=true,facing=up]", + "29:10": "sticky_piston[extended=true,facing=north]", + "29:11": "sticky_piston[extended=true,facing=south]", + "29:12": "sticky_piston[extended=true,facing=west]", + "29:13": "sticky_piston[extended=true,facing=east]", + "30:0": "cobweb", + "31:0": "dead_bush", + "31:1": "grass", + "31:2": "fern", + "32:0": "dead_bush", + "33:0": "piston[extended=false,facing=down]", + "33:1": "piston[extended=false,facing=up]", + "33:2": "piston[extended=false,facing=north]", + "33:3": "piston[extended=false,facing=south]", + "33:4": "piston[extended=false,facing=west]", + "33:5": "piston[extended=false,facing=east]", + "33:8": "piston[extended=true,facing=down]", + "33:9": "piston[extended=true,facing=up]", + "33:10": "piston[extended=true,facing=north]", + "33:11": "piston[extended=true,facing=south]", + "33:12": "piston[extended=true,facing=west]", + "33:13": "piston[extended=true,facing=east]", + "34:0": "piston_head[facing=down,short=false,type=normal]", + "34:1": "piston_head[facing=up,short=false,type=normal]", + "34:2": "piston_head[facing=north,short=false,type=normal]", + "34:3": "piston_head[facing=south,short=false,type=normal]", + "34:4": "piston_head[facing=west,short=false,type=normal]", + "34:5": "piston_head[facing=east,short=false,type=normal]", + "34:8": "piston_head[facing=down,short=false,type=sticky]", + "34:9": "piston_head[facing=up,short=false,type=sticky]", + "34:10": "piston_head[facing=north,short=false,type=sticky]", + "34:11": "piston_head[facing=south,short=false,type=sticky]", + "34:12": "piston_head[facing=west,short=false,type=sticky]", + "34:13": "piston_head[facing=east,short=false,type=sticky]", + "35:0": "white_wool", + "35:1": "orange_wool", + "35:2": "magenta_wool", + "35:3": "light_blue_wool", + "35:4": "yellow_wool", + "35:5": "lime_wool", + "35:6": "pink_wool", + "35:7": "gray_wool", + "35:8": "light_gray_wool", + "35:9": "cyan_wool", + "35:10": "purple_wool", + "35:11": "blue_wool", + "35:12": "brown_wool", + "35:13": "green_wool", + "35:14": "red_wool", + "35:15": "black_wool", + "36:0": "moving_piston[facing=down,type=normal]", + "36:1": "moving_piston[facing=up,type=normal]", + "36:2": "moving_piston[facing=north,type=normal]", + "36:3": "moving_piston[facing=south,type=normal]", + "36:4": "moving_piston[facing=west,type=normal]", + "36:5": "moving_piston[facing=east,type=normal]", + "36:8": "moving_piston[facing=down,type=sticky]", + "36:9": "moving_piston[facing=up,type=sticky]", + "36:10": "moving_piston[facing=north,type=sticky]", + "36:11": "moving_piston[facing=south,type=sticky]", + "36:12": "moving_piston[facing=west,type=sticky]", + "36:13": "moving_piston[facing=east,type=sticky]", + "37:0": "dandelion", + "38:0": "poppy", + "38:1": "blue_orchid", + "38:2": "allium", + "38:3": "azure_bluet", + "38:4": "red_tulip", + "38:5": "orange_tulip", + "38:6": "white_tulip", + "38:7": "pink_tulip", + "38:8": "oxeye_daisy", + "39:0": "brown_mushroom", + "40:0": "red_mushroom", + "41:0": "gold_block", + "42:0": "iron_block", + "43:0": "stone_slab[type=double]", + "43:1": "sandstone_slab[type=double]", + "43:2": "petrified_oak_slab[type=double]", + "43:3": "cobblestone_slab[type=double]", + "43:4": "brick_slab[type=double]", + "43:5": "stone_brick_slab[type=double]", + "43:6": "nether_brick_slab[type=double]", + "43:7": "quartz_slab[type=double]", + "43:8": "smooth_stone", + "43:9": "smooth_sandstone", + "43:10": "petrified_oak_slab[type=double]", + "43:11": "cobblestone_slab[type=double]", + "43:12": "brick_slab[type=double]", + "43:13": "stone_brick_slab[type=double]", + "43:14": "nether_brick_slab[type=double]", + "43:15": "smooth_quartz", + "44:0": "stone_slab[type=bottom]", + "44:1": "sandstone_slab[type=bottom]", + "44:2": "petrified_oak_slab[type=bottom]", + "44:3": "cobblestone_slab[type=bottom]", + "44:4": "brick_slab[type=bottom]", + "44:5": "stone_brick_slab[type=bottom]", + "44:6": "nether_brick_slab[type=bottom]", + "44:7": "quartz_slab[type=bottom]", + "44:8": "stone_slab[type=top]", + "44:9": "sandstone_slab[type=top]", + "44:10": "petrified_oak_slab[type=top]", + "44:11": "cobblestone_slab[type=top]", + "44:12": "brick_slab[type=top]", + "44:13": "stone_brick_slab[type=top]", + "44:14": "nether_brick_slab[type=top]", + "44:15": "quartz_slab[type=top]", + "45:0": "bricks", + "46:0": "tnt[unstable=false]", + "46:1": "tnt[unstable=true]", + "47:0": "bookshelf", + "48:0": "mossy_cobblestone", + "49:0": "obsidian", + "50:1": "wall_torch[facing=east]", + "50:2": "wall_torch[facing=west]", + "50:3": "wall_torch[facing=south]", + "50:4": "wall_torch[facing=north]", + "50:5": "torch", + "51:0": "fire[age=0,east=false,north=false,south=false,up=false,west=false]", + "51:1": "fire[age=1,east=false,north=false,south=false,up=false,west=false]", + "51:2": "fire[age=2,east=false,north=false,south=false,up=false,west=false]", + "51:3": "fire[age=3,east=false,north=false,south=false,up=false,west=false]", + "51:4": "fire[age=4,east=false,north=false,south=false,up=false,west=false]", + "51:5": "fire[age=5,east=false,north=false,south=false,up=false,west=false]", + "51:6": "fire[age=6,east=false,north=false,south=false,up=false,west=false]", + "51:7": "fire[age=7,east=false,north=false,south=false,up=false,west=false]", + "51:8": "fire[age=8,east=false,north=false,south=false,up=false,west=false]", + "51:9": "fire[age=9,east=false,north=false,south=false,up=false,west=false]", + "51:10": "fire[age=10,east=false,north=false,south=false,up=false,west=false]", + "51:11": "fire[age=11,east=false,north=false,south=false,up=false,west=false]", + "51:12": "fire[age=12,east=false,north=false,south=false,up=false,west=false]", + "51:13": "fire[age=13,east=false,north=false,south=false,up=false,west=false]", + "51:14": "fire[age=14,east=false,north=false,south=false,up=false,west=false]", + "51:15": "fire[age=15,east=false,north=false,south=false,up=false,west=false]", + "52:0": "mob_spawner", + "53:0": "oak_stairs[facing=east,half=bottom,shape=straight]", + "53:1": "oak_stairs[facing=west,half=bottom,shape=straight]", + "53:2": "oak_stairs[facing=south,half=bottom,shape=straight]", + "53:3": "oak_stairs[facing=north,half=bottom,shape=straight]", + "53:4": "oak_stairs[facing=east,half=top,shape=straight]", + "53:5": "oak_stairs[facing=west,half=top,shape=straight]", + "53:6": "oak_stairs[facing=south,half=top,shape=straight]", + "53:7": "oak_stairs[facing=north,half=top,shape=straight]", + "54:2": "chest[facing=north,type=single]", + "54:3": "chest[facing=south,type=single]", + "54:4": "chest[facing=west,type=single]", + "54:5": "chest[facing=east,type=single]", + "55:0": "redstone_wire[east=none,north=none,power=0,south=none,west=none]", + "55:1": "redstone_wire[east=none,north=none,power=1,south=none,west=none]", + "55:2": "redstone_wire[east=none,north=none,power=2,south=none,west=none]", + "55:3": "redstone_wire[east=none,north=none,power=3,south=none,west=none]", + "55:4": "redstone_wire[east=none,north=none,power=4,south=none,west=none]", + "55:5": "redstone_wire[east=none,north=none,power=5,south=none,west=none]", + "55:6": "redstone_wire[east=none,north=none,power=6,south=none,west=none]", + "55:7": "redstone_wire[east=none,north=none,power=7,south=none,west=none]", + "55:8": "redstone_wire[east=none,north=none,power=8,south=none,west=none]", + "55:9": "redstone_wire[east=none,north=none,power=9,south=none,west=none]", + "55:10": "redstone_wire[east=none,north=none,power=10,south=none,west=none]", + "55:11": "redstone_wire[east=none,north=none,power=11,south=none,west=none]", + "55:12": "redstone_wire[east=none,north=none,power=12,south=none,west=none]", + "55:13": "redstone_wire[east=none,north=none,power=13,south=none,west=none]", + "55:14": "redstone_wire[east=none,north=none,power=14,south=none,west=none]", + "55:15": "redstone_wire[east=none,north=none,power=15,south=none,west=none]", + "56:0": "diamond_ore", + "57:0": "diamond_block", + "58:0": "crafting_table", + "59:0": "wheat[age=0]", + "59:1": "wheat[age=1]", + "59:2": "wheat[age=2]", + "59:3": "wheat[age=3]", + "59:4": "wheat[age=4]", + "59:5": "wheat[age=5]", + "59:6": "wheat[age=6]", + "59:7": "wheat[age=7]", + "60:0": "farmland[moisture=0]", + "60:1": "farmland[moisture=1]", + "60:2": "farmland[moisture=2]", + "60:3": "farmland[moisture=3]", + "60:4": "farmland[moisture=4]", + "60:5": "farmland[moisture=5]", + "60:6": "farmland[moisture=6]", + "60:7": "farmland[moisture=7]", + "61:2": "furnace[facing=north,lit=false]", + "61:3": "furnace[facing=south,lit=false]", + "61:4": "furnace[facing=west,lit=false]", + "61:5": "furnace[facing=east,lit=false]", + "62:2": "furnace[facing=north,lit=true]", + "62:3": "furnace[facing=south,lit=true]", + "62:4": "furnace[facing=west,lit=true]", + "62:5": "furnace[facing=east,lit=true]", + "63:0": "sign[rotation=0]", + "63:1": "sign[rotation=1]", + "63:2": "sign[rotation=2]", + "63:3": "sign[rotation=3]", + "63:4": "sign[rotation=4]", + "63:5": "sign[rotation=5]", + "63:6": "sign[rotation=6]", + "63:7": "sign[rotation=7]", + "63:8": "sign[rotation=8]", + "63:9": "sign[rotation=9]", + "63:10": "sign[rotation=10]", + "63:11": "sign[rotation=11]", + "63:12": "sign[rotation=12]", + "63:13": "sign[rotation=13]", + "63:14": "sign[rotation=14]", + "63:15": "sign[rotation=15]", + "64:0": "oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "64:1": "oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "64:2": "oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "64:3": "oak_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "64:4": "oak_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "64:5": "oak_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "64:6": "oak_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "64:7": "oak_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "64:8": "oak_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "64:9": "oak_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "64:10": "oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "64:11": "oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "65:2": "ladder[facing=north]", + "65:3": "ladder[facing=south]", + "65:4": "ladder[facing=west]", + "65:5": "ladder[facing=east]", + "66:0": "rail[shape=north_south]", + "66:1": "rail[shape=east_west]", + "66:2": "rail[shape=ascending_east]", + "66:3": "rail[shape=ascending_west]", + "66:4": "rail[shape=ascending_north]", + "66:5": "rail[shape=ascending_south]", + "66:6": "rail[shape=south_east]", + "66:7": "rail[shape=south_west]", + "66:8": "rail[shape=north_west]", + "66:9": "rail[shape=north_east]", + "67:0": "cobblestone_stairs[facing=east,half=bottom,shape=straight]", + "67:1": "cobblestone_stairs[facing=west,half=bottom,shape=straight]", + "67:2": "cobblestone_stairs[facing=south,half=bottom,shape=straight]", + "67:3": "cobblestone_stairs[facing=north,half=bottom,shape=straight]", + "67:4": "cobblestone_stairs[facing=east,half=top,shape=straight]", + "67:5": "cobblestone_stairs[facing=west,half=top,shape=straight]", + "67:6": "cobblestone_stairs[facing=south,half=top,shape=straight]", + "67:7": "cobblestone_stairs[facing=north,half=top,shape=straight]", + "68:2": "wall_sign[facing=north]", + "68:3": "wall_sign[facing=south]", + "68:4": "wall_sign[facing=west]", + "68:5": "wall_sign[facing=east]", + "69:0": "lever[face=ceiling,facing=west,powered=false]", + "69:1": "lever[face=wall,facing=east,powered=false]", + "69:2": "lever[face=wall,facing=west,powered=false]", + "69:3": "lever[face=wall,facing=south,powered=false]", + "69:4": "lever[face=wall,facing=north,powered=false]", + "69:5": "lever[face=floor,facing=north,powered=false]", + "69:6": "lever[face=floor,facing=west,powered=false]", + "69:7": "lever[face=ceiling,facing=north,powered=false]", + "69:8": "lever[face=ceiling,facing=west,powered=true]", + "69:9": "lever[face=wall,facing=east,powered=true]", + "69:10": "lever[face=wall,facing=west,powered=true]", + "69:11": "lever[face=wall,facing=south,powered=true]", + "69:12": "lever[face=wall,facing=north,powered=true]", + "69:13": "lever[face=floor,facing=north,powered=true]", + "69:14": "lever[face=floor,facing=west,powered=true]", + "69:15": "lever[face=ceiling,facing=north,powered=true]", + "70:0": "stone_pressure_plate[powered=false]", + "70:1": "stone_pressure_plate[powered=true]", + "71:0": "iron_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "71:1": "iron_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "71:2": "iron_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "71:3": "iron_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "71:4": "iron_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "71:5": "iron_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "71:6": "iron_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "71:7": "iron_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "71:8": "iron_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "71:9": "iron_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "71:10": "iron_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "71:11": "iron_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "72:0": "oak_pressure_plate[powered=false]", + "72:1": "oak_pressure_plate[powered=true]", + "73:0": "redstone_ore[lit=false]", + "74:0": "redstone_ore[lit=true]", + "75:1": "redstone_wall_torch[facing=east,lit=false]", + "75:2": "redstone_wall_torch[facing=west,lit=false]", + "75:3": "redstone_wall_torch[facing=south,lit=false]", + "75:4": "redstone_wall_torch[facing=north,lit=false]", + "75:5": "redstone_torch[lit=false]", + "76:1": "redstone_wall_torch[facing=east,lit=true]", + "76:2": "redstone_wall_torch[facing=west,lit=true]", + "76:3": "redstone_wall_torch[facing=south,lit=true]", + "76:4": "redstone_wall_torch[facing=north,lit=true]", + "76:5": "redstone_torch[lit=true]", + "77:0": "stone_button[face=ceiling,facing=north,powered=false]", + "77:1": "stone_button[face=wall,facing=east,powered=false]", + "77:2": "stone_button[face=wall,facing=west,powered=false]", + "77:3": "stone_button[face=wall,facing=south,powered=false]", + "77:4": "stone_button[face=wall,facing=north,powered=false]", + "77:5": "stone_button[face=floor,facing=north,powered=false]", + "77:8": "stone_button[face=ceiling,facing=north,powered=true]", + "77:9": "stone_button[face=wall,facing=east,powered=true]", + "77:10": "stone_button[face=wall,facing=west,powered=true]", + "77:11": "stone_button[face=wall,facing=south,powered=true]", + "77:12": "stone_button[face=wall,facing=north,powered=true]", + "77:13": "stone_button[face=floor,facing=north,powered=true]", + "78:0": "snow[layers=1]", + "78:1": "snow[layers=2]", + "78:2": "snow[layers=3]", + "78:3": "snow[layers=4]", + "78:4": "snow[layers=5]", + "78:5": "snow[layers=6]", + "78:6": "snow[layers=7]", + "78:7": "snow[layers=8]", + "79:0": "ice", + "80:0": "snow_block", + "81:0": "cactus[age=0]", + "81:1": "cactus[age=1]", + "81:2": "cactus[age=2]", + "81:3": "cactus[age=3]", + "81:4": "cactus[age=4]", + "81:5": "cactus[age=5]", + "81:6": "cactus[age=6]", + "81:7": "cactus[age=7]", + "81:8": "cactus[age=8]", + "81:9": "cactus[age=9]", + "81:10": "cactus[age=10]", + "81:11": "cactus[age=11]", + "81:12": "cactus[age=12]", + "81:13": "cactus[age=13]", + "81:14": "cactus[age=14]", + "81:15": "cactus[age=15]", + "82:0": "clay", + "83:0": "sugar_cane[age=0]", + "83:1": "sugar_cane[age=1]", + "83:2": "sugar_cane[age=2]", + "83:3": "sugar_cane[age=3]", + "83:4": "sugar_cane[age=4]", + "83:5": "sugar_cane[age=5]", + "83:6": "sugar_cane[age=6]", + "83:7": "sugar_cane[age=7]", + "83:8": "sugar_cane[age=8]", + "83:9": "sugar_cane[age=9]", + "83:10": "sugar_cane[age=10]", + "83:11": "sugar_cane[age=11]", + "83:12": "sugar_cane[age=12]", + "83:13": "sugar_cane[age=13]", + "83:14": "sugar_cane[age=14]", + "83:15": "sugar_cane[age=15]", + "84:0": "jukebox[has_record=false]", + "84:1": "jukebox[has_record=true]", + "85:0": "oak_fence[east=false,north=false,south=false,west=false]", + "86:0": "carved_pumpkin[facing=south]", + "86:1": "carved_pumpkin[facing=west]", + "86:2": "carved_pumpkin[facing=north]", + "86:3": "carved_pumpkin[facing=east]", + "87:0": "netherrack", + "88:0": "soul_sand", + "89:0": "glowstone", + "90:1": "portal[axis=x]", + "90:2": "portal[axis=z]", + "91:0": "jack_o_lantern[facing=south]", + "91:1": "jack_o_lantern[facing=west]", + "91:2": "jack_o_lantern[facing=north]", + "91:3": "jack_o_lantern[facing=east]", + "92:0": "cake[bites=0]", + "92:1": "cake[bites=1]", + "92:2": "cake[bites=2]", + "92:3": "cake[bites=3]", + "92:4": "cake[bites=4]", + "92:5": "cake[bites=5]", + "92:6": "cake[bites=6]", + "93:0": "repeater[delay=1,facing=south,locked=false,powered=false]", + "93:1": "repeater[delay=1,facing=west,locked=false,powered=false]", + "93:2": "repeater[delay=1,facing=north,locked=false,powered=false]", + "93:3": "repeater[delay=1,facing=east,locked=false,powered=false]", + "93:4": "repeater[delay=2,facing=south,locked=false,powered=false]", + "93:5": "repeater[delay=2,facing=west,locked=false,powered=false]", + "93:6": "repeater[delay=2,facing=north,locked=false,powered=false]", + "93:7": "repeater[delay=2,facing=east,locked=false,powered=false]", + "93:8": "repeater[delay=3,facing=south,locked=false,powered=false]", + "93:9": "repeater[delay=3,facing=west,locked=false,powered=false]", + "93:10": "repeater[delay=3,facing=north,locked=false,powered=false]", + "93:11": "repeater[delay=3,facing=east,locked=false,powered=false]", + "93:12": "repeater[delay=4,facing=south,locked=false,powered=false]", + "93:13": "repeater[delay=4,facing=west,locked=false,powered=false]", + "93:14": "repeater[delay=4,facing=north,locked=false,powered=false]", + "93:15": "repeater[delay=4,facing=east,locked=false,powered=false]", + "94:0": "repeater[delay=1,facing=south,locked=false,powered=true]", + "94:1": "repeater[delay=1,facing=west,locked=false,powered=true]", + "94:2": "repeater[delay=1,facing=north,locked=false,powered=true]", + "94:3": "repeater[delay=1,facing=east,locked=false,powered=true]", + "94:4": "repeater[delay=2,facing=south,locked=false,powered=true]", + "94:5": "repeater[delay=2,facing=west,locked=false,powered=true]", + "94:6": "repeater[delay=2,facing=north,locked=false,powered=true]", + "94:7": "repeater[delay=2,facing=east,locked=false,powered=true]", + "94:8": "repeater[delay=3,facing=south,locked=false,powered=true]", + "94:9": "repeater[delay=3,facing=west,locked=false,powered=true]", + "94:10": "repeater[delay=3,facing=north,locked=false,powered=true]", + "94:11": "repeater[delay=3,facing=east,locked=false,powered=true]", + "94:12": "repeater[delay=4,facing=south,locked=false,powered=true]", + "94:13": "repeater[delay=4,facing=west,locked=false,powered=true]", + "94:14": "repeater[delay=4,facing=north,locked=false,powered=true]", + "94:15": "repeater[delay=4,facing=east,locked=false,powered=true]", + "95:0": "white_stained_glass", + "95:1": "orange_stained_glass", + "95:2": "magenta_stained_glass", + "95:3": "light_blue_stained_glass", + "95:4": "yellow_stained_glass", + "95:5": "lime_stained_glass", + "95:6": "pink_stained_glass", + "95:7": "gray_stained_glass", + "95:8": "light_gray_stained_glass", + "95:9": "cyan_stained_glass", + "95:10": "purple_stained_glass", + "95:11": "blue_stained_glass", + "95:12": "brown_stained_glass", + "95:13": "green_stained_glass", + "95:14": "red_stained_glass", + "95:15": "black_stained_glass", + "96:0": "oak_trapdoor[facing=north,half=bottom,open=false]", + "96:1": "oak_trapdoor[facing=south,half=bottom,open=false]", + "96:2": "oak_trapdoor[facing=west,half=bottom,open=false]", + "96:3": "oak_trapdoor[facing=east,half=bottom,open=false]", + "96:4": "oak_trapdoor[facing=north,half=bottom,open=true]", + "96:5": "oak_trapdoor[facing=south,half=bottom,open=true]", + "96:6": "oak_trapdoor[facing=west,half=bottom,open=true]", + "96:7": "oak_trapdoor[facing=east,half=bottom,open=true]", + "96:8": "oak_trapdoor[facing=north,half=top,open=false]", + "96:9": "oak_trapdoor[facing=south,half=top,open=false]", + "96:10": "oak_trapdoor[facing=west,half=top,open=false]", + "96:11": "oak_trapdoor[facing=east,half=top,open=false]", + "96:12": "oak_trapdoor[facing=north,half=top,open=true]", + "96:13": "oak_trapdoor[facing=south,half=top,open=true]", + "96:14": "oak_trapdoor[facing=west,half=top,open=true]", + "96:15": "oak_trapdoor[facing=east,half=top,open=true]", + "97:0": "infested_stone", + "97:1": "infested_cobblestone", + "97:2": "infested_stone_bricks", + "97:3": "infested_mossy_stone_bricks", + "97:4": "infested_cracked_stone_bricks", + "97:5": "infested_chiseled_stone_bricks", + "98:0": "stone_bricks", + "98:1": "mossy_stone_bricks", + "98:2": "cracked_stone_bricks", + "98:3": "chiseled_stone_bricks", + "99:0": "brown_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]", + "99:1": "brown_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]", + "99:2": "brown_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]", + "99:3": "brown_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]", + "99:4": "brown_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]", + "99:5": "brown_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]", + "99:6": "brown_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]", + "99:7": "brown_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]", + "99:8": "brown_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]", + "99:9": "brown_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]", + "99:10": "mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]", + "99:14": "brown_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]", + "99:15": "mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]", + "100:0": "red_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]", + "100:1": "red_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]", + "100:2": "red_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]", + "100:3": "red_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]", + "100:4": "red_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]", + "100:5": "red_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]", + "100:6": "red_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]", + "100:7": "red_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]", + "100:8": "red_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]", + "100:9": "red_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]", + "100:10": "mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]", + "100:14": "red_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]", + "100:15": "mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]", + "101:0": "iron_bars[east=false,north=false,south=false,west=false]", + "102:0": "glass_pane[east=false,north=false,south=false,west=false]", + "103:0": "melon_block", + "104:0": "pumpkin_stem[age=0]", + "104:1": "pumpkin_stem[age=1]", + "104:2": "pumpkin_stem[age=2]", + "104:3": "pumpkin_stem[age=3]", + "104:4": "pumpkin_stem[age=4]", + "104:5": "pumpkin_stem[age=5]", + "104:6": "pumpkin_stem[age=6]", + "104:7": "pumpkin_stem[age=7]", + "105:0": "melon_stem[age=0]", + "105:1": "melon_stem[age=1]", + "105:2": "melon_stem[age=2]", + "105:3": "melon_stem[age=3]", + "105:4": "melon_stem[age=4]", + "105:5": "melon_stem[age=5]", + "105:6": "melon_stem[age=6]", + "105:7": "melon_stem[age=7]", + "106:0": "vine[east=false,north=false,south=false,up=true,west=false]", + "106:1": "vine[east=false,north=false,south=true,up=true,west=false]", + "106:2": "vine[east=false,north=false,south=false,up=true,west=true]", + "106:3": "vine[east=false,north=false,south=true,up=true,west=true]", + "106:4": "vine[east=false,north=true,south=false,up=true,west=false]", + "106:5": "vine[east=false,north=true,south=true,up=true,west=false]", + "106:6": "vine[east=false,north=true,south=false,up=true,west=true]", + "106:7": "vine[east=false,north=true,south=true,up=true,west=true]", + "106:8": "vine[east=true,north=false,south=false,up=true,west=false]", + "106:9": "vine[east=true,north=false,south=true,up=true,west=false]", + "106:10": "vine[east=true,north=false,south=false,up=true,west=true]", + "106:11": "vine[east=true,north=false,south=true,up=true,west=true]", + "106:12": "vine[east=true,north=true,south=false,up=true,west=false]", + "106:13": "vine[east=true,north=true,south=true,up=true,west=false]", + "106:14": "vine[east=true,north=true,south=false,up=true,west=true]", + "106:15": "vine[east=true,north=true,south=true,up=true,west=true]", + "107:0": "oak_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "107:1": "oak_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "107:2": "oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "107:3": "oak_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "107:4": "oak_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "107:5": "oak_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "107:6": "oak_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "107:7": "oak_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "107:8": "oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "107:9": "oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "107:10": "oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "107:11": "oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "107:12": "oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "107:13": "oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "107:14": "oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "107:15": "oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "108:0": "brick_stairs[facing=east,half=bottom,shape=straight]", + "108:1": "brick_stairs[facing=west,half=bottom,shape=straight]", + "108:2": "brick_stairs[facing=south,half=bottom,shape=straight]", + "108:3": "brick_stairs[facing=north,half=bottom,shape=straight]", + "108:4": "brick_stairs[facing=east,half=top,shape=straight]", + "108:5": "brick_stairs[facing=west,half=top,shape=straight]", + "108:6": "brick_stairs[facing=south,half=top,shape=straight]", + "108:7": "brick_stairs[facing=north,half=top,shape=straight]", + "109:0": "stone_brick_stairs[facing=east,half=bottom,shape=straight]", + "109:1": "stone_brick_stairs[facing=west,half=bottom,shape=straight]", + "109:2": "stone_brick_stairs[facing=south,half=bottom,shape=straight]", + "109:3": "stone_brick_stairs[facing=north,half=bottom,shape=straight]", + "109:4": "stone_brick_stairs[facing=east,half=top,shape=straight]", + "109:5": "stone_brick_stairs[facing=west,half=top,shape=straight]", + "109:6": "stone_brick_stairs[facing=south,half=top,shape=straight]", + "109:7": "stone_brick_stairs[facing=north,half=top,shape=straight]", + "110:0": "mycelium[snowy=false]", + "111:0": "lily_pad", + "112:0": "nether_bricks", + "113:0": "nether_brick_fence[east=false,north=false,south=false,west=false]", + "114:0": "nether_brick_stairs[facing=east,half=bottom,shape=straight]", + "114:1": "nether_brick_stairs[facing=west,half=bottom,shape=straight]", + "114:2": "nether_brick_stairs[facing=south,half=bottom,shape=straight]", + "114:3": "nether_brick_stairs[facing=north,half=bottom,shape=straight]", + "114:4": "nether_brick_stairs[facing=east,half=top,shape=straight]", + "114:5": "nether_brick_stairs[facing=west,half=top,shape=straight]", + "114:6": "nether_brick_stairs[facing=south,half=top,shape=straight]", + "114:7": "nether_brick_stairs[facing=north,half=top,shape=straight]", + "115:0": "nether_wart[age=0]", + "115:1": "nether_wart[age=1]", + "115:2": "nether_wart[age=2]", + "115:3": "nether_wart[age=3]", + "116:0": "enchanting_table", + "117:0": "brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", + "117:1": "brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=false]", + "117:2": "brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=false]", + "117:3": "brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=false]", + "117:4": "brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=true]", + "117:5": "brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=true]", + "117:6": "brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=true]", + "117:7": "brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=true]", + "118:0": "cauldron[level=0]", + "118:1": "cauldron[level=1]", + "118:2": "cauldron[level=2]", + "118:3": "cauldron[level=3]", + "119:0": "end_portal", + "120:0": "end_portal_frame[eye=false,facing=south]", + "120:1": "end_portal_frame[eye=false,facing=west]", + "120:2": "end_portal_frame[eye=false,facing=north]", + "120:3": "end_portal_frame[eye=false,facing=east]", + "120:4": "end_portal_frame[eye=true,facing=south]", + "120:5": "end_portal_frame[eye=true,facing=west]", + "120:6": "end_portal_frame[eye=true,facing=north]", + "120:7": "end_portal_frame[eye=true,facing=east]", + "121:0": "end_stone", + "122:0": "dragon_egg", + "123:0": "redstone_lamp[lit=false]", + "124:0": "redstone_lamp[lit=true]", + "125:0": "oak_slab[type=double]", + "125:1": "spruce_slab[type=double]", + "125:2": "birch_slab[type=double]", + "125:3": "jungle_slab[type=double]", + "125:4": "acacia_slab[type=double]", + "125:5": "dark_oak_slab[type=double]", + "126:0": "oak_slab[type=bottom]", + "126:1": "spruce_slab[type=bottom]", + "126:2": "birch_slab[type=bottom]", + "126:3": "jungle_slab[type=bottom]", + "126:4": "acacia_slab[type=bottom]", + "126:5": "dark_oak_slab[type=bottom]", + "126:8": "oak_slab[type=top]", + "126:9": "spruce_slab[type=top]", + "126:10": "birch_slab[type=top]", + "126:11": "jungle_slab[type=top]", + "126:12": "acacia_slab[type=top]", + "126:13": "dark_oak_slab[type=top]", + "127:0": "cocoa[age=0,facing=south]", + "127:1": "cocoa[age=0,facing=west]", + "127:2": "cocoa[age=0,facing=north]", + "127:3": "cocoa[age=0,facing=east]", + "127:4": "cocoa[age=1,facing=south]", + "127:5": "cocoa[age=1,facing=west]", + "127:6": "cocoa[age=1,facing=north]", + "127:7": "cocoa[age=1,facing=east]", + "127:8": "cocoa[age=2,facing=south]", + "127:9": "cocoa[age=2,facing=west]", + "127:10": "cocoa[age=2,facing=north]", + "127:11": "cocoa[age=2,facing=east]", + "128:0": "sandstone_stairs[facing=east,half=bottom,shape=straight]", + "128:1": "sandstone_stairs[facing=west,half=bottom,shape=straight]", + "128:2": "sandstone_stairs[facing=south,half=bottom,shape=straight]", + "128:3": "sandstone_stairs[facing=north,half=bottom,shape=straight]", + "128:4": "sandstone_stairs[facing=east,half=top,shape=straight]", + "128:5": "sandstone_stairs[facing=west,half=top,shape=straight]", + "128:6": "sandstone_stairs[facing=south,half=top,shape=straight]", + "128:7": "sandstone_stairs[facing=north,half=top,shape=straight]", + "129:0": "emerald_ore", + "130:2": "ender_chest[facing=north]", + "130:3": "ender_chest[facing=south]", + "130:4": "ender_chest[facing=west]", + "130:5": "ender_chest[facing=east]", + "131:0": "tripwire_hook[attached=false,facing=south,powered=false]", + "131:1": "tripwire_hook[attached=false,facing=west,powered=false]", + "131:2": "tripwire_hook[attached=false,facing=north,powered=false]", + "131:3": "tripwire_hook[attached=false,facing=east,powered=false]", + "131:4": "tripwire_hook[attached=true,facing=south,powered=false]", + "131:5": "tripwire_hook[attached=true,facing=west,powered=false]", + "131:6": "tripwire_hook[attached=true,facing=north,powered=false]", + "131:7": "tripwire_hook[attached=true,facing=east,powered=false]", + "131:8": "tripwire_hook[attached=false,facing=south,powered=true]", + "131:9": "tripwire_hook[attached=false,facing=west,powered=true]", + "131:10": "tripwire_hook[attached=false,facing=north,powered=true]", + "131:11": "tripwire_hook[attached=false,facing=east,powered=true]", + "131:12": "tripwire_hook[attached=true,facing=south,powered=true]", + "131:13": "tripwire_hook[attached=true,facing=west,powered=true]", + "131:14": "tripwire_hook[attached=true,facing=north,powered=true]", + "131:15": "tripwire_hook[attached=true,facing=east,powered=true]", + "132:0": "tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]", + "132:1": "tripwire[attached=false,disarmed=false,east=false,north=false,powered=true,south=false,west=false]", + "132:4": "tripwire[attached=true,disarmed=false,east=false,north=false,powered=false,south=false,west=false]", + "132:5": "tripwire[attached=true,disarmed=false,east=false,north=false,powered=true,south=false,west=false]", + "132:8": "tripwire[attached=false,disarmed=true,east=false,north=false,powered=false,south=false,west=false]", + "132:9": "tripwire[attached=false,disarmed=true,east=false,north=false,powered=true,south=false,west=false]", + "132:12": "tripwire[attached=true,disarmed=true,east=false,north=false,powered=false,south=false,west=false]", + "132:13": "tripwire[attached=true,disarmed=true,east=false,north=false,powered=true,south=false,west=false]", + "133:0": "emerald_block", + "134:0": "spruce_stairs[facing=east,half=bottom,shape=straight]", + "134:1": "spruce_stairs[facing=west,half=bottom,shape=straight]", + "134:2": "spruce_stairs[facing=south,half=bottom,shape=straight]", + "134:3": "spruce_stairs[facing=north,half=bottom,shape=straight]", + "134:4": "spruce_stairs[facing=east,half=top,shape=straight]", + "134:5": "spruce_stairs[facing=west,half=top,shape=straight]", + "134:6": "spruce_stairs[facing=south,half=top,shape=straight]", + "134:7": "spruce_stairs[facing=north,half=top,shape=straight]", + "135:0": "birch_stairs[facing=east,half=bottom,shape=straight]", + "135:1": "birch_stairs[facing=west,half=bottom,shape=straight]", + "135:2": "birch_stairs[facing=south,half=bottom,shape=straight]", + "135:3": "birch_stairs[facing=north,half=bottom,shape=straight]", + "135:4": "birch_stairs[facing=east,half=top,shape=straight]", + "135:5": "birch_stairs[facing=west,half=top,shape=straight]", + "135:6": "birch_stairs[facing=south,half=top,shape=straight]", + "135:7": "birch_stairs[facing=north,half=top,shape=straight]", + "136:0": "jungle_stairs[facing=east,half=bottom,shape=straight]", + "136:1": "jungle_stairs[facing=west,half=bottom,shape=straight]", + "136:2": "jungle_stairs[facing=south,half=bottom,shape=straight]", + "136:3": "jungle_stairs[facing=north,half=bottom,shape=straight]", + "136:4": "jungle_stairs[facing=east,half=top,shape=straight]", + "136:5": "jungle_stairs[facing=west,half=top,shape=straight]", + "136:6": "jungle_stairs[facing=south,half=top,shape=straight]", + "136:7": "jungle_stairs[facing=north,half=top,shape=straight]", + "137:0": "command_block[conditional=false,facing=down]", + "137:1": "command_block[conditional=false,facing=up]", + "137:2": "command_block[conditional=false,facing=north]", + "137:3": "command_block[conditional=false,facing=south]", + "137:4": "command_block[conditional=false,facing=west]", + "137:5": "command_block[conditional=false,facing=east]", + "137:8": "command_block[conditional=true,facing=down]", + "137:9": "command_block[conditional=true,facing=up]", + "137:10": "command_block[conditional=true,facing=north]", + "137:11": "command_block[conditional=true,facing=south]", + "137:12": "command_block[conditional=true,facing=west]", + "137:13": "command_block[conditional=true,facing=east]", + "138:0": "beacon", + "139:0": "cobblestone_wall[east=false,north=false,south=false,up=false,west=false]", + "139:1": "mossy_cobblestone_wall[east=false,north=false,south=false,up=false,west=false]", + "140:0": "potted_cactus", + "140:1": "potted_cactus", + "140:2": "potted_cactus", + "140:3": "potted_cactus", + "140:4": "potted_cactus", + "140:5": "potted_cactus", + "140:6": "potted_cactus", + "140:7": "potted_cactus", + "140:8": "potted_cactus", + "140:9": "potted_cactus", + "140:10": "potted_cactus", + "140:11": "potted_cactus", + "140:12": "potted_cactus", + "140:13": "potted_cactus", + "140:14": "potted_cactus", + "140:15": "potted_cactus", + "141:0": "carrots[age=0]", + "141:1": "carrots[age=1]", + "141:2": "carrots[age=2]", + "141:3": "carrots[age=3]", + "141:4": "carrots[age=4]", + "141:5": "carrots[age=5]", + "141:6": "carrots[age=6]", + "141:7": "carrots[age=7]", + "142:0": "potatoes[age=0]", + "142:1": "potatoes[age=1]", + "142:2": "potatoes[age=2]", + "142:3": "potatoes[age=3]", + "142:4": "potatoes[age=4]", + "142:5": "potatoes[age=5]", + "142:6": "potatoes[age=6]", + "142:7": "potatoes[age=7]", + "143:0": "oak_button[face=ceiling,facing=north,powered=false]", + "143:1": "oak_button[face=wall,facing=east,powered=false]", + "143:2": "oak_button[face=wall,facing=west,powered=false]", + "143:3": "oak_button[face=wall,facing=south,powered=false]", + "143:4": "oak_button[face=wall,facing=north,powered=false]", + "143:5": "oak_button[face=floor,facing=north,powered=false]", + "143:8": "oak_button[face=ceiling,facing=north,powered=true]", + "143:9": "oak_button[face=wall,facing=east,powered=true]", + "143:10": "oak_button[face=wall,facing=west,powered=true]", + "143:11": "oak_button[face=wall,facing=south,powered=true]", + "143:12": "oak_button[face=wall,facing=north,powered=true]", + "143:13": "oak_button[face=floor,facing=north,powered=true]", + "144:0": "undefined[facing=down,nodrop=false]", + "144:1": "undefined[facing=up,nodrop=false]", + "144:2": "undefined[facing=north,nodrop=false]", + "144:3": "undefined[facing=south,nodrop=false]", + "144:4": "undefined[facing=west,nodrop=false]", + "144:5": "undefined[facing=east,nodrop=false]", + "144:8": "undefined[facing=down,nodrop=true]", + "144:9": "undefined[facing=up,nodrop=true]", + "144:10": "undefined[facing=north,nodrop=true]", + "144:11": "undefined[facing=south,nodrop=true]", + "144:12": "undefined[facing=west,nodrop=true]", + "144:13": "undefined[facing=east,nodrop=true]", + "145:0": "anvil[facing=south]", + "145:1": "anvil[facing=west]", + "145:2": "anvil[facing=north]", + "145:3": "anvil[facing=east]", + "145:4": "chipped_anvil[facing=south]", + "145:5": "chipped_anvil[facing=west]", + "145:6": "chipped_anvil[facing=north]", + "145:7": "chipped_anvil[facing=east]", + "145:8": "damaged_anvil[facing=south]", + "145:9": "damaged_anvil[facing=west]", + "145:10": "damaged_anvil[facing=north]", + "145:11": "damaged_anvil[facing=east]", + "146:2": "trapped_chest[facing=north,type=single]", + "146:3": "trapped_chest[facing=south,type=single]", + "146:4": "trapped_chest[facing=west,type=single]", + "146:5": "trapped_chest[facing=east,type=single]", + "147:0": "light_weighted_pressure_plate[power=0]", + "147:1": "light_weighted_pressure_plate[power=1]", + "147:2": "light_weighted_pressure_plate[power=2]", + "147:3": "light_weighted_pressure_plate[power=3]", + "147:4": "light_weighted_pressure_plate[power=4]", + "147:5": "light_weighted_pressure_plate[power=5]", + "147:6": "light_weighted_pressure_plate[power=6]", + "147:7": "light_weighted_pressure_plate[power=7]", + "147:8": "light_weighted_pressure_plate[power=8]", + "147:9": "light_weighted_pressure_plate[power=9]", + "147:10": "light_weighted_pressure_plate[power=10]", + "147:11": "light_weighted_pressure_plate[power=11]", + "147:12": "light_weighted_pressure_plate[power=12]", + "147:13": "light_weighted_pressure_plate[power=13]", + "147:14": "light_weighted_pressure_plate[power=14]", + "147:15": "light_weighted_pressure_plate[power=15]", + "148:0": "heavy_weighted_pressure_plate[power=0]", + "148:1": "heavy_weighted_pressure_plate[power=1]", + "148:2": "heavy_weighted_pressure_plate[power=2]", + "148:3": "heavy_weighted_pressure_plate[power=3]", + "148:4": "heavy_weighted_pressure_plate[power=4]", + "148:5": "heavy_weighted_pressure_plate[power=5]", + "148:6": "heavy_weighted_pressure_plate[power=6]", + "148:7": "heavy_weighted_pressure_plate[power=7]", + "148:8": "heavy_weighted_pressure_plate[power=8]", + "148:9": "heavy_weighted_pressure_plate[power=9]", + "148:10": "heavy_weighted_pressure_plate[power=10]", + "148:11": "heavy_weighted_pressure_plate[power=11]", + "148:12": "heavy_weighted_pressure_plate[power=12]", + "148:13": "heavy_weighted_pressure_plate[power=13]", + "148:14": "heavy_weighted_pressure_plate[power=14]", + "148:15": "heavy_weighted_pressure_plate[power=15]", + "149:0": "comparator[facing=south,mode=compare,powered=false]", + "149:1": "comparator[facing=west,mode=compare,powered=false]", + "149:2": "comparator[facing=north,mode=compare,powered=false]", + "149:3": "comparator[facing=east,mode=compare,powered=false]", + "149:4": "comparator[facing=south,mode=subtract,powered=false]", + "149:5": "comparator[facing=west,mode=subtract,powered=false]", + "149:6": "comparator[facing=north,mode=subtract,powered=false]", + "149:7": "comparator[facing=east,mode=subtract,powered=false]", + "149:8": "comparator[facing=south,mode=compare,powered=true]", + "149:9": "comparator[facing=west,mode=compare,powered=true]", + "149:10": "comparator[facing=north,mode=compare,powered=true]", + "149:11": "comparator[facing=east,mode=compare,powered=true]", + "149:12": "comparator[facing=south,mode=subtract,powered=true]", + "149:13": "comparator[facing=west,mode=subtract,powered=true]", + "149:14": "comparator[facing=north,mode=subtract,powered=true]", + "149:15": "comparator[facing=east,mode=subtract,powered=true]", + "150:0": "comparator[facing=south,mode=compare,powered=false]", + "150:1": "comparator[facing=west,mode=compare,powered=false]", + "150:2": "comparator[facing=north,mode=compare,powered=false]", + "150:3": "comparator[facing=east,mode=compare,powered=false]", + "150:4": "comparator[facing=south,mode=subtract,powered=false]", + "150:5": "comparator[facing=west,mode=subtract,powered=false]", + "150:6": "comparator[facing=north,mode=subtract,powered=false]", + "150:7": "comparator[facing=east,mode=subtract,powered=false]", + "150:8": "comparator[facing=south,mode=compare,powered=true]", + "150:9": "comparator[facing=west,mode=compare,powered=true]", + "150:10": "comparator[facing=north,mode=compare,powered=true]", + "150:11": "comparator[facing=east,mode=compare,powered=true]", + "150:12": "comparator[facing=south,mode=subtract,powered=true]", + "150:13": "comparator[facing=west,mode=subtract,powered=true]", + "150:14": "comparator[facing=north,mode=subtract,powered=true]", + "150:15": "comparator[facing=east,mode=subtract,powered=true]", + "151:0": "daylight_detector[inverted=false,power=0]", + "151:1": "daylight_detector[inverted=false,power=1]", + "151:2": "daylight_detector[inverted=false,power=2]", + "151:3": "daylight_detector[inverted=false,power=3]", + "151:4": "daylight_detector[inverted=false,power=4]", + "151:5": "daylight_detector[inverted=false,power=5]", + "151:6": "daylight_detector[inverted=false,power=6]", + "151:7": "daylight_detector[inverted=false,power=7]", + "151:8": "daylight_detector[inverted=false,power=8]", + "151:9": "daylight_detector[inverted=false,power=9]", + "151:10": "daylight_detector[inverted=false,power=10]", + "151:11": "daylight_detector[inverted=false,power=11]", + "151:12": "daylight_detector[inverted=false,power=12]", + "151:13": "daylight_detector[inverted=false,power=13]", + "151:14": "daylight_detector[inverted=false,power=14]", + "151:15": "daylight_detector[inverted=false,power=15]", + "152:0": "redstone_block", + "153:0": "nether_quartz_ore", + "154:0": "hopper[enabled=true,facing=down]", + "154:2": "hopper[enabled=true,facing=north]", + "154:3": "hopper[enabled=true,facing=south]", + "154:4": "hopper[enabled=true,facing=west]", + "154:5": "hopper[enabled=true,facing=east]", + "154:8": "hopper[enabled=false,facing=down]", + "154:10": "hopper[enabled=false,facing=north]", + "154:11": "hopper[enabled=false,facing=south]", + "154:12": "hopper[enabled=false,facing=west]", + "154:13": "hopper[enabled=false,facing=east]", + "155:0": "quartz_block", + "155:1": "chiseled_quartz_block", + "155:2": "quartz_pillar[axis=y]", + "155:3": "quartz_pillar[axis=x]", + "155:4": "quartz_pillar[axis=z]", + "156:0": "quartz_stairs[facing=east,half=bottom,shape=straight]", + "156:1": "quartz_stairs[facing=west,half=bottom,shape=straight]", + "156:2": "quartz_stairs[facing=south,half=bottom,shape=straight]", + "156:3": "quartz_stairs[facing=north,half=bottom,shape=straight]", + "156:4": "quartz_stairs[facing=east,half=top,shape=straight]", + "156:5": "quartz_stairs[facing=west,half=top,shape=straight]", + "156:6": "quartz_stairs[facing=south,half=top,shape=straight]", + "156:7": "quartz_stairs[facing=north,half=top,shape=straight]", + "157:0": "activator_rail[powered=false,shape=north_south]", + "157:1": "activator_rail[powered=false,shape=east_west]", + "157:2": "activator_rail[powered=false,shape=ascending_east]", + "157:3": "activator_rail[powered=false,shape=ascending_west]", + "157:4": "activator_rail[powered=false,shape=ascending_north]", + "157:5": "activator_rail[powered=false,shape=ascending_south]", + "157:8": "activator_rail[powered=true,shape=north_south]", + "157:9": "activator_rail[powered=true,shape=east_west]", + "157:10": "activator_rail[powered=true,shape=ascending_east]", + "157:11": "activator_rail[powered=true,shape=ascending_west]", + "157:12": "activator_rail[powered=true,shape=ascending_north]", + "157:13": "activator_rail[powered=true,shape=ascending_south]", + "158:0": "dropper[facing=down,triggered=false]", + "158:1": "dropper[facing=up,triggered=false]", + "158:2": "dropper[facing=north,triggered=false]", + "158:3": "dropper[facing=south,triggered=false]", + "158:4": "dropper[facing=west,triggered=false]", + "158:5": "dropper[facing=east,triggered=false]", + "158:8": "dropper[facing=down,triggered=true]", + "158:9": "dropper[facing=up,triggered=true]", + "158:10": "dropper[facing=north,triggered=true]", + "158:11": "dropper[facing=south,triggered=true]", + "158:12": "dropper[facing=west,triggered=true]", + "158:13": "dropper[facing=east,triggered=true]", + "159:0": "white_terracotta", + "159:1": "orange_terracotta", + "159:2": "magenta_terracotta", + "159:3": "light_blue_terracotta", + "159:4": "yellow_terracotta", + "159:5": "lime_terracotta", + "159:6": "pink_terracotta", + "159:7": "gray_terracotta", + "159:8": "light_gray_terracotta", + "159:9": "cyan_terracotta", + "159:10": "purple_terracotta", + "159:11": "blue_terracotta", + "159:12": "brown_terracotta", + "159:13": "green_terracotta", + "159:14": "red_terracotta", + "159:15": "black_terracotta", + "160:0": "white_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:1": "orange_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:2": "magenta_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:3": "light_blue_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:4": "yellow_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:5": "lime_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:6": "pink_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:7": "gray_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:8": "light_gray_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:9": "cyan_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:10": "purple_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:11": "blue_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:12": "brown_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:13": "green_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:14": "red_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:15": "black_stained_glass_pane[east=false,north=false,south=false,west=false]", + "161:0": "acacia_leaves[check_decay=false,decayable=true]", + "161:1": "dark_oak_leaves[check_decay=false,decayable=true]", + "161:4": "acacia_leaves[check_decay=false,decayable=false]", + "161:5": "dark_oak_leaves[check_decay=false,decayable=false]", + "161:8": "acacia_leaves[check_decay=true,decayable=true]", + "161:9": "dark_oak_leaves[check_decay=true,decayable=true]", + "161:12": "acacia_leaves[check_decay=true,decayable=false]", + "161:13": "dark_oak_leaves[check_decay=true,decayable=false]", + "162:0": "acacia_log[axis=y]", + "162:1": "dark_oak_log[axis=y]", + "162:4": "acacia_log[axis=x]", + "162:5": "dark_oak_log[axis=x]", + "162:8": "acacia_log[axis=z]", + "162:9": "dark_oak_log[axis=z]", + "162:12": "acacia_bark", + "162:13": "dark_oak_bark", + "163:0": "acacia_stairs[facing=east,half=bottom,shape=straight]", + "163:1": "acacia_stairs[facing=west,half=bottom,shape=straight]", + "163:2": "acacia_stairs[facing=south,half=bottom,shape=straight]", + "163:3": "acacia_stairs[facing=north,half=bottom,shape=straight]", + "163:4": "acacia_stairs[facing=east,half=top,shape=straight]", + "163:5": "acacia_stairs[facing=west,half=top,shape=straight]", + "163:6": "acacia_stairs[facing=south,half=top,shape=straight]", + "163:7": "acacia_stairs[facing=north,half=top,shape=straight]", + "164:0": "dark_oak_stairs[facing=east,half=bottom,shape=straight]", + "164:1": "dark_oak_stairs[facing=west,half=bottom,shape=straight]", + "164:2": "dark_oak_stairs[facing=south,half=bottom,shape=straight]", + "164:3": "dark_oak_stairs[facing=north,half=bottom,shape=straight]", + "164:4": "dark_oak_stairs[facing=east,half=top,shape=straight]", + "164:5": "dark_oak_stairs[facing=west,half=top,shape=straight]", + "164:6": "dark_oak_stairs[facing=south,half=top,shape=straight]", + "164:7": "dark_oak_stairs[facing=north,half=top,shape=straight]", + "165:0": "slime_block", + "166:0": "barrier", + "167:0": "iron_trapdoor[facing=north,half=bottom,open=false]", + "167:1": "iron_trapdoor[facing=south,half=bottom,open=false]", + "167:2": "iron_trapdoor[facing=west,half=bottom,open=false]", + "167:3": "iron_trapdoor[facing=east,half=bottom,open=false]", + "167:4": "iron_trapdoor[facing=north,half=bottom,open=true]", + "167:5": "iron_trapdoor[facing=south,half=bottom,open=true]", + "167:6": "iron_trapdoor[facing=west,half=bottom,open=true]", + "167:7": "iron_trapdoor[facing=east,half=bottom,open=true]", + "167:8": "iron_trapdoor[facing=north,half=top,open=false]", + "167:9": "iron_trapdoor[facing=south,half=top,open=false]", + "167:10": "iron_trapdoor[facing=west,half=top,open=false]", + "167:11": "iron_trapdoor[facing=east,half=top,open=false]", + "167:12": "iron_trapdoor[facing=north,half=top,open=true]", + "167:13": "iron_trapdoor[facing=south,half=top,open=true]", + "167:14": "iron_trapdoor[facing=west,half=top,open=true]", + "167:15": "iron_trapdoor[facing=east,half=top,open=true]", + "168:0": "prismarine", + "168:1": "prismarine_bricks", + "168:2": "dark_prismarine", + "169:0": "sea_lantern", + "170:0": "hay_block[axis=y]", + "170:4": "hay_block[axis=x]", + "170:8": "hay_block[axis=z]", + "171:0": "white_carpet", + "171:1": "orange_carpet", + "171:2": "magenta_carpet", + "171:3": "light_blue_carpet", + "171:4": "yellow_carpet", + "171:5": "lime_carpet", + "171:6": "pink_carpet", + "171:7": "gray_carpet", + "171:8": "light_gray_carpet", + "171:9": "cyan_carpet", + "171:10": "purple_carpet", + "171:11": "blue_carpet", + "171:12": "brown_carpet", + "171:13": "green_carpet", + "171:14": "red_carpet", + "171:15": "black_carpet", + "172:0": "terracotta", + "173:0": "coal_block", + "174:0": "packed_ice", + "175:0": "sunflower[half=lower]", + "175:1": "lilac[half=lower]", + "175:2": "tall_grass[half=lower]", + "175:3": "large_fern[half=lower]", + "175:4": "rose_bush[half=lower]", + "175:5": "peony[half=lower]", + "175:8": "peony[half=upper]", + "175:9": "peony[half=upper]", + "175:10": "peony[half=upper]", + "175:11": "peony[half=upper]", + "176:0": "white_banner[rotation=0]", + "176:1": "white_banner[rotation=1]", + "176:2": "white_banner[rotation=2]", + "176:3": "white_banner[rotation=3]", + "176:4": "white_banner[rotation=4]", + "176:5": "white_banner[rotation=5]", + "176:6": "white_banner[rotation=6]", + "176:7": "white_banner[rotation=7]", + "176:8": "white_banner[rotation=8]", + "176:9": "white_banner[rotation=9]", + "176:10": "white_banner[rotation=10]", + "176:11": "white_banner[rotation=11]", + "176:12": "white_banner[rotation=12]", + "176:13": "white_banner[rotation=13]", + "176:14": "white_banner[rotation=14]", + "176:15": "white_banner[rotation=15]", + "177:2": "white_wall_banner[facing=north]", + "177:3": "white_wall_banner[facing=south]", + "177:4": "white_wall_banner[facing=west]", + "177:5": "white_wall_banner[facing=east]", + "178:0": "daylight_detector[inverted=true,power=0]", + "178:1": "daylight_detector[inverted=true,power=1]", + "178:2": "daylight_detector[inverted=true,power=2]", + "178:3": "daylight_detector[inverted=true,power=3]", + "178:4": "daylight_detector[inverted=true,power=4]", + "178:5": "daylight_detector[inverted=true,power=5]", + "178:6": "daylight_detector[inverted=true,power=6]", + "178:7": "daylight_detector[inverted=true,power=7]", + "178:8": "daylight_detector[inverted=true,power=8]", + "178:9": "daylight_detector[inverted=true,power=9]", + "178:10": "daylight_detector[inverted=true,power=10]", + "178:11": "daylight_detector[inverted=true,power=11]", + "178:12": "daylight_detector[inverted=true,power=12]", + "178:13": "daylight_detector[inverted=true,power=13]", + "178:14": "daylight_detector[inverted=true,power=14]", + "178:15": "daylight_detector[inverted=true,power=15]", + "179:0": "red_sandstone", + "179:1": "chiseled_red_sandstone", + "179:2": "cut_red_sandstone", + "180:0": "red_sandstone_stairs[facing=east,half=bottom,shape=straight]", + "180:1": "red_sandstone_stairs[facing=west,half=bottom,shape=straight]", + "180:2": "red_sandstone_stairs[facing=south,half=bottom,shape=straight]", + "180:3": "red_sandstone_stairs[facing=north,half=bottom,shape=straight]", + "180:4": "red_sandstone_stairs[facing=east,half=top,shape=straight]", + "180:5": "red_sandstone_stairs[facing=west,half=top,shape=straight]", + "180:6": "red_sandstone_stairs[facing=south,half=top,shape=straight]", + "180:7": "red_sandstone_stairs[facing=north,half=top,shape=straight]", + "181:0": "red_sandstone_slab[type=double]", + "181:8": "smooth_red_sandstone", + "182:0": "red_sandstone_slab[type=bottom]", + "182:8": "red_sandstone_slab[type=top]", + "183:0": "spruce_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "183:1": "spruce_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "183:2": "spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "183:3": "spruce_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "183:4": "spruce_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "183:5": "spruce_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "183:6": "spruce_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "183:7": "spruce_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "183:8": "spruce_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "183:9": "spruce_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "183:10": "spruce_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "183:11": "spruce_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "183:12": "spruce_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "183:13": "spruce_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "183:14": "spruce_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "183:15": "spruce_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "184:0": "birch_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "184:1": "birch_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "184:2": "birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "184:3": "birch_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "184:4": "birch_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "184:5": "birch_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "184:6": "birch_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "184:7": "birch_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "184:8": "birch_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "184:9": "birch_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "184:10": "birch_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "184:11": "birch_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "184:12": "birch_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "184:13": "birch_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "184:14": "birch_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "184:15": "birch_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "185:0": "jungle_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "185:1": "jungle_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "185:2": "jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "185:3": "jungle_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "185:4": "jungle_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "185:5": "jungle_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "185:6": "jungle_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "185:7": "jungle_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "185:8": "jungle_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "185:9": "jungle_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "185:10": "jungle_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "185:11": "jungle_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "185:12": "jungle_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "185:13": "jungle_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "185:14": "jungle_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "185:15": "jungle_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "186:0": "dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "186:1": "dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "186:2": "dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "186:3": "dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "186:4": "dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "186:5": "dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "186:6": "dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "186:7": "dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "186:8": "dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "186:9": "dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "186:10": "dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "186:11": "dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "186:12": "dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "186:13": "dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "186:14": "dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "186:15": "dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "187:0": "acacia_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "187:1": "acacia_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "187:2": "acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "187:3": "acacia_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "187:4": "acacia_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "187:5": "acacia_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "187:6": "acacia_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "187:7": "acacia_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "187:8": "acacia_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "187:9": "acacia_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "187:10": "acacia_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "187:11": "acacia_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "187:12": "acacia_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "187:13": "acacia_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "187:14": "acacia_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "187:15": "acacia_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "188:0": "spruce_fence[east=false,north=false,south=false,west=false]", + "189:0": "birch_fence[east=false,north=false,south=false,west=false]", + "190:0": "jungle_fence[east=false,north=false,south=false,west=false]", + "191:0": "dark_oak_fence[east=false,north=false,south=false,west=false]", + "192:0": "acacia_fence[east=false,north=false,south=false,west=false]", + "193:0": "spruce_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "193:1": "spruce_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "193:2": "spruce_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "193:3": "spruce_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "193:4": "spruce_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "193:5": "spruce_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "193:6": "spruce_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "193:7": "spruce_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "193:8": "spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "193:9": "spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "193:10": "spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "193:11": "spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "194:0": "birch_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "194:1": "birch_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "194:2": "birch_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "194:3": "birch_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "194:4": "birch_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "194:5": "birch_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "194:6": "birch_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "194:7": "birch_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "194:8": "birch_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "194:9": "birch_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "194:10": "birch_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "194:11": "birch_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "195:0": "jungle_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "195:1": "jungle_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "195:2": "jungle_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "195:3": "jungle_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "195:4": "jungle_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "195:5": "jungle_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "195:6": "jungle_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "195:7": "jungle_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "195:8": "jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "195:9": "jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "195:10": "jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "195:11": "jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "196:0": "acacia_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "196:1": "acacia_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "196:2": "acacia_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "196:3": "acacia_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "196:4": "acacia_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "196:5": "acacia_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "196:6": "acacia_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "196:7": "acacia_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "196:8": "acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "196:9": "acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "196:10": "acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "196:11": "acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "197:0": "dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "197:1": "dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "197:2": "dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "197:3": "dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "197:4": "dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "197:5": "dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "197:6": "dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "197:7": "dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "197:8": "dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "197:9": "dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "197:10": "dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "197:11": "dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "198:0": "end_rod[facing=down]", + "198:1": "end_rod[facing=up]", + "198:2": "end_rod[facing=north]", + "198:3": "end_rod[facing=south]", + "198:4": "end_rod[facing=west]", + "198:5": "end_rod[facing=east]", + "199:0": "chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]", + "200:0": "chorus_flower[age=0]", + "200:1": "chorus_flower[age=1]", + "200:2": "chorus_flower[age=2]", + "200:3": "chorus_flower[age=3]", + "200:4": "chorus_flower[age=4]", + "200:5": "chorus_flower[age=5]", + "201:0": "purpur_block", + "202:0": "purpur_pillar[axis=y]", + "202:4": "purpur_pillar[axis=x]", + "202:8": "purpur_pillar[axis=z]", + "203:0": "purpur_stairs[facing=east,half=bottom,shape=straight]", + "203:1": "purpur_stairs[facing=west,half=bottom,shape=straight]", + "203:2": "purpur_stairs[facing=south,half=bottom,shape=straight]", + "203:3": "purpur_stairs[facing=north,half=bottom,shape=straight]", + "203:4": "purpur_stairs[facing=east,half=top,shape=straight]", + "203:5": "purpur_stairs[facing=west,half=top,shape=straight]", + "203:6": "purpur_stairs[facing=south,half=top,shape=straight]", + "203:7": "purpur_stairs[facing=north,half=top,shape=straight]", + "204:0": "purpur_slab[type=double]", + "205:0": "purpur_slab[type=bottom]", + "205:8": "purpur_slab[type=top]", + "206:0": "end_stone_bricks", + "207:0": "beetroots[age=0]", + "207:1": "beetroots[age=1]", + "207:2": "beetroots[age=2]", + "207:3": "beetroots[age=3]", + "208:0": "grass_path", + "209:0": "end_gateway", + "210:0": "repeating_command_block[conditional=false,facing=down]", + "210:1": "repeating_command_block[conditional=false,facing=up]", + "210:2": "repeating_command_block[conditional=false,facing=north]", + "210:3": "repeating_command_block[conditional=false,facing=south]", + "210:4": "repeating_command_block[conditional=false,facing=west]", + "210:5": "repeating_command_block[conditional=false,facing=east]", + "210:8": "repeating_command_block[conditional=true,facing=down]", + "210:9": "repeating_command_block[conditional=true,facing=up]", + "210:10": "repeating_command_block[conditional=true,facing=north]", + "210:11": "repeating_command_block[conditional=true,facing=south]", + "210:12": "repeating_command_block[conditional=true,facing=west]", + "210:13": "repeating_command_block[conditional=true,facing=east]", + "211:0": "chain_command_block[conditional=false,facing=down]", + "211:1": "chain_command_block[conditional=false,facing=up]", + "211:2": "chain_command_block[conditional=false,facing=north]", + "211:3": "chain_command_block[conditional=false,facing=south]", + "211:4": "chain_command_block[conditional=false,facing=west]", + "211:5": "chain_command_block[conditional=false,facing=east]", + "211:8": "chain_command_block[conditional=true,facing=down]", + "211:9": "chain_command_block[conditional=true,facing=up]", + "211:10": "chain_command_block[conditional=true,facing=north]", + "211:11": "chain_command_block[conditional=true,facing=south]", + "211:12": "chain_command_block[conditional=true,facing=west]", + "211:13": "chain_command_block[conditional=true,facing=east]", + "212:0": "frosted_ice[age=0]", + "212:1": "frosted_ice[age=1]", + "212:2": "frosted_ice[age=2]", + "212:3": "frosted_ice[age=3]", + "213:0": "magma_block", + "214:0": "nether_wart_block", + "215:0": "red_nether_bricks", + "216:0": "bone_block[axis=y]", + "216:4": "bone_block[axis=x]", + "216:8": "bone_block[axis=z]", + "217:0": "structure_void", + "218:0": "observer[facing=down,powered=false]", + "218:1": "observer[facing=up,powered=false]", + "218:2": "observer[facing=north,powered=false]", + "218:3": "observer[facing=south,powered=false]", + "218:4": "observer[facing=west,powered=false]", + "218:5": "observer[facing=east,powered=false]", + "218:8": "observer[facing=down,powered=true]", + "218:9": "observer[facing=up,powered=true]", + "218:10": "observer[facing=north,powered=true]", + "218:11": "observer[facing=south,powered=true]", + "218:12": "observer[facing=west,powered=true]", + "218:13": "observer[facing=east,powered=true]", + "219:0": "white_shulker_box[facing=down]", + "219:1": "white_shulker_box[facing=up]", + "219:2": "white_shulker_box[facing=north]", + "219:3": "white_shulker_box[facing=south]", + "219:4": "white_shulker_box[facing=west]", + "219:5": "white_shulker_box[facing=east]", + "220:0": "orange_shulker_box[facing=down]", + "220:1": "orange_shulker_box[facing=up]", + "220:2": "orange_shulker_box[facing=north]", + "220:3": "orange_shulker_box[facing=south]", + "220:4": "orange_shulker_box[facing=west]", + "220:5": "orange_shulker_box[facing=east]", + "221:0": "magenta_shulker_box[facing=down]", + "221:1": "magenta_shulker_box[facing=up]", + "221:2": "magenta_shulker_box[facing=north]", + "221:3": "magenta_shulker_box[facing=south]", + "221:4": "magenta_shulker_box[facing=west]", + "221:5": "magenta_shulker_box[facing=east]", + "222:0": "light_blue_shulker_box[facing=down]", + "222:1": "light_blue_shulker_box[facing=up]", + "222:2": "light_blue_shulker_box[facing=north]", + "222:3": "light_blue_shulker_box[facing=south]", + "222:4": "light_blue_shulker_box[facing=west]", + "222:5": "light_blue_shulker_box[facing=east]", + "223:0": "yellow_shulker_box[facing=down]", + "223:1": "yellow_shulker_box[facing=up]", + "223:2": "yellow_shulker_box[facing=north]", + "223:3": "yellow_shulker_box[facing=south]", + "223:4": "yellow_shulker_box[facing=west]", + "223:5": "yellow_shulker_box[facing=east]", + "224:0": "lime_shulker_box[facing=down]", + "224:1": "lime_shulker_box[facing=up]", + "224:2": "lime_shulker_box[facing=north]", + "224:3": "lime_shulker_box[facing=south]", + "224:4": "lime_shulker_box[facing=west]", + "224:5": "lime_shulker_box[facing=east]", + "225:0": "pink_shulker_box[facing=down]", + "225:1": "pink_shulker_box[facing=up]", + "225:2": "pink_shulker_box[facing=north]", + "225:3": "pink_shulker_box[facing=south]", + "225:4": "pink_shulker_box[facing=west]", + "225:5": "pink_shulker_box[facing=east]", + "226:0": "gray_shulker_box[facing=down]", + "226:1": "gray_shulker_box[facing=up]", + "226:2": "gray_shulker_box[facing=north]", + "226:3": "gray_shulker_box[facing=south]", + "226:4": "gray_shulker_box[facing=west]", + "226:5": "gray_shulker_box[facing=east]", + "227:0": "light_gray_shulker_box[facing=down]", + "227:1": "light_gray_shulker_box[facing=up]", + "227:2": "light_gray_shulker_box[facing=north]", + "227:3": "light_gray_shulker_box[facing=south]", + "227:4": "light_gray_shulker_box[facing=west]", + "227:5": "light_gray_shulker_box[facing=east]", + "228:0": "cyan_shulker_box[facing=down]", + "228:1": "cyan_shulker_box[facing=up]", + "228:2": "cyan_shulker_box[facing=north]", + "228:3": "cyan_shulker_box[facing=south]", + "228:4": "cyan_shulker_box[facing=west]", + "228:5": "cyan_shulker_box[facing=east]", + "229:0": "purple_shulker_box[facing=down]", + "229:1": "purple_shulker_box[facing=up]", + "229:2": "purple_shulker_box[facing=north]", + "229:3": "purple_shulker_box[facing=south]", + "229:4": "purple_shulker_box[facing=west]", + "229:5": "purple_shulker_box[facing=east]", + "230:0": "blue_shulker_box[facing=down]", + "230:1": "blue_shulker_box[facing=up]", + "230:2": "blue_shulker_box[facing=north]", + "230:3": "blue_shulker_box[facing=south]", + "230:4": "blue_shulker_box[facing=west]", + "230:5": "blue_shulker_box[facing=east]", + "231:0": "brown_shulker_box[facing=down]", + "231:1": "brown_shulker_box[facing=up]", + "231:2": "brown_shulker_box[facing=north]", + "231:3": "brown_shulker_box[facing=south]", + "231:4": "brown_shulker_box[facing=west]", + "231:5": "brown_shulker_box[facing=east]", + "232:0": "green_shulker_box[facing=down]", + "232:1": "green_shulker_box[facing=up]", + "232:2": "green_shulker_box[facing=north]", + "232:3": "green_shulker_box[facing=south]", + "232:4": "green_shulker_box[facing=west]", + "232:5": "green_shulker_box[facing=east]", + "233:0": "red_shulker_box[facing=down]", + "233:1": "red_shulker_box[facing=up]", + "233:2": "red_shulker_box[facing=north]", + "233:3": "red_shulker_box[facing=south]", + "233:4": "red_shulker_box[facing=west]", + "233:5": "red_shulker_box[facing=east]", + "234:0": "black_shulker_box[facing=down]", + "234:1": "black_shulker_box[facing=up]", + "234:2": "black_shulker_box[facing=north]", + "234:3": "black_shulker_box[facing=south]", + "234:4": "black_shulker_box[facing=west]", + "234:5": "black_shulker_box[facing=east]", + "235:0": "white_glazed_terracotta[facing=south]", + "235:1": "white_glazed_terracotta[facing=west]", + "235:2": "white_glazed_terracotta[facing=north]", + "235:3": "white_glazed_terracotta[facing=east]", + "236:0": "orange_glazed_terracotta[facing=south]", + "236:1": "orange_glazed_terracotta[facing=west]", + "236:2": "orange_glazed_terracotta[facing=north]", + "236:3": "orange_glazed_terracotta[facing=east]", + "237:0": "magenta_glazed_terracotta[facing=south]", + "237:1": "magenta_glazed_terracotta[facing=west]", + "237:2": "magenta_glazed_terracotta[facing=north]", + "237:3": "magenta_glazed_terracotta[facing=east]", + "238:0": "light_blue_glazed_terracotta[facing=south]", + "238:1": "light_blue_glazed_terracotta[facing=west]", + "238:2": "light_blue_glazed_terracotta[facing=north]", + "238:3": "light_blue_glazed_terracotta[facing=east]", + "239:0": "yellow_glazed_terracotta[facing=south]", + "239:1": "yellow_glazed_terracotta[facing=west]", + "239:2": "yellow_glazed_terracotta[facing=north]", + "239:3": "yellow_glazed_terracotta[facing=east]", + "240:0": "lime_glazed_terracotta[facing=south]", + "240:1": "lime_glazed_terracotta[facing=west]", + "240:2": "lime_glazed_terracotta[facing=north]", + "240:3": "lime_glazed_terracotta[facing=east]", + "241:0": "pink_glazed_terracotta[facing=south]", + "241:1": "pink_glazed_terracotta[facing=west]", + "241:2": "pink_glazed_terracotta[facing=north]", + "241:3": "pink_glazed_terracotta[facing=east]", + "242:0": "gray_glazed_terracotta[facing=south]", + "242:1": "gray_glazed_terracotta[facing=west]", + "242:2": "gray_glazed_terracotta[facing=north]", + "242:3": "gray_glazed_terracotta[facing=east]", + "243:0": "light_gray_glazed_terracotta[facing=south]", + "243:1": "light_gray_glazed_terracotta[facing=west]", + "243:2": "light_gray_glazed_terracotta[facing=north]", + "243:3": "light_gray_glazed_terracotta[facing=east]", + "244:0": "cyan_glazed_terracotta[facing=south]", + "244:1": "cyan_glazed_terracotta[facing=west]", + "244:2": "cyan_glazed_terracotta[facing=north]", + "244:3": "cyan_glazed_terracotta[facing=east]", + "245:0": "purple_glazed_terracotta[facing=south]", + "245:1": "purple_glazed_terracotta[facing=west]", + "245:2": "purple_glazed_terracotta[facing=north]", + "245:3": "purple_glazed_terracotta[facing=east]", + "246:0": "blue_glazed_terracotta[facing=south]", + "246:1": "blue_glazed_terracotta[facing=west]", + "246:2": "blue_glazed_terracotta[facing=north]", + "246:3": "blue_glazed_terracotta[facing=east]", + "247:0": "brown_glazed_terracotta[facing=south]", + "247:1": "brown_glazed_terracotta[facing=west]", + "247:2": "brown_glazed_terracotta[facing=north]", + "247:3": "brown_glazed_terracotta[facing=east]", + "248:0": "green_glazed_terracotta[facing=south]", + "248:1": "green_glazed_terracotta[facing=west]", + "248:2": "green_glazed_terracotta[facing=north]", + "248:3": "green_glazed_terracotta[facing=east]", + "249:0": "red_glazed_terracotta[facing=south]", + "249:1": "red_glazed_terracotta[facing=west]", + "249:2": "red_glazed_terracotta[facing=north]", + "249:3": "red_glazed_terracotta[facing=east]", + "250:0": "black_glazed_terracotta[facing=south]", + "250:1": "black_glazed_terracotta[facing=west]", + "250:2": "black_glazed_terracotta[facing=north]", + "250:3": "black_glazed_terracotta[facing=east]", + "251:0": "white_concrete", + "251:1": "orange_concrete", + "251:2": "magenta_concrete", + "251:3": "light_blue_concrete", + "251:4": "yellow_concrete", + "251:5": "lime_concrete", + "251:6": "pink_concrete", + "251:7": "gray_concrete", + "251:8": "light_gray_concrete", + "251:9": "cyan_concrete", + "251:10": "purple_concrete", + "251:11": "blue_concrete", + "251:12": "brown_concrete", + "251:13": "green_concrete", + "251:14": "red_concrete", + "251:15": "black_concrete", + "252:0": "white_concrete_powder", + "252:1": "orange_concrete_powder", + "252:2": "magenta_concrete_powder", + "252:3": "light_blue_concrete_powder", + "252:4": "yellow_concrete_powder", + "252:5": "lime_concrete_powder", + "252:6": "pink_concrete_powder", + "252:7": "gray_concrete_powder", + "252:8": "light_gray_concrete_powder", + "252:9": "cyan_concrete_powder", + "252:10": "purple_concrete_powder", + "252:11": "blue_concrete_powder", + "252:12": "brown_concrete_powder", + "252:13": "green_concrete_powder", + "252:14": "red_concrete_powder", + "252:15": "black_concrete_powder", + "255:0": "structure_block[mode=save]", + "255:1": "structure_block[mode=load]", + "255:2": "structure_block[mode=corner]", + "255:3": "structure_block[mode=data]" + }, + "clientCalculatedBlocks": { + "block_snowy": [ + "grass_block", + "dirt", + "coarse_dirt", + "podzol", + "mycelium" + ], + "directional": [ + "fire", + "redstone_wire", + "oak_fence", + "iron_bars", + "glass_pane", + "vine", + "nether_brick_fence", + "tripwire", + "cobblestone_wall", + "mossy_cobblestone_wall", + "white_stained_glass_pane", + "orange_stained_glass_pane", + "magenta_stained_glass_pane", + "light_blue_stained_glass_pane", + "yellow_stained_glass_pane", + "lime_stained_glass_pane", + "pink_stained_glass_pane", + "gray_stained_glass_pane", + "light_gray_stained_glass_pane", + "cyan_stained_glass_pane", + "purple_stained_glass_pane", + "blue_stained_glass_pane", + "brown_stained_glass_pane", + "green_stained_glass_pane", + "red_stained_glass_pane", + "black_stained_glass_pane", + "spruce_fence", + "birch_fence", + "jungle_fence", + "dark_oak_fence", + "acacia_fence", + "chorus_plant" + ], + "door": [ + "oak_door", + "iron_door", + "spruce_door", + "birch_door", + "jungle_door", + "acacia_door", + "dark_oak_door" + ], + "repeater_locked": [ + "repeater" + ], + "gate_in_wall": [ + "oak_fence_gate", + "spruce_fence_gate", + "birch_fence_gate", + "jungle_fence_gate", + "dark_oak_fence_gate", + "acacia_fence_gate" + ] + } +} From 93e9cf877b5de2cc9409fa9920db14d6d0abd525 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 06:01:14 +0300 Subject: [PATCH 007/107] fix project build on windows --- scripts/esbuildPlugins.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 49547ea1..f6b539c1 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -7,8 +7,9 @@ import { filesize } from 'filesize' import MCProtocol from 'minecraft-protocol' import MCData from 'minecraft-data' import { throttle } from 'lodash-es' +import { fileURLToPath } from 'url' -const __dirname = dirname(new URL(import.meta.url).pathname) +const __dirname = dirname(fileURLToPath(new URL(import.meta.url))) const { supportedVersions } = MCProtocol const prod = process.argv.includes('--prod') From b6cb302457ab232200e34e1a165dc7aff0f1a832 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 20 May 2024 06:11:09 +0300 Subject: [PATCH 008/107] fix build! --- src/flyingSquidUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index bd312bfb..1f070022 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -33,7 +33,6 @@ export const saveServer = async (autoSave = true) => { export const disconnect = async () => { if (localServer) { await saveServer() - //@ts-expect-error todo expose! void localServer.quit() // todo investigate we should await } window.history.replaceState({}, '', `${window.location.pathname}`) // remove qs From 0dfa7c3c9a283bc96a248333bcc40f098e5df18b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 20 May 2024 06:17:47 +0300 Subject: [PATCH 009/107] fix: fix default gamepad bindings of nextHotbarSlot, prevHotbarSlot --- src/controls.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 7d1e4cdf..b23d3beb 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -39,8 +39,8 @@ export const contro = new ControMax({ sneak: ['ShiftLeft'], toggleSneakOrDown: [null, 'Right Stick'], sprint: ['ControlLeft', 'Left Stick'], - nextHotbarSlot: [null, 'Left Bumper'], - prevHotbarSlot: [null, 'Right Bumper'], + nextHotbarSlot: [null, 'Right Bumper'], + prevHotbarSlot: [null, 'Left Bumper'], attackDestroy: [null, 'Right Trigger'], interactPlace: [null, 'Left Trigger'], chat: [['KeyT', 'Enter']], From 2a2667918b3cbfb0d4a028934d7d18641973bab3 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 21 May 2024 05:25:14 +0300 Subject: [PATCH 010/107] feat: limit rendering in background to 20fps so it uses less resources (+setting to control that) --- prismarine-viewer/viewer/lib/viewerWrapper.ts | 12 ++++++----- src/index.ts | 1 + src/optionsGuiScheme.tsx | 10 ++++++++++ src/optionsStorage.ts | 1 + src/react/OptionsItems.tsx | 20 ++++++++++++++++--- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/prismarine-viewer/viewer/lib/viewerWrapper.ts b/prismarine-viewer/viewer/lib/viewerWrapper.ts index c6419dff..b8017f38 100644 --- a/prismarine-viewer/viewer/lib/viewerWrapper.ts +++ b/prismarine-viewer/viewer/lib/viewerWrapper.ts @@ -5,9 +5,10 @@ export class ViewerWrapper { previousWindowWidth: number previousWindowHeight: number globalObject = globalThis as any - stopRenderOnBlur = true + stopRenderOnBlur = false addedToPage = false renderInterval = 0 + renderIntervalUnfocused: number | undefined fpsInterval constructor(public canvas: HTMLCanvasElement, public renderer?: THREE.WebGLRenderer) { @@ -44,7 +45,7 @@ export class ViewerWrapper { this.globalObject.requestAnimationFrame(this.render.bind(this)) } if (typeof window !== 'undefined') { - // this.trackWindowFocus() + this.trackWindowFocus() } } @@ -77,11 +78,12 @@ export class ViewerWrapper { for (const fn of beforeRenderFrame) fn() this.globalObject.requestAnimationFrame(this.render.bind(this)) if (this.globalObject.stopRender || this.renderer?.xr.isPresenting || (this.stopRenderOnBlur && !this.windowFocused)) return - if (this.renderInterval) { + const renderInterval = (this.windowFocused ? this.renderInterval : this.renderIntervalUnfocused) ?? this.renderInterval + if (renderInterval) { this.delta += time - this.lastTime this.lastTime = time - if (this.delta > this.renderInterval) { - this.delta %= this.renderInterval + if (this.delta > renderInterval) { + this.delta %= renderInterval // continue rendering } else { return diff --git a/src/index.ts b/src/index.ts index 8dbc46cf..1797c894 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,6 +120,7 @@ const renderWrapper = new ViewerWrapper(renderer.domElement, renderer) renderWrapper.addToPage() watchValue(options, (o) => { renderWrapper.renderInterval = o.frameLimit ? 1000 / o.frameLimit : 0 + renderWrapper.renderIntervalUnfocused = o.backgroundRendering === '5fps' ? 1000 / 5 : o.backgroundRendering === '20fps' ? 1000 / 20 : undefined }) const isFirefox = ua.getBrowser().name === 'Firefox' diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index b847fe11..46f258a8 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -43,6 +43,16 @@ export const guiOptionsScheme: { return + +} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index e384fbfd..d86cf202 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -38,6 +38,7 @@ import ServersListProvider from './react/ServersListProvider' import GamepadUiCursor from './react/GamepadUiCursor' import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' +import BedTime from './react/BedTime' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -116,6 +117,7 @@ const InGameUi = () => { + diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 2e20de29..85884b2f 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -14,7 +14,7 @@ import destroyStage9 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/de import { Vec3 } from 'vec3' import { LineMaterial, Wireframe, LineSegmentsGeometry } from 'three-stdlib' -import { isGameActive } from './globalState' +import { hideCurrentModal, isGameActive, showModal } from './globalState' import { assertDefined } from './utils' import { options } from './optionsStorage' @@ -201,7 +201,29 @@ class WorldInteraction { 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', ].includes(bot.heldItem.name) - if (cursorBlock && !activate) { + let stop = false + if (!bot.controlState.sneak) { + if (cursorBlock?.name === 'bed' || cursorBlock?.name.endsWith('_bed')) { + stop = true + showModal({ reactType: 'bed' }) + let cancelSleep = true + void bot.sleep(cursorBlock).catch((e) => { + if (cancelSleep) { + hideCurrentModal() + } + // if (e.message === 'bot is not sleeping') return + bot._client.emit('chat', { + message: JSON.stringify({ + text: e.message, + }) + }) + }) + setTimeout(() => { + cancelSleep = false + }) + } + } + if (cursorBlock && !activate && !stop) { const vecArray = [new Vec3(0, -1, 0), new Vec3(0, 1, 0), new Vec3(0, 0, -1), new Vec3(0, 0, 1), new Vec3(-1, 0, 0), new Vec3(1, 0, 0)] //@ts-expect-error const delta = cursorBlock.intersect.minus(cursorBlock.position) @@ -219,7 +241,7 @@ class WorldInteraction { bot.lookAt = oldLookAt }).catch(console.warn) } - } else { + } else if (!stop) { bot.activateItem() // todo offhand } this.lastBlockPlaced = 0 From bb85512cc10636e73ddb26b9e9bcfb40bde1fce1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 22 May 2024 04:26:33 +0300 Subject: [PATCH 015/107] update known block are not rendered test --- .../viewer/lib/mesher/test/tests.test.ts | 237 +++++++++++------- .../viewer/prepare/moreGeneratedBlocks.ts | 1 + 2 files changed, 153 insertions(+), 85 deletions(-) diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 22e3a7b2..75dd98fa 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -1,96 +1,163 @@ import { test, expect } from 'vitest' import { setup } from './mesherTester' +import minecraftData from 'minecraft-data' +import minecraftAssets from 'minecraft-assets' -const version = '1.18.1' +const version = minecraftAssets.versions.at(-1) const addPositions = [ - // [[0, 0, 0], 'diamond_block'], - [[1, 0, 0], 'stone'], - [[-1, 0, 0], 'stone'], - [[0, 1, 0], 'stone'], - [[0, -1, 0], 'stone'], - [[0, 0, 1], 'stone'], - [[0, 0, -1], 'stone'], + // [[0, 0, 0], 'diamond_block'], + // [[1, 0, 0], 'stone'], + // [[-1, 0, 0], 'stone'], + // [[0, 1, 0], 'stone'], + // [[0, -1, 0], 'stone'], + // [[0, 0, 1], 'stone'], + // [[0, 0, -1], 'stone'], ] as const test('Known blocks are not rendered', () => { - const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any) + const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any) + const ignoreAsExpected = ['air', 'cave_air', 'void_air', 'barrier', 'water', 'lava', 'moving_piston', 'light'] - let time = 0 - let times = 0 - const invalidBlocks = {}/* as {[number, number]} */ - for (const block of mcData.blocksArray) { - if (block.maxStateId! - block.minStateId! > 100) continue - for (let i = block.minStateId!; i <= block.maxStateId!; i++) { - if (block.transparent) continue - mesherWorld.setBlockStateId(pos, i) - const start = performance.now() - const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry() - time += performance.now() - start - times++ - if (centerFaces === 0 && centerTileNeighbors !== 0) { - if (invalidBlocks[block.name]) continue - invalidBlocks[block.name] = [i - block.minStateId!, centerTileNeighbors] - // console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId) - } - } - } - console.log('Average time', time / times) - // Fully expected - expect(invalidBlocks).toMatchInlineSnapshot(` - { - "creeper_head": [ - 0, - 6, - ], - "creeper_wall_head": [ - 0, - 6, - ], - "dragon_head": [ - 0, - 6, - ], - "dragon_wall_head": [ - 0, - 6, - ], - "player_head": [ - 0, - 6, - ], - "player_wall_head": [ - 0, - 6, - ], - "powder_snow": [ - 0, - 6, - ], - "skeleton_skull": [ - 0, - 6, - ], - "skeleton_wall_skull": [ - 0, - 6, - ], - "wither_skeleton_skull": [ - 0, - 6, - ], - "wither_skeleton_wall_skull": [ - 0, - 6, - ], - "zombie_head": [ - 0, - 6, - ], - "zombie_wall_head": [ - 0, - 6, - ], + let time = 0 + let times = 0 + const invalidBlocks = {}/* as {[number, number]} */ + for (const block of mcData.blocksArray) { + if (ignoreAsExpected.includes(block.name)) continue + // if (block.maxStateId! - block.minStateId! > 100) continue + // for (let i = block.minStateId!; i <= block.maxStateId!; i++) { + for (let i = block.defaultState!; i <= block.defaultState!; i++) { + // if (block.transparent) continue + mesherWorld.setBlockStateId(pos, i) + const start = performance.now() + const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry() + time += performance.now() - start + times++ + if (centerFaces === 0) { + if (invalidBlocks[block.name]) continue + invalidBlocks[block.name] = true + // invalidBlocks[block.name] = [i - block.defaultState!, centerTileNeighbors] + // console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId) } - `) + } + } + console.log('Average time', time / times) + // should be fixed, but to avoid regressions & for visibility + expect(invalidBlocks).toMatchInlineSnapshot(` + { + "acacia_hanging_sign": true, + "acacia_wall_hanging_sign": true, + "bamboo_hanging_sign": true, + "bamboo_wall_hanging_sign": true, + "birch_hanging_sign": true, + "birch_wall_hanging_sign": true, + "black_banner": true, + "black_bed": true, + "black_candle": true, + "black_wall_banner": true, + "blue_banner": true, + "blue_bed": true, + "blue_candle": true, + "blue_wall_banner": true, + "brown_banner": true, + "brown_bed": true, + "brown_candle": true, + "brown_wall_banner": true, + "bubble_column": true, + "candle": true, + "cherry_hanging_sign": true, + "cherry_wall_hanging_sign": true, + "creeper_head": true, + "creeper_wall_head": true, + "crimson_hanging_sign": true, + "crimson_wall_hanging_sign": true, + "cyan_banner": true, + "cyan_bed": true, + "cyan_candle": true, + "cyan_wall_banner": true, + "dark_oak_hanging_sign": true, + "dark_oak_wall_hanging_sign": true, + "decorated_pot": true, + "dragon_head": true, + "dragon_wall_head": true, + "end_gateway": true, + "end_portal": true, + "gray_banner": true, + "gray_bed": true, + "gray_candle": true, + "gray_wall_banner": true, + "green_banner": true, + "green_bed": true, + "green_candle": true, + "green_wall_banner": true, + "jungle_hanging_sign": true, + "jungle_wall_hanging_sign": true, + "light_blue_banner": true, + "light_blue_bed": true, + "light_blue_candle": true, + "light_blue_wall_banner": true, + "light_gray_banner": true, + "light_gray_bed": true, + "light_gray_candle": true, + "light_gray_wall_banner": true, + "lime_banner": true, + "lime_bed": true, + "lime_candle": true, + "lime_wall_banner": true, + "magenta_banner": true, + "magenta_bed": true, + "magenta_candle": true, + "magenta_wall_banner": true, + "mangrove_hanging_sign": true, + "mangrove_wall_hanging_sign": true, + "oak_hanging_sign": true, + "oak_wall_hanging_sign": true, + "orange_banner": true, + "orange_bed": true, + "orange_candle": true, + "orange_wall_banner": true, + "piglin_head": true, + "piglin_wall_head": true, + "pink_banner": true, + "pink_bed": true, + "pink_candle": true, + "pink_petals": true, + "pink_wall_banner": true, + "player_head": true, + "player_wall_head": true, + "powder_snow_cauldron": true, + "purple_banner": true, + "purple_bed": true, + "purple_candle": true, + "purple_wall_banner": true, + "red_banner": true, + "red_bed": true, + "red_candle": true, + "red_wall_banner": true, + "repeater": true, + "sea_pickle": true, + "skeleton_skull": true, + "skeleton_wall_skull": true, + "snow": true, + "spruce_hanging_sign": true, + "spruce_wall_hanging_sign": true, + "structure_void": true, + "turtle_egg": true, + "warped_hanging_sign": true, + "warped_wall_hanging_sign": true, + "water_cauldron": true, + "white_banner": true, + "white_bed": true, + "white_candle": true, + "white_wall_banner": true, + "wither_skeleton_skull": true, + "wither_skeleton_wall_skull": true, + "yellow_banner": true, + "yellow_bed": true, + "yellow_candle": true, + "yellow_wall_banner": true, + "zombie_head": true, + "zombie_wall_head": true, + } + `) }) diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index e0d2ef41..24b85cc3 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -419,6 +419,7 @@ const handlers = [ [/(.+)_wall_sign$/, handleSign], [/(.+)_sign$/, handleSign], [/^(?:(ender|trapped)_)?chest$/, handleChest], + // [/(^|(.+)_)bed$/, handleBed], // no-op just suppress warning [/(^light|^moving_piston$)/, true], ] as const From 893f6182413e8ea5fef964a5a59897fb4be1e455 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 23 May 2024 00:54:41 +0300 Subject: [PATCH 016/107] hotfix starfield crash (#127) --- prismarine-viewer/viewer/lib/worldrendererThree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index acf0e7bf..24b6a28a 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -323,7 +323,7 @@ class StarField { const clock = new THREE.Clock(); this.points.onBeforeRender = (renderer, scene, camera) => { - this.points!.position.copy(camera.position) + this.points?.position.copy?.(camera.position) material.uniforms.time.value = clock.getElapsedTime() * speed } } From c1d7d7c33f68c46f1a51cd33ba975251bc6bf77f Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Thu, 23 May 2024 09:46:59 +0400 Subject: [PATCH 017/107] feat: Support for binds with modifiers (#130) Co-authored-by: gguio --- package.json | 2 +- pnpm-lock.yaml | 64 ++++++++++++++++++++++++++++----- src/controls.ts | 24 ++++++------- src/react/KeybindingsScreen.tsx | 32 +++++++++++++---- 4 files changed, 94 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 6e73b981..9451b266 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.7", + "contro-max": "^0.1.8", "crypto-browserify": "^3.12.0", "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d784e17..8d34f233 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.7 - version: 0.1.7(typescript@5.5.0-beta) + specifier: ^0.1.8 + version: 0.1.8(typescript@5.5.0-beta) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -3808,8 +3808,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - contro-max@0.1.7: - resolution: {integrity: sha512-HIYF1Dl50tUyTKaDsX+mPMDv2OjleNMVedYuBTX0n1wKNm9WxjWu2w74ATjz/8fHVL9GgmziIxAlFStd2je6kg==} + contro-max@0.1.8: + resolution: {integrity: sha512-5SoeudO8Zzfj/gbFTDrMRFJny02+MY1lBtb2NyCNiBLtHAfvhWZxZs/Z3yJvKL2rY/qKUZs9gTQOIDygBcBrdw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} convert-source-map@1.9.0: @@ -6043,6 +6043,11 @@ packages: resolution: {integrity: sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==} engines: {node: '>=14'} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc: + resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc} + version: 1.47.0 + engines: {node: '>=14'} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7} version: 1.47.0 @@ -6717,6 +6722,11 @@ packages: prismarine-chat@1.9.1: resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16} + version: 1.35.0 + engines: {node: '>=14'} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f: resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f} version: 1.35.0 @@ -11936,11 +11946,11 @@ snapshots: flatmap: 0.0.3 long: 5.2.3 minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -12839,7 +12849,7 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.7(typescript@5.5.0-beta): + contro-max@0.1.8(typescript@5.5.0-beta): dependencies: events: 3.3.0 lodash-es: 4.17.21 @@ -13206,7 +13216,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) random-seed: 0.3.0 vec3: 0.1.8 @@ -15700,6 +15710,31 @@ snapshots: - encoding - supports-color + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): + dependencies: + '@types/readable-stream': 4.0.12 + aes-js: 3.1.2 + buffer-equal: 1.0.1 + debug: 4.3.4(supports-color@8.1.1) + endian-toggle: 0.0.0 + lodash.get: 4.4.2 + lodash.merge: 4.6.2 + minecraft-data: 3.65.0 + minecraft-folder-path: 1.2.0 + node-fetch: 2.7.0(encoding@0.1.13) + node-rsa: 0.4.2 + prismarine-auth: 2.4.2(encoding@0.1.13) + prismarine-chat: 1.10.1 + prismarine-nbt: 2.5.0 + prismarine-realms: 1.3.2(encoding@0.1.13) + protodef: 1.15.0 + readable-stream: 4.5.2 + uuid-1345: 1.0.2 + yggdrasil: 1.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + - supports-color + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): dependencies: '@types/readable-stream': 4.0.12 @@ -16520,6 +16555,19 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0): + dependencies: + prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-nbt: 2.5.0 + prismarine-registry: 1.7.0 + smart-buffer: 4.2.0 + uint4: 0.1.2 + vec3: 0.1.8 + xxhash-wasm: 0.4.2 + transitivePeerDependencies: + - minecraft-data + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) diff --git a/src/controls.ts b/src/controls.ts index 847741cf..f940d59d 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -6,7 +6,7 @@ import { proxy, subscribe } from 'valtio' import { ControMax } from 'contro-max/build/controMax' import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types' import { stringStartsWith } from 'contro-max/build/stringUtils' -import { UserOverridesConfig } from 'contro-max/build/types/store' +import { UserOverrideCommand, UserOverridesConfig } from 'contro-max/build/types/store' import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' @@ -19,6 +19,7 @@ import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' +import { updateBinds } from './react/KeybindingsScreenProvider' export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig @@ -86,7 +87,7 @@ export const contro = new ControMax({ window.controMax = contro export type Command = CommandEventArgument['command'] -// updateCustomBinds() +updateBinds(customKeymaps) const updateDoPreventDefault = () => { controlOptions.preventDefault = miscUiState.gameLoaded && !activeModalStack.length @@ -296,19 +297,18 @@ function cycleHotbarSlot (dir: 1 | -1) { bot.setQuickBarSlot(newHotbarSlot) } -// custom commands hamdler -const customCommandsHandler = (buttonData: { code?: string, button?: string, state: boolean }) => { - if (!buttonData.state || !isGameActive(true)) return +// custom commands handler +const customCommandsHandler = ({ command }) => { + const [section, name] = command.split('.') + if (!isGameActive(true) || section !== 'custom') return - const codeOrButton = buttonData.code ?? buttonData.button - const inputType = buttonData.code ? 'keys' : 'gamepad' - for (const value of Object.values(contro.userConfig!.custom ?? {})) { - if (value[inputType]?.includes(codeOrButton!)) { - customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) - } + if (contro.userConfig?.custom) { + customCommandsConfig[(contro.userConfig.custom[name] as CustomCommand).type].handler( + (contro.userConfig.custom[name] as CustomCommand).inputs + ) } } -contro.on('pressedKeyOrButtonChanged', customCommandsHandler) +contro.on('trigger', customCommandsHandler) contro.on('trigger', ({ command }) => { const willContinue = !isGameActive(true) diff --git a/src/react/KeybindingsScreen.tsx b/src/react/KeybindingsScreen.tsx index 57d7d7ef..2de24de8 100644 --- a/src/react/KeybindingsScreen.tsx +++ b/src/react/KeybindingsScreen.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef, createContext, useContext } from 'react' import { UserOverridesConfig } from 'contro-max/build/types/store' +import { ModifierOnlyKeys } from 'contro-max/build/types/keyCodes' import { contro as controEx } from '../controls' import { hideModal } from '../globalState' import triangle from './ps_icons/playstation_triangle_console_controller_gamepad_icon.svg' @@ -96,22 +97,35 @@ export default ( updateBindMap() }, [userConfig]) - const updateBinding = (data) => { - if (data.state === true || !awaitingInputType) return + const updateBinding = (data: any) => { + if ((!data.state && awaitingInputType) || !awaitingInputType) { + setAwaitingInputType(null) + return + } + + if ('code' in data) { + if (data.state && [...contro.pressedKeys].includes(data.code)) return + if (data.code === 'Escape' || ['Mouse0', 'Mouse1', 'Mouse2'].includes(data.code)) { setAwaitingInputType(null) return } - setBinding({ code: data.code, state: true }, groupName, actionName, buttonNum) + const pressedModifiers = [...contro.pressedKeys].filter( + key => /^(Meta|Control|Alt|Shift)?$/.test(key) + ) + setBinding( + { code: pressedModifiers.length ? `${pressedModifiers[0]}+${data.code}` : data.code, state: true }, + groupName, + actionName, + buttonNum + ) } if ('button' in data) { contro.enabled = false void Promise.resolve().then(() => { contro.enabled = true }) setBinding(data, groupName, actionName, buttonNum) } - - setAwaitingInputType(null) } const updateBindMap = () => { @@ -368,8 +382,12 @@ const parseActionName = (action: string) => { const parseBindingName = (binding: string | undefined) => { if (!binding) return '' const cut = binding.replaceAll(/(Numpad|Digit|Key)/g, '') - const parts = cut.split(/(?=[A-Z\d])/) - return parts.reverse().join(' ') + + const parts = cut.includes('+') ? cut.split('+') : [cut] + for (let i = 0; i < parts.length; i++) { + parts[i] = parts[i].split(/(?=[A-Z\d])/).reverse().join(' ') + } + return parts.join(' + ') } const buttonsMap = { From 1de6ae8f2c71cc8a2d2ebbb9029c962dfe079f61 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:19:33 +0300 Subject: [PATCH 018/107] fix: Fix crash in getItemUv function. now dropped items are always displayed --- src/index.ts | 39 ++++++++++++++++++++++++-------------- src/react/ChatProvider.tsx | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1797c894..89baaa10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -142,24 +142,35 @@ new THREE.TextureLoader().load(itemsPng, (texture) => { viewer.entities.itemsTexture = texture // todo unify viewer.entities.getItemUv = (id) => { - const name = loadedData.items[id]?.name - const uv = itemsAtlases.latest.textures[name] - if (!uv) { - const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] - if (!variant) return - const uvBlock = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces?.north.texture - if (!uvBlock) return + try { + const name = loadedData.items[id]?.name + const uv = itemsAtlases.latest.textures[name] + if (!uv) { + const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] + if (!variant) return + const faces = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces + const uvBlock = faces?.north?.texture ?? faces?.up?.texture ?? faces?.down?.texture ?? faces?.west?.texture ?? faces?.east?.texture ?? faces?.south?.texture + if (!uvBlock) return + return { + ...uvBlock, + size: Math.abs(uvBlock.su), + texture: viewer.world.material.map + } + } return { - ...uvBlock, - size: Math.abs(uvBlock.su), + ...uv, + size: itemsAtlases.latest.size, + texture: viewer.entities.itemsTexture + } + } catch (err) { + reportError?.(err) + return { + u: 0, + v: 0, + size: 16 / viewer.world.material.map!.image.width, texture: viewer.world.material.map } } - return { - ...uv, - size: itemsAtlases.latest.size, - texture: viewer.entities.itemsTexture - } } }) viewer.entities.entitiesOptions = { diff --git a/src/react/ChatProvider.tsx b/src/react/ChatProvider.tsx index 0322c60f..ad4a705d 100644 --- a/src/react/ChatProvider.tsx +++ b/src/react/ChatProvider.tsx @@ -74,7 +74,7 @@ export default () => { if (items[0].match) items = items.map(i => i.match) } if (completeValue === '/') { - if (!items[0].startsWith('/')) { + if (!items[0]?.startsWith('/')) { // normalize items = items.map(item => `/${item}`) } From 8fdcbdfc60bd42e769c4aa0895722f586690ecfe Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:21:41 +0300 Subject: [PATCH 019/107] fix: fix more starfield issues, make disableable --- .../viewer/lib/worldrendererThree.ts | 13 ++++++ src/entities.ts | 1 + src/optionsGuiScheme.tsx | 1 + src/optionsStorage.ts | 42 +++++++++++-------- src/watchOptions.ts | 5 +++ 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 24b6a28a..a2082a53 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -277,11 +277,23 @@ export class WorldRendererThree extends WorldRendererCommon { class StarField { points?: THREE.Points + private _enabled = true + get enabled () { + return this._enabled + } + set enabled (value) { + this._enabled = value + if (this.points) { + this.points.visible = value + } + } constructor(private scene: THREE.Scene) { } addToScene () { + if (this.points || !this.enabled) return + const radius = 80 const depth = 50 const count = 7000 @@ -332,6 +344,7 @@ class StarField { if (this.points) { this.points.geometry.dispose(); (this.points.material as THREE.Material).dispose(); + this.scene.remove(this.points) this.points = undefined; } diff --git a/src/entities.ts b/src/entities.ts index dbb59bed..b238d4ea 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -14,6 +14,7 @@ const updateAutoJump = () => { jumpOnAllEdges: options.autoParkour, // strictBlockCollision: true, }) + if (autoJump === bot.autoJumper.enabled) return if (autoJump) { bot.autoJumper.enable() } else { diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 46f258a8..88e6115f 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -69,6 +69,7 @@ export const guiOptionsScheme: { enableWarning: 'Enabling it will make chunks load ~4x slower', disabledDuringGame: true }, + starfieldRendering: {} }, ], main: [ diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 9350d5ab..ed71cfdb 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -30,24 +30,7 @@ const defaultOptions = { touchButtonsSize: 40, touchButtonsOpacity: 80, touchButtonsPosition: 12, - touchControlsPositions: { - action: [ - 70, - 85 - ], - sneak: [ - 90, - 85 - ], - break: [ - 70, - 65 - ], - jump: [ - 90, - 65 - ], - } as Record, + touchControlsPositions: getDefaultTouchControlsPositions(), touchControlsType: 'classic' as 'classic' | 'joystick-buttons', gpuPreference: 'default' as 'default' | 'high-performance' | 'low-power', backgroundRendering: '20fps' as 'full' | '20fps' | '5fps', @@ -59,6 +42,7 @@ const defaultOptions = { dayCycleAndLighting: true, loadPlayerSkins: true, lowMemoryMode: false, + starfieldRendering: true, // antiAliasing: false, showChunkBorders: false, // todo rename option @@ -73,6 +57,7 @@ const defaultOptions = { disableLoadPrompts: false, guestUsername: 'guest', askGuestName: true, + errorReporting: true, /** Actually might be useful */ showCursorBlockInSpectator: false, renderEntities: true, @@ -91,6 +76,27 @@ const defaultOptions = { wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never', } +function getDefaultTouchControlsPositions () { + return { + action: [ + 70, + 85 + ], + sneak: [ + 90, + 85 + ], + break: [ + 70, + 65 + ], + jump: [ + 90, + 65 + ], + } as Record +} + const qsOptionsRaw = new URLSearchParams(location.search).getAll('setting') export const qsOptions = Object.fromEntries(qsOptionsRaw.map(o => { const [key, value] = o.split(':') diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 56fc9c2c..4ff34be4 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -57,4 +57,9 @@ export const watchOptionsAfterViewerInit = () => { customEvents.on('gameLoaded', () => { viewer.world.mesherConfig.enableLighting = !bot.supportFeature('blockStateId') || options.newVersionsLighting }) + + watchValue(options, o => { + if (!(viewer.world instanceof WorldRendererThree)) return + viewer.world.starField.enabled = o.starfieldRendering + }) } From f2137d95a1a1ca0af04ebde6bd4c3b9194a1370f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:33:54 +0300 Subject: [PATCH 020/107] fix: fix critical memory leak block in the scene were not removed from the memory --- prismarine-viewer/viewer/lib/dispose.js | 6 ---- prismarine-viewer/viewer/lib/entities.js | 30 +++++++++---------- prismarine-viewer/viewer/lib/primitives.js | 7 ++--- prismarine-viewer/viewer/lib/threeJsUtils.ts | 13 ++++++++ .../viewer/lib/worldrendererThree.ts | 7 ++--- 5 files changed, 34 insertions(+), 29 deletions(-) delete mode 100644 prismarine-viewer/viewer/lib/dispose.js create mode 100644 prismarine-viewer/viewer/lib/threeJsUtils.ts diff --git a/prismarine-viewer/viewer/lib/dispose.js b/prismarine-viewer/viewer/lib/dispose.js deleted file mode 100644 index 15ec7b4b..00000000 --- a/prismarine-viewer/viewer/lib/dispose.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - dispose3 (o) { - o.geometry?.dispose() - o.dispose?.() - } -} diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 136c77fe..930f62c9 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -2,7 +2,6 @@ import * as THREE from 'three' import * as TWEEN from '@tweenjs/tween.js' import * as Entity from './entity/EntityMesh' -import { dispose3 } from './dispose' import nbt from 'prismarine-nbt' import EventEmitter from 'events' import { PlayerObject, PlayerAnimation } from 'skinview3d' @@ -14,10 +13,11 @@ import { NameTagObject } from 'skinview3d/libs/nametag' import { flat, fromFormattedString } from '@xmcl/text-component' import mojangson from 'mojangson' import externalTexturesJson from './entity/externalTextures.json' +import { disposeObject } from './threeJsUtils' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -61,7 +61,7 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -function getEntityMesh(entity, scene, options, overrides) { +function getEntityMesh (entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -105,15 +105,15 @@ export class Entities extends EventEmitter { this.getItemUv = undefined } - clear() { + clear () { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } this.entities = {} } - setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -125,14 +125,14 @@ export class Entities extends EventEmitter { } } - setVisible(visible, /** @type {THREE.Object3D?} */entity = null) { + setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { this.visible = visible for (const mesh of entity ? [entity] : Object.values(this.entities)) { mesh.visible = visible } } - render() { + render () { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -142,7 +142,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject(entityId) { + getPlayerObject (entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -152,7 +152,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -235,14 +235,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank(canvas) { + function isCanvasBlank (canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -262,14 +262,14 @@ export class Entities extends EventEmitter { } - displaySimpleText(jsonLike) { + displaySimpleText (jsonLike) { if (!jsonLike) return const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) const text = flat(parsed).map(x => x.text) return text.join('') } - update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true @@ -456,7 +456,7 @@ export class Entities extends EventEmitter { if (e.additionalCleanup) e.additionalCleanup() this.emit('remove', entity) this.scene.remove(e) - dispose3(e) + disposeObject(e) // todo dispose textures as well ? delete this.entities[entity.id] } diff --git a/prismarine-viewer/viewer/lib/primitives.js b/prismarine-viewer/viewer/lib/primitives.js index f206ee87..c8a0c006 100644 --- a/prismarine-viewer/viewer/lib/primitives.js +++ b/prismarine-viewer/viewer/lib/primitives.js @@ -1,6 +1,5 @@ const THREE = require('three') const { MeshLine, MeshLineMaterial } = require('three.meshline') -const { dispose3 } = require('./dispose') function getMesh (primitive, camera) { if (primitive.type === 'line') { @@ -48,7 +47,7 @@ function getMesh (primitive, camera) { } class Primitives { - constructor (scene, camera) { + constructor(scene, camera) { this.scene = scene this.camera = camera this.primitives = {} @@ -57,7 +56,7 @@ class Primitives { clear () { for (const mesh of Object.values(this.primitives)) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } this.primitives = {} } @@ -65,7 +64,7 @@ class Primitives { update (primitive) { if (this.primitives[primitive.id]) { this.scene.remove(this.primitives[primitive.id]) - dispose3(this.primitives[primitive.id]) + disposeObject(this.primitives[primitive.id]) delete this.primitives[primitive.id] } diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts new file mode 100644 index 00000000..f856c244 --- /dev/null +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -0,0 +1,13 @@ +import * as THREE from 'three'; + +export const disposeObject = (obj: THREE.Object3D) => { + if (!obj) return + // not cleaning texture there as it might be used by other objects, but would be good to also do that + if (obj instanceof THREE.Mesh) { + obj.geometry.dispose(); + obj.material.dispose(); + } + if (obj.children) { + obj.children.forEach(disposeObject); + } +} diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index a2082a53..60156a50 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -1,13 +1,13 @@ import * as THREE from 'three' import { Vec3 } from 'vec3' import nbt from 'prismarine-nbt' -import { dispose3 } from './dispose' import PrismarineChatLoader from 'prismarine-chat' import { renderSign } from '../sign-renderer/' import { chunkPos, sectionPos } from './simpleUtils' import { WorldRendererCommon, WorldRendererConfig } from './worldrendererCommon' import * as tweenJs from '@tweenjs/tween.js' import { BloomPass, RenderPass, UnrealBloomPass, EffectComposer, WaterPass, GlitchPass } from 'three-stdlib' +import { disposeObject } from './threeJsUtils' export class WorldRendererThree extends WorldRendererCommon { outputFormat = 'threeJs' as const @@ -62,7 +62,7 @@ export class WorldRendererThree extends WorldRendererCommon { let object: THREE.Object3D = this.sectionObjects[data.key] if (object) { this.scene.remove(object) - dispose3(object) + disposeObject(object) delete this.sectionObjects[data.key] } @@ -263,7 +263,7 @@ export class WorldRendererThree extends WorldRendererCommon { const mesh = this.sectionObjects[key] if (mesh) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } delete this.sectionObjects[key] } @@ -327,7 +327,6 @@ class StarField { material.blending = THREE.AdditiveBlending material.depthTest = false material.transparent = true - // material.unifo // Create points and add them to the scene this.points = new THREE.Points(geometry, material) From fcec85baa39f212a98e43a46b6bffa0eebc8455c Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 24 May 2024 10:21:03 +0300 Subject: [PATCH 021/107] feat: Make bow, foods cancellable and add use progression indicator feat: make item in offhand activatable --- prismarine-viewer/viewer/lib/threeJsUtils.ts | 5 +- src/react/Crosshair.css | 35 +++++++---- src/react/Crosshair.tsx | 64 +++++++++++++++++++- src/react/TitleProvider.tsx | 1 + src/worldInteractions.ts | 42 +++++++++---- 5 files changed, 121 insertions(+), 26 deletions(-) diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts index f856c244..e4f9404b 100644 --- a/prismarine-viewer/viewer/lib/threeJsUtils.ts +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -1,11 +1,10 @@ import * as THREE from 'three'; export const disposeObject = (obj: THREE.Object3D) => { - if (!obj) return // not cleaning texture there as it might be used by other objects, but would be good to also do that if (obj instanceof THREE.Mesh) { - obj.geometry.dispose(); - obj.material.dispose(); + obj.geometry?.dispose?.(); + obj.material?.dispose?.(); } if (obj.children) { obj.children.forEach(disposeObject); diff --git a/src/react/Crosshair.css b/src/react/Crosshair.css index 94252ffa..7076f475 100644 --- a/src/react/Crosshair.css +++ b/src/react/Crosshair.css @@ -1,12 +1,25 @@ .crosshair { - z-index: -1; - width: 16px; - height: 16px; - background: var(--gui-icons); - background-size: calc(256px * var(--crosshair-scale)); - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - image-rendering: pixelated; - } + z-index: -1; + width: 16px; + height: 16px; + background: var(--gui-icons); + background-size: calc(256px * var(--crosshair-scale)); + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + image-rendering: pixelated; + pointer-events: none; +} + +.crosshair-indicator { + z-index: -1; + width: var(--crosshair-indicator-size); + height: 1.5px; + position: fixed; + top: calc(50% + 8px); + left: 50%; + transform: translate(-50%, -50%); + background: lightgray; + pointer-events: none; +} diff --git a/src/react/Crosshair.tsx b/src/react/Crosshair.tsx index 877b8df4..ab289db8 100644 --- a/src/react/Crosshair.tsx +++ b/src/react/Crosshair.tsx @@ -1,8 +1,70 @@ +import { useEffect, useState } from 'react' import './Crosshair.css' +import { proxy, useSnapshot } from 'valtio' import SharedHudVars from './SharedHudVars' +// todo move to mineflayer +export const itemBeingUsed = proxy({ + name: null as string | null, + hand: 0 as 0 | 1 +}) + export default () => { + const { name: usingItem, hand } = useSnapshot(itemBeingUsed) + + const [displayIndicator, setDisplayIndicator] = useState(true) + const [indicatorProgress, setIndicatorProgress] = useState(0) + const [alternativeIndicator, setAlternativeIndicator] = useState(false) + const boxMaxTimeMs = 1000 + // todo add sword indicator + const indicatorSize = 20 + + useEffect(() => { + bot.on('heldItemChanged' as any, () => { + const displayBar = (item: import('prismarine-item').Item | null) => { + const itemName = item?.name + if (!itemName) return + return loadedData.foodsArray.map((food) => food.name).includes(itemName) || itemName === 'bow' || itemName === 'shield' || itemName === 'crossbow' + } + setDisplayIndicator(displayBar(bot.heldItem) || displayBar(bot.inventory.slots[45]) || false) + }) + }, []) + + useEffect(() => { + setAlternativeIndicator(usingItem === 'shield') + if (!usingItem) return + const startTime = Date.now() + let maxTime = 0 + if (usingItem === 'bow' || usingItem === 'crossbow') { + maxTime = 1000 + } + const isFood = loadedData.foodsArray.some((food) => food.name === usingItem) + if (isFood) { + maxTime = 32 * 50 + } + if (!maxTime) return + + const id = setInterval(() => { + const progress = (Date.now() - startTime) / boxMaxTimeMs + if (progress >= 1) { + clearInterval(id) + } else { + setIndicatorProgress(progress) + } + }, 1000 / 60) + return () => { + setIndicatorProgress(0) + clearInterval(id) + } + }, [usingItem]) + return -
+
+ {displayIndicator &&
} } diff --git a/src/react/TitleProvider.tsx b/src/react/TitleProvider.tsx index 151a93c1..f19669ec 100644 --- a/src/react/TitleProvider.tsx +++ b/src/react/TitleProvider.tsx @@ -23,6 +23,7 @@ export default () => { const [openActionBar, setOpenActionBar] = useState(false) useMemo(() => { + // todo move to mineflayer bot._client.on('set_title_text', (packet) => { setTitle(JSON.parse(packet.text)) setOpenTitle(true) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 85884b2f..239c02c2 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -17,6 +17,7 @@ import { LineMaterial, Wireframe, LineSegmentsGeometry } from 'three-stdlib' import { hideCurrentModal, isGameActive, showModal } from './globalState' import { assertDefined } from './utils' import { options } from './optionsStorage' +import { itemBeingUsed } from './react/Crosshair' function getViewDirection (pitch, yaw) { const csPitch = Math.cos(pitch) @@ -133,6 +134,9 @@ class WorldInteraction { } this.lastDugBlock = null }) + bot.on('heldItemChanged' as any, () => { + itemBeingUsed.name = null + }) const upLineMaterial = () => { const inCreative = bot.game.gameMode === 'creative' @@ -191,16 +195,20 @@ class WorldInteraction { // Place / interact / activate if (this.buttons[2] && this.lastBlockPlaced >= 4) { - const activate = bot.heldItem && ['egg', 'fishing_rod', 'firework_rocket', - 'fire_charge', 'snowball', 'ender_pearl', 'experience_bottle', 'potion', - 'glass_bottle', 'bucket', 'water_bucket', 'lava_bucket', 'milk_bucket', - 'minecart', 'boat', 'tnt_minecart', 'chest_minecart', 'hopper_minecart', - 'command_block_minecart', 'armor_stand', 'lead', 'name_tag', - // - 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', 'map', - 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', - 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', - ].includes(bot.heldItem.name) + const activatableItems = (itemName: string) => { + return ['egg', 'fishing_rod', 'firework_rocket', + 'fire_charge', 'snowball', 'ender_pearl', 'experience_bottle', 'potion', + 'glass_bottle', 'bucket', 'water_bucket', 'lava_bucket', 'milk_bucket', + 'minecart', 'boat', 'tnt_minecart', 'chest_minecart', 'hopper_minecart', + 'command_block_minecart', 'armor_stand', 'lead', 'name_tag', + // + 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', 'map', + 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', + 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', 'bow', 'crossbow', 'bucket_of_cod', + ...loadedData.foodsArray.map((f) => f.name), + ].includes(itemName) + } + const activate = bot.heldItem && activatableItems(bot.heldItem.name) let stop = false if (!bot.controlState.sneak) { if (cursorBlock?.name === 'bed' || cursorBlock?.name.endsWith('_bed')) { @@ -223,6 +231,7 @@ class WorldInteraction { }) } } + // todo placing with offhand if (cursorBlock && !activate && !stop) { const vecArray = [new Vec3(0, -1, 0), new Vec3(0, 1, 0), new Vec3(0, 0, -1), new Vec3(0, 0, 1), new Vec3(-1, 0, 0), new Vec3(1, 0, 0)] //@ts-expect-error @@ -242,10 +251,21 @@ class WorldInteraction { }).catch(console.warn) } } else if (!stop) { - bot.activateItem() // todo offhand + const offhand = activate ? false : activatableItems(bot.inventory.slots[45]?.name ?? '') + bot.activateItem(offhand) // todo offhand + itemBeingUsed.name = (offhand ? bot.inventory.slots[45]?.name : bot.heldItem?.name) ?? null + itemBeingUsed.hand = offhand ? 1 : 0 } this.lastBlockPlaced = 0 } + // stop using activated item (cancel) + if (itemBeingUsed.name && !this.buttons[2]) { + itemBeingUsed.name = null + // "only foods and bow can be deactivated" - not true, shields also can be deactivated and client always sends this + // if (bot.heldItem && (loadedData.foodsArray.map((f) => f.name).includes(bot.heldItem.name) || bot.heldItem.name === 'bow')) { + bot.deactivateItem() + // } + } // Stop break if ((!this.buttons[0] && this.lastButtons[0]) || cursorChanged) { From 87e724d5f6d7d4b8630a5f491857e8042f3206c6 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 24 May 2024 11:05:44 +0300 Subject: [PATCH 022/107] fix: fix offhand slot in hotbar display --- pnpm-lock.yaml | 8 ++++---- src/react/HotbarRenderApp.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d34f233..6fdf4afa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -299,7 +299,7 @@ importers: version: 1.0.0 minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next - version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0) + version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:PrismarineJS/mineflayer version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13) @@ -6035,8 +6035,8 @@ packages: minecraft-folder-path@1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c: - resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c} + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5: + resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5} version: 1.0.1 minecraft-protocol@1.47.0: @@ -15678,7 +15678,7 @@ snapshots: minecraft-folder-path@1.2.0: {} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0): + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0): dependencies: valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0) transitivePeerDependencies: diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 3b50f49b..02689485 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -93,7 +93,7 @@ export default () => { }, } as any) const { canvasManager } = inv - inv.inventory.supportsOffhand = bot.supportFeature('doesntHaveOffHandSlot') + inv.inventory.supportsOffhand = !bot.supportFeature('doesntHaveOffHandSlot') inv.pwindow.disablePicking = true canvasManager.children[0].disableHighlight = true From f4ef8f7d85e16727887fddc6c90228ccf235690d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 00:18:43 +0300 Subject: [PATCH 023/107] cleanup: remove preflat handling --- .../viewer/prepare/moreGeneratedBlocks.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index 24b85cc3..ffb1a705 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -1,6 +1,5 @@ import Jimp from 'jimp' import minecraftData from 'minecraft-data' -import prismarineRegistry from 'prismarine-registry' import { McAssets } from './modelsBuilder' import path from 'path' import fs from 'fs' @@ -11,8 +10,6 @@ const twoTileTextures: string[] = [] let currentImage: Jimp let currentBlockName: string let currentMcAssets: McAssets -let isPreFlattening = false -const postFlatenningRegistry = prismarineRegistry('1.13') const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) type SidesType = { @@ -24,9 +21,9 @@ type SidesType = { "down": string } -const getBlockStates = (name: string, postFlatenningName = name) => { - const mcData = isPreFlattening ? postFlatenningRegistry : minecraftData(currentMcAssets.version) - return mcData.blocksByName[isPreFlattening ? postFlatenningName : name]?.states +const getBlockStates = (name: string) => { + const mcData = minecraftData(currentMcAssets.version) + return mcData.blocksByName[name]?.states } export const addBlockCustomSidesModel = (name: string, sides: SidesType) => { @@ -124,7 +121,7 @@ const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { } const handleSign = async (dataBase: string, match: RegExpExecArray) => { - const states = getBlockStates(currentBlockName, currentBlockName === 'wall_sign' ? 'wall_sign' : 'sign') + const states = getBlockStates(currentBlockName) if (!states) return const [, signMaterial = ''] = match @@ -375,17 +372,11 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { if (modelName.endsWith('_left')) chestTextureName = `${chestTextureName}_left` if (modelName.endsWith('_right')) chestTextureName = `${chestTextureName}_right` - // reading latest version since the texture wasn't changed, but in pre-flatenning need custom mapping for doubled_chest const texture = path.join(currentMcAssets.directory, `../1.19.1/entity/chest/${chestTextureName}.png`) currentImage = await Jimp.read(texture) const model = structuredClone(chestModels[modelName]) - // todo < 1.9 - if (currentMcAssets.version === '1.8.8') { - // doesn't have definition of block yet - model.parent = undefined - } model.textures.particle = particle const newModelName = `${currentBlockName}_${modelName}` for (const variant of blockStatesVariants) { @@ -438,7 +429,6 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const mcData = minecraftData(mcAssets.version) - isPreFlattening = !mcData.supportFeature('blockStateId') const allTheBlocks = mcData.blocksArray.map(x => x.name) currentMcAssets = mcAssets From 0d8beef65c5022cf32dd2ea758891bad700e2374 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 26 May 2024 18:58:46 +0300 Subject: [PATCH 024/107] feat: add gamemode selector in create world screen. always use creative with ?singleplayer=1 --- cypress/e2e/index.spec.ts | 27 ++----------------- cypress/e2e/shared.ts | 15 +++++++++++ .../viewer/prepare/generateTextures.ts | 7 ++--- scripts/esbuildPlugins.mjs | 18 ++++++------- scripts/githubActions.mjs | 8 +++--- src/optionsStorage.ts | 4 ++- src/react/CreateWorld.tsx | 14 +++++++--- src/react/CreateWorldProvider.tsx | 7 ++--- src/react/Crosshair.tsx | 2 +- src/workerWorkaround.ts | 2 ++ tsconfig.json | 2 +- 11 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 cypress/e2e/shared.ts create mode 100644 src/workerWorkaround.ts diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 455b1283..05b50211 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -1,15 +1,5 @@ /// -import type { AppOptions } from '../../src/optionsStorage' - -const cleanVisit = (url?) => { - cy.clearLocalStorage() - visit(url) -} - -const visit = (url = '/') => { - window.localStorage.cypress = 'true' - cy.visit(url) -} +import { setOptions, cleanVisit, visit } from './shared' // todo use ssl @@ -31,14 +21,8 @@ const testWorldLoad = () => { }) } -const setOptions = (options: Partial) => { - cy.window().then(win => { - Object.assign(win['options'], options) - }) -} - it('Loads & renders singleplayer', () => { - visit('/?singleplayer=1') + cleanVisit('/?singleplayer=1') setOptions({ localServerOptions: { generation: { @@ -69,10 +53,3 @@ it('Loads & renders zip world', () => { cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) testWorldLoad() }) - -it.skip('Performance test', () => { - // select that world - // from -2 85 24 - // await bot.loadPlugin(pathfinder.pathfinder) - // bot.pathfinder.goto(new pathfinder.goals.GoalXZ(28, -28)) -}) diff --git a/cypress/e2e/shared.ts b/cypress/e2e/shared.ts new file mode 100644 index 00000000..9292a8d5 --- /dev/null +++ b/cypress/e2e/shared.ts @@ -0,0 +1,15 @@ +import { AppOptions } from '../../src/optionsStorage' + +export const cleanVisit = (url?) => { + cy.clearLocalStorage() + visit(url) +} +export const visit = (url = '/') => { + window.localStorage.cypress = 'true' + cy.visit(url) +} +export const setOptions = (options: Partial) => { + cy.window().then(win => { + Object.assign(win['options'], options) + }) +} diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts index dc838c65..f66fb5d7 100644 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ b/prismarine-viewer/viewer/prepare/generateTextures.ts @@ -19,9 +19,10 @@ const warnings = new Set() Promise.resolve().then(async () => { generateItemsAtlases() console.time('generateTextures') - for (const version of mcAssets.versions as typeof mcAssets['versions']) { + const versions = process.argv.includes('-l') ? [mcAssets.versions.at(-1)!] : mcAssets.versions + for (const version of versions as typeof mcAssets['versions']) { // for debugging (e.g. when above is overridden) - if (!mcAssets.versions.includes(version)) { + if (!versions.includes(version)) { throw new Error(`Version ${version} is not supported by minecraft-assets`) } if (versionToNumber(version) < versionToNumber('1.13')) { @@ -45,7 +46,7 @@ Promise.resolve().then(async () => { fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true }) } - fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + mcAssets.versions.map(v => `"${v}"`).toString() + ']') + fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + versions.map(v => `"${v}"`).toString() + ']') warnings.forEach(x => console.warn(x)) console.timeEnd('generateTextures') }) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index f6b539c1..fe4018f3 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -40,7 +40,7 @@ export const startWatchingHmr = () => { const mesherSharedPlugins = [ { name: 'minecraft-data', - setup (build) { + setup(build) { build.onLoad({ filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, }, async (args) => { @@ -59,7 +59,7 @@ const plugins = [ ...mesherSharedPlugins, { name: 'strict-aliases', - setup (build) { + setup(build) { build.onResolve({ filter: /^minecraft-protocol$/, }, async ({ kind, resolveDir }) => { @@ -110,7 +110,7 @@ const plugins = [ }, { name: 'data-assets', - setup (build) { + setup(build) { build.onResolve({ filter: /.*/, }, async ({ path, ...rest }) => { @@ -161,7 +161,7 @@ const plugins = [ }, { name: 'prevent-incorrect-linking', - setup (build) { + setup(build) { build.onResolve({ filter: /.+/, }, async ({ resolveDir, path, importer, kind, pluginData }) => { @@ -184,7 +184,7 @@ const plugins = [ }, { name: 'watch-notify', - setup (build) { + setup(build) { let count = 0 let time let prevHash @@ -234,7 +234,7 @@ const plugins = [ }, { name: 'esbuild-readdir', - setup (build) { + setup(build) { build.onResolve({ filter: /^esbuild-readdir:.+$/, }, ({ resolveDir, path }) => { @@ -262,7 +262,7 @@ const plugins = [ }, { name: 'esbuild-import-glob', - setup (build) { + setup(build) { build.onResolve({ filter: /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/, }, ({ resolveDir, path }) => { @@ -292,7 +292,7 @@ const plugins = [ }, { name: 'fix-dynamic-require', - setup (build) { + setup(build) { build.onResolve({ filter: /1\.14\/chunk/, }, async ({ resolveDir, path }) => { @@ -321,7 +321,7 @@ const plugins = [ }, { name: 'react-displayname', - setup (build) { + setup(build) { build.onLoad({ filter: /.tsx$/, }, async ({ path }) => { diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs index ba7b8566..ab786ea9 100644 --- a/scripts/githubActions.mjs +++ b/scripts/githubActions.mjs @@ -6,10 +6,10 @@ const fns = { async getAlias () { const aliasesRaw = process.env.ALIASES if (!aliasesRaw) throw new Error('No aliases found') - const aliases = aliasesRaw.split('\n').map((x) => x.split('=')) + const aliases = aliasesRaw.split('\n').map((x) => x.trim().split('=')) const githubActionsPull = process.env.PULL_URL?.split('/').at(-1) - if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`) - const prNumber = githubActionsPull[1] + if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.PULL_URL}`) + const prNumber = githubActionsPull const alias = aliases.find((x) => x[0] === prNumber) if (alias) { // set github output @@ -18,7 +18,7 @@ const fns = { } } -function setOutput(key, value) { +function setOutput (key, value) { // Temporary hack until core actions library catches up with github new recommendations const output = process.env['GITHUB_OUTPUT'] fs.appendFileSync(output, `${key}=${value}${os.EOL}`) diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index ed71cfdb..2a13abf4 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -52,7 +52,9 @@ const defaultOptions = { excludeCommunicationDebugEvents: [], preventDevReloadWhilePlaying: false, numWorkers: 4, - localServerOptions: {} as any, + localServerOptions: { + gameMode: 1 + } as any, preferLoadReadonly: false, disableLoadPrompts: false, guestUsername: 'guest', diff --git a/src/react/CreateWorld.tsx b/src/react/CreateWorld.tsx index ceed77ec..87b36777 100644 --- a/src/react/CreateWorld.tsx +++ b/src/react/CreateWorld.tsx @@ -8,17 +8,19 @@ import styles from './createWorld.module.css' // const worldTypes = ['default', 'flat', 'largeBiomes', 'amplified', 'customized', 'buffet', 'debug_all_block_states'] const worldTypes = ['default', 'flat'/* , 'void' */] +const gameModes = ['survival', 'creative'/* , 'adventure', 'spectator' */] export const creatingWorldState = proxy({ title: '', type: worldTypes[0], + gameMode: gameModes[0], version: '' }) export default ({ cancelClick, createClick, customizeClick, versions, defaultVersion }) => { const [quota, setQuota] = useState('') - const { title, type, version } = useSnapshot(creatingWorldState) + const { title, type, version, gameMode } = useSnapshot(creatingWorldState) useEffect(() => { creatingWorldState.version = defaultVersion void navigator.storage?.estimate?.().then(({ quota, usage }) => { @@ -54,9 +56,15 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer - + {/* */} +
Default and other world types are WIP
diff --git a/src/react/CreateWorldProvider.tsx b/src/react/CreateWorldProvider.tsx index 728e47ff..0f99ec42 100644 --- a/src/react/CreateWorldProvider.tsx +++ b/src/react/CreateWorldProvider.tsx @@ -3,8 +3,8 @@ import { hideCurrentModal, showModal } from '../globalState' import defaultLocalServerOptions from '../defaultLocalServerOptions' import { mkdirRecursive, uniqueFileNameFromWorldName } from '../browserfs' import CreateWorld, { WorldCustomize, creatingWorldState } from './CreateWorld' -import { useIsModalActive } from './utilsApp' import { getWorldsPath } from './SingleplayerProvider' +import { useIsModalActive } from './utilsApp' export default () => { const activeCreate = useIsModalActive('create-world') @@ -23,7 +23,7 @@ export default () => { }} createClick={async () => { // create new world - const { title, type, version } = creatingWorldState + const { title, type, version, gameMode } = creatingWorldState // todo display path in ui + disable if exist const savePath = await uniqueFileNameFromWorldName(title, getWorldsPath()) await mkdirRecursive(savePath) @@ -51,7 +51,8 @@ export default () => { levelName: title, version, generation, - 'worldFolder': savePath + 'worldFolder': savePath, + gameMode: gameMode === 'survival' ? 0 : 1, }, })) }} diff --git a/src/react/Crosshair.tsx b/src/react/Crosshair.tsx index ab289db8..9079fb66 100644 --- a/src/react/Crosshair.tsx +++ b/src/react/Crosshair.tsx @@ -12,7 +12,7 @@ export const itemBeingUsed = proxy({ export default () => { const { name: usingItem, hand } = useSnapshot(itemBeingUsed) - const [displayIndicator, setDisplayIndicator] = useState(true) + const [displayIndicator, setDisplayIndicator] = useState(false) const [indicatorProgress, setIndicatorProgress] = useState(0) const [alternativeIndicator, setAlternativeIndicator] = useState(false) const boxMaxTimeMs = 1000 diff --git a/src/workerWorkaround.ts b/src/workerWorkaround.ts new file mode 100644 index 00000000..00419b8c --- /dev/null +++ b/src/workerWorkaround.ts @@ -0,0 +1,2 @@ +global = globalThis +globalThis.window = globalThis diff --git a/tsconfig.json b/tsconfig.json index 5d018a46..dbbb9ced 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "forceConsistentCasingInFileNames": true, "useUnknownInCatchVariables": false, "skipLibCheck": true, - "experimentalDecorators": true, + "strictBindCallApply": true, // this the only options that allows smooth transition from js to ts (by not dropping types from js files) // however might need to consider includeing *only needed libraries* instead of using this "maxNodeModuleJsDepth": 1, From e129184ff1d14388a0d4d7b2d5a57e5a7f031422 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 27 May 2024 10:14:42 +0300 Subject: [PATCH 025/107] fix tsc --- src/workerWorkaround.ts | 2 ++ tsconfig.json | 1 + 2 files changed, 3 insertions(+) diff --git a/src/workerWorkaround.ts b/src/workerWorkaround.ts index 00419b8c..7fad22cf 100644 --- a/src/workerWorkaround.ts +++ b/src/workerWorkaround.ts @@ -1,2 +1,4 @@ +//@ts-nocheck +// eslint-disable-next-line no-global-assign global = globalThis globalThis.window = globalThis diff --git a/tsconfig.json b/tsconfig.json index dbbb9ced..454e60cb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ "forceConsistentCasingInFileNames": true, "useUnknownInCatchVariables": false, "skipLibCheck": true, + "experimentalDecorators": true, "strictBindCallApply": true, // this the only options that allows smooth transition from js to ts (by not dropping types from js files) // however might need to consider includeing *only needed libraries* instead of using this From 68269ee975f7c1f0d620dc6aac02b3efe2d5b533 Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Mon, 27 May 2024 12:24:28 +0400 Subject: [PATCH 026/107] feat: Screenshot on F2 and hide/show UI on F1 (#136) Co-authored-by: gguio --- src/controls.ts | 18 ++++++++++++++++++ src/globalState.ts | 1 + src/index.ts | 2 ++ src/reactUi.tsx | 4 +++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index f940d59d..a3a22029 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -651,6 +651,24 @@ window.addEventListener('keydown', (e) => { } }) +window.addEventListener('keydown', (e) => { + if (e.code !== 'F2' || e.repeat || !isGameActive(true)) return + e.preventDefault() + const canvas = document.getElementById('viewer-canvas') as HTMLCanvasElement + if (!canvas) return + const link = document.createElement('a') + link.href = canvas.toDataURL('image/png') + const date = new Date() + link.download = `screenshot ${date.toLocaleString().replaceAll('.', '-').replace(',', '')}.png` + link.click() +}) + +window.addEventListener('keydown', (e) => { + if (e.code !== 'F1' || e.repeat || !isGameActive(true)) return + e.preventDefault() + miscUiState.showUI = !miscUiState.showUI +}) + // #region experimental debug things window.addEventListener('keydown', (e) => { if (e.code === 'F11') { diff --git a/src/globalState.ts b/src/globalState.ts index 4b62f8d6..b7dc1602 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -138,6 +138,7 @@ export const miscUiState = proxy({ wanOpened: false, /** wether game hud is shown (in playing state) */ gameLoaded: false, + showUI: true, loadedServerIndex: '', /** currently trying to load or loaded mc version, after all data is loaded */ loadedDataVersion: null as string | null, diff --git a/src/index.ts b/src/index.ts index 89baaa10..d02f7b92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -108,6 +108,8 @@ let renderer: THREE.WebGLRenderer try { renderer = new THREE.WebGLRenderer({ powerPreference: options.gpuPreference, + preserveDrawingBuffer: true, + logarithmicDepthBuffer: true, }) } catch (err) { console.error(err) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index d86cf202..497f091f 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -143,6 +143,8 @@ const WidgetDisplay = ({ name, Component }) => { } const App = () => { + const { showUI } = useSnapshot(miscUiState) + return
@@ -154,7 +156,7 @@ const App = () => {
- + {showUI && } From cbaeb8c9186be140634f577d9396f129e39b81e0 Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Tue, 28 May 2024 13:34:22 +0400 Subject: [PATCH 027/107] fix hide ui was resetting state (#138) --- src/reactUi.tsx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 497f091f..ab1e4ae5 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -95,7 +95,7 @@ const InGameComponent = ({ children }) => { } const InGameUi = () => { - const { gameLoaded } = useSnapshot(miscUiState) + const { gameLoaded, showUI } = useSnapshot(miscUiState) if (!gameLoaded) return return <> @@ -107,17 +107,21 @@ const InGameUi = () => { - - - +
+ + + + +
- - - - - +
+ + + +
+ {showUI && }
From def2baba8fd728a16f38feb9649b3a4b95d6a12e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 28 May 2024 18:52:15 +0300 Subject: [PATCH 028/107] rm unused pmui-playscreen --- index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.html b/index.html index 3e921855..6d3b326b 100644 --- a/index.html +++ b/index.html @@ -94,9 +94,7 @@
-
- -
+
From 295967cc4d6ff4b5b9f83b6fe4f6b2c7f4600158 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 29 May 2024 10:56:57 +0300 Subject: [PATCH 029/107] fix inspectPacket function --- src/devtools.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devtools.ts b/src/devtools.ts index 4dbeb51d..e836af02 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -29,7 +29,7 @@ window.len = (obj) => Object.keys(obj).length window.inspectPacket = (packetName, full = false) => { const listener = (...args) => console.log('packet', packetName, full ? args : args[0]) const attach = () => { - bot?.on(packetName, listener) + bot?._client.on(packetName, listener) } attach() customEvents.on('mineflayerBotCreated', attach) From d96ff9ef3a23fc130a0133cc5c2b67dfa41da538 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 29 May 2024 11:16:42 +0300 Subject: [PATCH 030/107] fix: was unable to go edit server screen after hitting cancel --- src/react/ServersListProvider.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index bd39bc10..bb23004f 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -186,6 +186,12 @@ const Inner = () => { } }, [serverEditScreen]) + useDidUpdateEffect(() => { + if (!isEditScreenModal) { + setServerEditScreen(null) + } + }, [isEditScreenModal]) + if (isEditScreenModal) { return Date: Sat, 1 Jun 2024 10:36:04 +0300 Subject: [PATCH 031/107] fix: page was reloading infinitely in some edge cases, give some time service workers to unregister in these cases --- src/react/MainMenu.tsx | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/react/MainMenu.tsx b/src/react/MainMenu.tsx index f99b6b98..3e3170f4 100644 --- a/src/react/MainMenu.tsx +++ b/src/react/MainMenu.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react' import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' import { haveDirectoryPicker } from '../utils' +import { activeModalStack } from '../globalState' import styles from './mainMenu.module.css' import Button from './Button' import ButtonWithTooltip from './ButtonWithTooltip' @@ -17,12 +18,24 @@ interface Props { mapsProvider?: string } -const refreshApp = async () => { +const refreshApp = async (failedUpdate = false) => { const registration = await navigator.serviceWorker.getRegistration() await registration?.unregister() - window.justReloaded = true - sessionStorage.justReloaded = true - window.location.reload() + if (failedUpdate) { + await new Promise(resolve => { + setTimeout(resolve, 2000) + }) + } + if (activeModalStack.length !== 0) return + if (failedUpdate) { + sessionStorage.justReloaded = false + // try to force bypass cache + location.search = '?update=true' + } else { + window.justReloaded = true + sessionStorage.justReloaded = true + window.location.reload() + } } const httpsRegex = /^https?:\/\// @@ -40,10 +53,10 @@ export default ({ connectToServerAction, mapsProvider, singleplayerAction, optio const contents = await f.text() const isLatest = contents === process.env.BUILD_VERSION if (!isLatest && sessionStorage.justReloaded) { - // try to force bypass cache - location.search = '?update=true' + setVersionStatus('(force reloading, wait)') + void refreshApp(true) + return } - sessionStorage.justReloaded = false setVersionStatus(`(${isLatest ? 'latest' : 'new version available'})`) setVersionTitle(`Loaded: ${process.env.BUILD_VERSION}. Remote: ${contents}`) }, () => { }) From c5e636f2416312cf58c8a84cb0937f5cad007c23 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 00:59:23 +0300 Subject: [PATCH 032/107] fix (and now check) hide ui --- src/reactUi.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index ab1e4ae5..2f57e6f0 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -101,19 +101,19 @@ const InGameUi = () => { return <> {/* apply scaling */} - - - - - -
+ + + + + + +
-
@@ -129,7 +129,7 @@ const InGameUi = () => { {/* because of z-index */} - + {showUI && } @@ -147,8 +147,6 @@ const WidgetDisplay = ({ name, Component }) => { } const App = () => { - const { showUI } = useSnapshot(miscUiState) - return
@@ -160,7 +158,7 @@ const App = () => {
- {showUI && } + From 0b2e92c8606a66782243fc632985b569178112f2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 10:29:29 +0300 Subject: [PATCH 033/107] fix sentry 5431874132 --- src/react/HotbarRenderApp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 02689485..9c6dbe40 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -88,7 +88,7 @@ export default () => { return } const hotbarSlot = slot - bot.inventory.hotbarStart - if (hotbarSlot < 0 || hotbarSlot > 9) return + if (hotbarSlot < 0 || hotbarSlot > 8) return bot.setQuickBarSlot(hotbarSlot) }, } as any) From b317d8ad354e375b4a00c146eafeebf4d86a4170 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 14:20:21 +0300 Subject: [PATCH 034/107] fix: reduce fps drops on chunks load a bit by batching operations with a few other minor optimizations --- prismarine-viewer/viewer/lib/entities.js | 39 +++++++++-------- prismarine-viewer/viewer/lib/mesher/mesher.ts | 36 +++++++++++++++- prismarine-viewer/viewer/lib/threeJsUtils.ts | 8 ++-- .../viewer/lib/worldDataEmitter.ts | 11 ++++- .../viewer/lib/worldrendererCommon.ts | 34 +++++++++++++-- .../viewer/lib/worldrendererThree.ts | 43 ++++++++++++++++--- src/optionsGuiScheme.tsx | 3 +- src/react/DebugOverlay.tsx | 26 ++++++----- src/watchOptions.ts | 2 +- src/worldInteractions.ts | 1 + 10 files changed, 153 insertions(+), 50 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 930f62c9..28fc6d89 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -17,7 +17,7 @@ import { disposeObject } from './threeJsUtils' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -61,7 +61,7 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -function getEntityMesh (entity, scene, options, overrides) { +function getEntityMesh(entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -94,18 +94,19 @@ function getEntityMesh (entity, scene, options, overrides) { export class Entities extends EventEmitter { constructor(scene) { super() + /** @type {THREE.Scene} */ this.scene = scene this.entities = {} this.entitiesOptions = {} this.debugMode = 'none' this.onSkinUpdate = () => { } this.clock = new THREE.Clock() - this.visible = true + this.rendering = true this.itemsTexture = null this.getItemUv = undefined } - clear () { + clear() { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) disposeObject(mesh) @@ -113,7 +114,7 @@ export class Entities extends EventEmitter { this.entities = {} } - setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -125,14 +126,18 @@ export class Entities extends EventEmitter { } } - setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { - this.visible = visible - for (const mesh of entity ? [entity] : Object.values(this.entities)) { - mesh.visible = visible + setRendering(rendering, /** @type {THREE.Object3D?} */entity = null) { + this.rendering = rendering + for (const ent of entity ? [entity] : Object.values(this.entities)) { + if (rendering) { + if (!this.scene.children.includes(ent)) this.scene.add(ent) + } else { + this.scene.remove(ent) + } } } - render () { + render() { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -142,7 +147,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject (entityId) { + getPlayerObject(entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -152,7 +157,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -235,14 +240,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank (canvas) { + function isCanvasBlank(canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -262,14 +267,14 @@ export class Entities extends EventEmitter { } - displaySimpleText (jsonLike) { + displaySimpleText(jsonLike) { if (!jsonLike) return const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) const text = flat(parsed).map(x => x.text) return text.join('') } - update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true @@ -392,7 +397,7 @@ export class Entities extends EventEmitter { this.updatePlayerSkin(entity.id, '', overrides?.texture || stevePng) } this.setDebugMode(this.debugMode, group) - this.setVisible(this.visible, group) + this.setRendering(this.rendering, group) } //@ts-ignore diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts index bc1d3bbb..d0c82280 100644 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ b/prismarine-viewer/viewer/lib/mesher/mesher.ts @@ -19,6 +19,29 @@ function sectionKey (x, y, z) { return `${x},${y},${z}` } +const batchMessagesLimit = 100 + +let queuedMessages = [] as any[] +let queueWaiting = false +const postMessage = (data, transferList = []) => { + queuedMessages.push({ data, transferList }) + if (queuedMessages.length > batchMessagesLimit) { + drainQueue(0, batchMessagesLimit) + } + if (queueWaiting) return + queueWaiting = true + setTimeout(() => { + queueWaiting = false + drainQueue(0, queuedMessages.length) + }) +} + +function drainQueue (from, to) { + const messages = queuedMessages.slice(from, to) + global.postMessage(messages.map(m => m.data), messages.flatMap(m => m.transferList) as unknown as string) + queuedMessages = queuedMessages.slice(to) +} + function setSectionDirty (pos, value = true) { const x = Math.floor(pos.x / 16) * 16 const y = Math.floor(pos.y / 16) * 16 @@ -43,7 +66,7 @@ const softCleanup = () => { world = new World(world.config.version) } -self.onmessage = ({ data }) => { +const handleMessage = data => { const globalVar: any = globalThis if (data.type === 'mcData') { @@ -52,7 +75,7 @@ self.onmessage = ({ data }) => { if (data.config) { world ??= new World(data.config.version) - world.config = {...world.config, ...data.config} + world.config = { ...world.config, ...data.config } globalThis.world = world } @@ -80,6 +103,15 @@ self.onmessage = ({ data }) => { } } +self.onmessage = ({ data }) => { + if (Array.isArray(data)) { + data.forEach(handleMessage) + return + } + + handleMessage(data) +} + setInterval(() => { if (world === null || !blockStatesReady) return diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts index e4f9404b..ee22c477 100644 --- a/prismarine-viewer/viewer/lib/threeJsUtils.ts +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -1,12 +1,12 @@ -import * as THREE from 'three'; +import * as THREE from 'three' export const disposeObject = (obj: THREE.Object3D) => { // not cleaning texture there as it might be used by other objects, but would be good to also do that if (obj instanceof THREE.Mesh) { - obj.geometry?.dispose?.(); - obj.material?.dispose?.(); + obj.geometry?.dispose?.() + obj.material?.dispose?.() } if (obj.children) { - obj.children.forEach(disposeObject); + obj.children.forEach(disposeObject) } } diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 40cc3413..3a8fbd40 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -129,6 +129,15 @@ export class WorldDataEmitter extends EventEmitter { } } + readdDebug () { + const clonedLoadedChunks = { ...this.loadedChunks } + this.unloadAllChunks() + for (const loadedChunk in clonedLoadedChunks) { + const [x, z] = loadedChunk.split(',').map(Number) + this.loadChunk(new Vec3(x, 0, z)) + } + } + async loadChunk (pos: ChunkPos, isLightUpdate = false) { const [botX, botZ] = chunkPos(this.lastPos) const dx = Math.abs(botX - Math.floor(pos.x / 16)) @@ -187,7 +196,7 @@ export class WorldDataEmitter extends EventEmitter { const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => { const pos = new Vec3((botX + x) * 16, 0, (botZ + z) * 16) if (!this.loadedChunks[`${pos.x},${pos.z}`]) return pos - return undefined + return undefined! }).filter(a => !!a) this.lastPos.update(pos) await this._loadChunks(positions) diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index d1786650..1a87fa5d 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -73,10 +73,10 @@ export abstract class WorldRendererCommon const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName const worker: any = new Worker(src) - worker.onmessage = async ({ data }) => { + const handleMessage = (data) => { if (!this.active) return this.handleWorkerMessage(data) - await new Promise(resolve => { + new Promise(resolve => { setTimeout(resolve, 0) }) if (data.type === 'sectionFinished') { @@ -105,6 +105,13 @@ export abstract class WorldRendererCommon this.renderUpdateEmitter.emit('update') } } + worker.onmessage = ({ data }) => { + if (Array.isArray(data)) { + data.forEach(handleMessage) + return + } + handleMessage(data) + } if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) this.workers.push(worker) } @@ -215,6 +222,7 @@ export abstract class WorldRendererCommon } addColumn (x: number, z: number, chunk: any, isLightUpdate: boolean) { + if (!this.active) return if (this.workers.length === 0) throw new Error('workers not initialized yet') this.initialChunksLoad = false this.loadedChunks[`${x},${z}`] = true @@ -256,6 +264,9 @@ export abstract class WorldRendererCommon if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, 16)) } + queueAwaited = false + messagesQueue = {} as { [workerIndex: string]: any[] } + setSectionDirty (pos: Vec3, value = true) { if (this.viewDistance === -1) throw new Error('viewDistance not set') this.allChunksFinished = false @@ -269,7 +280,9 @@ export abstract class WorldRendererCommon // is always dispatched to the same worker const hash = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), this.workers.length) this.sectionsOutstanding.set(key, (this.sectionsOutstanding.get(key) ?? 0) + 1) - this.workers[hash].postMessage({ + this.messagesQueue[hash] ??= [] + this.messagesQueue[hash].push({ + // this.workers[hash].postMessage({ type: 'dirty', x: pos.x, y: pos.y, @@ -277,6 +290,21 @@ export abstract class WorldRendererCommon value, config: this.mesherConfig, }) + this.dispatchMessages() + } + + dispatchMessages () { + if (this.queueAwaited) return + this.queueAwaited = true + setTimeout(() => { + // group messages and send as one + for (const workerIndex in this.messagesQueue) { + const worker = this.workers[Number(workerIndex)] + worker.postMessage(this.messagesQueue[workerIndex]) + } + this.messagesQueue = {} + this.queueAwaited = false + }) } // Listen for chunk rendering updates emitted if a worker finished a render and resolve if the number diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 60156a50..4d28519a 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -16,6 +16,7 @@ export class WorldRendererThree extends WorldRendererCommon { chunkTextures = new Map() signsCache = new Map() starField: StarField + cameraSectionPos: Vec3 = new Vec3(0, 0, 0) get tilesRendered () { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) @@ -42,16 +43,18 @@ export class WorldRendererThree extends WorldRendererCommon { */ updatePosDataChunk (key: string) { const [x, y, z] = key.split(',').map(x => Math.floor(+x / 16)) - const [xPlayer, yPlayer, zPlayer] = this.camera.position.toArray().map(x => Math.floor(x / 16)) // sum of distances: x + y + z - const chunkDistance = Math.abs(x - xPlayer) + Math.abs(y - yPlayer) + Math.abs(z - zPlayer) + const chunkDistance = Math.abs(x - this.cameraSectionPos.x) + Math.abs(y - this.cameraSectionPos.y) + Math.abs(z - this.cameraSectionPos.z) const section = this.sectionObjects[key].children.find(child => child.name === 'mesh')! section.renderOrder = 500 - chunkDistance } updateViewerPosition (pos: Vec3): void { this.viewerPosition = pos - for (const [key, value] of Object.entries(this.sectionObjects)) { + const cameraPos = this.camera.position.toArray().map(x => Math.floor(x / 16)) as [number, number, number] + this.cameraSectionPos = new Vec3(...cameraPos) + for (const key in this.sectionObjects) { + const value = this.sectionObjects[key] if (!value) continue this.updatePosDataChunk(key) } @@ -95,7 +98,10 @@ export class WorldRendererThree extends WorldRendererCommon { mesh.name = 'mesh' object = new THREE.Group() object.add(mesh) - const boxHelper = new THREE.BoxHelper(mesh, 0xffff00) + // mesh with static dimensions: 16x16x16 + const staticChunkMesh = new THREE.Mesh(new THREE.BoxGeometry(16, 16, 16), new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0 })) + staticChunkMesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz) + const boxHelper = new THREE.BoxHelper(staticChunkMesh, 0xffff00) boxHelper.name = 'helper' object.add(boxHelper) object.name = 'chunk' @@ -117,6 +123,11 @@ export class WorldRendererThree extends WorldRendererCommon { } this.sectionObjects[data.key] = object this.updatePosDataChunk(data.key) + object.matrixAutoUpdate = false + mesh.onAfterRender = (renderer, scene, camera, geometry, material, group) => { + // mesh.matrixAutoUpdate = false + } + this.scene.add(object) } @@ -253,6 +264,24 @@ export class WorldRendererThree extends WorldRendererCommon { } } + readdChunks () { + for (const key of Object.keys(this.sectionObjects)) { + this.scene.remove(this.sectionObjects[key]) + } + setTimeout(() => { + for (const key of Object.keys(this.sectionObjects)) { + this.scene.add(this.sectionObjects[key]) + } + }, 500) + } + + disableUpdates (children = this.scene.children) { + for (const child of children) { + child.matrixWorldNeedsUpdate = false + this.disableUpdates(child.children ?? []) + } + } + removeColumn (x, z) { super.removeColumn(x, z) @@ -332,7 +361,7 @@ class StarField { this.points = new THREE.Points(geometry, material) this.scene.add(this.points) - const clock = new THREE.Clock(); + const clock = new THREE.Clock() this.points.onBeforeRender = (renderer, scene, camera) => { this.points?.position.copy?.(camera.position) material.uniforms.time.value = clock.getElapsedTime() * speed @@ -342,10 +371,10 @@ class StarField { remove () { if (this.points) { this.points.geometry.dispose(); - (this.points.material as THREE.Material).dispose(); + (this.points.material as THREE.Material).dispose() this.scene.remove(this.points) - this.points = undefined; + this.points = undefined } } } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 88e6115f..9be844d3 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -69,7 +69,8 @@ export const guiOptionsScheme: { enableWarning: 'Enabling it will make chunks load ~4x slower', disabledDuringGame: true }, - starfieldRendering: {} + starfieldRendering: {}, + renderEntities: {}, }, ], main: [ diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index 4b3c19b1..dd288b49 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -83,6 +83,16 @@ export default () => { packetsCountByNamePerSec.current.sent = {} }, 1000) + const freqUpdateInterval = setInterval(() => { + setPos(prev => { return { ...bot.entity.position } }) + setSkyL(prev => bot.world.getSkyLight(bot.entity.position)) + setBlockL(prev => bot.world.getBlockLight(bot.entity.position)) + setBiomeId(prev => bot.world.getBiome(bot.entity.position)) + setDimension(bot.game.dimension) + setDay(bot.time.day) + setCursorBlock(worldInteractions.cursorBlock) + }, 100) + // @ts-expect-error bot._client.on('packet', readPacket) // @ts-expect-error @@ -91,25 +101,12 @@ export default () => { sent.current.count++ managePackets('sent', name, data) }) - bot.on('move', () => { - setPos(prev => { return { ...bot.entity.position }}) - setSkyL(prev => bot.world.getSkyLight(bot.entity.position)) - setBlockL(prev => bot.world.getBlockLight(bot.entity.position)) - setBiomeId(prev => bot.world.getBiome(bot.entity.position)) - setDimension(bot.game.dimension) - }) - bot.on('time', () => { - setDay(bot.time.day) - }) bot.on('entitySpawn', () => { setEntitiesCount(Object.values(bot.entities).length) }) bot.on('entityGone', () => { setEntitiesCount(Object.values(bot.entities).length) }) - bot.on('physicsTick', () => { - setCursorBlock(worldInteractions.cursorBlock) - }) try { const gl = window.renderer.getContext() @@ -121,6 +118,7 @@ export default () => { return () => { document.removeEventListener('keydown', handleF3) clearInterval(packetsUpdateInterval) + clearInterval(freqUpdateInterval) } }, []) @@ -169,7 +167,7 @@ export default () => { ) } ) - : '' } + : ''} {cursorBlock ? (

Looking at: {cursorBlock.position.x} {cursorBlock.position.y} {cursorBlock.position.z}

) : ''} diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 4ff34be4..e379cb50 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -41,7 +41,7 @@ export const watchOptionsAfterViewerInit = () => { }) watchValue(options, o => { - viewer.entities.setVisible(o.renderEntities) + viewer.entities.setRendering(o.renderEntities) }) // viewer.world.mesherConfig.smoothLighting = options.smoothLighting diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 239c02c2..330dabd7 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -73,6 +73,7 @@ class WorldInteraction { this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial) this.blockBreakMesh.visible = false this.blockBreakMesh.renderOrder = 999 + this.blockBreakMesh.name = 'blockBreakMesh' viewer.scene.add(this.blockBreakMesh) // Setup events From 95b80d93ba95cc887ccdf964484c396ab2cb06ee Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 01:45:33 +0300 Subject: [PATCH 035/107] fix: waterlogged z-fighting fix --- prismarine-viewer/viewer/lib/mesher/models.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index 40b82ea2..39148aaa 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -35,7 +35,7 @@ function prepareTints (tints) { }) } -const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks); +const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks) export function preflatBlockCalculation (block: Block, world: World, position: Vec3) { const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0] if (!type) return @@ -239,9 +239,9 @@ function renderLiquid (world, cursor, texture, type, biome, water, attr) { for (const pos of corners) { const height = cornerHeights[pos[2] * 2 + pos[0]] attr.t_positions.push( - (pos[0] ? 1 : 0) + (cursor.x & 15) - 8, - (pos[1] ? height : 0) + (cursor.y & 15) - 8, - (pos[2] ? 1 : 0) + (cursor.z & 15) - 8) + (pos[0] ? 0.999 : 0.001) + (cursor.x & 15) - 8, + (pos[1] ? height - 0.001 : 0.001) + (cursor.y & 15) - 8, + (pos[2] ? 0.999 : 0.001) + (cursor.z & 15) - 8) attr.t_normals.push(...dir) attr.t_uvs.push(pos[3] * su + u, pos[4] * sv * (pos[1] ? 1 : height) + v) attr.t_colors.push(tint[0], tint[1], tint[2]) From 28e24a7a870a8b217f4d1d3b85f2b39473765c4f Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 4 Jun 2024 01:34:29 +0200 Subject: [PATCH 036/107] fix: fix rendering of Decorated Pot (#134) --- .../viewer/lib/mesher/test/tests.test.ts | 1 - prismarine-viewer/viewer/prepare/atlas.ts | 42 ++++++++++++--- .../blockModels/1.20/decorated_pot.json | 47 +++++++++++++++++ .../blockStates/1.20/decorated_pot.json | 19 +++++++ .../data/1.20/blockModels/decorated_pot.json | 47 +++++++++++++++++ .../data/1.20/blockStates/decorated_pot.json | 19 +++++++ .../viewer/prepare/moreGeneratedBlocks.ts | 51 +++++++++++++++++-- 7 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 75dd98fa..5a80fa49 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -77,7 +77,6 @@ test('Known blocks are not rendered', () => { "cyan_wall_banner": true, "dark_oak_hanging_sign": true, "dark_oak_wall_hanging_sign": true, - "decorated_pot": true, "dragon_head": true, "dragon_wall_head": true, "end_gateway": true, diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts index cb30b727..fc3e4029 100644 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ b/prismarine-viewer/viewer/prepare/atlas.ts @@ -35,7 +35,7 @@ export type JsonAtlas = { } } -export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number }, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { +export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number, origSizeTextures?}, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { image: Buffer, canvas: Canvas, json: JsonAtlas @@ -49,6 +49,7 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const texturesIndex = {} + let skipXY = [] as [x: number, y: number][] let offset = 0 const suSv = tileSize / imgSize for (const i in input) { @@ -56,20 +57,44 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const x = (pos % texSize) * tileSize const y = Math.floor(pos / texSize) * tileSize + if (skipXY.some(([sx, sy]) => sx === x + 1 && sy === y)) { + // todo more offsets + offset++ + } + const img = new Image() - const keyValue = input[i]; - const inputData = getInputData(keyValue); + const keyValue = input[i] + const inputData = getInputData(keyValue) img.src = inputData.contents - const renderWidth = tileSize * (inputData.tileWidthMult ?? 1) - g.drawImage(img, 0, 0, renderWidth, tileSize, x, y, renderWidth, tileSize) + let su = suSv + let sv = suSv + let renderWidth = tileSize * (inputData.tileWidthMult ?? 1) + let renderHeight = tileSize + if (inputData.origSizeTextures?.[keyValue]) { + // todo check have enough space + renderWidth = Math.ceil(img.width / tileSize) * tileSize + renderHeight = Math.ceil(img.height / tileSize) * tileSize + su = renderWidth / imgSize + sv = renderHeight / imgSize + if (renderWidth > tileSize) { + offset += Math.ceil(renderWidth / tileSize) - 1 + } + if (renderHeight > tileSize) { + const skipYs = Math.ceil(renderHeight / tileSize) - 1 + for (let i = 1; i <= skipYs; i++) { + skipXY.push([x, y + i]) + } + } + } + g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue texturesIndex[cleanName] = { u: x / imgSize, v: y / imgSize, ...suSvOptimize === 'remove' ? {} : { - su: suSv, - sv: suSv + su: su, + sv: sv } } } @@ -91,7 +116,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') textureFiles.unshift(...localTextures) - const { generated: additionalTextures, twoTileTextures } = getAdditionalTextures() + const { generated: additionalTextures, twoTileTextures, origSizeTextures } = getAdditionalTextures() textureFiles.push(...Object.keys(additionalTextures)) const atlas = makeTextureAtlas(textureFiles, name => { @@ -105,6 +130,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { return { contents, tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, + origSizeTextures } }) return atlas diff --git a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json new file mode 100644 index 00000000..364c72d4 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json @@ -0,0 +1,47 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json new file mode 100644 index 00000000..5b46a220 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "decorated_pot" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json new file mode 100644 index 00000000..364c72d4 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json @@ -0,0 +1,47 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json new file mode 100644 index 00000000..5b46a220 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "decorated_pot" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index ffb1a705..695464ea 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -7,6 +7,7 @@ import { fileURLToPath } from 'url' // todo refactor const twoTileTextures: string[] = [] +const origSizeTextures: string[] = [] let currentImage: Jimp let currentBlockName: string let currentMcAssets: McAssets @@ -82,7 +83,7 @@ const getBlockTexturesFromJimp = async > (sides: for (const [side, jimp] of Object.entries(sides)) { const textureName = `${textureNameBase}_${side}` const sideTexture = withUv ? { uv: [0, 0, jimp.getWidth(), jimp.getHeight()], texture: textureName } : textureName - const base64 = await jimp.getBase64Async(jimp.getMIME()) + const base64Url = await jimp.getBase64Async(jimp.getMIME()) if (side === 'side') { sidesTextures['north'] = sideTexture sidesTextures['east'] = sideTexture @@ -91,7 +92,7 @@ const getBlockTexturesFromJimp = async > (sides: } else { sidesTextures[side] = sideTexture } - generatedImageTextures[textureName] = base64 + generatedImageTextures[textureName] = base64Url } return sidesTextures @@ -229,6 +230,7 @@ const handleSign = async (dataBase: string, match: RegExpExecArray) => { twoTileTextures.push(blockTextures.up.texture) } +// TODO! should not be there! move to data with signs! const chestModels = { chest: { "parent": "block/block", @@ -401,6 +403,32 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { currentMcAssets.blocksStates[currentBlockName] = blockStates } +function getParsedJSON (block: string, type: string) { + const versionParts = currentMcAssets.version.split(".") + const version = versionParts[0] + "." + versionParts[1] + return JSON.parse(fs.readFileSync(path.join(__dirname, `${type}/${version}/${block}.json`), 'utf-8')) +} + +function getBlockState (match: string) { + return getParsedJSON(match, 'blockStates') +} + +async function loadBlockModelTextures (dataBase: string, blockModel: any) { + for (const key in Object.entries(blockModel.textures)) { + const texture: string = blockModel.textures[key] + currentImage = await Jimp.read(dataBase + texture + '.png') + blockModel.textures.particle = texture + generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, texture + '.png'), 'base64')}` + origSizeTextures[texture] = true + } +} + +async function getBlockModel (dataBase: string, block: string) { + const blockModel = getParsedJSON(block, 'blockModels') + await loadBlockModelTextures(dataBase, blockModel) + return blockModel +} + const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], @@ -427,6 +455,21 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { } } +const handleExternalData = async (dataBase: string, version: string) => { + const [major, minor] = version.split(".") + const dataVer = `${major}.${minor}` + if (!fs.existsSync(path.join(__dirname, 'data', dataVer))) return + const allModels = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockModels')).map(x => x.replace('.json', '')) + for (const model of allModels) { + currentMcAssets.blocksModels[model] = await getBlockModel(dataBase, model) + } + + const allBlockStates = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockStates')).map(x => x.replace('.json', '')) + for (const blockState of allBlockStates) { + currentMcAssets.blocksStates[blockState] = await getBlockState(blockState) + } +} + export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const mcData = minecraftData(mcAssets.version) const allTheBlocks = mcData.blocksArray.map(x => x.name) @@ -447,6 +490,8 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } } + await handleExternalData(mcAssets.directory, mcAssets.version) + const warnings: string[] = [] for (const [name, model] of Object.entries(mcAssets.blocksModels)) { if (Object.keys(model).length === 1 && model.textures) { @@ -462,5 +507,5 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures } + return { generated: generatedImageTextures, twoTileTextures, origSizeTextures } } From 228039c2450dcdee4a858b77ad740b99278e0ada Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 4 Jun 2024 12:41:53 +0200 Subject: [PATCH 037/107] cleanup external data handling in more generated blocks (#141) Co-authored-by: Vitaly Turovsky --- .../blockModels/1.20/decorated_pot.json | 47 ------------------- .../blockStates/1.20/decorated_pot.json | 19 -------- .../viewer/prepare/moreGeneratedBlocks.ts | 37 ++++++--------- 3 files changed, 14 insertions(+), 89 deletions(-) delete mode 100644 prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json delete mode 100644 prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json diff --git a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json deleted file mode 100644 index 364c72d4..00000000 --- a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "texture_size": [32, 32], - "textures": { - "0": "entity/decorated_pot/decorated_pot_base" - }, - "elements": [ - { - "name": "Body", - "from": [1, 0, 1], - "to": [15, 16, 15], - "faces": { - "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, - "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} - } - }, - { - "name": "Neck", - "from": [5, 16, 5], - "to": [11, 17, 11], - "faces": { - "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, - "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, - "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, - "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, - "down": {"uv": [0, 0, 3, 3], "texture": "#0"} - } - }, - { - "name": "Head", - "from": [4, 17, 4], - "to": [12, 20, 12], - "faces": { - "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, - "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, - "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, - "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, - "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, - "down": {"uv": [8, 0, 12, 4], "texture": "#0"} - } - } - ] -} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json deleted file mode 100644 index 5b46a220..00000000 --- a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "variants": { - "facing=east": { - "model": "decorated_pot", - "y": 90 - }, - "facing=south": { - "model": "decorated_pot", - "y": 180 - }, - "facing=west": { - "model": "decorated_pot", - "y": 270 - }, - "facing=north": { - "model": "decorated_pot" - } - } -} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index 695464ea..b343e595 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -403,18 +403,8 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { currentMcAssets.blocksStates[currentBlockName] = blockStates } -function getParsedJSON (block: string, type: string) { - const versionParts = currentMcAssets.version.split(".") - const version = versionParts[0] + "." + versionParts[1] - return JSON.parse(fs.readFileSync(path.join(__dirname, `${type}/${version}/${block}.json`), 'utf-8')) -} - -function getBlockState (match: string) { - return getParsedJSON(match, 'blockStates') -} - async function loadBlockModelTextures (dataBase: string, blockModel: any) { - for (const key in Object.entries(blockModel.textures)) { + for (const key in blockModel.textures) { const texture: string = blockModel.textures[key] currentImage = await Jimp.read(dataBase + texture + '.png') blockModel.textures.particle = texture @@ -423,12 +413,6 @@ async function loadBlockModelTextures (dataBase: string, blockModel: any) { } } -async function getBlockModel (dataBase: string, block: string) { - const blockModel = getParsedJSON(block, 'blockModels') - await loadBlockModelTextures(dataBase, blockModel) - return blockModel -} - const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], @@ -458,15 +442,22 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { const handleExternalData = async (dataBase: string, version: string) => { const [major, minor] = version.split(".") const dataVer = `${major}.${minor}` - if (!fs.existsSync(path.join(__dirname, 'data', dataVer))) return - const allModels = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockModels')).map(x => x.replace('.json', '')) - for (const model of allModels) { - currentMcAssets.blocksModels[model] = await getBlockModel(dataBase, model) + const baseDir = path.join(__dirname, 'data', dataVer) + if (!fs.existsSync(baseDir)) return + + const blockModelsDir = path.join(baseDir, 'blockModels') + const allBlockModels = fs.readdirSync(blockModelsDir).map(x => x.replace('.json', '')) + for (const blockModel of allBlockModels) { + const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, blockModel + '.json'), 'utf-8')) + currentMcAssets.blocksModels[blockModel] = model + await loadBlockModelTextures(dataBase, model) } - const allBlockStates = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockStates')).map(x => x.replace('.json', '')) + const blockStatesDir = path.join(baseDir, 'blockStates') + const allBlockStates = fs.readdirSync(blockStatesDir).map(x => x.replace('.json', '')) for (const blockState of allBlockStates) { - currentMcAssets.blocksStates[blockState] = await getBlockState(blockState) + const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, blockState + '.json'), 'utf-8')) + currentMcAssets.blocksStates[blockState] = state } } From 32de8ebacda4e63ea93d73219e978ffd9c09123a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 18:00:42 +0300 Subject: [PATCH 038/107] fix: fix all known minecraft-protocol issues. Fixed auto-version. Fixed: kick messages are now always displayed! --- cypress/minecraft-server.mjs | 1 + pnpm-lock.yaml | 8 ++++---- src/index.ts | 27 +++++++++++++++++---------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cypress/minecraft-server.mjs b/cypress/minecraft-server.mjs index 18f4e3db..32be0c9d 100644 --- a/cypress/minecraft-server.mjs +++ b/cypress/minecraft-server.mjs @@ -2,6 +2,7 @@ import mcServer from 'flying-squid' import defaultOptions from 'flying-squid/config/default-settings.json' assert { type: 'json' } +/** @type {Options} */ const serverOptions = { ...defaultOptions, 'online-mode': false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6fdf4afa..8bf3f7d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6224,8 +6224,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434} version: 0.2.4 nice-try@1.0.5: @@ -15990,7 +15990,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: dependencies: body-parser: 1.20.2 express: 4.18.2 diff --git a/src/index.ts b/src/index.ts index d02f7b92..e89bc186 100644 --- a/src/index.ts +++ b/src/index.ts @@ -186,7 +186,7 @@ let lastMouseMove: number const updateCursor = () => { worldInteractions.update() } -function onCameraMove (e) { +function onCameraMove(e) { if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return e.stopPropagation?.() const now = performance.now() @@ -212,7 +212,7 @@ contro.on('stickMovement', ({ stick, vector }) => { miscUiState.usingGamepadInput = true }) -function hideCurrentScreens () { +function hideCurrentScreens() { activeModalStacks['main-menu'] = [...activeModalStack] insertActiveModalStack('', []) } @@ -220,7 +220,7 @@ function hideCurrentScreens () { const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => { void connect({ singleplayer: true, username: options.localUsername, password: '', serverOverrides, serverOverridesFlat: flattenedServerOverrides }) } -function listenGlobalEvents () { +function listenGlobalEvents() { window.addEventListener('connect', e => { const options = (e as CustomEvent).detail void connect(options) @@ -261,7 +261,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } } -async function connect (connectOptions: ConnectOptions) { +async function connect(connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false lastConnectOptions.value = connectOptions @@ -444,18 +444,18 @@ async function connect (connectOptions: ConnectOptions) { } : {}, ...singleplayer ? { version: serverOptions.version, - connect () { }, + connect() { }, Client: CustomChannelClient as any, } : {}, username, password, viewDistance: renderDistance, checkTimeoutInterval: 240 * 1000, - noPongTimeout: 240 * 1000, + // noPongTimeout: 240 * 1000, closeTimeout: 240 * 1000, respawn: options.autoRespawn, maxCatchupTicks: 0, - async versionSelectedHook (client) { + async versionSelectedHook(client) { await downloadMcData(client.version) setLoadingScreenStatus(initialLoadingText) }, @@ -484,6 +484,13 @@ async function connect (connectOptions: ConnectOptions) { //@ts-expect-error bot._client.socket._ws.addEventListener('close', () => { console.log('WebSocket connection closed') + setTimeout(() => { + if (bot) { + bot.emit('end', 'WebSocket connection closed with unknown reason') + } + }, 1000) + }) + bot._client.socket.on('close', () => { setTimeout(() => { if (bot) { bot.emit('end', 'WebSocket connection closed with unknown reason') @@ -606,7 +613,7 @@ async function connect (connectOptions: ConnectOptions) { dayCycle() // Bot position callback - function botPosition () { + function botPosition() { viewer.world.lastCamUpdate = Date.now() // this might cause lag, but not sure viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) @@ -626,7 +633,7 @@ async function connect (connectOptions: ConnectOptions) { bot.entity.yaw -= x } - function changeCallback () { + function changeCallback() { if (notificationProxy.id === 'pointerlockchange') { hideNotification() } @@ -895,7 +902,7 @@ downloadAndOpenFile().then((downloadAction) => { const unsubscribe = subscribe(miscUiState, checkCanDisplay) checkCanDisplay() // eslint-disable-next-line no-inner-declarations - function checkCanDisplay () { + function checkCanDisplay() { if (miscUiState.appConfig) { unsubscribe() openServerEditor() From 423aa6a49c75022e48e636b3eaa21509810bfef4 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 18:04:34 +0300 Subject: [PATCH 039/107] fix eslint --- src/index.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index e89bc186..07781028 100644 --- a/src/index.ts +++ b/src/index.ts @@ -186,7 +186,7 @@ let lastMouseMove: number const updateCursor = () => { worldInteractions.update() } -function onCameraMove(e) { +function onCameraMove (e) { if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return e.stopPropagation?.() const now = performance.now() @@ -212,7 +212,7 @@ contro.on('stickMovement', ({ stick, vector }) => { miscUiState.usingGamepadInput = true }) -function hideCurrentScreens() { +function hideCurrentScreens () { activeModalStacks['main-menu'] = [...activeModalStack] insertActiveModalStack('', []) } @@ -220,7 +220,7 @@ function hideCurrentScreens() { const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => { void connect({ singleplayer: true, username: options.localUsername, password: '', serverOverrides, serverOverridesFlat: flattenedServerOverrides }) } -function listenGlobalEvents() { +function listenGlobalEvents () { window.addEventListener('connect', e => { const options = (e as CustomEvent).detail void connect(options) @@ -261,7 +261,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } } -async function connect(connectOptions: ConnectOptions) { +async function connect (connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false lastConnectOptions.value = connectOptions @@ -444,7 +444,7 @@ async function connect(connectOptions: ConnectOptions) { } : {}, ...singleplayer ? { version: serverOptions.version, - connect() { }, + connect () { }, Client: CustomChannelClient as any, } : {}, username, @@ -455,7 +455,7 @@ async function connect(connectOptions: ConnectOptions) { closeTimeout: 240 * 1000, respawn: options.autoRespawn, maxCatchupTicks: 0, - async versionSelectedHook(client) { + async versionSelectedHook (client) { await downloadMcData(client.version) setLoadingScreenStatus(initialLoadingText) }, @@ -613,7 +613,7 @@ async function connect(connectOptions: ConnectOptions) { dayCycle() // Bot position callback - function botPosition() { + function botPosition () { viewer.world.lastCamUpdate = Date.now() // this might cause lag, but not sure viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) @@ -633,7 +633,7 @@ async function connect(connectOptions: ConnectOptions) { bot.entity.yaw -= x } - function changeCallback() { + function changeCallback () { if (notificationProxy.id === 'pointerlockchange') { hideNotification() } @@ -902,7 +902,7 @@ downloadAndOpenFile().then((downloadAction) => { const unsubscribe = subscribe(miscUiState, checkCanDisplay) checkCanDisplay() // eslint-disable-next-line no-inner-declarations - function checkCanDisplay() { + function checkCanDisplay () { if (miscUiState.appConfig) { unsubscribe() openServerEditor() From 98da719e08495d75dfac919477ab0d71bf676a9e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 5 Jun 2024 11:58:26 +0300 Subject: [PATCH 040/107] fix show ui when has modals --- src/reactUi.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 2f57e6f0..449d7883 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -4,7 +4,7 @@ import { useSnapshot } from 'valtio' import { QRCodeSVG } from 'qrcode.react' import { createPortal } from 'react-dom' import { useEffect, useMemo, useState } from 'react' -import { miscUiState } from './globalState' +import { activeModalStack, miscUiState } from './globalState' import DeathScreenProvider from './react/DeathScreenProvider' import OptionsRenderApp from './react/OptionsRenderApp' import MainMenuRenderApp from './react/MainMenuRenderApp' @@ -95,7 +95,9 @@ const InGameComponent = ({ children }) => { } const InGameUi = () => { - const { gameLoaded, showUI } = useSnapshot(miscUiState) + const { gameLoaded, showUI: showUIRaw } = useSnapshot(miscUiState) + const hasModals = useSnapshot(activeModalStack).length > 0 + const showUI = showUIRaw || hasModals if (!gameLoaded) return return <> From 9a41214674458eea922298a2ae66d263b74705fa Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 6 Jun 2024 16:52:05 +0300 Subject: [PATCH 041/107] fix: fix breaking mesh was highlighted --- src/worldInteractions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 330dabd7..0245d418 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -68,7 +68,8 @@ class WorldInteraction { } const breakMaterial = new THREE.MeshBasicMaterial({ transparent: true, - blending: THREE.MultiplyBlending + blending: THREE.MultiplyBlending, + alphaTest: 0.5, }) this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial) this.blockBreakMesh.visible = false From d04a66738ef5c713379f155ac1f2bfaf1d610e33 Mon Sep 17 00:00:00 2001 From: arhellist <92224498+arhellist@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:23:43 +0400 Subject: [PATCH 042/107] fix game crash (#144) --- src/react/DebugOverlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index dd288b49..c83418f5 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -73,7 +73,7 @@ export default () => { } } - useMemo(() => { + useEffect(() => { document.addEventListener('keydown', handleF3) const packetsUpdateInterval = setInterval(() => { setPacketsString(prev => `↓ ${received.current.count} (${(received.current.size / 1024).toFixed(2)} KB/s, ${getFixedFilesize(receivedTotal.current)}) ↑ ${sent.current.count}`) From fec59aac03c5d04c15f9e1932c154fb26b694582 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 17:30:11 +0300 Subject: [PATCH 043/107] up mineflayer --- package.json | 2 +- pnpm-lock.yaml | 49 ++++++++++--------------------------------------- src/index.ts | 9 --------- 3 files changed, 11 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 9451b266..fa28ae5d 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "http-server": "^14.1.1", "https-browserify": "^1.0.0", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", - "mineflayer": "github:PrismarineJS/mineflayer", + "mineflayer": "github:zardoy/mineflayer", "mineflayer-pathfinder": "^2.4.4", "npm-run-all": "^4.1.5", "os-browserify": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bf3f7d0..f9928dc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -301,8 +301,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: - specifier: github:PrismarineJS/mineflayer - version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13) + specifier: github:zardoy/mineflayer + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6039,10 +6039,6 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5} version: 1.0.1 - minecraft-protocol@1.47.0: - resolution: {integrity: sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==} - engines: {node: '>=14'} - minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc} version: 1.47.0 @@ -6071,8 +6067,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f: - resolution: {tarball: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192} version: 4.20.1 engines: {node: '>=18'} @@ -15685,31 +15681,6 @@ snapshots: - '@types/react' - react - minecraft-protocol@1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): - dependencies: - '@types/readable-stream': 4.0.12 - aes-js: 3.1.2 - buffer-equal: 1.0.1 - debug: 4.3.4(supports-color@8.1.1) - endian-toggle: 0.0.0 - lodash.get: 4.4.2 - lodash.merge: 4.6.2 - minecraft-data: 3.65.0 - minecraft-folder-path: 1.2.0 - node-fetch: 2.7.0(encoding@0.1.13) - node-rsa: 0.4.2 - prismarine-auth: 2.4.2(encoding@0.1.13) - prismarine-chat: 1.10.1 - prismarine-nbt: 2.5.0 - prismarine-realms: 1.3.2(encoding@0.1.13) - protodef: 1.15.0 - readable-stream: 4.5.2 - uuid-1345: 1.0.2 - yggdrasil: 1.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - supports-color - minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): dependencies: '@types/readable-stream': 4.0.12 @@ -15804,11 +15775,11 @@ snapshots: mineflayer@4.20.1(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15824,14 +15795,14 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 - minecraft-protocol: 1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-chat: 1.9.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chat: 1.10.1 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 diff --git a/src/index.ts b/src/index.ts index 07781028..3b48a492 100644 --- a/src/index.ts +++ b/src/index.ts @@ -568,15 +568,6 @@ async function connect (connectOptions: ConnectOptions) { window.Vec3 = Vec3 window.pathfinder = pathfinder - // patch mineflayer - // todo move to mineflayer - bot.inventory.on('updateSlot', (index) => { - if ((index as unknown as number) === bot.quickBarSlot + bot.inventory.hotbarStart) { - //@ts-expect-error - bot.emit('heldItemChanged') - } - }) - miscUiState.gameLoaded = true miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' customEvents.emit('gameLoaded') From bd54b5bd807534bb30deb7e0314f089bcee8d715 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:09:07 +0300 Subject: [PATCH 044/107] fix: username override of servers was never used --- src/react/ServersList.tsx | 18 ++++++++++-------- src/react/ServersListProvider.tsx | 17 +++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/react/ServersList.tsx b/src/react/ServersList.tsx index f6b89452..f3759bce 100644 --- a/src/react/ServersList.tsx +++ b/src/react/ServersList.tsx @@ -5,14 +5,12 @@ import Singleplayer from './Singleplayer' import Input from './Input' import Button from './Button' import PixelartIcon from './PixelartIcon' +import { BaseServerInfo } from './AddServerOrConnect' interface Props extends React.ComponentProps { - joinServer: (ip: string, overrides: { - username?: string - password?: string - proxy?: string - versionOverride?: string + joinServer: (info: BaseServerInfo, additional: { shouldSave?: boolean + index?: number }) => void initialProxies: SavedProxiesLocalStorage updateProxies: (proxies: SavedProxiesLocalStorage) => void @@ -67,9 +65,11 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, version = parts.at(-1)! ip = parts.slice(0, -1).join(':') } - joinServer(ip, { - shouldSave: save, + joinServer({ + ip, versionOverride: version, + }, { + shouldSave: save, }) }} > @@ -116,7 +116,9 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, serversLayout onWorldAction={(action, serverName) => { if (action === 'load') { - joinServer(serverName, {}) + joinServer({ + ip: serverName, + }, {}) } props.onWorldAction?.(action, serverName) }} diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index bb23004f..9772c9b4 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -231,10 +231,11 @@ const Inner = () => { } return { + joinServer={(overrides, { shouldSave }) => { + const indexOrIp = overrides.ip let ip = indexOrIp let server: StoreServerItem | undefined - if (overrides.shouldSave === undefined) { + if (shouldSave === undefined) { // hack: inner component doesn't know of overrides for existing servers server = serversListSorted.find(s => s.index.toString() === indexOrIp)! ip = server.ip @@ -242,7 +243,7 @@ const Inner = () => { } const lastJoinedUsername = serversListSorted.find(s => s.usernameOverride)?.usernameOverride - let username = overrides.username || defaultUsername + let username = overrides.usernameOverride || defaultUsername if (!username) { username = prompt('Username', lastJoinedUsername || '') if (!username) return @@ -251,13 +252,13 @@ const Inner = () => { const options = { username, server: normalizeIp(ip), - proxy: overrides.proxy || selectedProxy, + proxy: overrides.proxyOverride || selectedProxy, botVersion: overrides.versionOverride ?? /* legacy */ overrides['version'], - password: overrides.password, + password: overrides.passwordOverride, ignoreQs: true, autoLoginPassword: server?.autoLogin?.[username], onSuccessfulPlay () { - if (overrides.shouldSave && !serversList.some(s => s.ip === ip)) { + if (shouldSave && !serversList.some(s => s.ip === ip)) { const newServersList: StoreServerItem[] = [...serversList, { ip, lastJoined: Date.now(), @@ -267,7 +268,7 @@ const Inner = () => { setNewServersList(newServersList) // component is not mounted } - if (overrides.shouldSave === undefined) { // loading saved + if (shouldSave === undefined) { // loading saved // find and update const server = serversList.find(s => s.ip === ip) if (server) { @@ -286,7 +287,7 @@ const Inner = () => { localStorage.setItem('selectedProxy', selectedProxy) } }, - serverIndex: overrides.shouldSave ? serversList.length.toString() : indexOrIp // assume last + serverIndex: shouldSave ? serversList.length.toString() : indexOrIp // assume last } satisfies ConnectOptions dispatchEvent(new CustomEvent('connect', { detail: options })) // qsOptions From aa18c3cbbdd1dd770f75f6695dd6bfff15b61a51 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:52:12 +0300 Subject: [PATCH 045/107] add ping proxy implementation --- src/index.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/index.ts b/src/index.ts index 3b48a492..fe584b4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -498,6 +498,22 @@ async function connect (connectOptions: ConnectOptions) { }) }) }) + let i = 0 + //@ts-expect-error + bot.pingProxy = async () => { + const curI = ++i + return new Promise(resolve => { + //@ts-expect-error + bot._client.socket._ws.send(`ping:${curI}`) + const date = Date.now() + const onPong = (received) => { + if (received !== curI.toString()) return + bot._client.socket.off('pong' as any, onPong) + resolve(Date.now() - date) + } + bot._client.socket.on('pong' as any, onPong) + }) + } } // socket setup actually can be delayed because of dns lookup if (bot._client.socket) { From 1e741c7c7a44fd783c2f76875b2d20cc618f8683 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:53:08 +0300 Subject: [PATCH 046/107] up net-browserify --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9928dc6..7ced3b41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: dependencies: body-parser: 1.20.2 express: 4.18.2 From 4c03d68b03f4748d41fe238a4aa81a8f14ed0089 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 7 Jun 2024 00:22:41 +0300 Subject: [PATCH 047/107] up browserify --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ced3b41..10add82d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: dependencies: body-parser: 1.20.2 express: 4.18.2 From bbf8fbf4a5fed3387b2329f39d3037cde595dbff Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 7 Jun 2024 01:30:00 +0300 Subject: [PATCH 048/107] fix o.text.includes is not a function crash --- src/botUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/botUtils.ts b/src/botUtils.ts index 30e13834..79b10118 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -101,7 +101,7 @@ export const formatMessage = (message: MessageInput, mcData: IndexedData = globa msglist = msglist.map(msg => { // normalize § - if (!msg.text.includes('§')) return msg + if (!msg.text.includes?.('§')) return msg const newMsg = fromFormattedString(msg.text) return flat(newMsg) }).flat(Infinity) From 94c665d851f8366b31ca4aa8873526dd53840af8 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 8 Jun 2024 23:13:44 +0300 Subject: [PATCH 049/107] move everything to frequent update interval --- src/react/DebugOverlay.tsx | 7 +------ src/reactUi.tsx | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index c83418f5..bb38672e 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -91,6 +91,7 @@ export default () => { setDimension(bot.game.dimension) setDay(bot.time.day) setCursorBlock(worldInteractions.cursorBlock) + setEntitiesCount(Object.values(bot.entities).length) }, 100) // @ts-expect-error @@ -101,12 +102,6 @@ export default () => { sent.current.count++ managePackets('sent', name, data) }) - bot.on('entitySpawn', () => { - setEntitiesCount(Object.values(bot.entities).length) - }) - bot.on('entityGone', () => { - setEntitiesCount(Object.values(bot.entities).length) - }) try { const gl = window.renderer.getContext() diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 449d7883..8a9cc32c 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -98,7 +98,7 @@ const InGameUi = () => { const { gameLoaded, showUI: showUIRaw } = useSnapshot(miscUiState) const hasModals = useSnapshot(activeModalStack).length > 0 const showUI = showUIRaw || hasModals - if (!gameLoaded) return + if (!gameLoaded || !bot) return return <> From 6be0bc8c9a93d79f0524d0e8bdb7041941e5c27d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 8 Jun 2024 23:20:07 +0300 Subject: [PATCH 050/107] fix: elytra equipped crashed hud bars fix sentry 5457375830 --- src/react/HudBarsProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/HudBarsProvider.tsx b/src/react/HudBarsProvider.tsx index 746d4819..ea78ae08 100644 --- a/src/react/HudBarsProvider.tsx +++ b/src/react/HudBarsProvider.tsx @@ -82,7 +82,7 @@ export default () => { const item = bot.inventory.slots[slotIndex] ?? null if (!item) continue const armorName = item.name.split('_') - points += armor[armorName[0]][armorName[1]] + points += armor[armorName[0]]?.[armorName[1]] ?? 0 } setArmorValue(points) } From 409577d8e0b272ec155e9cbfc96e94a0295b49de Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 00:19:08 +0300 Subject: [PATCH 051/107] up net --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10add82d..38a9ebb6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f: dependencies: body-parser: 1.20.2 express: 4.18.2 From 6268561e4148dbaec0de0c6965e3423ccb709849 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 01:09:02 +0300 Subject: [PATCH 052/107] make inputs in server editor a bit smaller, fix proxy select --- src/react/AddServerOrConnect.tsx | 60 +++++++++++++++++++------------- src/react/ServersList.tsx | 4 +-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/react/AddServerOrConnect.tsx b/src/react/AddServerOrConnect.tsx index 500c1e61..d74ff8fe 100644 --- a/src/react/AddServerOrConnect.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -23,6 +23,8 @@ interface Props { defaults?: Pick } +const ELEMENTS_WIDTH = 190 + export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, defaults }: Props) => { const qsParams = parseQs ? new URLSearchParams(window.location.search) : undefined @@ -41,24 +43,25 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ const lockConnect = qsParams?.get('lockConnect') === 'true' return -
{ - e.preventDefault() - let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` - ip = ip.replace(/:$/, '') - onConfirm({ - name: serverName, - ip, - versionOverride, - proxyOverride, - usernameOverride, - passwordOverride - }) - }} + { + e.preventDefault() + let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` + ip = ip.replace(/:$/, '') + onConfirm({ + name: serverName, + ip, + versionOverride, + proxyOverride, + usernameOverride, + passwordOverride + }) + }} >
setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> setUsernameOverride(value)} placeholder={defaults?.usernameOverride} /> setPasswordOverride(value)} /* placeholder='For advanced usage only' */ /> - {!lockConnect && <>} + {!lockConnect && <> + { + onBack() + }}>Cancel + Save + } {qsParams?.get('ip') &&
- + >Connect
}
} +const ButtonWrapper = ({ ...props }: React.ComponentProps) => { + props.style ??= {} + props.style.width = ELEMENTS_WIDTH + return
From 05a0d3a184ae4478470f11046b89d7f45160b4a1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 02:02:26 +0300 Subject: [PATCH 053/107] fix: attack entities on left click not on right click --- src/worldInteractions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 0245d418..49c21c2e 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -90,7 +90,7 @@ class WorldInteraction { const entity = getEntityCursor() - if (entity && e.button === 2) { + if (entity && e.button === 0) { bot.attack(entity) } else { // bot From 353bec4c6b718ab3a2b54f147a35d04fa274c058 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 9 Jun 2024 18:12:34 +0300 Subject: [PATCH 054/107] fix: fix entity label display for older versions of minecraft --- prismarine-viewer/viewer/lib/entities.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 28fc6d89..94f06e0c 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -267,11 +267,15 @@ export class Entities extends EventEmitter { } - displaySimpleText(jsonLike) { + parseEntityLabel(jsonLike) { if (!jsonLike) return - const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) - const text = flat(parsed).map(x => x.text) - return text.join('') + try { + const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) + const text = flat(parsed).map(x => x.text) + return text.join('') + } catch (err) { + return jsonLike + } } update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { @@ -410,7 +414,7 @@ export class Entities extends EventEmitter { } } // not player - const displayText = entity.metadata?.[3] && this.displaySimpleText(entity.metadata[2]) + const displayText = entity.metadata?.[3] && this.parseEntityLabel(entity.metadata[2]) if (entity.name !== 'player' && displayText) { addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh')) } From 7f3d5ca1f0ead78528f065c55ba3724f951b875b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 10 Jun 2024 03:27:34 +0300 Subject: [PATCH 055/107] rename project to minecraft-web-client fixes issue146 --- README.NPM.MD | 2 +- package.json | 2 +- package.npm.json | 2 +- scripts/downloadSoundsMap.mjs | 2 +- scripts/prepareSounds.mjs | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.NPM.MD b/README.NPM.MD index 24c90bc9..c036adba 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -24,7 +24,7 @@ const App = () => { } ``` -See [Storybook](https://mcraft.fun/storybook/) or [Storybook (Mirror link)](https://mcon.vercel.app/storybook/) for more examples and full components list. Also take a look at the full [standalone example](https://github.com/zardoy/prismarine-web-client/tree/experiments/UiStandaloneExample.tsx). +See [Storybook](https://mcraft.fun/storybook/) or [Storybook (Mirror link)](https://mcon.vercel.app/storybook/) for more examples and full components list. Also take a look at the full [standalone example](https://github.com/zardoy/minecraft-web-client/tree/experiments/UiStandaloneExample.tsx). There are two types of components: diff --git a/package.json b/package.json index fa28ae5d..7bbde636 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "prismarine-web-client", + "name": "minecraft-web-client", "version": "0.0.0-dev", "description": "A minecraft client running in a browser", "scripts": { diff --git a/package.npm.json b/package.npm.json index bae8b60f..7e13d67b 100644 --- a/package.npm.json +++ b/package.npm.json @@ -26,7 +26,7 @@ }, "module": "./dist/react/npmReactComponents.js", "types": "./dist/react/npmReactComponents.d.ts", - "repository": "zardoy/prismarine-web-client", + "repository": "zardoy/minecraft-web-client", "version": "0.0.0-dev", "dependencies": {}, "peerDependencies": { diff --git a/scripts/downloadSoundsMap.mjs b/scripts/downloadSoundsMap.mjs index 066a3df7..3c335f8f 100644 --- a/scripts/downloadSoundsMap.mjs +++ b/scripts/downloadSoundsMap.mjs @@ -1,6 +1,6 @@ import fs from 'fs' -const url = 'https://github.com/zardoy/prismarine-web-client/raw/sounds-generated/sounds.js' +const url = 'https://github.com/zardoy/minecraft-web-client/raw/sounds-generated/sounds.js' const savePath = 'dist/sounds.js' fetch(url).then(res => res.text()).then(data => { fs.writeFileSync(savePath, data, 'utf8') diff --git a/scripts/prepareSounds.mjs b/scripts/prepareSounds.mjs index 4ed119cb..8f3e5bef 100644 --- a/scripts/prepareSounds.mjs +++ b/scripts/prepareSounds.mjs @@ -61,7 +61,7 @@ const downloadAllSounds = async () => { } prevSounds = soundAssets } - async function downloadSound ({ name, hash, size }, namePath, log) { + async function downloadSound({ name, hash, size }, namePath, log) { const savePath = path.resolve(`generated/sounds/${namePath}`) if (fs.existsSync(savePath)) { // console.log('skipped', name) @@ -86,7 +86,7 @@ const downloadAllSounds = async () => { } writer.close() } - async function downloadSounds (assets, addPath = '') { + async function downloadSounds(assets, addPath = '') { for (let i = 0; i < assets.length; i += 5) { await Promise.all(assets.slice(i, i + 5).map((asset, j) => downloadSound(asset, `${addPath}${asset.name}`, () => { console.log('downloading', addPath, asset.name, i + j, '/', assets.length) @@ -135,7 +135,7 @@ const convertSounds = async () => { } const CONCURRENCY = 5 - for(let i = 0; i < toConvert.length; i += CONCURRENCY) { + for (let i = 0; i < toConvert.length; i += CONCURRENCY) { await Promise.all(toConvert.slice(i, i + CONCURRENCY).map((oggPath, j) => convertSound(i + j))) } } @@ -221,7 +221,7 @@ const makeSoundsBundle = async () => { const allSoundsMeta = { format: 'mp3', - baseUrl: 'https://raw.githubusercontent.com/zardoy/prismarine-web-client/sounds-generated/sounds/' + baseUrl: 'https://raw.githubusercontent.com/zardoy/minecraft-web-client/sounds-generated/sounds/' } await build({ From 7f4edbedba20b22bd9b903c780a2c268679d6463 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Jun 2024 03:26:24 +0300 Subject: [PATCH 056/107] rm manimali, replace with a better server --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 1bbbfd47..e4f86060 100644 --- a/config.json +++ b/config.json @@ -15,9 +15,9 @@ "description": "One of the best servers here. Join now!" }, { - "ip": "play.minemalia.com", + "ip": "sus.shhnowisnottheti.me", "version": "1.18.2", - "description": "Only login with existing accounts." + "description": "Creative, your own 'boxes' (islands)" } ] } From 38e4efc79b4054bfc354ccaaf6fe5c5f572a3978 Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 11 Jun 2024 20:14:58 +0200 Subject: [PATCH 057/107] fix: improve signs models & text, added all missing sign types (#143) Co-authored-by: Vitaly Turovsky --- prismarine-viewer/viewer/lib/mesher/models.ts | 4 +- .../viewer/lib/mesher/test/tests.test.ts | 22 -- .../viewer/lib/worldrendererThree.ts | 27 +- prismarine-viewer/viewer/prepare/atlas.ts | 49 +-- .../data/1.13/blockModels/sign/oak.json | 6 + .../data/1.13/blockModels/sign/oak_wall.json | 6 + .../data/1.13/blockModels/sign/sign.json | 140 +++++++ .../data/1.13/blockModels/sign/sign_wall.json | 72 ++++ .../data/1.13/blockStates/sign/sign.json | 67 ++++ .../data/1.13/blockStates/sign/wall_sign.json | 19 + .../data/1.14/blockModels/sign/acacia.json | 6 + .../1.14/blockModels/sign/acacia_wall.json | 6 + .../data/1.14/blockModels/sign/birch.json | 6 + .../1.14/blockModels/sign/birch_wall.json | 6 + .../data/1.14/blockModels/sign/dark_oak.json | 6 + .../1.14/blockModels/sign/dark_oak_wall.json | 6 + .../data/1.14/blockModels/sign/jungle.json | 6 + .../1.14/blockModels/sign/jungle_wall.json | 7 + .../data/1.14/blockModels/sign/spruce.json | 6 + .../1.14/blockModels/sign/spruce_wall.json | 6 + .../1.14/blockStates/sign/acacia_sign.json | 67 ++++ .../blockStates/sign/acacia_wall_sign.json | 19 + .../1.14/blockStates/sign/birch_sign.json | 67 ++++ .../blockStates/sign/birch_wall_sign.json | 19 + .../1.14/blockStates/sign/dark_oak_sign.json | 67 ++++ .../blockStates/sign/dark_oak_wall_sign.json | 19 + .../1.14/blockStates/sign/jungle_sign.json | 67 ++++ .../blockStates/sign/jungle_wall_sign.json | 19 + .../data/1.14/blockStates/sign/oak_sign.json | 67 ++++ .../1.14/blockStates/sign/oak_wall_sign.json | 19 + .../1.14/blockStates/sign/spruce_sign.json | 67 ++++ .../blockStates/sign/spruce_wall_sign.json | 19 + .../data/1.16/blockModels/sign/crimson.json | 6 + .../1.16/blockModels/sign/crimson_wall.json | 6 + .../data/1.16/blockModels/sign/warped.json | 6 + .../1.16/blockModels/sign/warped_wall.json | 6 + .../1.16/blockStates/sign/crimson_sign.json | 67 ++++ .../blockStates/sign/crimson_wall_sign.json | 19 + .../1.16/blockStates/sign/warped_sign.json | 67 ++++ .../blockStates/sign/warped_wall_sign.json | 19 + .../data/1.19/blockModels/sign/mangrove.json | 6 + .../1.19/blockModels/sign/mangrove_wall.json | 6 + .../1.19/blockStates/sign/mangrove_sign.json | 67 ++++ .../blockStates/sign/mangrove_wall_sign.json | 19 + .../1.20/blockModels/sign/acacia_hanging.json | 7 + .../blockModels/sign/acacia_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/bamboo.json | 6 + .../1.20/blockModels/sign/bamboo_hanging.json | 7 + .../1.20/blockModels/sign/bamboo_wall.json | 6 + .../blockModels/sign/bamboo_wall_hanging.json | 7 + .../1.20/blockModels/sign/birch_hanging.json | 7 + .../blockModels/sign/birch_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/cherry.json | 6 + .../1.20/blockModels/sign/cherry_hanging.json | 7 + .../1.20/blockModels/sign/cherry_wall.json | 6 + .../blockModels/sign/cherry_wall_hanging.json | 7 + .../blockModels/sign/crimson_hanging.json | 7 + .../sign/crimson_wall_hanging.json | 7 + .../blockModels/sign/dark_oak_hanging.json | 7 + .../sign/dark_oak_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/hanging.json | 115 ++++++ .../1.20/blockModels/sign/jungle_hanging.json | 7 + .../blockModels/sign/jungle_wall_hanging.json | 7 + .../blockModels/sign/mangrove_hanging.json | 7 + .../sign/mangrove_wall_hanging.json | 7 + .../1.20/blockModels/sign/oak_hanging.json | 7 + .../blockModels/sign/oak_wall_hanging.json | 7 + .../1.20/blockModels/sign/spruce_hanging.json | 7 + .../blockModels/sign/spruce_wall_hanging.json | 7 + .../1.20/blockModels/sign/wall_hanging.json | 347 ++++++++++++++++++ .../1.20/blockModels/sign/warped_hanging.json | 7 + .../blockModels/sign/warped_wall_hanging.json | 7 + .../blockStates/sign/acacia_hanging_sign.json | 67 ++++ .../sign/acacia_wall_hanging_sign.json | 19 + .../blockStates/sign/bamboo_hanging_sign.json | 67 ++++ .../1.20/blockStates/sign/bamboo_sign.json | 67 ++++ .../sign/bamboo_wall_hanging_sign.json | 19 + .../blockStates/sign/bamboo_wall_sign.json | 19 + .../blockStates/sign/birch_hanging_sign.json | 67 ++++ .../sign/birch_wall_hanging_sign.json | 19 + .../blockStates/sign/cherry_hanging_sign.json | 67 ++++ .../1.20/blockStates/sign/cherry_sign.json | 67 ++++ .../sign/cherry_wall_hanging_sign.json | 19 + .../blockStates/sign/cherry_wall_sign.json | 19 + .../sign/crimson_hanging_sign.json | 67 ++++ .../sign/crimson_wall_hanging_sign.json | 19 + .../sign/dark_oak_hanging_sign.json | 67 ++++ .../sign/dark_oak_wall_hanging_sign.json | 19 + .../blockStates/sign/jungle_hanging_sign.json | 67 ++++ .../sign/jungle_wall_hanging_sign.json | 19 + .../sign/mangrove_hanging_sign.json | 67 ++++ .../sign/mangrove_wall_hanging_sign.json | 19 + .../blockStates/sign/oak_hanging_sign.json | 67 ++++ .../sign/oak_wall_hanging_sign.json | 19 + .../blockStates/sign/spruce_hanging_sign.json | 67 ++++ .../sign/spruce_wall_hanging_sign.json | 19 + .../blockStates/sign/warped_hanging_sign.json | 67 ++++ .../sign/warped_wall_hanging_sign.json | 19 + .../viewer/prepare/modelsBuilder.ts | 10 +- .../viewer/prepare/moreGeneratedBlocks.ts | 193 +++------- 100 files changed, 3048 insertions(+), 196 deletions(-) create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index 39148aaa..c978c240 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -520,9 +520,11 @@ export function getSectionGeometry (sx, sy, sz, world: World) { "west": 1, "east": 3 } - const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('hanging_sign') + const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('wall_hanging_sign') + const isHanging = block.name.endsWith('hanging_sign') attr.signs[key] = { isWall, + isHanging, rotation: isWall ? facingRotationMap[props.facing] : +props.rotation } } diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 5a80fa49..de5db815 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -45,12 +45,6 @@ test('Known blocks are not rendered', () => { // should be fixed, but to avoid regressions & for visibility expect(invalidBlocks).toMatchInlineSnapshot(` { - "acacia_hanging_sign": true, - "acacia_wall_hanging_sign": true, - "bamboo_hanging_sign": true, - "bamboo_wall_hanging_sign": true, - "birch_hanging_sign": true, - "birch_wall_hanging_sign": true, "black_banner": true, "black_bed": true, "black_candle": true, @@ -65,18 +59,12 @@ test('Known blocks are not rendered', () => { "brown_wall_banner": true, "bubble_column": true, "candle": true, - "cherry_hanging_sign": true, - "cherry_wall_hanging_sign": true, "creeper_head": true, "creeper_wall_head": true, - "crimson_hanging_sign": true, - "crimson_wall_hanging_sign": true, "cyan_banner": true, "cyan_bed": true, "cyan_candle": true, "cyan_wall_banner": true, - "dark_oak_hanging_sign": true, - "dark_oak_wall_hanging_sign": true, "dragon_head": true, "dragon_wall_head": true, "end_gateway": true, @@ -89,8 +77,6 @@ test('Known blocks are not rendered', () => { "green_bed": true, "green_candle": true, "green_wall_banner": true, - "jungle_hanging_sign": true, - "jungle_wall_hanging_sign": true, "light_blue_banner": true, "light_blue_bed": true, "light_blue_candle": true, @@ -107,10 +93,6 @@ test('Known blocks are not rendered', () => { "magenta_bed": true, "magenta_candle": true, "magenta_wall_banner": true, - "mangrove_hanging_sign": true, - "mangrove_wall_hanging_sign": true, - "oak_hanging_sign": true, - "oak_wall_hanging_sign": true, "orange_banner": true, "orange_bed": true, "orange_candle": true, @@ -138,12 +120,8 @@ test('Known blocks are not rendered', () => { "skeleton_skull": true, "skeleton_wall_skull": true, "snow": true, - "spruce_hanging_sign": true, - "spruce_wall_hanging_sign": true, "structure_void": true, "turtle_egg": true, - "warped_hanging_sign": true, - "warped_wall_hanging_sign": true, "water_cauldron": true, "white_banner": true, "white_bed": true, diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 4d28519a..095e5a94 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -112,11 +112,11 @@ export class WorldRendererThree extends WorldRendererCommon { } // should not compute it once if (Object.keys(data.geometry.signs).length) { - for (const [posKey, { isWall, rotation }] of Object.entries(data.geometry.signs)) { + for (const [posKey, { isWall, isHanging, rotation }] of Object.entries(data.geometry.signs)) { const [x, y, z] = posKey.split(',') const signBlockEntity = this.blockEntities[posKey] if (!signBlockEntity) continue - const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(signBlockEntity)) + const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, isHanging, nbt.simplify(signBlockEntity)) if (!sign) continue object.add(sign) } @@ -165,7 +165,7 @@ export class WorldRendererThree extends WorldRendererCommon { this.renderer.render(this.scene, this.camera) } - renderSign (position: Vec3, rotation: number, isWall: boolean, blockEntity) { + renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) { const tex = this.getSignTexture(position, blockEntity) if (!tex) return @@ -182,13 +182,16 @@ export class WorldRendererThree extends WorldRendererCommon { mesh.renderOrder = 999 // todo @sa2urami shouldnt all this be done in worker? - mesh.scale.set(1, 7 / 16, 1) - if (isWall) { - mesh.position.set(0, 0, -(8 - 1.5) / 16 + 0.001) + const lineHeight = 7 / 16; + const scaleFactor = isHanging ? 1.3 : 1 + mesh.scale.set(1 * scaleFactor, lineHeight * scaleFactor, 1 * scaleFactor) + + const thickness = (isHanging ? 2 : 1.5) / 16 + const wallSpacing = 0.25 / 16; + if (isWall && !isHanging) { + mesh.position.set(0, 0, -0.5 + thickness + wallSpacing + 0.0001) } else { - // standing - const faceEnd = 8.75 - mesh.position.set(0, 0, (faceEnd - 16 / 2) / 16 + 0.001) + mesh.position.set(0, 0, thickness / 2 + 0.0001) } const group = new THREE.Group() @@ -196,8 +199,10 @@ export class WorldRendererThree extends WorldRendererCommon { rotation * (isWall ? 90 : 45 / 2) ), 0) group.add(mesh) - const y = isWall ? 4.5 / 16 + mesh.scale.y / 2 : (1 - (mesh.scale.y / 2)) - group.position.set(position.x + 0.5, position.y + y, position.z + 0.5) + const height = (isHanging ? 10 : 8)/16 + const heightOffset = (isHanging ? 0 : isWall ? 4.333 : 9.333) / 16 + const textPosition = height/2 + heightOffset + group.position.set(position.x + 0.5, position.y + textPosition, position.z + 0.5) return group } diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts index fc3e4029..cf73fdc4 100644 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ b/prismarine-viewer/viewer/prepare/atlas.ts @@ -49,19 +49,18 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const texturesIndex = {} - let skipXY = [] as [x: number, y: number][] - let offset = 0 + let nextX = 0 + let nextY = 0 + let rowMaxY = 0 + + const goToNextRow = () => { + nextX = 0 + nextY += rowMaxY + rowMaxY = 0 + } + const suSv = tileSize / imgSize for (const i in input) { - const pos = +i + offset - const x = (pos % texSize) * tileSize - const y = Math.floor(pos / texSize) * tileSize - - if (skipXY.some(([sx, sy]) => sx === x + 1 && sy === y)) { - // todo more offsets - offset++ - } - const img = new Image() const keyValue = input[i] const inputData = getInputData(keyValue) @@ -76,16 +75,24 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont renderHeight = Math.ceil(img.height / tileSize) * tileSize su = renderWidth / imgSize sv = renderHeight / imgSize - if (renderWidth > tileSize) { - offset += Math.ceil(renderWidth / tileSize) - 1 - } - if (renderHeight > tileSize) { - const skipYs = Math.ceil(renderHeight / tileSize) - 1 - for (let i = 1; i <= skipYs; i++) { - skipXY.push([x, y + i]) - } + if (renderHeight > imgSize || renderWidth > imgSize) { + throw new Error('Texture ' + keyValue + ' is too big') } } + + if (nextX + renderWidth > imgSize) { + goToNextRow() + } + + const x = nextX + const y = nextY + + nextX += renderWidth + rowMaxY = Math.max(rowMaxY, renderHeight) + if (nextX >= imgSize) { + goToNextRow() + } + g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue @@ -116,7 +123,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') textureFiles.unshift(...localTextures) - const { generated: additionalTextures, twoTileTextures, origSizeTextures } = getAdditionalTextures() + const { generated: additionalTextures, origSizeTextures } = getAdditionalTextures() textureFiles.push(...Object.keys(additionalTextures)) const atlas = makeTextureAtlas(textureFiles, name => { @@ -129,7 +136,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { return { contents, - tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, + // tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, origSizeTextures } }) diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json new file mode 100644 index 00000000..2f16a429 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/sign" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json new file mode 100644 index 00000000..dfdb230f --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/sign" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json new file mode 100644 index 00000000..4562cfae --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json @@ -0,0 +1,140 @@ +{ + "elements": [ + { + "from": [ + 7.25, + 0, + 7.25 + ], + "to": [ + 8.75, + 9.333, + 8.75 + ], + "faces": { + "north": { + "uv": [ + 1.5, + 8, + 2, + 15 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 1, + 8, + 1.5, + 15 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 8, + 1, + 15 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 15 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 7, + 1, + 8 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 1, + 7, + 1.5, + 8 + ], + "texture": "#sign" + } + } + }, + { + "from": [ + 0, + 9.333, + 7.25 + ], + "to": [ + 16, + 17.333, + 8.75 + ], + "faces": { + "north": { + "uv": [ + 7, + 1, + 13, + 7 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 6.5, + 1, + 7, + 7 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 1, + 6.5, + 7 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 1, + 0.5, + 7 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 0, + 6.5, + 1 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 6.5, + 1, + 12.5, + 0 + ], + "texture": "#sign" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json new file mode 100644 index 00000000..b743c983 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json @@ -0,0 +1,72 @@ +{ + "elements": [ + { + "from": [ + 0, + 4.333, + 0.25 + ], + "to": [ + 16, + 12.333, + 1.75 + ], + "faces": { + "north": { + "uv": [ + 7, + 1, + 13, + 7 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 6.5, + 1, + 7, + 7 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 1, + 6.5, + 7 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 1, + 0.5, + 7 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 0, + 6.5, + 1 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 6.5, + 1, + 12.5, + 0 + ], + "texture": "#sign" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json new file mode 100644 index 00000000..4ebcedcd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak" + }, + "rotation=1": { + "model": "sign/oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json new file mode 100644 index 00000000..26453d53 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/oak_wall" + }, + "facing=west": { + "model": "sign/oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json new file mode 100644 index 00000000..7057ded0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json new file mode 100644 index 00000000..70b755bf --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json new file mode 100644 index 00000000..d20d1438 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json new file mode 100644 index 00000000..c7983bee --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json new file mode 100644 index 00000000..803add52 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json new file mode 100644 index 00000000..b410acfe --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json new file mode 100644 index 00000000..17d52250 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json new file mode 100644 index 00000000..bfe6c8f8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/jungle" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json new file mode 100644 index 00000000..8f2b2179 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json new file mode 100644 index 00000000..1509eb3c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json new file mode 100644 index 00000000..370c2c84 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/acacia" + }, + "rotation=1": { + "model": "sign/acacia", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/acacia", + "y": 45 + }, + "rotation=3": { + "model": "sign/acacia", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/acacia", + "y": 90 + }, + "rotation=5": { + "model": "sign/acacia", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/acacia", + "y": 135 + }, + "rotation=7": { + "model": "sign/acacia", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/acacia", + "y": 180 + }, + "rotation=9": { + "model": "sign/acacia", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/acacia", + "y": 225 + }, + "rotation=11": { + "model": "sign/acacia", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/acacia", + "y": 270 + }, + "rotation=13": { + "model": "sign/acacia", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/acacia", + "y": 315 + }, + "rotation=15": { + "model": "sign/acacia", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json new file mode 100644 index 00000000..b524b126 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/acacia_wall" + }, + "facing=west": { + "model": "sign/acacia_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/acacia_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/acacia_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json new file mode 100644 index 00000000..2ffe5fd5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/birch" + }, + "rotation=1": { + "model": "sign/birch", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/birch", + "y": 45 + }, + "rotation=3": { + "model": "sign/birch", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/birch", + "y": 90 + }, + "rotation=5": { + "model": "sign/birch", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/birch", + "y": 135 + }, + "rotation=7": { + "model": "sign/birch", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/birch", + "y": 180 + }, + "rotation=9": { + "model": "sign/birch", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/birch", + "y": 225 + }, + "rotation=11": { + "model": "sign/birch", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/birch", + "y": 270 + }, + "rotation=13": { + "model": "sign/birch", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/birch", + "y": 315 + }, + "rotation=15": { + "model": "sign/birch", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json new file mode 100644 index 00000000..622924b5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/birch_wall" + }, + "facing=west": { + "model": "sign/birch_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/birch_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/birch_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json new file mode 100644 index 00000000..6001019b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/dark_oak" + }, + "rotation=1": { + "model": "sign/dark_oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/dark_oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/dark_oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/dark_oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/dark_oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/dark_oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/dark_oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/dark_oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/dark_oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/dark_oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/dark_oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/dark_oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/dark_oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/dark_oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/dark_oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json new file mode 100644 index 00000000..4b5cc921 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/dark_oak_wall" + }, + "facing=west": { + "model": "sign/dark_oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/dark_oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/dark_oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json new file mode 100644 index 00000000..983c2d68 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/jungle" + }, + "rotation=1": { + "model": "sign/jungle", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/jungle", + "y": 45 + }, + "rotation=3": { + "model": "sign/jungle", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/jungle", + "y": 90 + }, + "rotation=5": { + "model": "sign/jungle", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/jungle", + "y": 135 + }, + "rotation=7": { + "model": "sign/jungle", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/jungle", + "y": 180 + }, + "rotation=9": { + "model": "sign/jungle", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/jungle", + "y": 225 + }, + "rotation=11": { + "model": "sign/jungle", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/jungle", + "y": 270 + }, + "rotation=13": { + "model": "sign/jungle", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/jungle", + "y": 315 + }, + "rotation=15": { + "model": "sign/jungle", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json new file mode 100644 index 00000000..898f7323 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/jungle_wall" + }, + "facing=west": { + "model": "sign/jungle_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/jungle_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/jungle_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json new file mode 100644 index 00000000..4ebcedcd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak" + }, + "rotation=1": { + "model": "sign/oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json new file mode 100644 index 00000000..26453d53 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/oak_wall" + }, + "facing=west": { + "model": "sign/oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json new file mode 100644 index 00000000..78722223 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/spruce" + }, + "rotation=1": { + "model": "sign/spruce", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/spruce", + "y": 45 + }, + "rotation=3": { + "model": "sign/spruce", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/spruce", + "y": 90 + }, + "rotation=5": { + "model": "sign/spruce", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/spruce", + "y": 135 + }, + "rotation=7": { + "model": "sign/spruce", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/spruce", + "y": 180 + }, + "rotation=9": { + "model": "sign/spruce", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/spruce", + "y": 225 + }, + "rotation=11": { + "model": "sign/spruce", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/spruce", + "y": 270 + }, + "rotation=13": { + "model": "sign/spruce", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/spruce", + "y": 315 + }, + "rotation=15": { + "model": "sign/spruce", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json new file mode 100644 index 00000000..8366709a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/spruce_wall" + }, + "facing=west": { + "model": "sign/spruce_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/spruce_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/spruce_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json new file mode 100644 index 00000000..201e42ad --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json new file mode 100644 index 00000000..3faf8661 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json new file mode 100644 index 00000000..6dd3269e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json new file mode 100644 index 00000000..a046ec14 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json new file mode 100644 index 00000000..5df00a29 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/crimson" + }, + "rotation=1": { + "model": "sign/crimson", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/crimson", + "y": 45 + }, + "rotation=3": { + "model": "sign/crimson", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/crimson", + "y": 90 + }, + "rotation=5": { + "model": "sign/crimson", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/crimson", + "y": 135 + }, + "rotation=7": { + "model": "sign/crimson", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/crimson", + "y": 180 + }, + "rotation=9": { + "model": "sign/crimson", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/crimson", + "y": 225 + }, + "rotation=11": { + "model": "sign/crimson", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/crimson", + "y": 270 + }, + "rotation=13": { + "model": "sign/crimson", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/crimson", + "y": 315 + }, + "rotation=15": { + "model": "sign/crimson", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json new file mode 100644 index 00000000..149227b2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/crimson_wall" + }, + "facing=west": { + "model": "sign/crimson_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/crimson_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/crimson_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json new file mode 100644 index 00000000..4af216ca --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/warped" + }, + "rotation=1": { + "model": "sign/warped", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/warped", + "y": 45 + }, + "rotation=3": { + "model": "sign/warped", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/warped", + "y": 90 + }, + "rotation=5": { + "model": "sign/warped", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/warped", + "y": 135 + }, + "rotation=7": { + "model": "sign/warped", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/warped", + "y": 180 + }, + "rotation=9": { + "model": "sign/warped", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/warped", + "y": 225 + }, + "rotation=11": { + "model": "sign/warped", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/warped", + "y": 270 + }, + "rotation=13": { + "model": "sign/warped", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/warped", + "y": 315 + }, + "rotation=15": { + "model": "sign/warped", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json new file mode 100644 index 00000000..b1d7f5e0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/warped_wall" + }, + "facing=west": { + "model": "sign/warped_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/warped_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/warped_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json new file mode 100644 index 00000000..bb82e85a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json new file mode 100644 index 00000000..30e9bd55 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json new file mode 100644 index 00000000..54a92e7e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/mangrove" + }, + "rotation=1": { + "model": "sign/mangrove", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/mangrove", + "y": 45 + }, + "rotation=3": { + "model": "sign/mangrove", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/mangrove", + "y": 90 + }, + "rotation=5": { + "model": "sign/mangrove", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/mangrove", + "y": 135 + }, + "rotation=7": { + "model": "sign/mangrove", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/mangrove", + "y": 180 + }, + "rotation=9": { + "model": "sign/mangrove", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/mangrove", + "y": 225 + }, + "rotation=11": { + "model": "sign/mangrove", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/mangrove", + "y": 270 + }, + "rotation=13": { + "model": "sign/mangrove", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/mangrove", + "y": 315 + }, + "rotation=15": { + "model": "sign/mangrove", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json new file mode 100644 index 00000000..d00760e7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/mangrove_wall" + }, + "facing=west": { + "model": "sign/mangrove_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/mangrove_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/mangrove_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json new file mode 100644 index 00000000..13702388 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json new file mode 100644 index 00000000..1e2a9d85 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json new file mode 100644 index 00000000..6c9fd930 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json new file mode 100644 index 00000000..c5302b1b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json new file mode 100644 index 00000000..bf726f10 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json new file mode 100644 index 00000000..d3a46453 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json new file mode 100644 index 00000000..71a4b708 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json new file mode 100644 index 00000000..13b215a5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json new file mode 100644 index 00000000..406c6318 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json new file mode 100644 index 00000000..6ff4c5b7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json new file mode 100644 index 00000000..b3b07061 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json new file mode 100644 index 00000000..aeef94bd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json new file mode 100644 index 00000000..a6c9286a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json new file mode 100644 index 00000000..20889940 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json new file mode 100644 index 00000000..506c4440 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json new file mode 100644 index 00000000..21c1ebd5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json new file mode 100644 index 00000000..52d90ee3 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json @@ -0,0 +1,115 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [ + 64, + 32 + ], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [ + 1, + 0, + 7 + ], + "to": [ + 15, + 10, + 9 + ], + "faces": { + "north": { + "uv": [ + 4.5, + 7, + 8, + 12 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 4, + 7, + 4.5, + 12 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 0.5, + 7, + 4, + 12 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 7, + 0.5, + 12 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 4, + 6, + 0.5, + 7 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 4, + 7, + 7.5, + 6 + ], + "texture": "#wood" + } + } + }, + { + "from": [ + 2, + 10, + 8 + ], + "to": [ + 14, + 16, + 8 + ], + "faces": { + "north": { + "uv": [ + 3.5, + 3, + 6.5, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 3.5, + 3, + 6.5, + 6 + ], + "texture": "#wood" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json new file mode 100644 index 00000000..db141f6d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json new file mode 100644 index 00000000..aefe92f3 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json new file mode 100644 index 00000000..e84c41f2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json new file mode 100644 index 00000000..e5feb72e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json new file mode 100644 index 00000000..7437c82f --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json new file mode 100644 index 00000000..3c8d9e5e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json new file mode 100644 index 00000000..3dee635d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json new file mode 100644 index 00000000..71e66b9c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json new file mode 100644 index 00000000..424ffe37 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json @@ -0,0 +1,347 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [ + 64, + 32 + ], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [ + 1, + 0, + 7 + ], + "to": [ + 15, + 10, + 9 + ], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 4.5, + 7, + 8, + 12 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 4, + 7, + 4.5, + 12 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 0.5, + 7, + 4, + 12 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 7, + 0.5, + 12 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 4, + 6, + 0.5, + 7 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 4, + 7, + 7.5, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "Hanger", + "from": [ + 0, + 14, + 6 + ], + "to": [ + 16, + 16, + 10 + ], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 6, + 2, + 10, + 3 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 0, + 2, + 1, + 3 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1, + 2, + 5, + 3 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 2, + 1, + 3 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 1, + 0, + 5, + 2 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 5, + 0, + 9, + 2 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainA1", + "from": [ + 4.8, + 10, + 10.5 + ], + "to": [ + 6.2, + 14, + 10.5 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "north": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainB2", + "from": [ + 10.5, + 10, + 4.8 + ], + "to": [ + 10.5, + 14, + 6.2 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "east": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainB1", + "from": [ + 9.8, + 10, + 5.5 + ], + "to": [ + 11.2, + 14, + 5.5 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "north": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainA2", + "from": [ + 5.5, + 10, + 9.8 + ], + "to": [ + 5.5, + 14, + 11.2 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "east": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json new file mode 100644 index 00000000..015ba2c0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json new file mode 100644 index 00000000..8870c317 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json new file mode 100644 index 00000000..18a25013 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/acacia_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/acacia_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/acacia_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/acacia_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/acacia_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/acacia_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/acacia_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/acacia_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/acacia_hanging" + }, + "rotation=9": { + "model": "sign/acacia_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/acacia_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/acacia_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/acacia_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/acacia_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/acacia_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/acacia_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json new file mode 100644 index 00000000..edbae40d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/acacia_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/acacia_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/acacia_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/acacia_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json new file mode 100644 index 00000000..5ff1854b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/bamboo_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/bamboo_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/bamboo_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/bamboo_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/bamboo_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/bamboo_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/bamboo_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/bamboo_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/bamboo_hanging" + }, + "rotation=9": { + "model": "sign/bamboo_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/bamboo_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/bamboo_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/bamboo_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/bamboo_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/bamboo_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/bamboo_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json new file mode 100644 index 00000000..1041460a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/bamboo" + }, + "rotation=1": { + "model": "sign/bamboo", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/bamboo", + "y": 45 + }, + "rotation=3": { + "model": "sign/bamboo", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/bamboo", + "y": 90 + }, + "rotation=5": { + "model": "sign/bamboo", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/bamboo", + "y": 135 + }, + "rotation=7": { + "model": "sign/bamboo", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/bamboo", + "y": 180 + }, + "rotation=9": { + "model": "sign/bamboo", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/bamboo", + "y": 225 + }, + "rotation=11": { + "model": "sign/bamboo", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/bamboo", + "y": 270 + }, + "rotation=13": { + "model": "sign/bamboo", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/bamboo", + "y": 315 + }, + "rotation=15": { + "model": "sign/bamboo", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json new file mode 100644 index 00000000..3bd24804 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/bamboo_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/bamboo_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/bamboo_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/bamboo_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json new file mode 100644 index 00000000..8b5ce481 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/bamboo_wall" + }, + "facing=west": { + "model": "sign/bamboo_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/bamboo_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/bamboo_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json new file mode 100644 index 00000000..6052d4f7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/birch_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/birch_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/birch_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/birch_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/birch_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/birch_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/birch_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/birch_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/birch_hanging" + }, + "rotation=9": { + "model": "sign/birch_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/birch_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/birch_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/birch_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/birch_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/birch_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/birch_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json new file mode 100644 index 00000000..656e8093 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/birch_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/birch_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/birch_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/birch_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json new file mode 100644 index 00000000..32ce33dc --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/cherry_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/cherry_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/cherry_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/cherry_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/cherry_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/cherry_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/cherry_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/cherry_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/cherry_hanging" + }, + "rotation=9": { + "model": "sign/cherry_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/cherry_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/cherry_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/cherry_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/cherry_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/cherry_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/cherry_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json new file mode 100644 index 00000000..4e562a26 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/cherry" + }, + "rotation=1": { + "model": "sign/cherry", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/cherry", + "y": 45 + }, + "rotation=3": { + "model": "sign/cherry", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/cherry", + "y": 90 + }, + "rotation=5": { + "model": "sign/cherry", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/cherry", + "y": 135 + }, + "rotation=7": { + "model": "sign/cherry", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/cherry", + "y": 180 + }, + "rotation=9": { + "model": "sign/cherry", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/cherry", + "y": 225 + }, + "rotation=11": { + "model": "sign/cherry", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/cherry", + "y": 270 + }, + "rotation=13": { + "model": "sign/cherry", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/cherry", + "y": 315 + }, + "rotation=15": { + "model": "sign/cherry", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json new file mode 100644 index 00000000..3e0a2d04 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/cherry_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/cherry_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/cherry_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/cherry_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json new file mode 100644 index 00000000..1b13342c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/cherry_wall" + }, + "facing=west": { + "model": "sign/cherry_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/cherry_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/cherry_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json new file mode 100644 index 00000000..6e4131f2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/crimson_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/crimson_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/crimson_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/crimson_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/crimson_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/crimson_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/crimson_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/crimson_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/crimson_hanging" + }, + "rotation=9": { + "model": "sign/crimson_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/crimson_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/crimson_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/crimson_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/crimson_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/crimson_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/crimson_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json new file mode 100644 index 00000000..63c560ae --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/crimson_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/crimson_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/crimson_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/crimson_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json new file mode 100644 index 00000000..a2bc0458 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/dark_oak_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/dark_oak_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/dark_oak_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/dark_oak_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/dark_oak_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/dark_oak_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/dark_oak_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/dark_oak_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/dark_oak_hanging" + }, + "rotation=9": { + "model": "sign/dark_oak_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/dark_oak_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/dark_oak_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/dark_oak_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/dark_oak_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/dark_oak_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/dark_oak_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json new file mode 100644 index 00000000..138154f9 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/dark_oak_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/dark_oak_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/dark_oak_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/dark_oak_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json new file mode 100644 index 00000000..9f1f9eeb --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/jungle_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/jungle_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/jungle_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/jungle_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/jungle_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/jungle_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/jungle_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/jungle_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/jungle_hanging" + }, + "rotation=9": { + "model": "sign/jungle_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/jungle_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/jungle_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/jungle_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/jungle_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/jungle_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/jungle_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json new file mode 100644 index 00000000..3bdb8191 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/jungle_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/jungle_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/jungle_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/jungle_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json new file mode 100644 index 00000000..ff977160 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/mangrove_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/mangrove_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/mangrove_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/mangrove_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/mangrove_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/mangrove_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/mangrove_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/mangrove_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/mangrove_hanging" + }, + "rotation=9": { + "model": "sign/mangrove_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/mangrove_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/mangrove_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/mangrove_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/mangrove_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/mangrove_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/mangrove_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json new file mode 100644 index 00000000..9d1d019a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/mangrove_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/mangrove_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/mangrove_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/mangrove_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json new file mode 100644 index 00000000..01e66da8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/oak_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/oak_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/oak_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/oak_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/oak_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/oak_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/oak_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/oak_hanging" + }, + "rotation=9": { + "model": "sign/oak_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/oak_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/oak_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/oak_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/oak_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/oak_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/oak_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json new file mode 100644 index 00000000..9af80947 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/oak_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/oak_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/oak_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/oak_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json new file mode 100644 index 00000000..ee9509f6 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/spruce_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/spruce_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/spruce_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/spruce_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/spruce_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/spruce_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/spruce_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/spruce_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/spruce_hanging" + }, + "rotation=9": { + "model": "sign/spruce_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/spruce_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/spruce_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/spruce_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/spruce_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/spruce_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/spruce_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json new file mode 100644 index 00000000..0b9ec25a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/spruce_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/spruce_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/spruce_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/spruce_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json new file mode 100644 index 00000000..93764856 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/warped_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/warped_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/warped_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/warped_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/warped_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/warped_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/warped_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/warped_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/warped_hanging" + }, + "rotation=9": { + "model": "sign/warped_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/warped_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/warped_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/warped_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/warped_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/warped_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/warped_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json new file mode 100644 index 00000000..378e80f8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/warped_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/warped_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/warped_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/warped_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/modelsBuilder.ts b/prismarine-viewer/viewer/prepare/modelsBuilder.ts index 2a0cac57..b6e5268f 100644 --- a/prismarine-viewer/viewer/prepare/modelsBuilder.ts +++ b/prismarine-viewer/viewer/prepare/modelsBuilder.ts @@ -161,7 +161,7 @@ function prepareModel (model: BlockModel, texturesJson) { const getFinalTexture = (originalBlockName) => { // texture name e.g. blocks/anvil_base - const cleanBlockName = cleanupBlockName(originalBlockName); + const cleanBlockName = cleanupBlockName(originalBlockName) return { ...texturesJson[cleanBlockName], /* __debugName: cleanBlockName */ } } @@ -187,10 +187,12 @@ function prepareModel (model: BlockModel, texturesJson) { for (const sideName of Object.keys(elem.faces)) { const face = elem.faces[sideName] + const textureRaw = face.texture.charAt(0) === '#' + ? finalTextures![face.texture.slice(1)] + : getFinalTexture(face.texture) + if (!textureRaw) throw new Error(`Texture ${face.texture} in ${JSON.stringify(model.textures)} not found`) const finalTexture = deepCopy( - face.texture.charAt(0) === '#' - ? finalTextures![face.texture.slice(1)] - : getFinalTexture(face.texture) + textureRaw ) const _from = elem.from diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index b343e595..e64b7cff 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -4,9 +4,10 @@ import { McAssets } from './modelsBuilder' import path from 'path' import fs from 'fs' import { fileURLToPath } from 'url' +import { versionToNumber } from './utils' // todo refactor -const twoTileTextures: string[] = [] +const handledBlocks = ['water', 'lava', 'barrier'] const origSizeTextures: string[] = [] let currentImage: Jimp let currentBlockName: string @@ -121,115 +122,6 @@ const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { await addSimpleCubeWithSides(shulkerBoxTextures) } -const handleSign = async (dataBase: string, match: RegExpExecArray) => { - const states = getBlockStates(currentBlockName) - if (!states) return - - const [, signMaterial = ''] = match - currentImage = await Jimp.read(`${dataBase}entity/${signMaterial ? `signs/${signMaterial}` : 'sign'}.png`) - // todo cache - const signTextures = { - // todo correct mapping - // todo alg to fit to the side - signboard_side: justCrop(0, 2, 2, 12), - face: justCrop(2, 2, 24, 12), - up: justCrop(2, 0, 24, 2), - support: justCrop(0, 16, 2, 14) - } - const blockTextures = await getBlockTexturesFromJimp(signTextures, true) - - const isWall = currentBlockName.includes('wall_') - const isHanging = currentBlockName.includes('hanging_') - const rotationState = states.find(state => state.name === 'rotation') - const faceTexture = { texture: blockTextures.face.texture, uv: blockTextures.face.uv } - if (isWall || isHanging) { - // todo isHanging - if (!isHanging) { - const facingState = states.find(state => state.name === 'facing')! - const facingMap = { - south: 0, - west: 90, - north: 180, - east: 270 - } - - currentMcAssets.blocksStates[currentBlockName] = { - "variants": Object.fromEntries( - facingState.values!.map((_val, i) => { - const val = _val as string - return [`facing=${val}`, { - "model": currentBlockName, - y: facingMap[val], - }] - }) - ) - } - currentMcAssets.blocksModels[currentBlockName] = { - elements: [ - { - // signboard - "from": [0, 4.5, 0], - "to": [16, 11.5, 1.5], - faces: { - south: faceTexture, - east: blockTextures.signboard_side, - west: blockTextures.signboard_side, - up: blockTextures.up, - down: blockTextures.up, - }, - } - ], - } - } - } else if (rotationState) { - currentMcAssets.blocksStates[currentBlockName] = { - "variants": Object.fromEntries( - Array.from({ length: 16 }).map((_val, i) => { - return [`rotation=${i}`, { - "model": currentBlockName, - y: i * (45 / 2), - }] - }) - ) - } - - const supportTexture = blockTextures.support - // TODO fix models.ts, apply textures for signs correctly! - // const supportTexture = { texture: supportTextureImg, uv: [0, 0, 16, 16] } - currentMcAssets.blocksModels[currentBlockName] = { - elements: [ - { - // support post - "from": [7.5, 0, 7.5], - "to": [8.5, 9, 8.5], - faces: { - // todo 14 - north: supportTexture, - east: supportTexture, - south: supportTexture, - west: supportTexture, - } - }, - { - // signboard - "from": [0, 9, 7.25], - "to": [16, 16, 8.75], - faces: { - north: faceTexture, - south: faceTexture, - east: blockTextures.signboard_side, - west: blockTextures.signboard_side, - up: blockTextures.up, - down: blockTextures.up, - }, - } - ], - } - } - twoTileTextures.push(blockTextures.face.texture) - twoTileTextures.push(blockTextures.up.texture) -} - // TODO! should not be there! move to data with signs! const chestModels = { chest: { @@ -405,10 +297,10 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { async function loadBlockModelTextures (dataBase: string, blockModel: any) { for (const key in blockModel.textures) { - const texture: string = blockModel.textures[key] - currentImage = await Jimp.read(dataBase + texture + '.png') + let texture: string = blockModel.textures[key] + const useAssetsPath = !!texture.match(/^[0-9.]+\//) blockModel.textures.particle = texture - generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, texture + '.png'), 'base64')}` + generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, useAssetsPath ? '..' : '', texture + '.png'), 'base64')}` origSizeTextures[texture] = true } } @@ -416,11 +308,6 @@ async function loadBlockModelTextures (dataBase: string, blockModel: any) { const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], - [/^sign$/, handleSign], - [/^standing_sign$/, handleSign], - [/^wall_sign$/, handleSign], - [/(.+)_wall_sign$/, handleSign], - [/(.+)_sign$/, handleSign], [/^(?:(ender|trapped)_)?chest$/, handleChest], // [/(^|(.+)_)bed$/, handleBed], // no-op just suppress warning @@ -439,25 +326,58 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { } } -const handleExternalData = async (dataBase: string, version: string) => { - const [major, minor] = version.split(".") - const dataVer = `${major}.${minor}` - const baseDir = path.join(__dirname, 'data', dataVer) - if (!fs.existsSync(baseDir)) return +async function readAllBlockStates (blockStatesDir: string) { + const files = fs.readdirSync(blockStatesDir) + for (const file of files) { + if (file.endsWith('.json')) { + const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, file), 'utf-8')) + const name = file.replace('.json', '') + currentMcAssets.blocksStates[name] = state + handledBlocks.push(name) + } else { + await readAllBlockStates(path.join(blockStatesDir, file)) + } + } +} - const blockModelsDir = path.join(baseDir, 'blockModels') - const allBlockModels = fs.readdirSync(blockModelsDir).map(x => x.replace('.json', '')) - for (const blockModel of allBlockModels) { - const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, blockModel + '.json'), 'utf-8')) - currentMcAssets.blocksModels[blockModel] = model - await loadBlockModelTextures(dataBase, model) +async function readAllBlockModels (dataBase: string, blockModelsDir: string, completePath: string) { + const actualPath = completePath.length ? completePath + "/" : "" + const files = fs.readdirSync(blockModelsDir) + for (const file of files) { + if (file.endsWith('.json')) { + const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, file), 'utf-8')) + const name = actualPath + file.replace('.json', '') + currentMcAssets.blocksModels[name] = model + await loadBlockModelTextures(dataBase, model) + } else { + await readAllBlockModels(dataBase, path.join(blockModelsDir, file), actualPath + file) + } + } +} + +const handleExternalData = async (assetsPathRoot: string, version: string) => { + const currentVersionNumber = versionToNumber(version) + const versions = fs.readdirSync(path.join(__dirname, 'data'), { withFileTypes: true }) + .filter(x => x.isDirectory()) + .map(x => x.name) + .sort((a, b) => versionToNumber(b) - versionToNumber(a)) + + const allAssetsVersions = fs.readdirSync(assetsPathRoot, { withFileTypes: true }) + .filter(x => x.isDirectory()) + .map(x => x.name) + .sort((a, b) => versionToNumber(b) - versionToNumber(a)) + + const getAssetsVersion = (version: string) => { + return allAssetsVersions[version] ?? allAssetsVersions.find(x => x.startsWith(version)) } - const blockStatesDir = path.join(baseDir, 'blockStates') - const allBlockStates = fs.readdirSync(blockStatesDir).map(x => x.replace('.json', '')) - for (const blockState of allBlockStates) { - const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, blockState + '.json'), 'utf-8')) - currentMcAssets.blocksStates[blockState] = state + for (const curVer of versions) { + const baseDir = path.join(__dirname, 'data', curVer) + if (versionToNumber(curVer) > currentVersionNumber) continue + + const assetsVersion = getAssetsVersion(curVer) + await readAllBlockStates(path.join(baseDir, 'blockStates')) + await readAllBlockModels(path.join(assetsPathRoot, assetsVersion), path.join(baseDir, 'blockModels'), "") } } @@ -466,7 +386,6 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const allTheBlocks = mcData.blocksArray.map(x => x.name) currentMcAssets = mcAssets - const handledBlocks = ['water', 'lava', 'barrier'] // todo const ignoredBlocks = ['skull', 'structure_void', 'banner', 'bed', 'end_portal'] @@ -481,7 +400,7 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } } - await handleExternalData(mcAssets.directory, mcAssets.version) + await handleExternalData(path.join(mcAssets.directory, '..'), mcAssets.version) const warnings: string[] = [] for (const [name, model] of Object.entries(mcAssets.blocksModels)) { @@ -498,5 +417,5 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures, origSizeTextures } + return { generated: generatedImageTextures, origSizeTextures } } From 2d4b89651cdd8ff4ad9268d51aeb1c90f01b8968 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Jun 2024 21:17:07 +0300 Subject: [PATCH 058/107] format, remove useless comment --- .../viewer/lib/worldrendererThree.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 095e5a94..9a76474b 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -22,7 +22,7 @@ export class WorldRendererThree extends WorldRendererCommon { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) } - constructor(public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) { + constructor (public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) { super(config) this.starField = new StarField(scene) } @@ -181,13 +181,12 @@ export class WorldRendererThree extends WorldRendererCommon { const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ map: tex, transparent: true, })) mesh.renderOrder = 999 - // todo @sa2urami shouldnt all this be done in worker? - const lineHeight = 7 / 16; + const lineHeight = 7 / 16 const scaleFactor = isHanging ? 1.3 : 1 mesh.scale.set(1 * scaleFactor, lineHeight * scaleFactor, 1 * scaleFactor) const thickness = (isHanging ? 2 : 1.5) / 16 - const wallSpacing = 0.25 / 16; + const wallSpacing = 0.25 / 16 if (isWall && !isHanging) { mesh.position.set(0, 0, -0.5 + thickness + wallSpacing + 0.0001) } else { @@ -199,9 +198,9 @@ export class WorldRendererThree extends WorldRendererCommon { rotation * (isWall ? 90 : 45 / 2) ), 0) group.add(mesh) - const height = (isHanging ? 10 : 8)/16 + const height = (isHanging ? 10 : 8) / 16 const heightOffset = (isHanging ? 0 : isWall ? 4.333 : 9.333) / 16 - const textPosition = height/2 + heightOffset + const textPosition = height / 2 + heightOffset group.position.set(position.x + 0.5, position.y + textPosition, position.z + 0.5) return group } @@ -322,7 +321,7 @@ class StarField { } } - constructor(private scene: THREE.Scene) { + constructor (private scene: THREE.Scene) { } addToScene () { @@ -386,7 +385,7 @@ class StarField { const version = parseInt(THREE.REVISION.replace(/\D+/g, '')) class StarfieldMaterial extends THREE.ShaderMaterial { - constructor() { + constructor () { super({ uniforms: { time: { value: 0.0 }, fade: { value: 1.0 } }, vertexShader: /* glsl */ ` From 4f20e2481947d813317b3888e75e77b0b85f39dc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 12 Jun 2024 21:14:48 +0300 Subject: [PATCH 059/107] up flying squid --- package.json | 2 +- pnpm-lock.yaml | 79 ++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 7bbde636..f5f55c7f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.24", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.26", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38a9ebb6..3cbab433 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.24 - version: '@zardoy/flying-squid@0.0.24(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.26 + version: '@zardoy/flying-squid@0.0.26(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -386,7 +386,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chunk: specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.24': - resolution: {integrity: sha512-C+VNHyh9yYB7aG9OL6r9NR5bF73fyRQ0rHhkvvz901hLBZI3+5nOPdcA6XwJm9XX9BYStXbLTHp6shmo20JRHQ==} + '@zardoy/flying-squid@0.0.26': + resolution: {integrity: sha512-JUGrr+9I4vgXrgjop5iRpulRhWUgRbPC1j+xPapgICtJPEGuekpXIOOBjAL+X7yu7I5IcrmtG4XCjvTKcC0lIQ==} engines: {node: '>=8'} hasBin: true @@ -6718,13 +6718,8 @@ packages: prismarine-chat@1.9.1: resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16} - version: 1.35.0 - engines: {node: '>=14'} - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a} version: 1.35.0 engines: {node: '>=14'} @@ -6747,6 +6742,10 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29} version: 2.7.0 + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20} + version: 2.8.0 + prismarine-realms@1.3.2: resolution: {integrity: sha512-5apl9Ru8veTj5q2OozRc4GZOuSIcs3yY4UEtALiLKHstBe8bRw8vNlaz4Zla3jsQ8yP/ul1b1IJINTRbocuA6g==} @@ -6764,9 +6763,9 @@ packages: prismarine-windows@2.9.0: resolution: {integrity: sha512-fm4kOLjGFPov7TEJRmXHoiPabxIQrG36r2mDjlNxfkcLfMHFb3/1ML6mp4iRQa7wL0GK4DIAyiBqCWoeWDxARg==} - prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465} - version: 3.6.2 + prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7} + version: 3.6.3 engines: {node: '>=8.0.0'} process-nextick-args@2.0.1: @@ -11931,7 +11930,7 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.24(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.26(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 change-case: 4.1.2 @@ -11946,13 +11945,13 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0) prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 rambda: 9.2.0 random-seed: 0.3.0 range: 0.0.3 @@ -13212,7 +13211,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) random-seed: 0.3.0 vec3: 0.1.8 @@ -15779,7 +15778,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15787,7 +15786,7 @@ snapshots: prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) prismarine-registry: 1.7.0 prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 protodef: 1.15.0 typed-emitter: 1.4.0 vec3: 0.1.8 @@ -15802,7 +15801,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15810,7 +15809,7 @@ snapshots: prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) prismarine-registry: 1.7.0 prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 protodef: 1.15.0 typed-emitter: 1.4.0 vec3: 0.1.8 @@ -16526,20 +16525,7 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0): - dependencies: - prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 - smart-buffer: 4.2.0 - uint4: 0.1.2 - vec3: 0.1.8 - xxhash-wasm: 0.4.2 - transitivePeerDependencies: - - minecraft-data - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 @@ -16580,13 +16566,24 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0): dependencies: - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 uint4: 0.1.2 vec3: 0.1.8 transitivePeerDependencies: - minecraft-data + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0): + dependencies: + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-nbt: 2.5.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 + uint4: 0.1.2 + vec3: 0.1.8 + transitivePeerDependencies: + - minecraft-data + prismarine-realms@1.3.2(encoding@0.1.13): dependencies: debug: 4.3.4(supports-color@8.1.1) @@ -16609,7 +16606,7 @@ snapshots: minecraft-data: 3.65.0 prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-nbt: 2.2.1 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 vec3: 0.1.8 prismarine-windows@2.9.0: @@ -16618,7 +16615,7 @@ snapshots: prismarine-registry: 1.7.0 typed-emitter: 2.1.0 - prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465: + prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7: dependencies: vec3: 0.1.8 From 5be093a25f88dae99d216416b6f4cd64bc06ecd2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 13 Jun 2024 03:46:59 +0300 Subject: [PATCH 060/107] feat: support world saves for all versions of Minecraft Java! --- package.json | 2 +- pnpm-lock.yaml | 100 +++++++----------- .../viewer/lib/worldDataEmitter.ts | 2 +- src/createLocalServer.ts | 2 +- src/getCollisionShapes.ts | 6 +- src/globals.d.ts | 4 +- src/loadSave.ts | 10 +- src/react/MainMenu.tsx | 2 +- src/soundSystem.ts | 10 +- src/water.ts | 2 +- 10 files changed, 61 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index f5f55c7f..37e24dbb 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.26", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.27", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cbab433..052069c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.26 - version: '@zardoy/flying-squid@0.0.26(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.27 + version: '@zardoy/flying-squid@0.0.27(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -150,7 +150,7 @@ importers: version: 6.1.1 prismarine-provider-anvil: specifier: github:zardoy/prismarine-provider-anvil#everything - version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0) prosemirror-example-setup: specifier: ^1.2.2 version: 1.2.2 @@ -302,7 +302,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -383,10 +383,10 @@ importers: version: 1.3.6 prismarine-block: specifier: github:zardoy/prismarine-block#next-era - version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chunk: specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.26': - resolution: {integrity: sha512-JUGrr+9I4vgXrgjop5iRpulRhWUgRbPC1j+xPapgICtJPEGuekpXIOOBjAL+X7yu7I5IcrmtG4XCjvTKcC0lIQ==} + '@zardoy/flying-squid@0.0.27': + resolution: {integrity: sha512-8QlPCyLqNQYxsGBMBNNGbfc1HdRPO/t3nBr5NzINEridj772DEbgGHxl252rjZWWELt/3t/k3m6e4k9qS7/ZdA==} engines: {node: '>=8'} hasBin: true @@ -4097,8 +4097,8 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: - resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687} + diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015: + resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015} version: 1.3.0 diff-sequences@29.6.3: @@ -6067,8 +6067,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec} version: 4.20.1 engines: {node: '>=18'} @@ -6708,18 +6708,15 @@ packages: minecraft-data: 3.65.0 prismarine-registry: ^1.1.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0} + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8} version: 1.17.1 prismarine-chat@1.10.1: resolution: {integrity: sha512-XukYcuueuhDxzEXG7r8BZyt6jOObrPPB4JESCgb+/XenB9nExoSHF8eTQWWj8faKPLqm1dRQaYwFJlNBlJZJUw==} - prismarine-chat@1.9.1: - resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3} version: 1.35.0 engines: {node: '>=14'} @@ -6738,12 +6735,8 @@ packages: prismarine-physics@1.8.0: resolution: {integrity: sha512-gbM+S+bmVtOKVv+Z0WGaHMeEeBHISIDsRDRlv8sr0dex3ZJRhuq8djA02CBreguXtI18ZKh6q3TSj2qDr45NHA==} - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29} - version: 2.7.0 - - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20} + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc} version: 2.8.0 prismarine-realms@1.3.2: @@ -11930,12 +11923,12 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.26(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.27(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 change-case: 4.1.2 colors: 1.4.0 - diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687 + diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015 emit-then: 2.0.0 exit-hook: 2.2.1 flatmap: 0.0.3 @@ -11945,11 +11938,11 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0) prismarine-windows: 2.9.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 rambda: 9.2.0 @@ -13208,10 +13201,11 @@ snapshots: dependencies: dequal: 2.0.3 - diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: + diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) + prismarine-registry: 1.7.0 random-seed: 0.3.0 vec3: 0.1.8 @@ -15764,7 +15758,7 @@ snapshots: mineflayer-pathfinder@2.4.4: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.2.1 @@ -15776,9 +15770,9 @@ snapshots: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15794,14 +15788,14 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -16503,11 +16497,11 @@ snapshots: minecraft-data: 3.65.0 prismarine-registry: 1.7.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: dependencies: minecraft-data: 3.65.0 prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-chat: 1.9.1 + prismarine-chat: 1.10.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 @@ -16518,17 +16512,10 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 - prismarine-chat@1.9.1: - dependencies: - mojangson: 2.0.4 - prismarine-item: 1.14.0 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 smart-buffer: 4.2.0 @@ -16564,19 +16551,10 @@ snapshots: prismarine-nbt: 2.5.0 vec3: 0.1.8 - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0): + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0): dependencies: - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) - prismarine-nbt: 2.5.0 - uint4: 0.1.2 - vec3: 0.1.8 - transitivePeerDependencies: - - minecraft-data - - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0): - dependencies: - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 uint4: 0.1.2 @@ -16604,7 +16582,7 @@ snapshots: prismarine-schematic@1.2.3: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-nbt: 2.2.1 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 vec3: 0.1.8 diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 3a8fbd40..ed578040 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -83,7 +83,7 @@ export class WorldDataEmitter extends EventEmitter { get (_target, posKey, receiver) { if (typeof posKey !== 'string') return const [x, y, z] = posKey.split(',').map(Number) - return bot.world.getBlock(new Vec3(x, y, z)).entity + return bot.world.getBlock(new Vec3(x, y, z))?.entity }, })) this.emitter.emit('renderDistance', this.viewDistance) diff --git a/src/createLocalServer.ts b/src/createLocalServer.ts index 44bc2187..d0beac9a 100644 --- a/src/createLocalServer.ts +++ b/src/createLocalServer.ts @@ -14,4 +14,4 @@ export const startLocalServer = (serverOptions) => { // features that flying-squid doesn't support at all // todo move & generate in flying-squid -export const unsupportedLocalServerFeatures = ['transactionPacketExists', 'teleportUsesOwnPacket', 'dimensionDataIsAvailable'] +export const unsupportedLocalServerFeatures = ['transactionPacketExists', 'teleportUsesOwnPacket'] diff --git a/src/getCollisionShapes.ts b/src/getCollisionShapes.ts index 0faf5b6a..4ee0e802 100644 --- a/src/getCollisionShapes.ts +++ b/src/getCollisionShapes.ts @@ -1,4 +1,4 @@ -import { adoptBlockOrItemNamesFromLatest } from 'flying-squid/dist/blockRenames' +import { getRenamedData } from 'flying-squid/dist/blockRenames' import collisionShapesInit from '../generated/latestBlockCollisionsShapes.json' import outputInteractionShapesJson from './interactionShapesGenerated.json' @@ -6,7 +6,7 @@ import outputInteractionShapesJson from './interactionShapesGenerated.json' window.globalGetCollisionShapes = (version) => { // todo use the same in resourcepack const versionFrom = collisionShapesInit.version - const renamedBlocks = adoptBlockOrItemNamesFromLatest('blocks', Object.keys(collisionShapesInit.blocks), versionFrom, version) + const renamedBlocks = getRenamedData('blocks', Object.keys(collisionShapesInit.blocks), versionFrom, version) const collisionShapes = { ...collisionShapesInit, blocks: Object.fromEntries(Object.entries(collisionShapesInit.blocks).map(([, shape], i) => [renamedBlocks[i], shape])) @@ -17,7 +17,7 @@ window.globalGetCollisionShapes = (version) => { export default () => { customEvents.on('gameLoaded', () => { // todo also remap block states (e.g. redstone)! - const renamedBlocksInteraction = adoptBlockOrItemNamesFromLatest('blocks', Object.keys(outputInteractionShapesJson), '1.20.2', bot.version) + const renamedBlocksInteraction = getRenamedData('blocks', Object.keys(outputInteractionShapesJson), '1.20.2', bot.version) const interactionShapes = { ...outputInteractionShapesJson, ...Object.fromEntries(Object.entries(outputInteractionShapesJson).map(([block, shape], i) => [renamedBlocksInteraction[i], shape])) diff --git a/src/globals.d.ts b/src/globals.d.ts index 6a38a21d..05b29a14 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -3,7 +3,9 @@ declare const THREE: typeof import('three') // todo make optional declare const bot: Omit & { - world: import('prismarine-world').world.WorldSync + world: Omit & { + getBlock: (pos: import('vec3').Vec3) => import('prismarine-block').Block | null + } _client: Omit & { write: typeof import('./generatedClientPackets').clientWrite on: typeof import('./generatedServerPackets').clientOn diff --git a/src/loadSave.ts b/src/loadSave.ts index af9d078c..7ca454ff 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -1,15 +1,16 @@ import fs from 'fs' import path from 'path' -import { supportedVersions } from 'flying-squid/dist/lib/version' import * as nbt from 'prismarine-nbt' import { proxy } from 'valtio' import { gzip } from 'node-gzip' +import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' import { options } from './optionsStorage' import { nameToMcOfflineUUID, disconnect } from './flyingSquidUtils' import { existsViaStats, forceCachedDataPaths, forceRedirectPaths, mkdirRecursive } from './browserfs' import { isMajorVersionGreater } from './utils' import { activeModalStacks, insertActiveModalStack, miscUiState } from './globalState' +import supportedVersions from './supportedVersions.mjs' // todo include name of opened handle (zip)! // additional fs metadata @@ -91,13 +92,12 @@ export const loadSave = async (root = '/world') => { const newVersion = '1.8.8' version = newVersion } - // const lastSupportedVersion = supportedVersions.at(-1)! - const lastTestedVersion = '1.18.2' + const lastSupportedVersion = supportedVersions.at(-1)! const firstSupportedVersion = supportedVersions[0] const lowerBound = isMajorVersionGreater(firstSupportedVersion, version) - const upperBound = isMajorVersionGreater(version, lastTestedVersion) + const upperBound = versionToNumber(version) > versionToNumber(lastSupportedVersion) if (lowerBound || upperBound) { - version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastTestedVersion) + version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastSupportedVersion) if (!version) return } if (levelDat.WorldGenSettings) { diff --git a/src/react/MainMenu.tsx b/src/react/MainMenu.tsx index 3e3170f4..43908645 100644 --- a/src/react/MainMenu.tsx +++ b/src/react/MainMenu.tsx @@ -103,7 +103,7 @@ export default ({ connectToServerAction, mapsProvider, singleplayerAction, optio icon='pixelarticons:folder' onClick={openFileAction} initialTooltip={{ - content: 'Load any 1.8-1.16 Java world' + (haveDirectoryPicker() ? '' : ' (zip)'), + content: 'Load any Java world save' + (haveDirectoryPicker() ? '' : ' (zip)!'), placement: 'bottom-start', }} /> diff --git a/src/soundSystem.ts b/src/soundSystem.ts index a2cc1f70..e7fdaee7 100644 --- a/src/soundSystem.ts +++ b/src/soundSystem.ts @@ -144,10 +144,12 @@ subscribeKey(miscUiState, 'gameLoaded', async () => { // movement happening if (Date.now() - lastStepSound > 300) { const blockUnder = bot.world.getBlock(bot.entity.position.offset(0, -1, 0)) - const stepSound = getStepSound(blockUnder) - if (stepSound) { - await playHardcodedSound(stepSound, undefined, 0.6)// todo not sure why 0.6 - lastStepSound = Date.now() + if (blockUnder) { + const stepSound = getStepSound(blockUnder) + if (stepSound) { + await playHardcodedSound(stepSound, undefined, 0.6)// todo not sure why 0.6 + lastStepSound = Date.now() + } } } } diff --git a/src/water.ts b/src/water.ts index 9f8ec557..d8b4b41c 100644 --- a/src/water.ts +++ b/src/water.ts @@ -19,7 +19,7 @@ customEvents.on('gameLoaded', () => { } bot.on('physicsTick', () => { // todo - const _inWater = bot.world.getBlock(bot.entity.position.offset(0, 1, 0)).name === 'water' + const _inWater = bot.world.getBlock(bot.entity.position.offset(0, 1, 0))?.name === 'water' if (_inWater !== inWater) { inWater = _inWater updateInWater() From 216b1712c2dd418636d9fcc9c6e632137555e2d9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 13 Jun 2024 19:47:48 +0300 Subject: [PATCH 061/107] more basic tests. test joining to a local java vanilla server, movement! --- .eslintrc.json | 17 +++++++++ .gitignore | 1 + cypress/e2e/index.spec.ts | 57 ++++++++++++++++++++++++++++- cypress/e2e/shared.ts | 3 ++ cypress/plugins/index.js | 9 ++++- cypress/plugins/server.properties | 61 +++++++++++++++++++++++++++++++ cypress/plugins/startServer.ts | 45 +++++++++++++++++++++++ index.html | 2 +- src/index.ts | 7 +++- src/react/Chat.tsx | 3 +- src/worldInteractions.ts | 3 +- 11 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 cypress/plugins/server.properties create mode 100644 cypress/plugins/startServer.ts diff --git a/.eslintrc.json b/.eslintrc.json index 98388260..a91015d2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -96,5 +96,22 @@ "unicorn/filename-case": "off", "max-depth": "off" }, + "overrides": [ + { + "files": [ + "*.js" + ], + "rules": { + "space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ] + } + } + ], "root": true } diff --git a/.gitignore b/.gitignore index 240b751a..3a188862 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,6 @@ out .vercel generated storybook-static +server-jar src/react/npmReactComponents.ts diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 05b50211..ec7d84e7 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -1,4 +1,6 @@ +/* eslint-disable max-nested-callbacks */ /// +import supportedVersions from '../../src/supportedVersions.mjs' import { setOptions, cleanVisit, visit } from './shared' // todo use ssl @@ -12,7 +14,7 @@ const compareRenderedFlatWorld = () => { } const testWorldLoad = () => { - cy.document().then({ timeout: 20_000 }, doc => { + return cy.document().then({ timeout: 20_000 }, doc => { return new Cypress.Promise(resolve => { doc.addEventListener('cypress-world-ready', resolve) }) @@ -36,7 +38,7 @@ it('Loads & renders singleplayer', () => { testWorldLoad() }) -it('Joins to server', () => { +it('Joins to local flying-squid server', () => { visit('/?ip=localhost&version=1.16.1') window.localStorage.version = '' // todo replace with data-test @@ -47,9 +49,60 @@ it('Joins to server', () => { testWorldLoad() }) +it('Joins to local latest Java vanilla server', () => { + const version = supportedVersions.at(-1)! + cy.task('startServer', [version, 25_590]).then(() => { + visit('/?ip=localhost:25590&username=bot') + cy.get('[data-test-id="connect-qs"]').click() + testWorldLoad().then(() => { + let x = 0 + let z = 0 + cy.window().then((win) => { + x = win.bot.entity.position.x + z = win.bot.entity.position.z + }) + cy.document().trigger('keydown', { code: 'KeyW' }) + cy.wait(1500).then(() => { + cy.document().trigger('keyup', { code: 'KeyW' }) + cy.window().then(async (win) => { + // eslint-disable-next-line prefer-destructuring + const bot: typeof __type_bot = win.bot + // todo use f3 stats instead + if (bot.entity.position.x === x && bot.entity.position.z === z) { + throw new Error('Player not moved') + } + + bot.chat('Hello') // todo assert + bot.chat('/gamemode creative') + // bot.on('message', () => { + void bot.creative.setInventorySlot(bot.inventory.hotbarStart, new win.PrismarineItem(1, 1, 0)) + // }) + await bot.lookAt(bot.entity.position.offset(1, 0, 1)) + }).then(() => { + cy.document().trigger('mousedown', { button: 2, isTrusted: true, force: true }) // right click + cy.document().trigger('mouseup', { button: 2, isTrusted: true, force: true }) + cy.wait(1000) + }) + }) + }) + }) +}) + it('Loads & renders zip world', () => { cleanVisit() cy.get('[data-test-id="select-file-folder"]').click({ shiftKey: true }) cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) testWorldLoad() }) + + +it.skip('Loads & renders world from folder', () => { + cleanVisit() + // dragndrop folder + cy.get('[data-test-id="select-file-folder"]').click() + cy.get('input[type="file"]').selectFile('server-jar/world', { + force: true, + // action: 'drag-drop', + }) + testWorldLoad() +}) diff --git a/cypress/e2e/shared.ts b/cypress/e2e/shared.ts index 9292a8d5..47518f1b 100644 --- a/cypress/e2e/shared.ts +++ b/cypress/e2e/shared.ts @@ -3,6 +3,9 @@ import { AppOptions } from '../../src/optionsStorage' export const cleanVisit = (url?) => { cy.clearLocalStorage() visit(url) + window.localStorage.options = { + chatOpacity: 0 + } } export const visit = (url = '/') => { window.localStorage.cypress = 'true' diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index 35dc2989..e55f5d26 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -2,11 +2,13 @@ const { cypressEsbuildPreprocessor } = require('cypress-esbuild-preprocessor') const { initPlugin } = require('cypress-plugin-snapshots/plugin') const polyfill = require('esbuild-plugin-polyfill-node') +const { startMinecraftServer } = require('./startServer') module.exports = (on, config) => { initPlugin(on, config) on('file:preprocessor', cypressEsbuildPreprocessor({ esbuildOptions: { + sourcemap: true, plugins: [ polyfill.polyfillNode({ polyfills: { @@ -17,10 +19,15 @@ module.exports = (on, config) => { }, })) on('task', { - log (message) { + log(message) { console.log(message) return null }, }) + on('task', { + async startServer([version, port]) { + return startMinecraftServer(version, port) + } + }) return config } diff --git a/cypress/plugins/server.properties b/cypress/plugins/server.properties new file mode 100644 index 00000000..5873a1aa --- /dev/null +++ b/cypress/plugins/server.properties @@ -0,0 +1,61 @@ +#Minecraft server properties +allow-flight=false +allow-nether=true +broadcast-console-to-ops=true +broadcast-rcon-to-ops=true +difficulty=peaceful +enable-command-block=false +enable-jmx-monitoring=false +enable-query=false +enable-rcon=false +enable-status=true +enforce-secure-profile=true +enforce-whitelist=false +entity-broadcast-range-percentage=100 +force-gamemode=false +function-permission-level=2 +gamemode=survival +generate-structures=true +generator-settings={} +hardcore=false +hide-online-players=false +initial-disabled-packs= +initial-enabled-packs=vanilla +level-name=world +level-seed= +level-type=flat +log-ips=true +max-build-height=256 +max-chained-neighbor-updates=1000000 +max-players=20 +max-tick-time=60000 +max-world-size=29999984 +motd=A Minecraft Server +network-compression-threshold=256 +online-mode=false +op-permission-level=4 +player-idle-timeout=0 +prevent-proxy-connections=false +pvp=true +query.port=25565 +rate-limit=0 +rcon.password= +rcon.port=25575 +require-resource-pack=false +resource-pack= +resource-pack-id= +resource-pack-prompt= +resource-pack-sha1= +server-ip= +server-port=25565 +simulation-distance=10 +snooper-enabled=true +spawn-animals=true +spawn-monsters=true +spawn-npcs=true +spawn-protection=16 +sync-chunk-writes=true +text-filtering-config= +use-native-transport=true +view-distance=10 +white-list=false diff --git a/cypress/plugins/startServer.ts b/cypress/plugins/startServer.ts new file mode 100644 index 00000000..ecf0d210 --- /dev/null +++ b/cypress/plugins/startServer.ts @@ -0,0 +1,45 @@ +import { ChildProcess, spawn } from 'child_process' +import * as fs from 'fs' +import * as path from 'path' +import { promisify } from 'util' +import { downloadServer } from 'minecraft-wrap' +import * as waitOn from 'wait-on' + +let prevProcess: ChildProcess | null = null +export const startMinecraftServer = async (version: string, port: number) => { + if (prevProcess) return null + const jar = `./server-jar/${version}.jar` + + const start = () => { + // if (prevProcess) { + // prevProcess.kill() + // } + + prevProcess = spawn('java', ['-jar', path.basename(jar), 'nogui', '--port', `${port}`], { + stdio: 'inherit', + cwd: path.dirname(jar), + }) + } + + let coldStart = false + if (fs.existsSync(jar)) { + start() + } else { + coldStart = true + promisify(downloadServer)(version, jar).then(() => { + // add eula.txt + fs.writeFileSync(path.join(path.dirname(jar), 'eula.txt'), 'eula=true') + // copy cypress/plugins/server.properties + fs.copyFileSync(path.join(__dirname, 'server.properties'), path.join(path.dirname(jar), 'server.properties')) + // copy ops.json + fs.copyFileSync(path.join(__dirname, 'ops.json'), path.join(path.dirname(jar), 'ops.json')) + start() + }) + } + + return new Promise((res) => { + waitOn({ resources: [`tcp:localhost:${port}`] }, () => { + setTimeout(() => res(null), coldStart ? 6500 : 2000) // todo retry instead of timeout + }) + }) +} diff --git a/index.html b/index.html index 6d3b326b..62e109cd 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@
Loading...
-
A true Minecraft client in your browser!
+
A true Minecraft client in your browser!
` diff --git a/src/index.ts b/src/index.ts index fe584b4d..72f270d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ import './scaleInterface' import itemsPng from 'prismarine-viewer/public/textures/items.png' import { initWithRenderer } from './topRightStats' import PrismarineBlock from 'prismarine-block' +import PrismarineItem from 'prismarine-item' import { options, watchValue } from './optionsStorage' import './reactUi.jsx' @@ -580,6 +581,7 @@ async function connect (connectOptions: ConnectOptions) { errorAbortController.abort() const mcData = MinecraftData(bot.version) window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) + window.PrismarineItem = PrismarineItem(mcData.version.minecraftVersion!) window.loadedData = mcData window.Vec3 = Vec3 window.pathfinder = pathfinder @@ -825,9 +827,12 @@ listenGlobalEvents() watchValue(miscUiState, async s => { if (s.appLoaded) { // fs ready const qs = new URLSearchParams(window.location.search) + const moreServerOptions = {} as Record + if (qs.has('version')) moreServerOptions.version = qs.get('version') if (qs.get('singleplayer') === '1') { loadSingleplayer({}, { - worldFolder: undefined + worldFolder: undefined, + ...moreServerOptions }) } if (qs.get('loadSave')) { diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index b05f9930..981878c8 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -1,6 +1,5 @@ import { proxy, subscribe } from 'valtio' import { useEffect, useMemo, useRef, useState } from 'react' -import { isCypress } from '../standaloneUtils' import { MessageFormatPart } from '../botUtils' import { MessagePart } from './MessageFormatted' import './Chat.css' @@ -200,7 +199,7 @@ export default ({ messages, opacity = 1, fetchCompletionItems, opened, sendMessa return ( <> -
diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 9772c9b4..ca749560 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -7,6 +7,7 @@ import ServersList from './ServersList' import AddServerOrConnect, { BaseServerInfo } from './AddServerOrConnect' import { useDidUpdateEffect } from './utils' import { useIsModalActive } from './utilsApp' +import { showOptionsModal } from './SelectOption' interface StoreServerItem extends BaseServerInfo { lastJoined?: number @@ -46,6 +47,15 @@ type AdditionalDisplayData = { icon?: string } +export interface AuthenticatedAccount { + // type: 'microsoft' + username: string + cachedTokens?: { + data: any + expiresOn: number + } +} + const getInitialServersList = () => { if (localStorage['serversList']) return JSON.parse(localStorage['serversList']) as StoreServerItem[] @@ -62,7 +72,6 @@ const getInitialServersList = () => { if (localStorage['server']) { const legacyLastJoinedServer: StoreServerItem = { ip: localStorage['server'], - passwordOverride: localStorage['password'], versionOverride: localStorage['version'], lastJoined: Date.now() } @@ -104,16 +113,21 @@ const getInitialProxies = () => { return proxies } -export const updateLoadedServerData = (callback: (data: StoreServerItem) => StoreServerItem) => { +export const updateLoadedServerData = (callback: (data: StoreServerItem) => StoreServerItem, index = miscUiState.loadedServerIndex) => { + if (!index) return // function assumes component is not mounted to avoid sync issues after save - const { loadedServerIndex } = miscUiState - if (!loadedServerIndex) return const servers = getInitialServersList() - const server = servers[loadedServerIndex] - servers[loadedServerIndex] = callback(server) + const server = servers[index] + servers[index] = callback(server) setNewServersList(servers) } +export const updateAuthenticatedAccountData = (callback: (data: AuthenticatedAccount[]) => AuthenticatedAccount[]) => { + const accounts = JSON.parse(localStorage['authenticatedAccounts'] || '[]') as AuthenticatedAccount[] + const newAccounts = callback(accounts) + localStorage['authenticatedAccounts'] = JSON.stringify(newAccounts) +} + // todo move to base const normalizeIp = (ip: string) => ip.replace(/https?:\/\//, '').replace(/\/(:|$)/, '') @@ -122,6 +136,11 @@ const Inner = () => { const [selectedProxy, setSelectedProxy] = useState(localStorage.getItem('selectedProxy') ?? proxies?.[0] ?? '') const [serverEditScreen, setServerEditScreen] = useState(null) // true for add const [defaultUsername, setDefaultUsername] = useState(localStorage['username'] ?? (`mcrafter${Math.floor(Math.random() * 1000)}`)) + const [authenticatedAccounts, setAuthenticatedAccounts] = useState(JSON.parse(localStorage['authenticatedAccounts'] || '[]')) + + useEffect(() => { + localStorage.setItem('authenticatedAccounts', JSON.stringify(authenticatedAccounts)) + }, [authenticatedAccounts]) useEffect(() => { localStorage.setItem('username', defaultUsername) @@ -215,6 +234,7 @@ const Inner = () => { } setServerEditScreen(null) }} + accounts={authenticatedAccounts.map(a => a.username)} initialData={!serverEditScreen || serverEditScreen === true ? undefined : serverEditScreen} onQsConnect={(info) => { const connectOptions: ConnectOptions = { @@ -222,7 +242,6 @@ const Inner = () => { server: normalizeIp(info.ip), proxy: info.proxyOverride || selectedProxy, botVersion: info.versionOverride, - password: info.passwordOverride, ignoreQs: true, } dispatchEvent(new CustomEvent('connect', { detail: connectOptions })) @@ -249,14 +268,22 @@ const Inner = () => { if (!username) return setDefaultUsername(username) } + let authenticatedAccount: AuthenticatedAccount | true | undefined + if (overrides.authenticatedAccountOverride) { + if (overrides.authenticatedAccountOverride === true) { + authenticatedAccount = true + } else { + authenticatedAccount = authenticatedAccounts.find(a => a.username === overrides.authenticatedAccountOverride) ?? true + } + } const options = { username, server: normalizeIp(ip), proxy: overrides.proxyOverride || selectedProxy, botVersion: overrides.versionOverride ?? /* legacy */ overrides['version'], - password: overrides.passwordOverride, ignoreQs: true, autoLoginPassword: server?.autoLogin?.[username], + authenticatedAccount, onSuccessfulPlay () { if (shouldSave && !serversList.some(s => s.ip === ip)) { const newServersList: StoreServerItem[] = [...serversList, { @@ -294,6 +321,11 @@ const Inner = () => { }} username={defaultUsername} setUsername={setDefaultUsername} + onProfileClick={async () => { + const username = await showOptionsModal('Select authenticated account to remove', authenticatedAccounts.map(a => a.username)) + if (!username) return + setAuthenticatedAccounts(old => old.filter(a => a.username !== username)) + }} onWorldAction={(action, index) => { const server = serversList[index] if (!server) return diff --git a/src/react/SignInMessage.stories.tsx b/src/react/SignInMessage.stories.tsx new file mode 100644 index 00000000..16528700 --- /dev/null +++ b/src/react/SignInMessage.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from '@storybook/react' +import SignInMessage from './SignInMessage' + +const meta: Meta<{ open }> = { + component: SignInMessage as any, + render ({ open }) { + return + }, +} + +export default meta +type Story = StoryObj<{ open }> + +export const Primary: Story = { + args: { + }, +} diff --git a/src/react/SignInMessage.tsx b/src/react/SignInMessage.tsx new file mode 100644 index 00000000..2ec38816 --- /dev/null +++ b/src/react/SignInMessage.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react' +import { useUtilsEffect } from '@zardoy/react-util' +import PixelartIcon from './PixelartIcon' +import Screen from './Screen' +import Button from './Button' + +export default ({ + code = 'ABCD-EFGH-IJKL-MNOP', + loginLink = 'https://aka.ms/devicelogin', + connectingServer = 'mc.example.comsdlfjsklfjsfjdskfjsj', + warningText = true, + expiresEnd = Date.now() + 1000 * 60 * 5, + setSaveToken = (() => { }) as ((state: boolean) => void) | undefined, + defaultSaveToken = true, + onCancel = () => { }, + directLink = 'https://aka.ms/devicelogin' +}) => { + if (connectingServer.length > 30) connectingServer = connectingServer.slice(0, 30) + '...' + const [timeLeft, setTimeLeft] = useState(``) + + useUtilsEffect(({ interval }) => { + interval(1000, () => { + const timeLeft = Math.max(0, Math.ceil((expiresEnd - Date.now()) / 1000)) + const minutes = Math.floor(timeLeft / 60) + const seconds = timeLeft % 60 + setTimeLeft(`${minutes}:${seconds.toString().padStart(2, '0')}`) + if (timeLeft <= 0) setTimeLeft('Code expired!') + }) + }, []) + + return + + + +} diff --git a/src/react/SignInMessageProvider.tsx b/src/react/SignInMessageProvider.tsx new file mode 100644 index 00000000..68ea83aa --- /dev/null +++ b/src/react/SignInMessageProvider.tsx @@ -0,0 +1,32 @@ +import { proxy, ref, useSnapshot } from 'valtio' +import SignInMessage from './SignInMessage' +import { lastConnectOptions } from './AppStatusProvider' + +export const signInMessageState = proxy({ + code: '', + link: '', + expiresOn: 0, + shouldSaveToken: true, + abortController: ref(new AbortController()), +}) + +export default () => { + const { code, expiresOn, link, shouldSaveToken } = useSnapshot(signInMessageState) + + if (!code) return null + + return { + signInMessageState.shouldSaveToken = state + }} + connectingServer={lastConnectOptions.value?.server ?? ''} + onCancel={() => { + signInMessageState.abortController.abort() + }} + directLink={`http://microsoft.com/link?otc=${code}`} + /> +} diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts index 108fae54..7b0f64bb 100644 --- a/src/react/globals.d.ts +++ b/src/react/globals.d.ts @@ -32,9 +32,9 @@ declare module '*.svg' { interface PromiseConstructor { withResolvers (): { - resolve: (value: T) => void; - reject: (reason: any) => void; - promise: Promise; + resolve: (value: T) => void + reject: (reason: any) => void + promise: Promise } } @@ -44,6 +44,7 @@ declare namespace JSX { icon: string style?: React.CSSProperties class?: string + onClick?: (e) => void } } } diff --git a/src/reactUi.tsx b/src/reactUi.tsx index f140326e..34a567cd 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -40,6 +40,7 @@ import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' import BedTime from './react/BedTime' import NoModalFoundProvider from './react/NoModalFoundProvider' +import SignInMessageProvider from './react/SignInMessageProvider' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -173,6 +174,7 @@ const App = () => { + {/* */} @@ -191,7 +193,7 @@ const App = () => { const PerComponentErrorBoundary = ({ children }) => { return children.map((child, i) => { const componentNameClean = (child.type.name || child.type.displayName || 'Unknown').replaceAll(/__|_COMPONENT/g, '') - showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console to see more info.', true, undefined) + showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console for more.', true, undefined) return null }}>{child}) } diff --git a/src/yggdrasilReplacement.ts b/src/yggdrasilReplacement.ts new file mode 100644 index 00000000..e0cab6f0 --- /dev/null +++ b/src/yggdrasilReplacement.ts @@ -0,0 +1,27 @@ +export const server = ({ host: sessionServer }) => { + return { + async join (accessToken, sessionSelectedProfileId, serverId, sharedSecret, publicKey, cb) { + try { + const result = await fetch(`${sessionServer}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + accessToken, + selectedProfile: sessionSelectedProfileId, + serverId, + sharedSecret, + publicKey, + }), + }) + if (!result.ok) { + throw new Error(`Request failed ${await result.text()}`) + } + cb(null) + } catch (err) { + cb(err) + } + } + } +} From 324c08ef436ec66672d544109eacc08d27dd2dcc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 7 Jul 2024 00:32:04 +0300 Subject: [PATCH 097/107] finally update dockerfile to a working one! uses 6gb of ram to build btw. image size: 2.4gb, ~200mb when running --- .dockerignore | 2 -- Dockerfile | 19 ++++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 285d1303..38ca0016 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,3 @@ -# we dont want default config to be loaded in the dockerfile, but rather using a volume -config.json # build stuff node_modules public \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index aa9eb3dc..086240b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,22 @@ -FROM node:14-alpine +FROM node:18-alpine # Without git installing the npm packages fails RUN apk add git RUN mkdir /app WORKDIR /app COPY . /app -RUN npm install -RUN npm run build +# install python and other dependencies +RUN apk add python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev +# install pnpm +RUN npm i -g pnpm@9.0.4 +RUN pnpm install +# only for prod +RUN pnpm run build +# --- +EXPOSE 8080 +# uncomment for development +# EXPOSE 9090 +# VOLUME /app/src +# VOLUME /app/prismarine-viewer +# ENTRYPOINT ["pnpm", "run", "run-all"] +# only for prod ENTRYPOINT ["npm", "run", "prod-start"] From d80b71ede74a110debac25c1ea5b45f802b5d41d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 6 Jul 2024 23:20:40 +0300 Subject: [PATCH 098/107] add demo to npm readme file --- README.NPM.MD | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.NPM.MD b/README.NPM.MD index c036adba..c44492c6 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -1,9 +1,13 @@ # Minecraft React +Minecraft UI components for React. + ```bash -yarn add minecraft-react +pnpm i minecraft-react ``` +![demo](https://github-production-user-asset-6210df.s3.amazonaws.com/46503702/346295584-80f3ed4a-cab6-45d2-8896-5e20233cc9b1.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240706%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240706T195400Z&X-Amz-Expires=300&X-Amz-Signature=5b063823a57057c4042c15edd1db3edd107e00940fd0e66a2ba1df4e564a2809&X-Amz-SignedHeaders=host&actor_id=46503702&key_id=0&repo_id=432411890) + ## Usage ```jsx From d1d0959cb40af0e7872f12996db1ce6ce1f364e1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 7 Jul 2024 01:12:25 +0300 Subject: [PATCH 099/107] feat: add Sonar bypass making possible to join to projects like ruhypixel.net wip: packets replay feature! --- pnpm-lock.yaml | 8 ++++---- src/index.ts | 14 ++++++++++++-- src/inventoryWindows.ts | 4 ++-- src/optionsGuiScheme.tsx | 22 ++++++++++++++++++++++ src/react/AppStatusProvider.tsx | 7 ++++++- src/react/ServersListProvider.tsx | 2 ++ src/react/SignInMessage.tsx | 2 ++ 7 files changed, 50 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98618ba5..cf890476 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -311,7 +311,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6089,8 +6089,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479} version: 4.20.1 engines: {node: '>=18'} @@ -15831,7 +15831,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) diff --git a/src/index.ts b/src/index.ts index 5fd50ce3..e73e8240 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ import * as THREE from 'three' import MinecraftData, { versionsByMinecraftVersion } from 'minecraft-data' import debug from 'debug' import { defaultsDeep } from 'lodash-es' +import initializePacketsReplay from './packetsReplay' import { initVR } from './vr' import { @@ -97,6 +98,7 @@ import { ref, subscribe } from 'valtio' import { signInMessageState } from './react/SignInMessageProvider' import { updateAuthenticatedAccountData, updateLoadedServerData } from './react/ServersListProvider' import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' +import packetsPatcher from './packetsPatcher' window.debug = debug window.THREE = THREE @@ -108,6 +110,8 @@ window.beforeRenderFrame = [] void registerServiceWorker() watchFov() initCollisionShapes() +initializePacketsReplay() +packetsPatcher() // Create three.js context, add to page let renderer: THREE.WebGLRenderer @@ -361,6 +365,7 @@ async function connect (connectOptions: ConnectOptions) { } const renderDistance = singleplayer ? renderDistanceSingleplayer : multiplayerRenderDistance + let updateDataAfterJoin = () => { } let localServer try { const serverOptions = defaultsDeep({}, connectOptions.serverOverrides ?? {}, options.localServerOptions, defaultServerOptions) @@ -506,9 +511,13 @@ async function connect (connectOptions: ConnectOptions) { } return accounts }) - updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: client.username }), connectOptions.serverIndex) + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: client.username }), connectOptions.serverIndex) + } } else { - updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: undefined }), connectOptions.serverIndex) + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: undefined }), connectOptions.serverIndex) + } } setLoadingScreenStatus('Authentication successful. Logging in to server') } finally { @@ -660,6 +669,7 @@ async function connect (connectOptions: ConnectOptions) { setLoadingScreenStatus('Placing blocks (starting viewer)') localStorage.lastConnectOptions = JSON.stringify(connectOptions) connectOptions.onSuccessfulPlay?.() + updateDataAfterJoin() if (connectOptions.autoLoginPassword) { bot.chat(`/login ${connectOptions.autoLoginPassword}`) } diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index 5f7fc0a5..fd213509 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -328,9 +328,9 @@ export const getItemNameRaw = (item: Pick return parsed as MessageFormatPart } } catch (err) { - return [{ + return { text: customName - }] + } } } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index d7636392..76799a60 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -9,6 +9,7 @@ import Slider from './react/Slider' import { getScreenRefreshRate, setLoadingScreenStatus } from './utils' import { openFilePicker, resetLocalStorageWithoutWorld } from './browserfs' import { getResourcePackName, resourcePackState, uninstallTexturePack } from './texturePack' +import { downloadPacketsReplay, packetsReplaceSessionState } from './packetsReplay' export const guiOptionsScheme: { @@ -309,6 +310,27 @@ export const guiOptionsScheme: { if (confirm('Are you sure you want to reset all settings?')) resetLocalStorageWithoutWorld() }}>Reset all settings }, + }, + { + custom () { + return Developer + }, + }, + { + custom () { + const { active } = useSnapshot(packetsReplaceSessionState) + return + }, + }, + { + custom () { + const { active } = useSnapshot(packetsReplaceSessionState) + return + }, } ], } diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 0b12390c..c905be12 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -5,6 +5,7 @@ import { resetLocalStorageWorld } from '../browserfs' import { fsState } from '../loadSave' import { guessProblem } from '../errorLoadingScreenHelpers' import { ConnectOptions } from '../connect' +import { downloadPacketsReplay, packetsReplaceSessionState } from '../packetsReplay' import AppStatus from './AppStatus' import DiveTransition from './DiveTransition' import { useDidUpdateEffect } from './utils' @@ -32,6 +33,7 @@ export const lastConnectOptions = { export default () => { const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint } = useSnapshot(appStatusState) + const { active: replayActive } = useSnapshot(packetsReplaceSessionState) const isOpen = useIsModalActive('app-status') @@ -103,7 +105,10 @@ export default () => { } } : undefined} actionsSlot={ - displayAuthButton && diff --git a/src/react/ConceptCommandsGui.stories.tsx b/src/react/ConceptCommandsGui.stories.tsx index 89cb6eff..4f3586d4 100644 --- a/src/react/ConceptCommandsGui.stories.tsx +++ b/src/react/ConceptCommandsGui.stories.tsx @@ -11,7 +11,6 @@ const Button2 = ({ title, icon }) => {
{title}
- {/* { // const sessionEndpoint = 'http://localhost:3000/session' let authEndpoint = '' let sessionEndpoint = '' + if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}` + const url = proxyBaseUrl + '/api/vm/net/connect' + let result: Response + try { + result = await fetch(url) + } catch (err) { + throw new Error(`Selected proxy server ${proxyBaseUrl} most likely is down`) + } try { - if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}` - const url = proxyBaseUrl + '/api/vm/net/connect' - const result = await fetch(url) const json = await result.json() authEndpoint = urlWithBase(json.capabilities.authEndpoint, proxyBaseUrl) sessionEndpoint = urlWithBase(json.capabilities.sessionEndpoint, proxyBaseUrl) diff --git a/src/react/AppStatus.tsx b/src/react/AppStatus.tsx index 10cc5793..9ebecf93 100644 --- a/src/react/AppStatus.tsx +++ b/src/react/AppStatus.tsx @@ -28,6 +28,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction return ( diff --git a/src/react/Chat.css b/src/react/Chat.css index 41917783..cba0a1aa 100644 --- a/src/react/Chat.css +++ b/src/react/Chat.css @@ -24,6 +24,13 @@ div.chat-wrapper { left: 1px; box-sizing: border-box; background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + gap: 1px; +} + +.chat-input-wrapper form { + display: flex; } .chat-input { @@ -103,7 +110,8 @@ div.chat-wrapper { } .input-mobile #chatinput { - height: 20px; + height: 24px; + font-size: 13px; } .display-mobile { diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index 89b2aa8b..60467171 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -4,6 +4,8 @@ import { MessageFormatPart } from '../botUtils' import { MessagePart } from './MessageFormatted' import './Chat.css' import { isIos, reactKeyForMessage } from './utils' +import Button from './Button' +import { pixelartIcons } from './PixelartIcon' export type Message = { parts: MessageFormatPart[], @@ -221,6 +223,8 @@ export default ({ diff --git a/src/react/EnterFullscreenButton.tsx b/src/react/EnterFullscreenButton.tsx index ad78ddad..3901b9ae 100644 --- a/src/react/EnterFullscreenButton.tsx +++ b/src/react/EnterFullscreenButton.tsx @@ -1,6 +1,11 @@ import { useEffect, useState } from 'react' +import { useSnapshot } from 'valtio' +import { activeModalStack, miscUiState } from '../globalState' import Button from './Button' import { useUsingTouch } from './utilsApp' +import { pixelartIcons } from './PixelartIcon' + +const hideOnModals = new Set(['chat']) export default () => { const [fullScreen, setFullScreen] = useState(false) @@ -9,16 +14,23 @@ export default () => { setFullScreen(!!document.fullscreenElement) }) }, []) + const { gameLoaded } = useSnapshot(miscUiState) + + const activeStack = useSnapshot(activeModalStack) + + const inMainMenu = activeStack.length === 0 && !gameLoaded const usingTouch = useUsingTouch() - if (!usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null + const hideButton = activeStack.some(x => hideOnModals.has(x.reactType)) + + if (hideButton || !usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null return
+
{code}
+
+ Waiting... {timeLeft} +
+
+ {warningText &&
+ Join only vanilla servers! This client is detectable and may result in a ban by anti-cheat plugins. +
} + {setSaveToken && } +