diff --git a/package.json b/package.json index 6e73b9814..9451b266e 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 6d784e177..8d34f233e 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 847741cf4..f940d59d7 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 57d7d7ef5..2de24de80 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 = {