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
This commit is contained in:
IntegratedQuantum 2025-04-20 17:42:04 +02:00
parent 4286455915
commit 176c9d4c75
13 changed files with 46 additions and 72 deletions

View File

@ -1,4 +1,5 @@
.{
.tags = .{.metal},
.texture = "copper_ingot.png",
.material = .{
.density = 5.0,

View File

@ -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,
},
},
},
},
}

View File

@ -1,4 +1,5 @@
.{
.tags = .{.metal, .precious},
.texture = "gold_ingot.png",
.material = .{
.density = 19.5,

View File

@ -1,4 +1,5 @@
.{
.tags = .{.metal},
.texture = "iron_ingot.png",
.material = .{
.density = 7.5,

View File

@ -1,4 +1,5 @@
.{
.tags = .{.metal, .precious},
.texture = "silver_ingot.png",
.material = .{
.density = 10.5,

View File

@ -1,4 +1,5 @@
.{
.tags = .{.metal},
.texture = "uranium_ingot.png",
.material = .{
.density = 18,

View File

@ -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| {

View File

@ -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];
}

View File

@ -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,

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;