viewer: key control movement

This commit is contained in:
extremeheat 2021-04-07 01:56:32 -04:00
commit 01f19164ba
5 changed files with 129 additions and 17 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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 }

View file

@ -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
}
}

View file

@ -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 () {