Skip to content
2 changes: 2 additions & 0 deletions src/entityComponent/_list.zig
Original file line number Diff line number Diff line change
@@ -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");
114 changes: 114 additions & 0 deletions src/entityComponent/breaking.zig
Original file line number Diff line number Diff line change
@@ -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);
}
};
2 changes: 1 addition & 1 deletion src/entityComponent/player.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};
Expand Down
114 changes: 114 additions & 0 deletions src/entityComponent/swinging.zig
Original file line number Diff line number Diff line change
@@ -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);
}
};
64 changes: 34 additions & 30 deletions src/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand All @@ -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;
Expand Down
Loading