mirror of
https://github.com/danbulant/flying-squid
synced 2026-07-05 19:20:54 +00:00
commit
a3631cfc19
32 changed files with 832 additions and 621 deletions
|
|
@ -2,6 +2,7 @@ version: 2
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
parallelism: 2
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:10
|
- image: circleci/node:10
|
||||||
steps:
|
steps:
|
||||||
|
|
|
||||||
|
|
@ -25,5 +25,5 @@
|
||||||
},
|
},
|
||||||
"everybody-op":true,
|
"everybody-op":true,
|
||||||
"max-entities":100,
|
"max-entities":100,
|
||||||
"version": "1.8.9"
|
"version": "1.12.2"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diamond-square": "1.0.0",
|
"diamond-square": "^1.1.0",
|
||||||
"emit-then": "^2.0.0",
|
"emit-then": "^2.0.0",
|
||||||
"event-promise": "^0.0.1",
|
"event-promise": "^0.0.1",
|
||||||
"flatmap": "^0.0.3",
|
"flatmap": "^0.0.3",
|
||||||
|
|
@ -32,18 +32,18 @@
|
||||||
"minecraft-protocol": "^1.5.2",
|
"minecraft-protocol": "^1.5.2",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"moment": "^2.10.6",
|
"moment": "^2.10.6",
|
||||||
"node-uuid": "^1.4.3",
|
|
||||||
"prismarine-chunk": "^1.9.0",
|
"prismarine-chunk": "^1.9.0",
|
||||||
"prismarine-entity": "^0.2.0",
|
"prismarine-entity": "^0.2.0",
|
||||||
"prismarine-item": "^1.0.1",
|
"prismarine-item": "^1.0.1",
|
||||||
"prismarine-provider-anvil": "^2.0.0",
|
"prismarine-provider-anvil": "^2.1.0",
|
||||||
"prismarine-windows": "^1.0.1",
|
"prismarine-windows": "^1.0.1",
|
||||||
"prismarine-world": "^2.0.0",
|
"prismarine-world": "^2.1.0",
|
||||||
"random-seed": "^0.3.0",
|
"random-seed": "^0.3.0",
|
||||||
"range": "^0.0.3",
|
"range": "^0.0.3",
|
||||||
"request": "^2.83.0",
|
"request": "^2.83.0",
|
||||||
"request-promise": "^4.1.0",
|
"request-promise": "^4.1.0",
|
||||||
"spiralloop": "^1.0.2",
|
"spiralloop": "^1.0.2",
|
||||||
|
"uuid-1345": "^0.99.6",
|
||||||
"vec3": "^0.1.3"
|
"vec3": "^0.1.3"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
12
src/index.js
12
src/index.js
|
|
@ -2,11 +2,14 @@ const mc = require('minecraft-protocol')
|
||||||
const EventEmitter = require('events').EventEmitter
|
const EventEmitter = require('events').EventEmitter
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const requireIndex = require('./lib/requireindex')
|
const requireIndex = require('./lib/requireindex')
|
||||||
|
const supportedVersions = require('./lib/version').supportedVersions
|
||||||
require('emit-then').register()
|
require('emit-then').register()
|
||||||
if (process.env.NODE_ENV === 'dev') {
|
if (process.env.NODE_ENV === 'dev') {
|
||||||
require('longjohn')
|
require('longjohn')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const supportFeature = require('./lib/supportFeature')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createMCServer: createMCServer,
|
createMCServer: createMCServer,
|
||||||
Behavior: require('./lib/behavior'),
|
Behavior: require('./lib/behavior'),
|
||||||
|
|
@ -14,7 +17,8 @@ module.exports = {
|
||||||
generations: require('./lib/generations'),
|
generations: require('./lib/generations'),
|
||||||
experience: require('./lib/experience'),
|
experience: require('./lib/experience'),
|
||||||
UserError: require('./lib/user_error'),
|
UserError: require('./lib/user_error'),
|
||||||
portal_detector: require('./lib/portal_detector')
|
portal_detector: require('./lib/portal_detector'),
|
||||||
|
supportedVersions
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMCServer (options) {
|
function createMCServer (options) {
|
||||||
|
|
@ -31,6 +35,12 @@ class MCServer extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
connect (options) {
|
connect (options) {
|
||||||
|
const version = require('minecraft-data')(options.version).version
|
||||||
|
if (supportedVersions.indexOf(version.majorVersion) === -1) {
|
||||||
|
throw new Error(`Version ${version.minecraftVersion} is not supported.`)
|
||||||
|
}
|
||||||
|
this.supportFeature = feature => supportFeature(feature, version.majorVersion)
|
||||||
|
|
||||||
const plugins = requireIndex(path.join(__dirname, 'lib', 'plugins'))
|
const plugins = requireIndex(path.join(__dirname, 'lib', 'plugins'))
|
||||||
this._server = mc.createServer(options)
|
this._server = mc.createServer(options)
|
||||||
Object.keys(plugins)
|
Object.keys(plugins)
|
||||||
|
|
|
||||||
62
src/lib/features.json
Normal file
62
src/lib/features.json
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "entityCamelCase",
|
||||||
|
"description": "entity names are in camel case",
|
||||||
|
"versions": ["1.8"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "entitySnakeCase",
|
||||||
|
"description": "entity name are in snake case",
|
||||||
|
"versions": ["1.12"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "respawnIsPayload",
|
||||||
|
"description": "respawn field is payload",
|
||||||
|
"versions": ["1.8"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "respawnIsActionId",
|
||||||
|
"description": "respawn field is action id",
|
||||||
|
"versions": ["1.12"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "attachStackEntity",
|
||||||
|
"description": "attach is used to stack entities",
|
||||||
|
"versions": ["1.8"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "setPassengerStackEntity",
|
||||||
|
"description": "set passengers is used to stack entities",
|
||||||
|
"versions": ["1.12"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -36,7 +36,7 @@ module.exports.player = function (player, serv) {
|
||||||
},
|
},
|
||||||
action (params) {
|
action (params) {
|
||||||
let res = params.slice(1, 4)
|
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)
|
player.setBlock(new Vec3(res[0], res[1], res[2]).floored(), params[4], params[5] || 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
module.exports.player = function (player) {
|
|
||||||
// WIP: Does't work
|
|
||||||
/* player._client.write('world_border', {
|
|
||||||
action: 3,
|
|
||||||
x: 0,
|
|
||||||
z: 0,
|
|
||||||
old_radius: 15,
|
|
||||||
new_radius: 15,
|
|
||||||
speed: 10000000,
|
|
||||||
portalBoundary: 15,
|
|
||||||
warning_time: 5,
|
|
||||||
warning_blocks: 15
|
|
||||||
});
|
|
||||||
player._client.write('world_border', {
|
|
||||||
action: 0,
|
|
||||||
radius: 15
|
|
||||||
}); */
|
|
||||||
}
|
|
||||||
|
|
@ -102,7 +102,7 @@ module.exports.player = function (player, serv, {version}) {
|
||||||
return str || false
|
return str || false
|
||||||
},
|
},
|
||||||
action (sel) {
|
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)))
|
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) {
|
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) {
|
module.exports.server = function (serv) {
|
||||||
|
|
@ -190,8 +190,8 @@ module.exports.server = function (serv) {
|
||||||
})
|
})
|
||||||
|
|
||||||
sample = sample.filter(s => {
|
sample = sample.filter(s => {
|
||||||
if ((notudf(opt.radius) && s.position.scaled(1 / 32).distanceTo(pos) > opt.radius) ||
|
if ((notudf(opt.radius) && s.position.distanceTo(pos) > opt.radius) ||
|
||||||
(notudf(opt.minRadius) && s.position.scaled(1 / 32).distanceTo(pos) < opt.minRadius) ||
|
(notudf(opt.minRadius) && s.position.distanceTo(pos) < opt.minRadius) ||
|
||||||
(notudf(opt.gameMode) && s.gameMode !== opt.gameMode) ||
|
(notudf(opt.gameMode) && s.gameMode !== opt.gameMode) ||
|
||||||
(notudf(opt.level) && s.level > opt.level) ||
|
(notudf(opt.level) && s.level > opt.level) ||
|
||||||
(notudf(opt.minLevel) && s.level < opt.minLevel) ||
|
(notudf(opt.minLevel) && s.level < opt.minLevel) ||
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ module.exports.server = function (serv) {
|
||||||
serv._writeNearby = (packetName, packetFields, loc) =>
|
serv._writeNearby = (packetName, packetFields, loc) =>
|
||||||
serv._writeArray(packetName, packetFields, serv.getNearby(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.world === world &&
|
||||||
player.position.distanceTo(position) <= radius
|
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])
|
.map(eId => serv.entities[eId])
|
||||||
.filter(entity =>
|
.filter(entity =>
|
||||||
entity.world === world &&
|
entity.world === world &&
|
||||||
|
|
@ -26,7 +26,7 @@ module.exports.entity = function (entity, serv) {
|
||||||
.getNearbyEntities({
|
.getNearbyEntities({
|
||||||
world: entity.world,
|
world: entity.world,
|
||||||
position: entity.position,
|
position: entity.position,
|
||||||
radius: entity.viewDistance * 32
|
radius: entity.viewDistance
|
||||||
})
|
})
|
||||||
.filter((e) => e !== entity)
|
.filter((e) => e !== entity)
|
||||||
|
|
||||||
|
|
@ -34,10 +34,10 @@ module.exports.entity = function (entity, serv) {
|
||||||
|
|
||||||
entity.getOthers = () => serv.entities.filter((e) => e !== entity)
|
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')
|
.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')
|
.filter(e => e.type === 'player')
|
||||||
|
|
||||||
entity._writeOthers = (packetName, packetFields) =>
|
entity._writeOthers = (packetName, packetFields) =>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ module.exports.server = function (serv) {
|
||||||
const players = serv.getNearby({
|
const players = serv.getNearby({
|
||||||
world: entity.world,
|
world: entity.world,
|
||||||
position: entity.position,
|
position: entity.position,
|
||||||
radius: 1.5 * 32 // Seems good for now
|
radius: 1.5 // Seems good for now
|
||||||
})
|
})
|
||||||
if (players.length) {
|
if (players.length) {
|
||||||
players[0].collect(entity)
|
players[0].collect(entity)
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,10 @@ module.exports.player = function (player, serv, settings) {
|
||||||
player.crouching = false // Needs added in prismarine-entity later
|
player.crouching = false // Needs added in prismarine-entity later
|
||||||
player.op = settings['everybody-op'] // REMOVE THIS WHEN OUT OF TESTING
|
player.op = settings['everybody-op'] // REMOVE THIS WHEN OUT OF TESTING
|
||||||
player.username = player._client.username
|
player.username = player._client.username
|
||||||
|
player.uuid = player._client.uuid
|
||||||
serv.players.push(player)
|
serv.players.push(player)
|
||||||
serv.uuidToPlayer[player._client.uuid] = player
|
serv.uuidToPlayer[player.uuid] = player
|
||||||
player.heldItemSlot = 36
|
player.heldItemSlot = 0
|
||||||
player.loadedChunks = {}
|
player.loadedChunks = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,12 +56,12 @@ module.exports.player = function (player, serv, settings) {
|
||||||
reducedDebugInfo: false,
|
reducedDebugInfo: false,
|
||||||
maxPlayers: serv._server.maxPlayers
|
maxPlayers: serv._server.maxPlayers
|
||||||
})
|
})
|
||||||
player.position = player.spawnPoint.toFixedPosition()
|
player.position = player.spawnPoint.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendChunkWhenMove () {
|
function sendChunkWhenMove () {
|
||||||
player.on('move', () => {
|
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() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ module.exports.player = function (player, serv, settings) {
|
||||||
serv._writeAll('player_info', {
|
serv._writeAll('player_info', {
|
||||||
action: 1,
|
action: 1,
|
||||||
data: [{
|
data: [{
|
||||||
UUID: player._client.uuid,
|
UUID: player.uuid,
|
||||||
gamemode: player.gameMode
|
gamemode: player.gameMode
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
@ -91,7 +92,7 @@ module.exports.player = function (player, serv, settings) {
|
||||||
player._writeOthers('player_info', {
|
player._writeOthers('player_info', {
|
||||||
action: 0,
|
action: 0,
|
||||||
data: [{
|
data: [{
|
||||||
UUID: player._client.uuid,
|
UUID: player.uuid,
|
||||||
name: player.username,
|
name: player.username,
|
||||||
properties: player.profileProperties,
|
properties: player.profileProperties,
|
||||||
gamemode: player.gameMode,
|
gamemode: player.gameMode,
|
||||||
|
|
@ -102,7 +103,7 @@ module.exports.player = function (player, serv, settings) {
|
||||||
player._client.write('player_info', {
|
player._client.write('player_info', {
|
||||||
action: 0,
|
action: 0,
|
||||||
data: serv.players.map((otherPlayer) => ({
|
data: serv.players.map((otherPlayer) => ({
|
||||||
UUID: otherPlayer._client.uuid,
|
UUID: otherPlayer.uuid,
|
||||||
name: otherPlayer.username,
|
name: otherPlayer.username,
|
||||||
properties: otherPlayer.profileProperties,
|
properties: otherPlayer.profileProperties,
|
||||||
gamemode: otherPlayer.gameMode,
|
gamemode: otherPlayer.gameMode,
|
||||||
|
|
@ -112,7 +113,7 @@ module.exports.player = function (player, serv, settings) {
|
||||||
setInterval(() => player._client.write('player_info', {
|
setInterval(() => player._client.write('player_info', {
|
||||||
action: 2,
|
action: 2,
|
||||||
data: serv.players.map(otherPlayer => ({
|
data: serv.players.map(otherPlayer => ({
|
||||||
UUID: otherPlayer._client.uuid,
|
UUID: otherPlayer.uuid,
|
||||||
ping: otherPlayer._client.latency
|
ping: otherPlayer._client.latency
|
||||||
}))
|
}))
|
||||||
}), 5000)
|
}), 5000)
|
||||||
|
|
@ -135,12 +136,12 @@ module.exports.player = function (player, serv, settings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
player.login = async () => {
|
player.login = async () => {
|
||||||
if (serv.uuidToPlayer[player._client.uuid]) {
|
if (serv.uuidToPlayer[player.uuid]) {
|
||||||
player.kick('You are already connected')
|
player.kick('You are already connected')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (serv.bannedPlayers[player._client.uuid]) {
|
if (serv.bannedPlayers[player.uuid]) {
|
||||||
player.kick(serv.bannedPlayers[player._client.uuid].reason)
|
player.kick(serv.bannedPlayers[player.uuid].reason)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (serv.bannedIPs[player._client.socket.remoteAddress]) {
|
if (serv.bannedIPs[player._client.socket.remoteAddress]) {
|
||||||
|
|
@ -151,11 +152,11 @@ module.exports.player = function (player, serv, settings) {
|
||||||
addPlayer()
|
addPlayer()
|
||||||
await player.findSpawnPoint()
|
await player.findSpawnPoint()
|
||||||
sendLogin()
|
sendLogin()
|
||||||
await player.sendMap()
|
|
||||||
player.sendSpawnPosition()
|
player.sendSpawnPosition()
|
||||||
player.sendSelfPosition()
|
player.sendSelfPosition()
|
||||||
player.updateHealth(player.health)
|
|
||||||
player.sendAbilities()
|
player.sendAbilities()
|
||||||
|
await player.sendMap()
|
||||||
|
player.updateHealth(player.health)
|
||||||
|
|
||||||
updateTime()
|
updateTime()
|
||||||
fillTabList()
|
fillTabList()
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ module.exports.player = function (player, serv) {
|
||||||
player._writeOthers('player_info', {
|
player._writeOthers('player_info', {
|
||||||
action: 4,
|
action: 4,
|
||||||
data: [{
|
data: [{
|
||||||
UUID: player._client.uuid
|
UUID: player.uuid
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
player.nearbyPlayers().forEach(otherPlayer => otherPlayer.despawnEntities([player]))
|
player.nearbyPlayers().forEach(otherPlayer => otherPlayer.despawnEntities([player]))
|
||||||
|
|
@ -32,7 +32,7 @@ module.exports.player = function (player, serv) {
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
serv.players.splice(index, 1)
|
serv.players.splice(index, 1)
|
||||||
}
|
}
|
||||||
delete serv.uuidToPlayer[player._client.uuid]
|
delete serv.uuidToPlayer[player.uuid]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const rp = require('request-promise')
|
const rp = require('request-promise')
|
||||||
const nodeUuid = require('node-uuid')
|
const UUID = require('uuid-1345')
|
||||||
|
|
||||||
module.exports.server = function (serv) {
|
module.exports.server = function (serv) {
|
||||||
serv.ban = (uuid, reason) => {
|
serv.ban = (uuid, reason) => {
|
||||||
|
|
@ -20,7 +20,7 @@ module.exports.server = function (serv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function uuidInParts (plainUUID) {
|
function uuidInParts (plainUUID) {
|
||||||
return nodeUuid.unparse(nodeUuid.parse(plainUUID))
|
return UUID.stringify(UUID.parse(plainUUID))
|
||||||
}
|
}
|
||||||
|
|
||||||
serv.getUUIDFromUsername = username => {
|
serv.getUUIDFromUsername = username => {
|
||||||
|
|
@ -65,7 +65,7 @@ module.exports.player = function (player, serv) {
|
||||||
player.ban = reason => {
|
player.ban = reason => {
|
||||||
reason = reason || 'You were banned!'
|
reason = reason || 'You were banned!'
|
||||||
player.kick(reason)
|
player.kick(reason)
|
||||||
const uuid = player._client.uuid
|
const uuid = player.uuid
|
||||||
serv.ban(uuid, reason)
|
serv.ban(uuid, reason)
|
||||||
}
|
}
|
||||||
player.banIP = reason => {
|
player.banIP = reason => {
|
||||||
|
|
@ -74,7 +74,7 @@ module.exports.player = function (player, serv) {
|
||||||
serv.banIP(player._client.socket.remoteAddress)
|
serv.banIP(player._client.socket.remoteAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
player.pardon = () => serv.pardon(player._client.uuid)
|
player.pardon = () => serv.pardon(player.uuid)
|
||||||
|
|
||||||
player.commands.add({
|
player.commands.add({
|
||||||
base: 'kick',
|
base: 'kick',
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
const Vec3 = require('vec3').Vec3
|
const Vec3 = require('vec3').Vec3
|
||||||
|
|
||||||
module.exports.server = function (serv) {
|
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({
|
const players = (typeof whitelist !== 'undefined' ? (whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({
|
||||||
world: world,
|
world: world,
|
||||||
position: position.scaled(32).floored(),
|
position: position,
|
||||||
radius: radius // 32 blocks, fixed position
|
radius: radius
|
||||||
}))
|
}))
|
||||||
|
|
||||||
serv._writeArray('world_particles', {
|
serv._writeArray('world_particles', {
|
||||||
|
|
@ -45,7 +45,7 @@ module.exports.player = function (player, serv) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
player.chat('Emitting "' + particle + '" (count: ' + amount + ', size: ' + size.toString() + ')')
|
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 vSign = getSign(entity.velocity)
|
||||||
const sizeSigned = new Vec3(vSign.x * entity.size.x, vSign.y * entity.size.y, vSign.z * entity.size.z)
|
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 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).scaled(1 / 32).floored()
|
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).scaled(1 / 32).floored()
|
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
|
// Get block for each (x/y/z)Vec, check to avoid duplicate getBlockTypes
|
||||||
const xBlock = blocks[await entity.world.getBlockType(xVec)].boundingBox === 'block'
|
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.y += getMoveAmount('y', yBlock, entity, delta, sizeSigned.y)
|
||||||
newPos.z += getMoveAmount('z', zBlock, entity, delta, sizeSigned.z)
|
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 }
|
return { position: newPos, onGround: yBlock }
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.sendVelocity = (vel, maxVel) => {
|
entity.sendVelocity = (vel, maxVel) => {
|
||||||
const velocity = vel.scaled(32).floored() // Make fixed point
|
const velocity = vel
|
||||||
const maxVelocity = maxVel.scaled(32).floored()
|
const maxVelocity = maxVel
|
||||||
const scaledVelocity = velocity.scaled(8000 / 32 / 20).floored() // from fixed-position/second to unit => 1/8000 blocks per tick
|
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', {
|
entity._writeNearby('entity_velocity', {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
velocityX: scaledVelocity.x,
|
velocityX: scaledVelocity.x,
|
||||||
|
|
@ -56,9 +60,9 @@ module.exports.entity = function (entity, serv, {version}) {
|
||||||
function getMoveAmount (dir, block, entity, delta, sizeSigned) {
|
function getMoveAmount (dir, block, entity, delta, sizeSigned) {
|
||||||
if (block) {
|
if (block) {
|
||||||
entity.velocity[dir] = 0
|
entity.velocity[dir] = 0
|
||||||
return Math.floor(-1 * (entity.position[dir] + sizeSigned / 2 - floorInDirection(entity.position[dir], -sizeSigned)))
|
return -1 * (entity.position[dir] + sizeSigned / 2 - entity.position[dir])
|
||||||
} else {
|
} else {
|
||||||
return Math.floor(entity.velocity[dir] * delta)
|
return entity.velocity[dir] * delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,10 +70,6 @@ module.exports.entity = function (entity, serv, {version}) {
|
||||||
return new Vec3(Math.sign(vec.x), Math.sign(vec.y), Math.sign(vec.z))
|
return new Vec3(Math.sign(vec.x), Math.sign(vec.y), Math.sign(vec.z))
|
||||||
}
|
}
|
||||||
|
|
||||||
function floorInDirection (a, b) {
|
|
||||||
return b < 0 ? Math.floor(a) : Math.ceil(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
function addGravity (entity, dir, delta) {
|
function addGravity (entity, dir, delta) {
|
||||||
if (entity.velocity[dir] < entity.terminalvelocity[dir] && entity.velocity[dir] > -entity.terminalvelocity[dir]) {
|
if (entity.velocity[dir] < entity.terminalvelocity[dir] && entity.velocity[dir] > -entity.terminalvelocity[dir]) {
|
||||||
entity.velocity[dir] = clamp(-entity.terminalvelocity[dir], entity.velocity[dir] + entity.gravity[dir] * delta, entity.terminalvelocity[dir])
|
entity.velocity[dir] = clamp(-entity.terminalvelocity[dir], entity.velocity[dir] + entity.gravity[dir] * delta, entity.terminalvelocity[dir])
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,21 @@ const materialToSound = {
|
||||||
module.exports.player = function (player, serv, {version}) {
|
module.exports.player = function (player, serv, {version}) {
|
||||||
const blocks = require('minecraft-data')(version).blocks
|
const blocks = require('minecraft-data')(version).blocks
|
||||||
|
|
||||||
player._client.on('block_place', ({direction, heldItem, location} = {}) => {
|
player._client.on('block_place', ({direction, location} = {}) => {
|
||||||
if (direction === -1 || heldItem.blockId === -1 || !blocks[heldItem.blockId]) return
|
const heldItem = player.inventory.slots[36 + player.heldItemSlot]
|
||||||
|
if (direction === -1 || heldItem.type === -1 || !blocks[heldItem.type]) return
|
||||||
const referencePosition = new Vec3(location.x, location.y, location.z)
|
const referencePosition = new Vec3(location.x, location.y, location.z)
|
||||||
const directionVector = directionToVector[direction]
|
const directionVector = directionToVector[direction]
|
||||||
const placedPosition = referencePosition.plus(directionVector)
|
const placedPosition = referencePosition.plus(directionVector)
|
||||||
player.behavior('placeBlock', {
|
player.behavior('placeBlock', {
|
||||||
direction: directionVector,
|
direction: directionVector,
|
||||||
heldItem: heldItem,
|
heldItem: heldItem,
|
||||||
id: heldItem.blockId,
|
id: heldItem.type,
|
||||||
damage: heldItem.itemDamage,
|
damage: heldItem.metadata,
|
||||||
position: placedPosition,
|
position: placedPosition,
|
||||||
reference: referencePosition,
|
reference: referencePosition,
|
||||||
playSound: true,
|
playSound: true,
|
||||||
sound: 'dig.' + (materialToSound[blocks[heldItem.blockId].material] || 'stone')
|
sound: 'dig.' + (materialToSound[blocks[heldItem.type].material] || 'stone')
|
||||||
}, ({direction, heldItem, position, playSound, sound, id, damage}) => {
|
}, ({direction, heldItem, position, playSound, sound, id, damage}) => {
|
||||||
if (playSound) {
|
if (playSound) {
|
||||||
serv.playSound(sound, player.world, placedPosition.clone().add(new Vec3(0.5, 0.5, 0.5)), {
|
serv.playSound(sound, player.world, placedPosition.clone().add(new Vec3(0.5, 0.5, 0.5)), {
|
||||||
|
|
@ -34,9 +35,9 @@ module.exports.player = function (player, serv, {version}) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
player.inventory.slots[36 + player.heldItemSlot]--
|
if (player.gameMode === 0) { player.inventory.slots[36 + player.heldItemSlot]-- }
|
||||||
|
|
||||||
if (heldItem.blockId !== 323) {
|
if (heldItem.type !== 323) {
|
||||||
player.changeBlock(position, id, damage)
|
player.changeBlock(position, id, damage)
|
||||||
} else if (direction === 1) {
|
} else if (direction === 1) {
|
||||||
player.setBlock(position, 63, 0)
|
player.setBlock(position, 63, 0)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ module.exports.player = function (player, serv, {version}) {
|
||||||
const pars = str.split(' ')
|
const pars = str.split(' ')
|
||||||
if (pars.length !== 6) { return false }
|
if (pars.length !== 6) { return false }
|
||||||
let [x, y, z, direction, width, height] = pars;
|
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)
|
const bottomLeft = new Vec3(x, y, z)
|
||||||
if (direction !== 'x' && direction !== 'z') { throw new UserError('Wrong Direction') }
|
if (direction !== 'x' && direction !== 'z') { throw new UserError('Wrong Direction') }
|
||||||
direction = direction === 'x' ? new Vec3(1, 0, 0) : new Vec3(0, 0, 1)
|
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) {
|
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.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)
|
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 (entity.health <= 0) {
|
||||||
if (animation) {
|
if (animation) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
module.exports.player = function (player, serv) {
|
module.exports.player = function (player, serv) {
|
||||||
player._client.on('client_command', ({payload}) => {
|
player._client.on('client_command', (data) => {
|
||||||
if (payload === 0) {
|
let actionId
|
||||||
|
|
||||||
|
if (serv.supportFeature('respawnIsPayload')) {
|
||||||
|
actionId = data['payload']
|
||||||
|
} else if (serv.supportFeature('respawnIsActionId')) {
|
||||||
|
actionId = data['actionId']
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionId === 0) {
|
||||||
player.behavior('requestRespawn', {}, () => {
|
player.behavior('requestRespawn', {}, () => {
|
||||||
player._client.write('respawn', {
|
player._client.write('respawn', {
|
||||||
dimension: 0,
|
dimension: 0,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
const Vec3 = require('vec3').Vec3
|
const Vec3 = require('vec3').Vec3
|
||||||
|
|
||||||
module.exports.server = function (serv) {
|
module.exports.server = function (serv) {
|
||||||
serv.playSound = (sound, world, position, {whitelist, blacklist = [], radius = 32 * 32, volume = 1.0, pitch = 1.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({
|
const players = (typeof whitelist !== 'undefined' ? (typeof whitelist instanceof Array ? whitelist : [whitelist]) : serv.getNearby({
|
||||||
world: world,
|
world: world,
|
||||||
position: position.scaled(32).floored(),
|
position: position,
|
||||||
radius: radius // 32 blocks, fixed position
|
radius: radius
|
||||||
}))
|
}))
|
||||||
players.filter(player => blacklist.indexOf(player) === -1)
|
players.filter(player => blacklist.indexOf(player) === -1)
|
||||||
.forEach(player => {
|
.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', {
|
player._client.write('named_sound_effect', {
|
||||||
soundName: sound,
|
soundName: sound,
|
||||||
|
soundCategory,
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
y: pos.y,
|
y: pos.y,
|
||||||
z: pos.z,
|
z: pos.z,
|
||||||
|
|
@ -99,13 +102,13 @@ module.exports.player = function (player, serv) {
|
||||||
},
|
},
|
||||||
action (action) {
|
action (action) {
|
||||||
player.chat('Playing "' + action.sound_name + '" (volume: ' + action.volume + ', pitch: ' + action.pitch + ')')
|
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) {
|
module.exports.entity = function (entity, serv) {
|
||||||
entity.playSoundAtSelf = (sound, opt = {}) => {
|
entity.playSoundAtSelf = (sound, opt = {}) => {
|
||||||
serv.playSound(sound, entity.world, entity.position.scaled(1 / 32), opt)
|
serv.playSound(sound, entity.world, entity.position, opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const path = require('path')
|
||||||
const requireIndex = require('../requireindex')
|
const requireIndex = require('../requireindex')
|
||||||
const plugins = requireIndex(path.join(__dirname, '..', 'plugins'))
|
const plugins = requireIndex(path.join(__dirname, '..', 'plugins'))
|
||||||
const UserError = require('flying-squid').UserError
|
const UserError = require('flying-squid').UserError
|
||||||
|
const UUID = require('uuid-1345')
|
||||||
const Vec3 = require('vec3').Vec3
|
const Vec3 = require('vec3').Vec3
|
||||||
|
|
||||||
module.exports.server = function (serv, options) {
|
module.exports.server = function (serv, options) {
|
||||||
|
|
@ -29,16 +29,17 @@ 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}) => {
|
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.uuid = UUID.v4()
|
||||||
object.name = objectsById[type].name
|
object.name = objectsById[type].name
|
||||||
object.data = data
|
object.data = data
|
||||||
object.velocity = velocity.scaled(32).floored()
|
object.velocity = velocity
|
||||||
object.pitch = pitch
|
object.pitch = pitch
|
||||||
object.yaw = yaw
|
object.yaw = yaw
|
||||||
object.gravity = new Vec3(0, -20 * 32, 0)
|
object.gravity = new Vec3(0, -20, 0)
|
||||||
object.terminalvelocity = new Vec3(27 * 32, 27 * 32, 27 * 32)
|
object.terminalvelocity = new Vec3(27, 27, 27)
|
||||||
object.friction = new Vec3(15 * 32, 0, 15 * 32)
|
object.friction = new Vec3(15, 0, 15)
|
||||||
object.size = new Vec3(0.25 * 32, 0.25 * 32, 0.25 * 32) // Hardcoded, will be dependent on type!
|
object.size = new Vec3(0.25, 0.25, 0.25) // Hardcoded, will be dependent on type!
|
||||||
object.deathTime = deathTime
|
object.deathTime = deathTime
|
||||||
object.pickupTime = pickupTime
|
object.pickupTime = pickupTime
|
||||||
object.itemId = itemId
|
object.itemId = itemId
|
||||||
|
|
@ -48,15 +49,16 @@ module.exports.server = function (serv, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
serv.spawnMob = (type, world, position, {pitch = 0, yaw = 0, headPitch = 0, velocity = new Vec3(0, 0, 0), metadata = []} = {}) => {
|
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.uuid = UUID.v4()
|
||||||
mob.name = mobsById[type].name
|
mob.name = mobsById[type].name
|
||||||
mob.velocity = velocity.scaled(32).floored()
|
mob.velocity = velocity
|
||||||
mob.pitch = pitch
|
mob.pitch = pitch
|
||||||
mob.headPitch = headPitch
|
mob.headPitch = headPitch
|
||||||
mob.yaw = yaw
|
mob.yaw = yaw
|
||||||
mob.gravity = new Vec3(0, -20 * 32, 0)
|
mob.gravity = new Vec3(0, -20, 0)
|
||||||
mob.terminalvelocity = new Vec3(27 * 32, 27 * 32, 27 * 32)
|
mob.terminalvelocity = new Vec3(27, 27, 27)
|
||||||
mob.friction = new Vec3(15 * 32, 0, 15 * 32)
|
mob.friction = new Vec3(15, 0, 15)
|
||||||
mob.size = new Vec3(0.75, 1.75, 0.75)
|
mob.size = new Vec3(0.75, 1.75, 0.75)
|
||||||
mob.health = 20
|
mob.health = 20
|
||||||
mob.metadata = metadata
|
mob.metadata = metadata
|
||||||
|
|
@ -91,11 +93,11 @@ module.exports.player = function (player, serv, options) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (entity.type === 'mob') {
|
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)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
} else if (entity.type === 'object') {
|
} 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)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -122,11 +124,11 @@ module.exports.player = function (player, serv, options) {
|
||||||
let s = Math.floor(Math.sqrt(number))
|
let s = Math.floor(Math.sqrt(number))
|
||||||
for (let i = 0; i < number; i++) {
|
for (let i = 0; i < number; i++) {
|
||||||
if (entity.type === 'mob') {
|
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)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
} else if (entity.type === 'object') {
|
} 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)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -150,11 +152,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 !') }
|
if (Object.keys(serv.entities).length > options['max-entities'] - entityTypes.length) { throw new UserError('Too many mobs !') }
|
||||||
entityTypes.map(entity => {
|
entityTypes.map(entity => {
|
||||||
if (entity.type === 'mob') {
|
if (entity.type === 'mob') {
|
||||||
serv.spawnMob(entity.id, player.world, player.position.scaled(1 / 32), {
|
return serv.spawnMob(entity.id, player.world, player.position, {
|
||||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
} else if (entity.type === 'object') {
|
} else if (entity.type === 'object') {
|
||||||
serv.spawnObject(entity.id, player.world, player.position.scaled(1 / 32), {
|
return serv.spawnObject(entity.id, player.world, player.position, {
|
||||||
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random() * 10 + 10, (Math.random() - 0.5) * 10)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -234,14 +236,26 @@ module.exports.entity = function (entity, serv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.getSpawnPacket = () => {
|
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') {
|
if (entity.type === 'player') {
|
||||||
return {
|
return {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
playerUUID: entity._client.uuid,
|
playerUUID: entity.uuid,
|
||||||
x: entity.position.x,
|
x: entityPosition.x,
|
||||||
y: entity.position.y,
|
y: entityPosition.y,
|
||||||
z: entity.position.z,
|
z: entityPosition.z,
|
||||||
yaw: entity.yaw,
|
yaw: entity.yaw,
|
||||||
pitch: entity.pitch,
|
pitch: entity.pitch,
|
||||||
currentItem: 0,
|
currentItem: 0,
|
||||||
|
|
@ -250,10 +264,11 @@ module.exports.entity = function (entity, serv) {
|
||||||
} else if (entity.type === 'object') {
|
} else if (entity.type === 'object') {
|
||||||
return {
|
return {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
|
objectUUID: entity.uuid,
|
||||||
type: entity.entityType,
|
type: entity.entityType,
|
||||||
x: entity.position.x,
|
x: entityPosition.x,
|
||||||
y: entity.position.y,
|
y: entityPosition.y,
|
||||||
z: entity.position.z,
|
z: entityPosition.z,
|
||||||
pitch: entity.pitch,
|
pitch: entity.pitch,
|
||||||
yaw: entity.yaw,
|
yaw: entity.yaw,
|
||||||
objectData: {
|
objectData: {
|
||||||
|
|
@ -266,10 +281,11 @@ module.exports.entity = function (entity, serv) {
|
||||||
} else if (entity.type === 'mob') {
|
} else if (entity.type === 'mob') {
|
||||||
return {
|
return {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
|
entityUUID: entity.uuid,
|
||||||
type: entity.entityType,
|
type: entity.entityType,
|
||||||
x: entity.position.x,
|
x: entityPosition.x,
|
||||||
y: entity.position.y,
|
y: entityPosition.y,
|
||||||
z: entity.position.z,
|
z: entityPosition.z,
|
||||||
yaw: entity.yaw,
|
yaw: entity.yaw,
|
||||||
pitch: entity.pitch,
|
pitch: entity.pitch,
|
||||||
headPitch: entity.headPitch,
|
headPitch: entity.headPitch,
|
||||||
|
|
@ -303,7 +319,7 @@ module.exports.entity = function (entity, serv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.on('move', () => {
|
entity.on('move', () => {
|
||||||
if (entity.position.distanceTo(entity.lastPositionPlayersUpdated) > 2 * 32) { entity.updateAndSpawn() }
|
if (entity.position.distanceTo(entity.lastPositionPlayersUpdated) > 2) { entity.updateAndSpawn() }
|
||||||
})
|
})
|
||||||
|
|
||||||
entity.destroy = () => {
|
entity.destroy = () => {
|
||||||
|
|
@ -311,12 +327,22 @@ module.exports.entity = function (entity, serv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.attach = (attachedEntity, leash = false) => {
|
entity.attach = (attachedEntity, leash = false) => {
|
||||||
const p = {
|
if (serv.supportFeature('attachStackEntity') || (serv.supportFeature('setPassengerStackEntity') && leash)) {
|
||||||
entityId: attachedEntity.id,
|
const p = {
|
||||||
vehicleId: entity.id,
|
entityId: attachedEntity.id,
|
||||||
leash: leash
|
vehicleId: entity.id,
|
||||||
|
leash: leash
|
||||||
|
}
|
||||||
|
if (entity.type === 'player') { entity._client.write('attach_entity', p) }
|
||||||
|
entity._writeOthersNearby('attach_entity', p)
|
||||||
|
}
|
||||||
|
if (serv.supportFeature('setPassengerStackEntity')) {
|
||||||
|
const p = {
|
||||||
|
entityId: entity.id,
|
||||||
|
passengers: [ attachedEntity.id ]
|
||||||
|
}
|
||||||
|
if (entity.type === 'player') { entity._client.write('set_passengers', p) }
|
||||||
|
entity._writeOthersNearby('set_passengers', p)
|
||||||
}
|
}
|
||||||
if (entity.type === 'player') { entity._client.write('attach_entity', p) }
|
|
||||||
entity._writeOthersNearby('attach_entity', p)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,20 +18,20 @@ module.exports.player = (player, serv) => {
|
||||||
if (entityTo.length === 0) throw new UserError('Invalid target')
|
if (entityTo.length === 0) throw new UserError('Invalid target')
|
||||||
entityTo = entityTo[0]
|
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) {
|
} else if (args.length === 3) {
|
||||||
let x = serv.posFromString(args[0], player.position.x / 32)
|
let x = serv.posFromString(args[0], player.position.x)
|
||||||
let y = serv.posFromString(args[1], player.position.y / 32)
|
let y = serv.posFromString(args[1], player.position.y)
|
||||||
let z = serv.posFromString(args[2], player.position.z / 32)
|
let z = serv.posFromString(args[2], player.position.z)
|
||||||
|
|
||||||
player.teleport(new Vec3(x, y, z))
|
player.teleport(new Vec3(x, y, z))
|
||||||
} else if (args.length === 4) {
|
} else if (args.length === 4) {
|
||||||
let entitiesFrom = player.selectorString(args[0])
|
let entitiesFrom = player.selectorString(args[0])
|
||||||
|
|
||||||
entitiesFrom.forEach(e => e.teleport(new Vec3(
|
entitiesFrom.forEach(e => e.teleport(new Vec3(
|
||||||
serv.posFromString(args[1], e.position.x / 32),
|
serv.posFromString(args[1], e.position.x),
|
||||||
serv.posFromString(args[2], e.position.y / 32),
|
serv.posFromString(args[2], e.position.y),
|
||||||
serv.posFromString(args[3], e.position.z / 32)
|
serv.posFromString(args[3], e.position.z)
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
const Vec3 = require('vec3').Vec3
|
const Vec3 = require('vec3').Vec3
|
||||||
|
|
||||||
Vec3.prototype.toFixedPosition = function () {
|
|
||||||
return this.scaled(32).floored()
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.player = function (player) {
|
module.exports.player = function (player) {
|
||||||
player._client.on('look', ({yaw, pitch, onGround} = {}) => sendLook(yaw, pitch, onGround))
|
player._client.on('look', ({yaw, pitch, onGround} = {}) => sendLook(yaw, pitch, onGround))
|
||||||
|
|
||||||
|
|
@ -42,27 +38,29 @@ module.exports.player = function (player) {
|
||||||
}
|
}
|
||||||
|
|
||||||
player._client.on('position', ({x, y, z, onGround} = {}) => {
|
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._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)
|
sendLook(yaw, pitch, onGround)
|
||||||
})
|
})
|
||||||
|
|
||||||
player.sendSelfPosition = () => {
|
player.sendSelfPosition = () => {
|
||||||
|
// double position in all versions
|
||||||
player._client.write('position', {
|
player._client.write('position', {
|
||||||
x: player.position.x / 32,
|
x: player.position.x,
|
||||||
y: player.position.y / 32,
|
y: player.position.y,
|
||||||
z: player.position.z / 32,
|
z: player.position.z,
|
||||||
yaw: player.yaw,
|
yaw: player.yaw,
|
||||||
pitch: player.pitch,
|
pitch: player.pitch,
|
||||||
flags: 0x00
|
flags: 0x00,
|
||||||
|
teleportId: 1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
player.teleport = async (position) => {
|
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()
|
if (notCancelled) player.sendSelfPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +81,7 @@ module.exports.player = function (player) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.entity = function (entity) {
|
module.exports.entity = function (entity, serv) {
|
||||||
entity.sendPosition = (position, onGround, teleport = false) => {
|
entity.sendPosition = (position, onGround, teleport = false) => {
|
||||||
if (typeof position === 'undefined') throw new Error('undef')
|
if (typeof position === 'undefined') throw new Error('undef')
|
||||||
if (entity.position.equals(position) && entity.onGround === onGround) return Promise.resolve()
|
if (entity.position.equals(position) && entity.onGround === onGround) return Promise.resolve()
|
||||||
|
|
@ -92,23 +90,53 @@ module.exports.entity = function (entity) {
|
||||||
onGround: onGround,
|
onGround: onGround,
|
||||||
teleport: teleport
|
teleport: teleport
|
||||||
}, ({position, onGround}) => {
|
}, ({position, onGround}) => {
|
||||||
const diff = position.minus(entity.position)
|
// known position is very important because the diff (/delta) send to players is floored hence is not precise enough
|
||||||
if (diff.abs().x > 127 || diff.abs().y > 127 || diff.abs().z > 127) {
|
// 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)
|
||||||
|
|
||||||
|
let maxDelta
|
||||||
|
if (serv.supportFeature('fixedPointDelta')) {
|
||||||
|
maxDelta = 3
|
||||||
|
} else if (serv.supportFeature('fixedPointDelta128')) {
|
||||||
|
maxDelta = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff.abs().x > maxDelta || diff.abs().y > maxDelta || diff.abs().z > maxDelta) {
|
||||||
|
let entityPosition
|
||||||
|
|
||||||
|
if (serv.supportFeature('fixedPointPosition')) {
|
||||||
|
entityPosition = position.scaled(32).floored()
|
||||||
|
} else if (serv.supportFeature('doublePosition')) {
|
||||||
|
entityPosition = position
|
||||||
|
}
|
||||||
entity._writeOthersNearby('entity_teleport', {
|
entity._writeOthersNearby('entity_teleport', {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
x: position.x,
|
x: entityPosition.x,
|
||||||
y: position.y,
|
y: entityPosition.y,
|
||||||
z: position.z,
|
z: entityPosition.z,
|
||||||
yaw: entity.yaw,
|
yaw: entity.yaw,
|
||||||
pitch: entity.pitch,
|
pitch: entity.pitch,
|
||||||
onGround: onGround
|
onGround: onGround
|
||||||
})
|
})
|
||||||
|
entity.knownPosition = position
|
||||||
} else if (diff.distanceTo(new Vec3(0, 0, 0)) !== 0) {
|
} 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', {
|
entity._writeOthersNearby('rel_entity_move', {
|
||||||
entityId: entity.id,
|
entityId: entity.id,
|
||||||
dX: diff.x,
|
dX: delta.x,
|
||||||
dY: diff.y,
|
dY: delta.y,
|
||||||
dZ: diff.z,
|
dZ: delta.z,
|
||||||
onGround: onGround
|
onGround: onGround
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +149,6 @@ module.exports.entity = function (entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.teleport = (pos) => { // Overwritten in players inject above
|
entity.teleport = (pos) => { // Overwritten in players inject above
|
||||||
entity.sendPosition(pos.scaled(32), false, true)
|
entity.sendPosition(pos, false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ const Vec3 = require('vec3').Vec3
|
||||||
|
|
||||||
module.exports.player = function (player, serv, {version}) {
|
module.exports.player = function (player, serv, {version}) {
|
||||||
const items = require('minecraft-data')(version).items
|
const items = require('minecraft-data')(version).items
|
||||||
const Item = require('prismarine-item')(version)
|
|
||||||
|
|
||||||
player._client.on('block_place', ({direction, heldItem, location} = {}) => {
|
player._client.on('block_place', ({direction, location} = {}) => {
|
||||||
if (direction === -1 || heldItem.blockId === -1 || !items[heldItem.blockId]) return
|
const heldItem = player.inventory.slots[36 + player.heldItemSlot]
|
||||||
const item = Item.fromNotch(heldItem)
|
if (direction === -1 || heldItem.type === -1 || !items[heldItem.type]) return
|
||||||
|
const item = heldItem
|
||||||
const referencePosition = new Vec3(location.x, location.y, location.z)
|
const referencePosition = new Vec3(location.x, location.y, location.z)
|
||||||
const directionVector = directionToVector[direction]
|
const directionVector = directionToVector[direction]
|
||||||
const position = referencePosition.plus(directionVector)
|
const position = referencePosition.plus(directionVector)
|
||||||
|
|
|
||||||
|
|
@ -82,13 +82,21 @@ module.exports.server = async function (serv, {version, worldFolder, generation
|
||||||
module.exports.player = function (player, serv, settings) {
|
module.exports.player = function (player, serv, settings) {
|
||||||
player.unloadChunk = (chunkX, chunkZ) => {
|
player.unloadChunk = (chunkX, chunkZ) => {
|
||||||
delete player.loadedChunks[chunkX + ',' + chunkZ]
|
delete player.loadedChunks[chunkX + ',' + chunkZ]
|
||||||
player._client.write('map_chunk', {
|
|
||||||
x: chunkX,
|
if (serv.supportFeature('unloadChunkByEmptyChunk')) {
|
||||||
z: chunkZ,
|
player._client.write('map_chunk', {
|
||||||
groundUp: true,
|
x: chunkX,
|
||||||
bitMap: 0x0000,
|
z: chunkZ,
|
||||||
chunkData: Buffer.alloc(0)
|
groundUp: true,
|
||||||
})
|
bitMap: 0x0000,
|
||||||
|
chunkData: Buffer.alloc(0)
|
||||||
|
})
|
||||||
|
} else if (serv.supportFeature('unloadChunkDirect')) {
|
||||||
|
player._client.write('unload_chunk', {
|
||||||
|
chunkX,
|
||||||
|
chunkZ
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendChunk = (chunkX, chunkZ, column) => {
|
player.sendChunk = (chunkX, chunkZ, column) => {
|
||||||
|
|
@ -102,7 +110,8 @@ module.exports.player = function (player, serv, settings) {
|
||||||
z: z,
|
z: z,
|
||||||
groundUp: true,
|
groundUp: true,
|
||||||
bitMap: 0xffff,
|
bitMap: 0xffff,
|
||||||
chunkData: chunk.dump()
|
chunkData: chunk.dump(),
|
||||||
|
blockEntities: []
|
||||||
})
|
})
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
})
|
})
|
||||||
|
|
@ -118,8 +127,8 @@ module.exports.player = function (player, serv, settings) {
|
||||||
|
|
||||||
player.sendNearbyChunks = (view, group) => {
|
player.sendNearbyChunks = (view, group) => {
|
||||||
player.lastPositionChunkUpdated = player.position
|
player.lastPositionChunkUpdated = player.position
|
||||||
const playerChunkX = Math.floor(player.position.x / 16 / 32)
|
const playerChunkX = Math.floor(player.position.x / 16)
|
||||||
const playerChunkZ = Math.floor(player.position.z / 16 / 32)
|
const playerChunkZ = Math.floor(player.position.z / 16)
|
||||||
|
|
||||||
Object.keys(player.loadedChunks)
|
Object.keys(player.loadedChunks)
|
||||||
.map((key) => key.split(',').map(a => parseInt(a)))
|
.map((key) => key.split(',').map(a => parseInt(a)))
|
||||||
|
|
@ -181,7 +190,7 @@ module.exports.player = function (player, serv, settings) {
|
||||||
levelType: 'default'
|
levelType: 'default'
|
||||||
})
|
})
|
||||||
await player.findSpawnPoint()
|
await player.findSpawnPoint()
|
||||||
player.position = player.spawnPoint.toFixedPosition()
|
player.position = player.spawnPoint
|
||||||
player.sendSpawnPosition()
|
player.sendSpawnPosition()
|
||||||
player.updateAndSpawn()
|
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))
|
||||||
3
src/lib/version.js
Normal file
3
src/lib/version.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
supportedVersions: ['1.8', '1.12']
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ function generation ({version, seed, level = 50} = {}) {
|
||||||
let data
|
let data
|
||||||
|
|
||||||
if (y < bedrockheightbottom) block = 7
|
if (y < bedrockheightbottom) block = 7
|
||||||
else if (y < level) block = 87
|
else if (y < level) block = seedRand(50) === 0 ? 89 : 87
|
||||||
else if (y > 127 - bedrockheighttop) block = 7
|
else if (y > 127 - bedrockheighttop) block = 7
|
||||||
|
|
||||||
const pos = new Vec3(x, y, z)
|
const pos = new Vec3(x, y, z)
|
||||||
|
|
|
||||||
31
test/common/parallel.js
Normal file
31
test/common/parallel.js
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
const nodeIndex = parseInt(process.env.CIRCLE_NODE_INDEX)
|
||||||
|
const nodeTotal = parseInt(process.env.CIRCLE_NODE_TOTAL)
|
||||||
|
const parallel = process.env.CIRCLE_NODE_INDEX !== undefined && process.env.CIRCLE_NODE_TOTAL !== undefined
|
||||||
|
const mc = require('../../')
|
||||||
|
|
||||||
|
// expected values :
|
||||||
|
// (0,4,10) -> (0,2)
|
||||||
|
// (1,4,10) -> (3,5)
|
||||||
|
// (2,4,10) -> (6,8)
|
||||||
|
// (3,4,10) -> (9,9)
|
||||||
|
function testedRange (nodeIndex, nodeTotal, numberOfVersions) {
|
||||||
|
const nbFirsts = Math.ceil(numberOfVersions / nodeTotal)
|
||||||
|
if (nodeIndex === (nodeTotal - 1)) {
|
||||||
|
return {
|
||||||
|
firstVersion: nbFirsts * nodeIndex,
|
||||||
|
lastVersion: numberOfVersions - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
firstVersion: nodeIndex * nbFirsts,
|
||||||
|
lastVersion: (nodeIndex + 1) * nbFirsts - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log({ nodeIndex, nodeTotal, versions: mc.supportedVersions.length })
|
||||||
|
const { firstVersion, lastVersion } = parallel ? testedRange(nodeIndex, nodeTotal, mc.supportedVersions.length) : {
|
||||||
|
firstVersion: 0,
|
||||||
|
lastVersion: mc.supportedVersions.length - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { firstVersion, lastVersion }
|
||||||
|
|
@ -4,7 +4,6 @@ const squid = require('flying-squid')
|
||||||
const settings = require('../config/default-settings')
|
const settings = require('../config/default-settings')
|
||||||
const mineflayer = require('mineflayer')
|
const mineflayer = require('mineflayer')
|
||||||
const { Vec3 } = require('vec3')
|
const { Vec3 } = require('vec3')
|
||||||
const Item = require('prismarine-item')('1.8')
|
|
||||||
|
|
||||||
function assertPosEqual (actual, expected) {
|
function assertPosEqual (actual, expected) {
|
||||||
expect(actual.distanceTo(expected)).toBeLessThan(1)
|
expect(actual.distanceTo(expected)).toBeLessThan(1)
|
||||||
|
|
@ -12,228 +11,249 @@ function assertPosEqual (actual, expected) {
|
||||||
|
|
||||||
const once = require('event-promise')
|
const once = require('event-promise')
|
||||||
|
|
||||||
describe('server with mineflayer connection', () => {
|
const { firstVersion, lastVersion } = require('./common/parallel')
|
||||||
jest.setTimeout(60 * 1000)
|
|
||||||
let bot
|
|
||||||
let bot2
|
|
||||||
let serv
|
|
||||||
|
|
||||||
async function onGround (bot) {
|
squid.supportedVersions.forEach((supportedVersion, i) => {
|
||||||
await new Promise((resolve) => {
|
if (!(i >= firstVersion && i <= lastVersion)) {
|
||||||
const l = () => {
|
return
|
||||||
if (bot.entity.onGround) {
|
|
||||||
bot.removeListener('move', l)
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bot.on('move', l)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitMessage (bot, message) {
|
const mcData = require('minecraft-data')(supportedVersion)
|
||||||
const msg1 = await once(bot, 'message')
|
const version = mcData.version
|
||||||
expect(msg1.extra[0].text).toEqual(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function waitMessages (bot, messages) {
|
const Item = require('prismarine-item')(supportedVersion)
|
||||||
const toReceive = messages.reduce((acc, message) => {
|
|
||||||
acc[message] = 1
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
const received = {}
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const listener = msg => {
|
|
||||||
const message = msg.extra[0].text
|
|
||||||
if (!toReceive[message]) throw new Error('Received ' + message + ' , expected to receive one of ' + messages)
|
|
||||||
if (received[message]) throw new Error('Received ' + message + ' two times')
|
|
||||||
received[message] = 1
|
|
||||||
if (Object.keys(received).length === messages.length) {
|
|
||||||
bot.removeListener('message', listener)
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bot.on('message', listener)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function waitLoginMessage (bot) {
|
describe('server with mineflayer connection ' + version.minecraftVersion, () => {
|
||||||
return Promise.all([waitMessages(bot, ['bot joined the game.', 'bot2 joined the game.'])])
|
jest.setTimeout(100 * 1000)
|
||||||
}
|
let bot
|
||||||
|
let bot2
|
||||||
|
let serv
|
||||||
|
let entityName
|
||||||
|
|
||||||
beforeEach(async () => {
|
async function onGround (bot) {
|
||||||
const options = settings
|
await new Promise((resolve) => {
|
||||||
options['online-mode'] = false
|
const l = () => {
|
||||||
options['port'] = 25566
|
if (bot.entity.onGround) {
|
||||||
options['view-distance'] = 2
|
bot.removeListener('move', l)
|
||||||
options['worldFolder'] = undefined
|
|
||||||
options['logging'] = false
|
|
||||||
|
|
||||||
serv = squid.createMCServer(options)
|
|
||||||
|
|
||||||
await once(serv, 'listening')
|
|
||||||
bot = mineflayer.createBot({
|
|
||||||
host: 'localhost',
|
|
||||||
port: 25566,
|
|
||||||
username: 'bot',
|
|
||||||
version: '1.8'
|
|
||||||
})
|
|
||||||
bot2 = mineflayer.createBot({
|
|
||||||
host: 'localhost',
|
|
||||||
port: 25566,
|
|
||||||
username: 'bot2',
|
|
||||||
version: '1.8'
|
|
||||||
})
|
|
||||||
|
|
||||||
await Promise.all([once(bot, 'login'), once(bot2, 'login')])
|
|
||||||
bot.entity.onGround = false
|
|
||||||
bot2.entity.onGround = false
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await serv.quit()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('actions', () => {
|
|
||||||
function waitSpawnZone (bot, view) {
|
|
||||||
const nbChunksExpected = (view * 2) * (view * 2)
|
|
||||||
let c = 0
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const listener = () => {
|
|
||||||
c++
|
|
||||||
if (c === nbChunksExpected) {
|
|
||||||
bot.removeListener('chunkColumnLoad', listener)
|
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bot.on('chunkColumnLoad', listener)
|
bot.on('move', l)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
test('can dig', async () => {
|
async function waitMessage (bot, message) {
|
||||||
await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)])
|
const msg1 = await once(bot, 'message')
|
||||||
|
expect(msg1.extra[0].text).toEqual(message)
|
||||||
|
}
|
||||||
|
|
||||||
const pos = bot.entity.position.offset(0, -1, 0).floored()
|
async function waitMessages (bot, messages) {
|
||||||
bot.dig(bot.blockAt(pos))
|
const toReceive = messages.reduce((acc, message) => {
|
||||||
|
acc[message] = 1
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
const received = {}
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const listener = msg => {
|
||||||
|
const message = msg.extra[0].text
|
||||||
|
if (!toReceive[message]) throw new Error('Received ' + message + ' , expected to receive one of ' + messages)
|
||||||
|
if (received[message]) throw new Error('Received ' + message + ' two times')
|
||||||
|
received[message] = 1
|
||||||
|
if (Object.keys(received).length === messages.length) {
|
||||||
|
bot.removeListener('message', listener)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bot.on('message', listener)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let [, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
async function waitLoginMessage (bot) {
|
||||||
assertPosEqual(newBlock.position, pos)
|
return Promise.all([waitMessages(bot, ['bot joined the game.', 'bot2 joined the game.'])])
|
||||||
expect(newBlock.type).toEqual(0)
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const options = settings
|
||||||
|
options['online-mode'] = false
|
||||||
|
options['port'] = 0
|
||||||
|
options['view-distance'] = 2
|
||||||
|
options['worldFolder'] = undefined
|
||||||
|
options['logging'] = false
|
||||||
|
options['version'] = version.minecraftVersion
|
||||||
|
|
||||||
|
serv = squid.createMCServer(options)
|
||||||
|
if (serv.supportFeature('entityCamelCase')) {
|
||||||
|
entityName = 'EnderDragon'
|
||||||
|
} else {
|
||||||
|
entityName = 'ender_dragon'
|
||||||
|
}
|
||||||
|
|
||||||
|
await once(serv, 'listening')
|
||||||
|
const port = serv._server.socketServer.address().port
|
||||||
|
bot = mineflayer.createBot({
|
||||||
|
host: 'localhost',
|
||||||
|
port: port,
|
||||||
|
username: 'bot',
|
||||||
|
version: version.minecraftVersion
|
||||||
|
})
|
||||||
|
bot2 = mineflayer.createBot({
|
||||||
|
host: 'localhost',
|
||||||
|
port: port,
|
||||||
|
username: 'bot2',
|
||||||
|
version: version.minecraftVersion
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([once(bot, 'login'), once(bot2, 'login')])
|
||||||
|
bot.entity.onGround = false
|
||||||
|
bot2.entity.onGround = false
|
||||||
})
|
})
|
||||||
|
|
||||||
test('can place a block', async () => {
|
afterEach(async () => {
|
||||||
await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)])
|
await serv.quit()
|
||||||
|
})
|
||||||
|
|
||||||
const pos = bot.entity.position.offset(0, -2, 0).floored()
|
describe('actions', () => {
|
||||||
bot.dig(bot.blockAt(pos))
|
function waitSpawnZone (bot, view) {
|
||||||
|
const nbChunksExpected = (view * 2) * (view * 2)
|
||||||
|
let c = 0
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const listener = () => {
|
||||||
|
c++
|
||||||
|
if (c === nbChunksExpected) {
|
||||||
|
bot.removeListener('chunkColumnLoad', listener)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bot.on('chunkColumnLoad', listener)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let [, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
test('can dig', async () => {
|
||||||
assertPosEqual(newBlock.position, pos)
|
await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)])
|
||||||
expect(newBlock.type).toEqual(0)
|
|
||||||
|
|
||||||
bot.creative.setInventorySlot(36, new Item(1, 1))
|
const pos = bot.entity.position.offset(0, -1, 0).floored()
|
||||||
await new Promise((resolve) => {
|
bot.dig(bot.blockAt(pos))
|
||||||
bot.inventory.on('windowUpdate', (slot, oldItem, newItem) => {
|
|
||||||
if (slot === 36 && newItem && newItem.type === 1) { resolve() }
|
let [, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
||||||
|
assertPosEqual(newBlock.position, pos)
|
||||||
|
expect(newBlock.type).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('can place a block', async () => {
|
||||||
|
await Promise.all([waitSpawnZone(bot, 2), waitSpawnZone(bot2, 2), onGround(bot), onGround(bot2)])
|
||||||
|
|
||||||
|
const pos = bot.entity.position.offset(0, -2, 0).floored()
|
||||||
|
bot.dig(bot.blockAt(pos))
|
||||||
|
|
||||||
|
let [, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
||||||
|
assertPosEqual(newBlock.position, pos)
|
||||||
|
expect(newBlock.type).toEqual(0)
|
||||||
|
|
||||||
|
bot.creative.setInventorySlot(36, new Item(1, 1))
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
bot.inventory.on('windowUpdate', (slot, oldItem, newItem) => {
|
||||||
|
if (slot === 36 && newItem && newItem.type === 1) { resolve() }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
bot.placeBlock(bot.blockAt(pos.offset(0, -1, 0)), new Vec3(0, 1, 0));
|
||||||
|
|
||||||
|
[, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
||||||
|
assertPosEqual(newBlock.position, pos)
|
||||||
|
expect(newBlock.type).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('commands', () => {
|
||||||
|
jest.setTimeout(30 * 1000)
|
||||||
|
test('has an help command', async () => {
|
||||||
|
await waitLoginMessage(bot)
|
||||||
|
bot.chat('/help')
|
||||||
|
await once(bot, 'message')
|
||||||
|
})
|
||||||
|
test('can use /particle', async () => {
|
||||||
|
bot.chat('/particle 5 10 100 100 100')
|
||||||
|
await once(bot._client, 'world_particles')
|
||||||
|
})
|
||||||
|
test('can use /playsound', async () => {
|
||||||
|
bot.chat('/playsound ambient.weather.rain')
|
||||||
|
await once(bot, 'soundEffectHeard')
|
||||||
|
})
|
||||||
|
|
||||||
|
function waitDragon () {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const listener = (entity) => {
|
||||||
|
if (entity.name === entityName) {
|
||||||
|
bot.removeListener('entitySpawn', listener)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bot.on('entitySpawn', listener)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test('can use /summon', async () => {
|
||||||
|
bot.chat('/summon ' + entityName)
|
||||||
|
await waitDragon()
|
||||||
|
})
|
||||||
|
test('can use /kill', async () => {
|
||||||
|
bot.chat('/summon ' + entityName)
|
||||||
|
await waitDragon()
|
||||||
|
bot.chat('/kill @e[type=' + entityName + ']')
|
||||||
|
const entity = await once(bot, 'entityDead')
|
||||||
|
expect(entity.name).toEqual(entityName)
|
||||||
|
})
|
||||||
|
describe('can use /tp', () => {
|
||||||
|
test('can tp myself', async () => {
|
||||||
|
bot.chat('/tp 2 3 4')
|
||||||
|
await once(bot, 'forcedMove')
|
||||||
|
assertPosEqual(bot.entity.position, new Vec3(2, 3, 4))
|
||||||
|
})
|
||||||
|
test('can tp somebody else', async () => {
|
||||||
|
bot.chat('/tp bot2 2 3 4')
|
||||||
|
await once(bot2, 'forcedMove')
|
||||||
|
assertPosEqual(bot2.entity.position, new Vec3(2, 3, 4))
|
||||||
|
})
|
||||||
|
test('can tp to somebody else', async () => {
|
||||||
|
await onGround(bot)
|
||||||
|
bot.chat('/tp bot2 bot')
|
||||||
|
await once(bot2, 'forcedMove')
|
||||||
|
assertPosEqual(bot2.entity.position, bot.entity.position)
|
||||||
|
})
|
||||||
|
test('can tp with relative positions', async () => {
|
||||||
|
await onGround(bot)
|
||||||
|
const initialPosition = bot.entity.position.clone()
|
||||||
|
bot.chat('/tp ~1 ~-2 ~3')
|
||||||
|
await once(bot, 'forcedMove')
|
||||||
|
assertPosEqual(bot.entity.position, initialPosition.offset(1, -2, 3))
|
||||||
|
})
|
||||||
|
test('can tp somebody else with relative positions', async () => {
|
||||||
|
await Promise.all([onGround(bot), onGround(bot2)])
|
||||||
|
const initialPosition = bot2.entity.position.clone()
|
||||||
|
bot.chat('/tp bot2 ~1 ~-2 ~3')
|
||||||
|
await once(bot2, 'forcedMove')
|
||||||
|
assertPosEqual(bot2.entity.position, initialPosition.offset(1, -2, 3))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
test('can use /deop', async () => {
|
||||||
bot.placeBlock(bot.blockAt(pos.offset(0, -1, 0)), new Vec3(0, 1, 0));
|
await waitLoginMessage(bot)
|
||||||
|
bot.chat('/deop bot')
|
||||||
[, newBlock] = await once(bot2, 'blockUpdate', {array: true})
|
await waitMessage(bot, 'bot is deopped')
|
||||||
assertPosEqual(newBlock.position, pos)
|
bot.chat('/op bot')
|
||||||
expect(newBlock.type).toEqual(1)
|
await waitMessage(bot, 'You do not have permission to use this command')
|
||||||
})
|
serv.getPlayer('bot').op = true
|
||||||
})
|
|
||||||
|
|
||||||
describe('commands', () => {
|
|
||||||
jest.setTimeout(10 * 1000)
|
|
||||||
test('has an help command', async () => {
|
|
||||||
await waitLoginMessage(bot)
|
|
||||||
bot.chat('/help')
|
|
||||||
await once(bot, 'message')
|
|
||||||
})
|
|
||||||
test('can use /particle', async () => {
|
|
||||||
bot.chat('/particle 5 10 100 100 100')
|
|
||||||
await once(bot._client, 'world_particles')
|
|
||||||
})
|
|
||||||
test('can use /playsound', async () => {
|
|
||||||
bot.chat('/playsound ambient.weather.rain')
|
|
||||||
await once(bot, 'soundEffectHeard')
|
|
||||||
})
|
|
||||||
|
|
||||||
function waitDragon () {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const listener = (entity) => {
|
|
||||||
if (entity.name === 'EnderDragon') {
|
|
||||||
bot.removeListener('entitySpawn', listener)
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bot.on('entitySpawn', listener)
|
|
||||||
})
|
})
|
||||||
}
|
test('can use /setblock', async () => {
|
||||||
|
await once(bot, 'chunkColumnLoad')
|
||||||
test('can use /summon', async () => {
|
bot.chat('/setblock 1 2 3 95 0')
|
||||||
bot.chat('/summon EnderDragon')
|
let [, newBlock] = await once(bot, 'blockUpdate:' + new Vec3(1, 2, 3), {array: true})
|
||||||
await waitDragon()
|
expect(newBlock.type).toEqual(95)
|
||||||
})
|
|
||||||
test('can use /kill', async () => {
|
|
||||||
bot.chat('/summon EnderDragon')
|
|
||||||
await waitDragon()
|
|
||||||
bot.chat('/kill @e[type=EnderDragon]')
|
|
||||||
const entity = await once(bot, 'entityDead')
|
|
||||||
expect(entity.name).toEqual('EnderDragon')
|
|
||||||
})
|
|
||||||
describe('can use /tp', () => {
|
|
||||||
test('can tp myself', async () => {
|
|
||||||
bot.chat('/tp 2 3 4')
|
|
||||||
await once(bot, 'forcedMove')
|
|
||||||
assertPosEqual(bot.entity.position, new Vec3(2, 3, 4))
|
|
||||||
})
|
})
|
||||||
test('can tp somebody else', async () => {
|
test('can use /xp', async () => {
|
||||||
bot.chat('/tp bot2 2 3 4')
|
bot.chat('/xp 100')
|
||||||
await once(bot2, 'forcedMove')
|
await once(bot, 'experience')
|
||||||
assertPosEqual(bot2.entity.position, new Vec3(2, 3, 4))
|
expect(bot.experience.points).toEqual(100)
|
||||||
})
|
})
|
||||||
test('can tp to somebody else', async () => {
|
|
||||||
await onGround(bot)
|
|
||||||
bot.chat('/tp bot2 bot')
|
|
||||||
await once(bot2, 'forcedMove')
|
|
||||||
assertPosEqual(bot2.entity.position, bot.entity.position)
|
|
||||||
})
|
|
||||||
test('can tp with relative positions', async () => {
|
|
||||||
await onGround(bot)
|
|
||||||
const initialPosition = bot.entity.position.clone()
|
|
||||||
bot.chat('/tp ~1 ~-2 ~3')
|
|
||||||
await once(bot, 'forcedMove')
|
|
||||||
assertPosEqual(bot.entity.position, initialPosition.offset(1, -2, 3))
|
|
||||||
})
|
|
||||||
test('can tp somebody else with relative positions', async () => {
|
|
||||||
await Promise.all([onGround(bot), onGround(bot2)])
|
|
||||||
const initialPosition = bot2.entity.position.clone()
|
|
||||||
bot.chat('/tp bot2 ~1 ~-2 ~3')
|
|
||||||
await once(bot2, 'forcedMove')
|
|
||||||
assertPosEqual(bot2.entity.position, initialPosition.offset(1, -2, 3))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
test('can use /deop', async () => {
|
|
||||||
await waitLoginMessage(bot)
|
|
||||||
bot.chat('/deop bot')
|
|
||||||
await waitMessage(bot, 'bot is deopped')
|
|
||||||
bot.chat('/op bot')
|
|
||||||
await waitMessage(bot, 'You do not have permission to use this command')
|
|
||||||
serv.getPlayer('bot').op = true
|
|
||||||
})
|
|
||||||
test('can use /setblock', async () => {
|
|
||||||
await once(bot, 'chunkColumnLoad')
|
|
||||||
bot.chat('/setblock 1 2 3 95 0')
|
|
||||||
let [, newBlock] = await once(bot, 'blockUpdate:' + new Vec3(1, 2, 3), {array: true})
|
|
||||||
expect(newBlock.type).toEqual(95)
|
|
||||||
})
|
|
||||||
test('can use /xp', async () => {
|
|
||||||
bot.chat('/xp 100')
|
|
||||||
await once(bot, 'experience')
|
|
||||||
expect(bot.experience.points).toEqual(100)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,250 +1,260 @@
|
||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
|
|
||||||
const {
|
const squid = require('flying-squid')
|
||||||
detectFrame,
|
const { firstVersion, lastVersion } = require('./common/parallel')
|
||||||
findPotentialLines,
|
|
||||||
findBorder,
|
|
||||||
getAir,
|
|
||||||
generateLine,
|
|
||||||
generatePortal,
|
|
||||||
makeWorldWithPortal
|
|
||||||
} = require('flying-squid').portal_detector('1.8')
|
|
||||||
|
|
||||||
const { Vec3 } = require('vec3')
|
squid.supportedVersions.forEach((supportedVersion, i) => {
|
||||||
|
if (!(i >= firstVersion && i <= lastVersion)) return
|
||||||
|
|
||||||
describe('generate portal', () => {
|
const mcData = require('minecraft-data')(supportedVersion)
|
||||||
test('generate a line', () => {
|
const version = mcData.version
|
||||||
expect(generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2)).toEqual([new Vec3(3, 1, 1), new Vec3(4, 1, 1)])
|
|
||||||
})
|
|
||||||
|
|
||||||
test('generate a portal', () => {
|
const {
|
||||||
expect(generatePortal(new Vec3(2, 1, 1), new Vec3(1, 0, 0), 4, 5)).toEqual({
|
detectFrame,
|
||||||
bottom: generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2),
|
findPotentialLines,
|
||||||
left: generateLine(new Vec3(2, 2, 1), new Vec3(0, 1, 0), 3),
|
findBorder,
|
||||||
right: generateLine(new Vec3(5, 2, 1), new Vec3(0, 1, 0), 3),
|
getAir,
|
||||||
top: generateLine(new Vec3(3, 5, 1), new Vec3(1, 0, 0), 2),
|
generateLine,
|
||||||
air: generateLine(new Vec3(3, 2, 1), new Vec3(0, 1, 0), 3).concat(generateLine(new Vec3(4, 2, 1), new Vec3(0, 1, 0), 3))
|
generatePortal,
|
||||||
|
makeWorldWithPortal
|
||||||
|
} = squid.portal_detector(version.minecraftVersion)
|
||||||
|
|
||||||
|
const { Vec3 } = require('vec3')
|
||||||
|
|
||||||
|
describe('generate portal ' + version.minecraftVersion, () => {
|
||||||
|
test('generate a line', () => {
|
||||||
|
expect(generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2)).toEqual([new Vec3(3, 1, 1), new Vec3(4, 1, 1)])
|
||||||
})
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('detect portal', () => {
|
test('generate a portal', () => {
|
||||||
jest.setTimeout(60 * 1000)
|
expect(generatePortal(new Vec3(2, 1, 1), new Vec3(1, 0, 0), 4, 5)).toEqual({
|
||||||
const portalData = []
|
bottom: generateLine(new Vec3(3, 1, 1), new Vec3(1, 0, 0), 2),
|
||||||
|
left: generateLine(new Vec3(2, 2, 1), new Vec3(0, 1, 0), 3),
|
||||||
portalData.push({
|
right: generateLine(new Vec3(5, 2, 1), new Vec3(0, 1, 0), 3),
|
||||||
name: 'simple portal frame x',
|
top: generateLine(new Vec3(3, 5, 1), new Vec3(1, 0, 0), 2),
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
air: generateLine(new Vec3(3, 2, 1), new Vec3(0, 1, 0), 3).concat(generateLine(new Vec3(4, 2, 1), new Vec3(0, 1, 0), 3))
|
||||||
direction: new Vec3(1, 0, 0),
|
|
||||||
width: 4,
|
|
||||||
height: 5,
|
|
||||||
additionalAir: [],
|
|
||||||
additionalObsidian: []
|
|
||||||
})
|
|
||||||
|
|
||||||
portalData.push({
|
|
||||||
name: 'simple portal frame z',
|
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
|
||||||
direction: new Vec3(0, 0, 1),
|
|
||||||
width: 4,
|
|
||||||
height: 5,
|
|
||||||
additionalAir: [],
|
|
||||||
additionalObsidian: []
|
|
||||||
})
|
|
||||||
|
|
||||||
portalData.push({
|
|
||||||
name: 'big simple portal frame x',
|
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
|
||||||
direction: new Vec3(1, 0, 0),
|
|
||||||
width: 10,
|
|
||||||
height: 10,
|
|
||||||
additionalAir: [],
|
|
||||||
additionalObsidian: []
|
|
||||||
})
|
|
||||||
|
|
||||||
portalData.push({
|
|
||||||
name: 'simple portal frame x with borders',
|
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
|
||||||
direction: new Vec3(1, 0, 0),
|
|
||||||
width: 4,
|
|
||||||
height: 5,
|
|
||||||
additionalAir: [],
|
|
||||||
additionalObsidian: [new Vec3(2, 1, 1), new Vec3(5, 1, 1), new Vec3(2, 6, 1), new Vec3(5, 6, 1)]
|
|
||||||
})
|
|
||||||
|
|
||||||
const {bottom, left, right, top, air} = generatePortal(new Vec3(2, 1, 2), new Vec3(1, 0, 0), 4, 5)
|
|
||||||
|
|
||||||
portalData.push({
|
|
||||||
name: '2 portals',
|
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
|
||||||
direction: new Vec3(1, 0, 0),
|
|
||||||
width: 4,
|
|
||||||
height: 5,
|
|
||||||
additionalAir: air,
|
|
||||||
additionalObsidian: [].concat([], [bottom, left, right, top])
|
|
||||||
})
|
|
||||||
|
|
||||||
portalData.push({
|
|
||||||
name: 'huge simple portal frame z',
|
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
|
||||||
direction: new Vec3(0, 0, 1),
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
additionalAir: [],
|
|
||||||
additionalObsidian: []
|
|
||||||
})
|
|
||||||
|
|
||||||
portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => {
|
|
||||||
const portal = generatePortal(bottomLeft, direction, width, height)
|
|
||||||
const {bottom, left, right, top, air} = portal
|
|
||||||
describe('Detect ' + name, () => {
|
|
||||||
const expectedBorder = {bottom, left, right, top}
|
|
||||||
|
|
||||||
let world
|
|
||||||
beforeAll(async function () {
|
|
||||||
world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('detect potential first lines', () => {
|
|
||||||
test('detect potential first lines from bottom left', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, bottom[0], new Vec3(0, 1, 0))
|
|
||||||
expect(potentialLines).toContainEqual({
|
|
||||||
'direction': direction,
|
|
||||||
'line': bottom
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('detect potential first lines from bottom right', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, bottom[bottom.length - 1], new Vec3(0, 1, 0))
|
|
||||||
expect(potentialLines).toContainEqual({
|
|
||||||
'direction': direction,
|
|
||||||
'line': bottom
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('detect potential first lines from top left', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, top[0], new Vec3(0, -1, 0))
|
|
||||||
expect(potentialLines).toContainEqual({
|
|
||||||
'direction': direction,
|
|
||||||
'line': top
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('detect potential first lines from top right', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, top[top.length - 1], new Vec3(0, -1, 0))
|
|
||||||
expect(potentialLines).toContainEqual({
|
|
||||||
'direction': direction,
|
|
||||||
'line': top
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('detect potential first lines from left top', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, left[left.length - 1], direction)
|
|
||||||
expect(potentialLines).toEqual([{
|
|
||||||
'direction': new Vec3(0, 1, 0),
|
|
||||||
'line': left
|
|
||||||
}])
|
|
||||||
})
|
|
||||||
|
|
||||||
test('detect potential first lines from right bottom', async () => {
|
|
||||||
let potentialLines = await findPotentialLines(world, right[0], direction.scaled(-1))
|
|
||||||
expect(potentialLines).toEqual([{
|
|
||||||
'direction': new Vec3(0, 1, 0),
|
|
||||||
'line': right
|
|
||||||
}])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('find borders', () => {
|
|
||||||
test('find borders from bottom', async () => {
|
|
||||||
const border = await findBorder(world, {
|
|
||||||
'direction': direction,
|
|
||||||
'line': bottom
|
|
||||||
}, new Vec3(0, 1, 0))
|
|
||||||
expect(border).toEqual(expectedBorder)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('find borders from top', async () => {
|
|
||||||
const border = await findBorder(world, {
|
|
||||||
'direction': direction,
|
|
||||||
'line': top
|
|
||||||
}, new Vec3(0, -1, 0))
|
|
||||||
expect(border).toEqual(expectedBorder)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('find borders from left', async () => {
|
|
||||||
const border = await findBorder(world, {
|
|
||||||
'direction': new Vec3(0, 1, 0),
|
|
||||||
'line': left
|
|
||||||
}, direction)
|
|
||||||
expect(border).toEqual(expectedBorder)
|
|
||||||
})
|
|
||||||
test('find borders from right', async () => {
|
|
||||||
const border = await findBorder(world, {
|
|
||||||
'direction': new Vec3(0, 1, 0),
|
|
||||||
'line': right
|
|
||||||
}, direction.scaled(-1))
|
|
||||||
expect(border).toEqual(expectedBorder)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('detect portals', () => {
|
|
||||||
test('detect portals from bottom left', async () => {
|
|
||||||
const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0))
|
|
||||||
expect(portals).toEqual([portal])
|
|
||||||
})
|
|
||||||
test('detect portals from top left', async () => {
|
|
||||||
const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0))
|
|
||||||
expect(portals).toEqual([portal])
|
|
||||||
})
|
|
||||||
test('detect portals from right top', async () => {
|
|
||||||
const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1))
|
|
||||||
expect(portals).toEqual([portal])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('get air', () => {
|
|
||||||
const foundAir = getAir(expectedBorder)
|
|
||||||
expect(foundAir).toEqual(air)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
describe("doesn't detect non-portal", () => {
|
describe('detect portal ' + version.minecraftVersion, () => {
|
||||||
const portalData = []
|
jest.setTimeout(60 * 1000)
|
||||||
|
const portalData = []
|
||||||
|
|
||||||
portalData.push({
|
portalData.push({
|
||||||
name: 'simple portal frame x with one obsidian in the middle',
|
name: 'simple portal frame x',
|
||||||
bottomLeft: new Vec3(2, 1, 1),
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
direction: new Vec3(1, 0, 0),
|
direction: new Vec3(1, 0, 0),
|
||||||
width: 5,
|
width: 4,
|
||||||
height: 5,
|
height: 5,
|
||||||
additionalAir: [],
|
additionalAir: [],
|
||||||
additionalObsidian: [new Vec3(4, 3, 1)]
|
additionalObsidian: []
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.push({
|
||||||
|
name: 'simple portal frame z',
|
||||||
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
|
direction: new Vec3(0, 0, 1),
|
||||||
|
width: 4,
|
||||||
|
height: 5,
|
||||||
|
additionalAir: [],
|
||||||
|
additionalObsidian: []
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.push({
|
||||||
|
name: 'big simple portal frame x',
|
||||||
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
|
direction: new Vec3(1, 0, 0),
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
additionalAir: [],
|
||||||
|
additionalObsidian: []
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.push({
|
||||||
|
name: 'simple portal frame x with borders',
|
||||||
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
|
direction: new Vec3(1, 0, 0),
|
||||||
|
width: 4,
|
||||||
|
height: 5,
|
||||||
|
additionalAir: [],
|
||||||
|
additionalObsidian: [new Vec3(2, 1, 1), new Vec3(5, 1, 1), new Vec3(2, 6, 1), new Vec3(5, 6, 1)]
|
||||||
|
})
|
||||||
|
|
||||||
|
const {bottom, left, right, top, air} = generatePortal(new Vec3(2, 1, 2), new Vec3(1, 0, 0), 4, 5)
|
||||||
|
|
||||||
|
portalData.push({
|
||||||
|
name: '2 portals',
|
||||||
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
|
direction: new Vec3(1, 0, 0),
|
||||||
|
width: 4,
|
||||||
|
height: 5,
|
||||||
|
additionalAir: air,
|
||||||
|
additionalObsidian: [].concat([], [bottom, left, right, top])
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.push({
|
||||||
|
name: 'huge simple portal frame z',
|
||||||
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
|
direction: new Vec3(0, 0, 1),
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
additionalAir: [],
|
||||||
|
additionalObsidian: []
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => {
|
||||||
|
const portal = generatePortal(bottomLeft, direction, width, height)
|
||||||
|
const {bottom, left, right, top, air} = portal
|
||||||
|
describe('Detect ' + name, () => {
|
||||||
|
const expectedBorder = {bottom, left, right, top}
|
||||||
|
|
||||||
|
let world
|
||||||
|
beforeAll(async function () {
|
||||||
|
world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('detect potential first lines', () => {
|
||||||
|
test('detect potential first lines from bottom left', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, bottom[0], new Vec3(0, 1, 0))
|
||||||
|
expect(potentialLines).toContainEqual({
|
||||||
|
'direction': direction,
|
||||||
|
'line': bottom
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detect potential first lines from bottom right', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, bottom[bottom.length - 1], new Vec3(0, 1, 0))
|
||||||
|
expect(potentialLines).toContainEqual({
|
||||||
|
'direction': direction,
|
||||||
|
'line': bottom
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detect potential first lines from top left', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, top[0], new Vec3(0, -1, 0))
|
||||||
|
expect(potentialLines).toContainEqual({
|
||||||
|
'direction': direction,
|
||||||
|
'line': top
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detect potential first lines from top right', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, top[top.length - 1], new Vec3(0, -1, 0))
|
||||||
|
expect(potentialLines).toContainEqual({
|
||||||
|
'direction': direction,
|
||||||
|
'line': top
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detect potential first lines from left top', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, left[left.length - 1], direction)
|
||||||
|
expect(potentialLines).toEqual([{
|
||||||
|
'direction': new Vec3(0, 1, 0),
|
||||||
|
'line': left
|
||||||
|
}])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('detect potential first lines from right bottom', async () => {
|
||||||
|
let potentialLines = await findPotentialLines(world, right[0], direction.scaled(-1))
|
||||||
|
expect(potentialLines).toEqual([{
|
||||||
|
'direction': new Vec3(0, 1, 0),
|
||||||
|
'line': right
|
||||||
|
}])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('find borders', () => {
|
||||||
|
test('find borders from bottom', async () => {
|
||||||
|
const border = await findBorder(world, {
|
||||||
|
'direction': direction,
|
||||||
|
'line': bottom
|
||||||
|
}, new Vec3(0, 1, 0))
|
||||||
|
expect(border).toEqual(expectedBorder)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('find borders from top', async () => {
|
||||||
|
const border = await findBorder(world, {
|
||||||
|
'direction': direction,
|
||||||
|
'line': top
|
||||||
|
}, new Vec3(0, -1, 0))
|
||||||
|
expect(border).toEqual(expectedBorder)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('find borders from left', async () => {
|
||||||
|
const border = await findBorder(world, {
|
||||||
|
'direction': new Vec3(0, 1, 0),
|
||||||
|
'line': left
|
||||||
|
}, direction)
|
||||||
|
expect(border).toEqual(expectedBorder)
|
||||||
|
})
|
||||||
|
test('find borders from right', async () => {
|
||||||
|
const border = await findBorder(world, {
|
||||||
|
'direction': new Vec3(0, 1, 0),
|
||||||
|
'line': right
|
||||||
|
}, direction.scaled(-1))
|
||||||
|
expect(border).toEqual(expectedBorder)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('detect portals', () => {
|
||||||
|
test('detect portals from bottom left', async () => {
|
||||||
|
const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0))
|
||||||
|
expect(portals).toEqual([portal])
|
||||||
|
})
|
||||||
|
test('detect portals from top left', async () => {
|
||||||
|
const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0))
|
||||||
|
expect(portals).toEqual([portal])
|
||||||
|
})
|
||||||
|
test('detect portals from right top', async () => {
|
||||||
|
const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1))
|
||||||
|
expect(portals).toEqual([portal])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('get air', () => {
|
||||||
|
const foundAir = getAir(expectedBorder)
|
||||||
|
expect(foundAir).toEqual(air)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => {
|
describe("doesn't detect non-portal " + version.minecraftVersion, () => {
|
||||||
const portal = generatePortal(bottomLeft, direction, width, height)
|
const portalData = []
|
||||||
const {bottom, right, top} = portal
|
|
||||||
describe("doesn't detect detect " + name, () => {
|
|
||||||
let world
|
|
||||||
beforeAll(async function () {
|
|
||||||
world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("doesn't detect portals", () => {
|
portalData.push({
|
||||||
test("doesn't detect portals from bottom left", async () => {
|
name: 'simple portal frame x with one obsidian in the middle',
|
||||||
const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0))
|
bottomLeft: new Vec3(2, 1, 1),
|
||||||
expect(portals).toEqual([])
|
direction: new Vec3(1, 0, 0),
|
||||||
|
width: 5,
|
||||||
|
height: 5,
|
||||||
|
additionalAir: [],
|
||||||
|
additionalObsidian: [new Vec3(4, 3, 1)]
|
||||||
|
})
|
||||||
|
|
||||||
|
portalData.forEach(({name, bottomLeft, direction, width, height, additionalAir, additionalObsidian}) => {
|
||||||
|
const portal = generatePortal(bottomLeft, direction, width, height)
|
||||||
|
const {bottom, right, top} = portal
|
||||||
|
describe("doesn't detect detect " + name, () => {
|
||||||
|
let world
|
||||||
|
beforeAll(async function () {
|
||||||
|
world = await makeWorldWithPortal(portal, additionalAir, additionalObsidian)
|
||||||
})
|
})
|
||||||
test("doesn't detect portals from top left", async () => {
|
|
||||||
const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0))
|
describe("doesn't detect portals", () => {
|
||||||
expect(portals).toEqual([])
|
test("doesn't detect portals from bottom left", async () => {
|
||||||
})
|
const portals = await detectFrame(world, bottom[0], new Vec3(0, 1, 0))
|
||||||
test("doesn't detect portals from right top", async () => {
|
expect(portals).toEqual([])
|
||||||
const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1))
|
})
|
||||||
expect(portals).toEqual([])
|
test("doesn't detect portals from top left", async () => {
|
||||||
|
const portals = await detectFrame(world, top[0], new Vec3(0, -1, 0))
|
||||||
|
expect(portals).toEqual([])
|
||||||
|
})
|
||||||
|
test("doesn't detect portals from right top", async () => {
|
||||||
|
const portals = await detectFrame(world, right[right.length - 1], direction.scaled(-1))
|
||||||
|
expect(portals).toEqual([])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,45 @@ const squid = require('flying-squid')
|
||||||
|
|
||||||
const settings = require('../config/default-settings')
|
const settings = require('../config/default-settings')
|
||||||
|
|
||||||
describe('server', () => {
|
const { firstVersion, lastVersion } = require('./common/parallel')
|
||||||
let serv
|
|
||||||
|
|
||||||
beforeAll(done => {
|
squid.supportedVersions.forEach((supportedVersion, i) => {
|
||||||
const options = settings
|
if (!(i >= firstVersion && i <= lastVersion)) {
|
||||||
options['online-mode'] = false
|
return
|
||||||
options['port'] = 25566
|
}
|
||||||
options['view-distance'] = 2
|
|
||||||
options['worldFolder'] = undefined
|
|
||||||
options['logging'] = false
|
|
||||||
serv = squid.createMCServer(options)
|
|
||||||
|
|
||||||
serv.on('listening', () => {
|
const mcData = require('minecraft-data')(supportedVersion)
|
||||||
done()
|
const version = mcData.version
|
||||||
|
|
||||||
|
describe(`simple server ${version.minecraftVersion}`, () => {
|
||||||
|
let serv
|
||||||
|
|
||||||
|
beforeAll(done => {
|
||||||
|
const options = settings
|
||||||
|
options['online-mode'] = false
|
||||||
|
options['port'] = 0
|
||||||
|
options['view-distance'] = 2
|
||||||
|
options['worldFolder'] = undefined
|
||||||
|
options['logging'] = false
|
||||||
|
options['version'] = version.minecraftVersion
|
||||||
|
serv = squid.createMCServer(options)
|
||||||
|
|
||||||
|
serv.on('listening', () => {
|
||||||
|
done()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(done => {
|
afterAll(done => {
|
||||||
serv._server.close()
|
serv._server.close()
|
||||||
serv._server.on('close', () => {
|
serv._server.on('close', () => {
|
||||||
done()
|
done()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
test('is running', done => {
|
test('is running', done => {
|
||||||
const client = net.Socket()
|
const client = net.Socket()
|
||||||
client.connect(serv._server.socketServer.address().port, '127.0.0.1', done)
|
client.connect(serv._server.socketServer.address().port, '127.0.0.1', done)
|
||||||
client.on('error', done)
|
client.on('error', done)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue