Implement basic modifier restrictions with an example for diamond.

Still needs tooltips and item tags to be more useful
This commit is contained in:
IntegratedQuantum 2025-04-20 13:57:05 +02:00
parent 5f54d48a73
commit 4286455915
8 changed files with 196 additions and 1 deletions

View File

@ -14,6 +14,24 @@
.{ .{
.id = "fragile", .id = "fragile",
.strength = 0.5, .strength = 0.5,
.restriction = .{
.id = .not,
.child = .{
.id = "or",
.children = .{
.{
.id = .encased,
.item = "cubyz:gold_ingot",
.amount = 5,
},
.{
.id = .encased,
.item = "cubyz:silver_ingot",
.amount = 5,
},
},
},
},
}, },
}, },
}, },

View File

@ -17,6 +17,7 @@ const Vec3f = vec.Vec3f;
const NeverFailingAllocator = main.heap.NeverFailingAllocator; const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const modifierList = @import("tool/modifiers/_list.zig"); const modifierList = @import("tool/modifiers/_list.zig");
const modifierRestrictionList = @import("tool/modifiers/restrictions/_list.zig");
pub const Inventory = @import("Inventory.zig"); pub const Inventory = @import("Inventory.zig");
@ -54,12 +55,13 @@ const Material = struct { // MARK: Material
for(modifiersZon.toSlice(), self.modifiers) |item, *modifier| { for(modifiersZon.toSlice(), self.modifiers) |item, *modifier| {
const id = item.get([]const u8, "id", "not specified"); const id = item.get([]const u8, "id", "not specified");
const vTable = modifiers.get(id) orelse blk: { const vTable = modifiers.get(id) orelse blk: {
std.log.err("Couldn't find modifier with id {s}. Replacing it with 'Durable'", .{id}); std.log.err("Couldn't find modifier with id '{s}'. Replacing it with 'durable'", .{id});
break :blk modifiers.get("durable") orelse unreachable; break :blk modifiers.get("durable") orelse unreachable;
}; };
modifier.* = .{ modifier.* = .{
.vTable = vTable, .vTable = vTable,
.data = vTable.loadData(item), .data = vTable.loadData(item),
.restriction = ModifierRestriction.loadFromZon(allocator, item.getChild("restriction")),
}; };
} }
} }
@ -83,8 +85,35 @@ const Material = struct { // MARK: Material
} }
}; };
pub const ModifierRestriction = struct {
vTable: *const VTable,
data: *anyopaque,
pub const VTable = struct {
satisfied: *const fn(data: *anyopaque, tool: *const Tool, x: i32, y: i32) bool,
loadFromZon: *const fn(allocator: NeverFailingAllocator, zon: ZonElement) *anyopaque,
};
pub fn satisfied(self: ModifierRestriction, tool: *const Tool, x: i32, y: i32) bool {
return self.vTable.satisfied(self.data, tool, x, y);
}
pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) ModifierRestriction {
const id = zon.get([]const u8, "id", "always");
const vTable = modifierRestrictions.get(id) orelse blk: {
std.log.err("Couldn't find modifier restriction with id '{s}'. Replacing it with 'always'", .{id});
break :blk modifierRestrictions.get("always") orelse unreachable;
};
return .{
.vTable = vTable,
.data = vTable.loadFromZon(allocator, zon),
};
}
};
const Modifier = struct { const Modifier = struct {
data: VTable.Data, data: VTable.Data,
restriction: ModifierRestriction,
vTable: *const VTable, vTable: *const VTable,
pub const VTable = struct { pub const VTable = struct {
@ -102,6 +131,7 @@ const Modifier = struct {
return .{ return .{
.data = a.vTable.combineModifiers(a.data, b.data) orelse return null, .data = a.vTable.combineModifiers(a.data, b.data) orelse return null,
.vTable = a.vTable, .vTable = a.vTable,
.restriction = undefined,
}; };
} }
@ -319,6 +349,7 @@ const ToolPhysics = struct { // MARK: ToolPhysics
tool.getProperty(set.destination).* += set.factor*set.functionType.eval(material.getProperty(set.source) + set.additionConstant); tool.getProperty(set.destination).* += set.factor*set.functionType.eval(material.getProperty(set.source) + set.additionConstant);
} }
outer: for(material.modifiers) |newMod| { outer: for(material.modifiers) |newMod| {
if(!newMod.restriction.satisfied(tool, @intCast(i%5), @intCast(i/5))) continue;
for(tempModifiers.items) |*oldMod| { for(tempModifiers.items) |*oldMod| {
if(oldMod.vTable == newMod.vTable) { if(oldMod.vTable == newMod.vTable) {
oldMod.* = oldMod.combineModifiers(newMod) orelse continue; oldMod.* = oldMod.combineModifiers(newMod) orelse continue;
@ -537,6 +568,12 @@ pub const Tool = struct { // MARK: Tool
return hash; return hash;
} }
pub fn getItemAt(self: *const Tool, x: i32, y: i32) ?*const BaseItem {
if(x < 0 or x >= 5) return null;
if(y < 0 or y >= 5) return null;
return self.craftingGrid[@intCast(x + y*5)];
}
fn getProperty(self: *Tool, prop: ToolProperty) *f32 { fn getProperty(self: *Tool, prop: ToolProperty) *f32 {
switch(prop) { switch(prop) {
inline else => |field| return &@field(self, @tagName(field)), inline else => |field| return &@field(self, @tagName(field)),
@ -751,6 +788,7 @@ var arena: main.heap.NeverFailingArenaAllocator = undefined;
var toolTypes: std.StringHashMap(ToolType) = undefined; var toolTypes: std.StringHashMap(ToolType) = undefined;
var reverseIndices: std.StringHashMap(*BaseItem) = undefined; var reverseIndices: std.StringHashMap(*BaseItem) = undefined;
var modifiers: std.StringHashMap(*const Modifier.VTable) = undefined; var modifiers: std.StringHashMap(*const Modifier.VTable) = undefined;
var modifierRestrictions: std.StringHashMap(*const ModifierRestriction.VTable) = undefined;
pub var itemList: [65536]BaseItem = undefined; pub var itemList: [65536]BaseItem = undefined;
pub var itemListSize: u16 = 0; pub var itemListSize: u16 = 0;
@ -790,6 +828,14 @@ pub fn globalInit() void {
.priority = ModifierStruct.priority, .priority = ModifierStruct.priority,
}) catch unreachable; }) catch unreachable;
} }
modifierRestrictions = .init(main.globalAllocator.allocator);
inline for(@typeInfo(modifierRestrictionList).@"struct".decls) |decl| {
const ModifierRestrictionStruct = @field(modifierRestrictionList, decl.name);
modifierRestrictions.put(decl.name, &.{
.satisfied = comptime main.utils.castFunctionSelfToAnyopaque(ModifierRestrictionStruct.satisfied),
.loadFromZon = comptime main.utils.castFunctionReturnToAnyopaque(ModifierRestrictionStruct.loadFromZon),
}) catch unreachable;
}
Inventory.Sync.ClientSide.init(); Inventory.Sync.ClientSide.init();
} }
@ -952,6 +998,7 @@ pub fn deinit() void {
} }
recipeList.clearAndFree(); recipeList.clearAndFree();
modifiers.deinit(); modifiers.deinit();
modifierRestrictions.deinit();
arena.deinit(); arena.deinit();
Inventory.Sync.ClientSide.deinit(); Inventory.Sync.ClientSide.deinit();
} }

View File

@ -0,0 +1,5 @@
pub const always = @import("always.zig");
pub const @"and" = @import("and.zig");
pub const encased = @import("encased.zig");
pub const not = @import("not.zig");
pub const @"or" = @import("or.zig");

View File

@ -0,0 +1,14 @@
const std = @import("std");
const main = @import("main");
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const Tool = main.items.Tool;
const ZonElement = main.ZonElement;
pub fn satisfied(_: *const anyopaque, _: *const Tool, _: i32, _: i32) bool {
return true;
}
pub fn loadFromZon(_: NeverFailingAllocator, _: ZonElement) *const anyopaque {
return undefined;
}

View File

@ -0,0 +1,28 @@
const std = @import("std");
const main = @import("main");
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const ModifierRestriction = main.items.ModifierRestriction;
const Tool = main.items.Tool;
const ZonElement = main.ZonElement;
const And = struct {
children: []ModifierRestriction,
};
pub fn satisfied(self: *const And, tool: *const Tool, x: i32, y: i32) bool {
for(self.children) |child| {
if(!child.satisfied(tool, x, y)) return false;
}
return true;
}
pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const And {
const result = allocator.create(And);
const childrenZon = zon.getChild("children").toSlice();
result.children = allocator.alloc(ModifierRestriction, childrenZon.len);
for(result.children, childrenZon) |*child, childZon| {
child.* = ModifierRestriction.loadFromZon(allocator, childZon);
}
return result;
}

View File

@ -0,0 +1,32 @@
const std = @import("std");
const main = @import("main");
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const ModifierRestriction = main.items.ModifierRestriction;
const Tool = main.items.Tool;
const ZonElement = main.ZonElement;
const Encased = struct {
item: []const u8, // TODO: Use item tags instead
amount: usize,
};
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;
}
}
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"),
.amount = zon.get(usize, "amount", 8),
};
return result;
}

