From 176c9d4c750633ceaac888d2165ffc395052bf68 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 20 Apr 2025 17:42:04 +0200 Subject: [PATCH] Introduce item tags and generalize the tag system All tags now share the same index space, I don't see a reason why we should have separate spaces for these. I also made diamond powerful if encased in gold/silver --- assets/cubyz/items/copper_ingot.zig.zon | 1 + assets/cubyz/items/diamond.zig.zon | 25 +++++---- assets/cubyz/items/gold_ingot.zig.zon | 1 + assets/cubyz/items/iron_ingot.zig.zon | 1 + assets/cubyz/items/silver_ingot.zig.zon | 1 + assets/cubyz/items/uranium_ingot.zig.zon | 1 + src/assets.zig | 1 + src/blocks.zig | 57 +++------------------ src/items.zig | 14 ++++- src/main.zig | 5 ++ src/tool/modifiers/bad_at.zig | 2 +- src/tool/modifiers/good_at.zig | 2 +- src/tool/modifiers/restrictions/encased.zig | 7 ++- 13 files changed, 46 insertions(+), 72 deletions(-) diff --git a/assets/cubyz/items/copper_ingot.zig.zon b/assets/cubyz/items/copper_ingot.zig.zon index 67da98f1..9b8e9ac4 100644 --- a/assets/cubyz/items/copper_ingot.zig.zon +++ b/assets/cubyz/items/copper_ingot.zig.zon @@ -1,4 +1,5 @@ .{ + .tags = .{.metal}, .texture = "copper_ingot.png", .material = .{ .density = 5.0, diff --git a/assets/cubyz/items/diamond.zig.zon b/assets/cubyz/items/diamond.zig.zon index 1f94f34e..b6284104 100644 --- a/assets/cubyz/items/diamond.zig.zon +++ b/assets/cubyz/items/diamond.zig.zon @@ -17,22 +17,21 @@ .restriction = .{ .id = .not, .child = .{ - .id = "or", - .children = .{ - .{ - .id = .encased, - .item = "cubyz:gold_ingot", - .amount = 5, - }, - .{ - .id = .encased, - .item = "cubyz:silver_ingot", - .amount = 5, - }, - }, + .id = .encased, + .tag = .precious, + .amount = 6, }, }, }, + .{ + .id = "powerful", + .strength = 0.5, + .restriction = .{ + .id = .encased, + .tag = .precious, + .amount = 6, + }, + }, }, }, } diff --git a/assets/cubyz/items/gold_ingot.zig.zon b/assets/cubyz/items/gold_ingot.zig.zon index b434f057..eb3dc9ca 100644 --- a/assets/cubyz/items/gold_ingot.zig.zon +++ b/assets/cubyz/items/gold_ingot.zig.zon @@ -1,4 +1,5 @@ .{ + .tags = .{.metal, .precious}, .texture = "gold_ingot.png", .material = .{ .density = 19.5, diff --git a/assets/cubyz/items/iron_ingot.zig.zon b/assets/cubyz/items/iron_ingot.zig.zon index 12bfa2dd..152a089d 100644 --- a/assets/cubyz/items/iron_ingot.zig.zon +++ b/assets/cubyz/items/iron_ingot.zig.zon @@ -1,4 +1,5 @@ .{ + .tags = .{.metal}, .texture = "iron_ingot.png", .material = .{ .density = 7.5, diff --git a/assets/cubyz/items/silver_ingot.zig.zon b/assets/cubyz/items/silver_ingot.zig.zon index 9f8324d6..4cc8e310 100644 --- a/assets/cubyz/items/silver_ingot.zig.zon +++ b/assets/cubyz/items/silver_ingot.zig.zon @@ -1,4 +1,5 @@ .{ + .tags = .{.metal, .precious}, .texture = "silver_ingot.png", .material = .{ .density = 10.5, diff --git a/assets/cubyz/items/uranium_ingot.zig.zon b/assets/cubyz/items/uranium_ingot.zig.zon index f8048cf0..f83f8069 100644 --- a/assets/cubyz/items/uranium_ingot.zig.zon +++ b/assets/cubyz/items/uranium_ingot.zig.zon @@ -1,4 +1,5 @@ .{ + .tags = .{.metal}, .texture = "uranium_ingot.png", .material = .{ .density = 18, diff --git a/src/assets.zig b/src/assets.zig index 77e7a5fe..4d7efc74 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -655,6 +655,7 @@ pub fn unloadAssets() void { // MARK: unloadAssets() migrations_zig.reset(); main.models.reset(); main.rotation.reset(); + main.Tag.resetTags(); // Remove paths from asset hot reloading: var dir = std.fs.cwd().openDir("assets", .{.iterate = true}) catch |err| { diff --git a/src/blocks.zig b/src/blocks.zig index 1da6ae61..306d7f14 100644 --- a/src/blocks.zig +++ b/src/blocks.zig @@ -1,6 +1,7 @@ const std = @import("std"); const main = @import("main"); +const Tag = main.Tag; const ZonElement = @import("zon.zig").ZonElement; const Neighbor = @import("chunk.zig").Neighbor; const graphics = @import("graphics.zig"); @@ -20,48 +21,6 @@ const entity_data = @import("entity_data.zig"); const EntityDataClass = entity_data.EntityDataClass; const sbb = main.server.terrain.structure_building_blocks; -pub const BlockTag = enum(u32) { - air = 0, - fluid = 1, - sbbChild = 2, - _, - - var tagList: main.List([]const u8) = .init(allocator); - var tagIds: std.StringHashMap(BlockTag) = .init(allocator.allocator); - - fn loadDefaults() void { - inline for(comptime std.meta.fieldNames(BlockTag)) |tag| { - std.debug.assert(find(tag) == @field(BlockTag, tag)); - } - } - - fn reset() void { - tagList.clearAndFree(); - tagIds.clearAndFree(); - } - - pub fn find(tag: []const u8) BlockTag { - if(tagIds.get(tag)) |res| return res; - const result: BlockTag = @enumFromInt(tagList.items.len); - const dupedTag = allocator.dupe(u8, tag); - tagList.append(dupedTag); - tagIds.put(dupedTag, result) catch unreachable; - return result; - } - - pub fn loadFromZon(_allocator: main.heap.NeverFailingAllocator, zon: ZonElement) []BlockTag { - const result = _allocator.alloc(BlockTag, zon.toSlice().len); - for(zon.toSlice(), 0..) |tagZon, i| { - result[i] = BlockTag.find(tagZon.as([]const u8, "incorrect")); - } - return result; - } - - pub fn getName(tag: BlockTag) []const u8 { - return tagList.items[@intFromEnum(tag)]; - } -}; - var arena = main.heap.NeverFailingArenaAllocator.init(main.globalAllocator); const allocator = arena.allocator(); @@ -103,7 +62,7 @@ var _degradable: [maxBlockCount]bool = undefined; var _viewThrough: [maxBlockCount]bool = undefined; var _alwaysViewThrough: [maxBlockCount]bool = undefined; var _hasBackFace: [maxBlockCount]bool = undefined; -var _blockTags: [maxBlockCount][]BlockTag = undefined; +var _blockTags: [maxBlockCount][]Tag = undefined; var _light: [maxBlockCount]u32 = undefined; /// How much light this block absorbs if it is transparent var _absorption: [maxBlockCount]u32 = undefined; @@ -124,9 +83,7 @@ var size: u32 = 0; pub var ores: main.List(Ore) = .init(allocator); -pub fn init() void { - BlockTag.loadDefaults(); -} +pub fn init() void {} pub fn deinit() void { arena.deinit(); @@ -143,10 +100,10 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 { _blockHealth[size] = zon.get(f32, "blockHealth", 1); _blockResistance[size] = zon.get(f32, "blockResistance", 0); - _blockTags[size] = BlockTag.loadFromZon(allocator, zon.getChild("tags")); + _blockTags[size] = Tag.loadTagsFromZon(allocator, zon.getChild("tags")); if(_blockTags[size].len == 0) std.log.err("Block {s} is missing 'tags' field", .{id}); for(_blockTags[size]) |tag| { - if(tag == BlockTag.sbbChild) { + if(tag == Tag.sbbChild) { sbb.registerChildBlock(@intCast(size), _id[size]); break; } @@ -254,10 +211,8 @@ pub fn reset() void { size = 0; ores.clearAndFree(); meshes.reset(); - BlockTag.reset(); _ = arena.reset(.free_all); reverseIndices = .init(arena.allocator().allocator); - BlockTag.loadDefaults(); } pub fn getTypeById(id: []const u8) u16 { @@ -353,7 +308,7 @@ pub const Block = packed struct { // MARK: Block return _hasBackFace[self.typ]; } - pub inline fn blockTags(self: Block) []const BlockTag { + pub inline fn blockTags(self: Block) []const Tag { return _blockTags[self.typ]; } diff --git a/src/items.zig b/src/items.zig index c62ee3c7..83cb57d4 100644 --- a/src/items.zig +++ b/src/items.zig @@ -4,6 +4,7 @@ const blocks = @import("blocks.zig"); const Block = blocks.Block; const graphics = @import("graphics.zig"); const Color = graphics.Color; +const Tag = main.Tag; const ZonElement = @import("zon.zig").ZonElement; const main = @import("main"); const chunk = main.chunk; @@ -168,6 +169,7 @@ pub const BaseItem = struct { // MARK: BaseItem texture: ?graphics.Texture, // TODO: Properly deinit id: []const u8, name: []const u8, + tags: []const Tag, stackSize: u16, material: ?Material, @@ -196,6 +198,7 @@ pub const BaseItem = struct { // MARK: BaseItem }; } self.name = allocator.dupe(u8, zon.get([]const u8, "name", id)); + self.tags = Tag.loadTagsFromZon(allocator, zon.getChild("tags")); self.stackSize = zon.get(u16, "stackSize", 120); const material = zon.getChild("material"); if(material == .object) { @@ -239,6 +242,13 @@ pub const BaseItem = struct { // MARK: BaseItem fn getTooltip(self: BaseItem) []const u8 { return self.name; } + + pub fn hasTag(self: *const BaseItem, tag: Tag) bool { + for(self.tags) |other| { + if(other == tag) return true; + } + return false; + } }; ///Generates the texture of a Tool using the material information. @@ -420,7 +430,7 @@ const FunctionType = enum { pub const ToolType = struct { // MARK: ToolType id: []const u8, - blockTags: []main.blocks.BlockTag, + blockTags: []main.Tag, slotInfos: [25]SlotInfo, pixelSources: [16][16]u8, pixelSourcesOverlay: [16][16]u8, @@ -927,7 +937,7 @@ pub fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) vo const idDupe = arena.allocator().dupe(u8, id); toolTypes.put(idDupe, .{ .id = idDupe, - .blockTags = main.blocks.BlockTag.loadFromZon(arena.allocator(), zon.getChild("blockTags")), + .blockTags = Tag.loadTagsFromZon(arena.allocator(), zon.getChild("blockTags")), .slotInfos = slotInfos, .pixelSources = pixelSources, .pixelSourcesOverlay = pixelSourcesOverlay, diff --git a/src/main.zig b/src/main.zig index 10988c52..938a79f0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -23,6 +23,8 @@ pub const random = @import("random.zig"); pub const renderer = @import("renderer.zig"); pub const rotation = @import("rotation.zig"); pub const settings = @import("settings.zig"); +const tag = @import("tag.zig"); +pub const Tag = tag.Tag; pub const utils = @import("utils.zig"); pub const vec = @import("vec.zig"); pub const ZonElement = @import("zon.zig").ZonElement; @@ -618,6 +620,9 @@ pub fn main() void { // MARK: main() itemdrop.ItemDropRenderer.init(); defer itemdrop.ItemDropRenderer.deinit(); + tag.init(); + defer tag.deinit(); + assets.init(); defer assets.deinit(); diff --git a/src/tool/modifiers/bad_at.zig b/src/tool/modifiers/bad_at.zig index 27732642..7262ebe3 100644 --- a/src/tool/modifiers/bad_at.zig +++ b/src/tool/modifiers/bad_at.zig @@ -3,7 +3,7 @@ const std = @import("std"); const main = @import("main"); const Tool = main.items.Tool; -pub const Data = packed struct(u128) {strength: f32, tag: main.blocks.BlockTag, pad: u64 = undefined}; +pub const Data = packed struct(u128) {strength: f32, tag: main.Tag, pad: u64 = undefined}; pub const priority = 1; diff --git a/src/tool/modifiers/good_at.zig b/src/tool/modifiers/good_at.zig index 5044ab65..f1e9f96f 100644 --- a/src/tool/modifiers/good_at.zig +++ b/src/tool/modifiers/good_at.zig @@ -3,7 +3,7 @@ const std = @import("std"); const main = @import("main"); const Tool = main.items.Tool; -pub const Data = packed struct(u128) {strength: f32, tag: main.blocks.BlockTag, pad: u64 = undefined}; +pub const Data = packed struct(u128) {strength: f32, tag: main.Tag, pad: u64 = undefined}; pub const priority = 1; diff --git a/src/tool/modifiers/restrictions/encased.zig b/src/tool/modifiers/restrictions/encased.zig index 3e2c5c84..5cd42db7 100644 --- a/src/tool/modifiers/restrictions/encased.zig +++ b/src/tool/modifiers/restrictions/encased.zig @@ -7,7 +7,7 @@ const Tool = main.items.Tool; const ZonElement = main.ZonElement; const Encased = struct { - item: []const u8, // TODO: Use item tags instead + tag: main.Tag, amount: usize, }; @@ -15,17 +15,16 @@ pub fn satisfied(self: *const Encased, tool: *const Tool, x: i32, y: i32) bool { var count: usize = 0; for([_]i32{-1, 0, 1}) |dx| { for([_]i32{-1, 0, 1}) |dy| { - if(std.mem.eql(u8, (tool.getItemAt(x + dx, y + dy) orelse continue).id, self.item)) count += 1; + if((tool.getItemAt(x + dx, y + dy) orelse continue).hasTag(self.tag)) count += 1; } } - std.log.debug("{} {}", .{count, self.amount}); return count >= self.amount; } pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const Encased { const result = allocator.create(Encased); result.* = .{ - .item = zon.get([]const u8, "item", "not specified"), + .tag = main.Tag.find(zon.get([]const u8, "tag", "not specified")), .amount = zon.get(usize, "amount", 8), }; return result;