refactor controls to use contro-max!
it allows to use between mobile keyboard & gamepad consistently! fixed double jump!
This commit is contained in:
parent
091ccaf45e
commit
ce6e02ed1f
11 changed files with 291 additions and 287 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,7 +1,7 @@
|
|||
node_modules/
|
||||
package-lock.json
|
||||
.vscode
|
||||
public
|
||||
**/public
|
||||
*.log
|
||||
.env.local
|
||||
Thumbs.db
|
||||
|
|
@ -13,3 +13,4 @@ dist
|
|||
world
|
||||
out
|
||||
*.iml
|
||||
.vercel
|
||||
|
|
|
|||
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"configurations": [
|
||||
// UPDATED: all configs below are misconfigured and will crash vscode, open dist/index.html and use live preview debug instead
|
||||
// recommended as much faster
|
||||
{
|
||||
// to launch "C:\Program Files\Google\Chrome Beta\Application\chrome.exe" --remote-debugging-port=9222
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
"buffer": "^6.0.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"contro-max": "^0.1.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.8.1",
|
||||
|
|
|
|||
|
|
@ -1,193 +0,0 @@
|
|||
//@ts-check
|
||||
|
||||
const { Vec3 } = require('vec3')
|
||||
const { isGameActive, showModal, gameAdditionalState, activeModalStack } = require('./globalState')
|
||||
const { subscribe } = require('valtio')
|
||||
|
||||
const keyBindScrn = document.getElementById('keybinds-screen')
|
||||
|
||||
// these controls are for gamemode 3 actually
|
||||
|
||||
const makeInterval = (fn, interval) => {
|
||||
const intervalId = setInterval(fn, interval)
|
||||
|
||||
const cleanup = () => {
|
||||
clearInterval(intervalId)
|
||||
cleanup.active = false
|
||||
}
|
||||
cleanup.active = true
|
||||
return cleanup
|
||||
}
|
||||
|
||||
const flySpeedMult = 0.5
|
||||
|
||||
const isFlying = () => bot.physics.gravity === 0
|
||||
/** @type {ReturnType<typeof makeInterval>|undefined} */
|
||||
let endFlyLoop
|
||||
|
||||
const currentFlyVector = new Vec3(0, 0, 0)
|
||||
window.currentFlyVector = currentFlyVector
|
||||
|
||||
const startFlyLoop = () => {
|
||||
if (!isFlying()) return
|
||||
endFlyLoop?.()
|
||||
|
||||
endFlyLoop = makeInterval(() => {
|
||||
if (!window.bot) endFlyLoop()
|
||||
bot.entity.position.add(currentFlyVector.clone().multiply(new Vec3(flySpeedMult, flySpeedMult, flySpeedMult)))
|
||||
}, 50)
|
||||
}
|
||||
|
||||
// todo we will get rid of patching it when refactor controls
|
||||
let originalSetControlState
|
||||
const patchedSetControlState = (action, state) => {
|
||||
if (!isFlying()) {
|
||||
return originalSetControlState(action, state)
|
||||
}
|
||||
|
||||
const actionPerFlyVector = {
|
||||
jump: new Vec3(0, 1, 0),
|
||||
sneak: new Vec3(0, -1, 0),
|
||||
}
|
||||
|
||||
const changeVec = actionPerFlyVector[action]
|
||||
if (!changeVec) {
|
||||
return originalSetControlState(action, state)
|
||||
}
|
||||
const toAddVec = changeVec.scaled(state ? 1 : -1)
|
||||
for (const coord of ['x', 'y', 'z']) {
|
||||
if (toAddVec[coord] === 0) continue
|
||||
if (currentFlyVector[coord] === toAddVec[coord]) return
|
||||
}
|
||||
currentFlyVector.add(toAddVec)
|
||||
}
|
||||
|
||||
const standardAirborneAcceleration = 0.02
|
||||
const toggleFly = () => {
|
||||
if (bot.game.gameMode !== 'creative' && bot.game.gameMode !== 'spectator') return
|
||||
if (bot.setControlState !== patchedSetControlState) {
|
||||
originalSetControlState = bot.setControlState
|
||||
bot.setControlState = patchedSetControlState
|
||||
}
|
||||
|
||||
if (isFlying()) {
|
||||
bot.physics['airborneAcceleration'] = standardAirborneAcceleration
|
||||
bot.creative.stopFlying()
|
||||
endFlyLoop?.()
|
||||
} else {
|
||||
// window.flyingSpeed will be removed
|
||||
bot.physics['airborneAcceleration'] = window.flyingSpeed ?? 0.1
|
||||
bot.entity.velocity = new Vec3(0, 0, 0)
|
||||
bot.creative.startFlying()
|
||||
startFlyLoop()
|
||||
}
|
||||
gameAdditionalState.isFlying = isFlying()
|
||||
}
|
||||
|
||||
/** @type {Set<string>} */
|
||||
const pressedKeys = new Set()
|
||||
// window.pressedKeys = pressedKeys
|
||||
|
||||
// detect pause open, as ANY keyup event is not fired when you exit pointer lock (esc)
|
||||
subscribe(activeModalStack, () => {
|
||||
if (activeModalStack.length) {
|
||||
// iterate over pressedKeys
|
||||
for (const key of pressedKeys) {
|
||||
const e = new KeyboardEvent('keyup', { code: key })
|
||||
document.dispatchEvent(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let lastJumpUsage = 0
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (!isGameActive(true)) return
|
||||
|
||||
keyBindScrn.keymaps.forEach(km => {
|
||||
if (e.code === km.key) {
|
||||
switch (km.defaultKey) {
|
||||
case 'KeyE':
|
||||
// todo reenable
|
||||
showModal({ reactType: 'inventory', })
|
||||
// todo seems to be workaround
|
||||
// avoid calling inner keybinding listener, but should be handled there
|
||||
e.stopImmediatePropagation()
|
||||
break
|
||||
case 'KeyQ':
|
||||
if (bot.heldItem) bot.tossStack(bot.heldItem)
|
||||
break
|
||||
case 'ControlLeft':
|
||||
bot.setControlState('sprint', true)
|
||||
gameAdditionalState.isSprinting = true
|
||||
break
|
||||
case 'ShiftLeft':
|
||||
bot.setControlState('sneak', true)
|
||||
break
|
||||
case 'Space':
|
||||
bot.setControlState('jump', true)
|
||||
break
|
||||
case 'KeyD':
|
||||
bot.setControlState('right', true)
|
||||
e.preventDefault()
|
||||
break
|
||||
case 'KeyA':
|
||||
bot.setControlState('left', true)
|
||||
e.preventDefault()
|
||||
break
|
||||
case 'KeyS':
|
||||
bot.setControlState('back', true)
|
||||
e.preventDefault()
|
||||
break
|
||||
case 'KeyW':
|
||||
bot.setControlState('forward', true)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
pressedKeys.add(e.code)
|
||||
}, {
|
||||
capture: true,
|
||||
})
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
// workaround for pause pressed keys, multiple keyboard
|
||||
if (!isGameActive(false) || !pressedKeys.has(e.code)) {
|
||||
return
|
||||
}
|
||||
|
||||
keyBindScrn.keymaps.forEach(km => {
|
||||
if (e.code === km.key) {
|
||||
switch (km.defaultKey) {
|
||||
case 'ControlLeft':
|
||||
bot.setControlState('sprint', false)
|
||||
gameAdditionalState.isSprinting = false
|
||||
break
|
||||
case 'ShiftLeft':
|
||||
bot.setControlState('sneak', false)
|
||||
break
|
||||
case 'Space':
|
||||
const toggleFlyAction = Date.now() - lastJumpUsage < 500
|
||||
if (toggleFlyAction) {
|
||||
toggleFly()
|
||||
}
|
||||
lastJumpUsage = Date.now()
|
||||
|
||||
bot.setControlState('jump', false)
|
||||
break
|
||||
case 'KeyD':
|
||||
bot.setControlState('right', false)
|
||||
break
|
||||
case 'KeyA':
|
||||
bot.setControlState('left', false)
|
||||
break
|
||||
case 'KeyS':
|
||||
bot.setControlState('back', false)
|
||||
break
|
||||
case 'KeyW':
|
||||
bot.setControlState('forward', false)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
pressedKeys.delete(e.code)
|
||||
}, false)
|
||||
16
src/chat.js
16
src/chat.js
|
|
@ -228,24 +228,8 @@ class ChatBox extends LitElement {
|
|||
}
|
||||
})
|
||||
|
||||
const keyBindScrn = document.getElementById('keybinds-screen')
|
||||
|
||||
document.addEventListener('keypress', e => {
|
||||
if (!this.inChat && activeModalStack.length === 0) {
|
||||
keyBindScrn.keymaps.forEach(km => {
|
||||
if (e.code === km.key) {
|
||||
switch (km.defaultKey) {
|
||||
case 'KeyT':
|
||||
setTimeout(() => this.enableChat(), 0)
|
||||
break
|
||||
case 'Slash':
|
||||
setTimeout(() => this.enableChat('/'), 0)
|
||||
e.preventDefault()
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
266
src/controls.ts
Normal file
266
src/controls.ts
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
//@ts-check
|
||||
|
||||
import { Vec3 } from 'vec3'
|
||||
import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal } from './globalState'
|
||||
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'
|
||||
|
||||
// doesnt seem to work for now
|
||||
const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}'))
|
||||
subscribe(customKeymaps, () => {
|
||||
localStorage.keymap = JSON.parse(customKeymaps)
|
||||
})
|
||||
|
||||
export const contro = new ControMax({
|
||||
commands: {
|
||||
general: {
|
||||
jump: ['Space', 'A'],
|
||||
inventory: ['KeyE', 'X'],
|
||||
drop: ['KeyQ', 'B'],
|
||||
sneak: ['ShiftLeft', 'Right Stick'],
|
||||
sprint: ['ControlLeft', 'Left Stick'],
|
||||
nextHotbarSlot: [null, 'Left Bumper'],
|
||||
prevHotbarSlot: [null, 'Right Bumper'],
|
||||
attackDestroy: [null, 'Right Trigger'],
|
||||
interactPlace: [null, 'Left Trigger'],
|
||||
chat: [['KeyT', 'Enter'], null],
|
||||
command: ['Slash', null],
|
||||
},
|
||||
// waila: {
|
||||
// showLookingBlockRecipe: ['Numpad3'],
|
||||
// showLookingBlockUsages: ['Numpad4']
|
||||
// }
|
||||
} satisfies Record<string, Record<string, SchemaCommandInput>>,
|
||||
movementKeymap: 'WASD',
|
||||
movementVector: '2d',
|
||||
groupedCommands: {
|
||||
general: {
|
||||
switchSlot: ['Digits', []]
|
||||
}
|
||||
},
|
||||
}, {
|
||||
target: document,
|
||||
captureEvents() {
|
||||
return bot && isGameActive(false)
|
||||
},
|
||||
storeProvider: {
|
||||
load: () => customKeymaps,
|
||||
save() { },
|
||||
}
|
||||
})
|
||||
export type Command = CommandEventArgument<typeof contro['_commandsRaw']>['command']
|
||||
|
||||
const setSprinting = (state: boolean) => {
|
||||
bot.setControlState('sprint', state)
|
||||
gameAdditionalState.isSprinting = state
|
||||
}
|
||||
|
||||
contro.on('movementUpdate', ({ vector, gamepadIndex }) => {
|
||||
// gamepadIndex will be used for splitscreen in future
|
||||
const coordToAction = [
|
||||
['z', -1, 'forward'],
|
||||
['z', 1, 'back'],
|
||||
['x', -1, 'left'],
|
||||
['x', 1, 'right'],
|
||||
] as const
|
||||
|
||||
const newState: Partial<typeof bot.controlState> = {}
|
||||
for (const [coord, v] of Object.entries(vector)) {
|
||||
if (v === undefined || Math.abs(v) < 0.3) continue
|
||||
// todo use raw values eg for slow movement
|
||||
const mappedValue = v < 0 ? -1 : 1
|
||||
const foundAction = coordToAction.find(([c, mapV]) => c === coord && mapV === mappedValue)?.[2]
|
||||
newState[foundAction] = true
|
||||
}
|
||||
|
||||
for (const key of ['forward', 'back', 'left', 'right'] as const) {
|
||||
if (newState[key] === bot.controlState[key]) continue
|
||||
const action = !!newState[key]
|
||||
if (action && !isGameActive(true)) continue
|
||||
bot.setControlState(key, action)
|
||||
|
||||
if (key === 'forward') {
|
||||
// todo workaround: need to refactor
|
||||
if (action) {
|
||||
contro.emit('trigger', { command: 'general.forward' } as any)
|
||||
} else {
|
||||
setSprinting(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let lastCommandTrigger = null as { command: string, time: number } | null
|
||||
|
||||
const secondActionActivationTimeout = 600
|
||||
const secondActionCommands = {
|
||||
'general.jump'() {
|
||||
toggleFly()
|
||||
},
|
||||
'general.forward'() {
|
||||
setSprinting(true)
|
||||
}
|
||||
}
|
||||
|
||||
// detect pause open, as ANY keyup event is not fired when you exit pointer lock (esc)
|
||||
subscribe(activeModalStack, () => {
|
||||
if (activeModalStack.length) {
|
||||
// iterate over pressedKeys
|
||||
for (const key of contro.pressedKeys) {
|
||||
contro.pressedKeyOrButtonChanged({ code: key }, false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const onTriggerOrReleased = (command: Command, pressed: boolean) => {
|
||||
// always allow release!
|
||||
if (pressed && !isGameActive(true)) return
|
||||
if (stringStartsWith(command, 'general')) {
|
||||
// handle general commands
|
||||
switch (command) {
|
||||
case 'general.jump':
|
||||
bot.setControlState('jump', pressed)
|
||||
break
|
||||
case 'general.sneak':
|
||||
bot.setControlState('sneak', pressed)
|
||||
break
|
||||
case 'general.sprint':
|
||||
setSprinting(pressed)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// im still not sure, maybe need to refactor to handle in inventory instead
|
||||
const alwaysHandledCommand = (command: Command) => {
|
||||
if (command === 'general.inventory') {
|
||||
if (activeModalStack.at(-1)?.reactType === 'inventory') {
|
||||
hideCurrentModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contro.on('trigger', ({ command }) => {
|
||||
const willContinue = !isGameActive(true)
|
||||
alwaysHandledCommand(command)
|
||||
if (willContinue) return
|
||||
|
||||
const secondActionCommand = secondActionCommands[command]
|
||||
if (secondActionCommand) {
|
||||
const commandToTrigger = secondActionCommands[lastCommandTrigger?.command]
|
||||
if (commandToTrigger && Date.now() - lastCommandTrigger.time < secondActionActivationTimeout) {
|
||||
commandToTrigger()
|
||||
lastCommandTrigger = null
|
||||
} else {
|
||||
lastCommandTrigger = {
|
||||
command,
|
||||
time: Date.now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTriggerOrReleased(command, true)
|
||||
|
||||
if (stringStartsWith(command, 'general')) {
|
||||
switch (command) {
|
||||
case 'general.inventory':
|
||||
document.exitPointerLock?.()
|
||||
showModal({ reactType: 'inventory' })
|
||||
break
|
||||
case 'general.drop':
|
||||
if (bot.heldItem) bot.tossStack(bot.heldItem)
|
||||
break
|
||||
case 'general.chat':
|
||||
document.getElementById('hud').shadowRoot.getElementById('chat').enableChat()
|
||||
break
|
||||
case 'general.command':
|
||||
document.getElementById('hud').shadowRoot.getElementById('chat').enableChat('/')
|
||||
break
|
||||
// todo place / destroy
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
contro.on('release', ({ command }) => {
|
||||
onTriggerOrReleased(command, false)
|
||||
})
|
||||
|
||||
// #region creative fly
|
||||
// these controls are more like for gamemode 3
|
||||
|
||||
const makeInterval = (fn, interval) => {
|
||||
const intervalId = setInterval(fn, interval)
|
||||
|
||||
const cleanup = () => {
|
||||
clearInterval(intervalId)
|
||||
cleanup.active = false
|
||||
}
|
||||
cleanup.active = true
|
||||
return cleanup
|
||||
}
|
||||
|
||||
const isFlying = () => bot.physics.gravity === 0
|
||||
let endFlyLoop: ReturnType<typeof makeInterval> | undefined
|
||||
|
||||
const currentFlyVector = new Vec3(0, 0, 0)
|
||||
window.currentFlyVector = currentFlyVector
|
||||
|
||||
const startFlyLoop = () => {
|
||||
if (!isFlying()) return
|
||||
endFlyLoop?.()
|
||||
|
||||
endFlyLoop = makeInterval(() => {
|
||||
if (!window.bot) endFlyLoop()
|
||||
bot.entity.position.add(currentFlyVector.clone().multiply(new Vec3(0, 0.5, 0)))
|
||||
}, 50)
|
||||
}
|
||||
|
||||
// todo we will get rid of patching it when refactor controls
|
||||
let originalSetControlState
|
||||
const patchedSetControlState = (action, state) => {
|
||||
if (!isFlying()) {
|
||||
return originalSetControlState(action, state)
|
||||
}
|
||||
|
||||
const actionPerFlyVector = {
|
||||
jump: new Vec3(0, 1, 0),
|
||||
sneak: new Vec3(0, -1, 0),
|
||||
}
|
||||
|
||||
const changeVec = actionPerFlyVector[action]
|
||||
if (!changeVec) {
|
||||
return originalSetControlState(action, state)
|
||||
}
|
||||
const toAddVec = changeVec.scaled(state ? 1 : -1)
|
||||
for (const coord of ['x', 'y', 'z']) {
|
||||
if (toAddVec[coord] === 0) continue
|
||||
if (currentFlyVector[coord] === toAddVec[coord]) return
|
||||
}
|
||||
currentFlyVector.add(toAddVec)
|
||||
}
|
||||
|
||||
const standardAirborneAcceleration = 0.02
|
||||
const toggleFly = () => {
|
||||
if (bot.game.gameMode !== 'creative' && bot.game.gameMode !== 'spectator') return
|
||||
if (bot.setControlState !== patchedSetControlState) {
|
||||
originalSetControlState = bot.setControlState
|
||||
bot.setControlState = patchedSetControlState
|
||||
}
|
||||
|
||||
if (isFlying()) {
|
||||
bot.physics['airborneAcceleration'] = standardAirborneAcceleration
|
||||
bot.creative.stopFlying()
|
||||
endFlyLoop?.()
|
||||
} else {
|
||||
// window.flyingSpeed will be removed
|
||||
bot.physics['airborneAcceleration'] = window.flyingSpeed ?? 0.1
|
||||
bot.entity.velocity = new Vec3(0, 0, 0)
|
||||
bot.creative.startFlying()
|
||||
startFlyLoop()
|
||||
}
|
||||
gameAdditionalState.isFlying = isFlying()
|
||||
}
|
||||
// #endregion
|
||||
|
|
@ -37,7 +37,7 @@ require('./menus/title_screen')
|
|||
|
||||
require('./optionsStorage')
|
||||
require('./reactUi.jsx')
|
||||
require('./botControls')
|
||||
require('./controls')
|
||||
require('./dragndrop')
|
||||
require('./browserfs')
|
||||
require('./eruda')
|
||||
|
|
@ -47,9 +47,7 @@ const net = require('net')
|
|||
const Stats = require('stats.js')
|
||||
|
||||
const mineflayer = require('mineflayer')
|
||||
const { WorldView, Viewer, MapControls } = require('prismarine-viewer/viewer')
|
||||
const PrismarineWorld = require('prismarine-world')
|
||||
const nbt = require('prismarine-nbt')
|
||||
const { WorldView, Viewer } = require('prismarine-viewer/viewer')
|
||||
const pathfinder = require('mineflayer-pathfinder')
|
||||
const { Vec3 } = require('vec3')
|
||||
|
||||
|
|
|
|||
|
|
@ -224,9 +224,9 @@ class Hotbar extends LitElement {
|
|||
<div class="item-icon"></div>
|
||||
<span class="item-stack"></span>
|
||||
</div>
|
||||
${miscUiState.currentTouch && html`<div class="hotbar-item hotbar-more" @click=${() => {
|
||||
${miscUiState.currentTouch ? html`<div class="hotbar-item hotbar-more" @click=${() => {
|
||||
showModal({ reactType: 'inventory', })
|
||||
}}>`}
|
||||
}}>` : undefined}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class OptionsScreen extends CommonOptionsScreen {
|
|||
}}></pmui-slider>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<pmui-button pmui-width="150px" pmui-label="Key Binds" @pmui-click=${() => showModal(document.getElementById('keybinds-screen'))}></pmui-button>
|
||||
<pmui-button pmui-disabled="true" pmui-width="150px" pmui-label="Key Binds" @pmui-click=${() => showModal(document.getElementById('keybinds-screen'))}></pmui-button>
|
||||
<pmui-slider pmui-label="Gui Scale" pmui-value="${this.guiScale}" pmui-min="1" pmui-max="4" pmui-type="" @change=${(e) => {
|
||||
this.changeOption('guiScale', e.target.value)
|
||||
document.documentElement.style.setProperty('--guiScale', `${this.guiScale}`)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
//@ts-check
|
||||
import { renderToDom } from '@zardoy/react-util'
|
||||
|
||||
import { LeftTouchArea, InventoryNew, RightTouchArea, useUsingTouch, useInterfaceState } from '@dimaka/interface'
|
||||
import { LeftTouchArea, RightTouchArea, useUsingTouch, useInterfaceState } from '@dimaka/interface'
|
||||
import { css } from '@emotion/css'
|
||||
import { activeModalStack, hideCurrentModal, isGameActive } from './globalState'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useProxy } from 'valtio/utils'
|
||||
import useTypedEventListener from 'use-typed-event-listener'
|
||||
import { activeModalStack, isGameActive } from './globalState'
|
||||
import { isProbablyIphone } from './menus/components/common'
|
||||
// import DeathScreen from './react/DeathScreen'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { contro } from './controls'
|
||||
|
||||
// todo
|
||||
useInterfaceState.setState({
|
||||
|
|
@ -17,23 +17,22 @@ useInterfaceState.setState({
|
|||
},
|
||||
updateCoord: ([coord, state]) => {
|
||||
const coordToAction = [
|
||||
['z', -1, 'forward'],
|
||||
['z', 1, 'back'],
|
||||
['x', -1, 'left'],
|
||||
['x', 1, 'right'],
|
||||
['y', 1, 'jump'],
|
||||
['z', -1, 'KeyW'],
|
||||
['z', 1, 'KeyS'],
|
||||
['x', -1, 'KeyA'],
|
||||
['x', 1, 'KeyD'],
|
||||
['y', 1, 'Space'], // todo jump
|
||||
]
|
||||
// todo refactor
|
||||
const actionAndState = state !== 0 ? coordToAction.find(([axis, value]) => axis === coord && value === state) : coordToAction.filter(([axis]) => axis === coord)
|
||||
if (!bot) return
|
||||
if (state === 0) {
|
||||
for (const action of actionAndState) {
|
||||
//@ts-ignore
|
||||
bot.setControlState(action[2], false)
|
||||
contro.pressedKeyOrButtonChanged({code: action[2],}, false)
|
||||
}
|
||||
} else {
|
||||
//@ts-ignore
|
||||
bot.setControlState(actionAndState[2], true)
|
||||
contro.pressedKeyOrButtonChanged({code: actionAndState[2],}, true)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -67,71 +66,17 @@ const TouchControls = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const useActivateModal = (/** @type {string} */search, onlyLast = true) => {
|
||||
const stack = useProxy(activeModalStack)
|
||||
|
||||
return onlyLast ? stack.at(-1)?.reactType === search : stack.some((modal) => modal.reactType === search)
|
||||
}
|
||||
|
||||
function useIsBotAvailable() {
|
||||
const stack = useProxy(activeModalStack)
|
||||
const stack = useSnapshot(activeModalStack)
|
||||
|
||||
return isGameActive(false)
|
||||
}
|
||||
|
||||
function InventoryWrapper() {
|
||||
const isInventoryOpen = useActivateModal('inventory', false)
|
||||
const [slots, setSlots] = useState(bot.inventory.slots)
|
||||
|
||||
useEffect(() => {
|
||||
if (isInventoryOpen) {
|
||||
document.exitPointerLock?.()
|
||||
}
|
||||
}, [isInventoryOpen])
|
||||
|
||||
useTypedEventListener(document, 'keydown', (e) => {
|
||||
// todo use refactored keymap
|
||||
if (e.code === 'KeyE' && activeModalStack.at(-1)?.reactType === 'inventory') {
|
||||
hideCurrentModal()
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
bot.inventory.on('updateSlot', () => {
|
||||
setSlots([...bot.inventory.slots])
|
||||
})
|
||||
// todo need to think of better solution
|
||||
window['mcData'] = require('minecraft-data')(bot.version)
|
||||
window['mcAssets'] = require('minecraft-assets')(bot.version)
|
||||
}, [])
|
||||
|
||||
if (!isInventoryOpen) return null
|
||||
|
||||
return null
|
||||
|
||||
// return <div className={css`
|
||||
// position: fixed;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// background: rgba(0, 0, 0, 0.5);
|
||||
|
||||
// & > div {
|
||||
// scale: 0.6;
|
||||
// background: transparent !important;
|
||||
// }
|
||||
// `}>
|
||||
// <InventoryNew slots={slots} action={(oldSlot, newSlotIndex) => {
|
||||
// bot.moveSlotItem(oldSlot, newSlotIndex)
|
||||
// } } />
|
||||
// </div>
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const isBotAvailable = useIsBotAvailable()
|
||||
if (!isBotAvailable) return null
|
||||
// if (!isBotAvailable) return <DeathScreen />
|
||||
|
||||
return <div>
|
||||
<InventoryWrapper />
|
||||
<TouchControls />
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
"allowSyntheticDefaultImports": true,
|
||||
"noEmit": true,
|
||||
"strictFunctionTypes": true,
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
// "strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue