From 6a6bba2adf815264219c7222695ec7d3dcedb47a Mon Sep 17 00:00:00 2001 From: mnhs Date: Fri, 26 Jun 2026 17:36:24 +0200 Subject: [PATCH 1/6] init --- assets/cubyz/shaders/particles/particles.vert | 3 ++- src/particles.zig | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/assets/cubyz/shaders/particles/particles.vert b/assets/cubyz/shaders/particles/particles.vert index f7e48f1378..f00e9953be 100644 --- a/assets/cubyz/shaders/particles/particles.vert +++ b/assets/cubyz/shaders/particles/particles.vert @@ -11,6 +11,7 @@ struct ParticleData { vec3 pos; float rotation; float lifeRatio; + float loopRatio; uint light; uint type; }; @@ -81,6 +82,6 @@ void main() { const vec3 vertexPos = (billboardMatrix*vec4(particleType.size*vertexRotationPos, 1)).xyz + particle.pos; gl_Position = projectionAndViewMatrix*vec4(vertexPos, 1); - float textureIndex = floor(particle.lifeRatio*particleType.animationFrames + particleType.startFrame); + float textureIndex = floor(mod(particle.lifeRatio*particle.loopRatio*particleType.animationFrames, particleType.animationFrames) + particleType.startFrame); textureCoords = vec3(uvPositions[vertexID], textureIndex); } diff --git a/src/particles.zig b/src/particles.zig index c123a9af36..12a8159eab 100644 --- a/src/particles.zig +++ b/src/particles.zig @@ -72,6 +72,7 @@ pub const ParticleManager = struct { .density = RandomRange(f32).fromZon(zon.getChild("density")) orelse .init(2, 3), .rotVel = rotVel, .dragCoefficient = RandomRange(f32).fromZon(zon.getChild("dragCoefficient")) orelse .init(0.5, 0.6), + .loopTime = RandomRange(f32).fromZon(zon.getChild("loopTime")), }; particleTypeHashmap.put(main.worldArena.allocator, id, @intCast(types.items.len)) catch unreachable; @@ -314,6 +315,7 @@ pub const ParticleSystem = struct { .pos = @as(Vec3f, @floatCast(pos - previousPlayerPos)), .rot = rot, .typ = typ, + .loopRatio = lifeTime / if (particleType.loopTime) |l| l.get(&main.seed) else 1, }; particlesLocal[particleCount] = ParticleLocal{ .velAndRotationVel = vec.combine(vel, rotVel), @@ -551,15 +553,16 @@ pub const ParticleTypeLocal = struct { density: RandomRange(f32), rotVel: RandomRange(f32), dragCoefficient: RandomRange(f32), + loopTime: ?RandomRange(f32), }; pub const Particle = extern struct { pos: [3]f32 align(16), rot: f32 = 0, lifeRatio: f32 = 1, + loopRatio: f32 = 1, light: u32 = 0, typ: u32, - // 4 bytes left for use }; pub const ParticleLocal = struct { From 72f4c43a1c89918bfee0a854d6dd94b61bc658f2 Mon Sep 17 00:00:00 2001 From: mnhs Date: Sun, 28 Jun 2026 20:40:01 +0200 Subject: [PATCH 2/6] fmt --- src/particles.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles.zig b/src/particles.zig index 12a8159eab..9da60f385f 100644 --- a/src/particles.zig +++ b/src/particles.zig @@ -315,7 +315,7 @@ pub const ParticleSystem = struct { .pos = @as(Vec3f, @floatCast(pos - previousPlayerPos)), .rot = rot, .typ = typ, - .loopRatio = lifeTime / if (particleType.loopTime) |l| l.get(&main.seed) else 1, + .loopRatio = lifeTime/if (particleType.loopTime) |l| l.get(&main.seed) else 1, }; particlesLocal[particleCount] = ParticleLocal{ .velAndRotationVel = vec.combine(vel, rotVel), From f968396ffd7be1f7395aca7a228c6f654448fc4e Mon Sep 17 00:00:00 2001 From: mnhs Date: Fri, 10 Jul 2026 18:05:34 +0200 Subject: [PATCH 3/6] improved memory usage --- assets/cubyz/shaders/particles/particles.vert | 5 ++--- src/particles.zig | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/cubyz/shaders/particles/particles.vert b/assets/cubyz/shaders/particles/particles.vert index f00e9953be..3f52ecc86e 100644 --- a/assets/cubyz/shaders/particles/particles.vert +++ b/assets/cubyz/shaders/particles/particles.vert @@ -11,7 +11,6 @@ struct ParticleData { vec3 pos; float rotation; float lifeRatio; - float loopRatio; uint light; uint type; }; @@ -21,7 +20,7 @@ layout(std430, binding = 13) restrict readonly buffer _particleData }; struct ParticleTypeData { - float animationFrames; + float frameCount; float startFrame; float size; }; @@ -82,6 +81,6 @@ void main() { const vec3 vertexPos = (billboardMatrix*vec4(particleType.size*vertexRotationPos, 1)).xyz + particle.pos; gl_Position = projectionAndViewMatrix*vec4(vertexPos, 1); - float textureIndex = floor(mod(particle.lifeRatio*particle.loopRatio*particleType.animationFrames, particleType.animationFrames) + particleType.startFrame); + float textureIndex = floor(mod(particle.lifeRatio*particleType.frameCount, particleType.frameCount) + particleType.startFrame); textureCoords = vec3(uvPositions[vertexID], textureIndex); } diff --git a/src/particles.zig b/src/particles.zig index ac5d88fa26..92f60f758f 100644 --- a/src/particles.zig +++ b/src/particles.zig @@ -307,20 +307,22 @@ pub const ParticleSystem = struct { fn addParticle(typ: u32, particleType: ParticleTypeLocal, pos: Vec3d, vel: Vec3f, collides: bool, properties: EmitterProperties) void { const lifeTime = properties.lifeTime.get(&main.seed); + if (lifeTime == 0) return; const density = particleType.density.get(&main.seed); const rot = if (properties.randomizeRotation) random.nextFloat(&main.seed)*std.math.pi*2 else 0; const rotVel = particleType.rotVel.get(&main.seed); const dragCoeff = particleType.dragCoefficient.get(&main.seed); + const loopTime = lifeTime/if (particleType.loopTime) |l| l.get(&main.seed) else lifeTime; particles[particleCount] = Particle{ .pos = @as(Vec3f, @floatCast(pos - @as(Vec3d, @floatFromInt(previousPlayerPos)))), .rot = rot, .typ = typ, - .loopRatio = lifeTime/if (particleType.loopTime) |l| l.get(&main.seed) else 1, + .lifeRatio = loopTime, }; particlesLocal[particleCount] = ParticleLocal{ .velAndRotationVel = vec.combine(vel, rotVel), - .lifeVelocity = 1/lifeTime, + .lifeVelocity = 1/lifeTime*loopTime, .density = density, .dragCoefficient = dragCoeff, .collides = collides, @@ -561,7 +563,6 @@ pub const Particle = extern struct { pos: [3]f32 align(16), rot: f32 = 0, lifeRatio: f32 = 1, - loopRatio: f32 = 1, light: u32 = 0, typ: u32, }; From c4cac11a986e0055c61a0b65b04a6de40b295e24 Mon Sep 17 00:00:00 2001 From: mnhs Date: Sat, 11 Jul 2026 11:35:26 +0200 Subject: [PATCH 4/6] renaming --- assets/cubyz/shaders/particles/particles.vert | 4 +-- src/particles.zig | 34 +++++++++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/assets/cubyz/shaders/particles/particles.vert b/assets/cubyz/shaders/particles/particles.vert index 3f52ecc86e..df926a44ee 100644 --- a/assets/cubyz/shaders/particles/particles.vert +++ b/assets/cubyz/shaders/particles/particles.vert @@ -10,7 +10,7 @@ layout(location = 2) uniform mat4 billboardMatrix; struct ParticleData { vec3 pos; float rotation; - float lifeRatio; + float currentFrame; uint light; uint type; }; @@ -81,6 +81,6 @@ void main() { const vec3 vertexPos = (billboardMatrix*vec4(particleType.size*vertexRotationPos, 1)).xyz + particle.pos; gl_Position = projectionAndViewMatrix*vec4(vertexPos, 1); - float textureIndex = floor(mod(particle.lifeRatio*particleType.frameCount, particleType.frameCount) + particleType.startFrame); + float textureIndex = floor(mod(particle.currentFrame, particleType.frameCount) + particleType.startFrame); textureCoords = vec3(uvPositions[vertexID], textureIndex); } diff --git a/src/particles.zig b/src/particles.zig index 92f60f758f..943ec5fa8b 100644 --- a/src/particles.zig +++ b/src/particles.zig @@ -226,8 +226,8 @@ pub const ParticleSystem = struct { while (i < particleCount) { const particle = &particles[i]; const particleLocal = &particlesLocal[i]; - particle.lifeRatio -= particleLocal.lifeVelocity*deltaTime; - if (particle.lifeRatio < 0) { + particle.currentFrame -= particleLocal.frameRate*deltaTime; + if (particle.currentFrame < 0) { particleCount -= 1; particles[i] = particles[particleCount]; particlesLocal[i] = particlesLocal[particleCount]; @@ -305,24 +305,24 @@ pub const ParticleSystem = struct { previousPlayerPos = playerPosInt; } - fn addParticle(typ: u32, particleType: ParticleTypeLocal, pos: Vec3d, vel: Vec3f, collides: bool, properties: EmitterProperties) void { + fn addParticle(typ: u32, particleTypeLocal: ParticleTypeLocal, particleType: ParticleType, pos: Vec3d, vel: Vec3f, collides: bool, properties: EmitterProperties) void { const lifeTime = properties.lifeTime.get(&main.seed); if (lifeTime == 0) return; - const density = particleType.density.get(&main.seed); + const density = particleTypeLocal.density.get(&main.seed); const rot = if (properties.randomizeRotation) random.nextFloat(&main.seed)*std.math.pi*2 else 0; - const rotVel = particleType.rotVel.get(&main.seed); - const dragCoeff = particleType.dragCoefficient.get(&main.seed); + const rotVel = particleTypeLocal.rotVel.get(&main.seed); + const dragCoeff = particleTypeLocal.dragCoefficient.get(&main.seed); - const loopTime = lifeTime/if (particleType.loopTime) |l| l.get(&main.seed) else lifeTime; + const loopTime = lifeTime/if (particleTypeLocal.loopTime) |l| l.get(&main.seed) else lifeTime; particles[particleCount] = Particle{ .pos = @as(Vec3f, @floatCast(pos - @as(Vec3d, @floatFromInt(previousPlayerPos)))), .rot = rot, .typ = typ, - .lifeRatio = loopTime, + .currentFrame = loopTime*particleType.frameCount, }; particlesLocal[particleCount] = ParticleLocal{ .velAndRotationVel = vec.combine(vel, rotVel), - .lifeVelocity = 1/lifeTime*loopTime, + .frameRate = 1/lifeTime*loopTime*particleType.frameCount, .density = density, .dragCoefficient = dragCoeff, .collides = collides, @@ -404,7 +404,8 @@ pub const DirectionMode = union(enum) { pub const Emitter = struct { typ: u16 = 0, - particleType: ParticleTypeLocal, + particleTypeLocal: ParticleTypeLocal, + particleType: ParticleType, collides: bool, spawnShape: SpawnShape, properties: EmitterProperties, @@ -507,7 +508,8 @@ pub const Emitter = struct { return Emitter{ .typ = typ, - .particleType = ParticleManager.typesLocal.items[typ], + .particleTypeLocal = ParticleManager.typesLocal.items[typ], + .particleType = ParticleManager.types.items[typ], .collides = collides, .spawnShape = spawnShape, .properties = properties, @@ -528,7 +530,8 @@ pub const Emitter = struct { return Emitter{ .typ = typ, - .particleType = ParticleManager.typesLocal.items[typ], + .particleTypeLocal = ParticleManager.typesLocal.items[typ], + .particleType = ParticleManager.types.items[typ], .collides = collides, .spawnShape = spawnShape, .properties = EmitterProperties.parse(zon), @@ -541,7 +544,7 @@ pub const Emitter = struct { for (0..count) |_| { const particlePos, const particleVel = self.spawnShape.spawn(pos, self.properties, self.mode); - ParticleSystem.addParticle(self.typ, self.particleType, particlePos, particleVel, self.collides, self.properties); + ParticleSystem.addParticle(self.typ, self.particleTypeLocal, self.particleType, particlePos, particleVel, self.collides, self.properties); } } }; @@ -562,14 +565,15 @@ pub const ParticleTypeLocal = struct { pub const Particle = extern struct { pos: [3]f32 align(16), rot: f32 = 0, - lifeRatio: f32 = 1, + currentFrame: f32 = 1, light: u32 = 0, typ: u32, + // 4 bytes left for use }; pub const ParticleLocal = struct { velAndRotationVel: Vec4f, - lifeVelocity: f32, + frameRate: f32, density: f32, dragCoefficient: f32, collides: bool, From cfd351c1885dc2bf2ccff4d0a53f073d467827e9 Mon Sep 17 00:00:00 2001 From: mnhs Date: Sat, 11 Jul 2026 14:23:33 +0200 Subject: [PATCH 5/6] wip --- assets/cubyz/blocks/torch.zig.zon | 6 +++++ assets/cubyz/particles/flame.zig.zon | 2 +- src/blocks.zig | 11 ++++++++ src/callbacks/block/client/_list.zig | 1 + .../block/client/torch_update_particles.zig | 25 +++++++++++++++++++ src/game.zig | 24 ++++++++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/callbacks/block/client/torch_update_particles.zig diff --git a/assets/cubyz/blocks/torch.zig.zon b/assets/cubyz/blocks/torch.zig.zon index 2ad108c8d8..aece574d97 100644 --- a/assets/cubyz/blocks/torch.zig.zon +++ b/assets/cubyz/blocks/torch.zig.zon @@ -13,6 +13,12 @@ .onUpdate = .{ .type = .check_support_blocks, }, + .onInteract = .{ + .type = .torch_update_particles, + }, + .onClientUpdate = .{ + .type = .torch_update_particles, + }, .model = .{ .base = "cubyz:torch", .side = "cubyz:torch_side", diff --git a/assets/cubyz/particles/flame.zig.zon b/assets/cubyz/particles/flame.zig.zon index b5a0c4fbce..cbcf712ea0 100644 --- a/assets/cubyz/particles/flame.zig.zon +++ b/assets/cubyz/particles/flame.zig.zon @@ -1,6 +1,6 @@ .{ .texture = "cubyz:flame", .density = .{0.00065, 0.00085}, - .rotationVelocity = .{20, 35}, + .rotationVelocity = .{5, 10}, .dragCoefficient = .{0.2, 0.3}, } diff --git a/src/blocks.zig b/src/blocks.zig index 4ac584866f..ff2e723976 100644 --- a/src/blocks.zig +++ b/src/blocks.zig @@ -155,6 +155,7 @@ var _mobility: [maxBlockCount]f32 = undefined; var _allowOres: [maxBlockCount]bool = undefined; var _onTick: [maxBlockCount]ServerBlockCallback = undefined; var _onTouch: [maxBlockCount]BlockTouchCallback = undefined; +var _onClientUpdate: [maxBlockCount]ClientBlockCallback = undefined; var _blockEntity: [maxBlockCount]?*const BlockEntityType = undefined; var reverseIndices: std.StringHashMapUnmanaged(u16) = .{}; @@ -329,6 +330,12 @@ fn registerCallbacks(typ: u16, zon: ZonElement) void { break :blk .noop; }; }; + _onClientUpdate[typ] = blk: { + break :blk ClientBlockCallback.init(zon.getChildOrNull("onClientUpdate") orelse break :blk .noop, .{.block = .{.typ = typ, .data = 0}}) orelse { + std.log.err("Failed to load onClientUpdate event for block {s}", .{_id[typ]}); + break :blk .noop; + }; + }; } pub fn finishBlocks(zonElements: Assets.ZonHashMap) void { @@ -569,6 +576,10 @@ pub const Block = packed struct(u32) { // MARK: Block return _onTouch[self.typ]; } + pub inline fn onClientUpdate(self: Block) ClientBlockCallback { + return _onClientUpdate[self.typ]; + } + pub fn blockEntity(self: Block) ?*const BlockEntityType { return _blockEntity[self.typ]; } diff --git a/src/callbacks/block/client/_list.zig b/src/callbacks/block/client/_list.zig index 9a77fb7eb6..16ea67c5ca 100644 --- a/src/callbacks/block/client/_list.zig +++ b/src/callbacks/block/client/_list.zig @@ -1,3 +1,4 @@ pub const edit_sign = @import("edit_sign.zig"); pub const open_chest = @import("open_chest.zig"); pub const open_window = @import("open_window.zig"); +pub const torch_update_particles = @import("torch_update_particles.zig"); diff --git a/src/callbacks/block/client/torch_update_particles.zig b/src/callbacks/block/client/torch_update_particles.zig new file mode 100644 index 0000000000..dfd28b22fe --- /dev/null +++ b/src/callbacks/block/client/torch_update_particles.zig @@ -0,0 +1,25 @@ +const std = @import("std"); + +const main = @import("main"); +const Block = main.blocks.Block; +const vec = main.vec; +const Vec3i = vec.Vec3i; +const ZonElement = main.ZonElement; +const particles = main.particles; + + +pub fn init(_: ZonElement, _: main.callbacks.Creator) ?*anyopaque { + return @as(*anyopaque, undefined); +} + +pub fn run(_: *anyopaque, params: main.callbacks.ClientBlockCallback.Params) main.callbacks.Result { + var emitter: particles.Emitter = undefined; + const emitterProperties = particles.EmitterProperties{ + .speed = .init(0.15, 0.2), + .lifeTime = .init(0.25, 0.5), + .randomizeRotation = false, + }; + emitter = .init("cubyz:flame", false, .{.point = .{}}, emitterProperties, .spread); + emitter.spawnParticles(@as(vec.Vec3f, @floatFromInt(params.blockPos)) + vec.Vec3f{0.5, 0.5, 0.85}, 1); + return .handled; +} diff --git a/src/game.zig b/src/game.zig index dcb7edd8e1..b235a114c5 100644 --- a/src/game.zig +++ b/src/game.zig @@ -379,6 +379,30 @@ pub const World = struct { // MARK: World } network.protocols.playerPosition.send(self.conn, Player.getPosBlocking(), Player.getVelBlocking(), @intCast(newTime & 65535)); self.dayTime.update(deltaTime); + updateRandomTickBlocks(self, deltaTime); + } + + pub fn updateRandomTickBlocks(_: *World, _: f64) void { + const chunkRadius = 3; + const blockPos: Vec3i = @intFromFloat(@floor(Player.getPosBlocking())); + const mesh = main.renderer.mesh_storage.getMesh(.initFromWorldPos(blockPos, 1)) orelse return; + for (0..chunkRadius) |cx| { + for (0..chunkRadius) |cy| { + for (0..chunkRadius) |cz| { + + } + } + } + for (0..20) |_| { + const curBlockPos = Vec3i{ + main.random.nextIntBounded(i32, &main.seed, 32), + main.random.nextIntBounded(i32, &main.seed, 32), + main.random.nextIntBounded(i32, &main.seed, 32) + }; + const block = mesh.chunk.getBlock(curBlockPos[0], curBlockPos[1], curBlockPos[2]); + const onClientUpdate = block.onClientUpdate(); + if (onClientUpdate.run(.{.blockPos = curBlockPos + Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz}, .block = block, .chunk = mesh.chunk}) == .handled) continue; + } } pub const DayTime = struct { // MARK: DayTime From cc8589bfe8ed4a6c4ab2ef8e485fc136328f123b Mon Sep 17 00:00:00 2001 From: mnhs Date: Sun, 19 Jul 2026 21:05:59 +0200 Subject: [PATCH 6/6] add chunk radius and limit tickrate --- src/game.zig | 47 ++++++++++++++++++++++++------------ src/gui/windows/graphics.zig | 8 ++++++ src/settings.zig | 2 ++ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/game.zig b/src/game.zig index b235a114c5..c6540b7ff9 100644 --- a/src/game.zig +++ b/src/game.zig @@ -280,6 +280,7 @@ pub const World = struct { // MARK: World entityComponentPalette: *assets.Palette = undefined, itemDrops: ClientItemDropManager = undefined, playerBiome: Atomic(*const main.server.terrain.biomes.Biome) = undefined, + randomTicksTime: f64 = 0, pub fn init(self: *World, ip: []const u8, manager: *ConnectionManager) !void { main.heap.allocators.createWorldArena(); @@ -379,30 +380,44 @@ pub const World = struct { // MARK: World } network.protocols.playerPosition.send(self.conn, Player.getPosBlocking(), Player.getVelBlocking(), @intCast(newTime & 65535)); self.dayTime.update(deltaTime); - updateRandomTickBlocks(self, deltaTime); + + self.randomTicksTime += deltaTime; + const tickrate: f32 = 1.0/20.0; + if (self.randomTicksTime >= tickrate) { + updateRandomTickBlocks(self); + self.randomTicksTime = 0; + } } - pub fn updateRandomTickBlocks(_: *World, _: f64) void { - const chunkRadius = 3; - const blockPos: Vec3i = @intFromFloat(@floor(Player.getPosBlocking())); - const mesh = main.renderer.mesh_storage.getMesh(.initFromWorldPos(blockPos, 1)) orelse return; + pub fn updateRandomTickBlocks(_: *World) void { + const chunkRadius = settings.visualRandomTickRadius; + const playerBlockPos: Vec3i = @intFromFloat(@floor(Player.getPosBlocking())); + const thing: i32 = @intCast(if (@mod(chunkRadius, 2) == 0) @divFloor(chunkRadius, 2) else @divFloor(chunkRadius - 1, 2)); for (0..chunkRadius) |cx| { for (0..chunkRadius) |cy| { for (0..chunkRadius) |cz| { - + const chunkMultiplierPos: Vec3i = playerBlockPos +% @as(Vec3i, @splat(32))*Vec3i{ + @as(i32, @intCast(cx)) - thing, + @as(i32, @intCast(cy)) - thing, + @as(i32, @intCast(cz)) - thing + }; + const chunkMesh = main.renderer.mesh_storage.getMesh(.initFromWorldPos(chunkMultiplierPos, 1)); + + if (chunkMesh) |mesh| { + for (0..20) |_| { + const curBlockPos = Vec3i{ + main.random.nextIntBounded(i32, &main.seed, 32), + main.random.nextIntBounded(i32, &main.seed, 32), + main.random.nextIntBounded(i32, &main.seed, 32) + }; + const block = mesh.chunk.getBlock(curBlockPos[0], curBlockPos[1], curBlockPos[2]); + const onClientUpdate = block.onClientUpdate(); + if (onClientUpdate.run(.{.blockPos = curBlockPos + Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz}, .block = block, .chunk = mesh.chunk}) == .handled) continue; + } + } } } } - for (0..20) |_| { - const curBlockPos = Vec3i{ - main.random.nextIntBounded(i32, &main.seed, 32), - main.random.nextIntBounded(i32, &main.seed, 32), - main.random.nextIntBounded(i32, &main.seed, 32) - }; - const block = mesh.chunk.getBlock(curBlockPos[0], curBlockPos[1], curBlockPos[2]); - const onClientUpdate = block.onClientUpdate(); - if (onClientUpdate.run(.{.blockPos = curBlockPos + Vec3i{mesh.pos.wx, mesh.pos.wy, mesh.pos.wz}, .block = block, .chunk = mesh.chunk}) == .handled) continue; - } } pub const DayTime = struct { // MARK: DayTime diff --git a/src/gui/windows/graphics.zig b/src/gui/windows/graphics.zig index f84818a1f8..d14fb731cf 100644 --- a/src/gui/windows/graphics.zig +++ b/src/gui/windows/graphics.zig @@ -38,6 +38,8 @@ const fpsPresetsText = blk: { break :blk strings; }; +const visualRandomTickRadius = [_]u8{1, 2, 3, 4, 5, 6}; + fn fpsCapGetIndex(fpsOptional: ?u32) u16 { const fps: u16 = @truncate(fpsOptional orelse return fpsPresetsValue.len); return @intCast(std.sort.lowerBound(u16, &fpsPresetsValue, fps, struct { @@ -128,6 +130,11 @@ fn resolutionScaleCallback(newValue: u16) void { main.Window.GLFWCallbacks.framebufferSize(null, main.Window.width, main.Window.height); } +fn visualRandomTickRadiusCallback(newValue: u16) void { + settings.visualRandomTickRadius = newValue; + settings.save(); +} + pub fn onOpen() void { const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffFPS Limit:\n", "{s}", &fpsPresetsText, fpsCapGetIndex(settings.fpsCap), &fpsCapCallback)); @@ -151,6 +158,7 @@ pub fn onOpen() void { else => 2, }, &anisotropicFilteringCallback)); list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffResolution Scale: ", "{}%", &resolutions, @as(u16, @trunc(@log2(settings.resolutionScale) + 2.0)), &resolutionScaleCallback)); + list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffVisual random tick radius: ", "{} chunks", &visualRandomTickRadius, settings.visualRandomTickRadius, &visualRandomTickRadiusCallback)); list.finish(.center); window.rootComponent = list.toComponent(); window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); diff --git a/src/settings.zig b/src/settings.zig index 2cf4ddde27..fe6fdbfb79 100644 --- a/src/settings.zig +++ b/src/settings.zig @@ -71,6 +71,8 @@ pub var updateRepeatDelay: std.Io.Duration = .fromMilliseconds(500); pub var controllerAxisDeadzone: f32 = 0.2; +pub var visualRandomTickRadius: u16 = 5; + const settingsFile = if (builtin.mode == .Debug) "debug_settings.zig.zon" else "settings.zig.zon"; pub fn init() void {