1#include <base/logger.h>
2#include <base/system.h>
3
4#include <engine/shared/datafile.h>
5#include <engine/storage.h>
6
7#include <game/gamecore.h>
8#include <game/mapitems.h>
9
10static bool Process(IStorage *pStorage, const char **pMapNames)
11{
12 CDataFileReader aMaps[2];
13
14 for(int i = 0; i < 2; ++i)
15 {
16 if(!aMaps[i].Open(pStorage, pFilename: pMapNames[i], StorageType: IStorage::TYPE_ABSOLUTE))
17 {
18 dbg_msg(sys: "map_diff", fmt: "error opening map '%s'", pMapNames[i]);
19 return false;
20 }
21
22 const CMapItemVersion *pVersion = static_cast<CMapItemVersion *>(aMaps[i].FindItem(Type: MAPITEMTYPE_VERSION, Id: 0));
23 if(pVersion == nullptr || pVersion->m_Version != 1)
24 {
25 dbg_msg(sys: "map_diff", fmt: "unsupported map version '%s'", pMapNames[i]);
26 return false;
27 }
28 }
29
30 int aStart[2], aLayersNum[2];
31 for(int i = 0; i < 2; ++i)
32 aMaps[i].GetType(Type: MAPITEMTYPE_LAYER, pStart: &aStart[i], pNum: &aLayersNum[i]);
33
34 // ensure basic layout
35 if(aLayersNum[0] != aLayersNum[1])
36 {
37 dbg_msg(sys: "map_diff", fmt: "different layer numbers:");
38 for(int i = 0; i < 2; ++i)
39 dbg_msg(sys: "map_diff", fmt: " \"%s\": %d layers", pMapNames[i], aLayersNum[i]);
40 return false;
41 }
42
43 // preload data
44 for(int j = 0; j < aLayersNum[0]; ++j)
45 {
46 for(int i = 0; i < 2; ++i)
47 {
48 CMapItemLayer *pItem = (CMapItemLayer *)aMaps[i].GetItem(Index: aStart[i] + j);
49 if(pItem->m_Type == LAYERTYPE_TILES)
50 (void)aMaps[i].GetData(Index: ((CMapItemLayerTilemap *)pItem)->m_Data);
51 }
52 }
53
54 // compare
55 for(int j = 0; j < aLayersNum[0]; ++j)
56 {
57 CMapItemLayer *apItem[2];
58 for(int i = 0; i < 2; ++i)
59 apItem[i] = (CMapItemLayer *)aMaps[i].GetItem(Index: aStart[i] + j);
60
61 if(apItem[0]->m_Type != LAYERTYPE_TILES || apItem[1]->m_Type != LAYERTYPE_TILES)
62 continue;
63
64 CMapItemLayerTilemap *apTilemap[2];
65 char aaName[2][12];
66
67 for(int i = 0; i < 2; ++i)
68 {
69 apTilemap[i] = (CMapItemLayerTilemap *)apItem[i];
70 IntsToStr(pInts: apTilemap[i]->m_aName, NumInts: std::size(apTilemap[i]->m_aName), pStr: aaName[i], StrSize: std::size(aaName[i]));
71 }
72
73 if(str_comp(a: aaName[0], b: aaName[1]) != 0 || apTilemap[0]->m_Width != apTilemap[1]->m_Width || apTilemap[0]->m_Height != apTilemap[1]->m_Height)
74 {
75 dbg_msg(sys: "map_diff", fmt: "different tile layers:");
76 for(int i = 0; i < 2; ++i)
77 dbg_msg(sys: "map_diff", fmt: " \"%s\" (%dx%d)", aaName[i], apTilemap[i]->m_Width, apTilemap[i]->m_Height);
78 return false;
79 }
80 CTile *apTile[2];
81 for(int i = 0; i < 2; ++i)
82 apTile[i] = (CTile *)aMaps[i].GetData(Index: apTilemap[i]->m_Data);
83
84 for(int y = 0; y < apTilemap[0]->m_Height; y++)
85 {
86 for(int x = 0; x < apTilemap[0]->m_Width; x++)
87 {
88 int Pos = y * apTilemap[0]->m_Width + x;
89 if(apTile[0][Pos].m_Index != apTile[1][Pos].m_Index || apTile[0][Pos].m_Flags != apTile[1][Pos].m_Flags)
90 {
91 dbg_msg(sys: "map_diff", fmt: "[%d:%s] %dx%d: (index: %d, flags: %d) != (index: %d, flags: %d)", aLayersNum[0], aaName[0], x, y, apTile[0][Pos].m_Index, apTile[0][Pos].m_Flags, apTile[1][Pos].m_Index, apTile[1][Pos].m_Flags);
92 }
93 }
94 }
95 }
96
97 return true;
98}
99
100int main(int argc, const char *argv[])
101{
102 CCmdlineFix CmdlineFix(&argc, &argv);
103 std::vector<std::shared_ptr<ILogger>> vpLoggers;
104 std::shared_ptr<ILogger> pStdoutLogger = std::shared_ptr<ILogger>(log_logger_stdout());
105 if(pStdoutLogger)
106 {
107 vpLoggers.push_back(x: pStdoutLogger);
108 }
109 IOHANDLE LogFile = io_open(filename: "map_diff.txt", flags: IOFLAG_WRITE);
110 if(LogFile)
111 {
112 vpLoggers.push_back(x: std::shared_ptr<ILogger>(log_logger_file(file: LogFile)));
113 }
114 log_set_global_logger(logger: log_logger_collection(vpLoggers: std::move(vpLoggers)).release());
115
116 if(argc != 3)
117 {
118 dbg_msg(sys: "usage", fmt: "%s map1 map2", argv[0]);
119 return -1;
120 }
121
122 std::unique_ptr<IStorage> pStorage = CreateLocalStorage();
123 if(!pStorage)
124 {
125 log_error("map_diff", "Error creating local storage");
126 return -1;
127 }
128
129 return Process(pStorage: pStorage.get(), pMapNames: &argv[1]) ? 0 : 1;
130}
131