mirror of
https://github.com/danbulant/flying-squid
synced 2026-06-11 02:21:18 +00:00
move to normal position, fix #40 + multi version for position for 1.8 and 1.12
normal position is now possible because I understood it's necessary to stored the last sent position in order to compensate for the loss of precision next time a relative position packet is sent I introduced a features.json which makes it possible to describe high level differences between version and use that to handle multi version code
This commit is contained in:
parent
332ffbca08
commit
2e749ff49f
16 changed files with 168 additions and 93 deletions
|
|
@ -8,6 +8,8 @@ if (process.env.NODE_ENV === 'dev') {
|
|||
require('longjohn')
|
||||
}
|
||||
|
||||
const supportFeature = require('./lib/supportFeature')
|
||||
|
||||
module.exports = {
|
||||
createMCServer: createMCServer,
|
||||
Behavior: require('./lib/behavior'),
|
||||
|
|
@ -36,7 +38,7 @@ class MCServer extends EventEmitter {
|
|||
if (supportedVersions.indexOf(version.majorVersion) === -1) {
|
||||
throw new Error(`Version ${version.minecraftVersion} is not supported.`)
|
||||
}
|
||||
this.majorVersion = version.majorVersion
|
||||
this.supportFeature = feature => supportFeature(feature, version.majorVersion)
|
||||
|
||||
const plugins = requireIndex(path.join(__dirname, 'lib', 'plugins'))
|
||||
this._server = mc.createServer(options)
|
||||
|
|
|
|||
32
src/lib/features.json
Normal file
32
src/lib/features.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
{
|
||||
"name": "unloadChunkByEmptyChunk",
|
||||
"description": "Chunk unloading is done by sending an empty chunk",
|
||||
"versions": ["1.8"]
|
||||
},
|
||||
{
|
||||
"name": "unloadChunkDirect",
|
||||
"description": "Chunk unloading is done by sending directly an unload chunk packet",
|
||||
"versions": ["1.12"]
|
||||
},
|
||||
{
|
||||
"name": "fixedPointPosition",
|
||||
"description": "Entity positions are represented with fixed point numbers",
|
||||
"versions": ["1.8"]
|
||||
},
|
||||
{
|
||||
"name": "doublePosition",
|
||||
"description": "Entity positions are represented with double",
|
||||
"versions": ["1.12"]
|
||||
},
|
||||
{
|
||||
"name": "fixedPointDelta",
|
||||
"description": "Delta of position are represented with fixed point numbers",
|
||||
"versions": ["1.8"]
|
||||
},
|
||||
{
|
||||
"name": "fixedPointDelta128",
|
||||
"description": "Delta of position are represented with fixed point numbers times 128",
|
||||
"versions": ["1.12"]
|
||||
}
|
||||
]
|
||||
|
|
@ -36,7 +36,7 @@ module.exports.player = function (player, serv) {
|
|||
},
|
||||
action (params) {
|
||||
let res = params.slice(1, 4)
|
||||
res = res.map((val, i) => serv.posFromString(val, player.position[['x', 'y', 'z'][i]] / 32))
|
||||
res = res.map((val, i) => serv.posFromString(val, player.position[['x', 'y', 'z'][i]]))
|
||||
player.setBlock(new Vec3(res[0], res[1], res[2]).floored(), params[4], params[5] || 0)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ module.exports.player = function (player, serv, {version}) {
|
|||
return str || false
|
||||
},
|
||||
action (sel) {
|
||||
const arr = serv.selectorString(sel, player.position.scaled(1 / 32), player.world)
|
||||
const arr = serv.selectorString(sel, player.position, player.world)
|
||||
player.chat(JSON.stringify(arr.map(a => a.id)))
|
||||
}
|
||||
})
|
||||
|
|
@ -119,7 +119,7 @@ module.exports.player = function (player, serv, {version}) {
|
|||
}
|
||||
|
||||
module.exports.entity = function (entity, serv) {
|
||||
entity.selectorString = (str) => serv.selectorString(str, entity.position.scaled(1 / 32), entity.world)
|
||||
entity.selectorString = (str) => serv.selectorString(str, entity.position, entity.world)
|
||||
}
|
||||
|
||||
module.exports.server = function (serv) {
|
||||
|
|
@ -190,8 +190,8 @@ module.exports.server = function (serv) {
|
|||
})
|
||||
|
||||
sample = sample.filter(s => {
|
||||
if ((notudf(opt.radius) && s.position.scaled(1 / 32).distanceTo(pos) > opt.radius) ||
|
||||
(notudf(opt.minRadius) && s.position.scaled(1 / 32).distanceTo(pos) < opt.minRadius) ||
|
||||
if ((notudf(opt.radius) && s.position.distanceTo(pos) > opt.radius) ||
|
||||
(notudf(opt.minRadius) && s.position.distanceTo(pos) < opt.minRadius) ||
|
||||
(notudf(opt.gameMode) && s.gameMode !== opt.gameMode) ||
|
||||
(notudf(opt.level) && s.level > opt.level) ||
|
||||
(notudf(opt.minLevel) && s.level < opt.minLevel) ||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ module.exports.server = function (serv) {
|
|||
serv._writeNearby = (packetName, packetFields, loc) =>
|
||||
serv._writeArray(packetName, packetFields, serv.getNearby(loc))
|
||||
|
||||
serv.getNearby = ({world, position, radius = 8 * 16 * 32}) => serv.players.filter(player =>
|
||||
serv.getNearby = ({world, position, radius = 8 * 16}) => serv.players.filter(player =>
|
||||
player.world === world &&
|
||||
player.position.distanceTo(position) <= radius
|
||||
)
|
||||
|
||||
serv.getNearbyEntities = ({world, position, radius = 8 * 16 * 32}) => Object.keys(serv.entities)
|
||||
serv.getNearbyEntities = ({world, position, radius = 8 * 16}) => Object.keys(serv.entities)
|
||||
.map(eId => serv.entities[eId])
|
||||
.filter(entity =>
|
||||
entity.world === world &&
|
||||
|
|
@ -26,7 +26,7 @@ module.exports.entity = function (entity, serv) {
|
|||
.getNearbyEntities({
|
||||
world: entity.world,
|
||||
position: entity.position,
|
||||
radius: entity.viewDistance * 32
|
||||
radius: entity.viewDistance
|
||||
})
|
||||
.filter((e) => e !== entity)
|
||||
|
||||
|
|
@ -34,10 +34,10 @@ module.exports.entity = function (entity, serv) {
|
|||
|
||||
entity.getOthers = () => serv.entities.filter((e) => e !== entity)
|
||||
|
||||
entity.getNearbyPlayers = (radius = entity.viewDistance * 32) => entity.getNearby()
|
||||
entity.getNearbyPlayers = (radius = entity.viewDistance) => entity.getNearby()
|
||||
.filter((e) => e.type === 'player')
|
||||
|
||||
entity.nearbyPlayers = (radius = entity.viewDistance * 32) => entity.nearbyEntities
|
||||
entity.nearbyPlayers = (radius = entity.viewDistance) => entity.nearbyEntities
|
||||
.filter(e => e.type === 'player')
|
||||
|
||||
entity._writeOthers = (packetName, packetFields) =>
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ module.exports.player = function (player, serv, settings) {
|
|||
reducedDebugInfo: false,
|
||||
maxPlayers: serv._server.maxPlayers
|
||||
})
|
||||
player.position = player.spawnPoint.toFixedPosition()
|
||||
player.position = player.spawnPoint.clone()
|
||||
}
|
||||
|
||||
function sendChunkWhenMove () {
|
||||
player.on('move', () => {
|
||||
if (!player.sendingChunks && player.position.distanceTo(player.lastPositionChunkUpdated) > 16 * 32) { player.sendRestMap() }
|
||||
if (!player.sendingChunks && player.position.distanceTo(player.lastPositionChunkUpdated) > 16) { player.sendRestMap() }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
const Vec3 = require('vec3').Vec3
|
||||
|
||||
module.exports.server = function (serv) {
|
||||
serv.emitParticle = (particle, world, position, {whitelist, blacklist = [], radius = 32 * 32, longDistance = true, size = new Vec3(1, 1, 1), count = 1} = {}) => {
|
||||
serv.emitParticle = (particle, world, position, {whitelist, blacklist = [], radius = 32, longDistance = true, size = new Vec3(1, 1, 1), count = 1} = {}) => {
|
||||
const players = (typeof whitelist !== 'undefined' ? (whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({
|
||||
world: world,
|
||||
position: position.scaled(32).floored(),
|
||||
radius: radius // 32 blocks, fixed position
|
||||
position: position,
|
||||
radius: radius
|
||||
}))
|
||||
|
||||
serv._writeArray('world_particles', {
|
||||
|
|
@ -45,7 +45,7 @@ module.exports.player = function (player, serv) {
|
|||
return
|
||||
}
|
||||
player.chat('Emitting "' + particle + '" (count: ' + amount + ', size: ' + size.toString() + ')')
|
||||
serv.emitParticle(particle, player.world, player.position.scaled(1 / 32), {count: amount, size: size})
|
||||
serv.emitParticle(particle, player.world, player.position, {count: amount, size: size})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ module.exports.entity = function (entity, serv, {version}) {
|
|||
const vSign = getSign(entity.velocity)
|
||||
const sizeSigned = new Vec3(vSign.x * entity.size.x, vSign.y * entity.size.y, vSign.z * entity.size.z)
|
||||
|
||||
const xVec = entity.position.offset(entity.velocity.x * delta + sizeSigned.x / 2, 0, 0).scaled(1 / 32).floored()
|
||||
const yVec = entity.position.offset(0, entity.velocity.y * delta + sizeSigned.y / 2, 0).scaled(1 / 32).floored()
|
||||
const zVec = entity.position.offset(0, 0, entity.velocity.z * delta + sizeSigned.z / 2).scaled(1 / 32).floored()
|
||||
const xVec = entity.position.offset(entity.velocity.x * delta + sizeSigned.x / 2, 0, 0)
|
||||
const yVec = entity.position.offset(0, entity.velocity.y * delta + sizeSigned.y / 2, 0)
|
||||
const zVec = entity.position.offset(0, 0, entity.velocity.z * delta + sizeSigned.z / 2)
|
||||
|
||||
// Get block for each (x/y/z)Vec, check to avoid duplicate getBlockTypes
|
||||
const xBlock = blocks[await entity.world.getBlockType(xVec)].boundingBox === 'block'
|
||||
|
|
@ -33,14 +33,18 @@ module.exports.entity = function (entity, serv, {version}) {
|
|||
newPos.y += getMoveAmount('y', yBlock, entity, delta, sizeSigned.y)
|
||||
newPos.z += getMoveAmount('z', zBlock, entity, delta, sizeSigned.z)
|
||||
|
||||
// serv.emitParticle(30, serv.overworld, entity.position.scaled(1/32), { size: new Vec3(0, 0, 0) });
|
||||
// serv.emitParticle(30, serv.overworld, entity.position, { size: new Vec3(0, 0, 0) });
|
||||
return { position: newPos, onGround: yBlock }
|
||||
}
|
||||
|
||||
entity.sendVelocity = (vel, maxVel) => {
|
||||
const velocity = vel.scaled(32).floored() // Make fixed point
|
||||
const maxVelocity = maxVel.scaled(32).floored()
|
||||
const scaledVelocity = velocity.scaled(8000 / 32 / 20).floored() // from fixed-position/second to unit => 1/8000 blocks per tick
|
||||
const velocity = vel
|
||||
const maxVelocity = maxVel
|
||||
let scaledVelocity = velocity.scaled(8000 / 20) // from fixed-position/second to unit => 1/8000 blocks per tick
|
||||
if (serv.supportFeature('fixedPointPosition')) {
|
||||
scaledVelocity = scaledVelocity.scaled(1 / 32)
|
||||
}
|
||||
scaledVelocity = scaledVelocity.floored()
|
||||
entity._writeNearby('entity_velocity', {
|
||||
entityId: entity.id,
|
||||
velocityX: scaledVelocity.x,
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ module.exports.player = function (player, serv, {version}) {
|
|||
const pars = str.split(' ')
|
||||
if (pars.length !== 6) { return false }
|
||||
let [x, y, z, direction, width, height] = pars;
|
||||
[x, y, z] = [x, y, z].map((val, i) => serv.posFromString(val, player.position[['x', 'y', 'z'][i]] / 32))
|
||||
[x, y, z] = [x, y, z].map((val, i) => serv.posFromString(val, player.position[['x', 'y', 'z'][i]]))
|
||||
const bottomLeft = new Vec3(x, y, z)
|
||||
if (direction !== 'x' && direction !== 'z') { throw new UserError('Wrong Direction') }
|
||||
direction = direction === 'x' ? new Vec3(1, 0, 0) : new Vec3(0, 0, 1)
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ module.exports.player = function (player, serv) {
|
|||
module.exports.entity = function (entity, serv) {
|
||||
entity.takeDamage = ({sound = 'game.player.hurt', damage = 1, velocity = new Vec3(0, 0, 0), maxVelocity = new Vec3(4, 4, 4), animation = true}) => {
|
||||
entity.updateHealth(entity.health - damage)
|
||||
serv.playSound(sound, entity.world, entity.position.scaled(1 / 32))
|
||||
serv.playSound(sound, entity.world, entity.position)
|
||||
|
||||
entity.sendVelocity(velocity.scaled(1 / 32), maxVelocity)
|
||||
entity.sendVelocity(velocity, maxVelocity)
|
||||
|
||||
if (entity.health <= 0) {
|
||||
if (animation) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
const Vec3 = require('vec3').Vec3
|
||||
|
||||
module.exports.server = function (serv) {
|
||||
serv.playSound = (sound, world, position, {whitelist, blacklist = [], radius = 32 * 32, volume = 1.0, pitch = 1.0, soundCategory = 0} = {}) => {
|
||||
serv.playSound = (sound, world, position, {whitelist, blacklist = [], radius = 32, volume = 1.0, pitch = 1.0, soundCategory = 0} = {}) => {
|
||||
const players = (typeof whitelist !== 'undefined' ? (typeof whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({
|
||||
world: world,
|
||||
position: position.scaled(32).floored(),
|
||||
radius: radius // 32 blocks, fixed position
|
||||
position: position,
|
||||
radius: radius
|
||||
}))
|
||||
players.filter(player => blacklist.indexOf(player) === -1)
|
||||
.forEach(player => {
|
||||
const pos = (position || player.position.scaled(1 / 32)).scaled(8).floored()
|
||||
const iniPos = position ? position.scaled(1 / 32) : player.position.scaled(1 / 32)
|
||||
const pos = iniPos.scaled(8).floored()
|
||||
// only packet still in fixed position in all versions
|
||||
player._client.write('named_sound_effect', {
|
||||
soundName: sound,
|
||||
soundCategory,
|
||||
|
|
@ -100,13 +102,13 @@ module.exports.player = function (player, serv) {
|
|||
},
|
||||
action (action) {
|
||||
player.chat('Playing "' + action.sound_name + '" (volume: ' + action.volume + ', pitch: ' + action.pitch + ')')
|
||||
serv.playSound(action.sound_name, player.world, player.position.scaled(1 / 32), {volume: action.volume, pitch: action.pitch})
|
||||
serv.playSound(action.sound_name, player.world, player.position, {volume: action.volume, pitch: action.pitch})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.entity = function (entity, serv) {
|
||||
entity.playSoundAtSelf = (sound, opt = {}) => {
|
||||
serv.playSound(sound, entity.world, entity.position.scaled(1 / 32), opt)
|
||||
serv.playSound(sound, entity.world, entity.position, opt)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,16 +29,16 @@ module.exports.server = function (serv, options) {
|
|||
}
|
||||
|
||||
serv.spawnObject = (type, world, position, {pitch = 0, yaw = 0, velocity = new Vec3(0, 0, 0), data = 1, itemId, itemDamage = 0, pickupTime = undefined, deathTime = undefined}) => {
|
||||
const object = serv.initEntity('object', type, world, position.scaled(32).floored())
|
||||
const object = serv.initEntity('object', type, world, position)
|
||||
object.name = objectsById[type].name
|
||||
object.data = data
|
||||
object.velocity = velocity.scaled(32).floored()
|
||||
object.velocity = velocity
|
||||
object.pitch = pitch
|
||||
object.yaw = yaw
|
||||
object.gravity = new Vec3(0, -20 * 32, 0)
|
||||
object.terminalvelocity = new Vec3(27 * 32, 27 * 32, 27 * 32)
|
||||
object.friction = new Vec3(15 * 32, 0, 15 * 32)
|
||||
object.size = new Vec3(0.25 * 32, 0.25 * 32, 0.25 * 32) // Hardcoded, will be dependent on type!
|
||||
object.gravity = new Vec3(0, -20, 0)
|
||||
object.terminalvelocity = new Vec3(27, 27, 27)
|
||||
object.friction = new Vec3(15, 0, 15)
|
||||
object.size = new Vec3(0.25, 0.25, 0.25) // Hardcoded, will be dependent on type!
|
||||
object.deathTime = deathTime
|
||||
object.pickupTime = pickupTime
|
||||
object.itemId = itemId
|
||||
|
|
@ -48,15 +48,15 @@ module.exports.server = function (serv, options) {
|
|||
}
|
||||
|
||||
serv.spawnMob = (type, world, position, {pitch = 0, yaw = 0, headPitch = 0, velocity = new Vec3(0, 0, 0), metadata = []} = {}) => {
|
||||
const mob = serv.initEntity('mob', type, world, position.scaled(32).floored())
|
||||
const mob = serv.initEntity('mob', type, world, position)
|
||||
mob.name = mobsById[type].name
|
||||
mob.velocity = velocity.scaled(32).floored()
|
||||
mob.velocity = velocity
|
||||
mob.pitch = pitch
|
||||
mob.headPitch = headPitch
|
||||
mob.yaw = yaw
|
||||
mob.gravity = new Vec3(0, -20 * 32, 0)
|
||||
mob.terminalvelocity = new Vec3(27 * 32, 27 * 32, 27 * 32)
|
||||
mob.friction = new Vec3(15 * 32, 0, 15 * 32)
|
||||
mob.gravity = new Vec3(0, -20, 0)
|
||||
mob.terminalvelocity = new Vec3(27, 27, 27)
|
||||
mob.friction = new Vec3(15, 0, 15)
|
||||
mob.size = new Vec3(0.75, 1.75, 0.75)
|
||||
mob.health = 20
|
||||
mob.metadata = metadata
|
||||
|
|
@ -91,11 +91,11 @@ module.exports.player = function (player, serv, options) {
|
|||
return
|
||||
}
|
||||
if (entity.type === 'mob') {
|
||||
serv.spawnMob(entity.id, player.world, player.position.scaled(1 / 32), {
|
||||
serv.spawnMob(entity.id, player.world, player.position, {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
} else if (entity.type === 'object') {
|
||||
serv.spawnObject(entity.id, player.world, player.position.scaled(1 / 32), {
|
||||
serv.spawnObject(entity.id, player.world, player.position, {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
}
|
||||
|
|
@ -122,11 +122,11 @@ module.exports.player = function (player, serv, options) {
|
|||
let s = Math.floor(Math.sqrt(number))
|
||||
for (let i = 0; i < number; i++) {
|
||||
if (entity.type === 'mob') {
|
||||
serv.spawnMob(entity.id, player.world, player.position.scaled(1 / 32).offset(Math.floor(i / s * 10), 0, i % s * 10), {
|
||||
serv.spawnMob(entity.id, player.world, player.position.offset(Math.floor(i / s * 10), 0, i % s * 10), {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
} else if (entity.type === 'object') {
|
||||
serv.spawnObject(entity.id, player.world, player.position.scaled(1 / 32).offset(Math.floor(i / s * 10), 0, i % s * 10), {
|
||||
serv.spawnObject(entity.id, player.world, player.position.offset(Math.floor(i / s * 10), 0, i % s * 10), {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
}
|
||||
|
|
@ -150,11 +150,11 @@ module.exports.player = function (player, serv, options) {
|
|||
if (Object.keys(serv.entities).length > options['max-entities'] - entityTypes.length) { throw new UserError('Too many mobs !') }
|
||||
entityTypes.map(entity => {
|
||||
if (entity.type === 'mob') {
|
||||
serv.spawnMob(entity.id, player.world, player.position.scaled(1 / 32), {
|
||||
serv.spawnMob(entity.id, player.world, player.position, {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
} else if (entity.type === 'object') {
|
||||
serv.spawnObject(entity.id, player.world, player.position.scaled(1 / 32), {
|
||||
serv.spawnObject(entity.id, player.world, player.position, {
|
||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||
})
|
||||
}
|
||||
|
|
@ -234,14 +234,26 @@ module.exports.entity = function (entity, serv) {
|
|||
}
|
||||
|
||||
entity.getSpawnPacket = () => {
|
||||
const scaledVelocity = entity.velocity.scaled(8000 / 32 / 20).floored() // from fixed-position/second to unit => 1/8000 blocks per tick
|
||||
let scaledVelocity = entity.velocity.scaled(8000 / 20) // from fixed-position/second to unit => 1/8000 blocks per tick
|
||||
if (serv.supportFeature('fixedPointPosition')) {
|
||||
scaledVelocity = scaledVelocity.scaled(1 / 32)
|
||||
}
|
||||
scaledVelocity = scaledVelocity.floored()
|
||||
|
||||
let entityPosition
|
||||
if (serv.supportFeature('fixedPointPosition')) {
|
||||
entityPosition = entity.position.scaled(32).floored()
|
||||
} else if (serv.supportFeature('doublePosition')) {
|
||||
entityPosition = entity.position
|
||||
}
|
||||
|
||||
if (entity.type === 'player') {
|
||||
return {
|
||||
entityId: entity.id,
|
||||
playerUUID: entity._client.uuid,
|
||||
x: entity.position.x,
|
||||
y: entity.position.y,
|
||||
z: entity.position.z,
|
||||
x: entityPosition.x,
|
||||
y: entityPosition.y,
|
||||
z: entityPosition.z,
|
||||
yaw: entity.yaw,
|
||||
pitch: entity.pitch,
|
||||
currentItem: 0,
|
||||
|
|
@ -251,9 +263,9 @@ module.exports.entity = function (entity, serv) {
|
|||
return {
|
||||
entityId: entity.id,
|
||||
type: entity.entityType,
|
||||
x: entity.position.x,
|
||||
y: entity.position.y,
|
||||
z: entity.position.z,
|
||||
x: entityPosition.x,
|
||||
y: entityPosition.y,
|
||||
z: entityPosition.z,
|
||||
pitch: entity.pitch,
|
||||
yaw: entity.yaw,
|
||||
objectData: {
|
||||
|
|
@ -267,9 +279,9 @@ module.exports.entity = function (entity, serv) {
|
|||
return {
|
||||
entityId: entity.id,
|
||||
type: entity.entityType,
|
||||
x: entity.position.x,
|
||||
y: entity.position.y,
|
||||
z: entity.position.z,
|
||||
x: entityPosition.x,
|
||||
y: entityPosition.y,
|
||||
z: entityPosition.z,
|
||||
yaw: entity.yaw,
|
||||
pitch: entity.pitch,
|
||||
headPitch: entity.headPitch,
|
||||
|
|
@ -303,7 +315,7 @@ module.exports.entity = function (entity, serv) {
|
|||
}
|
||||
|
||||
entity.on('move', () => {
|
||||
if (entity.position.distanceTo(entity.lastPositionPlayersUpdated) > 2 * 32) { entity.updateAndSpawn() }
|
||||
if (entity.position.distanceTo(entity.lastPositionPlayersUpdated) > 2) { entity.updateAndSpawn() }
|
||||
})
|
||||
|
||||
entity.destroy = () => {
|
||||
|
|
|
|||
|
|
@ -18,20 +18,20 @@ module.exports.player = (player, serv) => {
|
|||
if (entityTo.length === 0) throw new UserError('Invalid target')
|
||||
entityTo = entityTo[0]
|
||||
|
||||
entitiesFrom.forEach(e => e.teleport(entityTo.position.scaled(1 / 32)))
|
||||
entitiesFrom.forEach(e => e.teleport(entityTo.position))
|
||||
} else if (args.length === 3) {
|
||||
let x = serv.posFromString(args[0], player.position.x / 32)
|
||||
let y = serv.posFromString(args[1], player.position.y / 32)
|
||||
let z = serv.posFromString(args[2], player.position.z / 32)
|
||||
let x = serv.posFromString(args[0], player.position.x)
|
||||
let y = serv.posFromString(args[1], player.position.y)
|
||||
let z = serv.posFromString(args[2], player.position.z)
|
||||
|
||||
player.teleport(new Vec3(x, y, z))
|
||||
} else if (args.length === 4) {
|
||||
let entitiesFrom = player.selectorString(args[0])
|
||||
|
||||
entitiesFrom.forEach(e => e.teleport(new Vec3(
|
||||
serv.posFromString(args[1], e.position.x / 32),
|
||||
serv.posFromString(args[2], e.position.y / 32),
|
||||
serv.posFromString(args[3], e.position.z / 32)
|
||||
serv.posFromString(args[1], e.position.x),
|
||||
serv.posFromString(args[2], e.position.y),
|
||||
serv.posFromString(args[3], e.position.z)
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
const Vec3 = require('vec3').Vec3
|
||||
|
||||
Vec3.prototype.toFixedPosition = function () {
|
||||
return this.scaled(32).floored()
|
||||
}
|
||||
|
||||
module.exports.player = function (player) {
|
||||
player._client.on('look', ({yaw, pitch, onGround} = {}) => sendLook(yaw, pitch, onGround))
|
||||
|
||||
|
|
@ -42,19 +38,20 @@ module.exports.player = function (player) {
|
|||
}
|
||||
|
||||
player._client.on('position', ({x, y, z, onGround} = {}) => {
|
||||
player.sendPosition((new Vec3(x, y, z)).toFixedPosition(), onGround)
|
||||
player.sendPosition((new Vec3(x, y, z)), onGround)
|
||||
})
|
||||
|
||||
player._client.on('position_look', ({x, y, z, onGround, yaw, pitch} = {}) => {
|
||||
player.sendPosition((new Vec3(x, y, z)).toFixedPosition(), onGround)
|
||||
player.sendPosition((new Vec3(x, y, z)), onGround)
|
||||
sendLook(yaw, pitch, onGround)
|
||||
})
|
||||
|
||||
player.sendSelfPosition = () => {
|
||||
// double position in all versions
|
||||
player._client.write('position', {
|
||||
x: player.position.x / 32,
|
||||
y: player.position.y / 32,
|
||||
z: player.position.z / 32,
|
||||
x: player.position.x,
|
||||
y: player.position.y,
|
||||
z: player.position.z,
|
||||
yaw: player.yaw,
|
||||
pitch: player.pitch,
|
||||
flags: 0x00
|
||||
|
|
@ -62,7 +59,7 @@ module.exports.player = function (player) {
|
|||
}
|
||||
|
||||
player.teleport = async (position) => {
|
||||
const notCancelled = await player.sendPosition(position.scaled(32).floored(), false, true)
|
||||
const notCancelled = await player.sendPosition(position, false, true)
|
||||
if (notCancelled) player.sendSelfPosition()
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +80,7 @@ module.exports.player = function (player) {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports.entity = function (entity) {
|
||||
module.exports.entity = function (entity, serv) {
|
||||
entity.sendPosition = (position, onGround, teleport = false) => {
|
||||
if (typeof position === 'undefined') throw new Error('undef')
|
||||
if (entity.position.equals(position) && entity.onGround === onGround) return Promise.resolve()
|
||||
|
|
@ -92,23 +89,45 @@ module.exports.entity = function (entity) {
|
|||
onGround: onGround,
|
||||
teleport: teleport
|
||||
}, ({position, onGround}) => {
|
||||
const diff = position.minus(entity.position)
|
||||
if (diff.abs().x > 127 || diff.abs().y > 127 || diff.abs().z > 127) {
|
||||
// known position is very important because the diff (/delta) send to players is floored hence is not precise enough
|
||||
// storing the known position allows to compensate next time a diff is sent
|
||||
// without the known position, the error accumulate fast and player position is incorrect from the point of view
|
||||
// of other players
|
||||
entity.knownPosition = entity.knownPosition === undefined ? entity.position : entity.knownPosition
|
||||
|
||||
const diff = position.minus(entity.knownPosition)
|
||||
if (diff.abs().x > 7 || diff.abs().y > 7 || diff.abs().z > 7) {
|
||||
let entityPosition
|
||||
|
||||
if (serv.supportFeature('fixedPointPosition')) {
|
||||
entityPosition = position.scaled(32).floored()
|
||||
} else if (serv.supportFeature('doublePosition')) {
|
||||
entityPosition = position
|
||||
}
|
||||
entity._writeOthersNearby('entity_teleport', {
|
||||
entityId: entity.id,
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
z: position.z,
|
||||
x: entityPosition.x,
|
||||
y: entityPosition.y,
|
||||
z: entityPosition.z,
|
||||
yaw: entity.yaw,
|
||||
pitch: entity.pitch,
|
||||
onGround: onGround
|
||||
})
|
||||
entity.knownPosition = position
|
||||
} else if (diff.distanceTo(new Vec3(0, 0, 0)) !== 0) {
|
||||
let delta
|
||||
if (serv.supportFeature('fixedPointDelta')) {
|
||||
delta = diff.scaled(32).floored()
|
||||
entity.knownPosition = entity.knownPosition.plus(delta.scaled(1 / 32))
|
||||
} else if (serv.supportFeature('fixedPointDelta128')) {
|
||||
delta = diff.scaled(32).scaled(128).floored()
|
||||
entity.knownPosition = entity.knownPosition.plus(delta.scaled(1 / 32 / 128))
|
||||
}
|
||||
entity._writeOthersNearby('rel_entity_move', {
|
||||
entityId: entity.id,
|
||||
dX: diff.x,
|
||||
dY: diff.y,
|
||||
dZ: diff.z,
|
||||
dX: delta.x,
|
||||
dY: delta.y,
|
||||
dZ: delta.z,
|
||||
onGround: onGround
|
||||
})
|
||||
}
|
||||
|
|
@ -121,6 +140,6 @@ module.exports.entity = function (entity) {
|
|||
}
|
||||
|
||||
entity.teleport = (pos) => { // Overwritten in players inject above
|
||||
entity.sendPosition(pos.scaled(32), false, true)
|
||||
entity.sendPosition(pos, false, true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ module.exports.player = function (player, serv, settings) {
|
|||
player.unloadChunk = (chunkX, chunkZ) => {
|
||||
delete player.loadedChunks[chunkX + ',' + chunkZ]
|
||||
|
||||
if (serv.majorVersion === '1.8') {
|
||||
if (serv.supportFeature('unloadChunkByEmptyChunk')) {
|
||||
player._client.write('map_chunk', {
|
||||
x: chunkX,
|
||||
z: chunkZ,
|
||||
|
|
@ -91,7 +91,7 @@ module.exports.player = function (player, serv, settings) {
|
|||
bitMap: 0x0000,
|
||||
chunkData: Buffer.alloc(0)
|
||||
})
|
||||
} else if (serv.majorVersion === '1.12') {
|
||||
} else if (serv.supportFeature('unloadChunkDirect')) {
|
||||
player._client.write('unload_chunk', {
|
||||
chunkX,
|
||||
chunkZ
|
||||
|
|
@ -127,8 +127,8 @@ module.exports.player = function (player, serv, settings) {
|
|||
|
||||
player.sendNearbyChunks = (view, group) => {
|
||||
player.lastPositionChunkUpdated = player.position
|
||||
const playerChunkX = Math.floor(player.position.x / 16 / 32)
|
||||
const playerChunkZ = Math.floor(player.position.z / 16 / 32)
|
||||
const playerChunkX = Math.floor(player.position.x / 16)
|
||||
const playerChunkZ = Math.floor(player.position.z / 16)
|
||||
|
||||
Object.keys(player.loadedChunks)
|
||||
.map((key) => key.split(',').map(a => parseInt(a)))
|
||||
|
|
@ -190,7 +190,7 @@ module.exports.player = function (player, serv, settings) {
|
|||
levelType: 'default'
|
||||
})
|
||||
await player.findSpawnPoint()
|
||||
player.position = player.spawnPoint.toFixedPosition()
|
||||
player.position = player.spawnPoint
|
||||
player.sendSpawnPosition()
|
||||
player.updateAndSpawn()
|
||||
|
||||
|
|
|
|||
4
src/lib/supportFeature.js
Normal file
4
src/lib/supportFeature.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
const features = require('./features')
|
||||
|
||||
module.exports = (feature, version) =>
|
||||
features.some(({name, versions}) => name === feature && versions.includes(version))
|
||||
Loading…
Reference in a new issue