diff --git a/src/entityComponent/_list.zig b/src/entityComponent/_list.zig index d162bf66e0..280bde371a 100644 --- a/src/entityComponent/_list.zig +++ b/src/entityComponent/_list.zig @@ -1,5 +1,7 @@ pub const @"cubyz:_template" = @import("_template.zig"); pub const @"cubyz:bag" = @import("bag.zig"); +pub const @"cubyz:breaking" = @import("breaking.zig"); pub const @"cubyz:model" = @import("model.zig"); pub const @"cubyz:permissions" = @import("permissions.zig"); pub const @"cubyz:player" = @import("player.zig"); +pub const @"cubyz:swinging" = @import("swinging.zig"); diff --git a/src/entityComponent/breaking.zig b/src/entityComponent/breaking.zig new file mode 100644 index 0000000000..ae2982009e --- /dev/null +++ b/src/entityComponent/breaking.zig @@ -0,0 +1,114 @@ +const std = @import("std"); + +const main = @import("main"); +const chunk = main.chunk; +const Entity = main.entity.Entity; +const ServerChunk = chunk.ServerChunk; +const game = main.game; +const graphics = main.graphics; +const ZonElement = main.ZonElement; +const renderer = main.renderer; +const settings = main.settings; +const utils = main.utils; +const BinaryReader = utils.BinaryReader; +const BinaryWriter = utils.BinaryWriter; +const vec = main.vec; +const Mat4f = vec.Mat4f; +const Vec3d = vec.Vec3d; +const Vec3f = vec.Vec3f; +const Vec4f = vec.Vec4f; +const Vec3i = vec.Vec3i; +const NeverFailingAllocator = main.heap.NeverFailingAllocator; +const blocks = main.blocks; +const World = game.World; +const ServerWorld = main.server.ServerWorld; +const items = main.items; +const ItemStack = items.ItemStack; +const random = main.random; + +const c = @import("c"); + +pub var entityComponentID: main.entity.EntityComponentId = undefined; +pub const entityComponentVersion = 0; + +// ############################# Client only stuff ################################ +pub const client = struct { + const Component = struct { + progress: f32, + blockPos: Vec3i, + }; + pub var components: main.utils.SparseSet(Component, Entity) = .{}; + + pub fn init() void {} + pub fn deinit() void { + components.deinit(main.globalAllocator); + } + pub fn clear() void { + components.clear(); + } + pub fn load(entity: Entity, reader: *utils.BinaryReader, version: u32) main.entity.EntityComponentLoadError!void { + if (version != 0) return error.InvalidComponentVersion; + const progress = reader.readFloat(f32) catch return error.UnreadableComponentData; + const blockPos = reader.readVec(Vec3i) catch return error.UnreadableComponentData; + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = Component{ + .progress = progress, + .blockPos = blockPos, + }; + } + + pub fn put(entity: Entity, blockPos: Vec3i) void { + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = .{ + .progress = 0, + .blockPos = blockPos, + }; + } + + pub fn unload(entity: Entity) void { + components.remove(entity) catch {}; + } + pub fn get(entity: Entity) ?*Component { + return components.get(entity); + } +}; +// ############################# Server only stuff ################################ +pub const server = struct { + pub const Component = struct { + progress: f32, + blockPos: Vec3i, + pub fn save(self: Component, writer: *utils.BinaryWriter, audience: main.entity.AudienceInfo) main.entity.ComponentSaveBehaviour { + if (audience == .disk) return .discard; + writer.writeFloat(f32, self.progress); + writer.writeVec(Vec3i, self.blockPos); + return .save; + } + }; + var components: main.utils.SparseSet(Component, Entity) = undefined; + pub fn init() void { + components = .{}; + } + pub fn deinit() void { + components.deinit(main.globalAllocator); + } + pub fn loadFromData(entity: Entity, _: *utils.BinaryReader, version: u32) main.entity.EntityComponentLoadError!void { + if (version != 0) return error.InvalidComponentVersion; + load(entity); + } + pub fn load(entity: Entity) void { + put(entity, Component{ + .progress = 0, + .blockPos = .{0, 0, 0}, + }); + } + pub fn unload(entity: Entity) void { + components.remove(entity) catch {}; + } + pub fn put(entity: Entity, renderComponent: Component) void { + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = renderComponent; + } + pub fn get(entity: Entity) ?*Component { + return components.get(entity); + } +}; diff --git a/src/entityComponent/player.zig b/src/entityComponent/player.zig index d20a73a5f7..796edf0451 100644 --- a/src/entityComponent/player.zig +++ b/src/entityComponent/player.zig @@ -59,8 +59,8 @@ pub const server = struct { pub const Component = struct { playerIndex: u32, // model pub fn save(self: Component, writer: *utils.BinaryWriter, audience: main.entity.AudienceInfo) main.entity.ComponentSaveBehaviour { - writer.writeVarInt(u32, self.playerIndex); if (audience == .disk) return .discard; + writer.writeVarInt(u32, self.playerIndex); return .save; } }; diff --git a/src/entityComponent/swinging.zig b/src/entityComponent/swinging.zig new file mode 100644 index 0000000000..7a0cba2ca7 --- /dev/null +++ b/src/entityComponent/swinging.zig @@ -0,0 +1,114 @@ +const std = @import("std"); + +const main = @import("main"); +const chunk = main.chunk; +const Entity = main.entity.Entity; +const ServerChunk = chunk.ServerChunk; +const game = main.game; +const graphics = main.graphics; +const ZonElement = main.ZonElement; +const renderer = main.renderer; +const settings = main.settings; +const utils = main.utils; +const BinaryReader = utils.BinaryReader; +const BinaryWriter = utils.BinaryWriter; +const vec = main.vec; +const Mat4f = vec.Mat4f; +const Vec3d = vec.Vec3d; +const Vec3f = vec.Vec3f; +const Vec4f = vec.Vec4f; +const Vec3i = vec.Vec3i; +const NeverFailingAllocator = main.heap.NeverFailingAllocator; +const blocks = main.blocks; +const World = game.World; +const ServerWorld = main.server.ServerWorld; +const items = main.items; +const ItemStack = items.ItemStack; +const random = main.random; + +const c = @import("c"); + +pub var entityComponentID: main.entity.EntityComponentId = undefined; +pub const entityComponentVersion = 0; + +// ############################# Client only stuff ################################ +pub const client = struct { + const Component = struct { + currentSwingProgress: f32, + currentSwingTime: f32, + }; + pub var components: main.utils.SparseSet(Component, Entity) = .{}; + + pub fn init() void {} + pub fn deinit() void { + components.deinit(main.globalAllocator); + } + pub fn clear() void { + components.clear(); + } + pub fn load(entity: Entity, reader: *utils.BinaryReader, version: u32) main.entity.EntityComponentLoadError!void { + if (version != 0) return error.InvalidComponentVersion; + const currentSwingProgress = reader.readFloat(f32) catch return error.UnreadableComponentData; + const currentSwingTime = reader.readFloat(f32) catch return error.UnreadableComponentData; + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = Component{ + .currentSwingProgress = currentSwingProgress, + .currentSwingTime = currentSwingTime, + }; + } + + pub fn put(entity: Entity) void { + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = .{ + .currentSwingProgress = 0, + .currentSwingTime = 0, + }; + } + + pub fn unload(entity: Entity) void { + components.remove(entity) catch {}; + } + pub fn get(entity: Entity) ?*Component { + return components.get(entity); + } +}; +// ############################# Server only stuff ################################ +pub const server = struct { + pub const Component = struct { + currentSwingProgress: f32, + currentSwingTime: f32, + pub fn save(self: Component, writer: *utils.BinaryWriter, audience: main.entity.AudienceInfo) main.entity.ComponentSaveBehaviour { + if (audience == .disk) return .discard; + writer.writeFloat(f32, self.currentSwingProgress); + writer.writeFloat(f32, self.currentSwingTime); + return .save; + } + }; + var components: main.utils.SparseSet(Component, Entity) = undefined; + pub fn init() void { + components = .{}; + } + pub fn deinit() void { + components.deinit(main.globalAllocator); + } + pub fn loadFromData(entity: Entity, _: *utils.BinaryReader, version: u32) main.entity.EntityComponentLoadError!void { + if (version != 0) return error.InvalidComponentVersion; + load(entity); + } + pub fn load(entity: Entity) void { + put(entity, Component{ + .currentSwingProgress = 0, + .currentSwingTime = 0, + }); + } + pub fn unload(entity: Entity) void { + components.remove(entity) catch {}; + } + pub fn put(entity: Entity, renderComponent: Component) void { + const ptr = components.get(entity) orelse components.add(main.globalAllocator, entity); + ptr.* = renderComponent; + } + pub fn get(entity: Entity) ?*Component { + return components.get(entity); + } +}; diff --git a/src/renderer.zig b/src/renderer.zig index b250021882..8ba03fe715 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -922,10 +922,6 @@ pub const MeshSelection = struct { // MARK: MeshSelection var posBeforeBlock: Vec3i = undefined; var neighborOfSelection: chunk.Neighbor = undefined; pub var selectedBlockPos: ?Vec3i = null; - var lastSelectedBlockPos: Vec3i = undefined; - var currentBlockProgress: f32 = 0; - var currentSwingProgress: f32 = 0; - var currentSwingTime: f32 = 0; var selectionMin: Vec3f = undefined; var selectionMax: Vec3f = undefined; var selectionNormal: Vec3f = undefined; @@ -1067,7 +1063,16 @@ pub const MeshSelection = struct { // MARK: MeshSelection } pub fn breakBlock(inventory: main.items.Inventory.ClientInventory, slot: u32, deltaTime: f64) void { + const swinging = main.entity.components.@"cubyz:swinging".client.get(main.game.Player.id) orelse blk: { + main.entity.components.@"cubyz:swinging".client.put(main.game.Player.id); + break :blk main.entity.components.@"cubyz:swinging".client.get(main.game.Player.id).?; + }; + if (selectedBlockPos) |selectedPos| { + const breaking = main.entity.components.@"cubyz:breaking".client.get(main.game.Player.id) orelse blk: { + main.entity.components.@"cubyz:breaking".client.put(main.game.Player.id, selectedPos); + break :blk main.entity.components.@"cubyz:breaking".client.get(main.game.Player.id).?; + }; const stack = inventory.getStack(slot); const isSelectionWand = stack.item == .baseItem and std.mem.eql(u8, stack.item.baseItem.id(), "cubyz:selection_wand"); if (isSelectionWand) { @@ -1076,12 +1081,11 @@ pub const MeshSelection = struct { // MARK: MeshSelection return; } - if (@reduce(.Or, lastSelectedBlockPos != selectedPos)) { - mesh_storage.removeBreakingAnimation(lastSelectedBlockPos); - currentSwingProgress = 0; - currentSwingTime = 0; - lastSelectedBlockPos = selectedPos; - currentBlockProgress = 0; + if (@reduce(.Or, breaking.blockPos != selectedPos)) { + mesh_storage.removeBreakingAnimation(breaking.blockPos); + main.entity.components.@"cubyz:breaking".client.put(main.game.Player.id, selectedPos); + swinging.currentSwingProgress = 0; + swinging.currentSwingTime = 0; } const block = mesh_storage.getBlockFromRenderThread(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return; const holdingTargetedBlock = stack.item == .baseItem and stack.item.baseItem.block() == block.typ; @@ -1099,44 +1103,44 @@ pub const MeshSelection = struct { // MARK: MeshSelection damage -= block.blockResistance(); if (damage > 0) { const swingTime = if (isProceduralItem and stack.item.proceduralItem.isEffectiveOn(block)) 1.0/stack.item.proceduralItem.getProperty(.swingSpeed) else 0.5; - if (currentSwingTime > swingTime) { - currentSwingProgress = 0; - currentSwingTime = 0; + if (swinging.currentSwingTime > swingTime) { + swinging.currentSwingProgress = 0; + swinging.currentSwingTime = 0; } - if (currentSwingTime == 0) { + if (swinging.currentSwingTime == 0) { const swings = @ceil(block.blockHealth()/damage); const damagePerSwing = block.blockHealth()/swings; - currentSwingTime = damagePerSwing/damage*swingTime; + swinging.currentSwingTime = damagePerSwing/damage*swingTime; } - currentSwingProgress += @floatCast(deltaTime); - while (currentSwingProgress > currentSwingTime) { - currentSwingProgress -= currentSwingTime; - currentBlockProgress += damage*currentSwingTime/swingTime/block.blockHealth(); - if (currentBlockProgress > 0.9999) break; + swinging.currentSwingProgress += @floatCast(deltaTime); + while (swinging.currentSwingProgress > swinging.currentSwingTime) { + swinging.currentSwingProgress -= swinging.currentSwingTime; + breaking.progress += damage*swinging.currentSwingTime/swingTime/block.blockHealth(); + if (breaking.progress > 0.9999) break; const swings = @ceil(block.blockHealth()/damage); const damagePerSwing = block.blockHealth()/swings; - currentSwingTime = damagePerSwing/damage*swingTime; + swinging.currentSwingTime = damagePerSwing/damage*swingTime; } - if (currentBlockProgress < 0.9999) { - mesh_storage.removeBreakingAnimation(lastSelectedBlockPos); - if (currentBlockProgress != 0) { - mesh_storage.addBreakingAnimation(lastSelectedBlockPos, currentBlockProgress); + if (breaking.progress < 0.9999) { + mesh_storage.removeBreakingAnimation(breaking.blockPos); + if (breaking.progress != 0) { + mesh_storage.addBreakingAnimation(breaking.blockPos, breaking.progress); } main.sync.client.mutex.unlock(); return; } else { - currentSwingProgress = 0; - mesh_storage.removeBreakingAnimation(lastSelectedBlockPos); - currentBlockProgress = 0; - currentSwingTime = 0; + swinging.currentSwingProgress = 0; + mesh_storage.removeBreakingAnimation(breaking.blockPos); + breaking.progress = 0; + swinging.currentSwingTime = 0; } } else { main.sync.client.mutex.unlock(); return; } } else { - mesh_storage.removeBreakingAnimation(lastSelectedBlockPos); + mesh_storage.removeBreakingAnimation(breaking.blockPos); } var newBlock = block;