Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions assets/cubyz/blocks/chest/baobab.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.{
.texture = "cubyz:chest/baobab/back",
.texture_front = "cubyz:chest/baobab/front",
.texture_left = "cubyz:chest/baobab/side",
.texture_right = "cubyz:chest/baobab/side",
.texture_top = "cubyz:chest/baobab/top",
.texture_bottom = "cubyz:chest/baobab/bottom",
}
8 changes: 8 additions & 0 deletions assets/cubyz/blocks/chest/birch.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.{
.texture = "cubyz:chest/birch/back",
.texture_front = "cubyz:chest/birch/front",
.texture_left = "cubyz:chest/birch/side",
.texture_right = "cubyz:chest/birch/side",
.texture_top = "cubyz:chest/birch/top",
.texture_bottom = "cubyz:chest/birch/bottom",
}
8 changes: 8 additions & 0 deletions assets/cubyz/blocks/chest/mahogany.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.{
.texture = "cubyz:chest/mahogany/back",
.texture_front = "cubyz:chest/mahogany/front",
.texture_left = "cubyz:chest/mahogany/side",
.texture_right = "cubyz:chest/mahogany/side",
.texture_top = "cubyz:chest/mahogany/top",
.texture_bottom = "cubyz:chest/mahogany/bottom",
}
8 changes: 8 additions & 0 deletions assets/cubyz/blocks/chest/pine.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.{
.texture = "cubyz:chest/pine/back",
.texture_front = "cubyz:chest/pine/front",
.texture_left = "cubyz:chest/pine/side",
.texture_right = "cubyz:chest/pine/side",
.texture_top = "cubyz:chest/pine/top",
.texture_bottom = "cubyz:chest/pine/bottom",
}
8 changes: 8 additions & 0 deletions assets/cubyz/blocks/chest/willow.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.{
.texture = "cubyz:chest/willow/back",
.texture_front = "cubyz:chest/willow/front",
.texture_left = "cubyz:chest/willow/side",
.texture_right = "cubyz:chest/willow/side",
.texture_top = "cubyz:chest/willow/top",
.texture_bottom = "cubyz:chest/willow/bottom",
}
24 changes: 24 additions & 0 deletions assets/cubyz/recipes/wood_recipes.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,30 @@
.inputs = .{"cubyz:willow_planks"},
.output = "cubyz:sign/willow",
},
.{
.inputs = .{"4 cubyz:birch_planks"},
.output = "cubyz:chest/birch",
},
.{
.inputs = .{"4 cubyz:baobab_planks"},
.output = "cubyz:chest/baobab",
},
.{
.inputs = .{"4 cubyz:oak_planks"},
.output = "cubyz:chest/oak",
},
.{
.inputs = .{"4 cubyz:mahogany_planks"},
.output = "cubyz:chest/mahogany",
},
.{
.inputs = .{"4 cubyz:pine_planks"},
.output = "cubyz:chest/pine",
},
.{
.inputs = .{"4 cubyz:willow_planks"},
.output = "cubyz:chest/willow",
},
.{
.inputs = .{"cubyz:log/cactus"},
.output = "2 cubyz:cactus_arm",
Expand Down
88 changes: 67 additions & 21 deletions src/Inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,16 @@ pub const Sync = struct { // MARK: Sync
pub const ServerSide = struct { // MARK: ServerSide
const ServerInventory = struct {
inv: Inventory,
users: main.ListUnmanaged(*main.server.User),
users: main.ListUnmanaged(struct {user: *main.server.User, cliendId: InventoryId}),
source: Source,
managed: Managed,

const Managed = enum {internallyManaged, externallyManaged};

fn init(len: usize, typ: Inventory.Type, source: Source, managed: Managed) ServerInventory {
fn init(len: usize, typ: Inventory.Type, source: Source, managed: Managed, onUpdateCallback: ?*const fn(Source) void) ServerInventory {
main.utils.assertLocked(&mutex);
return .{
.inv = Inventory._init(main.globalAllocator, len, typ, .server),
.inv = Inventory._init(main.globalAllocator, len, typ, source, .server, onUpdateCallback),
.users = .{},
.source = source,
.managed = managed,
Expand All @@ -191,7 +191,9 @@ pub const Sync = struct { // MARK: Sync

fn deinit(self: *ServerInventory) void {
main.utils.assertLocked(&mutex);
std.debug.assert(self.users.items.len == 0);
while(self.users.items.len != 0) {
self.removeUser(self.users.items[0].user, self.users.items[0].cliendId);
}
self.users.deinit(main.globalAllocator);
self.inv._deinit(main.globalAllocator, .server);
self.inv._items.len = 0;
Expand All @@ -201,13 +203,20 @@ pub const Sync = struct { // MARK: Sync

fn addUser(self: *ServerInventory, user: *main.server.User, clientId: InventoryId) void {
main.utils.assertLocked(&mutex);
self.users.append(main.globalAllocator, user);
self.users.append(main.globalAllocator, .{.user = user, .cliendId = clientId});
user.inventoryClientToServerIdMap.put(clientId, self.inv.id) catch unreachable;
}

fn removeUser(self: *ServerInventory, user: *main.server.User, clientId: InventoryId) void {
main.utils.assertLocked(&mutex);
_ = self.users.swapRemove(std.mem.indexOfScalar(*main.server.User, self.users.items, user).?);
var index: usize = undefined;
for(self.users.items, 0..) |userData, i| {
if(userData.user == user) {
index = i;
break;
}
}
_ = self.users.swapRemove(index);
std.debug.assert(user.inventoryClientToServerIdMap.fetchRemove(clientId).?.value == self.inv.id);
if(self.users.items.len == 0 and self.managed == .internallyManaged) {
if(self.inv.type.shouldDepositToUserOnClose()) {
Expand All @@ -230,6 +239,11 @@ pub const Sync = struct { // MARK: Sync
}

pub fn deinit() void {
for(inventories.items) |inv| {
if(inv.source != .alreadyFreed) {
std.log.err("Leaked inventory with source {}", .{inv.source});
}
}
std.debug.assert(freeIdList.items.len == @intFromEnum(maxId)); // leak
freeIdList.deinit();
inventories.deinit();
Expand Down Expand Up @@ -318,10 +332,10 @@ pub const Sync = struct { // MARK: Sync
executeCommand(payload, source);
}

pub fn createExternallyManagedInventory(len: usize, typ: Inventory.Type, source: Source, data: *BinaryReader) InventoryId {
pub fn createExternallyManagedInventory(len: usize, typ: Inventory.Type, source: Source, data: *BinaryReader, onUpdateCallback: ?*const fn(Source) void) InventoryId {
mutex.lock();
defer mutex.unlock();
const inventory = ServerInventory.init(len, typ, source, .externallyManaged);
const inventory = ServerInventory.init(len, typ, source, .externallyManaged, onUpdateCallback);
inventories.items[@intFromEnum(inventory.inv.id)] = inventory;
inventory.inv.fromBytes(data);
return inventory.inv.id;
Expand All @@ -334,6 +348,23 @@ pub const Sync = struct { // MARK: Sync
inventories.items[@intFromEnum(invId)].deinit();
}

pub fn destroyAndDropExternallyManagedInventory(invId: InventoryId, pos: Vec3i) void {
main.utils.assertLocked(&mutex);
std.debug.assert(inventories.items[@intFromEnum(invId)].managed == .externallyManaged);
const inv = &inventories.items[@intFromEnum(invId)];
for(inv.inv._items) |*itemStack| {
if(itemStack.amount == 0) continue;
main.server.world.?.drop(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the way items drop need some more love, now they just drop to the ground within volume of the chest, but that is probably a separate issue material, if you do agree it could be improved.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, how would you suggest to do it instead?
And yeah, that's definitely a separate issue.

itemStack.*,
@as(Vec3d, @floatFromInt(pos)) + main.random.nextDoubleVector(3, &main.seed),
main.random.nextFloatVectorSigned(3, &main.seed),
0.1,
);
itemStack.* = .{};
}
inv.deinit();
}

fn createInventory(user: *main.server.User, clientId: InventoryId, len: usize, typ: Inventory.Type, source: Source) !void {
main.utils.assertLocked(&mutex);
switch(source) {
Expand All @@ -357,13 +388,14 @@ pub const Sync = struct { // MARK: Sync
.other => {},
.alreadyFreed => unreachable,
}
const inventory = ServerInventory.init(len, typ, source, .internallyManaged);
const inventory = ServerInventory.init(len, typ, source, .internallyManaged, null);

inventories.items[@intFromEnum(inventory.inv.id)] = inventory;
inventories.items[@intFromEnum(inventory.inv.id)].addUser(user, clientId);

switch(source) {
.sharedTestingInventory => {},
.blockInventory => unreachable, // Should be loaded by the block entity
.playerInventory, .hand => unreachable, // Should be loaded on player creation
.recipe => |recipe| {
for(0..recipe.sourceAmounts.len) |i| {
Expand All @@ -373,16 +405,14 @@ 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].item = .{.baseItem = recipe.resultItem};
},
// TODO: Load block inventory data from save
.blockInventory => {},
.other => {},
.alreadyFreed => unreachable,
}
}

fn closeInventory(user: *main.server.User, clientId: InventoryId) !void {
main.utils.assertLocked(&mutex);
const serverId = user.inventoryClientToServerIdMap.get(clientId) orelse return error.Invalid;
const serverId = user.inventoryClientToServerIdMap.get(clientId) orelse return error.InventoryNotFound;
inventories.items[@intFromEnum(serverId)].removeUser(user, clientId);
}

Expand All @@ -402,6 +432,10 @@ pub const Sync = struct { // MARK: Sync
return null;
}

pub fn getInventoryFromId(serverId: InventoryId) Inventory {
return inventories.items[@intFromEnum(serverId)].inv;
}

pub fn clearPlayerInventory(user: *main.server.User) void {
mutex.lock();
defer mutex.unlock();
Expand Down Expand Up @@ -528,7 +562,7 @@ pub const Command = struct { // MARK: Command
fn read(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !InventoryAndSlot {
const id = try reader.readEnum(InventoryId);
return .{
.inv = Sync.getInventory(id, side, user) orelse return error.Invalid,
.inv = Sync.getInventory(id, side, user) orelse return error.InventoryNotFound,
.slot = try reader.readInt(u32),
};
}
Expand Down Expand Up @@ -660,7 +694,12 @@ pub const Command = struct { // MARK: Command
pub fn getUsers(self: SyncOperation, allocator: NeverFailingAllocator) []*main.server.User {
switch(self) {
inline .create, .delete, .useDurability => |data| {
return allocator.dupe(*main.server.User, Sync.ServerSide.inventories.items[@intFromEnum(data.inv.inv.id)].users.items);
const users = Sync.ServerSide.inventories.items[@intFromEnum(data.inv.inv.id)].users.items;
const result = allocator.alloc(*main.server.User, users.len);
for(0..users.len) |i| {
result[i] = users[i].user;
}
return result;
},
inline .health, .kill, .energy => |data| {
const out = allocator.alloc(*main.server.User, 1);
Expand Down Expand Up @@ -1184,7 +1223,7 @@ pub const Command = struct { // MARK: Command
};
try Sync.ServerSide.createInventory(user.?, id, len, typ, source);
return .{
.inv = Sync.ServerSide.getInventory(user.?, id) orelse return error.Invalid,
.inv = Sync.ServerSide.getInventory(user.?, id) orelse return error.InventoryNotFound,
.source = source,
};
}
Expand Down Expand Up @@ -1402,6 +1441,8 @@ pub const Command = struct { // MARK: Command
.type = .normal,
._items = &_items,
.id = undefined,
.source = undefined,
.onUpdateCallback = null,
};
cmd.tryCraftingTo(allocator, .{.inv = temp, .slot = 0}, self.source, side, user);
std.debug.assert(cmd.baseOperations.pop().create.dest.inv._items.ptr == temp._items.ptr); // Remove the extra step from undo list (we cannot undo dropped items)
Expand Down Expand Up @@ -1552,8 +1593,8 @@ pub const Command = struct { // MARK: Command
const destId = try reader.readEnum(InventoryId);
const sourceId = try reader.readEnum(InventoryId);
return .{
.dest = Sync.getInventory(destId, side, user) orelse return error.Invalid,
.source = Sync.getInventory(sourceId, side, user) orelse return error.Invalid,
.dest = Sync.getInventory(destId, side, user) orelse return error.InventoryNotFound,
.source = Sync.getInventory(sourceId, side, user) orelse return error.InventoryNotFound,
};
}
};
Expand Down Expand Up @@ -1583,7 +1624,7 @@ pub const Command = struct { // MARK: Command
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Clear {
const invId = try reader.readEnum(InventoryId);
return .{
.inv = Sync.getInventory(invId, side, user) orelse return error.Invalid,
.inv = Sync.getInventory(invId, side, user) orelse return error.InventoryNotFound,
};
}
};
Expand Down Expand Up @@ -1856,14 +1897,16 @@ const Type = union(TypeEnum) {
type: Type,
id: InventoryId,
_items: []ItemStack,
source: Source,
onUpdateCallback: ?*const fn(Source) void,

pub fn init(allocator: NeverFailingAllocator, _size: usize, _type: Type, source: Source) Inventory {
const self = _init(allocator, _size, _type, .client);
pub fn init(allocator: NeverFailingAllocator, _size: usize, _type: Type, source: Source, onUpdateCallback: ?*const fn(Source) void) Inventory {
const self = _init(allocator, _size, _type, source, .client, onUpdateCallback);
Sync.ClientSide.executeCommand(.{.open = .{.inv = self, .source = source}});
return self;
}

fn _init(allocator: NeverFailingAllocator, _size: usize, _type: Type, side: Side) Inventory {
fn _init(allocator: NeverFailingAllocator, _size: usize, _type: Type, source: Source, side: Side, onUpdateCallback: ?*const fn(Source) void) Inventory {
if(_type == .workbench) std.debug.assert(_size == 26);
const self = Inventory{
.type = _type,
Expand All @@ -1872,6 +1915,8 @@ fn _init(allocator: NeverFailingAllocator, _size: usize, _type: Type, side: Side
.client => Sync.ClientSide.nextId(),
.server => Sync.ServerSide.nextId(),
},
.source = source,
.onUpdateCallback = onUpdateCallback,
};
for(self._items) |*item| {
item.* = ItemStack{};
Expand Down Expand Up @@ -1901,6 +1946,7 @@ fn _deinit(self: Inventory, allocator: NeverFailingAllocator, side: Side) void {
}

fn update(self: Inventory) void {
defer if(self.onUpdateCallback) |cb| cb(self.source);
if(self.type == .workbench) {
self._items[self._items.len - 1].deinit();
self._items[self._items.len - 1].clear();
Expand Down
Loading