Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a716a3b
Add dynamite assets
Argmaster Apr 16, 2025
d65595c
Add explosions
Argmaster Apr 16, 2025
12e82f5
Fix formatting of special_recipes.zig.zon
Argmaster Apr 16, 2025
76095c6
change explosions
OneAvargeCoder193 Apr 16, 2025
15fd27b
some fixes
OneAvargeCoder193 Apr 16, 2025
aa8d7d8
Merge pull request #6 from OneAvargeCoder193/feature/dynamite
Argmaster Apr 16, 2025
53bb999
Add dynamite block
Argmaster Apr 16, 2025
2fbb40f
Fix formatting
Argmaster Apr 16, 2025
139abea
Tweak explosion strength and variable names
Argmaster Apr 16, 2025
4a578c6
Tweak explosion strength
Argmaster Apr 17, 2025
1d0ac2e
Fix formatting
Argmaster Apr 17, 2025
ed25223
Move explosions to server side and add gamerule
Argmaster Apr 17, 2025
bcda0a9
New dynamite textures, remove dynamite block model
careeoki Apr 17, 2025
020dfc3
Merge pull request #7 from careeoki/dynamite-textures
Argmaster Apr 17, 2025
9bb109b
Update assets/cubyz/blocks/dynamite/block.zig.zon
Argmaster Apr 18, 2025
b79f924
Update assets/cubyz/recipes/special_recipes.zig.zon
Argmaster Apr 18, 2025
8158a14
Merge remote-tracking branch 'origin/master' into feature/dynamite
Argmaster Apr 28, 2025
f2e5b16
Merge remote-tracking branch 'origin/master' into feature/dynamite
Argmaster May 1, 2025
8f5fc8e
Apply review change requests
Argmaster May 9, 2025
4005694
Add Allow Explosives to world creation
Argmaster May 9, 2025
2eacb2c
Merge remote-tracking branch 'origin/master' into feature/dynamite
Argmaster May 9, 2025
943c924
some fixes
OneAvargeCoder193 May 11, 2025
c4be4ca
Merge pull request #9 from OneAvargeCoder193/feature/dynamite
OneAvargeCoder193 May 11, 2025
bdfc414
apply formatting fix
OneAvargeCoder193 May 11, 2025
1064322
Merge pull request #10 from OneAvargeCoder193/feature/dynamite
OneAvargeCoder193 May 11, 2025
78fe9e5
Small fixes
Argmaster May 18, 2025
e9845fd
Big fixes
Argmaster May 18, 2025
509bccd
Merge remote-tracking branch 'origin/master' into feature/dynamite
Argmaster May 18, 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
12 changes: 12 additions & 0 deletions assets/cubyz/blocks/dynamite/block.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.{
.tags = .{.canBeIgnited, .explosive},
.blockHealth = 3,
.drops = .{
.{.items = .{.auto}},
},
.rotation = .log,
.model = "cubyz:cube",
.texture = "cubyz:dynamite/side",
.texture_top = "cubyz:dynamite/top",
.texture_bottom = "cubyz:dynamite/bottom",
}
20 changes: 20 additions & 0 deletions assets/cubyz/blocks/dynamite/stick.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.{
.tags = .{.canBeIgnited, .explosive},
.blockHealth = 1,
.drops = .{
.{.items = .{.auto}},
},
.solid = false,
.viewThrough = true,
.collide = false,
.rotation = .torch,
.model = .{
.base = "cubyz:dynamite/top",
.side = "cubyz:dynamite/side",
},
.texture = "cubyz:dynamite/stick",
.item = .{
.texture = "dynamite.png",
},
.lodReplacement = "cubyz:air",
}
1 change: 1 addition & 0 deletions assets/cubyz/blocks/sulfur_torch.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
.texture = "cubyz:sulfur_torch",
.item = .{
.tags = .{.canIgnite},
.texture = "sulfur_torch.png",
},
.lodReplacement = "cubyz:air",
Expand Down
Binary file added assets/cubyz/blocks/textures/dynamite/bottom.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/dynamite/side.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/dynamite/stick.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/dynamite/top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/cubyz/blocks/torch.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
.texture = "cubyz:torch",
.item = .{
.tags = .{.canIgnite},
.texture = "torch.png",
},
.lodReplacement = "cubyz:air",
Expand Down
Binary file added assets/cubyz/items/textures/dynamite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions assets/cubyz/models/dynamite/side.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
v -0.174106 0.625000 0.073623
v 0.124704 0.625000 0.761528
v -0.174106 0.375000 0.073623
v 0.124704 0.375000 0.761528
v 0.055196 0.375000 -0.025980
v 0.354005 0.375000 0.661925
v 0.055196 0.625000 -0.025980
v 0.354005 0.625000 0.661925
v 0.224307 0.500000 0.990829
v 0.453609 0.500000 0.891226
v 0.124704 0.500000 0.761528
v 0.354005 0.500000 0.661925
v 0.224307 0.500100 0.990829
v 0.453609 0.500100 0.891226
v 0.124704 0.500100 0.761528
v 0.354005 0.500100 0.661925
vn -0.9172 -0.0000 0.3984
vn 0.9172 -0.0000 -0.3984
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vn 0.3984 -0.0000 0.9172
vn -0.3984 -0.0000 -0.9172
vt 0.750000 0.250000
vt 0.750000 0.062500
vt 0.812500 0.062500
vt 0.812500 0.250000
vt 0.500000 0.250000
vt 0.500000 0.062500
vt 0.562500 0.062500
vt 0.562500 0.250000
vt 0.250000 0.500000
vt 0.250000 0.312500
vt 0.312500 0.312500
vt 0.312500 0.500000
vt 0.000000 0.500000
vt 0.000000 0.312500
vt 0.062500 0.312500
vt 0.062500 0.500000
vt 0.062500 0.187500
vt 0.062500 0.125000
vt 0.125000 0.125000
vt 0.125000 0.187500
vt 0.313125 0.125625
vt 0.313125 0.063125
vt 0.375625 0.063125
vt 0.375625 0.125625
vt 0.062500 0.250000
vt 0.125000 0.250000
s 0
f 2/1/1 1/2/1 3/3/1 4/4/1
f 6/5/2 5/6/2 7/7/2 8/8/2
f 4/9/3 3/10/3 5/11/3 6/12/3
f 8/13/4 7/14/4 1/15/4 2/16/4
f 6/17/5 8/18/5 2/19/5 4/20/5
f 3/21/6 1/22/6 7/23/6 5/24/6
f 9/17/3 11/25/3 12/26/3 10/20/3
f 13/17/4 14/20/4 16/26/4 15/25/4
57 changes: 57 additions & 0 deletions assets/cubyz/models/dynamite/top.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
v 0.375000 0.625000 -0.000000
v 0.375000 0.625000 0.750000
v 0.375000 0.375000 -0.000000
v 0.375000 0.375000 0.750000
v 0.625000 0.375000 -0.000000
v 0.625000 0.375000 0.750000
v 0.625000 0.625000 -0.000000
v 0.625000 0.625000 0.750000
v 0.375000 0.500000 1.000000
v 0.625000 0.500000 1.000000
v 0.375000 0.500000 0.750000
v 0.625000 0.500000 0.750000
v 0.375000 0.500000 1.000000
v 0.625000 0.500000 1.000000
v 0.375000 0.500000 0.750000
v 0.625000 0.500000 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.750000 0.250000
vt 0.750000 0.062500
vt 0.812500 0.062500
vt 0.812500 0.250000
vt 0.500000 0.250000
vt 0.500000 0.062500
vt 0.562500 0.062500
vt 0.562500 0.250000
vt 0.250000 0.500000
vt 0.250000 0.312500
vt 0.312500 0.312500
vt 0.312500 0.500000
vt 0.000000 0.500000
vt 0.000000 0.312500
vt 0.062500 0.312500
vt 0.062500 0.500000
vt 0.062500 0.187500
vt 0.062500 0.125000
vt 0.125000 0.125000
vt 0.125000 0.187500
vt 0.312500 0.125000
vt 0.312500 0.062500
vt 0.375000 0.062500
vt 0.375000 0.125000
vt 0.125000 0.250000
vt 0.062500 0.250000
s 0
f 2/1/1 1/2/1 3/3/1 4/4/1
f 6/5/2 5/6/2 7/7/2 8/8/2
f 4/9/3 3/10/3 5/11/3 6/12/3
f 8/13/4 7/14/4 1/15/4 2/16/4
f 6/17/5 8/18/5 2/19/5 4/20/5
f 3/21/6 1/22/6 7/23/6 5/24/6
f 9/17/4 10/20/4 12/25/4 11/26/4
f 13/17/3 15/26/3 16/25/3 14/20/3
12 changes: 12 additions & 0 deletions assets/cubyz/recipes/special_recipes.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,16 @@
.inputs = .{"cubyz:gravel"},
.output = "4 cubyz:pebbles",
},
.{
.inputs = .{"2 cubyz:sulfur_ore", "2 cubyz:coal"},
.output = "cubyz:dynamite/stick",
},
.{
.inputs = .{"8 cubyz:dynamite/stick"},
.output = "cubyz:dynamite/block",
},
.{
.inputs = .{"cubyz:dynamite/block"},
.output = "8 cubyz:dynamite/stick",
},
}
17 changes: 13 additions & 4 deletions src/gui/windows/save_creation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var gamemode: main.game.Gamemode = .creative;
var gamemodeInput: *Button = undefined;

