fix swing animations and improve replay server functions

This commit is contained in:
Vitaly Turovsky 2025-03-18 21:46:44 +03:00
commit 2277020de7
7 changed files with 118 additions and 26 deletions

View file

@ -86,7 +86,7 @@
"mojangson": "^2.0.4",
"net-browserify": "github:zardoy/prismarinejs-net-browserify",
"node-gzip": "^1.1.2",
"mcraft-fun-mineflayer": "^0.1.12",
"mcraft-fun-mineflayer": "^0.1.14",
"peerjs": "^1.5.0",
"pixelarticons": "^1.8.1",
"pretty-bytes": "^6.1.1",
@ -151,7 +151,7 @@
"http-server": "^14.1.1",
"https-browserify": "^1.0.0",
"mc-assets": "^0.2.42",
"mineflayer-mouse": "^0.1.1",
"mineflayer-mouse": "^0.1.2",
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
"mineflayer": "github:zardoy/mineflayer",
"mineflayer-pathfinder": "^2.4.4",

57
pnpm-lock.yaml generated
View file

@ -135,8 +135,8 @@ importers:
specifier: ^4.17.21
version: 4.17.21
mcraft-fun-mineflayer:
specifier: ^0.1.12
version: 0.1.12(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13))
specifier: ^0.1.14
version: 0.1.14(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13))
minecraft-data:
specifier: 3.83.1
version: 3.83.1
@ -362,8 +362,8 @@ importers:
specifier: github:zardoy/mineflayer
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13)
mineflayer-mouse:
specifier: ^0.1.1
version: 0.1.1(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1)
specifier: ^0.1.2
version: 0.1.2(@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
@ -6694,9 +6694,9 @@ packages:
resolution: {integrity: sha512-j2D1RNYtB5Z9gFu9MVjyDBbiALI0mWZ3xW/A3PPefVAHm3HJ2T1vH+1XBov1spBGPl7u+Zo7mRXza3X0egbeOg==}
engines: {node: '>=18.0.0'}
mcraft-fun-mineflayer@0.1.12:
resolution: {integrity: sha512-BhfkagVJX+QmD/dt3qNQS5f7g3/7NI//OfSW4VnRolCnZtrLU8ekr59bLRcNmUWsvtTjkg+wbMeXwclHshSWOA==}
version: 0.1.12
mcraft-fun-mineflayer@0.1.14:
resolution: {integrity: sha512-q/qXQaNbkGJIvXjRvudUT7/k0EsJgphFcvYjrSRWYyGDJeb61MKRVqq1hhMjqx7UK7FMfBKvjfPSxq/QlAP7WQ==}
version: 0.1.14
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
'@roamhq/wrtc': '*'
@ -6904,6 +6904,11 @@ packages:
resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/75e940a4cd50d89e0ba03db3733d5d704917a3c8}
version: 1.0.1
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1:
resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1}
version: 1.54.0
engines: {node: '>=22'}
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d:
resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d}
version: 1.54.0
@ -6920,8 +6925,8 @@ packages:
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824}
version: 1.2.0
mineflayer-mouse@0.1.1:
resolution: {integrity: sha512-7jKN+6pIGtQVfYxEIm4tA9CYwTS8Mgn/qJ2wyhrAoIEW8smCHUu0kj5Sdo0TwTCdlOQClKt8aEBZ13E7MGqOhg==}
mineflayer-mouse@0.1.2:
resolution: {integrity: sha512-QPGEXkF9PurZEpRq0xakKE8SV6sMY/6kCM9cdMeFbtq95IpYeh8ZJdD/twX2A3g3s8MooxlGovfxbpeHdWcOEQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
mineflayer-pathfinder@2.4.4:
@ -13607,7 +13612,7 @@ snapshots:
flatmap: 0.0.3
long: 5.2.3
minecraft-data: 3.83.1
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13)
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13)
mkdirp: 2.1.6
node-gzip: 1.1.2
node-rsa: 1.1.1
@ -17588,11 +17593,11 @@ snapshots:
maxrects-packer: 2.7.3
zod: 3.24.1
mcraft-fun-mineflayer@0.1.12(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13)):
mcraft-fun-mineflayer@0.1.14(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13)):
dependencies:
'@zardoy/flying-squid': 0.0.49(encoding@0.1.13)
exit-hook: 2.2.1
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13)
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13)
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13)
prismarine-item: 1.16.0
ws: 8.18.0
@ -17901,6 +17906,32 @@ snapshots:
- '@types/react'
- react
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13):
dependencies:
'@types/node-rsa': 1.1.4
'@types/readable-stream': 4.0.12
aes-js: 3.1.2
buffer-equal: 1.0.1
debug: 4.4.0(supports-color@8.1.1)
endian-toggle: 0.0.0
lodash.get: 4.4.2
lodash.merge: 4.6.2
minecraft-data: 3.83.1
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.18.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/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13):
dependencies:
'@types/node-rsa': 1.1.4
@ -17958,7 +17989,7 @@ snapshots:
- encoding
- supports-color
mineflayer-mouse@0.1.1(@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.1.2(@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

@ -8,6 +8,7 @@ import { ControMax } from 'contro-max/build/controMax'
import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types'
import { stringStartsWith } from 'contro-max/build/stringUtils'
import { UserOverrideCommand, UserOverridesConfig } from 'contro-max/build/types/store'
import { GameMode } from 'mineflayer'
import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState, hideModal, hideAllModals } from './globalState'
import { goFullscreen, isInRealGameSession, pointerLock, reloadChunks } from './utils'
import { options } from './optionsStorage'
@ -26,6 +27,7 @@ import { lastConnectOptions } from './react/AppStatusProvider'
import { onCameraMove, onControInit } from './cameraRotationControls'
import { createNotificationProgressReporter } from './core/progressReporter'
import { appStorage } from './react/appStorageProvider'
import { switchGameMode } from './packetsReplay/replayPackets'
export const customKeymaps = proxy(appStorage.keybindings)
@ -637,29 +639,35 @@ export const f3Keybinds: Array<{
{
key: 'F4',
async action () {
let nextGameMode: GameMode
switch (bot.game.gameMode) {
case 'creative': {
bot.chat('/gamemode survival')
nextGameMode = 'survival'
break
}
case 'survival': {
bot.chat('/gamemode adventure')
nextGameMode = 'adventure'
break
}
case 'adventure': {
bot.chat('/gamemode spectator')
nextGameMode = 'spectator'
break
}
case 'spectator': {
bot.chat('/gamemode creative')
nextGameMode = 'creative'
break
}
// No default
}
if (lastConnectOptions.value?.worldStateFileContents) {
switchGameMode(nextGameMode)
} else {
bot.chat(`/gamemode ${nextGameMode}`)
}
},
mobileTitle: 'Cycle Game Mode'
},
@ -810,15 +818,16 @@ let allowFlying = false
export const onBotCreate = () => {
let wasSpectatorFlying = false
bot._client.on('abilities', ({ flags }) => {
allowFlying = !!(flags & 4)
if (flags & 2) { // flying
toggleFly(true, false)
} else {
toggleFly(false, false)
}
allowFlying = !!(flags & 4)
})
const gamemodeCheck = () => {
if (bot.game.gameMode === 'spectator') {
allowFlying = true
toggleFly(true, false)
wasSpectatorFlying = true
} else if (wasSpectatorFlying) {

View file

@ -13,13 +13,43 @@ export const getFixedFilesize = (bytes: number) => {
const inner = async () => {
const { replayFileUrl } = appQueryParams
if (replayFileUrl) {
setLoadingScreenStatus('Downloading replay file...')
setLoadingScreenStatus('Downloading replay file')
const response = await fetch(replayFileUrl)
const contentLength = response.headers?.get('Content-Length')
const size = contentLength ? +contentLength : undefined
const filename = replayFileUrl.split('/').pop()
const contents = await response.text()
let downloadedBytes = 0
const buffer = await new Response(new ReadableStream({
async start (controller) {
if (!response.body) throw new Error('Server returned no response!')
const reader = response.body.getReader()
// eslint-disable-next-line no-constant-condition
while (true) {
const { done, value } = await reader.read()
if (done) {
controller.close()
break
}
downloadedBytes += value.byteLength
// Calculate download progress as a percentage
const progress = size ? (downloadedBytes / size) * 100 : undefined
setLoadingScreenStatus(`Download replay file progress: ${progress === undefined ? '?' : Math.floor(progress)}% (${getFixedFilesize(downloadedBytes)} / ${size && getFixedFilesize(size)})`, false, true)
// Pass the received data to the controller
controller.enqueue(value)
}
},
})).arrayBuffer()
// Convert buffer to text, handling any compression automatically
const decoder = new TextDecoder()
const contents = decoder.decode(buffer)
openFile({
contents,
filename,

View file

@ -781,11 +781,13 @@ export async function connect (connectOptions: ConnectOptions) {
setLoadingScreenStatus('Placing blocks (starting viewer)')
if (!connectOptions.worldStateFileContents || connectOptions.worldStateFileContents.length < 3 * 1024 * 1024) {
localStorage.lastConnectOptions = JSON.stringify(connectOptions)
if (process.env.NODE_ENV === 'development' && !localStorage.lockUrl && !Object.keys(window.debugQueryParams).length) {
lockUrl()
}
} else {
localStorage.removeItem('lastConnectOptions')
}
connectOptions.onSuccessfulPlay?.()
if (process.env.NODE_ENV === 'development' && !localStorage.lockUrl && !Object.keys(window.debugQueryParams).length) {
lockUrl()
}
updateDataAfterJoin()
if (connectOptions.autoLoginPassword) {
bot.chat(`/login ${connectOptions.autoLoginPassword}`)

View file

@ -3,6 +3,7 @@ import { createServer, ServerClient } from 'minecraft-protocol'
import { ParsedReplayPacket, parseReplayContents } from 'mcraft-fun-mineflayer/build/packetsLogger'
import { PACKETS_REPLAY_FILE_EXTENSION, WORLD_STATE_FILE_EXTENSION } from 'mcraft-fun-mineflayer/build/worldState'
import MinecraftData from 'minecraft-data'
import { GameMode } from 'mineflayer'
import { LocalServer } from '../customServer'
import { UserError } from '../mineflayer/userError'
import { packetsReplayState } from '../react/state/packetsReplayState'
@ -231,6 +232,25 @@ const mainPacketsReplayer = async (client: ServerClient, packets: ParsedReplayPa
}
}
export const switchGameMode = (gameMode: GameMode) => {
const gamemodes = {
survival: 0,
creative: 1,
adventure: 2,
spectator: 3
}
if (gameMode === 'spectator') {
bot._client.emit('abilities', {
// can fly + is flying
flags: 6
})
}
bot._client.emit('game_state_change', {
reason: 3,
gameMode: gamemodes[gameMode]
})
}
interface PacketsWaiterOptions {
unexpectedPacketReceived?: (name: string, params: any) => void
expectedPacketReceived?: (name: string, params: any) => void

View file

@ -22,7 +22,7 @@ export default function PacketsReplayProvider () {
return (
<ReplayPanel
style={{
transform: 'scale(0.5)',
transform: 'scale(0.4)',
transformOrigin: 'top right'
}}
replayName={state.replayName}