mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Directional drops (#1251)
* Add some crazy complicated logic to unstuck items * Add bouncinessFactor * Fix formatting issues * Use rayIntersection to determine direction of drop * Simplify blockDrop() code * Apply review change requests * Send bounding box for block drops * Rename BlockDrop to BlockDropLocation * Apply review change requests * Apply review change requests * Update src/Inventory.zig * Apply review change requests * Remove code reversing direction for carpet * Update src/Inventory.zig Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Update src/Inventory.zig Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Remove factors variable * Strip types from randomOffset --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
735e99826e
commit
668f9d0a9a
@ -13,6 +13,7 @@ const Vec3d = vec.Vec3d;
|
||||
const Vec3f = vec.Vec3f;
|
||||
const Vec3i = vec.Vec3i;
|
||||
const ZonElement = main.ZonElement;
|
||||
const Neighbor = main.chunk.Neighbor;
|
||||
|
||||
const Gamemode = main.game.Gamemode;
|
||||
|
||||
@ -1555,9 +1556,80 @@ pub const Command = struct { // MARK: Command
|
||||
const UpdateBlock = struct { // MARK: UpdateBlock
|
||||
source: InventoryAndSlot,
|
||||
pos: Vec3i,
|
||||
dropLocation: BlockDropLocation,
|
||||
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 {
|
||||
dir: Neighbor,
|
||||
min: Vec3f,
|
||||
max: Vec3f,
|
||||
|
||||
pub fn drop(self: BlockDropLocation, pos: Vec3i, newBlock: Block, _drop: main.blocks.BlockDrop) void {
|
||||
if(newBlock.collide()) {
|
||||
self.dropOutside(pos, _drop);
|
||||
} else {
|
||||
self.dropInside(pos, _drop);
|
||||
}
|
||||
}
|
||||
fn dropInside(self: BlockDropLocation, pos: Vec3i, _drop: main.blocks.BlockDrop) void {
|
||||
for(_drop.items) |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: main.blocks.BlockDrop) void {
|
||||
for(_drop.items) |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);
|
||||
return pos + self.randomOffset()*self.minor() + self.directionOffset()*self.major() + self.direction()*itemHitBoxMarginVec;
|
||||
}
|
||||
fn directionOffset(self: BlockDropLocation) Vec3d {
|
||||
return half + self.direction()*half;
|
||||
}
|
||||
inline fn direction(self: BlockDropLocation) Vec3d {
|
||||
return @floatFromInt(self.dir.relPos());
|
||||
}
|
||||
inline fn major(self: BlockDropLocation) Vec3d {
|
||||
return @floatFromInt(@abs(self.dir.relPos()));
|
||||
}
|
||||
inline fn minor(self: BlockDropLocation) Vec3d {
|
||||
return @floatFromInt(self.dir.orthogonalComponents());
|
||||
}
|
||||
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, allocator: NeverFailingAllocator, cmd: *Command, side: Side, user: ?*main.server.User, gamemode: Gamemode) error{serverFailure}!void {
|
||||
if(self.source.inv.type != .normal) return;
|
||||
|
||||
@ -1610,7 +1682,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) {
|
||||
blockDrop(self.pos, drop);
|
||||
self.dropLocation.drop(self.pos, self.newBlock, drop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1621,25 +1693,18 @@ pub const Command = struct { // MARK: Command
|
||||
if(side == .server and gamemode != .creative and self.oldBlock.typ != self.newBlock.typ and shouldDropSourceBlockOnSuccess) {
|
||||
for(self.oldBlock.blockDrops()) |drop| {
|
||||
if(drop.chance == 1 or main.random.nextFloat(&main.seed) < drop.chance) {
|
||||
blockDrop(self.pos, drop);
|
||||
self.dropLocation.drop(self.pos, self.newBlock, 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, writer: *utils.BinaryWriter) void {
|
||||
self.source.write(writer);
|
||||
writer.writeInt(i32, self.pos[0]);
|
||||
writer.writeInt(i32, self.pos[1]);
|
||||
writer.writeInt(i32, self.pos[2]);
|
||||
writer.writeVec(Vec3i, self.pos);
|
||||
writer.writeEnum(Neighbor, self.dropLocation.dir);
|
||||
writer.writeVec(Vec3f, self.dropLocation.min);
|
||||
writer.writeVec(Vec3f, self.dropLocation.max);
|
||||
writer.writeInt(u32, @as(u32, @bitCast(self.oldBlock)));
|
||||
writer.writeInt(u32, @as(u32, @bitCast(self.newBlock)));
|
||||
}
|
||||
@ -1647,10 +1712,11 @@ pub const Command = struct { // MARK: Command
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !UpdateBlock {
|
||||
return .{
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
.pos = .{
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
.pos = try reader.readVec(Vec3i),
|
||||
.dropLocation = .{
|
||||
.dir = try reader.readEnum(Neighbor),
|
||||
.min = try reader.readVec(Vec3f),
|
||||
.max = try reader.readVec(Vec3f),
|
||||
},
|
||||
.oldBlock = @bitCast(try reader.readInt(u32)),
|
||||
.newBlock = @bitCast(try reader.readInt(u32)),
|
||||
|
@ -716,6 +716,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
||||
var currentSwingTime: f32 = 0;
|
||||
var selectionMin: Vec3f = undefined;
|
||||
var selectionMax: Vec3f = undefined;
|
||||
var selectionFace: chunk.Neighbor = undefined;
|
||||
var lastPos: Vec3d = undefined;
|
||||
var lastDir: Vec3f = undefined;
|
||||
pub fn select(pos: Vec3d, _dir: Vec3f, item: ?main.items.Item) void {
|
||||
@ -750,6 +751,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
||||
selectedBlockPos = voxelPos;
|
||||
selectionMin = intersection.min;
|
||||
selectionMax = intersection.max;
|
||||
selectionFace = intersection.face;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -927,7 +929,19 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
||||
}
|
||||
|
||||
fn updateBlockAndSendUpdate(source: main.items.Inventory, slot: u32, x: i32, y: i32, z: i32, oldBlock: blocks.Block, newBlock: blocks.Block) void {
|
||||
main.items.Inventory.Sync.ClientSide.executeCommand(.{.updateBlock = .{.source = .{.inv = source, .slot = slot}, .pos = .{x, y, z}, .oldBlock = oldBlock, .newBlock = newBlock}});
|
||||
main.items.Inventory.Sync.ClientSide.executeCommand(.{
|
||||
.updateBlock = .{
|
||||
.source = .{.inv = source, .slot = slot},
|
||||
.pos = .{x, y, z},
|
||||
.dropLocation = .{
|
||||
.dir = selectionFace,
|
||||
.min = selectionMin,
|
||||
.max = selectionMax,
|
||||
},
|
||||
.oldBlock = oldBlock,
|
||||
.newBlock = newBlock,
|
||||
},
|
||||
});
|
||||
mesh_storage.updateBlock(x, y, z, newBlock);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ pub const RayIntersectionResult = struct {
|
||||
distance: f64,
|
||||
min: Vec3f,
|
||||
max: Vec3f,
|
||||
face: Neighbor,
|
||||
};
|
||||
|
||||
pub const Degrees = enum(u2) {
|
||||
@ -65,10 +66,27 @@ pub const RotationMode = struct { // MARK: RotationMode
|
||||
const boxTMin = @reduce(.Max, @min(t1, t2));
|
||||
const boxTMax = @reduce(.Min, @max(t1, t2));
|
||||
if(boxTMin <= boxTMax and boxTMax > 0) {
|
||||
var face: Neighbor = undefined;
|
||||
if(boxTMin == t1[0]) {
|
||||
face = Neighbor.dirNegX;
|
||||
} else if(boxTMin == t1[1]) {
|
||||
face = Neighbor.dirNegY;
|
||||
} else if(boxTMin == t1[2]) {
|
||||
face = Neighbor.dirDown;
|
||||
} else if(boxTMin == t2[0]) {
|
||||
face = Neighbor.dirPosX;
|
||||
} else if(boxTMin == t2[1]) {
|
||||
face = Neighbor.dirPosY;
|
||||
} else if(boxTMin == t2[2]) {
|
||||
face = Neighbor.dirUp;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
return .{
|
||||
.distance = boxTMin,
|
||||
.min = min,
|
||||
.max = max,
|
||||
.face = face,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
|
@ -296,15 +296,12 @@ pub fn rayIntersection(block: Block, item: ?main.items.Item, relativePlayerPos:
|
||||
if(item) |_item| {
|
||||
switch(_item) {
|
||||
.baseItem => |baseItem| {
|
||||
if(std.mem.eql(u8, baseItem.id, "cubyz:chisel")) { // Select only one eigth of a block
|
||||
if(std.mem.eql(u8, baseItem.id, "cubyz:chisel")) { // Select only one eighth of a block
|
||||
if(intersectionPos(block, relativePlayerPos, playerDir)) |intersection| {
|
||||
const offset: Vec3f = @floatFromInt(intersection.minPos);
|
||||
const half: Vec3f = @splat(0.5);
|
||||
return .{
|
||||
.distance = intersection.minT,
|
||||
.min = half*offset,
|
||||
.max = half + half*offset,
|
||||
};
|
||||
const fullIntersection = RotationMode.DefaultFunctions.rayIntersection(block, item, relativePlayerPos, playerDir) orelse unreachable;
|
||||
return .{.distance = intersection.minT, .min = half*offset, .max = half + half*offset, .face = fullIntersection.face};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user