2023-11-09 17:04:11 +00:00
|
|
|
import { Endian, IReader, IWriter, createWriter } from "bufferstuff";
|
2024-11-29 15:00:48 +00:00
|
|
|
import FunkyArray from "funky-array";
|
2023-10-29 05:08:26 +00:00
|
|
|
import IInventory from "./IInventory";
|
2024-10-26 14:24:38 +01:00
|
|
|
import ItemStack from "./ItemStack";
|
2023-10-29 05:08:26 +00:00
|
|
|
|
2024-10-26 14:24:38 +01:00
|
|
|
export default class Inventory implements IInventory {
|
2024-11-29 15:00:48 +00:00
|
|
|
private static CHANGE_HANDLER_ROLLING_HANDLE_ID = 0;
|
|
|
|
|
2024-12-02 00:25:03 +00:00
|
|
|
public changeHandlers:FunkyArray<number, (itemStack: number) => void>;
|
2023-11-02 08:31:43 +00:00
|
|
|
public itemStacks:Array<ItemStack | null>;
|
2023-10-29 05:08:26 +00:00
|
|
|
|
2024-12-01 00:19:32 +00:00
|
|
|
public readonly size:number;
|
|
|
|
public readonly name:string;
|
2023-10-29 05:08:26 +00:00
|
|
|
|
|
|
|
public constructor(size:number, name:string) {
|
2024-12-02 00:25:03 +00:00
|
|
|
this.changeHandlers = new FunkyArray<number, (itemStack: number) => void>();
|
2023-10-29 05:08:26 +00:00
|
|
|
this.itemStacks = new Array<ItemStack | null>();
|
|
|
|
for (let i = 0; i < size; i++) {
|
|
|
|
this.itemStacks.push(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.size = size;
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
|
2024-12-02 00:25:03 +00:00
|
|
|
registerChangeHandler(changeHandler: (slotId: number) => void) {
|
2024-11-29 15:00:48 +00:00
|
|
|
const changeHandlerHandle = Inventory.CHANGE_HANDLER_ROLLING_HANDLE_ID++;
|
|
|
|
this.changeHandlers.set(changeHandlerHandle, changeHandler);
|
|
|
|
return changeHandlerHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
unregisterChangeHandler(changeHandlerHandle: number) {
|
|
|
|
if (this.changeHandlers.has(changeHandlerHandle)) {
|
|
|
|
this.changeHandlers.remove(changeHandlerHandle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-09 17:04:11 +00:00
|
|
|
public fromSave(reader:IReader) {
|
|
|
|
const inventorySize = reader.readByte();
|
|
|
|
for (let i = 0; i < inventorySize; i++) {
|
|
|
|
this.itemStacks[i] = ItemStack.FromSave(reader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public toSave(writer:IWriter) {
|
|
|
|
writer.writeByte(this.size);
|
|
|
|
for (const itemStack of this.itemStacks) {
|
|
|
|
if (itemStack === null) {
|
|
|
|
writer.writeShort(-1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
itemStack.toSave(writer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-02 00:25:03 +00:00
|
|
|
sendSlotUpdate(slotId: number) {
|
|
|
|
this.changeHandlers.forEach(handler => handler(slotId));
|
|
|
|
}
|
|
|
|
|
2023-11-02 08:31:43 +00:00
|
|
|
addItemStack(itemStack:ItemStack) {
|
2024-12-01 00:19:32 +00:00
|
|
|
for (let slotId = 0; slotId < this.itemStacks.length; slotId++) {
|
2023-11-02 08:31:43 +00:00
|
|
|
if (itemStack.size === 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-01 00:19:32 +00:00
|
|
|
this.itemStacks[slotId]?.insert(itemStack);
|
2024-12-02 00:25:03 +00:00
|
|
|
this.changeHandlers.forEach(handler => handler(slotId));
|
2024-12-01 00:19:32 +00:00
|
|
|
}
|
2023-11-02 08:31:43 +00:00
|
|
|
}
|
|
|
|
|
2023-10-29 05:08:26 +00:00
|
|
|
getInventoryName() {
|
|
|
|
return this.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
getInventorySize() {
|
|
|
|
return this.itemStacks.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSlotItemStack(slotId:number) {
|
|
|
|
return this.itemStacks[slotId];
|
|
|
|
}
|
|
|
|
|
2023-11-07 01:50:51 +00:00
|
|
|
dropEmptyItemStacks() {
|
|
|
|
for (let i = 0; i < this.itemStacks.length; i++) {
|
|
|
|
const itemStack = this.itemStacks[i];
|
|
|
|
if (itemStack?.size === 0) {
|
|
|
|
this.itemStacks[i] = null;
|
2024-12-02 00:25:03 +00:00
|
|
|
this.changeHandlers.forEach(handler => handler(i));
|
2023-11-07 01:50:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-29 05:08:26 +00:00
|
|
|
setSlotItemStack(slotId:number, itemStack: ItemStack | null) {
|
|
|
|
if (slotId < 0 || slotId > this.size - 1) {
|
|
|
|
throw new Error(`Tried to set an Inventory ItemStack out of bounds! Requested slot: ${slotId}, Inventory Size: ${this.size}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.itemStacks[slotId] = itemStack;
|
2024-12-02 00:25:03 +00:00
|
|
|
this.changeHandlers.forEach(handler => handler(slotId));
|
2023-10-29 05:08:26 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-12-01 00:19:32 +00:00
|
|
|
public calculateInventoryPayloadSize(skip: number) {
|
2023-10-29 05:08:26 +00:00
|
|
|
let bufferSize = 0;
|
2024-12-01 00:19:32 +00:00
|
|
|
for (let i = skip; i < this.itemStacks.length; i++) {
|
|
|
|
const stack = this.itemStacks[i];
|
2023-10-29 05:08:26 +00:00
|
|
|
if (stack) {
|
|
|
|
bufferSize += 5; // short + byte + short
|
|
|
|
} else {
|
|
|
|
bufferSize += 2; // short
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bufferSize;
|
|
|
|
}
|
|
|
|
|
2024-12-01 00:19:32 +00:00
|
|
|
constructInventoryPayload(skip: number) {
|
|
|
|
const writer = createWriter(Endian.BE, this.calculateInventoryPayloadSize(skip));
|
|
|
|
for (let i = skip; i < this.itemStacks.length; i++) {
|
|
|
|
const stack = this.itemStacks[i];
|
2023-10-29 05:08:26 +00:00
|
|
|
writer.writeShort(stack == null ? -1 : stack.itemID);
|
|
|
|
if (stack != null) {
|
|
|
|
writer.writeByte(stack.size);
|
|
|
|
writer.writeShort(stack.damage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return writer.toBuffer();
|
|
|
|
}
|
2023-12-18 01:23:52 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2023-10-29 05:08:26 +00:00
|
|
|
}
|