feat: toggle chunk section border visibility by f3+g
This commit is contained in:
parent
6f6adaac3c
commit
1d4e0955c4
7 changed files with 62 additions and 42 deletions
|
|
@ -54,9 +54,9 @@ However, there are many things that can be done in online version. You can acces
|
|||
|
||||
- `bot` - Mineflayer bot instance. See Mineflayer documentation for more.
|
||||
- `viewer` - Three.js viewer instance, basically does all the rendering.
|
||||
- `viewer.world.sectionMeshs` - Object with all active chunk sections (geometries) in the world. Each chunk section is a Three.js mesh or group.
|
||||
- `localServer` - Only for singleplayer host / guest mode. Flying Squid server instance, see it's documentation for more.
|
||||
- `localServer.overworld.storageProvider.regions` - See ALL LOADED region files with all raw data!
|
||||
- `viewer.world.sectionObjects` - Object with all active chunk sections (geometries) in the world. Each chunk section is a Three.js mesh or group.
|
||||
- `localServer` - 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.
|
||||
|
||||
- `nbt.simplify(someNbt)` - Simplifies nbt data, so it's easier to read.
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"socket.io": "^4.0.0",
|
||||
"socket.io-client": "^4.0.0",
|
||||
"three.meshline": "^1.3.0",
|
||||
"vec3": "^0.1.7"
|
||||
"vec3": "^0.1.7",
|
||||
"node-canvas-webgl": "^0.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ function mod (x, n) {
|
|||
class WorldRenderer {
|
||||
constructor (scene, numWorkers = 4) {
|
||||
this.blockEntities = {}
|
||||
this.sectionMeshs = {}
|
||||
this.sectionObjects = {}
|
||||
this.showChunkBorders = false
|
||||
this.active = false
|
||||
this.version = undefined
|
||||
/** @type {THREE.Scene} */
|
||||
|
|
@ -47,11 +48,11 @@ class WorldRenderer {
|
|||
})
|
||||
if (data.type === 'geometry') {
|
||||
/** @type {THREE.Object3D} */
|
||||
let mesh = this.sectionMeshs[data.key]
|
||||
if (mesh) {
|
||||
this.scene.remove(mesh)
|
||||
dispose3(mesh)
|
||||
delete this.sectionMeshs[data.key]
|
||||
let object = this.sectionObjects[data.key]
|
||||
if (object) {
|
||||
this.scene.remove(object)
|
||||
dispose3(object)
|
||||
delete this.sectionObjects[data.key]
|
||||
}
|
||||
|
||||
const chunkCoords = data.key.split(',')
|
||||
|
|
@ -64,25 +65,25 @@ class WorldRenderer {
|
|||
geometry.setAttribute('uv', new THREE.BufferAttribute(data.geometry.uvs, 2))
|
||||
geometry.setIndex(data.geometry.indices)
|
||||
|
||||
const _mesh = new THREE.Mesh(geometry, this.material)
|
||||
_mesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz)
|
||||
const boxHelper = new THREE.BoxHelper(_mesh, 0xffff00)
|
||||
// shouldnt it compute once
|
||||
const mesh = new THREE.Mesh(geometry, this.material)
|
||||
mesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz)
|
||||
object = new THREE.Group()
|
||||
object.add(mesh)
|
||||
if (this.showChunkBorders) {
|
||||
const boxHelper = new THREE.BoxHelper(mesh, 0xffff00)
|
||||
object.add(boxHelper)
|
||||
}
|
||||
// should not it compute once
|
||||
if (Object.keys(data.geometry.signs).length) {
|
||||
mesh = new THREE.Group()
|
||||
mesh.add(_mesh)
|
||||
mesh.add(boxHelper)
|
||||
for (const [posKey, { isWall, rotation }] of Object.entries(data.geometry.signs)) {
|
||||
const [x, y, z] = posKey.split(',')
|
||||
const signBlockEntity = this.blockEntities[posKey]
|
||||
if (!signBlockEntity) continue
|
||||
mesh.add(this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(signBlockEntity)))
|
||||
object.add(this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(signBlockEntity)))
|
||||
}
|
||||
} else {
|
||||
mesh = _mesh
|
||||
}
|
||||
this.sectionMeshs[data.key] = mesh
|
||||
this.scene.add(mesh)
|
||||
this.sectionObjects[data.key] = object
|
||||
this.scene.add(object)
|
||||
} else if (data.type === 'sectionFinished') {
|
||||
this.sectionsOutstanding.delete(data.key)
|
||||
this.renderUpdateEmitter.emit('update')
|
||||
|
|
@ -125,10 +126,10 @@ class WorldRenderer {
|
|||
|
||||
resetWorld () {
|
||||
this.active = false
|
||||
for (const mesh of Object.values(this.sectionMeshs)) {
|
||||
for (const mesh of Object.values(this.sectionObjects)) {
|
||||
this.scene.remove(mesh)
|
||||
}
|
||||
this.sectionMeshs = {}
|
||||
this.sectionObjects = {}
|
||||
this.loadedChunks = {}
|
||||
this.sectionsOutstanding = new Set()
|
||||
for (const worker of this.workers) {
|
||||
|
|
@ -196,12 +197,12 @@ class WorldRenderer {
|
|||
for (let y = 0; y < 256; y += 16) {
|
||||
this.setSectionDirty(new Vec3(x, y, z), false)
|
||||
const key = `${x},${y},${z}`
|
||||
const mesh = this.sectionMeshs[key]
|
||||
const mesh = this.sectionObjects[key]
|
||||
if (mesh) {
|
||||
this.scene.remove(mesh)
|
||||
dispose3(mesh)
|
||||
}
|
||||
delete this.sectionMeshs[key]
|
||||
delete this.sectionObjects[key]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types
|
|||
import { stringStartsWith } from 'contro-max/build/stringUtils'
|
||||
import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal } from './globalState'
|
||||
import { reloadChunks } from './utils'
|
||||
import { options } from './optionsStorage'
|
||||
|
||||
// doesnt seem to work for now
|
||||
const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}'))
|
||||
|
|
@ -48,12 +49,12 @@ export const contro = new ControMax({
|
|||
},
|
||||
}, {
|
||||
target: document,
|
||||
captureEvents() {
|
||||
captureEvents () {
|
||||
return bot && isGameActive(false)
|
||||
},
|
||||
storeProvider: {
|
||||
load: () => customKeymaps,
|
||||
save() { },
|
||||
save () { },
|
||||
},
|
||||
gamepadPollingInterval: 10
|
||||
})
|
||||
|
|
@ -103,10 +104,10 @@ let lastCommandTrigger = null as { command: string, time: number } | null
|
|||
|
||||
const secondActionActivationTimeout = 300
|
||||
const secondActionCommands = {
|
||||
'general.jump'() {
|
||||
'general.jump' () {
|
||||
toggleFly()
|
||||
},
|
||||
'general.forward'() {
|
||||
'general.forward' () {
|
||||
setSprinting(true)
|
||||
}
|
||||
}
|
||||
|
|
@ -233,14 +234,23 @@ document.addEventListener('keydown', (e) => {
|
|||
}
|
||||
reloadChunks()
|
||||
}
|
||||
if (e.code === 'KeyG') {
|
||||
// todo make it work without reload
|
||||
options.showChunkBorders = !options.showChunkBorders
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (hardcodedPressedKeys.has(e.code)) return
|
||||
hardcodedPressedKeys.add(e.code)
|
||||
})
|
||||
document.addEventListener('keyup', (e) => {
|
||||
hardcodedPressedKeys.delete(e.code)
|
||||
})
|
||||
document.addEventListener('visibilitychange', (e) => {
|
||||
if (document.visibilityState === 'hidden') {
|
||||
hardcodedPressedKeys.clear()
|
||||
}
|
||||
})
|
||||
|
||||
// #region creative fly
|
||||
// these controls are more like for gamemode 3
|
||||
|
|
|
|||
19
src/index.ts
19
src/index.ts
|
|
@ -33,7 +33,7 @@ import { contro } from './controls'
|
|||
import './dragndrop'
|
||||
import './browserfs'
|
||||
import './eruda'
|
||||
import './watchOptions'
|
||||
import { watchOptionsAfterViewerInit } from './watchOptions'
|
||||
import downloadAndOpenFile from './downloadAndOpenFile'
|
||||
|
||||
import net from 'net'
|
||||
|
|
@ -111,6 +111,7 @@ window.viewer = viewer
|
|||
viewer.entities.entitiesOptions = {
|
||||
fontFamily: 'mojangles'
|
||||
}
|
||||
watchOptionsAfterViewerInit()
|
||||
initPanoramaOptions(viewer)
|
||||
watchTexturepackInViewer(viewer)
|
||||
|
||||
|
|
@ -163,7 +164,7 @@ const updateCursor = () => {
|
|||
debugMenu ??= hud.shadowRoot.querySelector('#debug-overlay')
|
||||
debugMenu.cursorBlock = blockInteraction.cursorBlock
|
||||
}
|
||||
function onCameraMove(e) {
|
||||
function onCameraMove (e) {
|
||||
if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return
|
||||
e.stopPropagation?.()
|
||||
const now = performance.now()
|
||||
|
|
@ -181,12 +182,12 @@ function onCameraMove(e) {
|
|||
window.addEventListener('mousemove', onCameraMove, { capture: true })
|
||||
|
||||
|
||||
function hideCurrentScreens() {
|
||||
function hideCurrentScreens () {
|
||||
activeModalStacks['main-menu'] = [...activeModalStack]
|
||||
insertActiveModalStack('', [])
|
||||
}
|
||||
|
||||
async function main() {
|
||||
async function main () {
|
||||
const menu = document.getElementById('play-screen')
|
||||
menu.addEventListener('connect', e => {
|
||||
const options = e.detail
|
||||
|
|
@ -234,7 +235,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine
|
|||
}
|
||||
}
|
||||
|
||||
async function connect(connectOptions: {
|
||||
async function connect (connectOptions: {
|
||||
server?: string; singleplayer?: any; username?: string; password?: any; proxy?: any; botVersion?: any; serverOverrides?; peerId?: string
|
||||
}) {
|
||||
document.getElementById('play-screen').style = 'display: none;'
|
||||
|
|
@ -377,7 +378,7 @@ async function connect(connectOptions: {
|
|||
} : {},
|
||||
...singeplayer ? {
|
||||
version: serverOptions.version,
|
||||
connect() { },
|
||||
connect () { },
|
||||
Client: CustomChannelClient as any,
|
||||
} : {},
|
||||
username,
|
||||
|
|
@ -387,7 +388,7 @@ async function connect(connectOptions: {
|
|||
noPongTimeout: 240 * 1000,
|
||||
closeTimeout: 240 * 1000,
|
||||
respawn: options.autoRespawn,
|
||||
async versionSelectedHook(client) {
|
||||
async versionSelectedHook (client) {
|
||||
// todo keep in sync with esbuild preload, expose cache ideally
|
||||
if (client.version === '1.20.1') {
|
||||
// ignore cache hit
|
||||
|
|
@ -542,7 +543,7 @@ async function connect(connectOptions: {
|
|||
dayCycle()
|
||||
|
||||
// Bot position callback
|
||||
function botPosition() {
|
||||
function botPosition () {
|
||||
// this might cause lag, but not sure
|
||||
viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch)
|
||||
worldView.updatePosition(bot.entity.position)
|
||||
|
|
@ -560,7 +561,7 @@ async function connect(connectOptions: {
|
|||
bot.entity.yaw -= x
|
||||
}
|
||||
|
||||
function changeCallback() {
|
||||
function changeCallback () {
|
||||
notification.show = false
|
||||
if (!pointerLock.hasPointerLock && activeModalStack.length === 0) {
|
||||
showModal(pauseMenu)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ const defaultOptions = {
|
|||
touchButtonsSize: 40,
|
||||
highPerformanceGpu: false,
|
||||
|
||||
showChunkBorders: false,
|
||||
frameLimit: false as number | false,
|
||||
alwaysBackupWorldBeforeLoading: undefined as boolean | undefined | null,
|
||||
alwaysShowMobileControls: false,
|
||||
|
|
@ -61,7 +62,7 @@ type WatchValue = <T extends Record<string, any>>(proxy: T, callback: (p: T) =>
|
|||
export const watchValue: WatchValue = (proxy, callback) => {
|
||||
const watchedProps = new Set<string>()
|
||||
callback(new Proxy(proxy, {
|
||||
get(target, p, receiver) {
|
||||
get (target, p, receiver) {
|
||||
watchedProps.add(p.toString())
|
||||
return Reflect.get(target, p, receiver)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
// not all options are watched here
|
||||
|
||||
import { subscribeKey } from 'valtio/utils'
|
||||
import { options } from './optionsStorage'
|
||||
import { options, watchValue } from './optionsStorage'
|
||||
import { reloadChunks } from './utils'
|
||||
|
||||
subscribeKey(options, 'renderDistance', reloadChunks)
|
||||
|
||||
export const watchOptionsAfterViewerInit = () => {
|
||||
watchValue(options, o => {
|
||||
viewer.world.showChunkBorders = o.showChunkBorders
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue