Reworked PlayerManager system and *kinda* made my code a bit better. Still have a lot of work to do tho.

This commit is contained in:
MrMasrozYTLIVE 2023-12-11 20:05:07 +03:00
parent 00e2cad9fa
commit 8847842c88
No known key found for this signature in database
11 changed files with 78 additions and 71 deletions

View File

@ -1,12 +1,14 @@
import { PacketManager } from "./utils/PacketManager"; import { PacketManager } from "./utils/PacketManager";
import {PlayerManager} from "./utils/PlayerManager"; import {PlayerManager} from "./utils/PlayerManager";
import {Server} from "node:net"; import {Server} from "node:net"; // TODO: Replace with https://bun.sh/docs/api/tcp
import {PacketDisconnectKick} from "./packet/impl/player/PacketDisconnectKick"; import {PacketDisconnectKick} from "./packet/impl/player/PacketDisconnectKick";
import {Player} from "./Player";
export class MinecraftServer { export class MinecraftServer {
public server: Server = new Server(); public server: Server = new Server();
public static debug: boolean = true; public static debug: boolean = true;
public static PlayerManagers = new Map<String, PlayerManager>();
// EntityMap = new Map<Number, IEntity>(); // EntityMap = new Map<Number, IEntity>();
public async start() { public async start() {
@ -18,7 +20,7 @@ export class MinecraftServer {
this.server.on('connection', socket => { this.server.on('connection', socket => {
if(MinecraftServer.debug) console.log('New connection!'); if(MinecraftServer.debug) console.log('New connection!');
PlayerManager.handleConnection(socket); new PlayerManager("Unknown", socket).handleConnection();
}); });
this.server.on('close', this.stop); this.server.on('close', this.stop);

View File

@ -1,8 +1,12 @@
import {Socket} from "node:net"; import {Socket} from "node:net";
import {IEntity} from "./IEntity"; import {IEntity} from "./IEntity";
import {PlayerManager} from "./utils/PlayerManager";
export class Player implements IEntity { export class Player implements IEntity {
public entityID: Number; public entityID: Number;
public username: String;
public socket: Socket;
public playerManager: PlayerManager;
public xPosition: number = 0; public xPosition: number = 0;
public yPosition: number = 100; public yPosition: number = 100;
@ -12,10 +16,9 @@ export class Player implements IEntity {
public pitch: number = 0; public pitch: number = 0;
public onGround: boolean = false; public onGround: boolean = false;
constructor(public options: IPlayerOption) {} constructor(username: String, socket: Socket, playerManager: PlayerManager) {
} this.username = username;
this.socket = socket;
export interface IPlayerOption { this.playerManager = playerManager;
client: Socket, }
username: String
} }

View File

@ -18,5 +18,4 @@ export interface IPacketOption {
player?: Player, player?: Player,
packetID: PacketEnum, packetID: PacketEnum,
name?: string, name?: string,
kickReason?: string
} }

View File

@ -12,7 +12,7 @@ export class PacketKeepAlive extends Packet {
} }
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
PlayerManager.sendPacket(player, this); player.playerManager.sendPacket(this);
} }
writeData() { writeData() {

View File

@ -4,9 +4,11 @@ import {createWriter, Endian, IReader} from "bufferstuff";
import {Player} from "../../../Player"; import {Player} from "../../../Player";
import {randomInt} from "node:crypto"; import {randomInt} from "node:crypto";
import {PlayerManager} from "../../../utils/PlayerManager"; import {PlayerManager} from "../../../utils/PlayerManager";
import {MinecraftServer} from "../../../MinecraftServer";
import {Socket} from "node:net";
export class PacketHandshake extends Packet { export class PacketHandshake extends Packet {
constructor() { constructor(public playerManager: PlayerManager) {
super({ super({
packetID: PacketEnum.Handshake packetID: PacketEnum.Handshake
}) })
@ -14,22 +16,27 @@ export class PacketHandshake extends Packet {
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
const username = reader.readString16(); const username = reader.readString16();
player = this.playerManager.player;
this.playerManager.username = username;
player.username = username;
if(PlayerManager.getPlayer(username)) { if(PlayerManager.getPlayer(username)) {
PlayerManager.kickPlayer(player, `Player with same username is already on the server.`); player.playerManager.kickPlayer(`Player with same username is already on the server.`);
return; return;
} }
if(username.length > 16) { if(username.length > 16) {
PlayerManager.kickPlayer(player, `Your username is too long!`); player.playerManager.kickPlayer(`Your username is too long!`);
return; return;
} }
player.options.username = username; player.username = username;
player.entityID = randomInt(0, 100); player.entityID = randomInt(0, 100);
PlayerManager.SocketMap.set(username, player.options.client); MinecraftServer.PlayerManagers.set(username, player.playerManager);
PlayerManager.sendPacket(player, this); player.playerManager.sendPacket(this);
} }
writeData() { writeData() {

View File

@ -7,8 +7,10 @@ import {PacketChat} from "../player/PacketChat";
import {PlayerManager} from "../../../utils/PlayerManager"; import {PlayerManager} from "../../../utils/PlayerManager";
import {PacketPreChunk} from "../world/PacketPreChunk"; import {PacketPreChunk} from "../world/PacketPreChunk";
import {PacketMapChunk} from "../world/PacketMapChunk"; import {PacketMapChunk} from "../world/PacketMapChunk";
import {PacketPosition} from "../player/PacketPosition";
import {PacketPositionLook} from "../player/PacketPositionLook";
export class PacketHandshake extends Packet { export class PacketLogin extends Packet {
constructor() { constructor() {
super({ super({
packetID: PacketEnum.Login packetID: PacketEnum.Login
@ -17,18 +19,18 @@ export class PacketHandshake extends Packet {
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
const protocol = reader.readInt(); const protocol = reader.readInt();
if(protocol > 14) PlayerManager.kickPlayer(player, `Server is outdated!`); if(protocol > 14) player.playerManager.kickPlayer(`Server is outdated!`);
else if (protocol < 14) PlayerManager.kickPlayer(player, `Client is outdated!`); else if (protocol < 14) player.playerManager.kickPlayer(`Client is outdated!`);
const username = reader.readString16(); const username = reader.readString16();
const seed = reader.readLong(); const seed = reader.readLong();
const dimension = reader.readByte(); const dimension = reader.readByte();
PlayerManager.sendPacket(player, this); player.playerManager.sendPacket(this);
PlayerManager.sendPacket(player, PacketManager.getPacket(PacketEnum.PositionLook)); player.playerManager.sendPacket(new PacketPositionLook());
PlayerManager.sendPacketToAll(new PacketChat(`§e<${username}> has joined the game.`)); PlayerManager.sendPacketToAll(new PacketChat(`§e<${username}> has joined the game.`));
PlayerManager.sendPacket(player, new PacketPreChunk()); player.playerManager.sendPacket(new PacketPreChunk());
PlayerManager.sendPacket(player, new PacketMapChunk()); player.playerManager.sendPacket(new PacketMapChunk());
} }
writeData() { writeData() {

View File

@ -12,7 +12,7 @@ export class PacketServerList extends Packet {
} }
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
PlayerManager.kickPlayer(player, `Beta 1.7.3 Server§0§0`); player.playerManager.kickPlayer(`Beta 1.7.3 Server§0§0`);
} }
writeData() { writeData() {

View File

@ -13,7 +13,7 @@ export class PacketChat extends Packet {
} }
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
this.message = `<${player.options.username}> ${reader.readString16()}` this.message = `<${player.username}> ${reader.readString16()}`
PlayerManager.sendPacketToAll(this); PlayerManager.sendPacketToAll(this);
} }

View File

@ -12,7 +12,7 @@ export class PacketDisconnectKick extends Packet {
} }
readData(reader: IReader, player: Player) { readData(reader: IReader, player: Player) {
PlayerManager.playerDisconnected(player.options.client); player.playerManager.playerDisconnected();
} }
writeData() { writeData() {

View File

@ -3,7 +3,7 @@ import {PacketEnum} from "../../../utils/PacketEnum";
import {createWriter, Endian, IReader} from "bufferstuff"; import {createWriter, Endian, IReader} from "bufferstuff";
import {Player} from "../../../Player"; import {Player} from "../../../Player";
export class PacketKick extends Packet { export class PacketPositionLook extends Packet {
constructor() { constructor() {
super({ super({
packetID: PacketEnum.PositionLook packetID: PacketEnum.PositionLook

View File

@ -6,80 +6,74 @@ import {Socket} from "node:net";
import {createReader, Endian} from "bufferstuff"; import {createReader, Endian} from "bufferstuff";
import {PacketManager} from "./PacketManager"; import {PacketManager} from "./PacketManager";
import {MinecraftServer} from "../MinecraftServer"; import {MinecraftServer} from "../MinecraftServer";
import {PacketEnum} from "./PacketEnum";
import {PacketHandshake} from "../packet/impl/login/PacketHandshake";
export class PlayerManager { export class PlayerManager {
static PlayerMap = new Map<Socket, Player>(); public player: Player;
static SocketMap = new Map<String, Socket>();
public static handleConnection(socket: Socket) { constructor(public username: string, public socket: Socket) {
if(!PlayerManager.PlayerMap.has(socket)) PlayerManager.PlayerMap.set(socket, new Player({ this.player = new Player(username, socket, this);
client: socket, }
username: "Unknown"
}));
socket.on('data', data => { public handleConnection() {
this.socket.on('data', data => {
const reader = createReader(Endian.BE, data); const reader = createReader(Endian.BE, data);
const packetID = reader.readUByte(); const packetID = reader.readUByte();
let packet: Packet; if(packetID == PacketEnum.Handshake) {
packet = PacketManager.getPacket(packetID); new PacketHandshake(this).readData(reader, null);
if(packet === undefined) {
if(MinecraftServer.debug) console.log(`Received Unknown packet: ${packetID}. Kicking the player.`);
PlayerManager.kickPlayer(PlayerManager.PlayerMap.get(socket), `Sent unknown packet ${packetID}`);
return; return;
} }
if(MinecraftServer.debug) console.log(`Received Packet: ${packet.options.name} (${packetID})`); let packet: Packet = PacketManager.getPacket(packetID);
packet.readData(reader, PlayerManager.PlayerMap.get(socket)); if(packet === undefined) {
if(MinecraftServer.debug) console.log(`Received Unknown packet: ${packetID}. Kicking the player.`);
this.kickPlayer(`Sent unknown packet ${packetID}`);
return;
}
if(MinecraftServer.debug && packetID != PacketEnum.Position && packetID != PacketEnum.PositionLook)
console.log(`Received Packet: ${packet.options.name} (${packetID})`);
packet.readData(reader, this.player);
}); });
socket.on('close', PlayerManager.playerDisconnected); this.socket.on('close', () => this.playerDisconnected());
socket.on('timeout', PlayerManager.playerDisconnected); this.socket.on('timeout', () => this.playerDisconnected());
} }
public static sendPacket(player: Player, packet: Packet) { public sendPacket(packet: Packet) {
if(!packet || !player) { if(!packet) {
console.log(`Tried to sent packet to player where either player or packet is null!`) console.log(`Tried to sent null packet!`)
return; return;
} }
if(MinecraftServer.debug) console.log(`Sending Packet: ${packet.options.name} (${packet.options.packetID}) to ${player.options.username}`); if(MinecraftServer.debug) console.log(`Sending Packet: ${packet.options.name} (${packet.options.packetID}) to ${this.username}`);
packet.options.player = player; packet.options.player = this.player;
player.options.client.write(packet.writeData()); this.player.socket.write(packet.writeData());
} }
public static sendPacketToAll(packet: Packet) { public static sendPacketToAll(packet: Packet) {
PlayerManager.PlayerMap.forEach(player => { MinecraftServer.PlayerManagers.forEach(manager => {
PlayerManager.sendPacket(player, packet); manager.sendPacket(packet);
}) })
} }
public static kickPlayer(player: Player, reason: string) { public kickPlayer(reason: string) {
if(!player) { this.sendPacket(new PacketDisconnectKick(reason));
console.log(`Tried to kick null player!`);
return;
}
PlayerManager.sendPacket(player, new PacketDisconnectKick(reason));
this.playerDisconnected(player.options.client);
} }
public static playerDisconnected(socket: Socket) { public playerDisconnected() {
const player = PlayerManager.PlayerMap.get(socket); if(MinecraftServer.debug) console.log(`Player ${this.username} left. Deleting from the map!`);
if(!player) return; MinecraftServer.PlayerManagers.delete(this.username);
const username = player.options.username; PlayerManager.sendPacketToAll(new PacketChat(`§e<${this.username}> left the game.`));
if(MinecraftServer.debug) console.log(`Player ${username} left. Deleting from the map!`);
PlayerManager.SocketMap.delete(username);
PlayerManager.PlayerMap.delete(socket);
PlayerManager.sendPacketToAll(new PacketChat(`§e<${username}> left the game.`));
} }
public static getPlayer(username: String) { public static getPlayer(username: String) {
return PlayerManager.PlayerMap.get(PlayerManager.SocketMap.get(username)); return MinecraftServer.PlayerManagers.get(username)?.player;
} }
} }