viewer: key control movement
This commit is contained in:
parent
7a830317ea
commit
01f19164ba
5 changed files with 129 additions and 17 deletions
|
|
@ -15,8 +15,19 @@ class BotProvider extends WorldView {
|
|||
this.listenToBot()
|
||||
this.world = new World()
|
||||
this.movements = new MovementManager(this)
|
||||
|
||||
this.onKeyDown = () => {}
|
||||
this.onKeyUp = () => {}
|
||||
|
||||
this.removeAllListeners('mouseClick')
|
||||
}
|
||||
|
||||
raycast () {
|
||||
// TODO : fix
|
||||
}
|
||||
|
||||
get entity () { return this.movements.player.entity }
|
||||
|
||||
handleChunk (packet, render = true) {
|
||||
const hash = (packet.x << 4) + ',' + (packet.z << 4)
|
||||
if (this.loadChunk[hash]) return
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* global THREE */
|
||||
const { Viewer, MapControls } = require('prismarine-viewer/viewer')
|
||||
// const { Vec3 } = require('vec3')
|
||||
// const { BotProvider } = require('./BotProvider')
|
||||
const { ClientProvider } = require('./ClientProvider')
|
||||
const { ProxyProvider } = require('./ProxyProvider')
|
||||
global.THREE = require('three')
|
||||
|
||||
|
|
@ -9,8 +9,8 @@ const MCVER = '1.16.1'
|
|||
|
||||
class BotViewer {
|
||||
start () {
|
||||
// this.bot = new BotProvider()
|
||||
this.bot = new ProxyProvider()
|
||||
this.bot = new ClientProvider()
|
||||
// this.bot = new ProxyProvider()
|
||||
// Create three.js context, add to page
|
||||
this.renderer = new THREE.WebGLRenderer()
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio || 1)
|
||||
|
|
@ -36,15 +36,18 @@ class BotViewer {
|
|||
this.registerBrowserEvents()
|
||||
|
||||
if (firstPerson && this.bot.movements) {
|
||||
this.viewer.camera.position.set(position.x, position.y, position.z)
|
||||
this.firstPerson = true
|
||||
this.controls.enabled = false
|
||||
} else {
|
||||
this.viewer.camera.position.set(position.x, position.y, position.z)
|
||||
}
|
||||
})
|
||||
|
||||
this.bot.on('playerMove', (id, pos) => {
|
||||
if (this.firstPerson && id === 1) {
|
||||
if (this.firstPerson && id < 10) {
|
||||
this.setFirstPersonCamera(pos)
|
||||
return
|
||||
}
|
||||
|
||||
window.viewer.viewer.entities.update({
|
||||
|
|
@ -58,6 +61,13 @@ class BotViewer {
|
|||
})
|
||||
})
|
||||
|
||||
this.bot.on('startSprint', () => {
|
||||
this.viewer.camera.fov += 20
|
||||
})
|
||||
this.bot.on('stopSprint', () => {
|
||||
this.viewer.camera.fov -= 20
|
||||
})
|
||||
|
||||
this.controls.update()
|
||||
|
||||
// Browser animation loop
|
||||
|
|
@ -76,12 +86,43 @@ class BotViewer {
|
|||
})
|
||||
}
|
||||
|
||||
onKeyDown = (evt) => {
|
||||
console.log('Key down', evt)
|
||||
onMouseMove = (e) => {
|
||||
if (this.firstPerson) {
|
||||
this.bot.entity.pitch -= e.movementY * 0.005
|
||||
this.bot.entity.yaw -= e.movementX * 0.004
|
||||
}
|
||||
}
|
||||
|
||||
onPointerLockChange = () => {
|
||||
const e = this.renderer.domElement
|
||||
if (document.pointerLockElement === e) {
|
||||
e.parentElement.addEventListener('mousemove', this.onMouseMove, { passive: true })
|
||||
} else {
|
||||
e.parentElement.removeEventListener('mousemove', this.onMouseMove, false)
|
||||
}
|
||||
}
|
||||
|
||||
onMouseDown = () => {
|
||||
if (this.firstPerson && !document.pointerLockElement) {
|
||||
this.renderer.domElement.requestPointerLock()
|
||||
}
|
||||
}
|
||||
|
||||
registerBrowserEvents () {
|
||||
this.renderer.domElement.parentElement.addEventListener('keydown', this.onKeyDown)
|
||||
const e = this.renderer.domElement
|
||||
e.parentElement.addEventListener('keydown', this.bot.onKeyDown)
|
||||
e.parentElement.addEventListener('keyup', this.bot.onKeyUp)
|
||||
e.parentElement.addEventListener('mousedown', this.onMouseDown)
|
||||
document.addEventListener('pointerlockchange', this.onPointerLockChange, false)
|
||||
}
|
||||
|
||||
unregisterBrowserEvents () {
|
||||
const e = this.renderer.domElement
|
||||
e.parentElement.removeEventListener('keydown', this.bot.onKeyDown)
|
||||
e.parentElement.removeEventListener('keyup', this.bot.onKeyUp)
|
||||
e.parentElement.removeEventListener('mousemove', this.onMouseMove)
|
||||
e.parentElement.removeEventListener('mousedown', this.onMouseDown)
|
||||
document.removeEventListener('pointerlockchange', this.onPointerLockChange, false)
|
||||
}
|
||||
|
||||
setFirstPersonCamera (entity) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,18 @@
|
|||
const { Client } = require('bedrock-protocol')
|
||||
const { BotProvider } = require('./BotProvider')
|
||||
|
||||
const controlMap = {
|
||||
forward: ['KeyW', 'KeyZ'],
|
||||
back: 'KeyS',
|
||||
left: ['KeyA', 'KeyQ'],
|
||||
right: 'KeyD',
|
||||
sneak: 'ShiftLeft',
|
||||
jump: 'Space'
|
||||
}
|
||||
|
||||
class ClientProvider extends BotProvider {
|
||||
downKeys = new Set()
|
||||
|
||||
connect () {
|
||||
const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 })
|
||||
|
||||
|
|
@ -20,7 +31,10 @@ class ClientProvider extends BotProvider {
|
|||
|
||||
client.queue('client_cache_status', { enabled: false })
|
||||
client.queue('request_chunk_radius', { chunk_radius: 1 })
|
||||
client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n })
|
||||
|
||||
this.heartbeat = setInterval(() => {
|
||||
client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n })
|
||||
})
|
||||
})
|
||||
|
||||
this.client = client
|
||||
|
|
@ -36,11 +50,13 @@ class ClientProvider extends BotProvider {
|
|||
})
|
||||
this.client.on('start_game', packet => {
|
||||
this.updatePosition(packet.player_position)
|
||||
this.movements.init('', packet.player_position, null, packet.rotation.z, packet.rotation.x, 0)
|
||||
})
|
||||
|
||||
this.client.on('spawn', () => {
|
||||
this.movements.startPhys()
|
||||
// server allows client to render chunks & spawn in world
|
||||
this.emit('spawn', { position: this.lastPos })
|
||||
this.emit('spawn', { position: this.lastPos, firstPerson: true })
|
||||
|
||||
this.tickLoop = setInterval(() => {
|
||||
this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n })
|
||||
|
|
@ -52,17 +68,45 @@ class ClientProvider extends BotProvider {
|
|||
})
|
||||
|
||||
this.client.on('move_player', packet => {
|
||||
if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position)
|
||||
if (packet.runtime_id === this.client.entityId) { this.movements.updatePosition(packet.position, packet.yaw, packet.pitch, packet.head_yaw, packet.tick) }
|
||||
})
|
||||
|
||||
this.client.on('set_entity_motion', packet => {
|
||||
if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position)
|
||||
// if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position)
|
||||
})
|
||||
|
||||
this.client.on('tick_sync', (packet) => {
|
||||
this.lastTick = packet.response_time
|
||||
})
|
||||
}
|
||||
|
||||
onKeyDown = (evt) => {
|
||||
const code = evt.code
|
||||
for (const control in controlMap) {
|
||||
if (controlMap[control].includes(code)) {
|
||||
this.movements.setControlState(control, true)
|
||||
break
|
||||
}
|
||||
if (evt.ctrlKey) {
|
||||
this.movements.setControlState('sprint', true)
|
||||
}
|
||||
}
|
||||
this.downKeys.add(code)
|
||||
}
|
||||
|
||||
onKeyUp = (evt) => {
|
||||
const code = evt.code
|
||||
if (code == 'ControlLeft' && this.downKeys.has('ControlLeft')) {
|
||||
this.movements.setControlState('sprint', false)
|
||||
}
|
||||
for (const control in controlMap) {
|
||||
if (controlMap[control].includes(code)) {
|
||||
this.movements.setControlState(control, false)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.downKeys.delete(code)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { ClientProvider }
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ class MovementManager {
|
|||
|
||||
get lastPos () { return this.player.entity.position.clone() }
|
||||
set lastPos (newPos) { this.player.entity.position.set(newPos.x, newPos.y, newPos.z) }
|
||||
|
||||
get lastRot () { return vec3(this.player.entity.yaw, this.player.entity.pitch, this.player.entity.headYaw) }
|
||||
|
||||
set lastRot (rot) {
|
||||
this.player.entity.yaw = rot.x
|
||||
this.player.entity.pitch = rot.y
|
||||
|
|
@ -33,10 +31,10 @@ class MovementManager {
|
|||
const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos)
|
||||
const rotationUpdated = !this.lastSentRot || !this.lastRot.equals(this.lastSentRot)
|
||||
|
||||
if (positionUpdated) {
|
||||
if (positionUpdated || rotationUpdated) {
|
||||
this.lastSentPos = this.lastPos.clone()
|
||||
console.log('We computed', this.lastPos)
|
||||
this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch)
|
||||
// console.log('We computed', this.lastPos)
|
||||
this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch || this.player.entity.pitch)
|
||||
if (this.serverMovements) {
|
||||
this.client.queue('player_auth_input', {
|
||||
pitch: this.player.pitch,
|
||||
|
|
@ -175,6 +173,7 @@ class MovementManager {
|
|||
stop_gliding: false
|
||||
})
|
||||
this.timeAccumulator -= PHYSICS_TIMESTEP
|
||||
this.tick++
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,16 +184,29 @@ class MovementManager {
|
|||
}, PHYSICS_INTERVAL_MS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the active control state and also keeps track of key toggles.
|
||||
* @param {'forward' | 'back' | 'left' | 'right' | 'jump' | 'sprint' | 'sneak'} control
|
||||
* @param {boolean} state
|
||||
*/
|
||||
setControlState (control, state) {
|
||||
// HACK ! switch left and right, fixes control issue
|
||||
if (control === 'left') control = 'right'
|
||||
else if (control === 'right') control = 'left'
|
||||
|
||||
if (this.controls[control] === state) return
|
||||
if (control === 'sprint') {
|
||||
this.player.events.startSprint = state
|
||||
this.player.events.stopSprint = !state
|
||||
if (state) this.bot.emit('startSprint')
|
||||
else this.bot.emit('stopSprint')
|
||||
this.controls.sprint = true
|
||||
} else if (control === 'sneak') {
|
||||
this.player.events.startSneak = state
|
||||
this.player.events.stopSneak = !state
|
||||
this.controls.sprint = true
|
||||
} else {
|
||||
this.controls[control] = state
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const path = require('path')
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow, globalShortcut } = require('electron')
|
||||
|
||||
function createMainWindow () {
|
||||
const window = new BrowserWindow({
|
||||
|
|
@ -28,6 +28,10 @@ function createMainWindow () {
|
|||
|
||||
app.on('ready', () => {
|
||||
createMainWindow()
|
||||
|
||||
globalShortcut.register('CommandOrControl+W', () => {
|
||||
// no op
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue