Parse ldtk file without error
parent
c9daf228ad
commit
c8c86dd11d
177
src/LDtk.zig
177
src/LDtk.zig
|
@ -1,57 +1,50 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn parse(allocator: std.mem.Allocator, json_string: []const u8) !Root {
|
||||
@setEvalBranchQuota(10_0000);
|
||||
var tokens = std.json.TokenStream.init(json_string);
|
||||
const root = try std.json.parse(Root, &tokens, .{ .allocator = allocator });
|
||||
return root;
|
||||
}
|
||||
// pub fn parse(parser: *std.json.Parser, json_string: []const u8) !std.json.Value {
|
||||
// const value_tree = try parser.parse(json_string);
|
||||
// value_tree.root.dump();
|
||||
|
||||
pub fn parseFree(allocator: std.mem.Allocator, root: Root) void {
|
||||
std.json.parseFree(Root, root, .{ .allocator = allocator });
|
||||
}
|
||||
// const root_obj = switch (value_tree.root) {
|
||||
// .Object => |obj| obj,
|
||||
// else => return error.InvalidRoot,
|
||||
// };
|
||||
// _ = root_obj;
|
||||
// // const root = Root {
|
||||
// // name: root_obj.get("name") orelse error.InvalidRoot,
|
||||
// // version: root_obj.get("jsonVersion") orelse error.InvalidRoot,
|
||||
// // defaultPivotX: root_obj.get("defaultPivotX") orelse error.InvalidRoot,
|
||||
// // defaultPivotY: root_obj.get("defaultPivotY") orelse error.InvalidRoot,
|
||||
// // defaultGridSize: root_obj.get("defaultGridSize") orelse error.InvalidRoot,
|
||||
// // name: root_obj.get("name") orelse error.InvalidRoot,
|
||||
// // };
|
||||
|
||||
// return Root{};
|
||||
// }
|
||||
|
||||
/// 1. LDtk Json root
|
||||
const Root = struct {
|
||||
__header__: __Header__,
|
||||
|
||||
name: []const u8,
|
||||
jsonVersion: u64,
|
||||
defaultPivotX: f64,
|
||||
defaultPivotY: f64,
|
||||
defaultGridSize: u64,
|
||||
pub const Root = struct {
|
||||
bgColor: []const u8,
|
||||
nextUid: u64,
|
||||
|
||||
defs: Definitions,
|
||||
|
||||
defs: ?Definitions = null,
|
||||
externalLevels: bool,
|
||||
jsonVersion: []const u8,
|
||||
levels: []Level,
|
||||
|
||||
worldGridHeight: ?u64 = null,
|
||||
worldGridWidth: ?u64 = null,
|
||||
worldGridHeight: ?i64 = null,
|
||||
worldGridWidth: ?i64 = null,
|
||||
worldLayout: ?WorldLayout = null,
|
||||
worlds: []World,
|
||||
};
|
||||
|
||||
const __Header__ = struct {
|
||||
fileType: []const u8,
|
||||
app: []const u8,
|
||||
appAuthor: []const u8,
|
||||
appVersion: []const u8,
|
||||
url: []const u8,
|
||||
worlds: ?[]World = null,
|
||||
};
|
||||
|
||||
/// 1.1. World
|
||||
const World = struct {
|
||||
pub const World = struct {
|
||||
identifier: []const u8,
|
||||
iid: []const u8,
|
||||
levels: []Level,
|
||||
worldGridHeight: u64,
|
||||
worldGridWidth: u64,
|
||||
worldGridHeight: i64,
|
||||
worldGridWidth: i64,
|
||||
worldLayout: WorldLayout,
|
||||
};
|
||||
|
||||
const WorldLayout = enum {
|
||||
pub const WorldLayout = enum {
|
||||
Free,
|
||||
GridVania,
|
||||
LinearHorizontal,
|
||||
|
@ -59,59 +52,61 @@ const WorldLayout = enum {
|
|||
};
|
||||
|
||||
/// 2. Level
|
||||
const Level = struct {
|
||||
__bgColor: []const u8,
|
||||
pub const Level = struct {
|
||||
__bgColor: ?[]const u8,
|
||||
__bgPos: ?struct {
|
||||
cropRect: [4]f64,
|
||||
scale: [2]f64,
|
||||
topLeftPx: [2]i64,
|
||||
},
|
||||
__neighbours: []struct {
|
||||
dir: []const u8,
|
||||
levelIid: []const u8,
|
||||
levelUid: ?u64 = null,
|
||||
},
|
||||
__neighbours: []Neighbour,
|
||||
bgRelPath: ?[]const u8,
|
||||
externalRelPath: ?[]const u8,
|
||||
fieldInstances: []FieldInstance,
|
||||
identifier: []const u8,
|
||||
iid: []const u8,
|
||||
layerInstances: ?[]LayerInstance,
|
||||
pxHei: u64,
|
||||
pxWid: u64,
|
||||
uid: u64,
|
||||
pxHei: i64,
|
||||
pxWid: i64,
|
||||
uid: i64,
|
||||
worldDepth: i64,
|
||||
worldX: i64,
|
||||
worldY: i64,
|
||||
};
|
||||
|
||||
pub const Neighbour = struct {
|
||||
dir: []const u8,
|
||||
levelIid: []const u8,
|
||||
levelUid: ?i64 = null,
|
||||
};
|
||||
|
||||
/// 2.1. Layer instance
|
||||
const LayerInstance = struct {
|
||||
__cHei: u64,
|
||||
__cWid: u64,
|
||||
__gridSize: u64,
|
||||
__cHei: i64,
|
||||
__cWid: i64,
|
||||
__gridSize: i64,
|
||||
__identifier: []const u8,
|
||||
__opacity: f64,
|
||||
__pxTotalOffsetX: i64,
|
||||
__pxTotalOffsetY: i64,
|
||||
__tilesetDefUid: ?u64,
|
||||
__tilesetDefUid: ?i64,
|
||||
__tilesetRelPath: ?[]const u8,
|
||||
__type: []const u8,
|
||||
autoLayerTiles: []TileInstance,
|
||||
entityInstances: []EntityInstance,
|
||||
gridTiles: []TileInstance,
|
||||
iid: []const u8,
|
||||
intGridCsv: []u64,
|
||||
layerDefUid: u64,
|
||||
levelId: u64,
|
||||
overrideTilesetUid: ?u64,
|
||||
pxOffsetX: u64,
|
||||
pxOffsetY: u64,
|
||||
intGridCsv: []i64,
|
||||
layerDefUid: i64,
|
||||
levelId: i64,
|
||||
overrideTilesetUid: ?i64,
|
||||
pxOffsetX: i64,
|
||||
pxOffsetY: i64,
|
||||
visible: bool,
|
||||
/// WARNING: this deprecated value is no longer exported since version 1.0.0
|
||||
/// Replaced by: intGridCsv
|
||||
intGrid: ?[][]const u8 = null,
|
||||
// seed: u64,
|
||||
// seed: i64,
|
||||
// autoTiles: []AutoTile,
|
||||
};
|
||||
|
||||
|
@ -127,7 +122,7 @@ const TileInstance = struct {
|
|||
f: FlipBits,
|
||||
px: [2]i64,
|
||||
src: [2]i64,
|
||||
t: u64,
|
||||
t: i64,
|
||||
};
|
||||
|
||||
const FlipBits = enum(u4) {
|
||||
|
@ -145,23 +140,23 @@ const EntityInstance = struct {
|
|||
__smartColor: []const u8,
|
||||
__tags: [][]const u8,
|
||||
__tile: ?TilesetRectangle,
|
||||
defUid: u64,
|
||||
defUid: i64,
|
||||
fieldInstances: []FieldInstance,
|
||||
height: u64,
|
||||
height: i64,
|
||||
iid: []const u8,
|
||||
px: [2]i64,
|
||||
width: u64,
|
||||
width: i64,
|
||||
};
|
||||
|
||||
/// 2.4. Field Instance
|
||||
const FieldInstance = struct {
|
||||
pub const FieldInstance = struct {
|
||||
__identifier: []const u8,
|
||||
__tile: ?TilesetRectangle,
|
||||
// TODO: type and value have many possible values and are not always strings.
|
||||
// Figure out if we can use JSON.parse for this
|
||||
__type: []const u8,
|
||||
__value: []const u8,
|
||||
defUid: u64,
|
||||
defUid: i64,
|
||||
};
|
||||
|
||||
const FieldType = union(enum) {
|
||||
|
@ -209,11 +204,11 @@ const LayerDefinition = struct {
|
|||
Tiles,
|
||||
AutoLayer,
|
||||
},
|
||||
autoSourceLayerDefUid: ?u64,
|
||||
autoSourceLayerDefUid: ?i64,
|
||||
displayOpacity: f64,
|
||||
gridSize: u64,
|
||||
gridSize: i64,
|
||||
identifier: []const u8,
|
||||
intGridValues: []struct { color: []const u8, identifier: ?[]const u8, value: u64 },
|
||||
intGridValues: []struct { color: []const u8, identifier: ?[]const u8, value: i64 },
|
||||
parallaxFactorX: f64,
|
||||
parallaxFactorY: f64,
|
||||
parallaxScaling: bool,
|
||||
|
@ -222,12 +217,12 @@ const LayerDefinition = struct {
|
|||
/// Reference to the default Tileset UID used by this layer definition.
|
||||
/// WARNING: some layer instances might use a different tileset. So most of the time, you should probably use the __tilesetDefUid value found in layer instances.
|
||||
/// NOTE: since version 1.0.0, the old autoTilesetDefUid was removed and merged into this value.
|
||||
tilesetDefUid: ?u64,
|
||||
tilesetDefUid: ?i64,
|
||||
/// Unique Int identifier
|
||||
uid: u64,
|
||||
uid: i64,
|
||||
/// WARNING: this deprecated value will be removed completely on version 1.2.0+
|
||||
/// Replaced by: tilesetDefUid
|
||||
autoTilesetDefUid: ?u64 = null,
|
||||
autoTilesetDefUid: ?i64 = null,
|
||||
};
|
||||
|
||||
/// 3.1.1. Auto-layer rule definition
|
||||
|
@ -236,19 +231,19 @@ const AutoLayerRuleDefinition = opaque {};
|
|||
/// 3.2. Entity definition
|
||||
const EntityDefinition = struct {
|
||||
color: []const u8,
|
||||
height: u64,
|
||||
height: i64,
|
||||
identifier: []const u8,
|
||||
nineSliceBorders: [4]i64,
|
||||
pivotX: f64,
|
||||
pivotY: f64,
|
||||
tileRect: TilesetRectangle,
|
||||
tileRenderMode: enum { Cover, FitInside, Repeat, Stretch, FullSizeCropped, FullSizeUncropped, NineSlice },
|
||||
tilesetId: ?u64,
|
||||
uid: u64,
|
||||
width: u64,
|
||||
tilesetId: ?i64,
|
||||
uid: i64,
|
||||
width: i64,
|
||||
/// WARNING: this deprecated value will be removed completely on version 1.2.0+
|
||||
/// Replaced by tileRect
|
||||
tileId: ?u64 = null,
|
||||
tileId: ?i64 = null,
|
||||
};
|
||||
|
||||
/// 3.2.1. Field definition
|
||||
|
@ -256,52 +251,52 @@ const FieldDefinition = []const u8;
|
|||
|
||||
/// 3.2.2. Tileset rectangle
|
||||
const TilesetRectangle = struct {
|
||||
h: u64,
|
||||
tilesetUid: u64,
|
||||
w: u64,
|
||||
h: i64,
|
||||
tilesetUid: i64,
|
||||
w: i64,
|
||||
x: i64,
|
||||
y: i64,
|
||||
};
|
||||
|
||||
/// 3.3. Tileset definition
|
||||
const TilesetDefinition = struct {
|
||||
__cHei: u64,
|
||||
__cWid: u64,
|
||||
__cHei: i64,
|
||||
__cWid: i64,
|
||||
customData: []struct {
|
||||
data: []const u8,
|
||||
tileId: u64,
|
||||
tileId: i64,
|
||||
},
|
||||
embedAtlas: ?enum { LdtkIcons },
|
||||
enumTags: []struct {
|
||||
enumValueId: []const u8,
|
||||
tileIds: []u64,
|
||||
tileIds: []i64,
|
||||
},
|
||||
identifier: []const u8,
|
||||
padding: i64,
|
||||
pxHei: u64,
|
||||
pxWid: u64,
|
||||
pxHei: i64,
|
||||
pxWid: i64,
|
||||
relPath: ?[]const u8,
|
||||
spacing: i64,
|
||||
tags: [][]const u8,
|
||||
tagsSourceEnumUid: ?u64,
|
||||
tileGridSize: u64,
|
||||
uid: u64,
|
||||
tagsSourceEnumUid: ?i64,
|
||||
tileGridSize: i64,
|
||||
uid: i64,
|
||||
};
|
||||
|
||||
/// 3.4. Enum definition
|
||||
const EnumDefinition = struct {
|
||||
externalRelPath: ?[]const u8,
|
||||
iconTilesetUid: ?u64,
|
||||
iconTilesetUid: ?i64,
|
||||
identifier: []const u8,
|
||||
tags: [][]const u8,
|
||||
uid: u64,
|
||||
uid: i64,
|
||||
values: []EnumValueDefinition,
|
||||
};
|
||||
|
||||
/// 3.4.1. Enum value definition
|
||||
const EnumValueDefinition = struct {
|
||||
__tileSrcRect: ?[4]i64,
|
||||
color: u64,
|
||||
color: i64,
|
||||
id: []const u8,
|
||||
tileId: ?u64,
|
||||
tileId: ?i64,
|
||||
};
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
|
||||
"__header__" : { // Some information header
|
||||
"fileType": "LDtk Project JSON",
|
||||
"app": "LDtk",
|
||||
"appAuthor": "Sebastien Benard",
|
||||
"appVersion": "0.6.3",
|
||||
"url": "..."
|
||||
},
|
||||
|
||||
// Global project settings
|
||||
"name" : "My empty project",
|
||||
"jsonVersion" : 1,
|
||||
"defaultPivotX" : 0.0,
|
||||
"defaultPivotY" : 0.0,
|
||||
"defaultGridSize" : 16,
|
||||
"bgColor" : "#7F8093",
|
||||
"nextUid" : 1,
|
||||
|
||||
"defs" : { // These are elements definitions
|
||||
"layers" : [],
|
||||
"entities" : [],
|
||||
"tilesets" : [],
|
||||
"enums" : [],
|
||||
"externalEnums" : []
|
||||
},
|
||||
|
||||
"levels" : [ // Actual level data
|
||||
{
|
||||
"identifier" : "Level",
|
||||
"uid" : 0,
|
||||
"pxWid" : 256,
|
||||
"pxHei" : 256,
|
||||
"layerInstances" : [] // "null" if levels are separated
|
||||
}
|
||||
]
|
||||
|
||||
}
|
143
src/main.zig
143
src/main.zig
|
@ -3,7 +3,144 @@ const testing = std.testing;
|
|||
const LDtk = @import("LDtk.zig");
|
||||
|
||||
test "load default/empty ldtk file" {
|
||||
const empty_ldtk = @embedFile("empty.ldtk");
|
||||
const world = try LDtk.parse(testing.allocator, empty_ldtk);
|
||||
_ = world;
|
||||
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;
|
||||
}
|
||||
_ = ldtk_root;
|
||||
|
||||
std.log.warn("\n{?}\n", .{ ldtk_root });
|
||||
}
|
||||
|
||||
// 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;
|
||||
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,
|
||||
// TODO
|
||||
.layerInstances = null,
|
||||
.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();
|
||||
}
|
||||
|
||||
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 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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"__header__": {
|
||||
"fileType": "LDtk Project JSON",
|
||||
"app": "LDtk",
|
||||
"doc": "https://ldtk.io/json",
|
||||
"schema": "https://ldtk.io/files/JSON_SCHEMA.json",
|
||||
"appAuthor": "Sebastien 'deepnight' Benard",
|
||||
"appVersion": "1.1.3",
|
||||
"url": "https://ldtk.io"
|
||||
},
|
||||
"jsonVersion": "1.1.3",
|
||||
"appBuildId": 458364,
|
||||
"nextUid": 1,
|
||||
"identifierStyle": "Capitalize",
|
||||
"worldLayout": "Free",
|
||||
"worldGridWidth": 256,
|
||||
"worldGridHeight": 256,
|
||||
"defaultLevelWidth": 256,
|
||||
"defaultLevelHeight": 256,
|
||||
"defaultPivotX": 0,
|
||||
"defaultPivotY": 0,
|
||||
"defaultGridSize": 16,
|
||||
"bgColor": "#40465B",
|
||||
"defaultLevelBgColor": "#696A79",
|
||||
"minifyJson": false,
|
||||
"externalLevels": false,
|
||||
"exportTiled": false,
|
||||
"simplifiedExport": false,
|
||||
"imageExportMode": "None",
|
||||
"pngFilePattern": null,
|
||||
"backupOnSave": false,
|
||||
"backupLimit": 10,
|
||||
"levelNamePattern": "Level_%idx",
|
||||
"tutorialDesc": null,
|
||||
"flags": [],
|
||||
"defs": { "layers": [], "entities": [], "tilesets": [], "enums": [], "externalEnums": [], "levelFields": [] },
|
||||
"levels": [
|
||||
{
|
||||
"identifier": "Level_0",
|
||||
"iid": "c0773b00-02f0-11ed-bf2c-25905856c5d2",
|
||||
"uid": 0,
|
||||
"worldX": 0,
|
||||
"worldY": 0,
|
||||
"worldDepth": 0,
|
||||
"pxWid": 256,
|
||||
"pxHei": 256,
|
||||
"__bgColor": "#696A79",
|
||||
"bgColor": null,
|
||||
"useAutoIdentifier": true,
|
||||
"bgRelPath": null,
|
||||
"bgPos": null,
|
||||
"bgPivotX": 0.5,
|
||||
"bgPivotY": 0.5,
|
||||
"__smartColor": "#ADADB5",
|
||||
"__bgPos": null,
|
||||
"externalRelPath": null,
|
||||
"fieldInstances": [],
|
||||
"layerInstances": [],
|
||||
"__neighbours": []
|
||||
}
|
||||
],
|
||||
"worlds": []
|
||||
}
|
Loading…
Reference in New Issue