implement dimension switching

This commit is contained in:
Holly Stubbs 2023-09-04 23:42:38 +01:00
parent 9feafc46c7
commit 74374cb0d6
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
8 changed files with 67 additions and 17 deletions

View file

@ -57,8 +57,6 @@ export class Chunk {
public getTopBlockY(x:number, z:number) { public getTopBlockY(x:number, z:number) {
let castY = this.MAX_HEIGHT; let castY = this.MAX_HEIGHT;
while (castY-- > 0) { while (castY-- > 0) {
const blockId = this.getBlockId(x >>> 0, castY, z >>> 0);
console.log(blockId === 0 ? "Air" : Block.blocks[blockId].blockName);
if (this.getBlockId(x >>> 0, castY, z >>> 0) !== 0) { if (this.getBlockId(x >>> 0, castY, z >>> 0) !== 0) {
break; break;
} }

View file

@ -13,11 +13,13 @@ import { PacketPlayerDigging } from "./packets/PlayerDigging";
import { Player } from "./entities/Player"; import { Player } from "./entities/Player";
import { Socket } from "net"; import { Socket } from "net";
import { Vec3 } from "./Vec3"; import { Vec3 } from "./Vec3";
import { PacketRespawn } from "./packets/Respawn";
import { PacketSpawnPosition } from "./packets/SpawnPosition";
export class MPClient { export class MPClient {
private readonly mcServer:MinecraftServer; private readonly mcServer:MinecraftServer;
private readonly socket:Socket; private readonly socket:Socket;
public readonly entity:Player; public entity:Player;
private diggingAt:Vec3; private diggingAt:Vec3;
@ -77,15 +79,25 @@ export class MPClient {
if (message[0].startsWith("/")) { if (message[0].startsWith("/")) {
packet.message = ""; packet.message = "";
if (message[0] === "/tp") { if (message[0] === "/tp") {
this.send(new PacketPlayerPositionLook(parseFloat(message[1]), parseFloat(message[2]), parseFloat(message[2]) + 0.62, parseFloat(message[3]), 0, 0, false).writeData()); const x = this.entity.x = parseFloat(message[1]);
const y = this.entity.y = parseFloat(message[2]);
const z = this.entity.z = parseFloat(message[3]);
this.send(new PacketPlayerPositionLook(x, y, y + 0.62, z, 0, 0, false).writeData());
Console.printInfo(packet.message = `Teleported ${this.entity.username} to ${message[1]} ${message[2]} ${message[3]}`); Console.printInfo(packet.message = `Teleported ${this.entity.username} to ${message[1]} ${message[2]} ${message[3]}`);
} else if (message[0] === "/csay") { } else if (message[0] === "/csay") {
this.mcServer.sendChatMessage(`[CONSOLE] ${message.slice(1, message.length).join(" ")}`); this.mcServer.sendChatMessage(`[CONSOLE] ${message.slice(1, message.length).join(" ")}`);
} else if (message[0] === "/top") { } else if (message[0] === "/top") {
packet.message = `Woosh!`; packet.message = `Woosh!`;
const topBlock = this.entity.world.getChunk(this.entity.x >> 4, this.entity.z >> 4).getTopBlockY(this.entity.x & 0xf, this.entity.z & 0xf); const topBlock = this.entity.world.getChunk(this.entity.x >> 4, this.entity.z >> 4).getTopBlockY(this.entity.x & 0xf, this.entity.z & 0xf);
console.log(topBlock);
this.send(new PacketPlayerPosition(this.entity.x, topBlock + 3, topBlock + 3.62, this.entity.z, false).writeData()); this.send(new PacketPlayerPosition(this.entity.x, topBlock + 3, topBlock + 3.62, this.entity.z, false).writeData());
} else if (message[0] === "/tpx") {
const dimension = parseInt(message[1]);
if (this.mcServer.worlds.has(dimension)) {
packet.message = "\u00a76Switching dimensions...";
this.switchDimension(dimension);
} else {
packet.message = `\u00a7cNo dimension by id "${dimension} exists!"`;
}
} }
if (packet.message !== "") { if (packet.message !== "") {
@ -157,6 +169,26 @@ export class MPClient {
} }
} }
private switchDimension(dimension:number) {
const world = this.mcServer.worlds.get(dimension);
if (world == undefined) {
return;
}
this.entity.world.removeEntity(this.entity);
this.entity.world = world;
world.addEntity(this.entity);
this.send(new PacketRespawn(dimension).writeData());
//this.send(new PacketSpawnPosition(8, 64, 8).writeData());
this.entity.x = 8;
this.entity.y = 70;
this.entity.z = 8;
this.send(new PacketPlayerPositionLook(8, 70, 70.62, 8, 0, 0, false).writeData());
this.entity.forceUpdatePlayerChunks();
}
private handleDisconnectKick() { private handleDisconnectKick() {
this.socket.end(); this.socket.end();
} }

View file

@ -33,7 +33,7 @@ export class MinecraftServer {
private readonly serverClock:NodeJS.Timeout; private readonly serverClock:NodeJS.Timeout;
private tickCounter:number = 0; private tickCounter:number = 0;
private clients:FunkyArray<string, MPClient>; private clients:FunkyArray<string, MPClient>;
private worlds:FunkyArray<number, World>; public worlds:FunkyArray<number, World>;
public saveManager:WorldSaveManager; public saveManager:WorldSaveManager;
private overworld:World; private overworld:World;
private nether:World; private nether:World;

View file

@ -61,6 +61,10 @@ export class World {
} }
} }
} }
// Clear player chunk list (they may be switching dimensions)
entity.loadedChunks = new Array<number>();
entity.justUnloaded = new Array<number>();
this.players.remove(entity.entityId); this.players.remove(entity.entityId);
} }

View file

@ -28,6 +28,8 @@ export class Entity implements IEntity {
private lastCrouchState:boolean; private lastCrouchState:boolean;
private lastFireState:boolean; private lastFireState:boolean;
private queuedChunkUpdate:boolean;
public constructor(world:World) { public constructor(world:World) {
this.entityId = Entity.nextEntityId++; this.entityId = Entity.nextEntityId++;
@ -35,7 +37,7 @@ export class Entity implements IEntity {
this.world = world; this.world = world;
this.x = this.y = this.z = this.lastX = this.lastY = this.lastZ = 0; this.x = this.y = this.z = this.lastX = this.lastY = this.lastZ = 0;
this.crouching = this.lastCrouchState = this.lastFireState = false; this.crouching = this.lastCrouchState = this.lastFireState = this.queuedChunkUpdate = false;
this.chunk = world.getChunk(this.x >> 4, this.z >> 4); this.chunk = world.getChunk(this.x >> 4, this.z >> 4);
@ -92,8 +94,13 @@ export class Entity implements IEntity {
updateEntityChunk() { updateEntityChunk() {
const bitX = this.x >> 4; const bitX = this.x >> 4;
const bitZ = this.z >> 4; const bitZ = this.z >> 4;
if (bitX != this.lastX >> 4 || bitZ != this.lastZ >> 4) { if (bitX != this.lastX >> 4 || bitZ != this.lastZ >> 4 || this.queuedChunkUpdate) {
if (this.world.chunkExists(bitX, bitZ)) {
this.chunk = this.world.getChunk(bitX, bitZ); this.chunk = this.world.getChunk(bitX, bitZ);
this.queuedChunkUpdate = false;
} else {
this.queuedChunkUpdate = true;
}
} }
} }

View file

@ -101,7 +101,6 @@ export class EntityLiving extends Entity {
// Drowning // Drowning
if (this.isInWater()) { if (this.isInWater()) {
console.log("in water!");
if (this.timeInWater == Number.MIN_SAFE_INTEGER) { if (this.timeInWater == Number.MIN_SAFE_INTEGER) {
this.timeInWater = 320; this.timeInWater = 320;
} }

View file

@ -7,6 +7,8 @@ import { EntityLiving } from "./EntityLiving";
import { PacketPreChunk } from "../packets/PreChunk"; import { PacketPreChunk } from "../packets/PreChunk";
import { PacketUpdateHealth } from "../packets/UpdateHealth"; import { PacketUpdateHealth } from "../packets/UpdateHealth";
const CHUNK_LOAD_RANGE = 5;
export class Player extends EntityLiving { export class Player extends EntityLiving {
public username:string; public username:string;
private server:MinecraftServer; private server:MinecraftServer;
@ -32,6 +34,10 @@ export class Player extends EntityLiving {
this.lastHealth = this.health; this.lastHealth = this.health;
} }
public forceUpdatePlayerChunks() {
this.firstUpdate = true;
}
private async updatePlayerChunks() { private async updatePlayerChunks() {
const bitX = this.x >> 4; const bitX = this.x >> 4;
const bitZ = this.z >> 4; const bitZ = this.z >> 4;
@ -47,8 +53,8 @@ export class Player extends EntityLiving {
// Load or keep any chunks we need // Load or keep any chunks we need
const currentLoads = []; const currentLoads = [];
for (let x = bitX - 10; x < bitX + 10; x++) { for (let x = bitX - CHUNK_LOAD_RANGE; x < bitX + CHUNK_LOAD_RANGE; x++) {
for (let z = bitZ - 10; z < bitZ + 10; z++) { for (let z = bitZ - CHUNK_LOAD_RANGE; z < bitZ + CHUNK_LOAD_RANGE; z++) {
const coordPair = Chunk.CreateCoordPair(x, z); const coordPair = Chunk.CreateCoordPair(x, z);
if (!this.loadedChunks.includes(coordPair)) { if (!this.loadedChunks.includes(coordPair)) {
const chunk = await this.world.getChunkSafe(x, z); const chunk = await this.world.getChunkSafe(x, z);

View file

@ -4,19 +4,23 @@ import { Packet } from "../enums/Packet";
export class PacketRespawn implements IPacket { export class PacketRespawn implements IPacket {
public packetId = Packet.Respawn; public packetId = Packet.Respawn;
public health:number; public dimension:number;
public constructor(health:number) { public constructor(dimension?:number) {
this.health = health; if (typeof(dimension) == "number") {
this.dimension = dimension;
} else {
this.dimension = Number.MIN_VALUE;
}
} }
public readData(reader:IReader) { public readData(reader:IReader) {
this.health = reader.readShort(); this.dimension = reader.readByte();
return this; return this;
} }
public writeData() { public writeData() {
return createWriter(Endian.BE, 3).writeUByte(this.packetId).writeShort(this.health).toBuffer(); return createWriter(Endian.BE, 2).writeUByte(this.packetId).writeByte(this.dimension).toBuffer();
} }
} }