var allowCheats: bool = true;
var allowExplosives: bool = true;

fn gamemodeCallback(_: usize) void {
gamemode = std.meta.intToEnum(main.game.Gamemode, @intFromEnum(gamemode) + 1) catch @enumFromInt(0);
Expand All @@ -38,6 +39,10 @@ fn allowCheatsCallback(allow: bool) void {
allowCheats = allow;
}

fn allowExplosivesCallback(allow: bool) void {
allowExplosives = allow;
}

fn createWorld(_: usize) void {
flawedCreateWorld() catch |err| {
std.log.err("Error while creating new world: {s}", .{@errorName(err)});
Expand Down Expand Up @@ -121,6 +126,7 @@ fn flawedCreateWorld() !void {

gamerules.put("default_gamemode", @tagName(gamemode));
gamerules.put("cheats", allowCheats);
gamerules.put("allow_explosives", allowExplosives);

try main.files.writeZon(gamerulePath, gamerules);
}
Expand Down Expand Up @@ -148,15 +154,18 @@ pub fn onOpen() void {
}
const name = std.fmt.allocPrint(main.stackAllocator.allocator, "Save{}", .{num}) catch unreachable;
defer main.stackAllocator.free(name);
textInput = TextInput.init(.{0, 0}, 128, 22, name, .{.callback = &createWorld}, .{});

const widgetWidth = 160;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We call them components, not widgets

textInput = TextInput.init(.{0, 0}, widgetWidth, 22, name, .{.callback = &createWorld}, .{});
list.add(textInput);

gamemodeInput = Button.initText(.{0, 0}, 128, @tagName(gamemode), .{.callback = &gamemodeCallback});
gamemodeInput = Button.initText(.{0, 0}, widgetWidth, @tagName(gamemode), .{.callback = &gamemodeCallback});
list.add(gamemodeInput);

list.add(CheckBox.init(.{0, 0}, 128, "Allow Cheats", true, &allowCheatsCallback));
list.add(CheckBox.init(.{0, 0}, widgetWidth, "Allow Cheats", true, &allowCheatsCallback));
list.add(CheckBox.init(.{0, 0}, widgetWidth, "Allow Explosives", true, &allowExplosivesCallback));

list.add(Button.initText(.{0, 0}, 128, "Create World", .{.callback = &createWorld}));
list.add(Button.initText(.{0, 0}, widgetWidth, "Create World", .{.callback = &createWorld}));

list.finish(.center);
window.rootComponent = list.toComponent();
Expand Down
5 changes: 1 addition & 4 deletions src/items.zig
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,7 @@ pub const BaseItem = struct { // MARK: BaseItem
}

pub fn hasTag(self: *const BaseItem, tag: Tag) bool {
for(self.tags) |other| {
if(other == tag) return true;
}
return false;
return std.mem.containsAtLeastScalar(Tag, self.tags, 1, tag);
}
};

Expand Down
100 changes: 100 additions & 0 deletions src/network.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,106 @@ pub const Protocols = struct {
conn.send(.fast, id, writer.data.items);
}
};
pub const explode = struct {
pub const id: u8 = 14;
pub const asynchronous = false;
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
const pos = try reader.readVec(Vec3i);

if(conn.user == null) return error.InvalidPacket;
if(!main.server.world.?.allowExplosives) return;
doExplode(pos);
}
fn doExplode(pos: Vec3i) void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not believe this belongs in the network code. Maybe the server world would be a more appropiate place?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I think they should be block entities and this code should be inside / next to onInteract, tho it is a big change and big redesign. This also would mean we are back to believing whatever client says, unless we introduce server side onInteract.
IMO we should consider it though because it would be an example of block entity with such interaction and some attached metadata (explosion radius).

Copy link
Member

@IntegratedQuantum IntegratedQuantum Jun 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you could just propagate it as a block entity data change, then you can check on the server side, if the gamerule is set.
Implementing it as a state change could also allow adding a short delay and some fuse particles before detonating.

const explosiveBlock = main.server.world.?.getBlock(pos[0], pos[1], pos[2]) orelse return;
if(!explosiveBlock.hasTag(.explosive)) return;

const strength = explosiveBlock.blockHealth()*32.0;
const radius = explosiveBlock.blockHealth()*4.0;

const airDamageDecrease = 8.0;
const fluidDamageDecrease = 64.0;

const diameter: u32 = @intFromFloat(std.math.ceil(radius)*2);
const goldenAngle = std.math.pi*(3.0 - @sqrt(5.0));
const radiusInt: usize = @intFromFloat(std.math.ceil(radius));
const numSamples: usize = @intFromFloat(std.math.ceil(4*std.math.pi*radius*radius)*2);

const exploded = main.utils.Array3D(bool).init(main.stackAllocator, diameter, diameter, diameter);
defer exploded.deinit(main.stackAllocator);
@memset(exploded.mem, false);

var explosionSeed: u64 = @bitCast(std.time.milliTimestamp());

for(0..numSamples) |i| {
const z = 1 - 2*@as(f32, @floatFromInt(i))/@as(f32, @floatFromInt(numSamples));
const radiusAtZ = @sqrt(1 - z*z);
const theta = goldenAngle*@as(f32, @floatFromInt(i));
const x = radiusAtZ*@cos(theta);
const y = radiusAtZ*@sin(theta);

var damage = strength;

for(0..radiusInt) |j| {
const distanceFactor = @as(f32, @floatFromInt(j))/@as(f32, @floatFromInt(radiusInt));
const distance = radius*distanceFactor;

const xOffset: i32 = @intFromFloat(x*distance);
const yOffset: i32 = @intFromFloat(y*distance);
const zOffset: i32 = @intFromFloat(z*distance);

const p = pos +% Vec3i{xOffset, yOffset, zOffset};

var oldBlock = main.server.world.?.getBlock(p[0], p[1], p[2]) orelse continue;

const blockDamageDelta = (oldBlock.blockHealth() + oldBlock.blockResistance());
if(damage < blockDamageDelta) {
defer damage = 0;
if(damage < 0 or damage/blockDamageDelta > main.random.nextFloat(&main.seed)) break;
}

if(oldBlock.hasTag(.air)) {
damage -= airDamageDecrease;
continue;
} else if(oldBlock.hasTag(.fluid)) {
damage -= fluidDamageDecrease;
continue;
} else {
damage -= blockDamageDelta*main.random.nextFloat(&main.seed) + airDamageDecrease*main.random.nextFloat(&main.seed);
}

const xCentered: usize = @intCast(xOffset + @as(i32, @intCast(diameter/2)));
const yCentered: usize = @intCast(yOffset + @as(i32, @intCast(diameter/2)));
const zCentered: usize = @intCast(zOffset + @as(i32, @intCast(diameter/2)));

exploded.set(xCentered, yCentered, zCentered, true);

damage -= strength/@as(f32, @floatFromInt(radiusInt)) + main.random.nextFloat(&explosionSeed)*0.5;
}
}

for(0..diameter) |_x| {
const x = @as(i32, @intCast(_x)) +% pos[0] -% @as(i32, @intCast(diameter/2));

for(0..diameter) |_y| {
const y = @as(i32, @intCast(_y)) +% pos[1] -% @as(i32, @intCast(diameter/2));

for(0..diameter) |_z| {
const z = @as(i32, @intCast(_z)) +% pos[2] -% @as(i32, @intCast(diameter/2));
if(exploded.get(_x, _y, _z)) {
_ = main.server.world.?.cmpxchgBlock(x, y, z, null, .{.typ = 0, .data = 0});
}
}
}
}
}
pub fn send(conn: *Connection, pos: Vec3i) void {
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 12);
defer writer.deinit();
writer.writeVec(Vec3i, pos);
conn.send(.fast, id, writer.data.items);
}
};
};

