载入中...
搜索中...
未找到
TileLayerReloader.cpp
浏览该文件的文档.
1// Reloads tile layers when their Tiled JSON changes, and re-binds tilesets when
2// the atlas image they reference changes.
3//
4// Registered at kConsumer priority so graphics has already re-uploaded the
5// atlas by the time the layers pick it up again.
6
8#include "common/Capability.h"
9#include "common/ECS.h"
10#include "common/Module.h"
11#include "graphics/Graphics.h"
12#include "map/TileConfig.h"
13#include "map/TileLayer.h"
14
15#include <cctype>
16#include <string>
17
18namespace eve::map {
19namespace {
20
21std::string extensionOf(const std::string &path) {
22 const auto pos = path.find_last_of('.');
23 if (pos == std::string::npos) return {};
24 std::string ext = path.substr(pos);
25 for (char &c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
26 return ext;
27}
28
29bool isImagePath(const std::string &path) {
30 const std::string ext = extensionOf(path);
31 return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp" || ext == ".tga" ||
32 ext == ".gif" || ext == ".webp" || ext == ".exr" || ext == ".hdr";
33}
34
36std::string normalize(std::string path) {
37 for (char &c : path) {
38 if (c == '\\') c = '/';
39 }
40 while (path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
41 while (path.size() > 1 && path.back() == '/') path.pop_back();
42 return path;
43}
44
45class TileLayerReloader : public eve::caps::IAssetReloader {
46public:
47 const char *reloadKind() const override { return "tilemap"; }
48
49 bool handlesPath(const std::string &normPath) const override {
50 const std::string ext = extensionOf(normPath);
51 return ext == ".json" || isImagePath(normPath);
52 }
53
54 bool reload(const std::string &normPath) override {
55 if (ecs::current()->getManager<TileLayer>() == nullptr) return false;
56 return isImagePath(normPath) ? rebindTileset(normPath) : reloadConfig(normPath);
57 }
58
59private:
60 static bool reloadConfig(const std::string &normPath) {
61 int reloaded = 0;
62 auto view = ecs::View<TileLayer, TileLayer::Config, TileLayer::Resource>();
63 for (auto it = view.begin(); it != view.end(); ++it) {
64 auto [cfg, res] = *it;
65 if (!cfg->entity || res->path.empty()) continue;
66 if (normalize(res->path) != normPath) continue;
67 if (reloadConfigFile(cfg->entity, nullptr)) ++reloaded;
68 }
69 return reloaded > 0;
70 }
71
72 static bool rebindTileset(const std::string &normPath) {
73 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
74 if (!gfx) return false;
75
76 bool any = false;
77 auto view = ecs::View<TileLayer, TileLayer::Config, TileLayer::Resource, TileLayer::Tileset>();
78 for (auto it = view.begin(); it != view.end(); ++it) {
79 auto [cfg, res, ts] = *it;
80 if (!cfg->entity || res->texturePath.empty()) continue;
81 if (normalize(res->texturePath) != normPath) continue;
82 try {
83 cfg->entity->setTileset(gfx->newTextureFromFile(normPath), ts->firstGid,
84 ts->columns, ts->margin, ts->spacing);
85 any = true;
86 } catch (...) {
87 }
88 }
89 return any;
90 }
91};
92
93struct Register {
94 Register() {
95 static TileLayerReloader reloader;
98 }
99} g_register;
100
101} // namespace
102} // namespace eve::map
uint32_t c
glm::mat4 view
I * query()
Definition Capability.h:77
放置世界:格子占用(多通道)+ 地形语义 + 已放置建筑实例。 行为由 PlacementSystem 提供;本类暴露便于脚本绑定的薄封装方法。 坐标换算统一走 eve::grid(支持 rectang...
bool reloadConfigFile(TileLayer *layer, std::string *error)