From dc05cd4a2d802bf280ad20f30f0ef059539e71ba Mon Sep 17 00:00:00 2001 From: Holly Date: Mon, 18 Dec 2023 01:23:52 +0000 Subject: [PATCH] WIP: Item Collection --- server/World.ts | 8 +++++-- server/entities/Entity.ts | 12 +++++++++++ server/entities/EntityItem.ts | 10 +++++++++ server/entities/IEntity.ts | 2 ++ server/entities/Player.ts | 13 +++++++++++- server/enums/Packet.ts | 1 + server/inventories/Inventory.ts | 13 ++++++++++++ server/inventories/PlayerInventory.ts | 7 ++++++- server/packets/CollectItem.ts | 30 +++++++++++++++++++++++++++ 9 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 server/packets/CollectItem.ts diff --git a/server/World.ts b/server/World.ts index eade78f..642a060 100644 --- a/server/World.ts +++ b/server/World.ts @@ -14,6 +14,7 @@ import { PacketDestroyEntity } from "./packets/DestroyEntity"; import { PacketPickupSpawn } from "./packets/PickupSpawn"; import { QueuedBlockUpdate } from "./queuedUpdateTypes/BlockUpdate"; import { IQueuedUpdate } from "./queuedUpdateTypes/IQueuedUpdate"; +import AABB from "./AABB"; export class World { public static ENTITY_MAX_SEND_DISTANCE = 50; @@ -25,6 +26,7 @@ export class World { public chunks:FunkyArray; public entites:FunkyArray; public players:FunkyArray; + public playerHitboxes:FunkyArray; public queuedChunkBlocks:Array; public queuedUpdates:Array; @@ -40,6 +42,7 @@ export class World { this.chunks = new FunkyArray(); this.entites = new FunkyArray(); this.players = new FunkyArray(); + this.playerHitboxes = new FunkyArray(); this.queuedChunkBlocks = new Array(); this.queuedUpdates = new Array(); this.generator = generator; @@ -47,6 +50,7 @@ export class World { public addEntity(entity:IEntity) { this.entites.set(entity.entityId, entity); + this.playerHitboxes.set(entity.entityId, entity.entityAABB); if (entity instanceof Player) { this.players.set(entity.entityId, entity); } else if (entity instanceof EntityItem) { @@ -72,6 +76,7 @@ export class World { entity.loadedChunks = new Array(); entity.justUnloaded = new Array(); + this.playerHitboxes.remove(entity.entityId); this.players.remove(entity.entityId); if (!entity.isDead) { @@ -274,8 +279,7 @@ export class World { if (entity instanceof Player) { if (entity.justUnloaded.length > 0) { for (const coordPair of entity.justUnloaded) { - if (this.chunks.get(coordPair) != undefined) - { + if (this.chunks.get(coordPair) != undefined) { const chunkToUnload = this.getChunkByCoordPair(coordPair); chunkToUnload.playersInChunk.remove(entity.entityId); if (!chunkToUnload.forceLoaded && chunkToUnload.playersInChunk.length === 0) { diff --git a/server/entities/Entity.ts b/server/entities/Entity.ts index 672bb86..7e1f2cd 100644 --- a/server/entities/Entity.ts +++ b/server/entities/Entity.ts @@ -15,6 +15,7 @@ import { PacketEntityRelativeMove } from "../packets/EntityRelativeMove"; import { PacketEntityTeleport } from "../packets/EntityTeleport"; import { PacketEntityVelocity } from "../packets/EntityVelocity"; import { IEntity } from "./IEntity"; +import { Player } from "./Player"; export class Entity implements IEntity { public static nextEntityId:number = 0; @@ -113,6 +114,17 @@ export class Entity implements IEntity { .writeByte(this.health); } + collidesWithPlayer(aabb:AABB) { + let collidedWith:Player | undefined; + this.world.players.forEach(player => { + if (this.entityAABB.intersects(player.entityAABB)) { + collidedWith = player; + } + }); + + return collidedWith; + } + sendToNearby(buffer:Buffer) { this.world.sendToNearbyClients(this, buffer); } diff --git a/server/entities/EntityItem.ts b/server/entities/EntityItem.ts index 3ee2d9e..a9954b7 100644 --- a/server/entities/EntityItem.ts +++ b/server/entities/EntityItem.ts @@ -1,6 +1,7 @@ import { World } from "../World"; import { ItemStack } from "../inventories/ItemStack"; import { Entity } from "./Entity"; +import { Player } from "./Player"; export class EntityItem extends Entity { public age:number; @@ -27,6 +28,15 @@ export class EntityItem extends Entity { super.onTick(); if (this.pickupDelay > 0) { this.pickupDelay--; + } else { + let playerCollided; + if (playerCollided = this.collidesWithPlayer(this.entityAABB)) { + playerCollided.inventory.addItemStack(this.itemStack); + playerCollided.itemPickup(this, this.itemStack.size); + if (this.itemStack.size <= 0) { + this.kill(); + } + } } this.motion.add(0, -0.04, 0); diff --git a/server/entities/IEntity.ts b/server/entities/IEntity.ts index e668c87..f5bc8bd 100644 --- a/server/entities/IEntity.ts +++ b/server/entities/IEntity.ts @@ -1,3 +1,4 @@ +import AABB from "../AABB" import Vec3 from "../Vec3" export interface IEntity { @@ -8,6 +9,7 @@ export interface IEntity { crouching:boolean, isDead:boolean, markedForDisposal:boolean, + entityAABB:AABB, updateMetadata:() => void, distanceTo:(entity:IEntity) => number, onTick:() => void diff --git a/server/entities/Player.ts b/server/entities/Player.ts index 8837141..d838683 100644 --- a/server/entities/Player.ts +++ b/server/entities/Player.ts @@ -13,6 +13,9 @@ import PlayerInventory from "../inventories/PlayerInventory"; import { Item } from "../items/Item"; import { PacketEntityEquipment } from "../packets/EntityEquipment"; import { IReader, IWriter } from "bufferstuff"; +import { EntityItem } from "./EntityItem"; +import { Entity } from "./Entity"; +import { PacketCollectItem } from "../packets/CollectItem"; const CHUNK_LOAD_RANGE = 15; @@ -34,7 +37,7 @@ export class Player extends EntityLiving { this.loadedChunks = new Array(); this.justUnloaded = new Array(); - this.inventory = new PlayerInventory(); + this.inventory = new PlayerInventory(this); this.inventory.setSlotItemStack(36, new ItemStack(Item.ironSword, 1)); this.inventory.setSlotItemStack(37, new ItemStack(Item.ironPickaxe, 1)); @@ -68,6 +71,14 @@ export class Player extends EntityLiving { this.firstUpdate = true; } + public itemPickup(entity:Entity, stackSize:number) { + if (!this.isDead) { + if (entity instanceof EntityItem) { + this.sendToAllNearby(new PacketCollectItem(entity.entityId, this.entityId).writeData()); + } + } + } + private async updatePlayerChunks() { const bitX = this.position.x >> 4; const bitZ = this.position.z >> 4; diff --git a/server/enums/Packet.ts b/server/enums/Packet.ts index 3de4911..53a90ef 100644 --- a/server/enums/Packet.ts +++ b/server/enums/Packet.ts @@ -22,6 +22,7 @@ export enum Packet { EntityAction = 0x13, NamedEntitySpawn = 0x14, PickupSpawn = 0x15, + CollectItem = 0x16, EntityVelocity = 0x1C, DestroyEntity = 0x1D, diff --git a/server/inventories/Inventory.ts b/server/inventories/Inventory.ts index 1cdd86c..1599d76 100644 --- a/server/inventories/Inventory.ts +++ b/server/inventories/Inventory.ts @@ -38,6 +38,7 @@ export class Inventory implements IInventory { } addItemStack(itemStack:ItemStack) { + throw new Error("Adding items to non player inventories is unimplemented."); // Check bottom inventory row (hotbar) first. /*let workingItemStack:ItemStack | null; for (let slotId = 9; slotId <= 35; slotId++) { @@ -106,4 +107,16 @@ export class Inventory implements IInventory { return writer.toBuffer(); } + + constructInventorySinglePayload(slotId:number) { + const stack = this.itemStacks[slotId]; + const writer = createWriter(Endian.BE, stack == null ? 2 : 5); + writer.writeShort(stack == null ? -1 : stack.itemID); + if (stack != null) { + writer.writeByte(stack.size); + writer.writeShort(stack.damage); + } + + return writer.toBuffer(); + } } \ No newline at end of file diff --git a/server/inventories/PlayerInventory.ts b/server/inventories/PlayerInventory.ts index ab464ac..a842da6 100644 --- a/server/inventories/PlayerInventory.ts +++ b/server/inventories/PlayerInventory.ts @@ -1,9 +1,14 @@ +import { Player } from "../entities/Player"; import { Inventory } from "./Inventory"; import { ItemStack } from "./ItemStack"; export default class PlayerInventory extends Inventory { - public constructor() { + private player:Player; + + public constructor(player:Player) { super(44, "Player Inventory"); + + this.player = player; } addItemStack(itemStack:ItemStack) { diff --git a/server/packets/CollectItem.ts b/server/packets/CollectItem.ts new file mode 100644 index 0000000..f6e5993 --- /dev/null +++ b/server/packets/CollectItem.ts @@ -0,0 +1,30 @@ +import { createWriter, IReader, Endian } from "bufferstuff"; +import { IPacket } from "./IPacket"; +import { Packet } from "../enums/Packet"; + +export class PacketCollectItem implements IPacket { + public packetId = Packet.CollectItem; + public collectedEID:number; + public collectorEID:number; + + public constructor(collectedEID?:number, collectorEID?:number) { + if (typeof(collectedEID) === "number" && typeof(collectorEID) === "number") { + this.collectedEID = collectedEID; + this.collectorEID = collectorEID; + } else { + this.collectedEID = Number.MIN_VALUE; + this.collectorEID = Number.MIN_VALUE; + } + } + + public readData(reader:IReader) { + this.collectedEID = reader.readInt(); + this.collectorEID = reader.readInt(); + + return this; + } + + public writeData() { + return createWriter(Endian.BE, 9).writeUByte(this.packetId).writeInt(this.collectedEID).writeInt(this.collectorEID).toBuffer(); + } +} \ No newline at end of file