Add Block Inventories (#1198)

* Add chest block placeholder

* Update location of chest.zig.zon

* added chests

* fix some stuff

* dont create all inventories on the client

* make it better

* remove comment

* fix formatting

* fix more formatting issues

* use chests instead of iron block

* fix formatting

* make blocks with inventories that are broken drop the items

* fix compiler error

* fix formatting

* fix formatting

* Trigger GitHub Actions

* add inventory saving to bin

* fix formatting

* fix formatting again

* fix formatting again again

* small change

* current changes

* thing

* Chest patch w/o quantums suggestions

* small test pls no merge

* it works with a couple segfaults that may or may not be in the base game

* final thing i think

* block inventories

* haha

* another thing

* fix formatting

* fix formatting again

* remove saving for now

* remove a comment

* remove more comments

* dont store inventory on the client

* something

* hardcode stuff for the future

* remove getwindow

* fix formatting

* fixes

---------

Co-authored-by: Krzysztof Wiśniewski <argmaster.world@gmail.com>
This commit is contained in:
OneAvargeCoder193 2025-04-28 11:17:39 -04:00 committed by GitHub
parent c7522483b0
commit cd0cabbbb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 105 additions and 44 deletions

View File

@ -302,7 +302,7 @@ pub const Sync = struct { // MARK: Sync
fn createInventory(user: *main.server.User, clientId: u32, len: usize, typ: Inventory.Type, source: Source) void { fn createInventory(user: *main.server.User, clientId: u32, len: usize, typ: Inventory.Type, source: Source) void {
main.utils.assertLocked(&mutex); main.utils.assertLocked(&mutex);
switch(source) { switch(source) {
.sharedTestingInventory, .recipe => { .sharedTestingInventory, .recipe, .blockInventory => {
for(inventories.items) |*inv| { for(inventories.items) |*inv| {
if(std.meta.eql(inv.source, source)) { if(std.meta.eql(inv.source, source)) {
inv.addUser(user, clientId); inv.addUser(user, clientId);
@ -315,6 +315,9 @@ pub const Sync = struct { // MARK: Sync
} }
const inventory = ServerInventory.init(len, typ, source); const inventory = ServerInventory.init(len, typ, source);
inventories.items[inventory.inv.id] = inventory;
inventories.items[inventory.inv.id].addUser(user, clientId);
switch(source) { switch(source) {
.sharedTestingInventory => {}, .sharedTestingInventory => {},
.playerInventory, .hand => { .playerInventory, .hand => {
@ -340,12 +343,11 @@ pub const Sync = struct { // MARK: Sync
inventory.inv._items[inventory.inv._items.len - 1].amount = recipe.resultAmount; inventory.inv._items[inventory.inv._items.len - 1].amount = recipe.resultAmount;
inventory.inv._items[inventory.inv._items.len - 1].item = .{.baseItem = recipe.resultItem}; inventory.inv._items[inventory.inv._items.len - 1].item = .{.baseItem = recipe.resultItem};
}, },
// TODO: Load block inventory data from save
.blockInventory => {},
.other => {}, .other => {},
.alreadyFreed => unreachable, .alreadyFreed => unreachable,
} }
inventories.items[inventory.inv.id] = inventory;
inventories.items[inventory.inv.id].addUser(user, clientId);
} }
fn closeInventory(user: *main.server.User, clientId: u32) !void { fn closeInventory(user: *main.server.User, clientId: u32) !void {
@ -1096,6 +1098,9 @@ pub const Command = struct { // MARK: Command
writer.writeWithDelimiter(val.sourceItems[i].id, 0); writer.writeWithDelimiter(val.sourceItems[i].id, 0);
} }
}, },
.blockInventory => |val| {
writer.writeVec(Vec3i, val);
},
.sharedTestingInventory, .other => {}, .sharedTestingInventory, .other => {},
.alreadyFreed => unreachable, .alreadyFreed => unreachable,
} }
@ -1140,6 +1145,7 @@ pub const Command = struct { // MARK: Command
return error.Invalid; return error.Invalid;
}, },
}, },
.blockInventory => .{.blockInventory = try reader.readVec(Vec3i)},
.other => .{.other = {}}, .other => .{.other = {}},
.alreadyFreed => unreachable, .alreadyFreed => unreachable,
}; };
@ -1779,6 +1785,7 @@ const SourceType = enum(u8) {
sharedTestingInventory = 2, sharedTestingInventory = 2,
hand = 3, hand = 3,
recipe = 4, recipe = 4,
blockInventory = 5,
other = 0xff, // TODO: List every type separately here. other = 0xff, // TODO: List every type separately here.
}; };
const Source = union(SourceType) { const Source = union(SourceType) {
@ -1787,6 +1794,7 @@ const Source = union(SourceType) {
sharedTestingInventory: void, sharedTestingInventory: void,
hand: u32, hand: u32,
recipe: *const main.items.Recipe, recipe: *const main.items.Recipe,
blockInventory: Vec3i,
other: void, other: void,
}; };

View File

@ -74,6 +74,7 @@ var _modeData: [maxBlockCount]u16 = undefined;
var _lodReplacement: [maxBlockCount]u16 = undefined; var _lodReplacement: [maxBlockCount]u16 = undefined;
var _opaqueVariant: [maxBlockCount]u16 = undefined; var _opaqueVariant: [maxBlockCount]u16 = undefined;
var _friction: [maxBlockCount]f32 = undefined; var _friction: [maxBlockCount]f32 = undefined;
var _allowOres: [maxBlockCount]bool = undefined; var _allowOres: [maxBlockCount]bool = undefined;
var _touchFunction: [maxBlockCount]?*const TouchFunction = undefined; var _touchFunction: [maxBlockCount]?*const TouchFunction = undefined;
var _entityDataClass: [maxBlockCount]?*EntityDataClass = undefined; var _entityDataClass: [maxBlockCount]?*EntityDataClass = undefined;

View File

@ -176,63 +176,39 @@ pub const EntityDataClasses = struct {
const StorageServer = BlockEntityDataStorage( const StorageServer = BlockEntityDataStorage(
.server, .server,
struct { struct {
contents: u64, id: ?u32,
},
);
const StorageClient = BlockEntityDataStorage(
.client,
struct {
contents: u64,
}, },
); );
pub const id = "chest"; pub const id = "chest";
pub fn init() void { pub fn init() void {
StorageServer.init(); StorageServer.init();
StorageClient.init();
} }
pub fn deinit() void { pub fn deinit() void {
StorageServer.deinit(); StorageServer.deinit();
StorageClient.deinit();
} }
pub fn reset() void { pub fn reset() void {
StorageServer.reset(); StorageServer.reset();
StorageClient.reset();
} }
pub fn onLoadClient(_: Vec3i, _: *Chunk) void { pub fn onLoadClient(_: Vec3i, _: *Chunk) void {}
std.log.debug("Chest.onLoadClient", .{}); pub fn onUnloadClient(_: Vec3i, _: *Chunk) void {}
} pub fn onLoadServer(_: Vec3i, _: *Chunk) void {}
pub fn onUnloadClient(_: Vec3i, _: *Chunk) void { pub fn onUnloadServer(_: Vec3i, _: *Chunk) void {}
std.log.debug("Chest.onUnloadClient", .{}); pub fn onPlaceClient(_: Vec3i, _: *Chunk) void {}
} pub fn onBreakClient(_: Vec3i, _: *Chunk) void {}
pub fn onLoadServer(_: Vec3i, _: *Chunk) void { pub fn onPlaceServer(_: Vec3i, _: *Chunk) void {}
std.log.debug("Chest.onLoadServer", .{});
}
pub fn onUnloadServer(_: Vec3i, _: *Chunk) void {
std.log.debug("Chest.onUnloadServer", .{});
}
pub fn onPlaceClient(pos: Vec3i, chunk: *Chunk) void {
std.log.debug("Chest.onPlaceClient", .{});
StorageClient.add(pos, .{.contents = 0}, chunk);
}
pub fn onBreakClient(pos: Vec3i, chunk: *Chunk) void {
std.log.debug("Chest.onBreakClient", .{});
StorageClient.remove(pos, chunk);
}
pub fn onPlaceServer(pos: Vec3i, chunk: *Chunk) void {
std.log.debug("Chest.onPlaceServer", .{});
StorageServer.add(pos, .{.contents = 0}, chunk);
}
pub fn onBreakServer(pos: Vec3i, chunk: *Chunk) void { pub fn onBreakServer(pos: Vec3i, chunk: *Chunk) void {
std.log.debug("Chest.onBreakServer", .{});
StorageServer.remove(pos, chunk); StorageServer.remove(pos, chunk);
} }
pub fn onInteract(pos: Vec3i, chunk: *Chunk) EventStatus { pub fn onInteract(pos: Vec3i, _: *Chunk) EventStatus {
StorageClient.mutex.lock(); if(main.KeyBoard.key("shift").pressed) return .ignored;
defer StorageClient.mutex.unlock();
const data = StorageClient.get(pos, chunk); const inventory = main.items.Inventory.init(main.globalAllocator, 20, .normal, .{.blockInventory = pos});
if(data == null) std.log.debug("Chest.onInteract: null", .{}) else std.log.debug("Chest.onInteract: {}", .{data.?.contents});
main.gui.windowlist.chest.setInventory(inventory);
main.gui.openWindow("chest");
main.Window.setMouseGrabbed(false);
return .handled; return .handled;
} }

View File

@ -303,12 +303,14 @@ fn addWindow(window: *GuiWindow) void {
pub fn openWindow(id: []const u8) void { pub fn openWindow(id: []const u8) void {
defer updateWindowPositions(); defer updateWindowPositions();
for(windowList.items) |window| { for(windowList.items) |window| {
if(std.mem.eql(u8, window.id, id)) { if(std.mem.eql(u8, window.id, id)) {
openWindowFromRef(window); openWindowFromRef(window);
return; return;
} }
} }
std.log.err("Could not find window with id {s}.", .{id}); std.log.err("Could not find window with id {s}.", .{id});
} }

View File

@ -1,6 +1,7 @@
pub const advanced_controls = @import("advanced_controls.zig"); pub const advanced_controls = @import("advanced_controls.zig");
pub const change_name = @import("change_name.zig"); pub const change_name = @import("change_name.zig");
pub const chat = @import("chat.zig"); pub const chat = @import("chat.zig");
pub const chest = @import("chest.zig");
pub const controls = @import("controls.zig"); pub const controls = @import("controls.zig");
pub const creative_inventory = @import("creative_inventory.zig"); pub const creative_inventory = @import("creative_inventory.zig");
pub const crosshair = @import("crosshair.zig"); pub const crosshair = @import("crosshair.zig");

73
src/gui/windows/chest.zig Normal file
View File

@ -0,0 +1,73 @@
const std = @import("std");
const main = @import("main");
const Player = main.game.Player;
const ItemStack = main.items.ItemStack;
const Vec2f = main.vec.Vec2f;
const Texture = main.graphics.Texture;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const GuiWindow = gui.GuiWindow;
const Button = GuiComponent.Button;
const HorizontalList = GuiComponent.HorizontalList;
const VerticalList = GuiComponent.VerticalList;
const ItemSlot = GuiComponent.ItemSlot;
const inventory = @import("inventory.zig");
pub var window = GuiWindow{
.relativePosition = .{
.{.attachedToWindow = .{.reference = &inventory.window, .selfAttachmentPoint = .middle, .otherAttachmentPoint = .middle}},
.{.attachedToWindow = .{.reference = &inventory.window, .selfAttachmentPoint = .upper, .otherAttachmentPoint = .lower}},
},
.contentSize = Vec2f{64*10, 64*3},
.scale = 0.75,
.closeIfMouseIsGrabbed = true,
};
const padding: f32 = 8;
var itemSlots: main.List(*ItemSlot) = undefined;
pub fn init() void {
itemSlots = .init(main.globalAllocator);
}
pub fn deinit() void {
itemSlots.deinit();
}
pub var openInventory: main.items.Inventory = undefined;
pub fn setInventory(selectedInventory: main.items.Inventory) void {
openInventory = selectedInventory;
}
pub fn onOpen() void {
const list = VerticalList.init(.{padding, padding + 16}, 300, 0);
for(0..2) |y| {
const row = HorizontalList.init();
for(0..10) |x| {
const index: usize = y*10 + x;
const slot = ItemSlot.init(.{0, 0}, openInventory, @intCast(index), .default, .normal);
itemSlots.append(slot);
row.add(slot);
}
list.add(row);
}
list.finish(.center);
window.rootComponent = list.toComponent();
window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding));
gui.updateWindowPositions();
}
pub fn onClose() void {
openInventory.deinit(main.globalAllocator);
itemSlots.clearRetainingCapacity();
if(window.rootComponent) |*comp| {
comp.deinit();
window.rootComponent = null;
}
}