mirror of
https://github.com/DeveloperExotic/LegacyCrossPlay.git
synced 2026-07-16 00:40:55 +00:00
Microslop authentication support
This commit is contained in:
BIN
.assets/crossplay2.png
Normal file
BIN
.assets/crossplay2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
node_modules/
|
||||
node_modules/
|
||||
.auth_cache/
|
||||
*.cache
|
||||
35
constants.js
35
constants.js
@@ -1,20 +1,21 @@
|
||||
/* --------------------------------------------------------------- */
|
||||
/* constants.js */
|
||||
/* --------------------------------------------------------------- */
|
||||
const GAME_PORT = 25565; //
|
||||
const WIN64_LAN_DISCOVERY_PORT = 25566; //
|
||||
const MINECRAFT_NET_VERSION = 560; //
|
||||
const JAVA_SERVER_HOST = "localhost"; // The java edition server host that the proxy will connect to.
|
||||
const JAVA_SERVER_PORT = 25564; // The java edition server port that the proxy will connect to (default is 25565).
|
||||
const PROXY_NAME = JAVA_SERVER_HOST + ":" + JAVA_SERVER_PORT; //
|
||||
module.exports = { //
|
||||
GAME_PORT, //
|
||||
WIN64_LAN_DISCOVERY_PORT, //
|
||||
MINECRAFT_NET_VERSION, //
|
||||
USE_LEGACY_USERNAME: false, // You can use your legacy edition username, or a custom username below.
|
||||
CUSTOM_USERNAME: "LCE_Player", // The custom username used if USE_LEGACY_USERNAME is false. Ensure it's UNDER 16 characters.
|
||||
JAVA_SERVER_HOST, //
|
||||
JAVA_SERVER_PORT, //
|
||||
PROXY_NAME, //
|
||||
}; //
|
||||
/* --------------------------------------------------------------- */
|
||||
const GAME_PORT = 25565;
|
||||
const WIN64_LAN_DISCOVERY_PORT = 25566;
|
||||
const MINECRAFT_NET_VERSION = 560;
|
||||
const JAVA_SERVER_HOST = "hypixel.net"; // The java edition server host that the proxy will connect to.
|
||||
const JAVA_SERVER_PORT = 25565; // The java edition server port that the proxy will connect to.
|
||||
const PROXY_NAME = JAVA_SERVER_HOST + ":" + JAVA_SERVER_PORT;
|
||||
module.exports = {
|
||||
GAME_PORT,
|
||||
WIN64_LAN_DISCOVERY_PORT,
|
||||
MINECRAFT_NET_VERSION,
|
||||
USE_JAVA_ACCOUNT: true, // Allows use of a microsoft java account for online servers. (Disable this if you don't own java - you'll only be able to connect to cracked/offline servers.)
|
||||
USE_LEGACY_USERNAME: false, // You can use your legacy edition username, or a custom username below. (offline servers only)
|
||||
CUSTOM_USERNAME: "LCE_Player", // The custom username used if USE_LEGACY_USERNAME is false. Ensure it's UNDER 16 characters. (offline servers only)
|
||||
JAVA_SERVER_HOST,
|
||||
JAVA_SERVER_PORT,
|
||||
PROXY_NAME,
|
||||
};
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
5
index.js
5
index.js
@@ -10,7 +10,10 @@ process.on("warning", (warning) => {
|
||||
const LCEProxy = require("./src/lceproxy");
|
||||
|
||||
const proxy = new LCEProxy();
|
||||
proxy.start();
|
||||
|
||||
(async () => {
|
||||
await proxy.start();
|
||||
})();
|
||||
|
||||
process.on("SIGINT", () => {
|
||||
proxy.stop();
|
||||
|
||||
3
package-lock.json
generated
3
package-lock.json
generated
@@ -9,7 +9,8 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minecraft-protocol": "^1.64.0"
|
||||
"minecraft-protocol": "^1.64.0",
|
||||
"prismarine-auth": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-common": {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minecraft-protocol": "^1.64.0"
|
||||
"minecraft-protocol": "^1.64.0",
|
||||
"prismarine-auth": "^2.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
92
src/auth.js
Normal file
92
src/auth.js
Normal file
@@ -0,0 +1,92 @@
|
||||
const { Authflow, Titles } = require("prismarine-auth");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const AUTH_CACHE_DIR = path.join(__dirname, "..", ".auth_cache");
|
||||
|
||||
class MicrosoftAuth {
|
||||
constructor() {
|
||||
this.authflow = null;
|
||||
this.authenticated = false;
|
||||
this.username = null;
|
||||
this.uuid = null;
|
||||
this.accessToken = null;
|
||||
}
|
||||
|
||||
ensureCacheDir() {
|
||||
if (!fs.existsSync(AUTH_CACHE_DIR)) {
|
||||
fs.mkdirSync(AUTH_CACHE_DIR, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
async authenticate() {
|
||||
this.ensureCacheDir();
|
||||
|
||||
if (!this.authflow) {
|
||||
const userIdentifier = "lce-proxy-user";
|
||||
this.authflow = new Authflow(userIdentifier, AUTH_CACHE_DIR);
|
||||
}
|
||||
|
||||
if (!this.authflow.onMsaCode) {
|
||||
this.authflow.onMsaCode = (data) => {
|
||||
console.log("\nYou have not yet logged into your Java account!");
|
||||
const url = `https://microsoft.com/link?otc=${data.userCode}`;
|
||||
console.log(`enter the code ${data.userCode} at ${url}`);
|
||||
console.log(
|
||||
"If you enabled this by accident and would like to only join offline servers, set USE_JAVA_ACCOUNT to false in constants.js\n",
|
||||
);
|
||||
|
||||
try {
|
||||
const { exec } = require("child_process");
|
||||
const platform = process.platform;
|
||||
const command =
|
||||
platform === "win32"
|
||||
? `start ${url}`
|
||||
: platform === "darwin"
|
||||
? `open ${url}`
|
||||
: `xdg-open ${url}`;
|
||||
exec(command);
|
||||
} catch (err) {
|
||||
/* do nothing */
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.authflow.getMinecraftJavaToken({
|
||||
fetchProfile: true,
|
||||
});
|
||||
|
||||
if (!result.profile) {
|
||||
throw new Error(
|
||||
"Error logging into Java Edition account! Do you own Minecraft Java Edition?\n",
|
||||
);
|
||||
}
|
||||
|
||||
this.username = result.profile.name;
|
||||
this.uuid = result.profile.id;
|
||||
this.accessToken = result.token;
|
||||
this.authenticated = true;
|
||||
|
||||
return {
|
||||
username: this.username,
|
||||
uuid: this.uuid,
|
||||
accessToken: this.accessToken,
|
||||
};
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async getAuthData() {
|
||||
return await this.authenticate();
|
||||
}
|
||||
|
||||
isAuthenticated() {
|
||||
return this.authenticated;
|
||||
}
|
||||
}
|
||||
|
||||
const authInstance = new MicrosoftAuth();
|
||||
|
||||
module.exports = authInstance;
|
||||
@@ -5,9 +5,11 @@ const mc = require("minecraft-protocol");
|
||||
const {
|
||||
JAVA_SERVER_HOST,
|
||||
JAVA_SERVER_PORT,
|
||||
USE_JAVA_ACCOUNT,
|
||||
USE_LEGACY_USERNAME,
|
||||
CUSTOM_USERNAME,
|
||||
} = require("../constants");
|
||||
const msAuth = require("./auth");
|
||||
const PacketWriter = require("./packetwriter");
|
||||
const { mapJavaItemToLCE, mapJavaBlockToLCE } = require("./mappings");
|
||||
const { mapJavaSoundToLCE } = require("./mappings/soundmapping");
|
||||
@@ -15,8 +17,8 @@ const { parseChatComponent } = require("./utils/chat");
|
||||
const { countSetBits, compressRLE } = require("./utils/chunk");
|
||||
const zlib = require("zlib");
|
||||
|
||||
function connectToJavaServer(proxy, client) {
|
||||
const javaClient = mc.createClient({
|
||||
async function connectToJavaServer(proxy, client) {
|
||||
let authConfig = {
|
||||
host: JAVA_SERVER_HOST,
|
||||
port: JAVA_SERVER_PORT,
|
||||
username: !USE_LEGACY_USERNAME
|
||||
@@ -24,7 +26,30 @@ function connectToJavaServer(proxy, client) {
|
||||
: client.username || "undefined",
|
||||
auth: "offline",
|
||||
version: "1.8.9",
|
||||
});
|
||||
};
|
||||
|
||||
if (USE_JAVA_ACCOUNT) {
|
||||
if (msAuth.isAuthenticated()) {
|
||||
authConfig = {
|
||||
host: JAVA_SERVER_HOST,
|
||||
port: JAVA_SERVER_PORT,
|
||||
username: msAuth.username,
|
||||
session: {
|
||||
accessToken: msAuth.accessToken,
|
||||
selectedProfile: {
|
||||
id: msAuth.uuid,
|
||||
name: msAuth.username,
|
||||
},
|
||||
},
|
||||
auth: "microsoft",
|
||||
version: "1.8.9",
|
||||
};
|
||||
} else {
|
||||
console.error("Not authenticated! This should not happen.");
|
||||
}
|
||||
}
|
||||
|
||||
const javaClient = mc.createClient(authConfig);
|
||||
|
||||
client.javaClient = javaClient;
|
||||
client._lastJavaPackets = [];
|
||||
@@ -1000,138 +1025,38 @@ function connectToJavaServer(proxy, client) {
|
||||
});
|
||||
|
||||
javaClient.on("spawn_entity", (packet) => {
|
||||
if (client.state === "play") {
|
||||
let lceEntityType = packet.type;
|
||||
|
||||
if (packet.type === 10) {
|
||||
lceEntityType = 10;
|
||||
const minecartSubtype = packet.intField || 0;
|
||||
const minecartTypes = [
|
||||
"Rideable",
|
||||
"Chest",
|
||||
"Furnace",
|
||||
"TNT",
|
||||
"Spawner",
|
||||
"Hopper",
|
||||
];
|
||||
const minecartType = minecartTypes[minecartSubtype] || "Unknown";
|
||||
}
|
||||
|
||||
let fallingBlockData = null;
|
||||
if (packet.type === 70) {
|
||||
const javaBlockId = packet.intField & 0xfff;
|
||||
const metadata = (packet.intField >> 12) & 0xf;
|
||||
|
||||
const lceBlockId = proxy.mapJavaBlockToLCE(javaBlockId);
|
||||
|
||||
fallingBlockData = lceBlockId | (metadata << 16);
|
||||
}
|
||||
|
||||
if (lceEntityType < 0 || lceEntityType > 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lceEntityId = proxy.mapJavaEntityIdToLce(client, packet.entityId);
|
||||
|
||||
let velocityX = 0,
|
||||
velocityY = 0,
|
||||
velocityZ = 0;
|
||||
if (packet.objectData) {
|
||||
velocityX = packet.objectData.velocityX || 0;
|
||||
velocityY = packet.objectData.velocityY || 0;
|
||||
velocityZ = packet.objectData.velocityZ || 0;
|
||||
}
|
||||
|
||||
let arrowData = -1;
|
||||
if (lceEntityType === 60) {
|
||||
arrowData = lceEntityId;
|
||||
const javaYaw = (packet.yaw / 256) * 360;
|
||||
const javaPitch = (packet.pitch / 256) * 360;
|
||||
}
|
||||
|
||||
let fishingHookData = -1;
|
||||
if (lceEntityType === 90) {
|
||||
const javaOwnerId = packet.intField || packet.entityId;
|
||||
|
||||
if (javaOwnerId === client.javaPlayerEntityId) {
|
||||
fishingHookData = client.lcePlayerEntityId || 1;
|
||||
} else {
|
||||
fishingHookData =
|
||||
proxy.mapJavaEntityIdToLce(client, javaOwnerId) || lceEntityId;
|
||||
try {
|
||||
if (client.state === "play") {
|
||||
if (
|
||||
!packet ||
|
||||
packet.entityId === undefined ||
|
||||
packet.type === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const entityInfo = {
|
||||
entityId: lceEntityId,
|
||||
javaEntityId: packet.entityId,
|
||||
type: lceEntityType,
|
||||
x: packet.x / 32,
|
||||
y: packet.y / 32,
|
||||
z: packet.z / 32,
|
||||
yaw: lceEntityType === 60 ? 0 : (packet.yaw / 256) * 360,
|
||||
pitch: lceEntityType === 60 ? 0 : (packet.pitch / 256) * 360,
|
||||
data:
|
||||
lceEntityType === 2
|
||||
? 1
|
||||
: lceEntityType === 60
|
||||
? arrowData
|
||||
: lceEntityType === 90
|
||||
? fishingHookData
|
||||
: lceEntityType === 63 || lceEntityType === 64
|
||||
? 0
|
||||
: lceEntityType === 70
|
||||
? fallingBlockData
|
||||
: lceEntityType === 10
|
||||
? packet.intField || 0
|
||||
: packet.objectData?.intField || -1,
|
||||
velocityX: velocityX,
|
||||
velocityY: velocityY,
|
||||
velocityZ: velocityZ,
|
||||
};
|
||||
|
||||
entityInfo.spawnTime = Date.now();
|
||||
|
||||
client.javaEntities.set(packet.entityId, entityInfo);
|
||||
|
||||
try {
|
||||
proxy.sendAddEntityPacket(client, entityInfo);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lceEntityType === 2) {
|
||||
entityInfo.waitingForItemData = true;
|
||||
}
|
||||
|
||||
if (lceEntityType === 10) {
|
||||
const minecartMetadata = [];
|
||||
const minecartSubtype = packet.intField || 0;
|
||||
let displayBlockId = 0;
|
||||
switch (minecartSubtype) {
|
||||
case 1:
|
||||
displayBlockId = 54;
|
||||
break; //chest
|
||||
case 2:
|
||||
displayBlockId = 61;
|
||||
break; //furnace
|
||||
case 3:
|
||||
displayBlockId = 46;
|
||||
break; //tNT
|
||||
case 5:
|
||||
displayBlockId = 154;
|
||||
break; //hopper
|
||||
case 4:
|
||||
displayBlockId = 52;
|
||||
break; //spawner
|
||||
default:
|
||||
displayBlockId = 0;
|
||||
break; //no display
|
||||
if (
|
||||
!Number.isFinite(packet.x) ||
|
||||
!Number.isFinite(packet.y) ||
|
||||
!Number.isFinite(packet.z)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (displayBlockId > 0) {
|
||||
minecartMetadata.push({ key: 20, type: 2, value: displayBlockId });
|
||||
minecartMetadata.push({ key: 21, type: 2, value: 6 });
|
||||
minecartMetadata.push({ key: 22, type: 0, value: 1 });
|
||||
proxy.sendEntityMetadataPacket(client, entityInfo, minecartMetadata);
|
||||
|
||||
if (!Number.isFinite(packet.yaw) || !Number.isFinite(packet.pitch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lceEntityType = packet.type;
|
||||
|
||||
const unsupportedEntityTypes = [78];
|
||||
if (unsupportedEntityTypes.includes(lceEntityType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.type === 10) {
|
||||
lceEntityType = 10;
|
||||
const minecartSubtype = packet.intField || 0;
|
||||
const minecartTypes = [
|
||||
"Rideable",
|
||||
"Chest",
|
||||
@@ -1140,9 +1065,142 @@ function connectToJavaServer(proxy, client) {
|
||||
"Spawner",
|
||||
"Hopper",
|
||||
];
|
||||
const cartType = minecartTypes[minecartSubtype] || "Unknown";
|
||||
const minecartType = minecartTypes[minecartSubtype] || "Unknown";
|
||||
}
|
||||
|
||||
let fallingBlockData = null;
|
||||
if (packet.type === 70) {
|
||||
const javaBlockId = packet.intField & 0xfff;
|
||||
const metadata = (packet.intField >> 12) & 0xf;
|
||||
|
||||
const lceBlockId = proxy.mapJavaBlockToLCE(javaBlockId);
|
||||
|
||||
fallingBlockData = lceBlockId | (metadata << 16);
|
||||
}
|
||||
|
||||
if (lceEntityType < 0 || lceEntityType > 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lceEntityId = proxy.mapJavaEntityIdToLce(client, packet.entityId);
|
||||
|
||||
let velocityX = 0,
|
||||
velocityY = 0,
|
||||
velocityZ = 0;
|
||||
if (packet.objectData) {
|
||||
velocityX = packet.objectData.velocityX || 0;
|
||||
velocityY = packet.objectData.velocityY || 0;
|
||||
velocityZ = packet.objectData.velocityZ || 0;
|
||||
}
|
||||
|
||||
let arrowData = -1;
|
||||
if (lceEntityType === 60) {
|
||||
arrowData = lceEntityId;
|
||||
const javaYaw = (packet.yaw / 256) * 360;
|
||||
const javaPitch = (packet.pitch / 256) * 360;
|
||||
}
|
||||
|
||||
let fishingHookData = -1;
|
||||
if (lceEntityType === 90) {
|
||||
const javaOwnerId = packet.intField || packet.entityId;
|
||||
|
||||
if (javaOwnerId === client.javaPlayerEntityId) {
|
||||
fishingHookData = client.lcePlayerEntityId || 1;
|
||||
} else {
|
||||
fishingHookData =
|
||||
proxy.mapJavaEntityIdToLce(client, javaOwnerId) || lceEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
const entityInfo = {
|
||||
entityId: lceEntityId,
|
||||
javaEntityId: packet.entityId,
|
||||
type: lceEntityType,
|
||||
x: packet.x / 32,
|
||||
y: packet.y / 32,
|
||||
z: packet.z / 32,
|
||||
yaw: lceEntityType === 60 ? 0 : (packet.yaw / 256) * 360,
|
||||
pitch: lceEntityType === 60 ? 0 : (packet.pitch / 256) * 360,
|
||||
data:
|
||||
lceEntityType === 2
|
||||
? 1
|
||||
: lceEntityType === 60
|
||||
? arrowData
|
||||
: lceEntityType === 90
|
||||
? fishingHookData
|
||||
: lceEntityType === 63 || lceEntityType === 64
|
||||
? 0
|
||||
: lceEntityType === 70
|
||||
? fallingBlockData
|
||||
: lceEntityType === 10
|
||||
? packet.intField || 0
|
||||
: packet.objectData?.intField || -1,
|
||||
velocityX: velocityX,
|
||||
velocityY: velocityY,
|
||||
velocityZ: velocityZ,
|
||||
};
|
||||
|
||||
entityInfo.spawnTime = Date.now();
|
||||
|
||||
client.javaEntities.set(packet.entityId, entityInfo);
|
||||
|
||||
try {
|
||||
proxy.sendAddEntityPacket(client, entityInfo);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lceEntityType === 2) {
|
||||
entityInfo.waitingForItemData = true;
|
||||
}
|
||||
|
||||
if (lceEntityType === 10) {
|
||||
const minecartMetadata = [];
|
||||
const minecartSubtype = packet.intField || 0;
|
||||
let displayBlockId = 0;
|
||||
switch (minecartSubtype) {
|
||||
case 1:
|
||||
displayBlockId = 54;
|
||||
break;
|
||||
case 2:
|
||||
displayBlockId = 61;
|
||||
break;
|
||||
case 3:
|
||||
displayBlockId = 46;
|
||||
break;
|
||||
case 5:
|
||||
displayBlockId = 154;
|
||||
break;
|
||||
case 4:
|
||||
displayBlockId = 52;
|
||||
break;
|
||||
default:
|
||||
displayBlockId = 0;
|
||||
break; //no display
|
||||
}
|
||||
if (displayBlockId > 0) {
|
||||
minecartMetadata.push({ key: 20, type: 2, value: displayBlockId });
|
||||
minecartMetadata.push({ key: 21, type: 2, value: 6 });
|
||||
minecartMetadata.push({ key: 22, type: 0, value: 1 });
|
||||
proxy.sendEntityMetadataPacket(
|
||||
client,
|
||||
entityInfo,
|
||||
minecartMetadata,
|
||||
);
|
||||
const minecartTypes = [
|
||||
"Rideable",
|
||||
"Chest",
|
||||
"Furnace",
|
||||
"TNT",
|
||||
"Spawner",
|
||||
"Hopper",
|
||||
];
|
||||
const cartType = minecartTypes[minecartSubtype] || "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
/* do nothing */
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1514,114 +1572,123 @@ function connectToJavaServer(proxy, client) {
|
||||
});
|
||||
|
||||
javaClient.on("entity_metadata", (packet) => {
|
||||
if (client.state === "play") {
|
||||
let isPlayer = false;
|
||||
for (const [uuid, player] of client.javaPlayers) {
|
||||
if (player.javaEntityId === packet.entityId && player.spawned) {
|
||||
//0x01=on fire, 0x02=sneaking, 0x04=unused, 0x08=sprinting, 0x10=eating, 0x20=invisible
|
||||
if (packet.metadata && packet.metadata.length > 0) {
|
||||
const sharedFlags = packet.metadata.find(
|
||||
(m) => m.key === 0 && m.type === 0,
|
||||
);
|
||||
if (sharedFlags !== undefined) {
|
||||
const flags = sharedFlags.value & 0xff;
|
||||
|
||||
const metaWriter = new PacketWriter();
|
||||
metaWriter.writeInt(player.entityId);
|
||||
metaWriter.writeByte((0 << 5) | 0);
|
||||
metaWriter.writeByte(flags);
|
||||
metaWriter.writeByte(0x7f);
|
||||
proxy.sendPacket(client, 0x28, metaWriter.toBuffer());
|
||||
}
|
||||
}
|
||||
isPlayer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPlayer && client.javaEntities.has(packet.entityId)) {
|
||||
const entity = client.javaEntities.get(packet.entityId);
|
||||
entity.metadata = packet.metadata || [];
|
||||
|
||||
if (entity.type === 90 && packet.metadata) {
|
||||
const hookedEntityMeta = packet.metadata.find((m) => m.key === 6);
|
||||
if (hookedEntityMeta) {
|
||||
if (hookedEntityMeta.value > 0) {
|
||||
const hookedJavaEntityId = hookedEntityMeta.value;
|
||||
const hookedLceEntityId = proxy.mapJavaEntityIdToLce(
|
||||
client,
|
||||
hookedJavaEntityId,
|
||||
try {
|
||||
if (client.state === "play") {
|
||||
let isPlayer = false;
|
||||
for (const [uuid, player] of client.javaPlayers) {
|
||||
if (player.javaEntityId === packet.entityId && player.spawned) {
|
||||
//0x01=on fire, 0x02=sneaking, 0x04=unused, 0x08=sprinting, 0x10=eating, 0x20=invisible
|
||||
if (packet.metadata && packet.metadata.length > 0) {
|
||||
const sharedFlags = packet.metadata.find(
|
||||
(m) => m.key === 0 && m.type === 0,
|
||||
);
|
||||
entity.hookedEntityId = hookedLceEntityId;
|
||||
if (sharedFlags !== undefined) {
|
||||
const flags = sharedFlags.value & 0xff;
|
||||
|
||||
const metaWriter = new PacketWriter();
|
||||
metaWriter.writeInt(player.entityId);
|
||||
metaWriter.writeByte((0 << 5) | 0);
|
||||
metaWriter.writeByte(flags);
|
||||
metaWriter.writeByte(0x7f);
|
||||
proxy.sendPacket(client, 0x28, metaWriter.toBuffer());
|
||||
}
|
||||
}
|
||||
isPlayer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if (entity.type === 10) {
|
||||
// console.log('minecart', entity.type, entity.entityId, JSON.stringify(packet.metadata));
|
||||
//}
|
||||
if (!isPlayer && client.javaEntities.has(packet.entityId)) {
|
||||
const entity = client.javaEntities.get(packet.entityId);
|
||||
entity.metadata = packet.metadata || [];
|
||||
|
||||
if (
|
||||
entity.type === 2 &&
|
||||
entity.waitingForItemData &&
|
||||
packet.metadata &&
|
||||
packet.metadata.length > 0
|
||||
) {
|
||||
const itemMetadata = packet.metadata.find(
|
||||
(m) => m.key === 10 && m.type === 5,
|
||||
);
|
||||
if (itemMetadata && itemMetadata.value) {
|
||||
proxy.sendSetItemDataPacket(client, entity, itemMetadata.value);
|
||||
entity.waitingForItemData = false;
|
||||
}
|
||||
}
|
||||
|
||||
const customNameMeta = packet.metadata.find(
|
||||
(m) => m.key === 2 && m.type === 4,
|
||||
);
|
||||
const customNameVisibleMeta = packet.metadata.find(
|
||||
(m) => m.key === 3 && m.type === 0,
|
||||
);
|
||||
|
||||
const lceMetadata = [];
|
||||
|
||||
if (customNameMeta && customNameMeta.value) {
|
||||
lceMetadata.push({
|
||||
key: 10,
|
||||
type: 4,
|
||||
value: customNameMeta.value,
|
||||
});
|
||||
}
|
||||
|
||||
if (customNameVisibleMeta !== undefined) {
|
||||
lceMetadata.push({
|
||||
key: 11,
|
||||
type: 0,
|
||||
value: customNameVisibleMeta.value,
|
||||
});
|
||||
}
|
||||
|
||||
const relevantMetadata = packet.metadata.filter((m) => {
|
||||
if (entity.type === 10) {
|
||||
if ([20, 21, 22].includes(m.key)) {
|
||||
return false;
|
||||
if (entity.type === 90 && packet.metadata) {
|
||||
const hookedEntityMeta = packet.metadata.find((m) => m.key === 6);
|
||||
if (hookedEntityMeta) {
|
||||
if (hookedEntityMeta.value > 0) {
|
||||
const hookedJavaEntityId = hookedEntityMeta.value;
|
||||
const hookedLceEntityId = proxy.mapJavaEntityIdToLce(
|
||||
client,
|
||||
hookedJavaEntityId,
|
||||
);
|
||||
entity.hookedEntityId = hookedLceEntityId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//0=shared flags (e.g. on fire, sneaking, sprinting)
|
||||
//12=age
|
||||
//13=skeleton type
|
||||
//16=villager profession or slime/magma size
|
||||
//17=batman hanging flag - 0x01 = hanging
|
||||
return [0, 12, 13, 16, 17].includes(m.key) && m.type !== 5;
|
||||
});
|
||||
//if (entity.type === 10) {
|
||||
// console.log('minecart', entity.type, entity.entityId, JSON.stringify(packet.metadata));
|
||||
//}
|
||||
|
||||
const allMetadata = [...lceMetadata, ...relevantMetadata];
|
||||
if (
|
||||
entity.type === 2 &&
|
||||
entity.waitingForItemData &&
|
||||
packet.metadata &&
|
||||
packet.metadata.length > 0
|
||||
) {
|
||||
const itemMetadata = packet.metadata.find(
|
||||
(m) => m.key === 10 && m.type === 5,
|
||||
);
|
||||
if (itemMetadata && itemMetadata.value) {
|
||||
proxy.sendSetItemDataPacket(client, entity, itemMetadata.value);
|
||||
entity.waitingForItemData = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allMetadata.length > 0 && entity.type !== 2) {
|
||||
proxy.sendEntityMetadataPacket(client, entity, allMetadata);
|
||||
const customNameMeta = packet.metadata
|
||||
? packet.metadata.find((m) => m && m.key === 2 && m.type === 4)
|
||||
: undefined;
|
||||
const customNameVisibleMeta = packet.metadata
|
||||
? packet.metadata.find((m) => m && m.key === 3 && m.type === 0)
|
||||
: undefined;
|
||||
|
||||
const lceMetadata = [];
|
||||
|
||||
if (customNameMeta && customNameMeta.value) {
|
||||
lceMetadata.push({
|
||||
key: 10,
|
||||
type: 4,
|
||||
value: customNameMeta.value,
|
||||
});
|
||||
}
|
||||
|
||||
if (customNameVisibleMeta !== undefined) {
|
||||
lceMetadata.push({
|
||||
key: 11,
|
||||
type: 0,
|
||||
value: customNameVisibleMeta.value,
|
||||
});
|
||||
}
|
||||
|
||||
const relevantMetadata = packet.metadata
|
||||
? packet.metadata.filter((m) => {
|
||||
if (!m || m.key === undefined || m.type === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entity.type === 10) {
|
||||
if ([20, 21, 22].includes(m.key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m.type === 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [0, 12, 13, 16, 17].includes(m.key);
|
||||
})
|
||||
: [];
|
||||
|
||||
const allMetadata = [...lceMetadata, ...relevantMetadata];
|
||||
|
||||
if (allMetadata.length > 0 && entity.type !== 2) {
|
||||
proxy.sendEntityMetadataPacket(client, entity, allMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
/* do nothing */
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -8,13 +8,16 @@ const {
|
||||
GAME_PORT,
|
||||
WIN64_LAN_DISCOVERY_PORT,
|
||||
MINECRAFT_NET_VERSION,
|
||||
USE_JAVA_ACCOUNT,
|
||||
USE_LEGACY_USERNAME,
|
||||
CUSTOM_USERNAME,
|
||||
PROXY_NAME,
|
||||
} = require("../constants");
|
||||
const msAuth = require("./auth");
|
||||
const PacketWriter = require("./packetwriter");
|
||||
const PacketReader = require("./packetreader");
|
||||
const LANBroadcast = require("./lanbroadcast");
|
||||
const recipeData = require("./mappings/recipemapping");
|
||||
const {
|
||||
createEntityTypeMapping,
|
||||
createItemMapping,
|
||||
@@ -54,6 +57,16 @@ class LCEProxy {
|
||||
this.javaBlockMapping = createBlockMapping();
|
||||
this.javaItemMapping = createItemMapping();
|
||||
this.javaEntityTypeMapping = createEntityTypeMapping();
|
||||
|
||||
this.validLCEPackets = new Set([
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x3e, 0x46, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x82, 0x83, 0xc8, 0xc9, 0xca, 0xcb,
|
||||
0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xfa, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
]);
|
||||
}
|
||||
|
||||
mapJavaBlockToLCE(javaBlockId) {
|
||||
@@ -163,7 +176,21 @@ class LCEProxy {
|
||||
return null;
|
||||
}
|
||||
|
||||
start() {
|
||||
async start() {
|
||||
if (USE_JAVA_ACCOUNT) {
|
||||
try {
|
||||
await msAuth.authenticate();
|
||||
console.log("Logged in as: " + msAuth.username);
|
||||
} catch (err) {
|
||||
console.log("\Failed to log into java account! (", err.message, ")");
|
||||
console.log(
|
||||
"If you enabled this by accident and would like to only join offline servers for free,",
|
||||
);
|
||||
console.log("set USE_JAVA_ACCOUNT to false in constants.js\n");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
this.startBroadcasting();
|
||||
this.startTCPServer();
|
||||
|
||||
@@ -510,10 +537,11 @@ class LCEProxy {
|
||||
this.handleContainerAck(client, packetData);
|
||||
}
|
||||
break;
|
||||
//maybe we can use a custom JavaCraftingPacket (0x9E) packet with
|
||||
//crafting grid data because java edition doesn't craft with recipe ids
|
||||
//case 0x96:
|
||||
// break;
|
||||
case 0x96:
|
||||
if (client.state === "play") {
|
||||
this.handleCraftItem(client, packetData);
|
||||
}
|
||||
break;
|
||||
case 0x97: //TradeItemPacket - 151
|
||||
if (client.state === "play") {
|
||||
this.handleTradeItem(client, packetData);
|
||||
@@ -2185,10 +2213,25 @@ class LCEProxy {
|
||||
}, totalDelay + 100);
|
||||
}
|
||||
|
||||
//LCE uses recipe ids to craft, whilst java edition requires grid data
|
||||
//we should write a server plugin that sends the recipe data when crafting because lazy
|
||||
handleCraftItem(client, data) {
|
||||
/* do nothing */
|
||||
const reader = new PacketReader(data.slice(1));
|
||||
const uid = reader.readShort();
|
||||
const recipeId = reader.readInt();
|
||||
|
||||
const grid = recipeData[recipeId] || [
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
"none",
|
||||
];
|
||||
|
||||
//console.log(`recipe id: ${recipeId}`);
|
||||
//console.log(`${grid[0]}, ${grid[1]}, ${grid[2]}, ${grid[3]}, ${grid[4]}, ${grid[5]}, ${grid[6]}, ${grid[7]}, ${grid[8]}`);
|
||||
}
|
||||
handleJavaCrafting(client, data) {
|
||||
/* do nothing */
|
||||
@@ -2526,13 +2569,35 @@ class LCEProxy {
|
||||
}
|
||||
|
||||
sendPacket(client, packetId, payload) {
|
||||
const packetData = Buffer.concat([Buffer.from([packetId]), payload]);
|
||||
const lengthPrefix = Buffer.allocUnsafe(4);
|
||||
lengthPrefix.writeUInt32BE(packetData.length, 0);
|
||||
if (!this.validLCEPackets.has(packetId)) {
|
||||
console.warn(
|
||||
`[WARNING] Attempted to send invalid packet ID: 0x${packetId.toString(16).toUpperCase().padStart(2, "0")}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const fullPacket = Buffer.concat([lengthPrefix, packetData]);
|
||||
if (!payload || !Buffer.isBuffer(payload)) {
|
||||
console.warn(
|
||||
`[WARNING] Invalid payload for packet 0x${packetId.toString(16).toUpperCase().padStart(2, "0")}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const success = client.socket.write(fullPacket);
|
||||
if (client.socket.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const packetData = Buffer.concat([Buffer.from([packetId]), payload]);
|
||||
const lengthPrefix = Buffer.allocUnsafe(4);
|
||||
lengthPrefix.writeUInt32BE(packetData.length, 0);
|
||||
|
||||
const fullPacket = Buffer.concat([lengthPrefix, packetData]);
|
||||
|
||||
client.socket.write(fullPacket);
|
||||
} catch (err) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
disconnectClient(client, reason = 0) {
|
||||
@@ -2602,8 +2667,8 @@ class LCEProxy {
|
||||
}
|
||||
}
|
||||
|
||||
connectToJavaServer(client) {
|
||||
return connectToJavaServerFunc(this, client);
|
||||
async connectToJavaServer(client) {
|
||||
return await connectToJavaServerFunc(this, client);
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
||||
586
src/mappings/recipemapping.js
Normal file
586
src/mappings/recipemapping.js
Normal file
@@ -0,0 +1,586 @@
|
||||
//all of the crafting recipes that are sent from the client converted into a java recipe grid.
|
||||
//this was absolute fucking torture to write, thanks mojang for not using recipe ids in java edition crafting until 1.12!
|
||||
|
||||
//unfinised as of 3/9/2026 (MM/DD/YY)
|
||||
|
||||
module.exports = {
|
||||
//page 1
|
||||
0: [
|
||||
"oak_log", "none", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
1: [
|
||||
"birch_log", "none", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
2: [
|
||||
"spruce_log", "none", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
3: [
|
||||
"jungle_log", "none", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
4: [
|
||||
"any_plank", "none", "none",
|
||||
"any_plank", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
40: [
|
||||
"sand", "sand", "none",
|
||||
"sand", "sand", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
41: [
|
||||
"sandstone_slab", "sandstone_slab", "none",
|
||||
"sandstone_slab", "sandstone_slab", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
42: [
|
||||
"quartz_slab", "none", "none",
|
||||
"quartz_slab", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
43: [
|
||||
"quartz_block", "none", "none",
|
||||
"quartz_block", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
49: [
|
||||
"stone", "stone", "none",
|
||||
"stone", "stone", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
51: [
|
||||
"nether_brick", "nether_brick", "none",
|
||||
"nether_brick", "nether_brick", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
156: [
|
||||
"snowball", "snowball", "none",
|
||||
"snowball", "snowball", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
157: [
|
||||
"snowball", "snowball", "none",
|
||||
"snowball", "snowball", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
158: [
|
||||
"clay", "clay", "none",
|
||||
"clay", "clay", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
159: [
|
||||
"brick", "brick", "none",
|
||||
"brick", "brick", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
203: [
|
||||
"nether_quartz", "nether_quartz", "none",
|
||||
"nether_quartz", "nether_quartz", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
44: [
|
||||
"any_plank", "any_plank", "none",
|
||||
"any_plank", "any_plank", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
45: [
|
||||
"cobblestone", "cobblestone", "cobblestone",
|
||||
"cobblestone", "none", "cobblestone",
|
||||
"cobblestone", "cobblestone", "cobblestone"
|
||||
],
|
||||
55: [
|
||||
"any_plank", "book", "none",
|
||||
"diamond", "obsidian", "diamond",
|
||||
"obsidian", "obsidian", "obsidian"
|
||||
],
|
||||
56: [
|
||||
"iron_block", "iron_block", "iron_block",
|
||||
"none", "iron_ingot", "none",
|
||||
"iron_ingot", "iron_ingot", "iron_ingot"
|
||||
],
|
||||
227: [
|
||||
"none", "none", "none",
|
||||
"none", "blaze_rod", "none",
|
||||
"cobblestone", "cobblestone", "cobblestone"
|
||||
],
|
||||
|
||||
|
||||
|
||||
46: [
|
||||
"any_plank", "any_plank", "any_plank",
|
||||
"any_plank", "none", "any_plank",
|
||||
"any_plank", "any_plank", "any_plank"
|
||||
],
|
||||
47: [
|
||||
"chest", "tripwire_hook", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
48: [
|
||||
"obsidian", "obsidian", "obsidian",
|
||||
"obsidian", "ender_eye", "obsidian",
|
||||
"obsidian", "obsidian", "obsidian"
|
||||
],
|
||||
|
||||
|
||||
|
||||
54: [
|
||||
"none", "none", "none",
|
||||
"any_wool", "any_wool", "any_wool",
|
||||
"any_plank", "any_plank", "any_plank"
|
||||
],
|
||||
|
||||
|
||||
|
||||
57: [
|
||||
"stick", "none", "stick",
|
||||
"stick", "stick", "stick",
|
||||
"stick", "none", "stick"
|
||||
],
|
||||
|
||||
|
||||
|
||||
58: [
|
||||
"stick", "any_plank", "stick",
|
||||
"stick", "any_plank", "stick",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
59: [
|
||||
"stick", "stick", "stick",
|
||||
"stick", "stick", "stick",
|
||||
"none", "none", "none"
|
||||
],
|
||||
60: [
|
||||
"nether_brick", "nether_brick", "nether_brick",
|
||||
"nether_brick", "nether_brick", "nether_brick",
|
||||
"none", "none", "none"
|
||||
],
|
||||
61: [
|
||||
"iron_ingot", "iron_ingot", "iron_ingot",
|
||||
"iron_ingot", "iron_ingot", "iron_ingot",
|
||||
"none", "none", "none"
|
||||
],
|
||||
62: [
|
||||
"cobblestone", "cobblestone", "cobblestone",
|
||||
"cobblestone", "cobblestone", "cobblestone",
|
||||
"none", "none", "none"
|
||||
],
|
||||
63: [
|
||||
"mossy_cobblestone", "mossy_cobblestone", "mossy_cobblestone",
|
||||
"mossy_cobblestone", "mossy_cobblestone", "mossy_cobblestone",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
64: [
|
||||
"any_plank", "any_plank", "none",
|
||||
"any_plank", "any_plank", "none",
|
||||
"any_plank", "any_plank", "none"
|
||||
],
|
||||
65: [
|
||||
"iron_ingot", "iron_ingot", "none",
|
||||
"iron_ingot", "iron_ingot", "none",
|
||||
"iron_ingot", "iron_ingot", "none"
|
||||
],
|
||||
67: [
|
||||
"any_plank", "any_plank", "any_plank",
|
||||
"any_plank", "any_plank", "any_plank",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
66: [
|
||||
"oak_plank", "none", "none",
|
||||
"oak_plank", "oak_plank", "none",
|
||||
"oak_plank", "oak_plank", "oak_plank"
|
||||
],
|
||||
68: [
|
||||
"cobblestone", "none", "none",
|
||||
"cobblestone", "cobblestone", "none",
|
||||
"cobblestone", "cobblestone", "cobblestone"
|
||||
],
|
||||
69: [
|
||||
"brick_block", "none", "none",
|
||||
"brick_block", "brick_block", "none",
|
||||
"brick_block", "brick_block", "brick_block"
|
||||
],
|
||||
70: [
|
||||
"stonebrick", "none", "none",
|
||||
"stonebrick", "stonebrick", "none",
|
||||
"stonebrick", "stonebrick", "stonebrick"
|
||||
],
|
||||
71: [
|
||||
"nether_brick", "none", "none",
|
||||
"nether_brick", "nether_brick", "none",
|
||||
"nether_brick", "nether_brick", "nether_brick"
|
||||
],
|
||||
72: [
|
||||
"sandstone", "none", "none",
|
||||
"sandstone", "sandstone", "none",
|
||||
"sandstone", "sandstone", "sandstone"
|
||||
],
|
||||
73: [
|
||||
"birch_planks", "none", "none",
|
||||
"birch_planks", "birch_planks", "none",
|
||||
"birch_planks", "birch_planks", "birch_planks"
|
||||
],
|
||||
74: [
|
||||
"spruce_planks", "none", "none",
|
||||
"spruce_planks", "spruce_planks", "none",
|
||||
"spruce_planks", "spruce_planks", "spruce_planks"
|
||||
],
|
||||
75: [
|
||||
"jungle_planks", "none", "none",
|
||||
"jungle_planks", "jungle_planks", "none",
|
||||
"jungle_planks", "jungle_planks", "jungle_planks"
|
||||
],
|
||||
76: [
|
||||
"quartz_block", "none", "none",
|
||||
"quartz_block", "quartz_block", "none",
|
||||
"quartz_block", "quartz_block", "quartz_block"
|
||||
],
|
||||
//next: slabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//page 2
|
||||
5: [
|
||||
"any_plank", "any_plank", "any_plank",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
9: [
|
||||
"cobblestone", "cobblestone", "cobblestone",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
13: [
|
||||
"iron_ingot", "iron_ingot", "iron_ingot",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
17: [
|
||||
"diamond", "diamond", "diamond",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
21: [
|
||||
"gold_ingot", "gold_ingot", "gold_ingot",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
6: [
|
||||
"none", "any_plank", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
10: [
|
||||
"none", "cobblestone", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
14: [
|
||||
"none", "iron_ingot", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
18: [
|
||||
"none", "diamond", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
22: [
|
||||
"none", "gold_ingot", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
7: [
|
||||
"any_plank", "any_plank", "none",
|
||||
"any_plank", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
11: [
|
||||
"cobblestone", "cobblestone", "none",
|
||||
"cobblestone", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
15: [
|
||||
"iron_ingot", "iron_ingot", "none",
|
||||
"iron_ingot", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
19: [
|
||||
"diamond", "diamond", "none",
|
||||
"diamond", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
23: [
|
||||
"gold_ingot", "gold_ingot", "none",
|
||||
"gold_ingot", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
8: [
|
||||
"any_plank", "any_plank", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
12: [
|
||||
"cobblestone", "cobblestone", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
16: [
|
||||
"iron_ingot", "iron_ingot", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
20: [
|
||||
"diamond", "diamond", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
24: [
|
||||
"gold_ingot", "gold_ingot", "none",
|
||||
"none", "stick", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
25: [
|
||||
"iron_ingot", "none", "none",
|
||||
"none", "iron_ingot", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
187: [
|
||||
"flint", "none", "none",
|
||||
"none", "iron_ingot", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
161: [
|
||||
"gunpowder", "sand", "gunpowder",
|
||||
"sand", "gunpowder", "sand",
|
||||
"gunpowder", "sand", "gunpowder"
|
||||
],
|
||||
|
||||
|
||||
|
||||
185: [
|
||||
"none", "none", "stick",
|
||||
"none", "stick", "string",
|
||||
"stick", "none", "string"
|
||||
],
|
||||
186: [
|
||||
"fishing_rod", "none", "none",
|
||||
"none", "carrot", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
189: [
|
||||
"none", "stick", "string",
|
||||
"stick", "none", "string",
|
||||
"none", "stick", "string"
|
||||
],
|
||||
190: [
|
||||
"flint", "none", "none",
|
||||
"stick", "none", "none",
|
||||
"feather", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
191: [
|
||||
"none", "any_plank", "none",
|
||||
"none", "any_plank", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
192: [
|
||||
"none", "cobblestone", "none",
|
||||
"none", "cobblestone", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
193: [
|
||||
"none", "iron_ingot", "none",
|
||||
"none", "iron_ingot", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
194: [
|
||||
"none", "diamond", "none",
|
||||
"none", "diamond", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
195: [
|
||||
"none", "gold_ingot", "none",
|
||||
"none", "gold_ingot", "none",
|
||||
"none", "stick", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
196: [
|
||||
"none", "none", "none",
|
||||
"iron_ingot", "none", "iron_ingot",
|
||||
"none", "iron_ingot", "none"
|
||||
],
|
||||
197: [
|
||||
"any_plank", "none", "any_plank",
|
||||
"none", "any_plank", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
198: [
|
||||
"glass", "none", "glass",
|
||||
"none", "glass", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
226: [
|
||||
"iront_ingot", "none", "iront_ingot",
|
||||
"iront_ingot", "none", "iront_ingot",
|
||||
"iront_ingot", "iront_ingot", "iront_ingot"
|
||||
],
|
||||
|
||||
|
||||
|
||||
200: [
|
||||
"charcoal", "none", "none",
|
||||
"stick", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
201: [
|
||||
"coal", "none", "none",
|
||||
"stick", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
202: [
|
||||
"glowstone", "glowstone", "none",
|
||||
"glowstone", "glowstone", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
213: [
|
||||
"gunpowder", "blaze_powder", "none",
|
||||
"charcoal", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
214: [
|
||||
"gunpowder", "blaze_powder", "none",
|
||||
"coal", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
228: [
|
||||
"pumpkin", "none", "none",
|
||||
"torch", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
211: [
|
||||
"none", "gold_ingot", "none",
|
||||
"gold_ingot", "redstone", "gold_ingot",
|
||||
"none", "gold_ingot", "none"
|
||||
],
|
||||
212: [
|
||||
"ender_pearl", "blaze_powder", "none",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
215: [
|
||||
"string", "string", "none",
|
||||
"string", "slime_ball", "none",
|
||||
"none", "none", "string"
|
||||
],
|
||||
216: [
|
||||
"none", "iron_ingot", "none",
|
||||
"iron_ingot", "redstone", "iron_ingot",
|
||||
"none", "iron_ingot", "none"
|
||||
],
|
||||
217: [
|
||||
"paper", "paper", "paper",
|
||||
"paper", "compass", "paper",
|
||||
"paper", "paper", "paper"
|
||||
],
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//page 3
|
||||
26: [
|
||||
"gold_ingot", "gold_ingot", "gold_ingot",
|
||||
"gold_ingot", "apple", "gold_ingot",
|
||||
"gold_ingot", "gold_ingot", "gold_ingot"
|
||||
],
|
||||
27: [
|
||||
"gold_block", "gold_block", "gold_block",
|
||||
"gold_block", "apple", "gold_block",
|
||||
"gold_block", "gold_block", "gold_block"
|
||||
],
|
||||
28: [
|
||||
"gold_nugget", "gold_nugget", "gold_nugget",
|
||||
"gold_nugget", "melon", "gold_nugget",
|
||||
"gold_nugget", "gold_nugget", "gold_nugget"
|
||||
],
|
||||
35: [
|
||||
"gold_nugget", "gold_nugget", "gold_nugget",
|
||||
"gold_nugget", "carrot", "gold_nugget",
|
||||
"gold_nugget", "gold_nugget", "gold_nugget"
|
||||
],
|
||||
|
||||
|
||||
|
||||
29: [
|
||||
"brown_mushroom", "red_mushroom", "none",
|
||||
"bowl", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
|
||||
|
||||
|
||||
30: [
|
||||
"wheat", "cocoa_beans", "wheat",
|
||||
"none", "none", "none",
|
||||
"none", "none", "none"
|
||||
],
|
||||
31: [
|
||||
"melon", "melon", "melon",
|
||||
"melon", "melon", "melon",
|
||||
"melon", "melon", "melon"
|
||||
],
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
/* --------------------------------------------------------------- */
|
||||
const playerPackets = require("./playerpackets");
|
||||
const entityPackets = require("./entitypackets");
|
||||
const worldPackets = require("./worldPackets");
|
||||
const worldPackets = require("./worldpackets");
|
||||
const containerPackets = require("./containerpackets");
|
||||
|
||||
module.exports = {
|
||||
|
||||
Reference in New Issue
Block a user