diff --git a/src/blocks.zig b/src/blocks.zig index 7a75f16c..71c70b97 100644 --- a/src/blocks.zig +++ b/src/blocks.zig @@ -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, diff --git a/src/game.zig b/src/game.zig index 57007526..8f41c49f 100644 --- a/src/game.zig +++ b/src/game.zig @@ -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; } diff --git a/src/main.zig b/src/main.zig index 309fbbc1..14803437 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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();