good release! (#117)

This commit is contained in:
Vitaly 2024-05-13 04:18:13 +03:00 committed by GitHub
commit eb4173bfcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 223 additions and 20 deletions

View file

@ -46,6 +46,9 @@ const buildOptions = {
// using \n breaks sourcemaps!
js: banner.join(';'),
},
external: [
'sharp'
],
alias: {
events: 'events', // make explicit
buffer: 'buffer',
@ -56,7 +59,8 @@ const buildOptions = {
stream: 'stream-browserify',
net: 'net-browserify',
assert: 'assert',
dns: './src/dns.js'
dns: './src/dns.js',
// todo write advancedAliases plugin
},
inject: [
'./src/shims.js'

View file

@ -0,0 +1,15 @@
<style>
div {
position: fixed;
bottom: env(safe-area-inset-bottom);
left: 0;
right: 0;
background: #f00;
width: 100%;
height: 20px;
font-family: sans-serif;
}
</style>
<div>
<span>bottom: env(safe-area-inset-bottom)</span>
</div>

View file

@ -16,7 +16,7 @@
"lint": "eslint \"{src,cypress}/**/*.{ts,js,jsx,tsx}\"",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build && node scripts/build.js moveStorybookFiles",
"start-experiments": "vite --config experiments/vite.config.ts",
"start-experiments": "vite --config experiments/vite.config.ts --host",
"watch-other-workers": "echo NOT IMPLEMENTED",
"watch-mesher": "node prismarine-viewer/buildMesherWorker.mjs -w",
"run-playground": "run-p watch-mesher watch-other-workers playground-server watch-playground",
@ -72,6 +72,7 @@
"minecraft-assets": "^1.12.2",
"minecraft-data": "3.65.0",
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol",
"mineflayer-item-map-downloader": "github:zardoy/mineflayer-item-map-downloader",
"mojangson": "^2.0.4",
"net-browserify": "github:zardoy/prismarinejs-net-browserify",
"node-gzip": "^1.1.2",

44
pnpm-lock.yaml generated
View file

@ -130,6 +130,9 @@ importers:
minecraft-protocol:
specifier: github:PrismarineJS/node-minecraft-protocol
version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13)
mineflayer-item-map-downloader:
specifier: github:zardoy/mineflayer-item-map-downloader
version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13)
mojangson:
specifier: ^2.0.4
version: 2.0.4
@ -6058,9 +6061,17 @@ packages:
minecrafthawkeye@1.3.6:
resolution: {integrity: sha512-SlRlorxQs6nNzMiiIQ5z47wzbAI27UaCdbRB82CE8jqj4C8m3Gqk5TlgN+PSThxx8EDPXySzd8Vk+/wNigAd5A==}
mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7:
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7}
version: 1.2.0
mineflayer-pathfinder@2.4.4:
resolution: {integrity: sha512-HAXakZrJRb1UC+5dv8EaDrqjW3ZnBnBk3nkb6x/YWyhHCUKn/E7VU0FO+UN9whuqPlkSaVumEdXJdydE6lSYxQ==}
mineflayer@4.20.1:
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}
version: 4.20.1
@ -15753,6 +15764,14 @@ snapshots:
detect-collisions: 7.0.5
vec3: 0.1.8
mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13):
dependencies:
mineflayer: 4.20.1(encoding@0.1.13)
sharp: 0.30.7
transitivePeerDependencies:
- encoding
- supports-color
mineflayer-pathfinder@2.4.4:
dependencies:
minecraft-data: 3.65.0
@ -15763,6 +15782,29 @@ snapshots:
prismarine-physics: 1.8.0
vec3: 0.1.8
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)
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-entity: 2.3.1
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
prismarine-physics: 1.8.0
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
protodef: 1.15.0
typed-emitter: 1.4.0
vec3: 0.1.8
transitivePeerDependencies:
- encoding
- supports-color
mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13):
dependencies:
minecraft-data: 3.65.0
@ -17408,7 +17450,7 @@ snapshots:
detect-libc: 2.0.2
node-addon-api: 5.1.0
prebuild-install: 7.1.1
semver: 7.5.4
semver: 7.6.0
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0

