aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/test/map.tmj66
-rw-r--r--src/tmz.zig377
2 files changed, 443 insertions, 0 deletions
diff --git a/src/test/map.tmj b/src/test/map.tmj
new file mode 100644
index 0000000..ddfa9f3
--- /dev/null
+++ b/src/test/map.tmj
@@ -0,0 +1,66 @@
+{
+ "compressionlevel": -1,
+ "height": 30,
+ "class": "bar",
+ "infinite": false,
+ "layers": [
+ {
+ "class": "bar",
+ "data": [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 19, 15, 19, 15, 19, 15, 19, 15, 19, 15,
+ 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 15, 14, 15, 15, 15, 14, 15, 15, 15, 14,
+ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 14, 15, 19, 15, 19, 15, 19, 15, 19, 15,
+ 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 3, 1, 3, 1, 3, 1, 15, 14, 15, 14, 15, 15, 15, 15, 15, 14,
+ 4, 4, 4, 4, 4, 4, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 3, 3, 14, 14, 14, 15, 19, 15, 19, 15, 19, 15,
+ 5, 5, 5, 5, 5, 5, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 3, 3, 14, 14, 15, 14, 15, 14, 15, 14, 15, 14,
+ 6, 6, 6, 6, 6, 6, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 16, 16, 16, 16, 14, 15, 19, 15, 19, 15, 19, 15,
+ 6, 6, 6, 6, 6, 6, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 16, 16, 16, 16, 15, 14, 15, 15, 15, 14, 15, 14,
+ 6, 6, 6, 6, 6, 6, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 3, 16, 16, 16, 16, 14, 14, 19, 15, 19, 15, 19, 15,
+ 7, 7, 7, 7, 7, 7, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 13, 13, 13, 13, 8, 9, 8, 14, 15, 14, 15, 14,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 8, 19, 15, 19, 15,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 8, 14, 15, 14,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2147483659, 10, 17, 15, 19, 15,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 1073741835, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3221225483, 10, 8, 14, 15, 14,
+ 4, 4, 4, 4, 4, 4, 10, 10, 10, 10, 1073741835, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3221225483, 10, 10, 17, 15, 19, 15,
+ 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 1073741835, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3221225483, 10, 10, 17, 15, 15, 15, 14,
+ 6, 6, 6, 6, 6, 6, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 18, 17, 15, 19, 15, 19, 15,
+ 6, 6, 6, 6, 6, 6, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 15, 15, 15, 14, 15, 14,
+ 6, 6, 6, 6, 6, 6, 1, 3, 1, 3, 1, 3, 1, 2, 1, 2, 1, 3, 1, 3, 1, 2, 1, 3, 1, 3, 1, 2, 19, 15, 19, 15,
+ 7, 7, 7, 7, 7, 7, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 15, 14, 15, 14,
+ 1, 2, 1, 3, 1, 3, 1, 3, 1, 2, 1, 2, 1, 3, 1, 2, 1, 2, 1, 2, 1, 3, 1, 2, 1, 2, 1, 2, 1, 2, 19, 15,
+ 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 15, 14,
+ 1, 3, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 19, 15,
+ 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 15, 14,
+ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
+ 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1,
+ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
+ 3, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1],
+ "height": 30,
+ "id": 1,
+ "name": "Tile Layer 1",
+ "opacity": 1,
+ "type": "tilelayer",
+ "visible": true,
+ "width": 32,
+ "x": 0,
+ "y": 0
+ }
+ ],
+ "nextlayerid": 2,
+ "nextobjectid": 1,
+ "orientation": "orthogonal",
+ "renderorder": "right-down",
+ "tiledversion": "1.10.0",
+ "tileheight": 8,
+ "tilesets": [
+ {
+ "firstgid": 1,
+ "source": "tiles.tsj"
+ }
+ ],
+ "tilewidth": 8,
+ "type": "map",
+ "version": "1.10",
+ "width": 32
+}
diff --git a/src/tmz.zig b/src/tmz.zig
new file mode 100644
index 0000000..ac16d75
--- /dev/null
+++ b/src/tmz.zig
@@ -0,0 +1,377 @@
+const std = @import("std");
+
+pub const flipped_horizontally: u32 = 0x80000000;
+pub const flipped_vertically: u32 = 0x40000000;
+pub const flipped_diagonally: u32 = 0x20000000;
+pub const rotated_hexagonal_120: u32 = 0x10000000;
+
+/// [https://doc.mapeditor.org/en/stable/reference/json-map-format/#map]
+pub const Map = struct {
+ backgroundcolor: ?[]const u8 = null,
+ class: ?[]const u8 = null,
+ compressionlevel: i32 = -1,
+ height: u32,
+ hexsidelength: ?u32 = null,
+ infinite: bool,
+ layers: []Layer,
+ nextlayerid: u32,
+ nextobjectid: u32,
+ orientation: Orientation,
+ parallaxoriginx: f32 = 0,
+ parallaxoriginy: f32 = 0,
+ properties: ?[]const Property = null,
+ renderorder: RenderOrder,
+ staggeraxis: ?StaggerAxis = null,
+ staggerindex: ?StaggerIndex = null,
+ tiledversion: []const u8,
+ tileheight: u32,
+ tilesets: []Tileset,
+ tilewidth: u32,
+ type: Type,
+ version: []const u8,
+ width: u32,
+
+ pub fn globalTileId(self: @This(), index: u32) !Gid {
+ const is_flipped_horizontally = (index & flipped_horizontally > 0);
+ const is_flipped_vertically = (index & flipped_vertically > 0);
+ const is_flipped_diagonally = (index & flipped_diagonally > 0);
+ const is_rotated = (index & rotated_hexagonal_120 > 0);
+
+ // clear flags
+ const gtid = index & ~flipped_horizontally | flipped_vertically | flipped_diagonally | rotated_hexagonal_120;
+
+ for (self.tilesets) |tileset| {
+ if (tileset.firstgid <= gtid) {
+ return .{ .gid = gtid - tileset.firstgid, .flipped_horizontally = is_flipped_horizontally, .flipped_vertically = is_flipped_vertically, .flipped_diagonally = is_flipped_diagonally, .rotated = is_rotated };
+ }
+ }
+ return error.GidNotFound;
+ }
+
+ pub const Gid = struct {
+ gid: u32,
+ flipped_horizontally: bool,
+ flipped_vertically: bool,
+ flipped_diagonally: bool,
+ rotated: bool,
+ };
+
+ pub const Orientation = enum { orthogonal, isometric, staggered, hexagonal };
+ pub const RenderOrder = enum { @"right-down", @"right-up", @"left-down", @"left-up" };
+ pub const StaggerAxis = enum { x, y };
+ pub const StaggerIndex = enum { odd, even };
+ pub const Type = enum { map };
+};
+
+inline fn get(source: std.json.Value, name: []const u8) ?[]const u8 {
+ if (source.object.get(name)) |o| {
+ return o.string;
+ }
+ return null;
+}
+
+// pub const DataEncoding = union(enum) {
+// csv: ?[]const u32,
+// base64: ?[]const u8,
+
+// pub fn jsonParse(allocator: Allocator, source: std.json.Value, options: std.json.ParseOptions) !@This() {
+// _ = source;
+// _ = options;
+// _ = allocator;
+// // if (source == .string) {
+// // // const beep = source.string;
+// // // return .{ .base64 = beep };
+// // return @This(){ .base64 = "hi" };
+// // } else if (source == .array) {
+// // // return .{ .csv = &[_]u32{ 2, 3 } };
+// // // return .{ .base64 = "fff" };
+// // return error.UnexpectedToken;
+// // } else {
+// // return error.UnexpectedToken;
+// // }
+// return .{ .base64 = "foo" };
+// }
+// };
+
+pub const Layer = struct {
+ // chunks: ?[]const ChunkEncoding = null,
+ class: ?[]const u8 = null,
+ compression: ?enum { zlib, gzip, zstd } = null,
+ data: ?[]const u32 = null,
+ draworder: ?enum { topdown, index } = .topdown,
+ encoding: ?Encoding = .csv,
+ // height: ?u32 = null,
+ // id: u32,
+ // image: ?[]const u8 = null,
+ // layers: ?[]Layer = null,
+ // locked: bool = false,
+ // name: []const u8,
+ // objects: ?[]Object = null,
+ // offsetx: f32 = 0,
+ // offsety: f32 = 0,
+ // opacity: f32,
+ // parallaxx: f32 = 1,
+ // parallaxy: f32 = 1,
+ // properties: ?[]Property = null,
+ // repeatx: ?bool = null,
+ // repeaty: ?bool = null,
+ // startx: ?i32 = null,
+ // starty: ?i32 = null,
+ // tintcolor: ?[]const u8 = null,
+ // transparentcolor: ?[]const u8 = null,
+ type: Type,
+ // visible: bool,
+ // width: ?u32 = null,
+ // x: i32,
+ // y: i32,
+
+ pub fn jsonParseFromValue(allocator: std.mem.Allocator, source: std.json.Value, options: std.json.ParseOptions) !@This() {
+ _ = allocator; // autofix
+ _ = options; // autofix
+ if (source.object.get("type")) |layer_type| {
+ if (std.mem.eql(u8, layer_type.string, "tilelayer")) {
+ if (source.object.get("encoding")) |encoding| {
+ if (std.mem.eql(u8, encoding.string, "csv")) {
+ return .{ .type = Type.fromString(layer_type.string) };
+ }
+ } else {
+ return .{ .type = Type.fromString(layer_type.string) };
+ }
+ }
+ } else {
+ return error.MissingField;
+ }
+ return error.MissingField;
+ }
+
+ pub const Type = enum {
+ tilelayer,
+ objectgroup,
+ imagelayer,
+ group,
+
+ pub fn fromString(string: []const u8) Type {
+ if (std.mem.eql(u8, string, "tilelayer")) {
+ return .tilelayer;
+ }
+ return .tilelayer;
+ }
+ };
+ pub const Encoding = enum { csv, base64 };
+
+ // pub fn jsonParseFromValue(allocator: Allocator, source: std.json.Value, options: std.json.ParseOptions) !@This() {
+ // if (source != .object) return error.UnexpectedToken;
+ // if (source.object.get("data")) |source_data| {
+ // std.log.info("yayyyyyyyyyyyy : {s}\n\n\n", .{source.object.keys()});
+ // const encoding_value: std.json.Value = source.object.get("encoding") orelse .{ .string = "csv" };
+ // if (encoding_value != .string) return error.UnexpectedToken;
+ // const encoding = encoding_value.string;
+ // var data: []const u32 = undefined;
+ // if (std.mem.eql(u8, encoding, "base64")) {
+ // var base64 = try std.json.parseFromValueLeaky([]const u8, allocator, source_data, options);
+
+ // // var buffer = allocator.alloc(u8, std.base64.standard.Decoder.calcSizeForSlice(base64) catch return error.UnexpectedToken);
+ // var buffer: [0x10000]u8 = undefined;
+ // var decoded = buffer[0 .. std.base64.standard.Decoder.calcSizeForSlice(base64) catch return error.UnexpectedToken];
+ // std.base64.standard.Decoder.decode(decoded, base64) catch return error.UnexpectedToken;
+
+ // data = &[_]u32{ 1, 4 };
+ // } else {
+ // data = try std.json.parseFromValueLeaky([]const u32, allocator, source_data, options);
+ // }
+ // return .{
+ // .id = @intCast(source.object.get("id").?.integer),
+ // .name = source.object.get("name").?.string,
+ // .opacity = 0,
+ // .type = .tilelayer,
+ // .visible = true,
+ // .x = 0,
+ // .y = 0,
+ // .data = data,
+ // };
+ // } else {
+ // std.log.err("brooooo : {s}\n\n\n", .{source.object.keys()});
+ // return error.UnexpectedToken;
+ // }
+ // }
+};
+
+pub const Data = union(enum) {
+ csv: []const u32,
+ base64: []const u8,
+};
+
+pub const Chunk = struct {
+ data: []const u32,
+ height: u32,
+ width: u32,
+ x: u32,
+ y: u32,
+};
+
+pub const Object = struct {
+ ellipse: ?bool = null,
+ gid: ?u32 = null,
+ height: f32,
+ id: u32,
+ name: []const u8,
+ point: ?bool = null,
+ polygon: ?[]Point = null,
+ polyline: ?[]Point = null,
+ properties: ?[]Property = null,
+ rotation: f32,
+ template: ?[]const u8 = null,
+ text: ?Text = null,
+ type: ?[]const u8 = null,
+ visible: bool,
+ width: f32,
+ x: f32,
+ y: f32,
+};
+
+pub const Point = struct {
+ x: f32,
+ y: f32,
+};
+
+pub const Text = struct {
+ bold: bool,
+ color: []const u8,
+ fontfamily: []const u8 = "sans-serif",
+ halign: enum { center, right, justify, left } = .left,
+ italic: bool = false,
+ kerning: bool = true,
+ pixelsize: usize = 16,
+ strikeout: bool = false,
+ text: []const u8,
+ underline: bool = false,
+ valign: enum { center, bottom, top } = .top,
+ wrap: bool = false,
+};
+
+pub const Property = struct {
+ name: []const u8,
+ type: enum {
+ string,
+ int,
+ float,
+ bool,
+ color,
+ file,
+ object,
+ class,
+ } = .string,
+ propertytype: []const u8 = "",
+};
+
+pub const Tileset = struct {
+ backgroundcolor: ?[]const u8 = null,
+ class: ?[]const u8 = null,
+ columns: ?u32 = null,
+ fillmode: ?enum { stretch, @"preserve-aspect-fit" } = .stretch,
+ firstgid: u32,
+ grid: ?Grid = null,
+ image: ?[]const u8 = null,
+ imageheight: ?u32 = null,
+ imagewidth: ?u32 = null,
+ margin: ?u32 = null,
+ name: ?[]const u8 = null,
+ objectalignment: ?enum { unspecified, topleft, top, topright, left, center, right, bottomleft, bottom, bottomright } = .unspecified,
+ properties: ?[]Property = null,
+ source: []const u8,
+ spacing: ?i32 = null,
+ terrains: ?[]Terrain = null,
+ tilecount: ?u32 = null,
+ tileversion: ?[]const u8 = null,
+ tileheight: ?u32 = null,
+ tileoffset: ?Point = null,
+ tilerendersize: ?enum { tile, grid } = .tile,
+ tiles: ?[]Tile = null,
+ tilewidth: ?u32 = null,
+ transformations: ?Transformations = null,
+ transparentcolor: ?[]const u8 = null,
+ type: ?enum { tileset } = .tileset,
+ version: ?[]const u8 = null,
+ wangsets: ?[]Wangset = null,
+};
+
+pub const Grid = struct {
+ orientation: enum { orthogonal, isometric } = .orthogonal,
+ height: i32,
+ width: i32,
+};
+
+pub const Terrain = struct {
+ name: []const u8,
+ properties: []Property,
+ tile: i32,
+};
+
+pub const Tile = struct {
+ animiation: []Frame,
+ id: i32,
+ name: ?[]const u8,
+ imageheight: u32,
+ imagewidth: u32,
+ x: i32,
+ y: i32,
+ width: u32,
+ height: u32,
+ objectgroup: ?Layer,
+ probability: f32,
+ properties: []Property,
+ terrain: []i32,
+ type: []const u8,
+};
+
+pub const Frame = struct {
+ duration: i32,
+ tileid: i32,
+};
+
+pub const Transformations = struct {
+ hflip: bool,
+ vflip: bool,
+ rotate: bool,
+ preferuntransformed: bool,
+};
+
+pub const Wangset = struct {
+ class: ?[]const u8,
+ colors: []Wangcolor,
+ name: []const u8,
+ properties: []Property,
+ tile: i32,
+ type: []const u8,
+ wangtiles: []Wangtile,
+};
+
+pub const Wangcolor = struct {
+ class: ?[]const u8,
+ color: []const u8,
+ name: []const u8,
+ probability: f32,
+ properties: []Property,
+ tile: i32,
+};
+
+pub const Wangtile = struct {
+ tileid: i32,
+ wangid: []i32,
+};
+
+pub fn parse(bytes: []const u8, allocator: std.mem.Allocator) !Map {
+ const map = try std.json.parseFromSliceLeaky(std.json.Value, allocator, bytes, .{});
+ return try std.json.parseFromValueLeaky(Map, allocator, map, .{ .ignore_unknown_fields = true });
+}
+
+test "parse works" {
+ const json_map = @embedFile("test/map.tmj");
+
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+ const map = try parse(json_map, arena.allocator());
+ try std.testing.expectEqualStrings("1.10", map.version);
+
+ // try std.testing.expectEqual(0, map.globalTileId(0));
+}