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 {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 {Player} from "./Player";
export class MinecraftServer {
public server: Server = new Server();
public static debug: boolean = true;
public static PlayerManagers = new Map<String, PlayerManager>();
// EntityMap = new Map<Number, IEntity>();
public async start() {
@ -18,7 +20,7 @@ export class MinecraftServer {
this.server.on('connection', socket => {
if(MinecraftServer.debug) console.log('New connection!');
PlayerManager.handleConnection(socket);
new PlayerManager("Unknown", socket).handleConnection();
});
this.server.on('close', this.stop);

View File

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

View File

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

View File

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

View File

@ -4,9 +4,11 @@ import {createWriter, Endian, IReader} from "bufferstuff";
import {Player} from "../../../Player";
import {randomInt} from "node:crypto";
import {PlayerManager} from "../../../utils/PlayerManager";
import {MinecraftServer} from "../../../MinecraftServer";
import {Socket} from "node:net";
export class PacketHandshake extends Packet {
constructor() {
constructor(public playerManager: PlayerManager) {
super({
packetID: PacketEnum.Handshake
})
@ -14,22 +16,27 @@ export class PacketHandshake extends Packet {
readData(reader: IReader, player: Player) {
const username = reader.readString16();
player = this.playerManager.player;
this.playerManager.username = username;
player.username = 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;
}
if(username.length > 16) {
PlayerManager.kickPlayer(player, `Your username is too long!`);
player.playerManager.kickPlayer(`Your username is too long!`);
return;
}
player.options.username = username;
player.username = username;
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() {

View File

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

View File

@ -12,7 +12,7 @@ export class PacketServerList extends Packet {
}
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() {

View File

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

View File

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

View File

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

View File

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