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