Files
noggit-red/src/noggit/project/ApplicationProject.cpp
T1ti f66c525f90 port from mysql conenctor to QTSQL module
add new classes to manage connections
begin work on generic database for client and db
2025-09-19 03:44:34 +02:00

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));
}
};