View file

@ -138,6 +138,7 @@ async function main () {
viewer.entities.onSkinUpdate = () => {
viewer.render()
}
viewer.world.mesherConfig.enableLighting = false
viewer.listen(worldView)
// Load chunks

View file

@ -38,8 +38,22 @@ export const setup = (version, initialBlocks: [number[], string][]) => {
}
reload()
const getLights = () => {
return Object.fromEntries(getGeometry().faces.map(({ face, light }) => ([face, light * 15 - 2])))
}
const setLight = (x: number, y: number, z: number, val = 0) => {
// create columns first
chunk1.setBlockLight(pos.offset(x, y, z), 15)
chunk1.setSkyLight(pos.offset(x, y, z), 15)
chunk1.setBlockLight(pos.offset(x, y, z), val)
chunk1.setSkyLight(pos.offset(x, y, z), 0)
}
return {
mesherWorld,
setLight,
getLights,
getGeometry,
pos,
mcData,

View file

@ -23,3 +23,23 @@ Object.defineProperty(window, 'debugSceneChunks', {
return (viewer.world as WorldRendererThree).getLoadedChunksRelative?.(bot.entity.position, true)
},
})
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)
}
attach()
customEvents.on('mineflayerBotCreated', attach)
const returnobj = {}
Object.defineProperty(returnobj, 'detach', {
get () {
bot?.removeListener(packetName, listener)
customEvents.removeListener('mineflayerBotCreated', attach)
return true
},
})
return returnobj
}

View file

@ -128,6 +128,12 @@ if (isFirefox) {
document.body.style.setProperty('--thin-if-firefox', 'thin')
}
const isIphone = ua.getDevice().model === 'iPhone' // todo ipad?
if (isIphone) {
document.documentElement.style.setProperty('--hud-bottom-max', '21px') // env-safe-aria-inset-bottom
}
// Create viewer
const viewer: import('prismarine-viewer/viewer/lib/viewer').Viewer = new Viewer(renderer)
window.viewer = viewer
@ -438,7 +444,9 @@ async function connect (connectOptions: ConnectOptions) {
async versionSelectedHook (client) {
await downloadMcData(client.version)
setLoadingScreenStatus(initialLoadingText)
}
},
'mapDownloader-saveToFile': false,
// "mapDownloader-saveInternal": false, // do not save into memory, todo must be implemeneted as we do really care of ram
}) as unknown as typeof __type_bot
window.bot = bot
earlySoundsMapCheck()
@ -539,6 +547,15 @@ 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')

55
src/react/HeldMapUi.tsx Normal file
View file

@ -0,0 +1,55 @@
import { useEffect, useState } from 'react'
import { mapDownloader } from 'mineflayer-item-map-downloader/'
import { setImageConverter } from 'mineflayer-item-map-downloader/lib/util'
export default () => {
const [dataUrl, setDataUrl] = useState<string | null | true>(null) // true means loading
useEffect(() => {
bot.loadPlugin(mapDownloader)
setImageConverter((buf: Uint8Array) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')!
canvas.width = 128
canvas.height = 128
const imageData = ctx.createImageData(canvas.width, canvas.height)
imageData.data.set(buf)
ctx.putImageData(imageData, 0, 0)
// data url
return canvas.toDataURL('image/png')
})
// TODO delete maps!
const updateHeldMap = () => {
setDataUrl(null)
if (!bot.heldItem || !['filled_map', 'map'].includes(bot.heldItem.name)) return
// setDataUrl(true)
const mapNumber = (bot.heldItem?.nbt?.value as any)?.map?.value
// if (!mapNumber) return
setDataUrl(bot.mapDownloader.maps?.[mapNumber] as unknown as string)
}
bot.on('heldItemChanged' as any, () => {
updateHeldMap()
})
bot.on('new_map', () => {
// total maps: Object.keys(bot.mapDownloader.maps).length
updateHeldMap()
})
}, [])
return dataUrl && dataUrl !== true ? <div style={{
position: 'fixed',
bottom: 20,
left: 8,
pointerEvents: 'none',
}}>
<img src={dataUrl} style={{
width: 92,
height: 92,
imageRendering: 'pixelated',
}} />
</div> : null
}

