this repo has no description
1import mc from "minecraft-protocol";
2
3type Player = {
4 uuid: string;
5 name: string;
6 properties?: Record<string, unknown>;
7 listed?: boolean;
8 latency?: number;
9 gameMode?: number;
10};
11
12const TARGET_HOST = "localhost";
13const TARGET_PORT = 25566;
14const MINECRAFT_VERSION = "1.20.4";
15
16const roster = new Map<string, Player>();
17
18const client = mc.createClient({
19 host: TARGET_HOST,
20 port: TARGET_PORT,
21 username: "hepticWarbler",
22 version: MINECRAFT_VERSION,
23 keepAlive: true,
24 auth: "offline",
25});
26
27client.on("login", () => {
28 console.log("✅ Joined server, tracking player list…");
29});
30
31client.on("packet", (data, meta) => {
32 if (meta.state !== "play") return;
33
34 switch (meta.name) {
35 case "player_info": {
36 const action = data.action;
37 for (const item of data.data) {
38 const uuid = item.UUID ?? item.uuid;
39 const name = item.name ?? item.username ?? "";
40 const entry = roster.get(uuid) ?? { uuid, name };
41
42 if (action === 0) {
43 roster.set(uuid, { ...entry, name });
44 console.log(`➕ join: ${name} (${uuid})`);
45 } else if (action === 1) {
46 roster.set(uuid, { ...entry, gameMode: item.gamemode });
47 } else if (action === 2) {
48 roster.set(uuid, { ...entry, latency: item.ping });
49 } else if (action === 4) {
50 roster.delete(uuid);
51 console.log(`➖ leave: ${name} (${uuid})`);
52 }
53 }
54 break;
55 }
56 case "player_info_update": {
57 const actions: string[] = data.actions;
58 for (const v of data.values) {
59 const uuid: string = v.uuid;
60 const prev = roster.get(uuid);
61 let name = prev?.name ?? v.name ?? v.profile?.name ?? "";
62 let listed = prev?.listed;
63
64 if (actions.includes("add_player")) {
65 name = v.name ?? name;
66 listed = true;
67 roster.set(uuid, {
68 uuid,
69 name,
70 listed,
71 properties: v.properties,
72 latency: v.latency,
73 gameMode: v.gamemode,
74 });
75 console.log(`➕ join: ${name} (${uuid})`);
76 }
77 if (actions.includes("update_latency")) {
78 roster.set(uuid, { ...(prev ?? { uuid, name }), latency: v.latency });
79 }
80 if (actions.includes("update_gamemode")) {
81 roster.set(uuid, {
82 ...(prev ?? { uuid, name }),
83 gameMode: v.gamemode,
84 });
85 }
86 if (actions.includes("remove_player")) {
87 roster.delete(uuid);
88 console.log(`➖ leave: ${name} (${uuid})`);
89 }
90 }
91 break;
92 }
93 }
94});
95
96setInterval(() => {
97 const players = Array.from(roster.values());
98 console.log("\n📋 Current players:", players.length);
99 players.forEach((p) => {
100 console.log(
101 ` - ${p.name} (${p.uuid}) | ping: ${p.latency}ms | mode: ${p.gameMode}`,
102 );
103 });
104 console.log("");
105}, 10000);
106
107client.on("error", (err) => {
108 console.error("❌ client error:", err);
109});
110
111client.on("end", (reason) => {
112 console.log("🔌 Disconnected:", reason);
113});