move document types from template.json into system.json change Talents into Items add rolls for Talents change the fallback language to german
165 lines
5.0 KiB
Zig
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;
|
|
}
|