Unify asset system: one asset set, always high-res

Remove HDPackManager, expansion overlay manifests, and BLP size-comparison
logic. Assets now resolve through a single manifest with a simple override
directory (Data/override/) for future HD upgrades.
This commit is contained in:
Kelsi 2026-02-15 04:18:34 -08:00
parent 1bc7b12b20
commit d7e2b26af7
13 changed files with 31 additions and 658 deletions

View file

@ -42,6 +42,7 @@ bool AssetManager::initialize(const std::string& dataPath_) {
}
dataPath = dataPath_;
overridePath_ = dataPath + "/override";
LOG_INFO("Initializing asset manager with data path: ", dataPath);
setupFileCacheBudget();
@ -58,6 +59,10 @@ bool AssetManager::initialize(const std::string& dataPath_) {
return false;
}
if (std::filesystem::is_directory(overridePath_)) {
LOG_INFO("Override directory found: ", overridePath_);
}
initialized = true;
LOG_INFO("Asset manager initialized: ", manifest_.getEntryCount(),
" files indexed (file cache: ", fileCacheBudget / (1024 * 1024), " MB)");
@ -104,97 +109,18 @@ void AssetManager::shutdown() {
}
clearCache();
overlayLayers_.clear();
initialized = false;
}
bool AssetManager::addOverlayManifest(const std::string& manifestPath, int priority, const std::string& id) {
// Check for duplicate
for (const auto& layer : overlayLayers_) {
if (layer.id == id) {
LOG_WARNING("Overlay '", id, "' already loaded, skipping");
return false;
}
}
ManifestLayer layer;
layer.priority = priority;
layer.id = id;
if (!layer.manifest.load(manifestPath)) {
LOG_ERROR("Failed to load overlay manifest: ", manifestPath);
return false;
}
overlayLayers_.push_back(std::move(layer));
// Sort by priority descending (highest priority first)
std::sort(overlayLayers_.begin(), overlayLayers_.end(),
[](const ManifestLayer& a, const ManifestLayer& b) {
return a.priority > b.priority;
});
LOG_INFO("Added overlay '", id, "' (priority ", priority, ", ",
overlayLayers_.back().manifest.getEntryCount(), " files) from ", manifestPath);
return true;
}
void AssetManager::removeOverlay(const std::string& id) {
auto it = std::remove_if(overlayLayers_.begin(), overlayLayers_.end(),
[&id](const ManifestLayer& layer) { return layer.id == id; });
if (it != overlayLayers_.end()) {
overlayLayers_.erase(it, overlayLayers_.end());
// Clear file cache since overlay removal changes file resolution
{
std::lock_guard<std::mutex> lock(cacheMutex);
fileCache.clear();
fileCacheTotalBytes = 0;
}
LOG_INFO("Removed overlay '", id, "', file cache cleared");
}
}
std::vector<std::string> AssetManager::getOverlayIds() const {
std::vector<std::string> ids;
ids.reserve(overlayLayers_.size());
for (const auto& layer : overlayLayers_) {
ids.push_back(layer.id);
}
return ids;
}
std::string AssetManager::resolveLayeredPath(const std::string& normalizedPath) const {
// For textures (.blp), pick the highest-resolution variant across overlays/base.
// Turtle/classic overlays can include lower-res textures; the base dataset may have higher-res.
auto isBlpTexture = [&]() -> bool {
return normalizedPath.size() >= 4 &&
normalizedPath.compare(normalizedPath.size() - 4, 4, ".blp") == 0;
};
if (isBlpTexture()) {
uint64_t bestSize = 0;
std::string bestFsPath;
auto consider = [&](const AssetManifest& m) {
if (const auto* e = m.lookup(normalizedPath)) {
if (e->size > bestSize) {
bestSize = e->size;
bestFsPath = m.getBasePath() + "/" + e->filesystemPath;
}
std::string AssetManager::resolveFile(const std::string& normalizedPath) const {
// Check override directory first (for HD upgrades, custom textures)
if (!overridePath_.empty()) {
const auto* entry = manifest_.lookup(normalizedPath);
if (entry && !entry->filesystemPath.empty()) {
std::string overrideFsPath = overridePath_ + "/" + entry->filesystemPath;
if (LooseFileReader::fileExists(overrideFsPath)) {
return overrideFsPath;
}
};
for (const auto& layer : overlayLayers_) consider(layer.manifest);
consider(manifest_);
if (!bestFsPath.empty()) return bestFsPath;
}
// Default: check overlay manifests first (sorted by priority desc)
for (const auto& layer : overlayLayers_) {
std::string fsPath = layer.manifest.resolveFilesystemPath(normalizedPath);
if (!fsPath.empty()) {
return fsPath;
}
}
// Fall back to base manifest
@ -239,7 +165,7 @@ BLPImage AssetManager::tryLoadPngOverride(const std::string& normalizedPath) con
std::string ext = normalizedPath.substr(normalizedPath.size() - 4);
if (ext != ".blp") return BLPImage();
std::string fsPath = resolveLayeredPath(normalizedPath);
std::string fsPath = resolveFile(normalizedPath);
if (fsPath.empty()) return BLPImage();
// Replace .blp/.BLP extension with .png
@ -398,12 +324,6 @@ bool AssetManager::fileExists(const std::string& path) const {
return false;
}
std::string normalized = normalizePath(path);
// Check overlay manifests first
for (const auto& layer : overlayLayers_) {
if (layer.manifest.hasEntry(normalized)) {
return true;
}
}
return manifest_.hasEntry(normalized);
}
@ -425,8 +345,8 @@ std::vector<uint8_t> AssetManager::readFile(const std::string& path) const {
}
}
// Read from filesystem using layered resolution (overlays first, then base)
std::string fsPath = resolveLayeredPath(normalized);
// Read from filesystem (override dir first, then base manifest)
std::string fsPath = resolveFile(normalized);
if (fsPath.empty()) {
return {};
}