feat(devtools): downloadFile global function

fix: local server wasnt saving the time of the world
feat(advanced): add a way to specify local server options
This commit is contained in:
Vitaly Turovsky 2024-09-06 03:48:54 +03:00
commit 8e330c0253
8 changed files with 29 additions and 20 deletions

View file

@ -101,6 +101,7 @@ Instead I recommend setting `options.debugLogNotFrequentPackets`. Also you can u
- `debugChangedOptions` - See what options are changed. Don't change options here.
- `localServer`/`server` - Only for singleplayer mode/host. Flying Squid server instance, see it's documentation for more.
- `localServer.overworld.storageProvider.regions` - See ALL LOADED region files with all raw data.
- `localServer.levelData.LevelName = 'test'; localServer.writeLevelDat()` - Change name of the world
- `nbt.simplify(someNbt)` - Simplifies nbt data, so it's easier to read.
@ -141,6 +142,7 @@ Single player specific:
- `?singleplayer=1` - Create empty world on load. Nothing will be saved
- `?version=<version>` - Set the version for the singleplayer world (when used with `?singleplayer=1`)
- `?noSave=true` - Disable auto save on unload / disconnect / export whenever a world is loaded. Only manual save with `/save` command will work.
- `?serverSetting=<key>:<value>` - Set local server [options](https://github.com/zardoy/space-squid/tree/everything/src/modules.ts#L51). For example `?serverSetting=noInitialChunksSend:true` will disable initial chunks loading on the loading screen.
- `?map=<map_url>` - Load the map from ZIP. You can use any url, but it must be **CORS enabled**.
- `?mapDir=<index_file_url>` - Load the map from a file descriptor. It's recommended and the fastest way to load world but requires additional setup. The file must be in the following format:

View file

@ -68,7 +68,7 @@
"esbuild-plugin-polyfill-node": "^0.3.0",
"express": "^4.18.2",
"filesize": "^10.0.12",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.38",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.40",
"fs-extra": "^11.1.1",
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
"jszip": "^3.10.1",

10
pnpm-lock.yaml generated
View file

@ -117,8 +117,8 @@ importers:
specifier: ^10.0.12
version: 10.0.12
flying-squid:
specifier: npm:@zardoy/flying-squid@^0.0.38
version: '@zardoy/flying-squid@0.0.38(encoding@0.1.13)'
specifier: npm:@zardoy/flying-squid@^0.0.40
version: '@zardoy/flying-squid@0.0.40(encoding@0.1.13)'
fs-extra:
specifier: ^11.1.1
version: 11.1.1
@ -3390,8 +3390,8 @@ packages:
resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
'@zardoy/flying-squid@0.0.38':
resolution: {integrity: sha512-xz/ZuWmva3mlT1cigOudOMqa5iQF2sWsUUVeBNUoqfHscXoXl0TIOXnRScBeEGZjY2fD7meJ24nlcInewgNfZg==}
'@zardoy/flying-squid@0.0.40':
resolution: {integrity: sha512-m1GbT9MUlr/+l2WpZPFiS5YClE2AzvEw1iXQqGbbOVVrqbYLsV4JlLCBn1+tWWyMeTLKnT1Nmy0oZiVGLFMcQg==}
engines: {node: '>=8'}
hasBin: true
@ -13366,7 +13366,7 @@ snapshots:
'@types/emscripten': 1.39.8
tslib: 1.14.1
'@zardoy/flying-squid@0.0.38(encoding@0.1.13)':
'@zardoy/flying-squid@0.0.40(encoding@0.1.13)':
dependencies:
'@tootallnate/once': 2.0.0
change-case: 4.1.2

View file

@ -107,6 +107,7 @@ const commands: Array<{
command: ['/save'],
async invoke () {
await saveServer(false)
writeText('Saved to browser memory')
}
}
]

View file

@ -1,10 +1,9 @@
// global variables useful for debugging
import fs from 'fs'
import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree'
import { getEntityCursor } from './worldInteractions'
// Object.defineProperty(window, 'cursorBlock', )
window.cursorBlockRel = (x = 0, y = 0, z = 0) => {
const newPos = bot.blockAtCursor(5)?.position.offset(x, y, z)
if (!newPos) return
@ -44,14 +43,14 @@ window.inspectPacket = (packetName, full = false) => {
return returnobj
}
// for advanced debugging, use with watch expression
let stats_ = {}
window.addStatHit = (key) => {
stats_[key] ??= 0
stats_[key]++
window.downloadFile = async (path: string) => {
if (!path.startsWith('/') && localServer) path = `${localServer.options.worldFolder}/${path}`
const data = await fs.promises.readFile(path)
const blob = new Blob([data], { type: 'application/octet-stream' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = path.split('/').at(-1)!
a.click()
URL.revokeObjectURL(url)
}
setInterval(() => {
window.stats = stats_
stats_ = {}
}, 1000)

View file

@ -28,7 +28,7 @@ export const saveServer = async (autoSave = true) => {
if (!localServer || fsState.isReadonly) return
// todo
const worlds = [(localServer as any).overworld] as Array<import('prismarine-world').world.World>
await Promise.all([savePlayers(autoSave), ...worlds.map(async world => world.saveNow())])
await Promise.all([localServer.writeLevelDat(), savePlayers(autoSave), ...worlds.map(async world => world.saveNow())])
}
export const disconnect = async () => {
if (localServer) {

View file

@ -232,7 +232,12 @@ function hideCurrentScreens () {
}
const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => {
void connect({ singleplayer: true, username: options.localUsername, serverOverrides, serverOverridesFlat: flattenedServerOverrides })
const serverSettingsQsRaw = new URLSearchParams(window.location.search).getAll('serverSetting')
const serverSettingsQs = serverSettingsQsRaw.map(x => x.split(':')).reduce<Record<string, string>>((acc, [key, value]) => {
acc[key] = JSON.parse(value)
return acc
}, {})
void connect({ singleplayer: true, username: options.localUsername, serverOverrides, serverOverridesFlat: { ...flattenedServerOverrides, ...serverSettingsQs } })
}
function listenGlobalEvents () {
window.addEventListener('connect', e => {

View file

@ -76,6 +76,8 @@ export const statsEnd = () => {
statsGl.end()
}
// for advanced debugging, use with watch expression
window.statsPerSec = {}
let statsPerSec = {}
window.addStatPerSec = (name) => {