1#include "Data/Serializer.h"
2#include "Utils/Utils.h"
3#include "Base/ModelImporter.h"
4#include "Data/ProjectData.h"
5#include "Data/VersionInfo.h"
6#include "Data/ApplicationState.h"
7#include "Misc/AppStyles.h"
8#include "Shading/ShadingManager.h"
12#include "dirent/dirent.h"
23#define TRY_CATCH_ERR_SERIALIZE(code, message) try{ code } catch(...){onError(message, true);}
24#define TRY_CATCH_ERR_DESERIALIZE(code, message) try{ code } catch(...){onError(message, false);}
25#define TRY_CATCH_ERR_DESERIALIZE_WITH_CODE(code, message, errorCode) try{ code } catch(...){onError(message, false); errorCode}
27static void zip_walk(
struct zip_t *zip,
const char *path,
bool isFristLayer =
true, std::string prevPath =
"")
31 char fullpath[MAX_PATH];
33 memset(fullpath, 0, MAX_PATH);
37 while ((entry = readdir(dir)))
40 if (!strcmp(entry->d_name,
".\0") || !strcmp(entry->d_name,
"..\0"))
45 snprintf(fullpath,
sizeof(fullpath),
"%s/%s", path, entry->d_name);
48 if (S_ISDIR(s.st_mode))
50 zip_walk(zip, fullpath,
false, prevPath + entry->d_name + PATH_SEPARATOR);
55 zip_entry_open(zip, (prevPath + entry->d_name).c_str());
56 zip_entry_fwrite(zip, fullpath);
68 onError = [](std::string message,
bool whileSerialize)
70 std::cout << (whileSerialize ?
"Serailizer Error : " :
"Deserailizer Error : ") << message << std::endl;;
74Serializer::Serializer(
ApplicationState *state, std::function<
void(std::string,
bool)> errorFunc)
79Serializer::~Serializer()
87 data[
"type"] =
"SAVEFILE";
88 data[
"serailizerVersion"] = TERR3D_SERIALIZER_VERSION;
89 data[
"maxSerailizerVersion"] = TERR3D_MAX_SERIALIZER_VERSION;
90 data[
"minSerailizerVersion"] = TERR3D_MIN_SERIALIZER_VERSION;
91 data[
"versionHash"] = MD5File(GetExecutablePath()).ToString();
92 data[
"name"] =
"TerraForge3D v2.2.0";
93 data[
"mode"] = appState->mode;
95 TRY_CATCH_ERR_SERIALIZE(data[
"appData"] = appState->globals.appData;,
"Failed to save App Data");
96 TRY_CATCH_ERR_SERIALIZE(data[
"appStyles"] = GetStyleData();,
"Failed to save app styles");
97 TRY_CATCH_ERR_SERIALIZE(data[
"imguiData"] = std::string(ImGui::SaveIniSettingsToMemory());,
"Failed to save ImGui Data.");
98 TRY_CATCH_ERR_SERIALIZE(data[
"camera"] = appState->cameras.Save();,
"Failed to save cameras.");
99 TRY_CATCH_ERR_SERIALIZE(data[
"windows"] = appState->windows.Save();,
"Failed to save window states");
100 TRY_CATCH_ERR_SERIALIZE(data[
"states"] = appState->states.Save();,
"Failed to save states.");
101 TRY_CATCH_ERR_SERIALIZE(data[
"globals"] = appState->globals.Save();,
"Failed to save globals.");
102 TRY_CATCH_ERR_SERIALIZE(data[
"sea"] = appState->seaManager->Save();,
"Failed to save Sea.");
103 TRY_CATCH_ERR_SERIALIZE(data[
"foliage"] = appState->foliageManager->Save();,
"Failed to save foliage manager.");
104 TRY_CATCH_ERR_SERIALIZE(data[
"projectID"] = appState->projectManager->GetId();,
"Failed to save project id.");
105 TRY_CATCH_ERR_SERIALIZE(data[
"textureBaker"] = appState->textureBaker->Save();,
"Failed to save texture baker settings.");
106 TRY_CATCH_ERR_SERIALIZE(appState->projectManager->SaveDatabase(); data[
"projectDatabase"] = appState->projectManager->GetDatabase();,
"Failed to save project database.");
107 TRY_CATCH_ERR_SERIALIZE(data[
"lighting"] = appState->lightManager->Save();,
"Failed to save lighting data.");
108 TRY_CATCH_ERR_SERIALIZE(data[
"shading"] = appState->shadingManager->Save();,
"Failed to save shading data.");
109 TRY_CATCH_ERR_SERIALIZE(data[
"generators"] = appState->meshGenerator->Save();,
"Failed to save generators.");
110 TRY_CATCH_ERR_SERIALIZE(
112 if (!appState->mode == ApplicationMode::CUSTOM_BASE)
114 std::string baseHash = MD5File(appState->globals.currentBaseModelPath)
116 std::string projectAsset = appState->projectManager->GetAsset(baseHash);
118 if (projectAsset ==
"")
120 MkDir(appState->projectManager->GetResourcePath() + PATH_SEPARATOR
"models");
121 CopyFileData(appState->globals.currentBaseModelPath, appState->projectManager->GetResourcePath() + PATH_SEPARATOR
"models" PATH_SEPARATOR + baseHash + appState->globals.currentBaseModelPath.substr(appState->globals.currentBaseModelPath.find_last_of(
".")));
122 appState->projectManager->RegisterAsset(baseHash,
"models" PATH_SEPARATOR + baseHash + appState->globals.currentBaseModelPath.substr(appState->globals.currentBaseModelPath.find_last_of(
".")));
125 data[
"baseid"] = baseHash;
127 ,
"Failed to save custom base model."
132void Serializer::PackProject(std::string path)
134 if (path.find(
".terr3dpack") == std::string::npos)
136 path = path +
".terr3dpack";
140 std::ofstream outfile;
141 outfile.open(appState->projectManager->GetResourcePath() + PATH_SEPARATOR
"project.terr3d");
142 outfile << data.
dump(4,
' ',
false);
144 MkDir(GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
"temp");
145 std::string uid = GenerateId(64);
146 SaveFile(GetExecutableDir() +
"Data" + PATH_SEPARATOR
"temp" PATH_SEPARATOR + uid);
147 zip_t *packed = zip_open(path.c_str(), 9,
'w');
148 zip_walk(packed, appState->projectManager->GetResourcePath().c_str());
152void Serializer::LoadPackedProject(std::string path)
154 if (path.find(
".terr3dpack") == std::string::npos)
156 path = path +
".terr3dpack";
159 std::string uid = GenerateId(64);
160 MkDir(GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
"temp"
161 PATH_SEPARATOR
"pcache_" + uid);
162 zip_extract(path.c_str(), (GetExecutableDir() + PATH_SEPARATOR
"Data"
163 PATH_SEPARATOR
"temp" PATH_SEPARATOR
"pcache_" + uid).c_str(),
164 [](
const char *filename,
void *arg)
169 if (FileExists(GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
"temp" PATH_SEPARATOR
"pcache_" + uid + PATH_SEPARATOR
"project.terr3d",
true))
172 std::string sdata = ReadShaderSourceFile(GetExecutableDir() +
173 PATH_SEPARATOR
"Data" PATH_SEPARATOR
"temp" PATH_SEPARATOR
174 "pcache_" + uid + PATH_SEPARATOR
"project.terr3d", &tmp);
176 if (sdata.size() <= 0)
178 Log(
"Emppty Project File!");
191 Log(
"Failed to Parse Project file!");
195 std::string projId = data[
"projectID"];
196 zip_extract(path.c_str(), (GetExecutableDir() + PATH_SEPARATOR
"Data"
197 PATH_SEPARATOR
"cache" PATH_SEPARATOR
"project_data"
198 PATH_SEPARATOR
"project_" + projId).c_str(), [](
const char
199 *filename,
void *arg)
201 Log(std::string(
"Extracted ") + filename);
204 std::string oriDir = path.substr(0, path.rfind(PATH_SEPARATOR));
205 std::string oriName = path.substr(path.rfind(PATH_SEPARATOR) + 1);
206 CopyFileData((GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
207 "cache" PATH_SEPARATOR
"project_data" PATH_SEPARATOR
208 "project_" + projId + PATH_SEPARATOR
209 "project.terr3d").c_str(), oriDir + PATH_SEPARATOR +
210 oriName +
".terr3d");
211 LoadFile(oriDir + PATH_SEPARATOR + oriName +
".terr3d");
216 Log(
"Not a valid terr3dpack file!");
220void Serializer::SaveFile(std::string path)
222 if (path.size() <= 3)
227 if (path.find(
".terr3d") == std::string::npos)
229 path = path +
".terr3d";
232 if (path != appState->globals.currentOpenFilePath)
234 appState->globals.currentOpenFilePath = path;
238 std::ofstream outfile;
239 outfile.open(appState->projectManager->GetResourcePath() + PATH_SEPARATOR
"project.terr3d");
240 outfile << data.
dump(4,
' ',
false);
243 outfile << data.
dump(4,
' ',
false);
247void Serializer::LoadFile(std::string path)
249 if (path.size() <= 3)
254 if (path.find(
".terr3d") == std::string::npos)
256 path = path +
".terr3d";
260 std::string sdata = ReadShaderSourceFile(path, &flagRd);
264 Log(
"Could not read file : " + path);
268 if (sdata.size() == 0)
283 Log(
"Failed to Parse file : " + path);
286 if (path != appState->globals.currentOpenFilePath)
288 appState->globals.currentOpenFilePath = path;
297 std::cout <<
"Wating for remesh cycle to finish ...\n";
299 while (appState->states.remeshing);
301 std::cout <<
"Finished remesing." << std::endl;
302 TRY_CATCH_ERR_DESERIALIZE(
304 if (data[
"versionHash"] != MD5File(GetExecutablePath()).ToString())
306 onError(
"The file you are tryng to open was made with a different version of TerraForge3D!\nTrying to check Serializer compatibility",
false);
308 ,
"Failed to verify file version."
310 TRY_CATCH_ERR_DESERIALIZE_WITH_CODE(
311 int serializerVersion = data[
"serailizerVersion"];
313 if (serializerVersion < TERR3D_MIN_SERIALIZER_VERSION)
315 onError(
"This file cannot be opened as it was serialized using serializer V" + std::to_string(serializerVersion) +
" but the minimum serializer version required is V" + std::to_string(TERR3D_MIN_SERIALIZER_VERSION),
false);
319 if (serializerVersion > TERR3D_MAX_SERIALIZER_VERSION)
321 onError(
"This file cannot be opened as it was serialized using serializer V" + std::to_string(serializerVersion) +
" but the maximum serializer version supported is V" + std::to_string(TERR3D_MAX_SERIALIZER_VERSION),
false);
324 ,
"Failed to verify Serializer",
328 if (data[
"type"] !=
"SAVEFILE")
330 onError(
"This file is not a savefile.",
false);
334 TRY_CATCH_ERR_DESERIALIZE(LoadThemeFromStr(data[
"styleData"]);,
"Failed to load theme.");
335 TRY_CATCH_ERR_DESERIALIZE(appState->globals.appData = data[
"appData"];,
"Failed to app data.");
336 TRY_CATCH_ERR_DESERIALIZE(appState->globals.appData = data[
"appData"];,
"Failed to app data.");
337 TRY_CATCH_ERR_DESERIALIZE(appState->mode = data[
"mode"];,
"Failed to app mode.");
338 TRY_CATCH_ERR_DESERIALIZE(appState->projectManager->SetId(data[
"projectID"]);,
"Failed to load Project ID.");
339 TRY_CATCH_ERR_DESERIALIZE(appState->projectManager->SetDatabase(data[
"projectDatabase"]);,
"Failed to load project database.");
340 std::cout <<
"Loaded Project ID : " << appState->projectManager->GetId() << std::endl;
341 TRY_CATCH_ERR_DESERIALIZE(appState->cameras.Load(data[
"camera"]);,
"Failed to load camera.");
342 TRY_CATCH_ERR_DESERIALIZE(appState->windows.Load(data[
"windows"]);,
"Failed to load windows.");
343 TRY_CATCH_ERR_DESERIALIZE(appState->states.Load(data[
"states"]);,
"Failed to load states.");
344 TRY_CATCH_ERR_DESERIALIZE(appState->globals.Load(data[
"globals"]);,
"Failed to load globals.");
345 TRY_CATCH_ERR_DESERIALIZE(appState->textureBaker->Load(data[
"textureBaker"]);,
"Failed to load texture baker settings.");
346 TRY_CATCH_ERR_DESERIALIZE(appState->seaManager->Load(data[
"sea"]);,
"Failed to load sea.");
347 TRY_CATCH_ERR_DESERIALIZE(appState->foliageManager->Load(data[
"foliage"]);,
"Failed to load foliage.");
348 TRY_CATCH_ERR_DESERIALIZE(appState->lightManager->Load(data[
"lighting"]);,
"Failed to load lighting.");
349 TRY_CATCH_ERR_DESERIALIZE(appState->meshGenerator->Load(data[
"generators"]);,
"Failed to load generators.");
350 TRY_CATCH_ERR_DESERIALIZE(appState->shadingManager->Load(data[
"shading"]);,
"Failed to load shading data.");
351 TRY_CATCH_ERR_DESERIALIZE_WITH_CODE(
353 if (appState->mode == ApplicationMode::CUSTOM_BASE)
355 std::string baseHash = data[
"baseid"];
356 std::string projectAsset = appState->projectManager->GetAsset(baseHash);
358 if (projectAsset ==
"")
360 std::cout <<
"Failed to load base model from save file!\n";
361 appState->states.usingBase = true;
366 if (!appState->models.customBase)
368 delete appState->models.customBase;
369 delete appState->models.customBaseCopy;
372 appState->globals.currentBaseModelPath = appState->projectManager->GetResourcePath() + PATH_SEPARATOR + projectAsset;
373 appState->models.customBase = LoadModel(appState->globals.currentBaseModelPath);
374 appState->models.customBaseCopy = LoadModel(appState->globals.currentBaseModelPath);
375 appState->states.usingBase =
false;
378 ,
"Failed to load custom base model. Falling back to plane.",
380 if (!appState->models.customBase)
382 delete appState->models.customBase;
383 delete appState->models.customBaseCopy;
385appState->states.usingBase =
true;
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json parse(InputType &&i, const parser_callback_t cb=nullptr, const bool allow_exceptions=true, const bool ignore_comments=false)
deserialize from a compatible input
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
a class to store JSON values
basic_json<> json
default JSON class