352 lines
12 KiB
C++
Executable File
352 lines
12 KiB
C++
Executable File
#include "ApplicationProject.h"
|
|
#include "ApplicationProjectReader.h"
|
|
#include "ApplicationProjectWriter.h"
|
|
|
|
#include <noggit/application/Configuration/NoggitApplicationConfiguration.hpp>
|
|
#include <noggit/World.h>
|
|
#include <noggit/MapChunk.h>
|
|
#include <noggit/MapTile.h>
|
|
|
|
#include <blizzard-database-library/include/BlizzardDatabase.h>
|
|
#include <blizzard-archive-library/include/CASCArchive.hpp>
|
|
#include <string>
|
|
#include <blizzard-archive-library/include/Exception.hpp>
|
|
#include <blizzard-archive-library/include/ClientFile.hpp>
|
|
|
|
#include <QFile>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QMessageBox>
|
|
|
|
namespace Noggit::Project
|
|
{
|
|
ApplicationProject::ApplicationProject(std::shared_ptr<Application::NoggitApplicationConfiguration> configuration)
|
|
{
|
|
_active_project = nullptr;
|
|
_configuration = configuration;
|
|
}
|
|
|
|
void ApplicationProject::createProject(std::filesystem::path const& project_path, std::filesystem::path const& client_path, std::string const& client_version, std::string const& project_name)
|
|
{
|
|
if (!std::filesystem::exists(project_path))
|
|
std::filesystem::create_directory(project_path);
|
|
|
|
auto project = NoggitProject();
|
|
project.ProjectName = project_name;
|
|
project.projectVersion = ClientVersionFactory::mapToEnumVersion(client_version);
|
|
project.ClientPath = client_path.generic_string();
|
|
project.ProjectPath = project_path.generic_string();
|
|
|
|
auto project_writer = ApplicationProjectWriter();
|
|
project_writer.saveProject(&project, project_path);
|
|
}
|
|
|
|
std::shared_ptr<NoggitProject> ApplicationProject::loadProject(std::filesystem::path const& project_path)
|
|
{
|
|
ApplicationProjectReader project_reader{};
|
|
auto project = project_reader.readProject(project_path);
|
|
|
|
if (!project.has_value())
|
|
{
|
|
LogError << "loadProject() failed, Project is null" << std::endl;
|
|
return {};
|
|
}
|
|
else
|
|
{
|
|
Log << "loadProject(): Loading Project Data" << std::endl;
|
|
}
|
|
|
|
|
|
project_reader.readPalettes(&project.value());
|
|
project_reader.readObjectSelectionGroups(&project.value());
|
|
|
|
std::string dbd_file_directory = _configuration->ApplicationDatabaseDefinitionsPath;
|
|
|
|
BlizzardDatabaseLib::Structures::Build client_build("3.3.5.12340");
|
|
auto client_archive_version = BlizzardArchive::ClientVersion::WOTLK;
|
|
auto client_archive_locale = BlizzardArchive::Locale::AUTO;
|
|
if (project->projectVersion == ProjectVersion::SL)
|
|
{
|
|
client_archive_version = BlizzardArchive::ClientVersion::SL;
|
|
client_build = BlizzardDatabaseLib::Structures::Build("9.1.0.39584");
|
|
client_archive_locale = BlizzardArchive::Locale::enUS;
|
|
}
|
|
|
|
else if (project->projectVersion == ProjectVersion::WOTLK)
|
|
{
|
|
client_archive_version = BlizzardArchive::ClientVersion::WOTLK;
|
|
client_build = BlizzardDatabaseLib::Structures::Build("3.3.5.12340");
|
|
client_archive_locale = BlizzardArchive::Locale::AUTO;
|
|
}
|
|
|
|
else
|
|
{
|
|
LogError << "Unsupported project version" << std::endl;
|
|
return {};
|
|
}
|
|
|
|
project->ClientDatabase = std::make_shared<BlizzardDatabaseLib::BlizzardDatabase>(dbd_file_directory, client_build);
|
|
|
|
Log << "Loading Client Path : " << project->ClientPath << std::endl;
|
|
|
|
try
|
|
{
|
|
project->ClientData = std::make_shared<BlizzardArchive::ClientData>(
|
|
project->ClientPath, client_archive_version, client_archive_locale, project_path.generic_string());
|
|
}
|
|
catch (BlizzardArchive::Exceptions::Locale::LocaleNotFoundError& e)
|
|
{
|
|
LogError << e.what() << std::endl;
|
|
QMessageBox::critical(nullptr, "Error", e.what());
|
|
return {};
|
|
}
|
|
catch (BlizzardArchive::Exceptions::Locale::IncorrectLocaleModeError& e)
|
|
{
|
|
LogError << e.what() << std::endl;
|
|
QMessageBox::critical(nullptr, "Error", e.what());
|
|
return {};
|
|
}
|
|
catch (BlizzardArchive::Exceptions::Archive::ArchiveOpenError& e)
|
|
{
|
|
LogError << e.what() << std::endl;
|
|
QMessageBox::critical(nullptr, "Error", e.what());
|
|
return {};
|
|
}
|
|
catch (...)
|
|
{
|
|
LogError << "Failed loading Client data. Unhandled exception." << std::endl;
|
|
return {};
|
|
}
|
|
|
|
if (!project->ClientData)
|
|
{
|
|
LogError << "Failed loading Client data." << std::endl;
|
|
return {};
|
|
}
|
|
|
|
// Log << "Client Version: " << static_cast<int>(project->ClientData->version()) << std::endl;
|
|
|
|
Log << "Client Locale: " << project->ClientData->locale_name() << std::endl;
|
|
|
|
for (auto const loaded_achive : *project->ClientData->loadedArchives())
|
|
{
|
|
Log << "Loaded client Archive: " << loaded_achive->path() << std::endl;
|
|
}
|
|
|
|
// QSettings settings;
|
|
// bool modern_features = settings.value("modern_features", false).toBool();
|
|
bool modern_features = _configuration->modern_features;
|
|
if (modern_features)
|
|
{
|
|
Log << "Modern Features Enabled" << std::endl;
|
|
loadExtraData(project.value());
|
|
}
|
|
else
|
|
{
|
|
Log << "Modern Features Disabled" << std::endl;
|
|
}
|
|
return std::make_shared<NoggitProject>(project.value());
|
|
}
|
|
|
|
void ApplicationProject::loadExtraData(NoggitProject& project)
|
|
{
|
|
std::filesystem::path extraDataFolder = (project.ProjectPath);
|
|
extraDataFolder /= "extraData";
|
|
|
|
Log << "Loading extra data from " << extraDataFolder << std::endl;
|
|
|
|
if (std::filesystem::exists(extraDataFolder) && std::filesystem::is_directory(extraDataFolder))
|
|
{
|
|
for (const auto& entry : std::filesystem::directory_iterator(extraDataFolder))
|
|
{
|
|
if (entry.path().extension() == ".cfg")
|
|
{
|
|
QFile input_file(QString::fromStdString(entry.path().generic_string()));
|
|
input_file.open(QIODevice::ReadOnly);
|
|
QJsonParseError err;
|
|
auto document = QJsonDocument().fromJson(input_file.readAll(), &err);
|
|
auto root = document.object();
|
|
auto keys = root.keys();
|
|
if (entry.path().stem() == "global")
|
|
{
|
|
for (auto const& entry : keys)
|
|
{
|
|
texture_heightmapping_data newData;
|
|
newData.uvScale = root[entry].toObject()["Scale"].toInt();
|
|
newData.heightOffset = root[entry].toObject()["HeightOffset"].toDouble();
|
|
newData.heightScale = root[entry].toObject()["HeightScale"].toDouble();
|
|
project.ExtraMapData.SetTextureHeightData_Global(entry.toStdString(), newData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void NoggitExtraMapData::SetTextureHeightData_Global(const std::string& texture, texture_heightmapping_data data, World* worldToUpdate)
|
|
{
|
|
TextureHeightData_Global[texture] = data;
|
|
if (worldToUpdate)
|
|
{
|
|
for (MapTile* tile : worldToUpdate->mapIndex.loaded_tiles())
|
|
{
|
|
tile->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
|
tile->forceAlphaUpdate();
|
|
tile->forceRecalcExtents();
|
|
}
|
|
}
|
|
}
|
|
void NoggitExtraMapData::SetTextureHeightDataForADT(int mapID, const TileIndex& ti, const std::string& texture, texture_heightmapping_data data, World* worldToUpdate)
|
|
{
|
|
TextureHeightData_ADT[mapID][ti.x][ti.z][texture] = data;
|
|
if (worldToUpdate)
|
|
{
|
|
MapTile* tile = worldToUpdate->mapIndex.getTile(ti);
|
|
tile->registerChunkUpdate(ChunkUpdateFlags::ALPHAMAP);
|
|
tile->forceAlphaUpdate();
|
|
tile->forceRecalcExtents();
|
|
}
|
|
}
|
|
const texture_heightmapping_data NoggitExtraMapData::GetTextureHeightDataForADT(int mapID, const TileIndex& tileIndex, const std::string& texture) const
|
|
{
|
|
static texture_heightmapping_data defaultValue;
|
|
auto foundMapIter = TextureHeightData_ADT.find(mapID);
|
|
if (foundMapIter != TextureHeightData_ADT.end())
|
|
{
|
|
auto foundXIter = foundMapIter->second.find(tileIndex.x);
|
|
if (foundXIter != foundMapIter->second.end())
|
|
{
|
|
auto foundYIter = foundXIter->second.find(tileIndex.z);
|
|
if (foundYIter != foundXIter->second.end())
|
|
{
|
|
auto foundTexData = foundYIter->second.find(texture);
|
|
if (foundTexData != foundYIter->second.end())
|
|
{
|
|
return foundTexData->second;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
auto foundGenericSettings = TextureHeightData_Global.find(texture);
|
|
if (foundGenericSettings != TextureHeightData_Global.end())
|
|
{
|
|
return foundGenericSettings->second;
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
ProjectVersion ClientVersionFactory::mapToEnumVersion(std::string const& projectVersion)
|
|
{
|
|
if (projectVersion == "Wrath Of The Lich King")
|
|
return ProjectVersion::WOTLK;
|
|
if (projectVersion == "Shadowlands")
|
|
return ProjectVersion::SL;
|
|
|
|
assert(false);
|
|
}
|
|
|
|
std::string ClientVersionFactory::MapToStringVersion(ProjectVersion const& projectVersion)
|
|
{
|
|
if (projectVersion == ProjectVersion::WOTLK)
|
|
return std::string("Wrath Of The Lich King");
|
|
if (projectVersion == ProjectVersion::SL)
|
|
return std::string("Shadowlands");
|
|
|
|
assert(false);
|
|
}
|
|
|
|
NoggitProject::NoggitProject()
|
|
{
|
|
_projectWriter = std::make_shared<ApplicationProjectWriter>();
|
|
}
|
|
|
|
unsigned int NoggitProject::buildId()
|
|
{
|
|
return ClientDatabase->getBuild();
|
|
}
|
|
|
|
void NoggitProject::createBookmark(const NoggitProjectBookmarkMap& bookmark)
|
|
{
|
|
Bookmarks.push_back(bookmark);
|
|
|
|
_projectWriter->saveProject(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
|
|
void NoggitProject::deleteBookmark()
|
|
{
|
|
}
|
|
|
|
void NoggitProject::pinMap(int map_id, const std::string& map_name)
|
|
{
|
|
auto pinnedMap = NoggitProjectPinnedMap();
|
|
pinnedMap.MapName = map_name;
|
|
pinnedMap.MapId = map_id;
|
|
|
|
auto pinnedMapFound = std::find_if(std::begin(PinnedMaps), std::end(PinnedMaps),
|
|
[&](Project::NoggitProjectPinnedMap pinnedMap)
|
|
{
|
|
return pinnedMap.MapId == map_id;
|
|
});
|
|
|
|
if (pinnedMapFound != std::end(PinnedMaps))
|
|
return;
|
|
|
|
PinnedMaps.push_back(pinnedMap);
|
|
|
|
_projectWriter->saveProject(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
|
|
void NoggitProject::unpinMap(int mapId)
|
|
{
|
|
PinnedMaps.erase(std::remove_if(PinnedMaps.begin(), PinnedMaps.end(),
|
|
[=](NoggitProjectPinnedMap pinnedMap)
|
|
{
|
|
return pinnedMap.MapId == mapId;
|
|
}),
|
|
PinnedMaps.end());
|
|
|
|
_projectWriter->saveProject(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
|
|
void NoggitProject::saveTexturePalette(const NoggitProjectTexturePalette& new_texture_palette)
|
|
{
|
|
TexturePalettes.erase(std::remove_if(TexturePalettes.begin(), TexturePalettes.end(),
|
|
[=](NoggitProjectTexturePalette texture_palette)
|
|
{
|
|
return texture_palette.MapId == new_texture_palette.MapId;
|
|
}),
|
|
TexturePalettes.end());
|
|
|
|
TexturePalettes.push_back(new_texture_palette);
|
|
|
|
_projectWriter->savePalettes(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
|
|
void NoggitProject::saveObjectPalette(const NoggitProjectObjectPalette& new_object_palette)
|
|
{
|
|
ObjectPalettes.erase(std::remove_if(ObjectPalettes.begin(), ObjectPalettes.end(),
|
|
[=](NoggitProjectObjectPalette obj_palette)
|
|
{
|
|
return obj_palette.MapId == new_object_palette.MapId;
|
|
}),
|
|
ObjectPalettes.end());
|
|
|
|
ObjectPalettes.push_back(new_object_palette);
|
|
|
|
_projectWriter->savePalettes(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
|
|
void NoggitProject::saveObjectSelectionGroups(const NoggitProjectSelectionGroups& new_selection_groups)
|
|
{
|
|
ObjectSelectionGroups.erase(std::remove_if(ObjectSelectionGroups.begin(), ObjectSelectionGroups.end(),
|
|
[=](NoggitProjectSelectionGroups proj_selection_group)
|
|
{
|
|
return proj_selection_group.MapId == new_selection_groups.MapId;
|
|
}),
|
|
ObjectSelectionGroups.end());
|
|
|
|
ObjectSelectionGroups.push_back(new_selection_groups);
|
|
|
|
_projectWriter->saveObjectSelectionGroups(this, std::filesystem::path(ProjectPath));
|
|
}
|
|
};
|