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 }