From 1c5229e4801c07383b1054eb2f8bb723bf9ab15e Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Wed, 1 Jan 2025 17:21:27 +0100 Subject: [PATCH] Reduce air drag and reduce intitial velocity of item drops when breaking a block. Also offset their initial position randomly within the block. progress towards #868 --- src/Inventory.zig | 47 ++++++++++++++++++++++++++--------------------- src/itemdrop.zig | 10 ++++------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/Inventory.zig b/src/Inventory.zig index ad796898..d3f2b802 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -8,6 +8,7 @@ const ItemStack = main.items.ItemStack; const Tool = main.items.Tool; const NeverFailingAllocator = main.utils.NeverFailingAllocator; const vec = main.vec; +const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; const Vec3i = vec.Vec3i; const ZonElement = main.ZonElement; @@ -465,7 +466,7 @@ pub const Command = struct { // MARK: Command }, }; - const SyncOperation = struct { + const SyncOperation = struct { // MARK: SyncOperation // Since the client doesn't know about all inventories, we can only use create(+amount)/delete(-amount) operations to apply the server side updates. inv: InventoryAndSlot, amount: i32, @@ -536,7 +537,7 @@ pub const Command = struct { // MARK: Command return list.toOwnedSlice(); } - fn do(self: *Command, allocator: NeverFailingAllocator, side: Side, user: ?*main.server.User, gamemode: main.game.Gamemode) error{serverFailure}!void { + fn do(self: *Command, allocator: NeverFailingAllocator, side: Side, user: ?*main.server.User, gamemode: main.game.Gamemode) error{serverFailure}!void { // MARK: do() std.debug.assert(self.baseOperations.items.len == 0); // do called twice without cleaning up switch(self.payload) { inline else => |payload| { @@ -654,7 +655,7 @@ pub const Command = struct { // MARK: Command } } - fn executeBaseOperation(self: *Command, allocator: NeverFailingAllocator, _op: BaseOperation, side: Side) void { + fn executeBaseOperation(self: *Command, allocator: NeverFailingAllocator, _op: BaseOperation, side: Side) void { // MARK: executeBaseOperation() var op = _op; switch(op) { .move => |info| { @@ -706,7 +707,7 @@ pub const Command = struct { // MARK: Command return true; } - fn tryCraftingTo(self: *Command, allocator: NeverFailingAllocator, dest: InventoryAndSlot, source: InventoryAndSlot, side: Side, user: ?*main.server.User) void { + fn tryCraftingTo(self: *Command, allocator: NeverFailingAllocator, dest: InventoryAndSlot, source: InventoryAndSlot, side: Side, user: ?*main.server.User) void { // MARK: tryCraftingTo() std.debug.assert(source.inv.type == .crafting); std.debug.assert(dest.inv.type == .normal); if(source.slot != source.inv._items.len - 1) return; @@ -768,7 +769,7 @@ pub const Command = struct { // MARK: Command }}, side); } - const Open = struct { + const Open = struct { // MARK: Open inv: Inventory, source: Source, @@ -820,7 +821,7 @@ pub const Command = struct { // MARK: Command } }; - const Close = struct { + const Close = struct { // MARK: Close inv: Inventory, allocator: NeverFailingAllocator, @@ -848,7 +849,7 @@ pub const Command = struct { // MARK: Command } }; - const DepositOrSwap = struct { + const DepositOrSwap = struct { // MARK: DepositOrSwap dest: InventoryAndSlot, source: InventoryAndSlot, @@ -910,7 +911,7 @@ pub const Command = struct { // MARK: Command } }; - const Deposit = struct { + const Deposit = struct { // MARK: Deposit dest: InventoryAndSlot, source: InventoryAndSlot, amount: u16, @@ -957,7 +958,7 @@ pub const Command = struct { // MARK: Command } }; - const TakeHalf = struct { + const TakeHalf = struct { // MARK: TakeHalf dest: InventoryAndSlot, source: InventoryAndSlot, @@ -1020,7 +1021,7 @@ pub const Command = struct { // MARK: Command } }; - const Drop = struct { + const Drop = struct { // MARK: Drop source: InventoryAndSlot, desiredAmount: u16 = 0xffff, @@ -1075,7 +1076,7 @@ pub const Command = struct { // MARK: Command } }; - const FillFromCreative = struct { + const FillFromCreative = struct { // MARK: FillFromCreative dest: InventoryAndSlot, item: ?Item, amount: u16 = 0, @@ -1128,7 +1129,7 @@ pub const Command = struct { // MARK: Command } }; - const DepositOrDrop = struct { + const DepositOrDrop = struct { // MARK: DepositOrDrop dest: Inventory, source: Inventory, @@ -1189,7 +1190,7 @@ pub const Command = struct { // MARK: Command } }; - const Clear = struct { + const Clear = struct { // MARK: Clear inv: Inventory, pub fn run(self: Clear, allocator: NeverFailingAllocator, cmd: *Command, side: Side, _: ?*main.server.User, _: Gamemode) error{serverFailure}!void { @@ -1220,7 +1221,7 @@ pub const Command = struct { // MARK: Command } }; - const UpdateBlock = struct { + const UpdateBlock = struct { // MARK: UpdateBlock source: InventoryAndSlot, pos: Vec3i, oldBlock: Block, @@ -1275,9 +1276,7 @@ pub const Command = struct { // MARK: Command for(0..amount) |_| { for(self.newBlock.blockDrops()) |drop| { if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) { - for(drop.items) |itemStack| { - main.server.world.?.drop(itemStack.clone(), @as(vec.Vec3d, @floatFromInt(self.pos)) + vec.Vec3d{0.5, 0.5, 0.5}, main.random.nextFloatVectorSigned(3, &main.seed), main.random.nextFloat(&main.seed)*20); - } + blockDrop(self.pos, drop); } } } @@ -1288,14 +1287,20 @@ pub const Command = struct { // MARK: Command if(side == .server and gamemode != .creative and self.oldBlock.typ != self.newBlock.typ) { for(self.oldBlock.blockDrops()) |drop| { if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) { - for(drop.items) |itemStack| { - main.server.world.?.drop(itemStack.clone(), @as(vec.Vec3d, @floatFromInt(self.pos)) + vec.Vec3d{0.5, 0.5, 0.5}, main.random.nextFloatVectorSigned(3, &main.seed), main.random.nextFloat(&main.seed)*20); - } + blockDrop(self.pos, drop); } } } } + fn blockDrop(pos: Vec3i, drop: main.blocks.BlockDrop) void { + for(drop.items) |itemStack| { + const dropPos = @as(Vec3d, @floatFromInt(pos)) + @as(Vec3d, @splat(0.5)) + main.random.nextDoubleVectorSigned(3, &main.seed)*@as(Vec3d, @splat(0.5 - main.itemdrop.ItemDropManager.radius)); + const dir = vec.normalize(main.random.nextFloatVectorSigned(3, &main.seed)); + main.server.world.?.drop(itemStack.clone(), dropPos, dir, main.random.nextFloat(&main.seed)*1.5); + } + } + fn serialize(self: UpdateBlock, data: *main.List(u8)) void { self.source.write(data.addMany(8)[0..8]); std.mem.writeInt(i32, data.addMany(4)[0..4], self.pos[0], .big); @@ -1334,7 +1339,7 @@ const Source = union(SourceType) { other: void, }; -const Inventory = @This(); +const Inventory = @This(); // MARK: Inventory const Type = enum(u8) { normal = 0, diff --git a/src/itemdrop.zig b/src/itemdrop.zig index 7b6e4bfc..e0bbcf15 100644 --- a/src/itemdrop.zig +++ b/src/itemdrop.zig @@ -35,11 +35,11 @@ const ItemDrop = struct { // MARK: ItemDrop pub const ItemDropManager = struct { // MARK: ItemDropManager /// Half the side length of all item entities hitboxes as a cube. - const radius: f64 = 0.1; + pub const radius: f64 = 0.1; /// Side length of all item entities hitboxes as a cube. - const diameter: f64 = 2*radius; + pub const diameter: f64 = 2*radius; - const pickupRange: f64 = 1.0; + pub const pickupRange: f64 = 1.0; const maxSpeed = 10; @@ -285,7 +285,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager self.fixStuckInBlock(chunk, pos, vel, deltaTime); return; } - var drag: f64 = self.airDragFactor; vel.* += Vec3d{0, 0, -self.gravity*deltaTime}; inline for(0..3) |i| { const move = vel.*[i]*deltaTime;// + acceleration[i]*deltaTime; @@ -299,10 +298,9 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager } else { pos.*[i] += move; } - drag += 0.5; // TODO: Calculate drag from block properties and add buoyancy. } // Apply drag: - vel.* *= @splat(@max(0, 1 - drag*deltaTime)); + vel.* *= @splat(@max(0, 1 - self.airDragFactor*deltaTime)); } fn fixStuckInBlock(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {