dsa-4th-edition/zig/foundry.zig
Sven Balzer 942c395f59 add zig build for compendium packs
move document types from template.json into system.json
change Talents into Items
add rolls for Talents
change the fallback language to german
2024-11-23 18:29:11 +01:00

165 lines
5.0 KiB
Zig

const std = @import("std");
const leveldb = @import("leveldb");
const system = @import("system.zig");
const String = []const u8;
const CORE_VERSION = "12.331";
const SYSTEM_NAME = system.SYSTEM_NAME;
const SYSTEM_VERSION = system.SYSTEM_VERSION;
// Entry must be a tagged union with one tag being
// Folder: struct {
// name: String,
// entries: []const Entry,
// },
// and the other tags being the respective Foundry type name
pub fn Compendium(base_type: BaseType, Entry: type) type {
if (std.meta.activeTag(@typeInfo(Entry)) != .Union) @compileError("Entry must be a tagged union.");
if (@typeInfo(Entry).Union.tag_type == null) @compileError("Entry must be a tagged union.");
return struct {
entries: []const Entry = &.{},
pub fn serialize(self: @This(), path: [:0]const u8) !void {
try leveldb.destroy(.{ .path = path });
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var diagnostic: leveldb.Diagnostic = null;
const db = leveldb.open(.{ .path = path, .diagnostic = &diagnostic, .options = .{ .create_if_missing = true, .compression = .Snappy } }) catch |err| {
std.log.err("leveldb.open failed: {s}", .{ diagnostic.? });
return err;
};
defer db.close();
for (self.entries) |entry| {
defer _ = arena.reset(.retain_capacity);
try serialize_entry(arena.allocator(), db, entry, null);
}
}
fn serialize_entry(allocator: std.mem.Allocator, db: leveldb, entry: Entry, folder: ?String) !void{
switch (entry) {
.Folder => |_folder| {
const foundry_folder: Folder(base_type) = .{
.name = _folder.name,
._id = &random_id(),
.folder = folder,
};
const key = try std.fmt.allocPrintZ(allocator, "!folders!{s}", .{ foundry_folder._id.? });
const value = try std.json.stringifyAlloc(allocator, foundry_folder, .{});
try db.put(.{ .key = key, .value = value });
for (_folder.entries) |folder_entry| {
try serialize_entry(allocator, db, folder_entry, foundry_folder._id);
}
},
inline else => |item| {
std.debug.assert(item.folder == null);
var foundry_item = item;
foundry_item.folder = folder;
if (foundry_item._id == null)
foundry_item._id = &random_id();
const key = try std.fmt.allocPrintZ(allocator, "!{s}!{s}", .{ base_type.to_compendium_type(), foundry_item._id.? });
const value = try std.json.stringifyAlloc(allocator, foundry_item, .{});
try db.put(.{ .key = key, .value = value });
}
}
}
};
}
const BaseType = enum {
Item,
Actor,
fn to_compendium_type(self: @This()) String {
return switch (self) {
.Item => "items",
.Actor => "actors",
};
}
};
fn Folder(base_type: BaseType) type {
return struct {
_id: ?String = null,
name: String,
@"type": BaseType = base_type,
description: String = "",
folder: ?String = null,
sorting: enum { a, m } = .a,
sort: u64 = 0,
color: ?String = null,
flags: struct {} = .{},
_stats: DocumentStats = .{},
};
}
pub fn Item(comptime typename: String, comptime T: type) type {
return struct {
const Type: BaseType = .Item;
_id: ?String = null,
name: String,
@"type": String = typename,
img: String = "icons/svg/item-bag.svg",
system: T,
effects: []u0 = &.{},
folder: ?String = null,
sort: u64 = 0,
ownership: struct {
default: u8 = 0,
} = .{},
flags: struct {} = .{},
_stats: DocumentStats = .{},
};
}
pub const DocumentStats = struct {
coreVersion: String = CORE_VERSION,
systemId: String = SYSTEM_NAME,
systemVersion: String = SYSTEM_VERSION,
createdTime: ?u64 = null,
modifiedTime: ?u64 = null,
lastModifiedBy: ?String = null,
compendiumSource: ?String = null,
duplicateSource: ?String = null,
};
inline fn random_char(alphabet: []const u8) u8 {
return alphabet[std.crypto.random.uintLessThan(u8, alphabet.len)];
}
var id_set = std.BufSet.init(std.heap.c_allocator);
fn random_id() [16]u8 {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var result: [16]u8 = undefined;
inline for (&result) |*c| c.* = random_char(alphabet);
if (id_set.contains(&result)) {
return random_id();
}
id_set.insert(&result) catch unreachable;
return result;
}