chests work better i suppose, but it crashes now :c
All checks were successful
Node.js Build / build (20.x) (push) Successful in 5m16s

This commit is contained in:
Holly Stubbs 2024-12-01 00:19:32 +00:00
parent 65d31be4f9
commit 7c59d531ae
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
8 changed files with 128 additions and 33 deletions

View file

@ -33,6 +33,7 @@ import WindowChest from "./windows/WindowChest";
import TileEntityChest from "./tileentities/TileEntityChest"; import TileEntityChest from "./tileentities/TileEntityChest";
import WindowCrafting from "./windows/WindowCrafting"; import WindowCrafting from "./windows/WindowCrafting";
import PacketWindowClick from "./packets/WindowClick"; import PacketWindowClick from "./packets/WindowClick";
import PlayerCombinedInventory from "./inventories/PlayerCombinedInventory";
export default class MPClient { export default class MPClient {
private readonly mcServer:MinecraftServer; private readonly mcServer:MinecraftServer;
@ -280,12 +281,12 @@ export default class MPClient {
if (blockClicked.is(Block.chest)) { if (blockClicked.is(Block.chest)) {
const tileEntity = this.entity.world.getChunk(packet.x >> 4, packet.z >> 4).getTileEntity(packet.x, packet.y, packet.z); const tileEntity = this.entity.world.getChunk(packet.x >> 4, packet.z >> 4).getTileEntity(packet.x, packet.y, packet.z);
if (tileEntity && tileEntity instanceof TileEntityChest) { if (tileEntity && tileEntity instanceof TileEntityChest) {
const window = new WindowChest(tileEntity.inventory); const window = new WindowChest(PlayerCombinedInventory.FromExisting(this, tileEntity.inventory, tileEntity.inventory.name));
this.windows.set(window.windowId, window); this.windows.set(window.windowId, window);
window.openWindow(this); window.openWindow(this);
} }
} else if (blockClicked.is(Block.craftingTable)) { } else if (blockClicked.is(Block.craftingTable)) {
const window = new WindowCrafting(this); const window = new WindowCrafting(new PlayerCombinedInventory(this, 10, "Crafting"));
this.windows.set(window.windowId, window); this.windows.set(window.windowId, window);
window.openWindow(this); window.openWindow(this);
} }

View file

@ -248,7 +248,7 @@ export default class MinecraftServer {
socket.write(new PacketPlayerPositionLook(clientEntity.position.x, clientEntity.position.y, clientEntity.position.y + 0.62, clientEntity.position.z, 0, 0, false).writeData()); socket.write(new PacketPlayerPositionLook(clientEntity.position.x, clientEntity.position.y, clientEntity.position.y + 0.62, clientEntity.position.z, 0, 0, false).writeData());
const playerInventory = clientEntity.inventory; const playerInventory = clientEntity.inventory;
socket.write(new PacketWindowItems(0, playerInventory.getInventorySize(), playerInventory.constructInventoryPayload()).writeData()); socket.write(new PacketWindowItems(0, playerInventory.getInventorySize(), playerInventory.constructInventoryPayload(0)).writeData());
} else { } else {
socket.write(new PacketDisconnectKick("Failed to find world to put player in.").writeData()); socket.write(new PacketDisconnectKick("Failed to find world to put player in.").writeData());
} }

View file

@ -9,8 +9,8 @@ export default class Inventory implements IInventory {
public changeHandlers:FunkyArray<number, (itemStack: ItemStack) => void>; public changeHandlers:FunkyArray<number, (itemStack: ItemStack) => void>;
public itemStacks:Array<ItemStack | null>; public itemStacks:Array<ItemStack | null>;
private size:number; public readonly size:number;
private name:string; public readonly name:string;
public constructor(size:number, name:string) { public constructor(size:number, name:string) {
this.changeHandlers = new FunkyArray<number, (itemStack: ItemStack) => void>(); this.changeHandlers = new FunkyArray<number, (itemStack: ItemStack) => void>();
@ -55,18 +55,13 @@ export default class Inventory implements IInventory {
} }
addItemStack(itemStack:ItemStack) { addItemStack(itemStack:ItemStack) {
throw new Error("Adding items to non player inventories is unimplemented."); for (let slotId = 0; slotId < this.itemStacks.length; slotId++) {
// Check bottom inventory row (hotbar) first.
/*let workingItemStack:ItemStack | null;
for (let slotId = 9; slotId <= 35; slotId++) {
if (itemStack.size === 0) { if (itemStack.size === 0) {
break; break;
} }
if ((workingItemStack = this.itemStacks[slotId]) != null) { this.itemStacks[slotId]?.insert(itemStack);
workingItemStack.insert(itemStack); }
}
}*/
} }
getInventoryName() { getInventoryName() {
@ -100,9 +95,10 @@ export default class Inventory implements IInventory {
return this; return this;
} }
private calculateInventoryPayloadSize() { public calculateInventoryPayloadSize(skip: number) {
let bufferSize = 0; let bufferSize = 0;
for (const stack of this.itemStacks) { for (let i = skip; i < this.itemStacks.length; i++) {
const stack = this.itemStacks[i];
if (stack) { if (stack) {
bufferSize += 5; // short + byte + short bufferSize += 5; // short + byte + short
} else { } else {
@ -112,9 +108,10 @@ export default class Inventory implements IInventory {
return bufferSize; return bufferSize;
} }
constructInventoryPayload() { constructInventoryPayload(skip: number) {
const writer = createWriter(Endian.BE, this.calculateInventoryPayloadSize()); const writer = createWriter(Endian.BE, this.calculateInventoryPayloadSize(skip));
for (const stack of this.itemStacks) { for (let i = skip; i < this.itemStacks.length; i++) {
const stack = this.itemStacks[i];
writer.writeShort(stack == null ? -1 : stack.itemID); writer.writeShort(stack == null ? -1 : stack.itemID);
if (stack != null) { if (stack != null) {
writer.writeByte(stack.size); writer.writeByte(stack.size);

View file

@ -1,16 +1,93 @@
import { createWriter, Endian } from "bufferstuff";
import MPClient from "../MPClient";
import Inventory from "./Inventory"; import Inventory from "./Inventory";
import ItemStack from "./ItemStack"; import ItemStack from "./ItemStack";
export default class PlayerCombinedInventory extends Inventory { export default class PlayerCombinedInventory extends Inventory {
private combinedInventoryChangeHandlerHandle: number; private static PLAYER_INVENTORY_OFFSET = 10;
public constructor(size: number, name: string) { private mpClient: MPClient;
public constructor(mpClient:MPClient, size: number, name: string) {
super(size, name); super(size, name);
this.combinedInventoryChangeHandlerHandle = this.registerChangeHandler(this.onInventoryChange); this.mpClient = mpClient;
} }
private onInventoryChange(itemStack: ItemStack) { private getSlotId(slotId: number) {
if (slotId > this.size - 1) {
return slotId + PlayerCombinedInventory.PLAYER_INVENTORY_OFFSET;
} else {
return slotId;
}
}
static FromExisting(mpClient: MPClient, inventory: Inventory, name: string) {
const linkedInventory = new PlayerCombinedInventory(mpClient, inventory.size, name);
linkedInventory.itemStacks = inventory.itemStacks;
return linkedInventory;
}
addItemStack(itemStack:ItemStack) {
for (let slotId = 0; slotId < this.itemStacks.length; slotId++) {
if (itemStack.size === 0) {
break;
}
this.itemStacks[slotId]?.insert(itemStack);
}
if (itemStack.size === 0) {
return;
}
for (let slotId = 0; slotId < this.mpClient.entity.inventory.itemStacks.length; slotId++) {
if (itemStack.size === 0) {
break;
}
this.mpClient.entity.inventory.itemStacks[slotId]?.insert(itemStack);
}
}
// getInventorySize() {
// return this.itemStacks.length + this.mpClient.entity.inventory.itemStacks.length;
// }
getSlotItemStack(slotId:number) {
return this.itemStacks[slotId] ?? this.mpClient.entity.inventory.itemStacks[this.getSlotId(slotId)];
}
dropEmptyItemStacks() {
super.dropEmptyItemStacks();
this.mpClient.entity.inventory.dropEmptyItemStacks();
}
setSlotItemStack(slotId:number, itemStack: ItemStack | null) {
if (slotId > this.size - 1) {
this.mpClient.entity.inventory.setSlotItemStack(this.getSlotId(slotId), itemStack);
} else {
super.setSlotItemStack(slotId, itemStack);
}
return this;
}
constructInventoryPayload() {
const thisInventoryPayload = super.constructInventoryPayload(0);
const playerInventoryPayload = this.mpClient.entity.inventory.constructInventoryPayload(PlayerCombinedInventory.PLAYER_INVENTORY_OFFSET);
return Buffer.concat([thisInventoryPayload, playerInventoryPayload], thisInventoryPayload.length + playerInventoryPayload.length);
}
constructInventorySinglePayload(slotId:number) {
const stack = this.itemStacks[slotId] ?? this.mpClient.entity.inventory.itemStacks[this.getSlotId(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

@ -3,6 +3,7 @@ import ItemStack from "./ItemStack";
import PacketSetSlot from "../packets/SetSlot"; import PacketSetSlot from "../packets/SetSlot";
import PacketWindowItems from "../packets/WindowItems"; import PacketWindowItems from "../packets/WindowItems";
import Player from "../entities/Player"; import Player from "../entities/Player";
import { createWriter, Endian } from "bufferstuff";
export default class PlayerInventory extends Inventory { export default class PlayerInventory extends Inventory {
private player:Player; private player:Player;

View file

@ -1,27 +1,44 @@
import InventoryType from "../enums/InventoryType"; import InventoryType from "../enums/InventoryType";
import Inventory from "../inventories/Inventory"; import Inventory from "../inventories/Inventory";
import ItemStack from "../inventories/ItemStack"; import ItemStack from "../inventories/ItemStack";
import PlayerCombinedInventory from "../inventories/PlayerCombinedInventory";
import MPClient from "../MPClient"; import MPClient from "../MPClient";
import PacketOpenWindow from "../packets/OpenWindow"; import PacketOpenWindow from "../packets/OpenWindow";
import PacketWindowItems from "../packets/WindowItems";
export default abstract class Window { export default abstract class Window {
public static WINDOW_GLOBAL_COUNTER = 1; public static WINDOW_GLOBAL_COUNTER = 1;
public readonly inventorySize: number;
public windowId = Window.WINDOW_GLOBAL_COUNTER++; public windowId = Window.WINDOW_GLOBAL_COUNTER++;
public inventoryType: InventoryType; public inventoryType: InventoryType;
public inventory: Inventory; public inventory: PlayerCombinedInventory;
public cursorItemStack?: ItemStack; public cursorItemStack: ItemStack | null;
public constructor(inventoryType: InventoryType, inventory: PlayerCombinedInventory, inventorySize: number) {
this.inventorySize = inventorySize;
public constructor(inventoryType: InventoryType, inventory: Inventory) {
this.inventoryType = inventoryType; this.inventoryType = inventoryType;
this.inventory = inventory; this.inventory = inventory;
this.cursorItemStack = null;
} }
openWindow(mpClient: MPClient) { openWindow(mpClient: MPClient) {
const windowPacket = new PacketOpenWindow(this.windowId, this.inventoryType, this.inventory.getInventoryName(), this.inventory.getInventorySize()).writeData(); const windowPacket = new PacketOpenWindow(this.windowId, this.inventoryType, this.inventory.getInventoryName(), this.inventory.getInventorySize()).writeData();
//const inventoryDataPayload = this.inventory.constructInventoryPayload(); const windowItems = new PacketWindowItems(this.windowId, this.inventorySize, this.inventory.constructInventoryPayload()).writeData();
//mpClient.send(Buffer.concat([ windowPacket, inventoryDataPayload ], windowPacket.length + inventoryDataPayload.length)); mpClient.send(Buffer.concat([ windowPacket, windowItems ], windowPacket.length + windowItems.length));
mpClient.send(windowPacket); //mpClient.send(windowPacket);
//mpClient.send(inventoryDataPayload);
}
clickedWindow(slotId: number, rightClick: boolean) {
if (this.cursorItemStack) {
} else {
this.cursorItemStack = this.inventory.getSlotItemStack(slotId);
}
} }
} }

View file

@ -1,9 +1,10 @@
import InventoryType from "../enums/InventoryType"; import InventoryType from "../enums/InventoryType";
import Inventory from "../inventories/Inventory"; import Inventory from "../inventories/Inventory";
import PlayerCombinedInventory from "../inventories/PlayerCombinedInventory";
import Window from "./Window"; import Window from "./Window";
export default class WindowChest extends Window { export default class WindowChest extends Window {
public constructor(inventory: Inventory) { public constructor(inventory: PlayerCombinedInventory) {
super(InventoryType.Chest, inventory); super(InventoryType.Chest, inventory, 62);
} }
} }

View file

@ -1,10 +1,11 @@
import InventoryType from "../enums/InventoryType"; import InventoryType from "../enums/InventoryType";
import Inventory from "../inventories/Inventory"; import Inventory from "../inventories/Inventory";
import PlayerCombinedInventory from "../inventories/PlayerCombinedInventory";
import MPClient from "../MPClient"; import MPClient from "../MPClient";
import Window from "./Window"; import Window from "./Window";
export default class WindowCrafting extends Window { export default class WindowCrafting extends Window {
public constructor(mpClient: MPClient) { public constructor(inventory: PlayerCombinedInventory) {
super(InventoryType.CraftingTable, new Inventory(45, "Crafting")); super(InventoryType.CraftingTable, inventory, 45);
} }
} }