Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add branch block type #1118

Merged
merged 25 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c2131f2
Add branch block type
Argmaster Feb 28, 2025
e975279
Fix tabs
Argmaster Feb 28, 2025
f5a6f78
Degenerate quads by setting them (.5,.5,.5)
Argmaster Feb 28, 2025
2ba91bd
Add directional branch connecting
Argmaster Feb 28, 2025
a9ae716
Fix branches connecting to non-solid blocks
Argmaster Feb 28, 2025
3057efe
Simplify branchTransform
Argmaster Mar 1, 2025
9e07452
No automatic connections to solid blocks
Argmaster Mar 1, 2025
7b16918
Use Neighbor to express branch connections
Argmaster Mar 1, 2025
49ae8b8
Allow manual modification of branch connections
Argmaster Mar 1, 2025
a09d60e
Update branch model to have solid ends
Argmaster Mar 1, 2025
6ddadaf
Merge remote-tracking branch 'origin/master' into feature/oak-pillar
Argmaster Mar 1, 2025
c76ae76
Tweak block connecting logic
Argmaster Mar 1, 2025
9a769d0
Tweak comments
Argmaster Mar 1, 2025
1ff8559
Tweak branch model UV
Argmaster Mar 1, 2025
53b7c67
Update branch debug texture
Argmaster Mar 1, 2025
e516a19
Remove extra faces on connections
Argmaster Mar 1, 2025
1f4243a
Apply review suggestions
Argmaster Mar 1, 2025
5942870
Exclude viewThrough blocks from branch updateData
Argmaster Mar 1, 2025
234f67e
Revert "Exclude viewThrough blocks from branch updateData"
Argmaster Mar 1, 2025
e12ff99
Apply review suggestions
Argmaster Mar 2, 2025
5e14deb
Merge remote-tracking branch 'origin/master' into feature/oak-pillar
Argmaster Mar 2, 2025
90a50cd
Snakes not allowed
Argmaster Mar 2, 2025
16498e2
Fix style issues
Argmaster Mar 2, 2025
806b6eb
Apply review suggestions
Argmaster Mar 3, 2025
8781ad2
Fix formatting issue
Argmaster Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions assets/cubyz/blocks/oak_branch.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.{
.tags = .{.wood},
.blockHealth = 5,
.drops = .{
.{ .items = .{.auto} },
},
.absorbedLight = 0x202830,
.rotation = .branch,
.model = "cubyz:branch",
.texture = "cubyz:oak_branch",
}
Binary file added assets/cubyz/blocks/textures/oak_branch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cubyz/blocks/textures/oak_branch_debug.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
108 changes: 108 additions & 0 deletions assets/cubyz/models/branch.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Blender 4.1.0
# www.blender.org
o branch
v 0.250000 0.750000 0.750000
v 0.250000 0.750000 0.250000
v 0.250000 0.250000 0.250000
v 0.250000 0.250000 0.750000
v 0.750000 0.250000 0.750000
v 0.750000 0.250000 0.250000
v 0.750000 0.750000 0.250000
v 0.750000 0.750000 0.750000
v 0.750000 0.250000 0.750000
v 0.750000 0.250000 0.250000
v 1.000000 0.250000 0.250000
v 1.000000 0.250000 0.750000
v 1.000000 0.750000 0.750000
v 1.000000 0.750000 0.250000
v 0.750000 0.750000 0.250000
v 0.750000 0.750000 0.750000
v 0.750000 0.250000 0.750000
v 0.750000 0.250000 0.250000
v 0.750000 0.000000 0.250000
v 0.750000 0.000000 0.750000
v 0.250000 0.000000 0.750000
v 0.250000 0.000000 0.250000
v 0.250000 0.250000 0.250000
v 0.250000 0.250000 0.750000
v 0.750000 0.250000 0.250000
v 0.250000 0.250000 0.250000
v 0.250000 0.250000 -0.000000
v 0.750000 0.250000 -0.000000
v 0.750000 0.750000 -0.000000
v 0.250000 0.750000 -0.000000
v 0.250000 0.750000 0.250000
v 0.750000 0.750000 0.250000
v 0.750000 0.250000 1.000000
v 0.250000 0.250000 1.000000
v 0.250000 0.250000 0.750000
v 0.750000 0.250000 0.750000
v 0.750000 0.750000 0.750000
v 0.250000 0.750000 0.750000
v 0.250000 0.750000 1.000000
v 0.750000 0.750000 1.000000
v 0.250000 1.000000 0.750000
v 0.250000 1.000000 0.250000
v 0.250000 0.750000 0.250000
v 0.250000 0.750000 0.750000
v 0.750000 0.750000 0.750000
v 0.750000 0.750000 0.250000
v 0.750000 1.000000 0.250000
v 0.750000 1.000000 0.750000
v 0.000000 0.250000 0.750000
v 0.000000 0.250000 0.250000
v 0.250000 0.250000 0.250000
v 0.250000 0.250000 0.750000
v 0.250000 0.750000 0.750000
v 0.250000 0.750000 0.250000
v 0.000000 0.750000 0.250000
v 0.000000 0.750000 0.750000
vn -1.0000 -0.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn -0.0000 -0.0000 1.0000
vt 0.062500 0.187500
vt 0.062500 0.062500
vt 0.187500 0.062500
vt 0.187500 0.187500
vt 0.000000 0.062500
vt 0.000000 0.187500
vt 0.187500 0.250000
vt 0.062500 0.250000
vt 0.250000 0.062500
vt 0.250000 0.187500
vt 0.187500 0.000000
vt 0.062500 0.000000
s 0
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/1/2 6/2/2 7/3/2 8/4/2
f 4/4/3 3/3/3 6/2/3 5/1/3
f 8/4/4 7/1/4 2/2/4 1/3/4
f 9/1/3 10/2/3 11/5/3 12/6/3
f 13/7/4 14/8/4 15/1/4 16/4/4
f 10/2/5 15/1/5 14/6/5 11/5/5
f 12/6/6 13/5/6 16/2/6 9/1/6
f 20/8/6 17/1/6 24/4/6 21/7/6
f 20/6/2 19/5/2 18/2/2 17/1/2
f 24/4/1 23/3/1 22/9/1 21/10/1
f 22/11/5 23/3/5 18/2/5 19/12/5
f 5/1/6 8/2/6 1/3/6 4/4/6
f 3/3/5 2/4/5 7/1/5 6/2/5
f 25/2/3 26/3/3 27/11/3 28/12/3
f 29/6/4 30/5/4 31/2/4 32/1/4
f 26/3/1 31/2/1 30/12/1 27/11/1
f 28/12/2 29/11/2 32/3/2 25/2/2
f 33/8/3 34/7/3 35/4/3 36/1/3
f 37/4/4 38/3/4 39/9/4 40/10/4
f 34/7/1 39/8/1 38/1/1 35/4/1
f 36/1/2 37/4/2 40/7/2 33/8/2
f 41/6/1 42/5/1 43/2/1 44/1/1
f 45/4/2 46/3/2 47/9/2 48/10/2
f 43/4/5 42/7/5 47/8/5 46/1/5
f 45/2/6 48/12/6 41/11/6 44/3/6
f 49/10/3 50/9/3 51/3/3 52/4/3
f 53/3/4 54/2/4 55/12/4 56/11/4
f 50/9/5 55/10/5 54/4/5 51/3/5
f 52/4/6 53/3/6 56/9/6 49/10/6
160 changes: 160 additions & 0 deletions src/rotation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,166 @@ pub const RotationModes = struct {
return true;
}
};
pub const Branch = struct { // MARK: Branch
pub const id: []const u8 = "branch";
pub const dependsOnNeighbors = true;
var branchModels: std.StringHashMap(u16) = undefined;
const BranchData = packed struct(u6) {
enabledConnections: u6,

pub fn init(blockData: u16) BranchData {
return .{.enabledConnections = @truncate(blockData)};
}

pub fn isConnected(self: @This(), neighbor: Neighbor) bool {
return (self.enabledConnections & Neighbor.bitMask(neighbor)) != 0;
}

pub fn setConnection(self: *@This(), neighbor: Neighbor, value: bool) void {
if(value) {
self.enabledConnections |= Neighbor.bitMask(neighbor);
} else {
self.enabledConnections &= ~Neighbor.bitMask(neighbor);
}
}
};

fn init() void {
branchModels = .init(main.globalAllocator.allocator);
}

fn deinit() void {
branchModels.deinit();
}

fn branchTransform(quad: *main.models.QuadInfo, data: BranchData) void {
for(&quad.corners) |*corner| {
if((!data.isConnected(Neighbor.dirNegX) and corner[0] == 0) or
(!data.isConnected(Neighbor.dirPosX) and corner[0] == 1) or
(!data.isConnected(Neighbor.dirNegY) and corner[1] == 0) or
(!data.isConnected(Neighbor.dirPosY) and corner[1] == 1) or
(!data.isConnected(Neighbor.dirDown) and corner[2] == 0) or
(!data.isConnected(Neighbor.dirUp) and corner[2] == 1)) return degenerateQuad(quad);
}
}

fn degenerateQuad(quad: *main.models.QuadInfo) void {
for(&quad.corners) |*corner| {
corner.* = @splat(0.5);
}
}

pub fn createBlockModel(modelId: []const u8) u16 {
if(branchModels.get(modelId)) |modelIndex| return modelIndex;

const baseModelIndex = main.models.getModelIndex(modelId);
const baseModel = main.models.models.items[baseModelIndex];

const modelIndex: u16 = baseModel.transformModel(branchTransform, .{BranchData.init(0)});
for(1..64) |branchData| {
_ = baseModel.transformModel(branchTransform, .{BranchData.init(@truncate(branchData))});
}
branchModels.put(modelId, modelIndex) catch unreachable;
return modelIndex;
}

pub fn model(block: Block) u16 {
return blocks.meshes.modelIndexStart(block) + (block.data & 63);
}

pub fn generateData(
_: *main.game.World,
_: Vec3i,
_: Vec3f,
_: Vec3f,
_: Vec3i,
neighbor: ?Neighbor,
currentBlock: *Block,
neighborBlock: Block,
blockPlacing: bool,
) bool {
const blockBaseModel = blocks.meshes.modelIndexStart(currentBlock.*);
const neighborBaseModel = blocks.meshes.modelIndexStart(neighborBlock);

if(blockPlacing or blockBaseModel == neighborBaseModel or neighborBlock.solid()) {
const neighborModel = blocks.meshes.model(neighborBlock);

var currentData = BranchData.init(currentBlock.data);
// Branch block upon placement should extend towards a block it was placed
// on if the block is solid or also uses branch model.
const targetVal = ((neighborBlock.solid() and !neighborBlock.viewThrough()) and (blockBaseModel == neighborBaseModel or main.models.models.items[neighborModel].isNeighborOccluded[neighbor.?.reverse().toInt()]));
currentData.setConnection(neighbor.?, targetVal);

const result: u16 = currentData.enabledConnections;
if(result == currentBlock.data) return false;

currentBlock.data = result;
return true;
}
return false;
}

pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
const blockBaseModel = blocks.meshes.modelIndexStart(block.*);
const neighborBaseModel = blocks.meshes.modelIndexStart(neighborBlock);
var currentData = BranchData.init(block.data);

// Handle joining with other branches. While placed, branches extend in a
// opposite direction than they were placed from, effectively connecting
// to the block they were placed at.
if(blockBaseModel == neighborBaseModel) {
const neighborData = BranchData.init(neighborBlock.data);
currentData.setConnection(neighbor, neighborData.isConnected(neighbor.reverse()));
} else if(!neighborBlock.solid()) {
currentData.setConnection(neighbor, false);
}

const result: u16 = currentData.enabledConnections;
if(result == block.data) return false;

block.data = result;
return true;
}

