PrismarineJS / PrismarineJS/node-minecraft-protocol
Deserialization Error as Client
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 1.4k
- Forks
- 290
- Avg merge
- 4d 8h
- Merged PRs (30d)
- 7
Description
[ ] The FAQ doesn't contain a resolution to my issue
Versions
- minecraft-protocol: 1.13.0
- server: vanilla/spigot/paper 1.16.1
- node: 12.16.0
Detailed description of a problem
Got a type error while other player flaying over a jungle biome
Current code
import { Client, createClient } from 'minecraft-protocol';
import { IPacketMessage } from '../models/IPacketMessage';
import { IPacket } from '../models/IPacket';
import { ETranslate } from '../models/ETranslate';
import { MC_CLIENT } from '../config/config'
import * as axios from '../services/axios';
import { ITp } from '../models/ITp';
import { IUser } from '../models/IUser';
import { ICoordinates } from '../models/ICoordinates';
let tpDB: Array<ITp>;
let userDB: Array<IUser>;
let ops: Array<string>;
let timer: NodeJS.Timeout;
const dimensions: Array<string> = [
'overworld',
'the_nether',
'the_end'
];
/**
* Checks if the dimension exists.
* @param dimension the name of the dimension.
*/
const checkDimension = (dimension: string): number => {
switch (dimension) {
case 'OVERWORLD':
return 0;
case 'NETHER':
return 1;
case 'END':
return 2;
default:
return -1;
}
}
/**
* Load all databases necesary for the commands.
*/
const loadDBs = async (): Promise<void> => {
tpDB = await axios.getTps();
userDB = await axios.getUsers();
ops = await axios.getOps();
}
/**
* Checks if a user is an OP.
* @param username The name of the user to check.
*/
const isOp = (username: string): boolean => {
return username in ops;
}
/**
* Add an user to the OP list.
* @param op The name of the user adding new OP.
* @param newop The name of the new OP user.
* @returns `-1` if the user adding is not OP, `0` if the added user is already an OP, `1` if new user added.
*/
const addOp = (op: string, newop: string): number => {
if (!isOp(op)) {
return -1;
}
if (isOp(newop)) {
return 0;
}
ops.push(newop);
return 1;
}
/**
* Adds a set amount of points to a scoreboard every certain time.
* @param sbname Name of the scoreboard.
* @param points Amount of points to add.
* @param time The time between each adition.
*/
const startTimer = (sbname: string, points: number = 500, time: number = 3600000): void => {
timer = setInterval(() => {
write(`/scoreboard players add @a[name=!"${MC_CLIENT.username}"] ${sbname} ${points}`);
write(`/tellraw @a [{"text":"[${MC_CLIENT.username}] ", "color":"gold"}, {"text":"Free Money Hour", "color":"gray"}]`);
}, time);
}
const client: Client = createClient(MC_CLIENT);
/**
* Basic chat message writer.
* @param msg The message or messages to send to chat.
*/
const write = (msg: Array<string> | string): void => {
if (msg instanceof Array) {
for (const m of msg) {
client.write('chat', { message: m });
}
} else {
client.write('chat', { message: msg });
}
}
client.on('success', (user): void => {
// console.log(user);
console.log('connected!');
startTimer('Money');
// read db here
// loadDBs();
});
client.on('chat', (packet: IPacket): void => {
// Listen for chat messages and echo them back.
// console.log(packet)
const jsonMsg: IPacketMessage = JSON.parse(packet.message);
const msgWith: Array<any> = jsonMsg.with;
if (!msgWith) return;
console.log(JSON.stringify(jsonMsg, null, 2));
// console.log(jsonMsg)
// console.log(msgWith);
const username: string = msgWith[0].text || msgWith[0].insertion;
const tl: string = jsonMsg.translate;
// console.log(tl === ETranslate.TEXT)
let msg = '';
if (!username) return;
if (username === client.username || username === 'Server') return;
// console.log(username);
switch (true) {
case (tl === ETranslate.TEXT):
msg = msgWith[1];
break;
case (tl === ETranslate.INCOMING):
msg = msgWith[1].text;
break;
default: return;
}
// console.log('m:', msg, 'u:', username);
if (msg.length < 1) return;
if (msg[0] !== '!') return;
let args: Array<string> = msg.slice(1).split(' ');
let cmd: string = args[0];
args = args.slice(1);
console.log(cmd, args);
let response;
switch (cmd) {
case 'init':
/* check for op */
break;
case 'register':
// db.push()
const rind = userDB.findIndex((u: IUser) => u.username === username);
if (rind > -1) {
write(`/tell ${username} You are already registered`);
return;
}
write([
`/tell ${username} Registered!`,
`/tell ${username} Here is some money to start`,
`/scoreboard players add ${username} Money 1000`
]);
break;
case 'tp':
response = '';
const name = args[0].toUpperCase();
const uind = userDB.findIndex((u: IUser) => u.username === username);
if (uind < 0) {
write(`/tell ${username} Use '!register' to use this command`);
return;
}
const d = args[1].toUpperCase();
const id = checkDimension(d);
if (id < 0) {
write(`/tell ${username} Dimension '${d}' does not exists`)
return;
}
const dn = dimensions[id];
const tpind = userDB[uind].tp.findIndex((tp: ITp) =>
tp.name === name && tp.dimension === dn);
switch (args.length) {
case 1:
// do tp if exists//
if (tpind < 0) {
response = `/tell ${username} tp '${name}' in dimension '${d}' not registered`;
break;
}
const tp = userDB[uind].tp[tpind].coordinates;
// response = `/tp ${username} ${tp.x} ${tp.y} ${tp.z}`;
response = `/execute in ${dn} run tp ${username} ${tp.x} ${tp.y} ${tp.z}`;
break;
case 5:
// store tp //
const cx = parseInt(args[1]);
const cy = parseInt(args[2]);
const cz = parseInt(args[3]);
if (isNaN(cx) || isNaN(cy) || isNaN(cz)) {
response = `/tell ${username} X Y Z values must be numeric integers`;
break;
}
if (tpind < 0) {
userDB[uind].tp.push({
name: name,
dimension: dn,
coordinates: {
x: cx,
y: cy,
z: cz
}
});
response = `/tell ${username} tp '${name}' in dimension '${d}' created`;
} else {
userDB[uind].tp[tpind].coordinates = {
x: cx,
y: cy,
z: cz
};
response = `/tell ${username} tp '${name}' in dimension '${d}' updated`;
}
// console.log('good')
break;
default:
response = `/tell ${username} Wrong arguments, use !tp <name> <overworld|nether|end> [<x> <y> <z>]`;
break;
}
// console.log('command pos')
write(response);
break;
case 'gtp':
response = '';
const nameg = args[0].toUpperCase();
const dg = args[1].toUpperCase();
const idg = checkDimension(dg);
if (idg < 0) {
write(`/tell ${username} Dimension '${dg}' does not exists`);
return;
}
const dng = dimensions[idg];
const ind = tpDB.findIndex((tp: ITp) =>
tp.name === nameg && tp.dimension === dng);
switch (args.length) {
case 1:
// do tp if exists//
if (ind < 0) {
response = `/tell ${username} tp '${nameg}' on dimension '${dg}' does not exists`
break;
};
const tpg = tpDB[ind].coordinates;
// response = `/tp ${username} ${tpg.x} ${tpg.y} ${tpg.z}`;
response = `/execute in ${dng} run tp ${username} ${tpg.x} ${tpg.y} ${tpg.z}`;
break;
case 5:
// store / update global tp //
const cxg = parseInt(args[2]);
const cyg = parseInt(args[3]);
const czg = parseInt(args[4]);
if (isNaN(cxg) || isNaN(cyg) || isNaN(czg)) {
response = `/tell ${username} X Y Z values must be numeric integers`;
break;
}
if (ind < 0) {
tpDB.push({
name: nameg,
dimension: dng,
coordinates: {
x: cxg,
y: cyg,
z: czg
}
});
// response = `/tell ${username} tp '${nameg}' created`;
response = `Global tp '${nameg}' on dimension '${dg}' created`;
} else {
tpDB[ind].coordinates = {
x: cxg,
y: cyg,
z: czg
};
// response = `/tell ${username} tp '${nameg}' updated`;
response = `Global tp '${nameg}' on dimension '${dg}' updated`;
}
// console.log('good')
break;
default:
response = `/tell ${username} Wrong arguments: !tpg <name> <overworld|nether|end> [ <x> <y> <z> ]`;
break;
}
if (response.length === 0) return;
write(response);
break;
case 'disconnect':
/* check for op */
if (username !== 'arceus6666') break;
write('Disconnecting');
setTimeout(() => {
client.end('op close');
}, 5000);
break;
case 'print':
console.log(jsonMsg);
break;
case 'packet':
console.log(packet);
break;
case 'env':
console.log(process.env);
case 'test':
write('testing');
break;
default:
write(`/tell ${username} Unknown command, use !list or !help for more details`);
break;
}
});
client.on('end', (reason) => {
console.log('something:', reason);
clearInterval(timer);
process.exit(0)
});
Expected behavior
Client stay logged in
Additional context
TypeError: Deserialization error for play.toClient : Read error for undefined : Cannot destructure property 'value' of 'ctx.entityMetadataItem(...)' as it is undefined.
at eval (eval at compile (\girabot\node_modules\protodef\src\compiler.js:243:12), :199:24)
at Object.entityMetadata (eval at compile (r\girabot\node_modules\protodef\src\compiler.js:243:12), :201:9)
at Object.packet_entity_metadata (eval at compile (\girabot\node_modules\protodef\src\compiler.js:243:12), :1392:75)
at eval (eval at compile (\girabot\node_modules\protodef\src\compiler.js:243:12), :1947:70)
at packet (eval at compile (\girabot\node_modules\protodef\src\compiler.js:243:12), :1974:9)
at CompiledProtodef.read (\girabot\node_modules\protodef\src\compiler.js:64:12)
at e.message (\girabot\node_modules\protodef\src\compiler.js:99:49)
at tryCatch (\girabot\node_modules\protodef\src\utils.js:50:16)
at CompiledProtodef.parsePacketBuffer (\girabot\node_modules\protodef\src\compiler.js:99:29)
at FullPacketParser.parsePacketBuffer (\girabot\node_modules\protodef\src\serializer.js:68:23)
Emitted 'error' event on Client instance at:
at FullPacketParser. (\girabot\node_modules\minecraft-protocol\src\client.js:77:12)
eam_writable.js:160:5)
at FullPacketParser.afterTransform (\girabot\node_modules\readable-stream\lib_stream_transform.js:89:3)
at FullPacketParser._transform (\girabot\node_modules\protodef\src\serializer.js:80:14)
at FullPacketParser.Transform._read (\girabot\node_modules\readable-stream\lib_stream_transform.js:177:10)
at FullPacketParser.Transform._write (\girabot\node_modules\readable-stream\lib_stream_transform.js:164:83) {
field: 'play.toClient'
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the failure with minecraft-protocol 1.13.0, Node 12.16.0, and a 1.16.1 vanilla, Spigot, or Paper server. Start at the packet_entity_metadata and entityMetadata stack frames, then inspect src/client.js where the parser error is emitted. Done means the client stays logged in when another player flies over a jungle biome without this deserialization error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100