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
This commit is contained in:
IntegratedQuantum 2025-01-01 17:21:27 +01:00
parent 613498d048
commit 1c5229e480
2 changed files with 30 additions and 27 deletions

View File

@ -8,6 +8,7 @@ const ItemStack = main.items.ItemStack;
const Tool = main.items.Tool; const Tool = main.items.Tool;
const NeverFailingAllocator = main.utils.NeverFailingAllocator; const NeverFailingAllocator = main.utils.NeverFailingAllocator;
const vec = main.vec; const vec = main.vec;
const Vec3d = vec.Vec3d;
const Vec3f = vec.Vec3f; const Vec3f = vec.Vec3f;
const Vec3i = vec.Vec3i; const Vec3i = vec.Vec3i;
const ZonElement = main.ZonElement; 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. // 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, inv: InventoryAndSlot,
amount: i32, amount: i32,
@ -536,7 +537,7 @@ pub const Command = struct { // MARK: Command
return list.toOwnedSlice(); 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 std.debug.assert(self.baseOperations.items.len == 0); // do called twice without cleaning up
switch(self.payload) { switch(self.payload) {
inline else => |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; var op = _op;
switch(op) { switch(op) {
.move => |info| { .move => |info| {
@ -706,7 +707,7 @@ pub const Command = struct { // MARK: Command
return true; 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(source.inv.type == .crafting);
std.debug.assert(dest.inv.type == .normal); std.debug.assert(dest.inv.type == .normal);
if(source.slot != source.inv._items.len - 1) return; if(source.slot != source.inv._items.len - 1) return;
@ -768,7 +769,7 @@ pub const Command = struct { // MARK: Command
}}, side); }}, side);
} }
const Open = struct { const Open = struct { // MARK: Open
inv: Inventory, inv: Inventory,
source: Source, source: Source,
@ -820,7 +821,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const Close = struct { const Close = struct { // MARK: Close
inv: Inventory, inv: Inventory,
allocator: NeverFailingAllocator, allocator: NeverFailingAllocator,
@ -848,7 +849,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const DepositOrSwap = struct { const DepositOrSwap = struct { // MARK: DepositOrSwap
dest: InventoryAndSlot, dest: InventoryAndSlot,
source: InventoryAndSlot, source: InventoryAndSlot,
@ -910,7 +911,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const Deposit = struct { const Deposit = struct { // MARK: Deposit
dest: InventoryAndSlot, dest: InventoryAndSlot,
source: InventoryAndSlot, source: InventoryAndSlot,
amount: u16, amount: u16,
@ -957,7 +958,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const TakeHalf = struct { const TakeHalf = struct { // MARK: TakeHalf
dest: InventoryAndSlot, dest: InventoryAndSlot,
source: InventoryAndSlot, source: InventoryAndSlot,
@ -1020,7 +1021,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const Drop = struct { const Drop = struct { // MARK: Drop
source: InventoryAndSlot, source: InventoryAndSlot,
desiredAmount: u16 = 0xffff, desiredAmount: u16 = 0xffff,
@ -1075,7 +1076,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const FillFromCreative = struct { const FillFromCreative = struct { // MARK: FillFromCreative
dest: InventoryAndSlot, dest: InventoryAndSlot,
item: ?Item, item: ?Item,
amount: u16 = 0, amount: u16 = 0,
@ -1128,7 +1129,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const DepositOrDrop = struct { const DepositOrDrop = struct { // MARK: DepositOrDrop
dest: Inventory, dest: Inventory,
source: Inventory, source: Inventory,
@ -1189,7 +1190,7 @@ pub const Command = struct { // MARK: Command
} }
}; };
const Clear = struct { const Clear = struct { // MARK: Clear
inv: Inventory, inv: Inventory,
pub fn run(self: Clear, allocator: NeverFailingAllocator, cmd: *Command, side: Side, _: ?*main.server.User, _: Gamemode) error{serverFailure}!void { 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, source: InventoryAndSlot,
pos: Vec3i, pos: Vec3i,
oldBlock: Block, oldBlock: Block,
@ -1275,9 +1276,7 @@ pub const Command = struct { // MARK: Command
for(0..amount) |_| { for(0..amount) |_| {
for(self.newBlock.blockDrops()) |drop| { for(self.newBlock.blockDrops()) |drop| {
if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) { if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) {
for(drop.items) |itemStack| { blockDrop(self.pos, drop);
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);
}
} }
} }
} }
@ -1288,11 +1287,17 @@ pub const Command = struct { // MARK: Command
if(side == .server and gamemode != .creative and self.oldBlock.typ != self.newBlock.typ) { if(side == .server and gamemode != .creative and self.oldBlock.typ != self.newBlock.typ) {
for(self.oldBlock.blockDrops()) |drop| { for(self.oldBlock.blockDrops()) |drop| {
if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) { if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) {
blockDrop(self.pos, drop);
}
}
}
}
fn blockDrop(pos: Vec3i, drop: main.blocks.BlockDrop) void {
for(drop.items) |itemStack| { 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); 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);
}
} }
} }
@ -1334,7 +1339,7 @@ const Source = union(SourceType) {
other: void, other: void,
}; };
const Inventory = @This(); const Inventory = @This(); // MARK: Inventory
const Type = enum(u8) { const Type = enum(u8) {
normal = 0, normal = 0,

View File

@ -35,11 +35,11 @@ const ItemDrop = struct { // MARK: ItemDrop
pub const ItemDropManager = struct { // MARK: ItemDropManager pub const ItemDropManager = struct { // MARK: ItemDropManager
/// Half the side length of all item entities hitboxes as a cube. /// 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. /// 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; const maxSpeed = 10;
@ -285,7 +285,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
self.fixStuckInBlock(chunk, pos, vel, deltaTime); self.fixStuckInBlock(chunk, pos, vel, deltaTime);
return; return;
} }
var drag: f64 = self.airDragFactor;
vel.* += Vec3d{0, 0, -self.gravity*deltaTime}; vel.* += Vec3d{0, 0, -self.gravity*deltaTime};
inline for(0..3) |i| { inline for(0..3) |i| {
const move = vel.*[i]*deltaTime;// + acceleration[i]*deltaTime; const move = vel.*[i]*deltaTime;// + acceleration[i]*deltaTime;
@ -299,10 +298,9 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
} else { } else {
pos.*[i] += move; pos.*[i] += move;
} }
drag += 0.5; // TODO: Calculate drag from block properties and add buoyancy.
} }
// Apply drag: // 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 { fn fixStuckInBlock(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {