mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Allow direct use of blueprints as SBBs (#1500)
## Descriptions This pull request adds inline SBBs feature which allows blueprints to be used directly (without SBB zon file) as child in other SBB files. Blueprint used this way must not any child blocks on it's own. To ensure that the feature works correctly some of the now redundant SBB zon files were removed. Current implementation generates SBB at runtime for each of the blueprints that has 0 child blocks and doesn't have an SBB with same ID. In the future the implementation could be changed to create SBBs on demand, to avoid wasting memory on blueprints which are not used or use SBB with different name, that is not critical tho (really small gains) and requires #1499 ## Links Resolves: #1403 --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
74b0fb4431
commit
8f9ebe55fa
@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.id = "cubyz:sbb",
|
.id = "cubyz:sbb",
|
||||||
.structure = "cubyz:tree/birch/forest_generator",
|
.structure = "cubyz:tree/birch/mixed_forest_generator",
|
||||||
.placeMode = .degradable,
|
.placeMode = .degradable,
|
||||||
.chance = 0.1,
|
.chance = 0.1,
|
||||||
},
|
},
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.id = "cubyz:sbb",
|
.id = "cubyz:sbb",
|
||||||
.structure = "cubyz:tree/birch/birch_forest_generator",
|
.structure = "cubyz:tree/birch/forest_generator",
|
||||||
.placeMode = .degradable,
|
.placeMode = .degradable,
|
||||||
.chance = 0.2,
|
.chance = 0.2,
|
||||||
},
|
},
|
||||||
|
Binary file not shown.
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/root/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/root/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/root/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/small_branch/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/small_branch/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/small_branch/3",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/stub/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/stub/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/stub/3",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/stub/4",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/top/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/birch/1/top/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:generator",
|
|
||||||
.children = .{
|
|
||||||
.crimson = .{
|
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/1", .chance = 0.2},
|
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/2", .chance = 0.2},
|
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/3", .chance = 0.2},
|
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/4", .chance = 0.4},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
@ -1,11 +1,11 @@
|
|||||||
.{
|
.{
|
||||||
.blueprint = "cubyz:generator",
|
.blueprint = "cubyz:tree/birch/forest_generator",
|
||||||
.children = .{
|
.children = .{
|
||||||
.crimson = .{
|
.crimson = .{
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/1"},
|
.{.structure = "cubyz:tree/birch/1/tree/1", .chance = 0.2},
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/2"},
|
.{.structure = "cubyz:tree/birch/1/tree/2", .chance = 0.2},
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/3"},
|
.{.structure = "cubyz:tree/birch/1/tree/3", .chance = 0.2},
|
||||||
.{.structure = "cubyz:tree/birch/1/tree/4"},
|
.{.structure = "cubyz:tree/birch/1/tree/4", .chance = 0.4},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
11
assets/cubyz/sbb/tree/birch/mixed_forest_generator.zig.zon
Normal file
11
assets/cubyz/sbb/tree/birch/mixed_forest_generator.zig.zon
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.{
|
||||||
|
.blueprint = "cubyz:tree/birch/forest_generator",
|
||||||
|
.children = .{
|
||||||
|
.crimson = .{
|
||||||
|
.{.structure = "cubyz:tree/birch/1/tree/1"},
|
||||||
|
.{.structure = "cubyz:tree/birch/1/tree/2"},
|
||||||
|
.{.structure = "cubyz:tree/birch/1/tree/3"},
|
||||||
|
.{.structure = "cubyz:tree/birch/1/tree/4"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/leaf/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/leaf/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/leaf/3",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/3",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/4",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/5",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/root/6",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/stub/1",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/stub/2",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/stub/3",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.{
|
|
||||||
.blueprint = "cubyz:tree/oak/1/stub/4",
|
|
||||||
.children = .{},
|
|
||||||
}
|
|
BIN
assets/cubyz/sbb/tree/oak/forest_generator.blp
Normal file
BIN
assets/cubyz/sbb/tree/oak/forest_generator.blp
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
.{
|
.{
|
||||||
.blueprint = "cubyz:generator",
|
.blueprint = "cubyz:tree/oak/forest_generator",
|
||||||
.children = .{
|
.children = .{
|
||||||
.crimson = .{
|
.crimson = .{
|
||||||
.{.structure = "cubyz:tree/oak/1/base/1", .chance = 0.5},
|
.{.structure = "cubyz:tree/oak/1/base/1", .chance = 0.5},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.{
|
.{
|
||||||
.blueprint = "cubyz:generator",
|
.blueprint = "cubyz:tree/oak/forest_generator",
|
||||||
.children = .{
|
.children = .{
|
||||||
.crimson = .{
|
.crimson = .{
|
||||||
.{.structure = "cubyz:tree/oak/1/base/1"},
|
.{.structure = "cubyz:tree/oak/1/base/1"},
|
||||||
|
@ -46,6 +46,10 @@ const BlueprintEntry = struct {
|
|||||||
pub inline fn pos(self: StructureBlock) Vec3i {
|
pub inline fn pos(self: StructureBlock) Vec3i {
|
||||||
return Vec3i{self.x, self.y, self.z};
|
return Vec3i{self.x, self.y, self.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(self: StructureBlock) []const u8 {
|
||||||
|
return childBlockStringId.items[self.index];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn init(blueprint: Blueprint, stringId: []const u8) !BlueprintEntry {
|
fn init(blueprint: Blueprint, stringId: []const u8) !BlueprintEntry {
|
||||||
@ -120,10 +124,14 @@ pub const StructureBuildingBlock = struct {
|
|||||||
std.log.err("['{s}'] Missing blueprint field.", .{stringId});
|
std.log.err("['{s}'] Missing blueprint field.", .{stringId});
|
||||||
return error.MissingBlueprintIdField;
|
return error.MissingBlueprintIdField;
|
||||||
};
|
};
|
||||||
const blueprints = blueprintCache.get(blueprintId) orelse {
|
const blueprintsTemplate = blueprintCache.get(blueprintId) orelse {
|
||||||
std.log.err("['{s}'] Could not find blueprint '{s}'.", .{stringId, blueprintId});
|
std.log.err("['{s}'] Could not find blueprint '{s}'.", .{stringId, blueprintId});
|
||||||
return error.MissingBlueprint;
|
return error.MissingBlueprint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const blueprints = arenaAllocator.create([4]BlueprintEntry);
|
||||||
|
blueprints.* = blueprintsTemplate.*;
|
||||||
|
|
||||||
const self = StructureBuildingBlock{
|
const self = StructureBuildingBlock{
|
||||||
.id = stringId,
|
.id = stringId,
|
||||||
.children = arenaAllocator.alloc(AliasTable(Child), childBlockStringId.items.len),
|
.children = arenaAllocator.alloc(AliasTable(Child), childBlockStringId.items.len),
|
||||||
@ -133,8 +141,54 @@ pub const StructureBuildingBlock = struct {
|
|||||||
for(childBlockStringId.items, 0..) |colorName, colorIndex| {
|
for(childBlockStringId.items, 0..) |colorName, colorIndex| {
|
||||||
self.children[colorIndex] = try initChildTableFromZon(stringId, colorName, colorIndex, childrenZon.getChild(colorName));
|
self.children[colorIndex] = try initChildTableFromZon(stringId, colorName, colorIndex, childrenZon.getChild(colorName));
|
||||||
}
|
}
|
||||||
|
self.updateBlueprintChildLists();
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
pub fn updateBlueprintChildLists(self: StructureBuildingBlock) void {
|
||||||
|
for(self.children, 0..) |child, index| found: {
|
||||||
|
if(child.items.len == 0) continue;
|
||||||
|
|
||||||
|
for(self.blueprints[0].childBlocks) |blueprintChild| {
|
||||||
|
if(blueprintChild.index != index) continue;
|
||||||
|
break :found;
|
||||||
|
}
|
||||||
|
std.log.err("['{s}'] Blueprint doesn't contain child '{s}' but configuration for it was specified.", .{self.id, childBlockStringId.items[index]});
|
||||||
|
}
|
||||||
|
for(self.blueprints, 0..) |*blueprint, index| {
|
||||||
|
var childBlocks: ListUnmanaged(BlueprintEntry.StructureBlock) = .{};
|
||||||
|
defer childBlocks.deinit(main.stackAllocator);
|
||||||
|
|
||||||
|
for(blueprint.childBlocks) |child| {
|
||||||
|
if(self.children[child.index].items.len == 0) {
|
||||||
|
if(index == 0) std.log.err("['{s}'] Missing child structure configuration for child '{s}'", .{self.id, child.id()});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
childBlocks.append(main.stackAllocator, child);
|
||||||
|
}
|
||||||
|
blueprint.childBlocks = arenaAllocator.dupe(BlueprintEntry.StructureBlock, childBlocks.items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn initInline(sbbId: []const u8) !StructureBuildingBlock {
|
||||||
|
const blueprintsTemplate = blueprintCache.get(sbbId) orelse {
|
||||||
|
std.log.err("['{s}'] Could not find blueprint '{s}'.", .{sbbId, sbbId});
|
||||||
|
return error.MissingBlueprint;
|
||||||
|
};
|
||||||
|
|
||||||
|
const blueprints = arenaAllocator.create([4]BlueprintEntry);
|
||||||
|
blueprints.* = blueprintsTemplate.*;
|
||||||
|
for(blueprints, 0..) |*blueprint, index| {
|
||||||
|
if(index == 0) {
|
||||||
|
for(blueprint.childBlocks) |child| std.log.err("['{s}'] Missing child structure configuration for child '{s}'", .{sbbId, child.id()});
|
||||||
|
}
|
||||||
|
blueprint.childBlocks = &.{};
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.id = sbbId,
|
||||||
|
.children = &.{},
|
||||||
|
.blueprints = blueprints,
|
||||||
|
};
|
||||||
|
}
|
||||||
pub fn getBlueprint(self: StructureBuildingBlock, rotation: Degrees) *BlueprintEntry {
|
pub fn getBlueprint(self: StructureBuildingBlock, rotation: Degrees) *BlueprintEntry {
|
||||||
return &self.blueprints[@intFromEnum(rotation)];
|
return &self.blueprints[@intFromEnum(rotation)];
|
||||||
}
|
}
|
||||||
@ -150,8 +204,8 @@ fn initChildTableFromZon(parentId: []const u8, colorName: []const u8, colorIndex
|
|||||||
return .init(arenaAllocator, &.{});
|
return .init(arenaAllocator, &.{});
|
||||||
}
|
}
|
||||||
if(zon.array.items.len == 0) {
|
if(zon.array.items.len == 0) {
|
||||||
std.log.err("['{s}'->'{s}'] Empty children list.", .{parentId, colorName});
|
std.log.err("['{s}'->'{s}'] Empty children list not allowed. Remove 'children' field or add child structure configurations.", .{parentId, colorName});
|
||||||
return error.EmptyChildrenList;
|
return .init(arenaAllocator, &.{});
|
||||||
}
|
}
|
||||||
const list = arenaAllocator.alloc(Child, zon.array.items.len);
|
const list = arenaAllocator.alloc(Child, zon.array.items.len);
|
||||||
for(zon.array.items, 0..) |entry, childIndex| {
|
for(zon.array.items, 0..) |entry, childIndex| {
|
||||||
@ -193,16 +247,38 @@ pub fn registerSBB(structures: *Assets.ZonHashMap) !void {
|
|||||||
std.log.debug("Registered structure building block: '{s}'", .{entry.key_ptr.*});
|
std.log.debug("Registered structure building block: '{s}'", .{entry.key_ptr.*});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
var keyIterator = blueprintCache.keyIterator();
|
||||||
|
while(keyIterator.next()) |key_ptr| {
|
||||||
|
const blueprintId = key_ptr.*;
|
||||||
|
|
||||||
|
if(structureCache.contains(blueprintId)) continue;
|
||||||
|
|
||||||
|
const value = StructureBuildingBlock.initInline(blueprintId) catch |err| {
|
||||||
|
std.log.err("Could not register inline structure building block '{s}' ({s})", .{blueprintId, @errorName(err)});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
const key = arenaAllocator.dupe(u8, blueprintId);
|
||||||
|
structureCache.put(arenaAllocator.allocator, key, value) catch unreachable;
|
||||||
|
std.log.debug("Registered inline structure building block: '{s}'", .{blueprintId});
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
for(childrenToResolve.items) |entry| {
|
for(childrenToResolve.items) |entry| {
|
||||||
const parent = structureCache.getPtr(entry.parentId).?;
|
const parent = structureCache.getPtr(entry.parentId).?;
|
||||||
const child = structureCache.getPtr(entry.structureId) orelse {
|
const child = getByStringId(entry.structureId) orelse {
|
||||||
std.log.err("Could not find child structure '{s}' for child resolution.", .{entry.structureId});
|
std.log.err("Could not find child structure nor blueprint '{s}' for child resolution.", .{entry.structureId});
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(parent.children.len <= entry.colorIndex) {
|
||||||
|
main.utils.panicWithMessage("Error resolving child structure '{s}'->'{s}'->'{d}' to '{s}'", .{entry.parentId, entry.colorName, entry.childIndex, entry.structureId});
|
||||||
|
}
|
||||||
|
|
||||||
|
const childColor = parent.children[entry.colorIndex];
|
||||||
|
|
||||||
std.log.debug("Resolved child structure '{s}'->'{s}'->'{d}' to '{s}'", .{entry.parentId, entry.colorName, entry.childIndex, entry.structureId});
|
std.log.debug("Resolved child structure '{s}'->'{s}'->'{d}' to '{s}'", .{entry.parentId, entry.colorName, entry.childIndex, entry.structureId});
|
||||||
parent.children[entry.colorIndex].items[entry.childIndex].structure = child;
|
childColor.items[entry.childIndex].structure = child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2212,3 +2212,8 @@ test "NamedCallbacks registers functions" {
|
|||||||
try std.testing.expectEqual(null, testFunctions.getFunctionPointer("functionTest"));
|
try std.testing.expectEqual(null, testFunctions.getFunctionPointer("functionTest"));
|
||||||
try std.testing.expectEqual(null, testFunctions.getFunctionPointer("wrongSignatureFunction"));
|
try std.testing.expectEqual(null, testFunctions.getFunctionPointer("wrongSignatureFunction"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn panicWithMessage(comptime fmt: []const u8, args: anytype) void {
|
||||||
|
const message = std.fmt.allocPrint(main.stackAllocator.allocator, fmt, args) catch unreachable;
|
||||||
|
@panic(message);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user