Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
9 changes: 9 additions & 0 deletions src/blocks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,15 @@ pub const Block = packed struct(u32) { // MARK: Block
pub inline fn isSelectableByItem(self: Block, item: Item) bool {
return self.selectionCapabilities().allowsSelectionByItem(self, item);
}

pub fn tryDropWhenBrokenWithItem(self: Block, newBlock: Block, item: Item, ctx: BlockDrop.Location.Context) void {
Comment thread
DellieDelta marked this conversation as resolved.
Outdated
const dropAmount = self.mode().itemDropsOnChange(self, newBlock);
for (0..dropAmount) |_| {
for (self.blockDrops()) |drop| {
drop.tryDropWhenBrokenWithItem(item, ctx);
}
}
}
};

pub const meshes = struct { // MARK: meshes
Expand Down
87 changes: 87 additions & 0 deletions src/server/BlockDrop.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ const main = @import("main");
const Tag = main.Tag;
const items = main.items;
const Item = items.Item;
const vec = main.vec;
const Vec3d = vec.Vec3d;
const Vec3f = vec.Vec3f;
const Vec3i = vec.Vec3i;

itemStacks: []const items.ItemStack,
chance: f32,
Expand All @@ -20,3 +24,86 @@ pub fn isDroppedWhenBrokenWithItem(self: @This(), item: Item) bool {

return true;
}

pub fn tryDropWhenBrokenWithItem(self: @This(), item: Item, ctx: Location.Context) void {
if (!self.isDroppedWhenBrokenWithItem(item)) return;

if (self.chance == 1 or main.random.nextFloat(&main.seed) < self.chance) {
for (self.itemStacks) |itemStack| {
main.server.world.?.drop(itemStack.clone(), ctx.pos, ctx.dir, ctx.velocity);
}
}
}

pub const Location = struct {
normalDir: Vec3f,
min: Vec3f,
max: Vec3f,

const half = @as(Vec3f, @splat(0.5));
const itemHitBoxMargin: f32 = @floatCast(main.itemdrop.ItemDropManager.radius);
const itemHitBoxMarginVec: Vec3f = @splat(itemHitBoxMargin);

pub const Context = struct {
pos: Vec3d,
dir: Vec3f,
velocity: f32,
};
pub fn getContext(self: Location, pos: Vec3i, collide: bool) Context {
const dropPos = if (collide) self.outsidePos(pos) else self.insidePos(pos);
return .{
.pos = dropPos,
.dir = self.dropDir(),
.velocity = self.dropVelocity(),
};
}

fn insidePos(self: Location, _pos: Vec3i) Vec3d {
const pos: Vec3d = @floatFromInt(_pos);
return pos + self.randomOffset();
}
fn randomOffset(self: Location) Vec3f {
const max = @min(@as(Vec3f, @splat(1.0)) - itemHitBoxMarginVec, @max(itemHitBoxMarginVec, self.max - itemHitBoxMarginVec));
const min = @min(max, @max(itemHitBoxMarginVec, self.min + itemHitBoxMarginVec));
const center = (max + min)*half;
const width = (max - min)*half;
return center + width*main.random.nextFloatVectorSigned(3, &main.seed)*half;
}
fn outsidePos(self: Location, _pos: Vec3i) Vec3d {
const pos: Vec3d = @floatFromInt(_pos);
const random = self.randomOffset();
const minorVectors = minors(self);
const minor1Offset = @as(Vec3f, @splat(vec.dot(random, minorVectors[0])))*minorVectors[0];
const minor2Offset = @as(Vec3f, @splat(vec.dot(random, minorVectors[1])))*minorVectors[1];
return pos + minor1Offset + minor2Offset + self.directionOffset()*self.major() + self.direction()*itemHitBoxMarginVec;
}
fn directionOffset(self: Location) Vec3d {
return half + self.direction()*half;
}
inline fn direction(self: Location) Vec3f {
return self.normalDir;
}
inline fn major(self: Location) Vec3f {
return @abs(self.normalDir);
}
inline fn minors(self: Location) struct { Vec3f, Vec3f } {
const minor1 = vec.normalize(vec.cross(self.normalDir, if (@reduce(.And, @abs(self.normalDir) == Vec3f{1.0, 0.0, 0.0})) Vec3f{0.0, 1.0, 0.0} else Vec3f{1.0, 0.0, 0.0}));
const minor2 = vec.normalize(vec.cross(self.normalDir, minor1));
return .{minor1, minor2};
}
fn dropDir(self: Location) Vec3f {
const randomnessVec: Vec3f = main.random.nextFloatVectorSigned(3, &main.seed)*@as(Vec3f, @splat(0.25));
const directionVec: Vec3f = @as(Vec3f, @floatCast(self.direction())) + randomnessVec;
const z: f32 = directionVec[2];
return vec.normalize(Vec3f{
directionVec[0],
directionVec[1],
if (z < -0.5) 0 else if (z < 0.0) (z + 0.5)*4.0 else z + 2.0,
});
}
fn dropVelocity(self: Location) f32 {
const velocity = 3.5 + main.random.nextFloatSigned(&main.seed)*0.5;
if (self.direction()[2] < -0.5) return velocity*0.333;
return velocity;
}
};
90 changes: 3 additions & 87 deletions src/sync.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1537,86 +1537,10 @@ pub const Command = struct { // MARK: Command
const UpdateBlock = struct { // MARK: UpdateBlock
source: InventoryAndSlot,
pos: Vec3i,
dropLocation: BlockDropLocation,
dropLocation: BlockDrop.Location,
oldBlock: Block,
newBlock: Block,

const half = @as(Vec3f, @splat(0.5));
const itemHitBoxMargin: f32 = @floatCast(main.itemdrop.ItemDropManager.radius);
const itemHitBoxMarginVec: Vec3f = @splat(itemHitBoxMargin);

const BlockDropLocation = struct {
normalDir: Vec3f,
min: Vec3f,
max: Vec3f,

pub fn drop(self: BlockDropLocation, pos: Vec3i, newBlock: Block, _drop: BlockDrop) void {
if (newBlock.collide()) {
self.dropOutside(pos, _drop);
} else {
self.dropInside(pos, _drop);
}
}
fn dropInside(self: BlockDropLocation, pos: Vec3i, _drop: BlockDrop) void {
for (_drop.itemStacks) |itemStack| {
main.server.world.?.drop(itemStack.clone(), self.insidePos(pos), self.dropDir(), self.dropVelocity());
}
}
fn insidePos(self: BlockDropLocation, _pos: Vec3i) Vec3d {
const pos: Vec3d = @floatFromInt(_pos);
return pos + self.randomOffset();
}
fn randomOffset(self: BlockDropLocation) Vec3f {
const max = @min(@as(Vec3f, @splat(1.0)) - itemHitBoxMarginVec, @max(itemHitBoxMarginVec, self.max - itemHitBoxMarginVec));
const min = @min(max, @max(itemHitBoxMarginVec, self.min + itemHitBoxMarginVec));
const center = (max + min)*half;
const width = (max - min)*half;
return center + width*main.random.nextFloatVectorSigned(3, &main.seed)*half;
}
fn dropOutside(self: BlockDropLocation, pos: Vec3i, _drop: BlockDrop) void {
for (_drop.itemStacks) |itemStack| {
main.server.world.?.drop(itemStack.clone(), self.outsidePos(pos), self.dropDir(), self.dropVelocity());
}
}
fn outsidePos(self: BlockDropLocation, _pos: Vec3i) Vec3d {
const pos: Vec3d = @floatFromInt(_pos);
const random = self.randomOffset();
const minorVectors = minors(self);
const minor1Offset = @as(Vec3f, @splat(vec.dot(random, minorVectors[0])))*minorVectors[0];
const minor2Offset = @as(Vec3f, @splat(vec.dot(random, minorVectors[1])))*minorVectors[1];
return pos + minor1Offset + minor2Offset + self.directionOffset()*self.major() + self.direction()*itemHitBoxMarginVec;
}
fn directionOffset(self: BlockDropLocation) Vec3d {
return half + self.direction()*half;
}
inline fn direction(self: BlockDropLocation) Vec3f {
return self.normalDir;
}
inline fn major(self: BlockDropLocation) Vec3f {
return @abs(self.normalDir);
}
inline fn minors(self: BlockDropLocation) struct { Vec3f, Vec3f } {
const minor1 = vec.normalize(vec.cross(self.normalDir, if (@reduce(.And, @abs(self.normalDir) == Vec3f{1.0, 0.0, 0.0})) Vec3f{0.0, 1.0, 0.0} else Vec3f{1.0, 0.0, 0.0}));
const minor2 = vec.normalize(vec.cross(self.normalDir, minor1));
return .{minor1, minor2};
}
fn dropDir(self: BlockDropLocation) Vec3f {
const randomnessVec: Vec3f = main.random.nextFloatVectorSigned(3, &main.seed)*@as(Vec3f, @splat(0.25));
const directionVec: Vec3f = @as(Vec3f, @floatCast(self.direction())) + randomnessVec;
const z: f32 = directionVec[2];
return vec.normalize(Vec3f{
directionVec[0],
directionVec[1],
if (z < -0.5) 0 else if (z < 0.0) (z + 0.5)*4.0 else z + 2.0,
});
}
fn dropVelocity(self: BlockDropLocation) f32 {
const velocity = 3.5 + main.random.nextFloatSigned(&main.seed)*0.5;
if (self.direction()[2] < -0.5) return velocity*0.333;
return velocity;
}
};

fn run(self: UpdateBlock, ctx: Context) error{serverFailure}!void {
const stack = self.source.ref();

Expand Down Expand Up @@ -1672,16 +1596,8 @@ pub const Command = struct { // MARK: Command
},
}
if (ctx.side == .server and ctx.gamemode != .creative and shouldDropSourceBlockOnSuccess) {
const dropAmount = self.oldBlock.mode().itemDropsOnChange(self.oldBlock, self.newBlock);
for (0..dropAmount) |_| {
for (self.oldBlock.blockDrops()) |drop| {
if (!drop.isDroppedWhenBrokenWithItem(handItem)) continue;

if (drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) {
self.dropLocation.drop(self.pos, self.newBlock, drop);
}
}
}
const dropCtx = self.dropLocation.getContext(self.pos, self.newBlock.collide());
self.oldBlock.tryDropWhenBrokenWithItem(self.newBlock, handItem, dropCtx);
}
}

Expand Down
Loading