pub const Connection = struct { // MARK: Connection
Expand Down
4 changes: 4 additions & 0 deletions src/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,10 @@ pub const MeshSelection = struct { // MARK: MeshSelection
if(inventory.getItem(slot)) |item| {
switch(item) {
.baseItem => |baseItem| {
if(baseItem.hasTag(.canIgnite) and oldBlock.hasTag(.canBeIgnited)) {
if(oldBlock.hasTag(.explosive)) main.network.Protocols.explode.send(main.game.world.?.conn, selectedPos);
return;
}
if(baseItem.block()) |itemBlock| {
const rotationMode = blocks.Block.mode(.{.typ = itemBlock, .data = 0});
var neighborDir = Vec3i{0, 0, 0};
Expand Down
2 changes: 2 additions & 0 deletions src/server/world.zig
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld

defaultGamemode: main.game.Gamemode = undefined,
allowCheats: bool = undefined,
allowExplosives: bool = undefined,

seed: u64,
path: []const u8,
Expand Down Expand Up @@ -539,6 +540,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld

self.defaultGamemode = std.meta.stringToEnum(main.game.Gamemode, gamerules.get([]const u8, "default_gamemode", "creative")) orelse .creative;
self.allowCheats = gamerules.get(bool, "cheats", true);
self.allowExplosives = gamerules.get(bool, "allow_explosives", true);

self.chunkManager = try ChunkManager.init(self, generatorSettings);
errdefer self.chunkManager.deinit();
Expand Down
3 changes: 3 additions & 0 deletions src/tag.zig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub const Tag = enum(u32) {
air = 0,
fluid = 1,
sbbChild = 2,
explosive = 3,
canIgnite = 4,
canBeIgnited = 5,
_,

pub fn resetTags() void {
Expand Down