View File

@ -0,0 +1,23 @@
const std = @import("std");
const main = @import("main");
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const ModifierRestriction = main.items.ModifierRestriction;
const Tool = main.items.Tool;
const ZonElement = main.ZonElement;
const Not = struct {
child: ModifierRestriction,
};
pub fn satisfied(self: *const Not, tool: *const Tool, x: i32, y: i32) bool {
return !self.child.satisfied(tool, x, y);
}
pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const Not {
const result = allocator.create(Not);
result.* = .{
.child = ModifierRestriction.loadFromZon(allocator, zon.getChild("child")),
};
return result;
}

View File

@ -0,0 +1,28 @@
const std = @import("std");
const main = @import("main");
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const ModifierRestriction = main.items.ModifierRestriction;
const Tool = main.items.Tool;
const ZonElement = main.ZonElement;
const Or = struct {
children: []ModifierRestriction,
};
pub fn satisfied(self: *const Or, tool: *const Tool, x: i32, y: i32) bool {
for(self.children) |child| {
if(child.satisfied(tool, x, y)) return true;
}
return false;
}
pub fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) *const Or {
const result = allocator.create(Or);
const childrenZon = zon.getChild("children").toSlice();
result.children = allocator.alloc(ModifierRestriction, childrenZon.len);
for(result.children, childrenZon) |*child, childZon| {
child.* = ModifierRestriction.loadFromZon(allocator, childZon);
}
return result;
}