fn closestRay(block: Block, relativePlayerPos: Vec3f, playerDir: Vec3f) ?u16 {
var closestIntersectionDistance: f64 = std.math.inf(f64);
var resultBitMask: ?u16 = null;
{
const modelIndex = blocks.meshes.modelIndexStart(block);
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
closestIntersectionDistance = intersection.distance;
resultBitMask = 0;
}
}
for(Neighbor.iterable) |direction| {
const directionBitMask = Neighbor.bitMask(direction);

if((block.data & directionBitMask) != 0) {
const modelIndex = blocks.meshes.modelIndexStart(block) + directionBitMask;
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
if(@abs(closestIntersectionDistance) > @abs(intersection.distance)) {
closestIntersectionDistance = intersection.distance;
resultBitMask = direction.bitMask();
}
}
}
}
return resultBitMask;
}

pub fn onBlockBreaking(_: ?main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f, currentData: *Block) void {
if(closestRay(currentData.*, relativePlayerPos, playerDir)) |directionBitMask| {
// If player destroys a central part of branch block, branch block is completely destroyed.
if(directionBitMask == 0) {
currentData.typ = 0;
currentData.data = 0;
return;
}
// Otherwise only the connection player aimed at is destroyed.
currentData.data &= ~directionBitMask;
}
}
};
pub const Stairs = struct { // MARK: Stairs
pub const id: []const u8 = "stairs";
var modelIndex: u16 = 0;
Expand Down