mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add Structure Building Block asset loading (#1240)
* SBB * Fix rotation code * Remove rotate command * Fix segfault during generation * Delete format.bat * Pregenerate all rotated blueprints * Apply review suggestions * Apply review suggestions * Change child block storage model * Resolve child structures during load * Move structure_building_blocks.zig to terrain * Update src/rotation.zig * Apply review suggestions * Remove sbb blocks * Remove SBBGen * Remove example SBB * Remove blueprint code * Remove createAssetStringID * Apply review suggestions * Apply review suggestions * Add asset ID generation * Revert "Add asset ID generation" This reverts commit ffe8fd281486f2124ab83b0e614b6a7db97a020d. * Remove SBB loading * Revert "Remove SBB loading" This reverts commit 7eabad906dd05e3c128115b824986ff96815ac03. * Apply review requests * Restore base.zig.zon
This commit is contained in:
parent
d9dc3f1a22
commit
21409df5a1
@ -21,6 +21,7 @@ var commonBiomes: std.StringHashMap(ZonElement) = undefined;
|
||||
var commonBiomeMigrations: std.StringHashMap(ZonElement) = undefined;
|
||||
var commonRecipes: std.StringHashMap(ZonElement) = undefined;
|
||||
var commonModels: std.StringHashMap([]const u8) = undefined;
|
||||
var commonStructureBuildingBlocks: std.StringHashMap(ZonElement) = undefined;
|
||||
var commonBlueprints: std.StringHashMap([]u8) = undefined;
|
||||
|
||||
pub fn init() void {
|
||||
@ -37,6 +38,7 @@ pub fn init() void {
|
||||
commonBiomeMigrations = .init(arenaAllocator.allocator);
|
||||
commonRecipes = .init(arenaAllocator.allocator);
|
||||
commonModels = .init(arenaAllocator.allocator);
|
||||
commonStructureBuildingBlocks = .init(arenaAllocator.allocator);
|
||||
commonBlueprints = .init(arenaAllocator.allocator);
|
||||
|
||||
readAssets(
|
||||
@ -50,12 +52,13 @@ pub fn init() void {
|
||||
&commonBiomeMigrations,
|
||||
&commonRecipes,
|
||||
&commonModels,
|
||||
&commonStructureBuildingBlocks,
|
||||
&commonBlueprints,
|
||||
);
|
||||
|
||||
std.log.info(
|
||||
"Finished assets init with {} blocks ({} migrations), {} items, {} tools, {} biomes ({} migrations), {} recipes, and {} blueprints",
|
||||
.{commonBlocks.count(), commonBlockMigrations.count(), commonItems.count(), commonTools.count(), commonBiomes.count(), commonBiomeMigrations.count(), commonRecipes.count(), commonBlueprints.count()},
|
||||
"Finished assets init with {} blocks ({} migrations), {} items, {} tools, {} biomes ({} migrations), {} recipes, {} structure building blocks and {} blueprints",
|
||||
.{commonBlocks.count(), commonBlockMigrations.count(), commonItems.count(), commonTools.count(), commonBiomes.count(), commonBiomeMigrations.count(), commonRecipes.count(), commonStructureBuildingBlocks.count(), commonBlueprints.count()},
|
||||
);
|
||||
}
|
||||
|
||||
@ -267,6 +270,7 @@ pub fn readAssets(
|
||||
biomeMigrations: *std.StringHashMap(ZonElement),
|
||||
recipes: *std.StringHashMap(ZonElement),
|
||||
models: *std.StringHashMap([]const u8),
|
||||
structureBuildingBlocks: *std.StringHashMap(ZonElement),
|
||||
blueprints: *std.StringHashMap([]u8),
|
||||
) void {
|
||||
var addons = main.List(std.fs.Dir).init(main.stackAllocator);
|
||||
@ -305,6 +309,7 @@ pub fn readAssets(
|
||||
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "biomes", true, biomes, biomeMigrations);
|
||||
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "recipes", false, recipes, null);
|
||||
readAllObjFilesInAddonsHashmap(externalAllocator, addons, addonNames, "models", models);
|
||||
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "sbb", true, structureBuildingBlocks, null);
|
||||
readAllBlueprintFilesInAddons(externalAllocator, addons, addonNames, "blueprints", blueprints);
|
||||
}
|
||||
|
||||
@ -472,6 +477,8 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPale
|
||||
defer recipes.clearAndFree();
|
||||
var models = commonModels.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
|
||||
defer models.clearAndFree();
|
||||
var structureBuildingBlocks = commonStructureBuildingBlocks.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
|
||||
defer structureBuildingBlocks.clearAndFree();
|
||||
var blueprints = commonBlueprints.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
|
||||
defer blueprints.clearAndFree();
|
||||
|
||||
@ -486,6 +493,7 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPale
|
||||
&biomeMigrations,
|
||||
&recipes,
|
||||
&models,
|
||||
&structureBuildingBlocks,
|
||||
&blueprints,
|
||||
);
|
||||
errdefer unloadAssets();
|
||||
@ -594,6 +602,7 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPale
|
||||
}
|
||||
|
||||
try sbb.registerBlueprints(&blueprints);
|
||||
try sbb.registerSBB(&structureBuildingBlocks);
|
||||
|
||||
// Biomes:
|
||||
var nextBiomeNumericId: u32 = 0;
|
||||
|
@ -14,6 +14,7 @@ const NeverFailingAllocator = main.heap.NeverFailingAllocator;
|
||||
var arena = main.heap.NeverFailingArenaAllocator.init(main.globalAllocator);
|
||||
const arenaAllocator = arena.allocator();
|
||||
|
||||
var structureCache: std.StringHashMapUnmanaged(StructureBuildingBlock) = .{};
|
||||
var blueprintCache: std.StringHashMapUnmanaged(*[4]BlueprintEntry) = .{};
|
||||
var childrenToResolve: List(struct {parentId: []const u8, colorName: []const u8, colorIndex: usize, childIndex: usize, structureId: []const u8}) = undefined;
|
||||
|
||||
@ -101,6 +102,103 @@ pub fn isOriginBlock(block: Block) bool {
|
||||
return block.typ == originBlockNumericId;
|
||||
}
|
||||
|
||||
pub const StructureBuildingBlock = struct {
|
||||
children: []AliasTable(Child),
|
||||
blueprints: *[4]BlueprintEntry,
|
||||
|
||||
fn initFromZon(stringId: []const u8, zon: ZonElement) !StructureBuildingBlock {
|
||||
const blueprintId = zon.get(?[]const u8, "blueprint", null) orelse {
|
||||
std.log.err("['{s}'] Missing blueprint field.", .{stringId});
|
||||
return error.MissingBlueprintIdField;
|
||||
};
|
||||
const blueprints = blueprintCache.get(blueprintId) orelse {
|
||||
std.log.err("['{s}'] Could not find blueprint '{s}'.", .{stringId, blueprintId});
|
||||
return error.MissingBlueprint;
|
||||
};
|
||||
const self = StructureBuildingBlock{
|
||||
.children = arenaAllocator.alloc(AliasTable(Child), childBlockStringId.items.len),
|
||||
.blueprints = blueprints,
|
||||
};
|
||||
const childrenZon = zon.getChild("children");
|
||||
for(childBlockStringId.items, 0..) |colorName, colorIndex| {
|
||||
self.children[colorIndex] = try initChildTableFromZon(stringId, colorName, colorIndex, childrenZon.getChild(colorName));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
pub fn getBlueprint(self: StructureBuildingBlock, rotation: Degrees) *BlueprintEntry {
|
||||
return &self.blueprints[@intFromEnum(rotation)];
|
||||
}
|
||||
pub fn pickChild(self: StructureBuildingBlock, block: BlueprintEntry.StructureBlock, seed: *u64) *const StructureBuildingBlock {
|
||||
return self.children[block.index].sample(seed).structure;
|
||||
}
|
||||
};
|
||||
|
||||
fn initChildTableFromZon(parentId: []const u8, colorName: []const u8, colorIndex: usize, zon: ZonElement) !AliasTable(Child) {
|
||||
if(zon == .null) return .init(arenaAllocator, &.{});
|
||||
if(zon != .array) {
|
||||
std.log.err("['{s}'->'{s}'] Incorrect child data structure, array expected.", .{parentId, colorName});
|
||||
return .init(arenaAllocator, &.{});
|
||||
}
|
||||
if(zon.array.items.len == 0) {
|
||||
std.log.err("['{s}'->'{s}'] Empty children list.", .{parentId, colorName});
|
||||
return error.EmptyChildrenList;
|
||||
}
|
||||
const list = arenaAllocator.alloc(Child, zon.array.items.len);
|
||||
for(zon.array.items, 0..) |entry, childIndex| {
|
||||
list[childIndex] = try Child.initFromZon(parentId, colorName, colorIndex, childIndex, entry);
|
||||
}
|
||||
return .init(arenaAllocator, list);
|
||||
}
|
||||
|
||||
const Child = struct {
|
||||
structure: *StructureBuildingBlock,
|
||||
chance: f32,
|
||||
|
||||
fn initFromZon(parentId: []const u8, colorName: []const u8, colorIndex: usize, childIndex: usize, zon: ZonElement) !Child {
|
||||
const structureId = zon.get([]const u8, "structure", "");
|
||||
if(structureId.len == 0) {
|
||||
std.log.err("['{s}'->'{s}'->'{d}'] Child node has empty structure field, parent structure will be discarded.", .{parentId, colorName, childIndex});
|
||||
return error.EmptyStructureId;
|
||||
}
|
||||
childrenToResolve.append(.{.parentId = parentId, .colorName = colorName, .colorIndex = colorIndex, .childIndex = childIndex, .structureId = structureId});
|
||||
return .{
|
||||
.structure = undefined,
|
||||
.chance = zon.get(f32, "chance", 1.0),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn registerSBB(structures: *std.StringHashMap(ZonElement)) !void {
|
||||
std.debug.assert(structureCache.capacity() == 0);
|
||||
structureCache.ensureTotalCapacity(arenaAllocator.allocator, structures.count()) catch unreachable;
|
||||
childrenToResolve = .init(main.stackAllocator);
|
||||
{
|
||||
var iterator = structures.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
const value = StructureBuildingBlock.initFromZon(entry.key_ptr.*, entry.value_ptr.*) catch |err| {
|
||||
std.log.err("Could not register structure building block '{s}' ({s})", .{entry.key_ptr.*, @errorName(err)});
|
||||
continue;
|
||||
};
|
||||
const key = arenaAllocator.dupe(u8, entry.key_ptr.*);
|
||||
structureCache.put(arenaAllocator.allocator, key, value) catch unreachable;
|
||||
std.log.debug("Registered structure building block: '{s}'", .{entry.key_ptr.*});
|
||||
}
|
||||
}
|
||||
{
|
||||
for(childrenToResolve.items) |entry| {
|
||||
const parent = structureCache.getPtr(entry.parentId).?;
|
||||
const child = structureCache.getPtr(entry.structureId) orelse {
|
||||
std.log.err("Could not find child structure '{s}' for child resolution.", .{entry.structureId});
|
||||
continue;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
childrenToResolve.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn registerChildBlock(numericId: u16, stringId: []const u8) void {
|
||||
const index: u16 = @intCast(childBlockNumericIdMap.count());
|
||||
childBlockNumericIdMap.put(arenaAllocator.allocator, numericId, index) catch unreachable;
|
||||
@ -123,7 +221,7 @@ pub fn registerBlueprints(blueprints: *std.StringHashMap([]u8)) !void {
|
||||
while(iterator.next()) |entry| {
|
||||
const stringId = entry.key_ptr.*;
|
||||
const blueprint0 = Blueprint.load(arenaAllocator, entry.value_ptr.*) catch |err| {
|
||||
std.log.err("Could not load blueprint {s}: {s}", .{stringId, @errorName(err)});
|
||||
std.log.err("Could not load blueprint '{s}' ({s})", .{stringId, @errorName(err)});
|
||||
continue;
|
||||
};
|
||||
|
||||
@ -140,9 +238,14 @@ pub fn registerBlueprints(blueprints: *std.StringHashMap([]u8)) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getByStringId(stringId: []const u8) ?*StructureBuildingBlock {
|
||||
return structureCache.getPtr(stringId);
|
||||
}
|
||||
|
||||
pub fn reset() void {
|
||||
childBlockNumericIdMap = .{};
|
||||
childBlockStringId = .{};
|
||||
structureCache = .{};
|
||||
blueprintCache = .{};
|
||||
|
||||
_ = arena.reset(.free_all);
|
||||
|
Loading…
x
Reference in New Issue
Block a user