1 /// Module for saving and loading tilemap data.
2 module isodi.tilemap;
3 
4 import rcdata.bin;
5 import std.bitmanip;
6 
7 import isodi.exception;
8 import isodi.tilemap_legacy;
9 
10 version (Isodi_Regular) {
11 
12     import isodi.chunk;
13     import isodi.resources.pack;
14 
15 }
16 
17 
18 @safe:
19 
20 
21 enum FormatVersion : int {
22 
23     version0 = 0x000150D1,
24 
25 }
26 
27 /// Load tilemaps
28 /// Params:
29 ///     range        = Range of bytes containing map data.
30 ///     declarations = All blocks defined in the tilemap. Must be sorted before passing to a pack.
31 ///     modifier     = Delegate to edit blocks before adding them into the chunk.
32 version (Isodi_Regular)
33 Chunk loadTilemap(T)(Pack pack, T range, out string[] declarations,
34     void delegate(ref Block block) @safe modifier = null)
35 do {
36 
37     Chunk chunk;
38     LoadTilemap loader;
39 
40     BlockPosition blockPosition;
41 
42     loader.onDeclarations = (decl, heightSteps) @safe {
43 
44         chunk.properties.heightSteps = heightSteps;
45         declarations = decl.dup;
46 
47     };
48 
49     loader.onEntry = (x, y, layer) @safe {
50 
51         blockPosition = BlockPosition(x, y);
52 
53     };
54 
55     loader.onBlock = (id, height, depth) @safe {
56 
57         blockPosition.height = height;
58         blockPosition.depth = depth;
59 
60         // Create the block
61         auto block = Block(
62             pack.blockType(declarations[id]),
63             blockPosition,
64         );
65 
66         // Edit the block
67         if (modifier) modifier(block);
68 
69         // Add it to the chunk
70         chunk.addX(block.tupleof, block.position.height);
71 
72         // Increment position
73         blockPosition.x += 1;
74 
75     };
76 
77     loader.parse(range);
78 
79     return chunk;
80 
81 }
82 
83 /// Struct for advanced tilemap loading.
84 struct LoadTilemap {
85 
86     /// This delegate is called with data declarations at the start of the file.
87     void delegate(scope string[] blockNames, int heightSteps) @safe onDeclarations;
88     // TODO elaborate
89 
90     /// This delegate is called when matched an entry, that is, a row of blocks in an arbitrary position.
91     ///
92     /// The parameters define the position of the entry. Following block calls will start from this position, each new
93     /// block should increment x.
94     void delegate(int x, int y, int layer) @safe onEntry;
95 
96     /// This delegate is called when found a block. It is called with an ID corresponding to the tile type declaration
97     /// (from [onDeclarations]) and a definition of the block's height.
98     void delegate(ulong blockID, int heightTop, int depth) @safe onBlock;
99 
100     /// Begin parsing. A callback member will be ran for each matched element of the input.
101     void parse(T)(T range) @trusted {  // system but shut
102 
103         // Create the parser
104         auto bin = rcbinParser(range);
105 
106         // Read magic bytes
107         auto magicBytes = bin.read!(ubyte[4]).bigEndianToNative!int;
108 
109         switch (magicBytes) with (FormatVersion) {
110 
111             case version0:
112                 parseVersion0(bin, this);
113                 return;
114 
115             default:
116                 enforce!MapException("Given file is not a tilemap");
117 
118         }
119 
120     }
121 
122 }