Make API more consistent
parent
d2a8d304f9
commit
ec04460077
87
src/LDtk.zig
87
src/LDtk.zig
|
@ -1,5 +1,15 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn parse(alloc: std.mem.Allocator, ldtk_file: []const u8) !Root {
|
||||
var parser = std.json.Parser.init(alloc, false);
|
||||
defer parser.deinit();
|
||||
|
||||
var value_tree = try parser.parse(ldtk_file);
|
||||
defer value_tree.deinit();
|
||||
|
||||
return Root.fromJSON(alloc, value_tree.root);
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
pub fn object(value_opt: ?std.json.Value) ?std.json.ObjectMap {
|
||||
const value = value_opt orelse return null;
|
||||
|
@ -92,6 +102,25 @@ pub const Root = struct {
|
|||
worldGridWidth: ?i64 = null,
|
||||
worldLayout: ?WorldLayout = null,
|
||||
worlds: ?[]World = null,
|
||||
|
||||
pub fn fromJSON(alloc: std.mem.Allocator, root_opt: ?std.json.Value) !Root {
|
||||
const root = object(root_opt) orelse return error.InvalidRoot;
|
||||
const ldtk_levels = try Level.fromJSONMany(alloc, root.get("levels"));
|
||||
var ldtk_root = Root{
|
||||
.bgColor = string(root.get("bgColor")) orelse return error.InvalidBGColor,
|
||||
// .defs = ldtk_defs,
|
||||
.externalLevels = boolean(root.get("externalLevels")) orelse return error.InvalidExternalLevels,
|
||||
.jsonVersion = string(root.get("jsonVersion")) orelse return error.InvalidJsonVersion,
|
||||
.levels = ldtk_levels,
|
||||
.worldGridHeight = integer(root.get("worldGridHeight")) orelse return error.InvalidHeight,
|
||||
.worldGridWidth = integer(root.get("worldGridWidth")) orelse return error.InvalidWidth,
|
||||
.worldLayout = enum_from_value(WorldLayout, root.get("worldLayout")) orelse return error.InvalidWorldLayout,
|
||||
};
|
||||
if (array(root.get("worlds"))) |worlds| {
|
||||
ldtk_root.worlds = try World.fromJSONMany(alloc, worlds);
|
||||
}
|
||||
return ldtk_root;
|
||||
}
|
||||
};
|
||||
|
||||
/// 1.1. World
|
||||
|
@ -102,6 +131,28 @@ pub const World = struct {
|
|||
worldGridHeight: i64,
|
||||
worldGridWidth: i64,
|
||||
worldLayout: WorldLayout,
|
||||
|
||||
pub fn fromJSON(alloc: std.mem.Allocator, world_value: ?std.json.Value) !World {
|
||||
const world_obj = object(world_value) orelse return error.InvalidWorld;
|
||||
const levels_obj = world_obj.get("levels") orelse return error.InvalidWorldLevels;
|
||||
const levels = try Level.fromJSONMany(alloc, levels_obj);
|
||||
return World{
|
||||
.identifier = string(world_obj.get("identifier")) orelse return error.InvalidIdentifier,
|
||||
.iid = string(world_obj.get("iid")) orelse return error.InvalidIID,
|
||||
.levels = levels,
|
||||
.worldGridHeight = integer(world_obj.get("worldGridHeight")) orelse return error.InvalidWorldGridHeight,
|
||||
.worldGridWidth = integer(world_obj.get("worldGridHeight")) orelse return error.InvalidWorldGridHeight,
|
||||
.worldLayout = enum_from_value(WorldLayout, world_obj.get("worldLayout")) orelse return error.InvalidWorldLayout,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromJSONMany(alloc: std.mem.Allocator, worlds: std.json.Array) ![]World {
|
||||
var ldtk_worlds = try std.ArrayList(World).initCapacity(alloc, worlds.items.len);
|
||||
for (worlds.items) |world_value| {
|
||||
ldtk_worlds.appendAssumeCapacity(try fromJSON(alloc, world_value));
|
||||
}
|
||||
return ldtk_worlds.toOwnedSlice();
|
||||
}
|
||||
};
|
||||
|
||||
pub const WorldLayout = enum {
|
||||
|
@ -132,6 +183,42 @@ pub const Level = struct {
|
|||
worldDepth: i64,
|
||||
worldX: i64,
|
||||
worldY: i64,
|
||||
|
||||
pub fn fromJSON(alloc: std.mem.Allocator, level_opt: ?std.json.Value) !Level {
|
||||
const level_obj = object(level_opt) orelse return error.InvalidLevel;
|
||||
const layer_instances = if (level_obj.get("layerInstances")) |layerInstances| try LayerInstance.fromJSONMany(alloc, layerInstances) else null;
|
||||
return Level{
|
||||
.__bgColor = string(level_obj.get("__bgColor")),
|
||||
// TODO
|
||||
.__bgPos = null,
|
||||
// TODO
|
||||
.__neighbours = &[_]Neighbour{},
|
||||
.bgRelPath = string(level_obj.get("bgRelPath")),
|
||||
.externalRelPath = string(level_obj.get("externalRelPath")),
|
||||
// TODO
|
||||
.fieldInstances = &[_]FieldInstance{},
|
||||
.identifier = string(level_obj.get("identifier")) orelse return error.InvalidIdentifier,
|
||||
.iid = string(level_obj.get("iid")) orelse return error.InvalidIID,
|
||||
.layerInstances = layer_instances,
|
||||
.pxHei = integer(level_obj.get("pxHei")) orelse return error.InvalidPxHei,
|
||||
.pxWid = integer(level_obj.get("pxWid")) orelse return error.InvalidPxWid,
|
||||
.uid = integer(level_obj.get("uid")) orelse return error.InvalidUID,
|
||||
.worldDepth = integer(level_obj.get("worldDepth")) orelse return error.InvalidWorldDepth,
|
||||
.worldX = integer(level_obj.get("worldX")) orelse return error.InvalidWorldX,
|
||||
.worldY = integer(level_obj.get("worldY")) orelse return error.InvalidWorldY,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
pub fn fromJSONMany(alloc: std.mem.Allocator, levels_opt: ?std.json.Value) ![]Level {
|
||||
const levels = array(levels_opt) orelse return error.InvalidLevels;
|
||||
var ldtk_levels = try std.ArrayList(Level).initCapacity(alloc, levels.items.len);
|
||||
defer ldtk_levels.deinit(); // levels will be returned using toOwnedSlice
|
||||
for (levels.items) |level_value| {
|
||||
ldtk_levels.appendAssumeCapacity(try fromJSON(alloc, level_value));
|
||||
}
|
||||
return ldtk_levels.toOwnedSlice();
|
||||
}
|
||||
};
|
||||
|
||||
pub const Neighbour = struct {
|
||||
|
|
179
src/main.zig
179
src/main.zig
|
@ -5,41 +5,7 @@ const LDtk = @import("LDtk.zig");
|
|||
test "load default/empty ldtk file" {
|
||||
const empty_ldtk = @embedFile("test.ldtk");
|
||||
|
||||
var parser = std.json.Parser.init(testing.allocator, false);
|
||||
defer parser.deinit();
|
||||
|
||||
var value_tree = try parser.parse(empty_ldtk);
|
||||
defer value_tree.deinit();
|
||||
|
||||
value_tree.root.dump();
|
||||
|
||||
// Seperate root for easier access
|
||||
const root = object(value_tree.root) orelse return error.InvalidRoot;
|
||||
|
||||
// Pull out the more complicated structures
|
||||
// const defs = object(root.get("defs")) orelse return error.InvalidDefs;
|
||||
const levels = array(root.get("levels")) orelse return error.InvalidLevels;
|
||||
|
||||
// const ldtk_defs = try extract_defs(testing.allocator, defs);
|
||||
// defer testing.allocator.free(ldtk_defs);
|
||||
const ldtk_levels = try extract_levels(testing.allocator, levels);
|
||||
defer testing.allocator.free(ldtk_levels);
|
||||
|
||||
var ldtk_root = LDtk.Root{
|
||||
.bgColor = string(root.get("bgColor")) orelse return error.InvalidBGColor,
|
||||
// .defs = ldtk_defs,
|
||||
.externalLevels = boolean(root.get("externalLevels")) orelse return error.InvalidExternalLevels,
|
||||
.jsonVersion = string(root.get("jsonVersion")) orelse return error.InvalidJsonVersion,
|
||||
.levels = ldtk_levels,
|
||||
.worldGridHeight = integer(root.get("worldGridHeight")) orelse return error.InvalidHeight,
|
||||
.worldGridWidth = integer(root.get("worldGridWidth")) orelse return error.InvalidWidth,
|
||||
.worldLayout = enum_from_value(LDtk.WorldLayout, root.get("worldLayout")) orelse return error.InvalidWorldLayout,
|
||||
};
|
||||
if (array(root.get("worlds"))) |worlds| {
|
||||
const ldtk_worlds = try extract_worlds(testing.allocator, worlds);
|
||||
defer testing.allocator.free(ldtk_worlds);
|
||||
ldtk_root.worlds = ldtk_worlds;
|
||||
}
|
||||
const ldtk_root = try LDtk.parse(testing.allocator, empty_ldtk);
|
||||
|
||||
try testing.expectEqualStrings("1.1.3", ldtk_root.jsonVersion);
|
||||
try testing.expectEqualStrings("#40465B", ldtk_root.bgColor);
|
||||
|
@ -49,146 +15,3 @@ test "load default/empty ldtk file" {
|
|||
try testing.expect(!ldtk_root.externalLevels);
|
||||
}
|
||||
|
||||
// pub fn extract_defs(alloc: std.mem.Allocator, defs_obj: std.json.Value) !LDtk.Definitions {
|
||||
// // TODO
|
||||
// }
|
||||
|
||||
pub fn extract_worlds(alloc: std.mem.Allocator, worlds: std.json.Array) ![]LDtk.World {
|
||||
var ldtk_worlds = try std.ArrayList(LDtk.World).initCapacity(alloc, worlds.items.len);
|
||||
for (worlds.items) |world_value| {
|
||||
const world_obj = object(world_value) orelse return error.InvalidWorld;
|
||||
const levels_obj = array(world_obj.get("levels")) orelse return error.InvalidWorldLevels;
|
||||
const levels = try extract_levels(alloc, levels_obj);
|
||||
ldtk_worlds.appendAssumeCapacity(.{
|
||||
.identifier = string(world_obj.get("identifier")) orelse return error.InvalidIdentifier,
|
||||
.iid = string(world_obj.get("iid")) orelse return error.InvalidIID,
|
||||
.levels = levels,
|
||||
.worldGridHeight = integer(world_obj.get("worldGridHeight")) orelse return error.InvalidWorldGridHeight,
|
||||
.worldGridWidth = integer(world_obj.get("worldGridHeight")) orelse return error.InvalidWorldGridHeight,
|
||||
.worldLayout = enum_from_value(LDtk.WorldLayout, world_obj.get("worldLayout")) orelse return error.InvalidWorldLayout,
|
||||
});
|
||||
}
|
||||
return ldtk_worlds.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn extract_levels(alloc: std.mem.Allocator, levels: std.json.Array) ![]LDtk.Level {
|
||||
var ldtk_levels = try std.ArrayList(LDtk.Level).initCapacity(alloc, levels.items.len);
|
||||
defer ldtk_levels.deinit(); // levels will be returned using toOwnedSlice
|
||||
for (levels.items) |level_value| {
|
||||
const level_obj = object(level_value) orelse return error.InvalidLevel;
|
||||
const layer_instances = if (level_obj.get("layerInstances")) |layerInstances| try LDtk.LayerInstance.fromJSONMany(alloc, layerInstances) else null;
|
||||
ldtk_levels.appendAssumeCapacity(.{
|
||||
.__bgColor = string(level_obj.get("__bgColor")),
|
||||
// TODO
|
||||
.__bgPos = null,
|
||||
// TODO
|
||||
.__neighbours = &[_]LDtk.Neighbour{},
|
||||
.bgRelPath = string(level_obj.get("bgRelPath")),
|
||||
.externalRelPath = string(level_obj.get("externalRelPath")),
|
||||
// TODO
|
||||
.fieldInstances = &[_]LDtk.FieldInstance{},
|
||||
.identifier = string(level_obj.get("identifier")) orelse return error.InvalidIdentifier,
|
||||
.iid = string(level_obj.get("iid")) orelse return error.InvalidIID,
|
||||
.layerInstances = layer_instances,
|
||||
.pxHei = integer(level_obj.get("pxHei")) orelse return error.InvalidPxHei,
|
||||
.pxWid = integer(level_obj.get("pxWid")) orelse return error.InvalidPxWid,
|
||||
.uid = integer(level_obj.get("uid")) orelse return error.InvalidUID,
|
||||
.worldDepth = integer(level_obj.get("worldDepth")) orelse return error.InvalidWorldDepth,
|
||||
.worldX = integer(level_obj.get("worldX")) orelse return error.InvalidWorldX,
|
||||
.worldY = integer(level_obj.get("worldY")) orelse return error.InvalidWorldY,
|
||||
});
|
||||
}
|
||||
return ldtk_levels.toOwnedSlice();
|
||||
}
|
||||
|
||||
// pub fn extract_layers(alloc: std.mem.Allocator, layers: std.json.Array) ![]LDtk.LayerInstance {
|
||||
// var ldtk_layers = try std.ArrayList(LDtk.LayerInstance).initCapacity(alloc, layers.items.len);
|
||||
// defer ldtk_layers.deinit(); // levels will be returned using toOwnedSlice
|
||||
// for (layers.items) |layer_value| {
|
||||
// const layer_obj = object(layer_value) orelse return error.InvalidLayer;
|
||||
// const __type = enum_from_value(LDtk.LayerType, layer_obj.get("__type")) orelse return error.InvalidType;
|
||||
// const autoLayerTiles = if (__type == .AutoLayer) {} else null;
|
||||
// const entityInstances = if (__type == .Entities) {} else null;
|
||||
// const gridTiles = if (__type == .Tiles) {} else null;
|
||||
// const intGridCsv = if (__type == .IntGrid) {} else null;
|
||||
// ldtk_layers.appendAssumeCapacity(.{
|
||||
// .__cHei = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// .__cWid = integer(layer_obj.get("__cWid")) orelse return error.InvalidCWid,
|
||||
// .__gridSize = integer(layer_obj.get("__gridSize")) orelse return error.InvalidGridSize,
|
||||
// .__identifier = string(layer_obj.get("__identifier")) orelse return error.InvalidIdentifier,
|
||||
// .__opacity = float(layer_obj.get("__opacity")) orelse return error.InvalidOpacity,
|
||||
// .__pxTotalOffsetX = integer(layer_obj.get("__pxTotalOffsetX")) orelse return error.InvalidTotalOffsetX,
|
||||
// .__pxTotalOffsetY = integer(layer_obj.get("__pxTotalOffsetY")) orelse return error.InvalidTotalOffsetY,
|
||||
// .__tilesetDefUid = integer(layer_obj.get("__tilesetDefUid")) orelse return error.InvalidTilesetDefUid,
|
||||
// .__tilesetRelPath = integer(layer_obj.get("__tilesetRelPath")) orelse return error.InvalidTilesetRelPath,
|
||||
// .__type = __type,
|
||||
// .autoLayerTiles = autoLayerTiles,
|
||||
// .entityInstances = entityInstances,
|
||||
// .gridTiles = gridTiles,
|
||||
// .iid = string(layer_obj.get("iid")) orelse return error.InvalidIID,
|
||||
// .intGridCsv = integer(layer_obj.get("intGridCsv")) orelse return error.InvalidGridCsv,
|
||||
// .levelId = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// .overrideTilesetUid = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// .pxOffsetX = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// .pxOffsetY = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// .visible = integer(layer_obj.get("__cHei")) orelse return error.InvalidCHei,
|
||||
// });
|
||||
// }
|
||||
// return ldtk_layers.toOwnedSlice();
|
||||
// }
|
||||
|
||||
fn object(value_opt: ?std.json.Value) ?std.json.ObjectMap {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.Object => |obj| obj,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn array(value_opt: ?std.json.Value) ?std.json.Array {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.Array => |arr| arr,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn string(value_opt: ?std.json.Value) ?[]const u8 {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.String => |str| str,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn boolean(value_opt: ?std.json.Value) ?bool {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.Bool => |b| b,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn integer(value_opt: ?std.json.Value) ?i64 {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.Integer => |int| int,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn float(value_opt: ?std.json.Value) ?f64 {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.Float => |float| float,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn enum_from_value(comptime T: type, value_opt: ?std.json.Value) ?T {
|
||||
const value = value_opt orelse return null;
|
||||
return switch (value) {
|
||||
.String => |str| std.meta.stringToEnum(T, str),
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue