-
+
+
+
+
diff --git a/src/rendererUtils.ts b/src/rendererUtils.ts
new file mode 100644
index 000000000..6b83fd011
--- /dev/null
+++ b/src/rendererUtils.ts
@@ -0,0 +1,27 @@
+import { subscribeKey } from 'valtio/utils'
+import { gameAdditionalState } from './globalState'
+import { options } from './optionsStorage'
+
+export const watchFov = () => {
+ const updateFov = () => {
+ if (!bot) return
+ let fovSetting = options.fov
+ // todo check values and add transition
+ if (bot.controlState.sprint && !bot.controlState.sneak) {
+ fovSetting += 5
+ }
+ if (gameAdditionalState.isFlying) {
+ fovSetting += 5
+ }
+ viewer.camera.fov = fovSetting
+ viewer.camera.updateProjectionMatrix()
+ }
+ updateFov()
+ subscribeKey(options, 'fov', updateFov)
+ subscribeKey(gameAdditionalState, 'isFlying', updateFov)
+ subscribeKey(gameAdditionalState, 'isSprinting', updateFov)
+ subscribeKey(gameAdditionalState, 'isSneaking', () => {
+ viewer.isSneaking = gameAdditionalState.isSneaking
+ viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch)
+ })
+}
diff --git a/src/styles.css b/src/styles.css
index ea0c4feff..a1a8a8ed2 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -22,9 +22,15 @@ html {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
height: 100vh;
overflow: hidden;
+ color: white;
+}
+body {
--widgets-gui-atlas: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png');
--title-gui: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/title/minecraft.png');
- color: white;
+}
+body.disable-assets {
+ --widgets-gui-atlas: none;
+ --title-gui: none;
}
body {
@@ -119,6 +125,10 @@ body {
animation-fill-mode: forwards;
}
+.muted {
+ color: #999;
+}
+
@keyframes dive-animation {
0% {
transform: translateZ(-150px);
diff --git a/src/texturePack.ts b/src/texturePack.ts
index 1e975522b..d17aa5d9e 100644
--- a/src/texturePack.ts
+++ b/src/texturePack.ts
@@ -4,9 +4,10 @@ import JSZip from 'jszip'
import type { Viewer } from 'prismarine-viewer/viewer/lib/viewer'
import { subscribeKey } from 'valtio/utils'
import { proxy, ref } from 'valtio'
+import { getVersion } from 'prismarine-viewer/viewer/lib/version'
import blocksFileNames from '../generated/blocks.json'
-import type { BlockStates } from './inventory'
-import { removeFileRecursiveAsync } from './browserfs'
+import type { BlockStates } from './playerWindows'
+import { copyFilesAsync, copyFilesAsyncWithProgress, mkdirRecursive, removeFileRecursiveAsync } from './browserfs'
import { setLoadingScreenStatus } from './utils'
import { showNotification } from './globalState'
@@ -27,19 +28,7 @@ function nextPowerOfTwo (n) {
return n + 1
}
-const mkdirRecursive = async (path) => {
- const parts = path.split('/')
- let current = ''
- for (const part of parts) {
- current += part + '/'
- try {
- await fs.promises.mkdir(current)
- } catch (err) {
- }
- }
-}
-
-const texturePackBasePath = '/userData/resourcePacks/default'
+const texturePackBasePath = '/data/resourcePacks/default'
export const uninstallTexturePack = async () => {
await removeFileRecursiveAsync(texturePackBasePath)
setCustomTexturePackData(undefined, undefined)
@@ -65,6 +54,12 @@ export const updateTexturePackInstalledState = async () => {
}
}
+export const installTexturePackFromHandle = async () => {
+ await mkdirRecursive(texturePackBasePath)
+ await copyFilesAsyncWithProgress('/world', texturePackBasePath)
+ await completeTexturePackInstall()
+}
+
export const installTexturePack = async (file: File | ArrayBuffer, name = file['name']) => {
try {
await uninstallTexturePack()
@@ -91,6 +86,10 @@ export const installTexturePack = async (file: File | ArrayBuffer, name = file['
done++
upStatus()
}))
+ await completeTexturePackInstall(name)
+}
+
+export const completeTexturePackInstall = async (name?: string) => {
await fs.promises.writeFile(join(texturePackBasePath, 'name.txt'), name ?? '??', 'utf8')
if (viewer?.world.active) {
@@ -120,7 +119,7 @@ type TextureResolvedData = {
const arrEqual = (a: any[], b: any[]) => a.length === b.length && a.every((x) => b.includes(x))
const applyTexturePackData = async (version: string, { blockSize }: TextureResolvedData, blocksUrlContent: string) => {
- const result = await fetch(`blocksStates/${version}.json`)
+ const result = await fetch(`blocksStates/${getVersion(version)}.json`)
const blockStates: BlockStates = await result.json()
const factor = blockSize / 16
@@ -170,11 +169,11 @@ const getSizeFromImage = async (filePath: string) => {
export const genTexturePackTextures = async (version: string) => {
setCustomTexturePackData(undefined, undefined)
- let blocksBasePath = '/userData/resourcePacks/default/assets/minecraft/textures/block'
+ let blocksBasePath = '/data/resourcePacks/default/assets/minecraft/textures/block'
// todo not clear why this is needed
- const blocksBasePathAlt = '/userData/resourcePacks/default/assets/minecraft/textures/blocks'
- const blocksGeneratedPath = `/userData/resourcePacks/default/${version}.png`
- const generatedPathData = `/userData/resourcePacks/default/${version}.json`
+ const blocksBasePathAlt = '/data/resourcePacks/default/assets/minecraft/textures/blocks'
+ const blocksGeneratedPath = `/data/resourcePacks/default/${version}.png`
+ const generatedPathData = `/data/resourcePacks/default/${version}.json`
if (!(await existsAsync(blocksBasePath))) {
if (await existsAsync(blocksBasePathAlt)) {
blocksBasePath = blocksBasePathAlt
@@ -214,7 +213,7 @@ export const genTexturePackTextures = async (version: string) => {
const canvas = document.createElement('canvas')
canvas.width = imgSize
canvas.height = imgSize
- const src = `textures/${version}.png`
+ const src = `textures/${getVersion(version)}.png`
const ctx = canvas.getContext('2d')
ctx.imageSmoothingEnabled = false
const img = new Image()
@@ -271,8 +270,8 @@ export const genTexturePackTextures = async (version: string) => {
export const watchTexturepackInViewer = (viewer: Viewer) => {
subscribeKey(resourcePackState, 'currentTexturesDataUrl', () => {
console.log('applying resourcepack world data')
- viewer.world.texturesDataUrl = resourcePackState.currentTexturesDataUrl
- viewer.world.blockStatesData = resourcePackState.currentTexturesBlockStates
+ viewer.world.customTexturesDataUrl = resourcePackState.currentTexturesDataUrl
+ viewer.world.customBlockStatesData = resourcePackState.currentTexturesBlockStates
if (!viewer?.world.active) return
viewer.world.updateTexturesData()
})
diff --git a/src/utils.ts b/src/utils.ts
index 1af37722d..d4aaeb6b0 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -2,7 +2,7 @@ import { hideModal, isGameActive, miscUiState, notification, showModal } from '.
import { options } from './optionsStorage'
import { openWorldZip } from './browserfs'
import { installTexturePack } from './texturePack'
-import { appStatusState } from './react/AppStatus'
+import { appStatusState } from './react/AppStatusProvider'
import { saveServer } from './flyingSquidUtils'
export const goFullscreen = async (doToggle = false) => {
@@ -81,7 +81,7 @@ export async function getScreenRefreshRate (): Promise
{
const fps = Math.floor(1000 * 10 / (DOMHighResTimeStamp - t0))
if (!callbackTriggered) {
- resolve(fps/* , DOMHighResTimeStampCollection */)
+ resolve(Math.max(fps, 1000)/* , DOMHighResTimeStampCollection */)
}
callbackTriggered = true
@@ -153,7 +153,7 @@ export const setLoadingScreenStatus = function (status: string | undefined | nul
export const disconnect = async () => {
- if (window.localServer) {
+ if (localServer) {
await saveServer()
localServer.quit()
}
diff --git a/src/blockInteraction.js b/src/worldInteractions.js
similarity index 83%
rename from src/blockInteraction.js
rename to src/worldInteractions.js
index a88a8cb2e..93602b961 100644
--- a/src/blockInteraction.js
+++ b/src/worldInteractions.js
@@ -23,13 +23,22 @@ function getViewDirection (pitch, yaw) {
return new Vec3(-snYaw * csPitch, snPitch, -csYaw * csPitch)
}
-class BlockInteraction {
+class WorldInteraction {
static instance = null
/** @type {null | {blockPos,mesh}} */
interactionLines = null
+ prevBreakState
+ currentDigTime
+ prevOnGround
init () {
bot.on('physicsTick', () => { if (this.lastBlockPlaced < 4) this.lastBlockPlaced++ })
+ bot.on('diggingCompleted', () => {
+ this.breakStartTime = undefined
+ })
+ bot.on('diggingAborted', () => {
+ this.breakStartTime = undefined
+ })
// Init state
this.buttons = [false, false, false]
@@ -153,9 +162,23 @@ class BlockInteraction {
this.lastBlockPlaced = 0
}
+ // Stop break
+ if ((!this.buttons[0] && this.lastButtons[0]) || cursorChanged) {
+ try {
+ bot.stopDigging() // this shouldnt throw anything...
+ } catch (e) { } // to be reworked in mineflayer, then remove the try here
+ }
+
+ const onGround = bot.entity.onGround || bot.game.gameMode === 'creative'
+ this.prevOnGround ??= onGround // todo this should be fixed in mineflayer to involve correct calculations when this changes as this is very important when mining straight down // todo this should be fixed in mineflayer to involve correct calculations when this changes as this is very important when mining straight down // todo this should be fixed in mineflayer to involve correct calculations when this changes as this is very important when mining straight down
// Start break
// todo last check doesnt work as cursorChanged happens once (after that check is false)
- if (cursorBlockDiggable && this.buttons[0] && (!this.lastButtons[0] || (cursorChanged && Date.now() - (this.lastDigged ?? 0) > 100))) {
+ if (
+ cursorBlockDiggable && this.buttons[0]
+ && (!this.lastButtons[0] || (cursorChanged && Date.now() - (this.lastDigged ?? 0) > 100) || onGround !== this.prevOnGround)
+ && onGround
+ ) {
+ this.currentDigTime = bot.digTime(cursorBlock)
this.breakStartTime = performance.now()
bot.dig(cursorBlock, 'ignore').catch((err) => {
if (err.message === 'Digging aborted') return
@@ -163,13 +186,7 @@ class BlockInteraction {
})
this.lastDigged = Date.now()
}
-
- // Stop break
- if (!this.buttons[0] && this.lastButtons[0]) {
- try {
- bot.stopDigging() // this shouldnt throw anything...
- } catch (e) { } // to be reworked in mineflayer, then remove the try here
- }
+ this.prevOnGround = onGround
// Show cursor
if (cursorBlock) {
@@ -199,11 +216,19 @@ class BlockInteraction {
}
// Show break animation
- if (cursorBlockDiggable && this.buttons[0]) {
+ if (this.breakStartTime && bot.game.gameMode !== 'creative') {
const elapsed = performance.now() - this.breakStartTime
const time = bot.digTime(cursorBlock)
+ if (time !== this.currentDigTime) {
+ console.warn('dig time changed! cancelling!', time, 'from', this.currentDigTime) // todo
+ try { bot.stopDigging() } catch { }
+ }
const state = Math.floor((elapsed / time) * 10)
- this.blockBreakMesh.material.map = this.breakTextures[state]
+ this.blockBreakMesh.material.map = this.breakTextures[state] ?? this.breakTextures.at(-1)
+ if (state !== this.prevBreakState) {
+ this.blockBreakMesh.material.needsUpdate = true
+ }
+ this.prevBreakState = state
this.blockBreakMesh.visible = true
} else {
this.blockBreakMesh.visible = false
@@ -228,4 +253,4 @@ const getDataFromShape = (shape) => {
return { position, width, height, depth }
}
-export default new BlockInteraction()
+export default new WorldInteraction()