mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 11:44:21 -04:00
parent
8418202df8
commit
6473362c6e
5
assets/cubyz/items/chisel.json
Normal file
5
assets/cubyz/items/chisel.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"texture" : "special/chisel.png",
|
||||
"stackSize" : 1,
|
||||
"onLeftUse" : "chisel",
|
||||
}
|
@ -91,7 +91,7 @@ pub const Player = struct {
|
||||
|
||||
pub fn breakBlock() void { // TODO: Breaking animation and tools
|
||||
if(!main.Window.grabbed) return;
|
||||
main.renderer.MeshSelection.breakBlock();
|
||||
main.renderer.MeshSelection.breakBlock(&inventory__SEND_CHANGES_TO_SERVER.items[selectedSlot]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,8 @@ const Mat4f = vec.Mat4f;
|
||||
const Vec2f = vec.Vec2f;
|
||||
const Vec2i = vec.Vec2i;
|
||||
const Vec3i = vec.Vec3i;
|
||||
const Vec3d = vec.Vec3d;
|
||||
const Vec3f = vec.Vec3f;
|
||||
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
||||
|
||||
/// Holds the basic properties of a tool crafting material.
|
||||
@ -69,6 +71,8 @@ pub const BaseItem = struct {
|
||||
block: ?u16,
|
||||
foodValue: f32, // TODO: Effects.
|
||||
|
||||
leftClickUse: ?*const fn(world: *main.game.World, pos: Vec3i, relativePlayerPos: Vec3d, playerDir: Vec3f, currentData: *Block) bool,
|
||||
|
||||
var unobtainable = BaseItem {
|
||||
.image = graphics.Image.defaultImage,
|
||||
.texture = null,
|
||||
@ -78,6 +82,7 @@ pub const BaseItem = struct {
|
||||
.material = null,
|
||||
.block = null,
|
||||
.foodValue = 0,
|
||||
.leftClickUse = null,
|
||||
};
|
||||
|
||||
fn init(self: *BaseItem, allocator: NeverFailingAllocator, texturePath: []const u8, replacementTexturePath: []const u8, id: []const u8, json: JsonElement) void {
|
||||
@ -104,6 +109,14 @@ pub const BaseItem = struct {
|
||||
};
|
||||
self.texture = null;
|
||||
self.foodValue = json.get(f32, "food", 0);
|
||||
self.leftClickUse = if(std.mem.eql(u8, json.get([]const u8, "onLeftUse", ""), "chisel")) &chiselFunction else null; // TODO: Proper registry.
|
||||
}
|
||||
|
||||
fn chiselFunction(world: *main.game.World, pos: Vec3i, relativePlayerPos: Vec3d, playerDir: Vec3f, currentData: *Block) bool {
|
||||
if(currentData.mode() == main.rotation.getByID("stairs")) {
|
||||
return main.rotation.RotationModes.Stairs.chisel(world, pos, relativePlayerPos, playerDir, currentData);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn hashCode(self: BaseItem) u32 {
|
||||
|
@ -832,8 +832,25 @@ pub const MeshSelection = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn breakBlock() void {
|
||||
pub fn breakBlock(inventoryStack: *main.items.ItemStack) void {
|
||||
if(selectedBlockPos) |selectedPos| {
|
||||
var block = mesh_storage.getBlockFromRenderThread(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return;
|
||||
// TODO: Breaking animation and tools.
|
||||
if(inventoryStack.item) |item| {
|
||||
switch(item) {
|
||||
.baseItem => |baseItem| {
|
||||
if(baseItem.leftClickUse) |leftClick| {
|
||||
const relPos = lastPos - @as(Vec3d, @floatFromInt(selectedPos));
|
||||
if(leftClick(main.game.world.?, selectedPos, relPos, lastDir, &block)) {
|
||||
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); (→ Sending it over the network)
|
||||
mesh_storage.updateBlock(selectedPos[0], selectedPos[1], selectedPos[2], block);
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
mesh_storage.updateBlock(selectedPos[0], selectedPos[1], selectedPos[2], .{.typ = 0, .data = 0});
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ fn rotationMatrixTransform(quad: *main.models.QuadInfo, transformMatrix: Mat4f)
|
||||
}
|
||||
}
|
||||
|
||||
const RotationModes = struct {
|
||||
pub const RotationModes = struct {
|
||||
pub const NoRotation = struct {
|
||||
pub const id: []const u8 = "no_rotation";
|
||||
fn init() void {}
|
||||
@ -196,8 +196,11 @@ const RotationModes = struct {
|
||||
pub const id: []const u8 = "stairs";
|
||||
var modelIndex: u16 = 0;
|
||||
|
||||
fn subBlockMask(x: u1, y: u1, z: u1) u8 {
|
||||
return @as(u8, 1) << ((@as(u3, x)*2 + @as(u3, y))*2 + z);
|
||||
}
|
||||
fn hasSubBlock(stairData: u8, x: u1, y: u1, z: u1) bool {
|
||||
return stairData & @as(u8, 1) << ((@as(u3, x)*2 + @as(u3, y))*2 + z) == 0;
|
||||
return stairData & subBlockMask(x, y, z) == 0;
|
||||
}
|
||||
|
||||
fn init() void {
|
||||
@ -301,7 +304,7 @@ const RotationModes = struct {
|
||||
// Greedy mesh it:
|
||||
var faces: [2]GreedyFaceInfo = undefined;
|
||||
const frontFaces = mergeFaces(visibleFront, &faces);
|
||||
for(frontFaces) |face| {
|
||||
for(frontFaces) |*face| {
|
||||
var xLower = @abs(xAxis)*@as(Vec3f, @splat(face.min[0]));
|
||||
var xUpper = @abs(xAxis)*@as(Vec3f, @splat(face.max[0]));
|
||||
if(@reduce(.Add, xAxis) > 0) std.mem.swap(Vec3f, &xLower, &xUpper);
|
||||
@ -309,6 +312,25 @@ const RotationModes = struct {
|
||||
var yUpper = @abs(yAxis)*@as(Vec3f, @splat(face.max[1]));
|
||||
if(@reduce(.Add, yAxis) > 0) std.mem.swap(Vec3f, &yLower, &yUpper);
|
||||
const zValue: Vec3f = @floatFromInt(zComponent*zMap[1]);
|
||||
if(neighbor != chunk.Neighbors.dirUp) {
|
||||
if(neighbor == chunk.Neighbors.dirNegX or neighbor == chunk.Neighbors.dirPosY) {
|
||||
face.min[1] = 1 - face.min[1];
|
||||
face.max[1] = 1 - face.max[1];
|
||||
const swap = face.min[1];
|
||||
face.min[1] = face.max[1];
|
||||
face.max[1] = swap;
|
||||
} else if(neighbor == chunk.Neighbors.dirDown) {
|
||||
face.min[0] = 1 - face.min[0];
|
||||
face.max[0] = 1 - face.max[0];
|
||||
const swap = face.min[0];
|
||||
face.min[0] = face.max[0];
|
||||
face.max[0] = swap;
|
||||
} else {
|
||||
face.min = Vec2f{1, 1} - face.min;
|
||||
face.max = Vec2f{1, 1} - face.max;
|
||||
std.mem.swap(Vec2f, &face.min, &face.max);
|
||||
}
|
||||
}
|
||||
quads.append(.{
|
||||
.normal = zAxis,
|
||||
.corners = .{
|
||||
@ -322,7 +344,7 @@ const RotationModes = struct {
|
||||
});
|
||||
}
|
||||
const middleFaces = mergeFaces(visibleMiddle, &faces);
|
||||
for(middleFaces) |face| {
|
||||
for(middleFaces) |*face| {
|
||||
var xLower = @abs(xAxis)*@as(Vec3f, @splat(face.min[0]));
|
||||
var xUpper = @abs(xAxis)*@as(Vec3f, @splat(face.max[0]));
|
||||
if(@reduce(.Add, xAxis) > 0) std.mem.swap(Vec3f, &xLower, &xUpper);
|
||||
@ -330,6 +352,25 @@ const RotationModes = struct {
|
||||
var yUpper = @abs(yAxis)*@as(Vec3f, @splat(face.max[1]));
|
||||
if(@reduce(.Add, yAxis) > 0) std.mem.swap(Vec3f, &yLower, &yUpper);
|
||||
const zValue = @as(Vec3f, @floatFromInt(zComponent))*@as(Vec3f, @splat(0.5));
|
||||
if(neighbor != chunk.Neighbors.dirUp) {
|
||||
if(neighbor == chunk.Neighbors.dirNegX or neighbor == chunk.Neighbors.dirPosY) {
|
||||
face.min[1] = 1 - face.min[1];
|
||||
face.max[1] = 1 - face.max[1];
|
||||
const swap = face.min[1];
|
||||
face.min[1] = face.max[1];
|
||||
face.max[1] = swap;
|
||||
} else if(neighbor == chunk.Neighbors.dirDown) {
|
||||
face.min[0] = 1 - face.min[0];
|
||||
face.max[0] = 1 - face.max[0];
|
||||
const swap = face.min[0];
|
||||
face.min[0] = face.max[0];
|
||||
face.max[0] = swap;
|
||||
} else {
|
||||
face.min = Vec2f{1, 1} - face.min;
|
||||
face.max = Vec2f{1, 1} - face.max;
|
||||
std.mem.swap(Vec2f, &face.min, &face.max);
|
||||
}
|
||||
}
|
||||
quads.append(.{
|
||||
.normal = zAxis,
|
||||
.corners = .{
|
||||
@ -354,11 +395,49 @@ const RotationModes = struct {
|
||||
pub fn model(block: Block) u16 {
|
||||
return blocks.meshes.modelIndexStart(block) + (block.data & 255);
|
||||
}
|
||||
var data: u8 = 0;
|
||||
|
||||
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3d, _: Vec3f, _: Vec3i, currentData: *Block, blockPlacing: bool) bool {
|
||||
if(blockPlacing) {
|
||||
currentData.data = data; // TODO: Set this to a full block and allow modifying the stairs with a chisel.
|
||||
data +%= 1;
|
||||
currentData.data = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn intersectHalfUnitBox(start: Vec3f, invDir: Vec3f) ?f32 {
|
||||
const t0 = start*invDir;
|
||||
const t1 = (start + Vec3f{0.5, 0.5, 0.5})*invDir;
|
||||
const entry = @reduce(.Max, @min(t0, t1));
|
||||
const exit = @reduce(.Min, @max(t0, t1));
|
||||
if(entry > exit or exit < 0) {
|
||||
return null;
|
||||
} else return entry;
|
||||
}
|
||||
|
||||
pub fn chisel(_: *main.game.World, _: Vec3i, relativePlayerPos: Vec3d, playerDir: Vec3f, currentData: *Block) bool {
|
||||
const invDir = @as(Vec3f, @splat(1))/playerDir;
|
||||
const relPos: Vec3f = @floatCast(-relativePlayerPos);
|
||||
const data: u8 = @truncate(currentData.data);
|
||||
var minT: f32 = std.math.floatMax(f32);
|
||||
var minPos: @Vector(3, u1) = undefined;
|
||||
for(0..8) |i| {
|
||||
const subPos: @Vector(3, u1) = .{
|
||||
@truncate(i >> 2),
|
||||
@truncate(i >> 1),
|
||||
@truncate(i),
|
||||
};
|
||||
if(hasSubBlock(data, subPos[0], subPos[1], subPos[2])) {
|
||||
const relSubPos = relPos + @as(Vec3f, @floatFromInt(subPos))*@as(Vec3f, @splat(0.5));
|
||||
if(intersectHalfUnitBox(relSubPos, invDir)) |t| {
|
||||
if(t < minT) {
|
||||
minT = t;
|
||||
minPos = subPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(minT != std.math.floatMax(f32)) {
|
||||
currentData.data = data | subBlockMask(minPos[0], minPos[1], minPos[2]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user