2018-05-13 16:50:16 -04:00
/* eslint-env mocha */
2015-10-01 20:02:54 -04:00
2018-05-13 16:50:16 -04:00
const mc = require ( '../' )
const assert = require ( 'power-assert' )
2021-05-01 19:12:37 -04:00
const { once } = require ( 'events' )
2017-05-09 20:49:13 -04:00
2021-06-28 22:58:21 -04:00
const { getPort } = require ( './common/util' )
2020-06-23 10:52:18 -04:00
const w = {
piglin _safe : {
type : 'byte' ,
value : 0
} ,
natural : {
type : 'byte' ,
value : 1
} ,
ambient _light : {
type : 'float' ,
value : 0
} ,
infiniburn : {
type : 'string' ,
value : 'minecraft:infiniburn_overworld'
} ,
respawn _anchor _works : {
type : 'byte' ,
value : 0
} ,
has _skylight : {
type : 'byte' ,
value : 1
} ,
bed _works : {
type : 'byte' ,
value : 1
} ,
has _raids : {
type : 'byte' ,
value : 1
} ,
name : {
type : 'string' ,
value : 'minecraft:overworld'
} ,
logical _height : {
type : 'int' ,
value : 256
} ,
shrunk : {
type : 'byte' ,
value : 0
} ,
ultrawarm : {
type : 'byte' ,
value : 0
} ,
has _ceiling : {
type : 'byte' ,
value : 0
}
}
2015-10-01 20:02:54 -04:00
2021-06-12 22:54:16 -04:00
for ( const supportedVersion of mc . supportedVersions ) {
2021-06-28 22:58:21 -04:00
let PORT
2018-05-13 16:50:16 -04:00
const mcData = require ( 'minecraft-data' ) ( supportedVersion )
const version = mcData . version
describe ( 'mc-server ' + version . minecraftVersion , function ( ) {
2021-06-28 22:58:21 -04:00
this . beforeAll ( async function ( ) {
PORT = await getPort ( )
console . log ( ` Using port for tests: ${ PORT } ` )
} )
2018-05-13 16:50:16 -04:00
this . timeout ( 5000 )
it ( 'starts listening and shuts down cleanly' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
let listening = false
server . on ( 'listening' , function ( ) {
listening = true
server . close ( )
} )
server . on ( 'close' , function ( ) {
assert . ok ( listening )
done ( )
} )
} )
it ( 'kicks clients that do not log in' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
kickTimeout : 100 ,
checkTimeoutInterval : 10 ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
let count = 2
server . on ( 'connection' , function ( client ) {
client . on ( 'end' , function ( reason ) {
2020-12-05 10:52:36 -05:00
assert . strictEqual ( reason , 'LoginTimeout' )
2018-05-13 16:50:16 -04:00
server . close ( )
} )
} )
server . on ( 'close' , function ( ) {
resolve ( )
} )
server . on ( 'listening' , function ( ) {
const client = new mc . Client ( false , version . minecraftVersion )
client . on ( 'end' , function ( ) {
resolve ( )
} )
client . connect ( PORT , '127.0.0.1' )
} )
2015-10-01 20:02:54 -04:00
2018-05-13 16:50:16 -04:00
function resolve ( ) {
count -= 1
if ( count <= 0 ) done ( )
2015-10-01 20:02:54 -04:00
}
2018-05-13 16:50:16 -04:00
} )
it ( 'kicks clients that do not send keepalive packets' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
kickTimeout : 100 ,
checkTimeoutInterval : 10 ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
let count = 2
server . on ( 'connection' , function ( client ) {
client . on ( 'end' , function ( reason ) {
2020-12-05 10:52:36 -05:00
assert . strictEqual ( reason , 'KeepAliveTimeout' )
2018-05-13 16:50:16 -04:00
server . close ( )
} )
} )
server . on ( 'close' , function ( ) {
resolve ( )
} )
server . on ( 'listening' , function ( ) {
2017-07-13 08:03:52 -04:00
const client = mc . createClient ( {
2015-10-01 20:02:54 -04:00
username : 'superpants' ,
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
port : PORT ,
2015-10-01 20:02:54 -04:00
keepAlive : false ,
2016-02-18 18:48:39 -05:00
version : version . minecraftVersion
2018-05-13 16:50:16 -04:00
} )
client . on ( 'end' , function ( ) {
resolve ( )
} )
} )
function resolve ( ) {
count -= 1
if ( count <= 0 ) done ( )
2015-10-01 20:02:54 -04:00
}
2018-05-13 16:50:16 -04:00
} )
it ( 'responds to ping requests' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
motd : 'test1234' ,
'max-players' : 120 ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
server . on ( 'listening' , function ( ) {
2015-10-01 20:02:54 -04:00
mc . ping ( {
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} , function ( err , results ) {
if ( err ) return done ( err )
assert . ok ( results . latency >= 0 )
assert . ok ( results . latency <= 1000 )
delete results . latency
2015-10-01 20:02:54 -04:00
assert . deepEqual ( results , {
version : {
name : version . minecraftVersion ,
protocol : version . version
} ,
players : {
max : 120 ,
online : 0 ,
sample : [ ]
} ,
2018-09-24 16:07:34 -04:00
description : { text : 'test1234' }
2018-05-13 16:50:16 -04:00
} )
server . close ( )
} )
} )
server . on ( 'close' , done )
} )
it ( 'clients can log in and chat' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
const username = [ 'player1' , 'player2' ]
let index = 0
server . on ( 'login' , function ( client ) {
assert . notEqual ( client . id , null )
assert . strictEqual ( client . username , username [ index ++ ] )
broadcast ( client . username + ' joined the game.' )
client . on ( 'end' , function ( ) {
broadcast ( client . username + ' left the game.' , client )
if ( client . username === 'player2' ) server . close ( )
} )
2020-10-06 16:46:53 -04:00
const loginPacket = {
2015-10-01 20:02:54 -04:00
entityId : client . id ,
levelType : 'default' ,
gameMode : 1 ,
2021-06-28 18:27:37 -04:00
previousGameMode : version . version >= 755 ? 0 : 255 ,
2020-06-23 10:52:18 -04:00
worldNames : [ 'minecraft:overworld' ] ,
2021-06-28 18:27:37 -04:00
dimensionCodec : version . version >= 755 ? mcData . loginPacket . dimensionCodec : ( version . version >= 735 ? mcData . loginPacket . dimension : { name : '' , type : 'compound' , value : { dimension : { type : 'list' , value : { type : 'compound' , value : [ w ] } } } } ) ,
2020-10-06 16:46:53 -04:00
dimension : ( version . version >= 735 ? mcData . loginPacket . dimension : 0 ) ,
2020-06-23 10:52:18 -04:00
worldName : 'minecraft:overworld' ,
2019-12-29 17:27:04 -05:00
hashedSeed : [ 0 , 0 ] ,
2015-10-01 20:02:54 -04:00
difficulty : 2 ,
maxPlayers : server . maxPlayers ,
2020-10-06 16:46:53 -04:00
reducedDebugInfo : ( version . version >= 735 ? false : 0 ) ,
2019-12-29 17:27:04 -05:00
enableRespawnScreen : true
2020-10-06 16:46:53 -04:00
}
if ( version . version >= 735 ) { // 1.16x
loginPacket . isDebug = false
loginPacket . isFlat = false
loginPacket . isHardcore = false
loginPacket . viewDistance = 10
delete loginPacket . levelType
delete loginPacket . difficulty
}
client . write ( 'login' , loginPacket )
2018-05-13 16:50:16 -04:00
client . on ( 'chat' , function ( packet ) {
const message = '<' + client . username + '>' + ' ' + packet . message
broadcast ( message )
} )
} )
server . on ( 'close' , done )
server . on ( 'listening' , function ( ) {
2017-07-13 08:03:52 -04:00
const player1 = mc . createClient ( {
2015-10-01 20:02:54 -04:00
username : 'player1' ,
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
player1 . on ( 'login' , function ( packet ) {
assert . strictEqual ( packet . gameMode , 1 )
player1 . once ( 'chat' , function ( packet ) {
assert . strictEqual ( packet . message , '{"text":"player2 joined the game."}' )
player1 . once ( 'chat' , function ( packet ) {
assert . strictEqual ( packet . message , '{"text":"<player2> hi"}' )
player2 . once ( 'chat' , fn )
function fn ( packet ) {
if ( /<player2>/ . test ( packet . message ) ) {
player2 . once ( 'chat' , fn )
return
2015-10-01 20:02:54 -04:00
}
2018-05-13 16:50:16 -04:00
assert . strictEqual ( packet . message , '{"text":"<player1> hello"}' )
player1 . once ( 'chat' , function ( packet ) {
assert . strictEqual ( packet . message , '{"text":"player2 left the game."}' )
player1 . end ( )
} )
player2 . end ( )
2015-10-01 20:02:54 -04:00
}
2018-09-24 16:07:34 -04:00
player1 . write ( 'chat' , { message : 'hello' } )
2018-05-13 16:50:16 -04:00
} )
2018-09-24 16:07:34 -04:00
player2 . write ( 'chat' , { message : 'hi' } )
2018-05-13 16:50:16 -04:00
} )
2017-07-13 08:03:52 -04:00
const player2 = mc . createClient ( {
2015-10-01 20:02:54 -04:00
username : 'player2' ,
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
} )
} )
2015-10-01 20:02:54 -04:00
2018-05-13 16:50:16 -04:00
function broadcast ( message , exclude ) {
let client
for ( const clientId in server . clients ) {
2019-08-03 19:29:14 -04:00
if ( server . clients [ clientId ] === undefined ) continue
2015-10-01 20:02:54 -04:00
2018-05-13 16:50:16 -04:00
client = server . clients [ clientId ]
2020-06-23 10:52:18 -04:00
if ( client !== exclude ) client . write ( 'chat' , { message : JSON . stringify ( { text : message } ) , position : 0 , sender : '0' } )
2015-10-01 20:02:54 -04:00
}
}
2018-05-13 16:50:16 -04:00
} )
it ( 'kicks clients when invalid credentials' , function ( done ) {
this . timeout ( 10000 )
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
let count = 4
server . on ( 'connection' , function ( client ) {
client . on ( 'end' , function ( reason ) {
resolve ( )
server . close ( )
} )
} )
server . on ( 'close' , function ( ) {
resolve ( )
} )
server . on ( 'listening' , function ( ) {
resolve ( )
2017-07-13 08:03:52 -04:00
const client = mc . createClient ( {
2015-10-01 20:02:54 -04:00
username : 'lalalal' ,
2018-05-13 16:50:16 -04:00
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
client . on ( 'end' , function ( ) {
resolve ( )
} )
} )
function resolve ( ) {
count -= 1
if ( count <= 0 ) done ( )
2015-10-01 20:02:54 -04:00
}
2018-05-13 16:50:16 -04:00
} )
it ( 'gives correct reason for kicking clients when shutting down' , function ( done ) {
2017-07-13 08:03:52 -04:00
const server = mc . createServer ( {
2015-10-01 20:02:54 -04:00
'online-mode' : false ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
let count = 2
server . on ( 'login' , function ( client ) {
client . on ( 'end' , function ( reason ) {
2020-12-05 10:52:36 -05:00
assert . strictEqual ( reason , 'ServerShutdown' )
2018-05-13 16:50:16 -04:00
resolve ( )
} )
2020-10-06 16:46:53 -04:00
const loginPacket = {
2015-10-01 20:02:54 -04:00
entityId : client . id ,
levelType : 'default' ,
gameMode : 1 ,
2021-06-28 18:27:37 -04:00
previousGameMode : version . version >= 755 ? 0 : 255 ,
2020-06-23 10:52:18 -04:00
worldNames : [ 'minecraft:overworld' ] ,
2021-06-28 18:27:37 -04:00
dimensionCodec : version . version >= 755 ? mcData . loginPacket . dimensionCodec : ( version . version >= 735 ? mcData . loginPacket . dimension : { name : '' , type : 'compound' , value : { dimension : { type : 'list' , value : { type : 'compound' , value : [ w ] } } } } ) ,
2020-10-06 16:46:53 -04:00
dimension : ( version . version >= 735 ? mcData . loginPacket . dimension : 0 ) ,
2020-06-23 10:52:18 -04:00
worldName : 'minecraft:overworld' ,
2019-12-29 17:27:04 -05:00
hashedSeed : [ 0 , 0 ] ,
2015-10-01 20:02:54 -04:00
difficulty : 2 ,
maxPlayers : server . maxPlayers ,
2020-10-06 16:46:53 -04:00
reducedDebugInfo : ( version . version >= 735 ? false : 0 ) ,
2019-12-29 17:27:04 -05:00
enableRespawnScreen : true
2020-10-06 16:46:53 -04:00
}
if ( version . version >= 735 ) { // 1.16x
loginPacket . isDebug = false
loginPacket . isFlat = false
loginPacket . isHardcore = false
loginPacket . viewDistance = 10
delete loginPacket . levelType
delete loginPacket . difficulty
}
client . write ( 'login' , loginPacket )
2018-05-13 16:50:16 -04:00
} )
server . on ( 'close' , function ( ) {
resolve ( )
} )
server . on ( 'listening' , function ( ) {
2017-07-13 08:03:52 -04:00
const client = mc . createClient ( {
2015-10-01 20:02:54 -04:00
username : 'lalalal' ,
host : '127.0.0.1' ,
2016-02-23 13:37:47 -05:00
version : version . minecraftVersion ,
2018-05-13 16:50:16 -04:00
port : PORT
} )
client . on ( 'login' , function ( ) {
server . close ( )
} )
} )
function resolve ( ) {
count -= 1
if ( count <= 0 ) done ( )
2015-10-01 20:02:54 -04:00
}
2018-05-13 16:50:16 -04:00
} )
2021-05-01 19:12:37 -04:00
it ( 'encodes chat packet once and send it to two clients' , function ( done ) {
const server = mc . createServer ( {
'online-mode' : false ,
version : version . minecraftVersion ,
port : PORT
} )
server . on ( 'login' , function ( client ) {
const loginPacket = {
entityId : client . id ,
levelType : 'default' ,
gameMode : 1 ,
2021-06-28 18:27:37 -04:00
previousGameMode : version . version >= 755 ? 0 : 255 ,
2021-05-01 19:12:37 -04:00
worldNames : [ 'minecraft:overworld' ] ,
2021-06-28 18:27:37 -04:00
dimensionCodec : version . version >= 755 ? mcData . loginPacket . dimensionCodec : ( version . version >= 735 ? mcData . loginPacket . dimension : { name : '' , type : 'compound' , value : { dimension : { type : 'list' , value : { type : 'compound' , value : [ w ] } } } } ) ,
2021-05-01 19:12:37 -04:00
dimension : ( version . version >= 735 ? mcData . loginPacket . dimension : 0 ) ,
worldName : 'minecraft:overworld' ,
hashedSeed : [ 0 , 0 ] ,
difficulty : 2 ,
maxPlayers : server . maxPlayers ,
reducedDebugInfo : ( version . version >= 735 ? false : 0 ) ,
enableRespawnScreen : true
}
if ( version . version >= 735 ) { // 1.16x
loginPacket . isDebug = false
loginPacket . isFlat = false
loginPacket . isHardcore = false
loginPacket . viewDistance = 10
delete loginPacket . levelType
delete loginPacket . difficulty
}
client . write ( 'login' , loginPacket )
} )
server . on ( 'close' , done )
server . on ( 'listening' , async function ( ) {
const player1 = mc . createClient ( {
username : 'player1' ,
host : '127.0.0.1' ,
version : version . minecraftVersion ,
port : PORT
} )
const player2 = mc . createClient ( {
username : 'player2' ,
host : '127.0.0.1' ,
version : version . minecraftVersion ,
port : PORT
} )
await Promise . all ( [ once ( player1 , 'login' ) , once ( player2 , 'login' ) ] )
server . writeToClients ( Object . values ( server . clients ) , 'chat' , { message : JSON . stringify ( { text : 'A message from the server.' } ) , position : 1 , sender : '00000000-0000-0000-0000-000000000000' } )
let results = await Promise . all ( [ once ( player1 , 'chat' ) , once ( player2 , 'chat' ) ] )
results . forEach ( res => assert . strictEqual ( res [ 0 ] . message , '{"text":"A message from the server."}' ) )
player1 . end ( )
player2 . end ( )
await Promise . all ( [ once ( player1 , 'end' ) , once ( player2 , 'end' ) ] )
server . close ( )
} )
} )
2018-05-13 16:50:16 -04:00
} )
2021-06-12 22:54:16 -04:00
}