This commit is contained in:
Vitaly 2025-03-05 23:15:35 +03:00 committed by GitHub
commit a906e4a3db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 140 additions and 22 deletions

View file

@ -149,7 +149,7 @@
"http-server": "^14.1.1",
"https-browserify": "^1.0.0",
"mc-assets": "^0.2.42",
"mineflayer-mouse": "^0.0.5",
"mineflayer-mouse": "^0.0.7",
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
"mineflayer": "github:zardoy/mineflayer",
"mineflayer-pathfinder": "^2.4.4",

10
pnpm-lock.yaml generated
View file

@ -359,8 +359,8 @@ importers:
specifier: github:zardoy/mineflayer
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13)
mineflayer-mouse:
specifier: ^0.0.5
version: 0.0.5(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1)
specifier: ^0.0.7
version: 0.0.7(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1)
mineflayer-pathfinder:
specifier: ^2.4.4
version: 2.4.4
@ -6801,8 +6801,8 @@ packages:
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824}
version: 1.2.0
mineflayer-mouse@0.0.5:
resolution: {integrity: sha512-0r/AOGTq+wZH9vrBcW93jH2dGRSlwlO6xc1Z67VJUFlZZ8oBefAOpiZq7LIGc7ROVbpcKEKjROdNv/iCFmzXYA==}
mineflayer-mouse@0.0.7:
resolution: {integrity: sha512-/cSDsc2ZPlvakc3BX+/K9VD64HAIa+LGiz34RpQvUy7hwx3nXdZjJHDjzEdn86BBzRF5pZOxIoXm8hlZKCYeeQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
mineflayer-pathfinder@2.4.4:
@ -17742,7 +17742,7 @@ snapshots:
- encoding
- supports-color
mineflayer-mouse@0.0.5(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1):
mineflayer-mouse@0.0.7(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1):
dependencies:
change-case: 5.4.4
debug: 4.4.0(supports-color@8.1.1)

View file

@ -44,6 +44,7 @@ export const formatMessage = (message: MessageInput, mcData: IndexedData = globa
obfuscated: !!msg.obfuscated
}
if (!msg.text && typeof msg.json?.[''] === 'string') msg.text = msg.json['']
if (msg.text) {
msglist.push({
...msg,

View file

@ -25,6 +25,9 @@ export default () => {
useEffect(() => {
bot.addListener('message', (jsonMsg, position) => {
if (position === 'game_info') return // ignore action bar messages, they are handled by the TitleProvider
if (jsonMsg['unsigned']) {
jsonMsg = jsonMsg['unsigned']
}
const parts = formatMessage(jsonMsg)
setMessages(m => {

View file

@ -2,7 +2,7 @@ import { useState } from 'react'
import { useIsHashActive } from './simpleHooks'
export default () => {
const MODES_COUNT = 4
const MODES_COUNT = 5
const [mode, setMode] = useState(0)
const isHashActive = useIsHashActive('#edges')
@ -41,6 +41,14 @@ export default () => {
styles.height = '100dvh'
text = 'top 0 fixed 100dvh'
}
if (mode === 4) {
styles.position = 'fixed'
styles.top = 0
styles.left = 0
styles.right = 0
styles.height = '100dvh'
text = 'top 0 bottom 0 fixed 100dvh'
}
return <div
style={styles}

View file

@ -150,9 +150,13 @@ function GameInteractionOverlayInner ({
document.dispatchEvent(new MouseEvent('mouseup', { button: 0 }))
virtualClickActive = false
} else if (!capturedPointer.active.activateCameraMove && (Date.now() - capturedPointer.active.time < touchStartBreakingBlockMs)) {
document.dispatchEvent(new MouseEvent('mousedown', { button: 2 }))
// single click action
const MOUSE_BUTTON_RIGHT = 2
const MOUSE_BUTTON_LEFT = 0
const gonnaAttack = !!bot.mouse.getCursorState().entity
document.dispatchEvent(new MouseEvent('mousedown', { button: gonnaAttack ? MOUSE_BUTTON_LEFT : MOUSE_BUTTON_RIGHT }))
bot.mouse.update()
document.dispatchEvent(new MouseEvent('mouseup', { button: 2 }))
document.dispatchEvent(new MouseEvent('mouseup', { button: gonnaAttack ? MOUSE_BUTTON_LEFT : MOUSE_BUTTON_RIGHT }))
}
if (screenTouches > 0) {

View file

@ -0,0 +1,19 @@
.hint_container {
position: fixed;
top: 20%;
left: 0;
right: 0;
margin: 0 auto;
width: fit-content;
display: flex;
align-items: center;
gap: 8px;
pointer-events: none;
z-index: 1000;
text-shadow: 1px 1px 8px rgba(0, 0, 0, 1);
}
.hint_text {
color: white;
font-size: 10px;
}

View file

@ -0,0 +1,10 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
hintContainer: string;
hintText: string;
hint_container: string;
hint_text: string;
}
declare const cssExports: CssExports;
export default cssExports;

View file

@ -0,0 +1,46 @@
import { useEffect, useState } from 'react'
import { useSnapshot } from 'valtio'
import { options } from '../optionsStorage'
import { activeModalStack } from '../globalState'
import PixelartIcon, { pixelartIcons } from './PixelartIcon'
import styles from './InteractionHint.module.css'
import { useUsingTouch } from './utilsApp'
export default () => {
const usingTouch = useUsingTouch()
const modalStack = useSnapshot(activeModalStack)
const { touchInteractionType } = useSnapshot(options)
const [hintText, setHintText] = useState<string | null>(null)
useEffect(() => {
const update = () => {
const cursorState = bot.mouse.getCursorState()
if (cursorState.entity) {
const entityName = cursorState.entity.displayName ?? cursorState.entity.name
setHintText(`Attack ${entityName}`)
} else {
setHintText(null)
}
}
// Initial update
update()
// Subscribe to physics ticks
bot.on('physicsTick', update)
return () => {
bot.removeListener('physicsTick', update)
}
}, [])
if (!usingTouch || touchInteractionType !== 'classic' || modalStack.length > 0) return null
if (!hintText) return null
return (
<div className={`${styles.hint_container} interaction-hint`}>
<PixelartIcon iconName={pixelartIcons['sun-alt']} width={14} />
<span className={styles.hint_text}>{hintText}</span>
</div>
)
}

View file

@ -33,6 +33,28 @@ export default () => {
}
const longPressEvent = useLongPress(onLongPress, () => {}, defaultOptions)
const onChatLongPress = () => {
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab' }))
}
const onChatClick = () => {
if (activeModalStack.at(-1)?.reactType === 'chat') {
hideCurrentModal()
} else {
showModal({ reactType: 'chat' })
}
}
const chatLongPressEvent = useLongPress(
onChatLongPress,
onChatClick,
{
shouldPreventDefault: true,
delay: 300,
}
)
// ios note: just don't use <button>
return <div ref={elRef} className={styles['mobile-top-btns']} id="mobile-top">
<div
@ -49,13 +71,10 @@ export default () => {
>F3
</div>
<div
className={styles['chat-btn']} onPointerDown={(e) => {
e.stopPropagation()
if (activeModalStack.at(-1)?.reactType === 'chat') {
hideCurrentModal()
} else {
showModal({ reactType: 'chat' })
}
className={styles['chat-btn']}
{...chatLongPressEvent}
onPointerUp={(e) => {
document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Tab' }))
}}
/>
<div

View file

@ -39,6 +39,10 @@ export default () => {
bot.on('playerUpdated', () => requestUpdate())
bot.on('playerJoined', () => requestUpdate())
bot.on('playerLeft', () => requestUpdate())
const interval = setInterval(() => {
requestUpdate()
}, 1000)
return () => clearInterval(interval)
}, [])
useEffect(() => {

View file

@ -52,6 +52,7 @@ import MineflayerPluginConsole from './react/MineflayerPluginConsole'
import { UIProvider } from './react/UIProvider'
import { useAppScale } from './scaleInterface'
import PacketsReplayProvider from './react/PacketsReplayProvider'
import InteractionHint from './react/InteractionHint'
const RobustPortal = ({ children, to }) => {
return createPortal(<PerComponentErrorBoundary>{children}</PerComponentErrorBoundary>, to)
@ -146,6 +147,7 @@ const InGameUi = () => {
<PauseScreen />
<MineflayerPluginHud />
<MineflayerPluginConsole />
{showUI && <InteractionHint />}
<div style={{ display: showUI ? 'block' : 'none' }}>
{!disabledUiParts.includes('xp-bar') && <XPBarProvider />}
{!disabledUiParts.includes('hud-bars') && <HudBarsProvider />}

View file

@ -132,8 +132,8 @@ body {
left: 0;
transform-origin: top left;
transform: scale(var(--guiScale));
width: calc(100% / var(--guiScale));
height: calc(100% / var(--guiScale));
width: calc(100dvw / var(--guiScale));
height: calc(100dvh / var(--guiScale));
z-index: 8;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
@ -148,8 +148,8 @@ body {
inset: 0;
transform-origin: top left;
transform: scale(var(--guiScale));
width: calc(100% / var(--guiScale));
height: calc(100% / var(--guiScale));
width: calc(100dvw / var(--guiScale));
height: calc(100dvh / var(--guiScale));
z-index: 80;
image-rendering: pixelated;
pointer-events: none;
@ -163,8 +163,10 @@ body {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
bottom: 0;
right: 0;
height: 100dvh;
width: 100dvw;
font-size: 0;
margin: 0;
padding: 0;