WIP: Item Collection

This commit is contained in:
Holly Stubbs 2023-12-18 01:23:52 +00:00
parent 3ea5e47c57
commit dc05cd4a2d
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
9 changed files with 92 additions and 4 deletions

View file

@ -14,6 +14,7 @@ import { PacketDestroyEntity } from "./packets/DestroyEntity";
import { PacketPickupSpawn } from "./packets/PickupSpawn"; import { PacketPickupSpawn } from "./packets/PickupSpawn";
import { QueuedBlockUpdate } from "./queuedUpdateTypes/BlockUpdate"; import { QueuedBlockUpdate } from "./queuedUpdateTypes/BlockUpdate";
import { IQueuedUpdate } from "./queuedUpdateTypes/IQueuedUpdate"; import { IQueuedUpdate } from "./queuedUpdateTypes/IQueuedUpdate";
import AABB from "./AABB";
export class World { export class World {
public static ENTITY_MAX_SEND_DISTANCE = 50; public static ENTITY_MAX_SEND_DISTANCE = 50;
@ -25,6 +26,7 @@ export class World {
public chunks:FunkyArray<number, Chunk>; public chunks:FunkyArray<number, Chunk>;
public entites:FunkyArray<number, IEntity>; public entites:FunkyArray<number, IEntity>;
public players:FunkyArray<number, Player>; public players:FunkyArray<number, Player>;
public playerHitboxes:FunkyArray<number, AABB>;
public queuedChunkBlocks:Array<IQueuedUpdate>; public queuedChunkBlocks:Array<IQueuedUpdate>;
public queuedUpdates:Array<IQueuedUpdate>; public queuedUpdates:Array<IQueuedUpdate>;
@ -40,6 +42,7 @@ export class World {
this.chunks = new FunkyArray<number, Chunk>(); this.chunks = new FunkyArray<number, Chunk>();
this.entites = new FunkyArray<number, IEntity>(); this.entites = new FunkyArray<number, IEntity>();
this.players = new FunkyArray<number, Player>(); this.players = new FunkyArray<number, Player>();
this.playerHitboxes = new FunkyArray<number, AABB>();
this.queuedChunkBlocks = new Array<IQueuedUpdate>(); this.queuedChunkBlocks = new Array<IQueuedUpdate>();
this.queuedUpdates = new Array<IQueuedUpdate>(); this.queuedUpdates = new Array<IQueuedUpdate>();
this.generator = generator; this.generator = generator;
@ -47,6 +50,7 @@ export class World {
public addEntity(entity:IEntity) { public addEntity(entity:IEntity) {
this.entites.set(entity.entityId, entity); this.entites.set(entity.entityId, entity);
this.playerHitboxes.set(entity.entityId, entity.entityAABB);
if (entity instanceof Player) { if (entity instanceof Player) {
this.players.set(entity.entityId, entity); this.players.set(entity.entityId, entity);
} else if (entity instanceof EntityItem) { } else if (entity instanceof EntityItem) {
@ -72,6 +76,7 @@ export class World {
entity.loadedChunks = new Array<number>(); entity.loadedChunks = new Array<number>();
entity.justUnloaded = new Array<number>(); entity.justUnloaded = new Array<number>();
this.playerHitboxes.remove(entity.entityId);
this.players.remove(entity.entityId); this.players.remove(entity.entityId);
if (!entity.isDead) { if (!entity.isDead) {
@ -274,8 +279,7 @@ export class World {
if (entity instanceof Player) { if (entity instanceof Player) {
if (entity.justUnloaded.length > 0) { if (entity.justUnloaded.length > 0) {
for (const coordPair of entity.justUnloaded) { for (const coordPair of entity.justUnloaded) {
if (this.chunks.get(coordPair) != undefined) if (this.chunks.get(coordPair) != undefined) {
{
const chunkToUnload = this.getChunkByCoordPair(coordPair); const chunkToUnload = this.getChunkByCoordPair(coordPair);
chunkToUnload.playersInChunk.remove(entity.entityId); chunkToUnload.playersInChunk.remove(entity.entityId);
if (!chunkToUnload.forceLoaded && chunkToUnload.playersInChunk.length === 0) { if (!chunkToUnload.forceLoaded && chunkToUnload.playersInChunk.length === 0) {

View file

@ -15,6 +15,7 @@ import { PacketEntityRelativeMove } from "../packets/EntityRelativeMove";
import { PacketEntityTeleport } from "../packets/EntityTeleport"; import { PacketEntityTeleport } from "../packets/EntityTeleport";
import { PacketEntityVelocity } from "../packets/EntityVelocity"; import { PacketEntityVelocity } from "../packets/EntityVelocity";
import { IEntity } from "./IEntity"; import { IEntity } from "./IEntity";
import { Player } from "./Player";
export class Entity implements IEntity { export class Entity implements IEntity {
public static nextEntityId:number = 0; public static nextEntityId:number = 0;
@ -113,6 +114,17 @@ export class Entity implements IEntity {
.writeByte(this.health); .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) { sendToNearby(buffer:Buffer) {
this.world.sendToNearbyClients(this, buffer); this.world.sendToNearbyClients(this, buffer);
} }

View file

@ -1,6 +1,7 @@
import { World } from "../World"; import { World } from "../World";
import { ItemStack } from "../inventories/ItemStack"; import { ItemStack } from "../inventories/ItemStack";
import { Entity } from "./Entity"; import { Entity } from "./Entity";
import { Player } from "./Player";
export class EntityItem extends Entity { export class EntityItem extends Entity {
public age:number; public age:number;
@ -27,6 +28,15 @@ export class EntityItem extends Entity {
super.onTick(); super.onTick();
if (this.pickupDelay > 0) { if (this.pickupDelay > 0) {
this.pickupDelay--; 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); this.motion.add(0, -0.04, 0);

View file

@ -1,3 +1,4 @@
import AABB from "../AABB"
import Vec3 from "../Vec3" import Vec3 from "../Vec3"
export interface IEntity { export interface IEntity {
@ -8,6 +9,7 @@ export interface IEntity {
crouching:boolean, crouching:boolean,
isDead:boolean, isDead:boolean,
markedForDisposal:boolean, markedForDisposal:boolean,
entityAABB:AABB,
updateMetadata:() => void, updateMetadata:() => void,
distanceTo:(entity:IEntity) => number, distanceTo:(entity:IEntity) => number,
onTick:() => void onTick:() => void

View file

@ -13,6 +13,9 @@ import PlayerInventory from "../inventories/PlayerInventory";
import { Item } from "../items/Item"; import { Item } from "../items/Item";
import { PacketEntityEquipment } from "../packets/EntityEquipment"; import { PacketEntityEquipment } from "../packets/EntityEquipment";
import { IReader, IWriter } from "bufferstuff"; import { IReader, IWriter } from "bufferstuff";
import { EntityItem } from "./EntityItem";
import { Entity } from "./Entity";
import { PacketCollectItem } from "../packets/CollectItem";
const CHUNK_LOAD_RANGE = 15; const CHUNK_LOAD_RANGE = 15;
@ -34,7 +37,7 @@ export class Player extends EntityLiving {
this.loadedChunks = new Array<number>(); this.loadedChunks = new Array<number>();
this.justUnloaded = new Array<number>(); this.justUnloaded = new Array<number>();
this.inventory = new PlayerInventory(); this.inventory = new PlayerInventory(this);
this.inventory.setSlotItemStack(36, new ItemStack(Item.ironSword, 1)); this.inventory.setSlotItemStack(36, new ItemStack(Item.ironSword, 1));
this.inventory.setSlotItemStack(37, new ItemStack(Item.ironPickaxe, 1)); this.inventory.setSlotItemStack(37, new ItemStack(Item.ironPickaxe, 1));
@ -68,6 +71,14 @@ export class Player extends EntityLiving {
this.firstUpdate = true; 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() { private async updatePlayerChunks() {
const bitX = this.position.x >> 4; const bitX = this.position.x >> 4;
const bitZ = this.position.z >> 4; const bitZ = this.position.z >> 4;

View file

@ -22,6 +22,7 @@ export enum Packet {
EntityAction = 0x13, EntityAction = 0x13,
NamedEntitySpawn = 0x14, NamedEntitySpawn = 0x14,
PickupSpawn = 0x15, PickupSpawn = 0x15,
CollectItem = 0x16,
EntityVelocity = 0x1C, EntityVelocity = 0x1C,
DestroyEntity = 0x1D, DestroyEntity = 0x1D,

View file

@ -38,6 +38,7 @@ export class Inventory implements IInventory {
} }
addItemStack(itemStack:ItemStack) { addItemStack(itemStack:ItemStack) {
throw new Error("Adding items to non player inventories is unimplemented.");
// Check bottom inventory row (hotbar) first. // Check bottom inventory row (hotbar) first.
/*let workingItemStack:ItemStack | null; /*let workingItemStack:ItemStack | null;
for (let slotId = 9; slotId <= 35; slotId++) { for (let slotId = 9; slotId <= 35; slotId++) {
@ -106,4 +107,16 @@ export class Inventory implements IInventory {
return writer.toBuffer(); 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();
}
} }

View file

@ -1,9 +1,14 @@
import { Player } from "../entities/Player";
import { Inventory } from "./Inventory"; import { Inventory } from "./Inventory";
import { ItemStack } from "./ItemStack"; import { ItemStack } from "./ItemStack";
export default class PlayerInventory extends Inventory { export default class PlayerInventory extends Inventory {
public constructor() { private player:Player;
public constructor(player:Player) {
super(44, "Player Inventory"); super(44, "Player Inventory");
this.player = player;
} }
addItemStack(itemStack:ItemStack) { addItemStack(itemStack:ItemStack) {

View file

@ -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();
}
}