PrismarineJS / node-minecraft-protocol

Parse and serialize minecraft packets, plus authentication and encryption.
https://prismarinejs.github.io/node-minecraft-protocol/
BSD 3-Clause "New" or "Revised" License
1.2k stars 241 forks source link

"Chunk size is 42 but only 2 was read" error #1279

Open ImAhmadAbdullah opened 6 months ago

ImAhmadAbdullah commented 6 months ago

[ ] The FAQ doesn't contain a resolution to my issue

Versions

Detailed description of a problem

Missing characters in string, found size is 3 expected size was 50 The error got in Minecraft: Internal Exception: io.netty.handler.codec.DecoderException: net.minecraft.class_8911: Loading NBT data. The error is random and I am failing to debug or reproduce. Full error:

PartialReadError: Read error for undefined : Missing characters in string, found size is 3 expected size was 50
    at new ExtendableError (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/utils.js:63:13)
    at new PartialReadError (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/utils.js:70:5)
    at Object.string (eval at compile (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:258:12), <anonymous>:91:15)
    at Object.packet_set_protocol (eval at compile (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:258:12), <anonymous>:712:69)
    at eval (eval at compile (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:258:12), <anonymous>:728:64)
    at packet (eval at compile (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:258:12), <anonymous>:732:9)
    at CompiledProtodef.read (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:70:12)
    at e.message (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:111:49)
    at tryCatch (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/utils.js:50:16)
    at CompiledProtodef.parsePacketBuffer (/root/QbastyBots/OpenAnarchy/node_modules/.pnpm/protodef@1.15.0/node_modules/protodef/src/compiler.js:111:29)
Chunk size is 42 but only 2 was read ; partial packet : {"name":96}; buffer :e00000000000436f6f6b69653a206d737473686173683d41646d696e697374720d0a0100080003000000
error: 02:01:2024|20:18:42:69108310 [object Object]

Current code

import sendLog from "./sendLog.js";
import requestMojang from "./requestMojang.js";
import { createServer } from "minecraft-protocol";
import { readFileSync } from "node:fs";
export default async function verifyServer(client) {
  const serverLogo = readFileSync("./images/server-icon.png", { encoding: "base64" });
  const { ip, port } = client.config.server;
  const server = createServer({
    host: ip,
    "online-mode": false,
    maxPlayers: new Date().getFullYear(),
    motd: client.config.server.motd,
    version: false,
    port: port,
    errorHandler: error => sendLog(error, client, 0),
    beforePing: response => {
      response.version.name = "";
      response.favicon = `data:image/png;base64,${serverLogo}`;
    },
  });
  sendLog(`[SERVER] Server started on ${ip}:${port}`, client, 1);
  server.on("login", async serverClient => {
    const code = await getCode(client, serverClient);
    serverClient.end(await codeCreatedMessage(client, code.code));
  });
}
async function getCode(client, serverClient) {
  const generateCode = () => Math.floor(1000 + Math.random() * 9000);
  const codeArray = (await client.db.get("codeArray")) || [];
  const currentDate = new Date();
  const validCodes = codeArray.filter(e => new Date(e.expiry) > currentDate);
  const { username } = serverClient;
  const existingCode = validCodes.find(e => e.username === username);
  let expiry;
  if (existingCode) {
    expiry = existingCode.expiry;
  } else {
    expiry = new Date(currentDate.getTime() + 5 * 60000);
    let code = generateCode();
    while (validCodes.some(e => e.code === code)) {
      code = generateCode();
    }
    const premium = (await requestMojang(username)) !== false;
    const time = formatUTCDate(expiry);
    const channel = client.channels.cache.get(client.config.discord.channel.logs);
    sendLog(
      `[SERVER] ${serverClient.username} has been given the code ${code} which expires at ${time}.`,
      client,
      1
    );
    await channel.send(
      `**${serverClient.username}** has been given the code **${code}** which expires at **${time}**.`
    );
    const newCode = { username, code, expiry, premium };
    await client.db.set("codeArray", [...validCodes, newCode]);
    return newCode;
  }
  await client.db.set("codeArray", validCodes);
  return existingCode;
}
function formatUTCDate(date) {
  const hours = date.getUTCHours();
  const minutes = date.getUTCMinutes();
  const ampm = hours >= 12 ? "PM" : "AM";
  const displayHours = hours % 12 || 12;
  return `${displayHours}:${String(minutes).padStart(2, "0")} ${ampm} (UTC)`;
}
const formatTime = milliseconds => {
  const seconds = Math.floor(milliseconds / 1000);
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const remainingSeconds = seconds % 60;
  const timeParts = [];
  if (hours > 0) timeParts.push(`${hours} ${hours === 1 ? "hour" : "hours"}`);
  if (minutes > 0) timeParts.push(`${minutes} ${minutes === 1 ? "minute" : "minutes"}`);
  if (remainingSeconds > 0 || (hours === 0 && minutes === 0)) {
    timeParts.push(`${remainingSeconds} ${remainingSeconds === 1 ? "second" : "seconds"}`);
  }
  return timeParts.join(", ");
};
const codeCreatedMessage = async (client, code) => {
  const codeArray = (await client.db.get("codeArray")) || [];
  const entry = codeArray.find(e => e.code === code);
  if (entry) {
    const expiry = new Date(entry.expiry);
    if (expiry instanceof Date) {
      const remainingTime = Math.max(0, expiry.getTime() - Date.now());
      const { title, lineone, linetwo, linethree, lineaftertime } = client.config.server;
      return `${title}\n\n${lineone}${code}\n\n${linetwo}#${
        client.channels.cache.get(client.config.discord.channel.verification)?.name
      }\n${linethree}${formatTime(remainingTime)}${lineaftertime}`;
    } else {
      const { title, linerror } = client.config.server;
      return `${title}\n\n${linerror}`;
    }
  } else {
    const { title, linerror } = client.config.server;
    return `${title}\n\n${linerror}`;
  }
};

Expected behavior

It should work normally without errors.

Additional context

Add any other context about the problem here.

extremeheat commented 6 months ago

What version? And is this server specific or not?

ImAhmadAbdullah commented 6 months ago

Could you explain what you mean by specific? And in the server I kick on join to verify people and allow all versions.

ImAhmadAbdullah commented 6 months ago

@Pandapip1 Please see this:

Chunk size is 42 but only 2 was read ; partial packet : {"name":96}; buffer :e00000000000436f6f6b69653a206d737473686173683d41646d696e697374720d0a0100080003000000

wgaylord commented 6 months ago

What MC version btw. If 1.20.2 going to probably want to replace login with playerJoin (it will work for older versions too ) since login is before all the config state stuff happens.

Pandapip1 commented 6 months ago

I am unaffiliated with this project. Please make sure you are using an up-to-date node-minecraft-protocol. That solved my inital issue, although I also encountered this roadblock.

vincss commented 4 months ago

What MC version btw. If 1.20.2 going to probably want to replace login with playerJoin (it will work for older versions too ) since login is before all the config state stuff happens.

Thanks ! I missed that information... Was it on a changelog or something like that ? Event login could be marked as depreciated.

wgaylord commented 4 months ago

The login event is still useful, but is fired when thr player logins in but before the transition to play state state happens, while playerJoin happens after the switch from configuration state to the play state. (And at every switch from config state to play)