feat: Add interaction hint for touch-based entity targeting

This commit is contained in:
Vitaly Turovsky 2025-03-05 22:49:36 +03:00
commit a27fa4cd1d
5 changed files with 81 additions and 2 deletions

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,44 @@
import { useEffect, useState } from 'react'
import { useSnapshot } from 'valtio'
import { options } from '../optionsStorage'
import PixelartIcon, { pixelartIcons } from './PixelartIcon'
import styles from './InteractionHint.module.css'
import { useUsingTouch } from './utilsApp'
export default () => {
const usingTouch = useUsingTouch()
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') 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

@ -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 />}