diff --git a/src/Inventory.zig b/src/Inventory.zig index 21259bb4..3eb18717 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -310,14 +310,14 @@ pub const Sync = struct { // MARK: Sync } } }, - .playerInventory, .other => {}, + .playerInventory, .hand, .other => {}, .alreadyFreed => unreachable, } const inventory = ServerInventory.init(len, typ, source); switch (source) { .sharedTestingInventory => {}, - .playerInventory => { + .playerInventory, .hand => { const dest: []u8 = main.stackAllocator.alloc(u8, std.base64.url_safe.Encoder.calcSize(user.name.len)); defer main.stackAllocator.free(dest); const hashedName = std.base64.url_safe.Encoder.encode(dest, user.name); @@ -328,7 +328,7 @@ pub const Sync = struct { // MARK: Sync const playerData = main.files.readToZon(main.stackAllocator, path) catch .null; defer playerData.deinit(main.stackAllocator); - const inventoryZon = playerData.getChild("inventory"); + const inventoryZon = playerData.getChild(@tagName(source)); inventory.inv.loadFromZon(inventoryZon); }, @@ -352,10 +352,10 @@ pub const Sync = struct { // MARK: Sync return inventories.items[serverId].inv; } - pub fn getInventoryFromSource(source: SourceType) ?Inventory { + pub fn getInventoryFromSource(source: Source) ?Inventory { main.utils.assertLocked(&mutex); for(inventories.items) |inv| { - if (inv.source == source) { + if (std.meta.eql(inv.source, source)) { return inv.inv; } } @@ -1059,8 +1059,14 @@ pub const Command = struct { // MARK: Command std.mem.writeInt(usize, data.addMany(8)[0..8], self.inv._items.len, .big); data.append(@intFromEnum(self.inv.type)); data.append(@intFromEnum(self.source)); + switch (self.source) { + .playerInventory, .hand => |val| { + std.mem.writeInt(u32, data.addMany(4)[0..4], val, .big); + }, + else => {} + } switch(self.source) { - .playerInventory, .sharedTestingInventory, .other => {}, + .playerInventory, .sharedTestingInventory, .hand, .other => {}, .alreadyFreed => unreachable, } } @@ -1073,8 +1079,9 @@ pub const Command = struct { // MARK: Command const typ: Inventory.Type = @enumFromInt(data[12]); const sourceType: SourceType = @enumFromInt(data[13]); const source: Source = switch(sourceType) { - .playerInventory => .{.playerInventory = {}}, + .playerInventory => .{.playerInventory = std.mem.readInt(u32, data[14..18], .big)}, .sharedTestingInventory => .{.sharedTestingInventory = {}}, + .hand => .{.hand = std.mem.readInt(u32, data[14..18], .big)}, .other => .{.other = {}}, .alreadyFreed => unreachable, }; @@ -1647,12 +1654,14 @@ const SourceType = enum(u8) { alreadyFreed = 0, playerInventory = 1, sharedTestingInventory = 2, + hand = 3, other = 0xff, // TODO: List every type separately here. }; const Source = union(SourceType) { alreadyFreed: void, - playerInventory: void, + playerInventory: u32, sharedTestingInventory: void, + hand: u32, other: void, }; @@ -1691,7 +1700,13 @@ fn _init(allocator: NeverFailingAllocator, _size: usize, _type: Type, side: Side } pub fn deinit(self: Inventory, allocator: NeverFailingAllocator) void { - Sync.ClientSide.executeCommand(.{.close = .{.inv = self, .allocator = allocator}}); + if (main.game.world.?.connected) { + Sync.ClientSide.executeCommand(.{.close = .{.inv = self, .allocator = allocator}}); + } else { + Sync.ClientSide.mutex.lock(); + defer Sync.ClientSide.mutex.unlock(); + self._deinit(allocator, .client); + } } fn _deinit(self: Inventory, allocator: NeverFailingAllocator, side: Side) void { diff --git a/src/game.zig b/src/game.zig index 949269f3..6245418b 100644 --- a/src/game.zig +++ b/src/game.zig @@ -521,6 +521,7 @@ pub const World = struct { // MARK: World milliTime: i64, gameTime: Atomic(i64) = .init(0), spawn: Vec3f = undefined, + connected: bool = true, blockPalette: *assets.Palette = undefined, biomePalette: *assets.Palette = undefined, itemDrops: ClientItemDropManager = undefined, @@ -533,6 +534,7 @@ pub const World = struct { // MARK: World .name = "client", .milliTime = std.time.milliTimestamp(), }; + self.itemDrops.init(main.globalAllocator, self); network.Protocols.handShake.clientSide(self.conn, settings.playerName); @@ -545,15 +547,17 @@ pub const World = struct { // MARK: World } pub fn deinit(self: *World) void { + self.conn.deinit(); + + self.connected = false; + // TODO: Close all world related guis. main.gui.inventory.deinit(); main.gui.deinit(); main.gui.init(); - Player.inventory.deinit(main.globalAllocator); main.threadPool.clear(); - self.conn.deinit(); self.itemDrops.deinit(); self.blockPalette.deinit(); self.biomePalette.deinit(); @@ -580,7 +584,7 @@ pub const World = struct { // MARK: World try assets.loadWorldAssets("serverAssets", self.blockPalette, self.biomePalette); Player.loadFrom(zon.getChild("player")); Player.id = zon.get(u32, "player_id", std.math.maxInt(u32)); - Player.inventory = Inventory.init(main.globalAllocator, 32, .normal, .playerInventory); + Player.inventory = Inventory.init(main.globalAllocator, 32, .normal, .{.playerInventory = Player.id}); } pub fn update(self: *World) void { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index c7497f1f..2454f357 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -593,7 +593,7 @@ pub const inventory = struct { // MARK: inventory var initialized: bool = false; pub fn init() void { - carried = Inventory.init(main.globalAllocator, 1, .normal, .other); + carried = Inventory.init(main.globalAllocator, 1, .normal, .{.hand = main.game.Player.id}); leftClickSlots = .init(main.globalAllocator); rightClickSlots = .init(main.globalAllocator); carriedItemSlot = ItemSlot.init(.{0, 0}, carried, 0, .default, .normal); diff --git a/src/server/server.zig b/src/server/server.zig index b5513f90..35fef900 100644 --- a/src/server/server.zig +++ b/src/server/server.zig @@ -70,6 +70,12 @@ pub const User = struct { // MARK: User pub fn deinit(self: *User) void { std.debug.assert(self.refCount.load(.monotonic) == 0); + + world.?.savePlayer(self) catch |err| { + std.log.err("Failed to save player: {s}", .{@errorName(err)}); + return; + }; + main.items.Inventory.Sync.ServerSide.disconnectUser(self); std.debug.assert(self.inventoryClientToServerIdMap.count() == 0); // leak self.inventoryClientToServerIdMap.deinit(); diff --git a/src/server/world.zig b/src/server/world.zig index 73265eb6..304d5b41 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -815,8 +815,12 @@ pub const ServerWorld = struct { // MARK: ServerWorld { main.items.Inventory.Sync.ServerSide.mutex.lock(); defer main.items.Inventory.Sync.ServerSide.mutex.unlock(); - if (main.items.Inventory.Sync.ServerSide.getInventoryFromSource(.playerInventory)) |inv| { - playerZon.put("inventory", inv.save(main.stackAllocator)); + if (main.items.Inventory.Sync.ServerSide.getInventoryFromSource(.{.playerInventory = user.id})) |inv| { + playerZon.put("playerInventory", inv.save(main.stackAllocator)); + } + + if (main.items.Inventory.Sync.ServerSide.getInventoryFromSource(.{.hand = user.id})) |inv| { + playerZon.put("hand", inv.save(main.stackAllocator)); } }