Simplified Block Touch Detection (#1143)

* Add block touch detection

* Fix touch detection syntax errors

* Remove Whitespace

* Fix off by one in negatives

* Remove Block Touch Detection

* Simpler touch detection as suggested by Quantum

* Remove touchRetraction because for some reason it is no longer needed

* Touch Functions are now function pointers

* Remove unwanted debug prints

* Add parameter names to TouchFunction declaration

* Add error check

---------

Co-authored-by: gfh <@>
Co-authored-by: SuperIceG <102669377+SEGenjoysBlivits@users.noreply.github.com>
This commit is contained in:
qFelix 2025-03-06 23:30:33 +01:00 committed by GitHub
parent 471210f585
commit 2b3547d103
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 97 additions and 0 deletions

View File

@ -13,6 +13,7 @@ const items = @import("items.zig");
const models = @import("models.zig");
const rotation = @import("rotation.zig");
const RotationMode = rotation.RotationMode;
const Entity = main.server.Entity;
pub const BlockTag = enum(u32) {
air = 0,
@ -109,6 +110,8 @@ var _friction: [maxBlockCount]f32 = undefined;
var _allowOres: [maxBlockCount]bool = undefined;
var _touchFunction: [maxBlockCount]?*const TouchFunction = undefined;
var reverseIndices = std.StringHashMap(u16).init(allocator.allocator);
var size: u32 = 0;
@ -149,6 +152,7 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 {
_hasBackFace[size] = zon.get(bool, "hasBackFace", false);
_friction[size] = zon.get(f32, "friction", 20);
_allowOres[size] = zon.get(bool, "allowOres", false);
_touchFunction[size] = TouchFunctions.getFunctionPointer(zon.get([]const u8, "touchFunction", ""));
const oreProperties = zon.getChild("ore");
if(oreProperties != .null) blk: {
@ -374,11 +378,44 @@ pub const Block = packed struct { // MARK: Block
return _allowOres[self.typ];
}
pub inline fn touchFunction(self: Block) ?*const TouchFunction {
return _touchFunction[self.typ];
}
pub fn canBeChangedInto(self: Block, newBlock: Block, item: main.items.ItemStack, shouldDropSourceBlockOnSuccess: *bool) main.rotation.RotationMode.CanBeChangedInto {
return newBlock.mode().canBeChangedInto(self, newBlock, item, shouldDropSourceBlockOnSuccess);
}
};
pub const TouchFunction = fn(block: Block, entity: Entity, posX: i32, posY: i32, posZ: i32, isEntityInside: bool) void;
pub const TouchFunctions = struct {
var hashMap: std.StringHashMap(*const TouchFunction) = undefined;
pub fn init() void {
hashMap = .init(main.globalAllocator.allocator);
inline for(@typeInfo(TouchFunctions).@"struct".decls) |declaration| {
if(@TypeOf(@field(TouchFunctions, declaration.name)) == TouchFunction) {
hashMap.putNoClobber(declaration.name, &@field(TouchFunctions, declaration.name)) catch unreachable;
}
}
}
pub fn deinit() void {
hashMap.deinit();
}
pub fn getFunctionPointer(id: []const u8) ?*const TouchFunction {
const pointer = hashMap.getPtr(id);
if(pointer == null) {
if(id.len != 0)
std.log.err("Could not find touch function {s}.", .{id});
return null;
}
return pointer.?.*;
}
};
pub const meshes = struct { // MARK: meshes
const AnimationData = extern struct {
startFrame: u32,

View File

@ -25,6 +25,7 @@ const models = main.models;
const Fog = graphics.Fog;
const renderer = @import("renderer.zig");
const settings = @import("settings.zig");
const Block = main.blocks.Block;
pub const camera = struct { // MARK: camera
pub var rotation: Vec3f = Vec3f{0, 0, 0};
@ -362,6 +363,61 @@ pub const collision = struct {
return resultingMovement;
}
fn isBlockIntersecting(block: Block, posX: i32, posY: i32, posZ: i32, center: Vec3d, extent: Vec3d) bool {
const model = &models.models.items[block.mode().model(block)];
const position = Vec3d{@floatFromInt(posX), @floatFromInt(posY), @floatFromInt(posZ)};
for(model.neighborFacingQuads) |quads| {
for(quads) |quadIndex| {
const quad = &models.quads.items[quadIndex];
if(triangleAABB(.{quad.corners[0] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[1] + quad.normal + position}, center, extent) or
triangleAABB(.{quad.corners[1] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[3] + quad.normal + position}, center, extent)) return true;
}
}
for(model.internalQuads) |quadIndex| {
const quad = &models.quads.items[quadIndex];
if(triangleAABB(.{quad.corners[0] + position, quad.corners[2] + position, quad.corners[1] + position}, center, extent) or
triangleAABB(.{quad.corners[1] + position, quad.corners[2] + position, quad.corners[3] + position}, center, extent)) return true;
}
return false;
}
pub fn touchBlocks(entity: main.server.Entity, hitBox: Box, side: main.utils.Side) void {
const boundingBox: Box = .{.min = entity.pos + hitBox.min, .max = entity.pos + hitBox.max};
const minX: i32 = @intFromFloat(@floor(boundingBox.min[0] - 0.01));
const maxX: i32 = @intFromFloat(@floor(boundingBox.max[0] + 0.01));
const minY: i32 = @intFromFloat(@floor(boundingBox.min[1] - 0.01));
const maxY: i32 = @intFromFloat(@floor(boundingBox.max[1] + 0.01));
const minZ: i32 = @intFromFloat(@floor(boundingBox.min[2] - 0.01));
const maxZ: i32 = @intFromFloat(@floor(boundingBox.max[2] + 0.01));
const center: Vec3d = boundingBox.center();
const extent: Vec3d = boundingBox.extent();
const extentX: Vec3d = extent + Vec3d{0.01, -0.01, -0.01};
const extentY: Vec3d = extent + Vec3d{-0.01, 0.01, -0.01};
const extentZ: Vec3d = extent + Vec3d{-0.01, -0.01, 0.01};
var posX: i32 = minX;
while(posX <= maxX) : (posX += 1) {
var posY: i32 = minY;
while(posY <= maxY) : (posY += 1) {
var posZ: i32 = minZ;
while(posZ <= maxZ) : (posZ += 1) {
const block: ?Block =
if(side == .client) main.renderer.mesh_storage.getBlock(posX, posY, posZ) else main.server.world.?.getBlock(posX, posY, posZ);
if(block == null or block.?.touchFunction() == null)
continue;
const touchX: bool = isBlockIntersecting(block.?, posX, posY, posZ, center, extentX);
const touchY: bool = isBlockIntersecting(block.?, posX, posY, posZ, center, extentY);
const touchZ: bool = isBlockIntersecting(block.?, posX, posY, posZ, center, extentZ);
if(touchX or touchY or touchZ)
block.?.touchFunction().?(block.?, entity, posX, posY, posZ, touchX and touchY and touchZ);
}
}
}
}
pub const Box = struct {
min: Vec3d,
max: Vec3d,
@ -1126,6 +1182,7 @@ pub fn update(deltaTime: f64) void { // MARK: update()
} else if(Player.eyeCoyote > 0) {
Player.eyePos[2] -= move[2];
}
collision.touchBlocks(Player.super, hitBox, .client);
} else {
Player.super.pos += move;
}

View File

@ -580,6 +580,9 @@ pub fn main() void { // MARK: main()
rotation.init();
defer rotation.deinit();
blocks.TouchFunctions.init();
defer blocks.TouchFunctions.deinit();
models.init();
defer models.deinit();