Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/utility/map_grep.cpp
blob: 9f8bb002e297c130dae1782b579b9e66c52e55c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "StarFile.hpp"
#include "StarLogging.hpp"
#include "StarRootLoader.hpp"
#include "StarDungeonTMXPart.hpp"

using namespace Star;
using namespace Star::Dungeon;

typedef String TileName;
typedef pair<String, String> TileProperty;

typedef MVariant<TileName, TileProperty> MatchCriteria;

struct SearchParameters {
  MatchCriteria criteria;
};

typedef function<void(String, Vec2I)> MatchReporter;

String const MapFilenameSuffix = ".json";

Maybe<String> matchTile(SearchParameters const& search, Tiled::Tile const& tile) {
  Tiled::Properties const& properties = tile.properties;
  if (search.criteria.is<TileName>()) {
    if (auto tileName = properties.opt<String>("//name"))
      if (tileName->regexMatch(search.criteria.get<TileName>()))
        return tileName;
  } else {
    String propertyName;
    String matchValue;
    tie(propertyName, matchValue) = search.criteria.get<TileProperty>();
    if (auto propertyValue = properties.opt<String>(propertyName))
      if (propertyValue->regexMatch(matchValue))
        return properties.opt<String>("//name").value("?");
  }
  return {};
}

void grepTileLayer(SearchParameters const& search, TMXMapPtr map, TMXTileLayerPtr tileLayer, MatchReporter callback) {
  tileLayer->forEachTile(map.get(),
      [&](Vec2I pos, Tile const& tile) {
        if (auto tileName = matchTile(search, static_cast<Tiled::Tile const&>(tile)))
          callback(*tileName, pos);
        return false;
      });
}

void grepObjectGroup(SearchParameters const& search, TMXObjectGroupPtr objectGroup, MatchReporter callback) {
  for (auto object : objectGroup->objects()) {
    if (auto tileName = matchTile(search, object->tile()))
      callback(*tileName, object->pos());
  }
}

void grepMap(SearchParameters const& search, String file) {
  auto map = make_shared<TMXMap>(Json::parseJson(File::readFileString(file)));

  for (auto tileLayer : map->tileLayers())
    grepTileLayer(search, map, tileLayer, [&](String const& tileName, Vec2I const& pos) {
        coutf("{}: {}: {} @ {}\n", file, tileLayer->name(), tileName, pos);
      });

  for (auto objectGroup : map->objectGroups())
    grepObjectGroup(search, objectGroup, [&](String const& tileName, Vec2I const& pos) {
        coutf("{}: {}: {} @ {}\n", file, objectGroup->name(), tileName, pos);
      });
}

void grepDirectory(SearchParameters const& search, String directory) {
  for (pair<String, bool> entry : File::dirList(directory)) {
    if (entry.second)
      grepDirectory(search, File::relativeTo(directory, entry.first));
    else if (entry.first.endsWith(MapFilenameSuffix))
      grepMap(search, File::relativeTo(directory, entry.first));
  }
}

void grepPath(SearchParameters const& search, String path) {
  if (File::isFile(path)) {
    grepMap(search, path);
  } else if (File::isDirectory(path)) {
    grepDirectory(search, path);
  }
}

MatchCriteria parseMatchCriteria(String const& criteriaStr) {
  if (criteriaStr.contains("=")) {
    StringList parts = criteriaStr.split('=', 1);
    return make_pair(parts[0], parts[1]);
  }
  return TileName(criteriaStr);
}

int main(int argc, char* argv[]) {
  try {
    RootLoader rootLoader({{}, {}, {}, LogLevel::Warn, false, {}});
    rootLoader.setSummary("Search Tiled map files for specific materials or objects.");
    rootLoader.addArgument("MaterialId|ObjectName|Property=Value", OptionParser::Required);
    rootLoader.addArgument("JsonMapFile", OptionParser::Multiple);

    RootUPtr root;
    OptionParser::Options options;
    tie(root, options) = rootLoader.commandInitOrDie(argc, argv);

    SearchParameters search = {parseMatchCriteria(options.arguments[0])};
    StringList files = options.arguments.slice(1);

    for (auto file : files)
      grepPath(search, file);

    return 0;
  } catch (std::exception const& e) {
    cerrf("exception caught: {}\n", outputException(e, true));
    return 1;
  }
}