diff --git a/src/Entity.ts b/src/Entity.ts new file mode 100644 index 0000000..e8b6f8c --- /dev/null +++ b/src/Entity.ts @@ -0,0 +1,5 @@ +import {IEntity} from "./IEntity"; + +export class Entity implements IEntity { + entityID: number; +} \ No newline at end of file diff --git a/src/IEntity.ts b/src/IEntity.ts index d614215..6b053b3 100644 --- a/src/IEntity.ts +++ b/src/IEntity.ts @@ -1,3 +1,3 @@ export interface IEntity { - entityID: Number + entityID: number } \ No newline at end of file diff --git a/src/MinecraftServer.ts b/src/MinecraftServer.ts index 0ac3299..88669ed 100644 --- a/src/MinecraftServer.ts +++ b/src/MinecraftServer.ts @@ -24,6 +24,7 @@ export class MinecraftServer { }); this.server.on('close', this.stop); + this.server.on('drop', () => {}) } public stop() { diff --git a/src/Player.ts b/src/Player.ts index 17e0001..c45ed2d 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -1,24 +1,60 @@ import {Socket} from "node:net"; import {IEntity} from "./IEntity"; import {PlayerManager} from "./utils/PlayerManager"; +import {Entity} from "./Entity"; +import {PacketEntityPositionLook} from "./packet/impl/entity/PacketEntityPositionLook"; +import {PacketEntityTeleport} from "./packet/impl/entity/PacketEntityTeleport"; -export class Player implements IEntity { - public entityID: Number; +export class Player extends Entity { public username: String; public socket: Socket; public playerManager: PlayerManager; public xPosition: number = 0; + public prevXPosition: number = this.xPosition; public yPosition: number = 100; - public stance: number = 102; + public prevYPosition: number = this.yPosition; public zPosition: number = 0; + public prevZPosition: number = this.zPosition; + public stance: number = 102; public yaw: number = 0; public pitch: number = 0; public onGround: boolean = false; constructor(username: String, socket: Socket, playerManager: PlayerManager) { + super(); this.username = username; this.socket = socket; this.playerManager = playerManager; } + + public updatePosition(x?: number, y?: number, stance?: number, z?: number, yaw?: number, pitch?: number, onGround?: boolean) { + if(x) { + this.prevXPosition = this.xPosition; + this.xPosition = x; + } + if(y && stance) { + this.prevYPosition = this.yPosition; + this.yPosition = y; + this.stance = stance; + + const sy = stance - y; + if(sy < 0.1 || sy > 1.65) this.playerManager.kickPlayer("Illegal Stance"); + } + if(z) { + this.prevZPosition = this.zPosition; + this.zPosition = z; + } + if(yaw) this.yaw = yaw; + if(pitch) this.pitch = pitch; + if(onGround != undefined) this.onGround = onGround; + + // console.log(this.toString()); + PlayerManager.sendPacketToAll(new PacketEntityTeleport(this.entityID, this.xPosition, this.yPosition, this.zPosition, 0, 0)) + } + + public toString() { + return `[Player ${this.username}] X=${this.xPosition},Y=${this.yPosition},stance=${this.stance},` + + `Z=${this.zPosition},yaw=${this.yaw},pitch=${this.pitch},onGround=${this.onGround}`; + } } \ No newline at end of file diff --git a/src/packet/Packet.ts b/src/packet/Packet.ts index 4fa03ac..2ef0547 100644 --- a/src/packet/Packet.ts +++ b/src/packet/Packet.ts @@ -2,13 +2,15 @@ import {PacketEnum} from "../utils/PacketEnum"; import {createWriter, Endian, IReader} from "bufferstuff"; import {Player} from "../Player"; import {Socket} from "node:net"; +import {Entity} from "../Entity"; +import {IEntity} from "../IEntity"; export class Packet { constructor(public options: IPacketOption) { options.name = PacketEnum[options.packetID].toString(); } - readData(reader: IReader, player: Player) {} + readData(reader: IReader, entity: IEntity) {} writeData() { return createWriter(Endian.BE).toBuffer(); } diff --git a/src/packet/impl/entity/PacketEntityPositionLook.ts b/src/packet/impl/entity/PacketEntityPositionLook.ts new file mode 100644 index 0000000..8996d0b --- /dev/null +++ b/src/packet/impl/entity/PacketEntityPositionLook.ts @@ -0,0 +1,29 @@ +import {Packet} from "../../Packet"; +import {PacketEnum} from "../../../utils/PacketEnum"; +import {createWriter, Endian, IReader} from "bufferstuff"; +import {Player} from "../../../Player"; +import {PlayerManager} from "../../../utils/PlayerManager"; +import {Entity} from "../../../Entity"; + +export class PacketEntityPositionLook extends Packet { + constructor(private entityID: number, private dX: number, private dY: number, private dZ: number, private yaw: number, private pitch: number) { + super({ + packetID: PacketEnum.EntityPositionLook + }) + } + + readData(reader: IReader, entity: Entity) { + + } + + writeData() { + return createWriter(Endian.BE).writeUByte(this.options.packetID) + .writeInt(this.entityID) + .writeByte(this.dX) + .writeByte(this.dY) + .writeByte(this.dZ) + .writeByte(this.yaw) + .writeByte(this.pitch) + .toBuffer(); + } +} \ No newline at end of file diff --git a/src/packet/impl/entity/PacketEntityTeleport.ts b/src/packet/impl/entity/PacketEntityTeleport.ts new file mode 100644 index 0000000..29910ec --- /dev/null +++ b/src/packet/impl/entity/PacketEntityTeleport.ts @@ -0,0 +1,29 @@ +import {Packet} from "../../Packet"; +import {PacketEnum} from "../../../utils/PacketEnum"; +import {createWriter, Endian, IReader} from "bufferstuff"; +import {Player} from "../../../Player"; +import {PlayerManager} from "../../../utils/PlayerManager"; +import {Entity} from "../../../Entity"; + +export class PacketEntityTeleport extends Packet { + constructor(private entityID: number, private dX: number, private dY: number, private dZ: number, private yaw: number, private pitch: number) { + super({ + packetID: PacketEnum.EntityTeleport + }) + } + + readData(reader: IReader, entity: Entity) { + + } + + writeData() { + return createWriter(Endian.BE).writeUByte(this.options.packetID) + .writeInt(this.entityID) + .writeInt(this.dX) + .writeInt(this.dY) + .writeInt(this.dZ) + .writeByte(this.yaw) + .writeByte(this.pitch) + .toBuffer(); + } +} \ No newline at end of file diff --git a/src/packet/impl/player/PacketChat.ts b/src/packet/impl/player/PacketChat.ts index 14befea..9171004 100644 --- a/src/packet/impl/player/PacketChat.ts +++ b/src/packet/impl/player/PacketChat.ts @@ -4,6 +4,7 @@ import {createWriter, Endian, IReader} from "bufferstuff"; import {Player} from "../../../Player"; import {PlayerManager} from "../../../utils/PlayerManager"; import {PacketPreChunk} from "../world/PacketPreChunk"; +import {PacketPositionLook} from "./PacketPositionLook"; export class PacketChat extends Packet { constructor(public message: string) { @@ -13,9 +14,31 @@ export class PacketChat extends Packet { } readData(reader: IReader, player: Player) { - this.message = `<${player.username}> ${reader.readString16()}` + const msg = reader.readString16(); + this.message = `<${player.username}> ${msg}` + if(msg.startsWith("/")) { + this.handleCommand(player, msg); + return; + } PlayerManager.sendPacketToAll(this); + + + } + + handleCommand(player: Player, msg: string) { + if(!msg.startsWith("/")) return; + const cmd = msg.replace("/", "").split(" "); + if(cmd.length < 1) { + this.message = "Unknown command!"; + return player.playerManager.sendPacket(this) + } + if(cmd[0] == "tp") { + player.xPosition = 0; + player.yPosition = 100; + player.zPosition = 0; + player.playerManager.sendPacket(new PacketPositionLook()) + } } writeData() { diff --git a/src/packet/impl/player/PacketLook.ts b/src/packet/impl/player/PacketLook.ts new file mode 100644 index 0000000..d11f373 --- /dev/null +++ b/src/packet/impl/player/PacketLook.ts @@ -0,0 +1,34 @@ +import {Packet} from "../../Packet"; +import {PacketEnum} from "../../../utils/PacketEnum"; +import {createWriter, Endian, IReader} from "bufferstuff"; +import {Player} from "../../../Player"; + +export class PacketLook extends Packet { + constructor() { + super({ + packetID: PacketEnum.Look + }) + } + + readData(reader: IReader, player: Player) { + player.updatePosition( + undefined, // X + undefined, // Y + undefined, // Stance + undefined, // Z + reader.readFloat(), // Yaw + reader.readFloat(), // Pitch + reader.readBool() // onGround + ); + } + + writeData() { + const player: Player = this.options.player; + + return createWriter(Endian.BE).writeUByte(this.options.packetID) + .writeLong(player.yaw) + .writeLong(player.pitch) + .writeBool(player.onGround) + .toBuffer(); + } +} \ No newline at end of file diff --git a/src/packet/impl/player/PacketPosition.ts b/src/packet/impl/player/PacketPosition.ts index 1bc813a..5e29f86 100644 --- a/src/packet/impl/player/PacketPosition.ts +++ b/src/packet/impl/player/PacketPosition.ts @@ -11,11 +11,15 @@ export class PacketPosition extends Packet { } readData(reader: IReader, player: Player) { - player.xPosition = reader.readDouble(); - player.yPosition = reader.readDouble(); - player.stance = reader.readDouble(); - player.zPosition = reader.readDouble(); - player.onGround = reader.readBool(); + player.updatePosition( + reader.readDouble(), // X + reader.readDouble(), // Y + reader.readDouble(), // Stance + reader.readDouble(), // Z + undefined, // Yaw + undefined, // Pitch + reader.readBool() // onGround + ); } writeData() { diff --git a/src/packet/impl/player/PacketPositionLook.ts b/src/packet/impl/player/PacketPositionLook.ts index 29d144b..ad82800 100644 --- a/src/packet/impl/player/PacketPositionLook.ts +++ b/src/packet/impl/player/PacketPositionLook.ts @@ -1,6 +1,6 @@ import {Packet} from "../../Packet"; import {PacketEnum} from "../../../utils/PacketEnum"; -import {createWriter, Endian, IReader} from "bufferstuff"; +import {createWriter, Endian, IReader, IWriter} from "bufferstuff"; import {Player} from "../../../Player"; export class PacketPositionLook extends Packet { @@ -11,13 +11,15 @@ export class PacketPositionLook extends Packet { } readData(reader: IReader, player: Player) { - player.xPosition = reader.readDouble(); - player.yPosition = reader.readDouble(); - player.stance = reader.readDouble(); - player.zPosition = reader.readDouble(); - player.yaw = reader.readFloat(); - player.pitch = reader.readFloat(); - player.onGround = reader.readBool(); + player.updatePosition( + reader.readDouble(), // X + reader.readDouble(), // Y + reader.readDouble(), // Stance + reader.readDouble(), // Z + reader.readFloat(), // Yaw + reader.readFloat(), // Pitch + reader.readBool() // onGround + ); } writeData() { @@ -28,8 +30,8 @@ export class PacketPositionLook extends Packet { .writeDouble(player.stance) .writeDouble(player.yPosition) .writeDouble(player.zPosition) - .writeLong(player.yaw) - .writeLong(player.pitch) + .writeFloat(player.yaw) + .writeFloat(player.pitch) .writeBool(player.onGround) .toBuffer(); } diff --git a/src/utils/PacketEnum.ts b/src/utils/PacketEnum.ts index cc201ee..0f9709e 100644 --- a/src/utils/PacketEnum.ts +++ b/src/utils/PacketEnum.ts @@ -9,6 +9,8 @@ export enum PacketEnum { Look = 0x0C, PositionLook = 0x0D, Animation = 0x12, + EntityPositionLook = 0x21, + EntityTeleport = 0x22, PreChunk = 0x32, MapChunk = 0x33, MultiBlockChange = 0x34, diff --git a/src/utils/PlayerManager.ts b/src/utils/PlayerManager.ts index f24bac3..0e78730 100644 --- a/src/utils/PlayerManager.ts +++ b/src/utils/PlayerManager.ts @@ -30,7 +30,7 @@ export class PlayerManager { if(packet === undefined) { if(MinecraftServer.debug) console.log(`Received Unknown packet: ${packetID}. Kicking the player.`); - this.kickPlayer(`Sent unknown packet ${packetID}`); + // this.kickPlayer(`Sent unknown packet ${packetID}`); return; } @@ -42,6 +42,7 @@ export class PlayerManager { this.socket.on('close', () => this.playerDisconnected()); this.socket.on('timeout', () => this.playerDisconnected()); + this.socket.on('error', () => this.playerDisconnected()); } public sendPacket(packet: Packet) {