View file

@ -211,7 +211,7 @@ export default () => {
justifyContent: 'center',
zIndex: hasModals ? 1 : 8,
pointerEvents: 'none',
bottom: 'env(safe-area-inset-bottom)'
bottom: 'var(--hud-bottom-raw)'
}} />
</Portal>
</SharedHudVars>

View file

@ -7,9 +7,9 @@ import './IndicatorEffects.css'
function formatTime (seconds: number): string {
if (seconds < 0) return ''
const minutes = Math.floor(seconds / 60)
const remainingSeconds = seconds % 60
const remainingSeconds = Math.floor(seconds % 60)
const formattedMinutes = String(minutes).padStart(2, '0')
const formattedSeconds = String(remainingSeconds).padStart(2, '0')
const formattedSeconds = String(remainingSeconds)
return `${formattedMinutes}:${formattedSeconds}`
}
@ -32,10 +32,10 @@ const EffectBox = ({ image, time, level }: Pick<EffectType, 'image' | 'time' | '
// if time is negative then effect is shown without time.
// Component should be removed manually with time = 0
<div className='effect-box__time'>{formattedTime}</div>
) : null }
) : null}
{level > 0 && level < 256 ? (
<div className='effect-box__level'>{level + 1}</div>
) : null }
) : null}
</div>
</div>
}
@ -56,7 +56,7 @@ const indicatorIcons: Record<keyof typeof defaultIndicatorsState, string> = {
readonlyFiles: 'file-off',
}
export default ({ indicators, effects }: {indicators: typeof defaultIndicatorsState, effects: readonly EffectType[]}) => {
export default ({ indicators, effects }: { indicators: typeof defaultIndicatorsState, effects: readonly EffectType[] }) => {
const effectsRef = useRef(effects)
useEffect(() => {
effectsRef.current = effects

View file

@ -60,14 +60,22 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer,
return <Singleplayer {...props}
firstRowChildrenOverride={<form style={{ width: '100%', display: 'flex', justifyContent: 'center' }} onSubmit={(e) => {
e.preventDefault()
joinServer(serverIp, {
let ip = serverIp
let version
const parts = ip.split(':')
if (parts.length > 1 && parts.at(-1)!.includes('.')) {
version = parts.at(-1)!
ip = parts.slice(0, -1).join(':')
}
joinServer(ip, {
shouldSave: save,
versionOverride: version,
})
}}
>
<div style={{ display: 'flex', gap: 5, alignItems: 'center' }}>
{/* todo history */}
<Input required placeholder='Quick Connect IP' value={serverIp} onChange={({ target: { value } }) => setServerIp(value)} />
<Input required placeholder='Quick Connect IP (:version)' value={serverIp} onChange={({ target: { value } }) => setServerIp(value)} />
<label style={{ fontSize: 10, display: 'flex', alignItems: 'center', gap: 5, height: '100%', marginTop: '-1px' }}>
<input type='checkbox' checked={save}
style={{ borderRadius: 0 }}

View file

@ -114,6 +114,9 @@ export const updateLoadedServerData = (callback: (data: StoreServerItem) => Stor
setNewServersList(servers)
}
// todo move to base
const normalizeIp = (ip: string) => ip.replace(/https?:\/\//, '').replace(/\/(:|$)/, '')
const Inner = () => {
const [proxies, setProxies] = useState<readonly string[]>(localStorage['proxies'] ? JSON.parse(localStorage['proxies']) : getInitialProxies())
const [selectedProxy, setSelectedProxy] = useState(localStorage.getItem('selectedProxy') ?? proxies?.[0] ?? '')
@ -210,7 +213,7 @@ const Inner = () => {
onQsConnect={(info) => {
const connectOptions: ConnectOptions = {
username: info.usernameOverride || defaultUsername,
server: info.ip,
server: normalizeIp(info.ip),
proxy: info.proxyOverride || selectedProxy,
botVersion: info.versionOverride,
password: info.passwordOverride,
@ -241,7 +244,7 @@ const Inner = () => {
}
const options = {
username,
server: ip,
server: normalizeIp(ip),
proxy: overrides.proxy || selectedProxy,
botVersion: overrides.versionOverride ?? /* legacy */ overrides['version'],
password: overrides.password,

View file

@ -8,10 +8,12 @@ export default ({ children }): React.ReactElement => {
// 1. Don't inline long data URLs for better DX in elements tab
// 2. Easier application to globally override icons with custom image (eg from resourcepacks)
const css = /* css */`
:root {
html {
--widgets-gui-atlas: url(${widgets});
--gui-icons: url(${icons}), url(${icons});
--safe-area-inset-bottom: calc(env(safe-area-inset-bottom) / 2);
--hud-bottom-max: 0px;
--hud-bottom-raw: max(env(safe-area-inset-bottom), var(--hud-bottom-max));
--safe-area-inset-bottom: calc(var(--hud-bottom-raw) / 2);
}
`
const style = document.createElement('style')

View file

@ -23,7 +23,7 @@
.world_root {
height: 40px;
width: 300px;
width: 308px;
border: 1px solid transparent;
display: flex;
outline: none;
@ -43,6 +43,7 @@
flex-direction: column;
font-size: 11px;
white-space: nowrap;
width: 100%;
}
.world_info_formatted {
font-size: 10px;

View file

@ -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 HeldMapUi from './react/HeldMapUi'
const RobustPortal = ({ children, to }) => {
return createPortal(<PerComponentErrorBoundary>{children}</PerComponentErrorBoundary>, to)
@ -85,6 +86,12 @@ const GameHud = ({ children }) => {
return gameLoaded ? children : null
}
const InGameComponent = ({ children }) => {
const { gameLoaded } = useSnapshot(miscUiState)
if (!gameLoaded) return null
return children
}
const InGameUi = () => {
const { gameLoaded } = useSnapshot(miscUiState)
if (!gameLoaded) return
@ -135,6 +142,14 @@ const WidgetDisplay = ({ name, Component }) => {
const App = () => {
return <div>
<ButtonAppProvider>
<RobustPortal to={document.body}>
<div className='overlay-bottom-scaled'>
<InGameComponent>
<HeldMapUi />
</InGameComponent>
</div>
<div></div>
</RobustPortal>
<EnterFullscreenButton />
<InGameUi />
<RobustPortal to={document.querySelector('#ui-root')}>
@ -151,6 +166,7 @@ const App = () => {
</GameHud> */}
</RobustPortal>
<RobustPortal to={document.body}>
{/* todo correct mounting! */}
<div className='overlay-top-scaled'>
<GamepadUiCursor />
</div>

View file

@ -134,7 +134,7 @@ body {
-ms-interpolation-mode: nearest-neighbor;
}
.overlay-top-scaled {
.overlay-top-scaled, .overlay-bottom-scaled {
position: fixed;
inset: 0;
transform-origin: top left;
@ -146,6 +146,10 @@ body {
pointer-events: none;
}
.overlay-bottom-scaled {
z-index: 1;
}
#viewer-canvas {
position: fixed;
top: 0;

View file

@ -197,7 +197,7 @@ class WorldInteraction {
'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',
'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)
@ -219,10 +219,10 @@ class WorldInteraction {
bot.lookAt = oldLookAt
}).catch(console.warn)
}
this.lastBlockPlaced = 0
} else {
bot.activateItem() // todo offhand
}
this.lastBlockPlaced = 0
}
// Stop break