50 #include <OgreException.h>
51 #include <OgreFileSystem.h>
52 #include <OgreFileSystemLayer.h>
53 #include <rapidjson/document.h>
54 #include <rapidjson/istreamwrapper.h>
55 #include <rapidjson/ostreamwrapper.h>
56 #include <rapidjson/writer.h>
62 CacheEntry::CacheEntry() :
67 custom_particles(false),
78 forwardcommands(false),
81 importcommands(false),
162 RoR::Log(
"[RoR|ModCache] Performing rebuild ...");
167 RoR::Log(
"[RoR|ModCache] Performing update ...");
182 RoR::Log(
"[RoR|ModCache] Cache loaded");
192 std::string filename;
193 std::string bundlename;
195 StringUtil::toLowerCase(filename);
196 StringUtil::toLowerCase(bundlename);
197 size_t partial_match_length = std::numeric_limits<size_t>::max();
199 std::vector<CacheEntryPtr> log_candidates;
202 if ((type ==
LT_Terrain) != (entry->fext ==
"terrn2") ||
203 (type ==
LT_DashBoard) != (entry->fext ==
"dashboard") ||
204 (type ==
LT_AllBeam && entry->fext ==
"skin"))
207 String fname = entry->
fname;
208 String fname_without_uid = entry->fname_without_uid;
210 String _path_placeholder;
211 StringUtil::splitFilename(entry->resource_bundle_path, bname, _path_placeholder);
212 StringUtil::toLowerCase(fname);
213 StringUtil::toLowerCase(fname_without_uid);
214 StringUtil::toLowerCase(bname);
215 if (fname == filename || fname_without_uid == filename)
217 if (bundlename ==
"" || bname == bundlename)
223 log_candidates.push_back(entry);
227 fname.length() < partial_match_length &&
228 fname.find(filename) != std::string::npos)
230 if (bundlename ==
"" || bname == bundlename)
232 partial_match = entry;
233 partial_match_length = fname.length();
237 log_candidates.push_back(entry);
242 if (log_candidates.size() > 0)
245 fmt::format(
_LC(
"CacheSystem",
"Mod '{}' was not found in cache; candidates ({}) are:"), _filename_maybe_bundlequalified, log_candidates.size()));
248 std::string bundle_name, bundle_path;
249 StringUtil::toLowerCase(bundle_name);
250 Ogre::StringUtil::splitFilename(entry->resource_bundle_path, bundle_name, bundle_path);
252 fmt::format(
_LC(
"CacheSystem",
"* {}:{}"), bundle_name, entry->fname));
256 return (partial) ? partial_match :
nullptr;
268 RoR::Log(
"[RoR|ModCache] Cannot load cache file: wrong version, corrupted or missing.");
275 RoR::Log(
"[RoR|ModCache] Cache file out of date");
281 std::string fn = entry->resource_bundle_path;
282 if (entry->resource_bundle_type ==
"FileSystem")
293 RoR::Log(
"[RoR|ModCache] Cache valid");
300 out_entry->
usagecounter = j_entry[
"usagecounter"].GetInt();
301 out_entry->
addtimestamp = j_entry[
"addtimestamp"].GetInt();
304 out_entry->
fpath = j_entry[
"fpath"].GetString();
305 out_entry->
fname = j_entry[
"fname"].GetString();
307 out_entry->
fext = j_entry[
"fext"].GetString();
308 out_entry->
filetime = j_entry[
"filetime"].GetInt();
309 out_entry->
dname = j_entry[
"dname"].GetString();
310 out_entry->
uniqueid = j_entry[
"uniqueid"].GetString();
311 out_entry->
version = j_entry[
"version"].GetInt();
312 out_entry->
filecachename = j_entry[
"filecachename"].GetString();
314 out_entry->
guid = j_entry[
"guid"].GetString();
315 Ogre::StringUtil::trim(out_entry->
guid);
318 int category_id = j_entry[
"categoryid"].GetInt();
328 for (rapidjson::Value& j_author: j_entry[
"authors"].GetArray())
332 author.
type = j_author[
"type"].GetString();
333 author.
name = j_author[
"name"].GetString();
334 author.
email = j_author[
"email"].GetString();
335 author.
id = j_author[
"id"].GetInt();
337 out_entry->
authors.push_back(author);
341 out_entry->
description = j_entry[
"description"].GetString();
342 out_entry->
tags = j_entry[
"tags"].GetString();
343 out_entry->
default_skin = j_entry[
"default_skin"].GetString();
345 out_entry->
hasSubmeshs = j_entry[
"hasSubmeshs"].GetBool();
346 out_entry->
nodecount = j_entry[
"nodecount"].GetInt();
347 out_entry->
beamcount = j_entry[
"beamcount"].GetInt();
348 out_entry->
shockcount = j_entry[
"shockcount"].GetInt();
349 out_entry->
fixescount = j_entry[
"fixescount"].GetInt();
350 out_entry->
hydroscount = j_entry[
"hydroscount"].GetInt();
351 out_entry->
wheelcount = j_entry[
"wheelcount"].GetInt();
353 out_entry->
commandscount = j_entry[
"commandscount"].GetInt();
354 out_entry->
flarescount = j_entry[
"flarescount"].GetInt();
355 out_entry->
propscount = j_entry[
"propscount"].GetInt();
356 out_entry->
wingscount = j_entry[
"wingscount"].GetInt();
358 out_entry->
turbojetcount = j_entry[
"turbojetcount"].GetInt();
359 out_entry->
rotatorscount = j_entry[
"rotatorscount"].GetInt();
360 out_entry->
exhaustscount = j_entry[
"exhaustscount"].GetInt();
363 out_entry->
truckmass = j_entry[
"truckmass"].GetFloat();
364 out_entry->
loadmass = j_entry[
"loadmass"].GetFloat();
365 out_entry->
minrpm = j_entry[
"minrpm"].GetFloat();
366 out_entry->
maxrpm = j_entry[
"maxrpm"].GetFloat();
367 out_entry->
torque = j_entry[
"torque"].GetFloat();
368 out_entry->
customtach = j_entry[
"customtach"].GetBool();
372 out_entry->
rescuer = j_entry[
"rescuer"].GetBool();
374 out_entry->
numgears = j_entry[
"numgears"].GetInt();
375 out_entry->
enginetype =
static_cast<char>(j_entry[
"enginetype"].GetInt());
378 for (rapidjson::Value& j_module_name: j_entry[
"sectionconfigs"].GetArray())
384 for (rapidjson::Value& j_addonguid: j_entry[
"addonpart_guids"].GetArray())
390 for (rapidjson::Value& j_addonfname: j_entry[
"addonpart_filenames"].GetArray())
404 rapidjson::Document j_doc;
406 !j_doc.IsObject() || !j_doc.HasMember(
"entries") || !j_doc[
"entries"].IsArray())
408 RoR::Log(
"[RoR|ModCache] Error, cache file still invalid after check/update, content selector will be empty.");
414 RoR::Log(
"[RoR|ModCache] Invalid cache file format");
418 for (rapidjson::Value& j_entry: j_doc[
"entries"].GetArray())
435 std::vector<String> paths;
438 std::string fn = entry->resource_bundle_path;
439 if (entry->resource_bundle_type ==
"FileSystem")
448 if (std::find(paths.begin(), paths.end(), fn) == paths.end())
455 entry->deleted =
true;
468 String group = entry->resource_group;
471 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
472 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
479 RoR::Log(
"[RoR|ModCache] Searching for duplicates ...");
480 std::map<String, String> possible_duplicates;
488 String dnameA = entryA->
dname;
489 StringUtil::toLowerCase(dnameA);
490 StringUtil::trim(dnameA);
492 StringUtil::toLowerCase(dirA);
493 String basenameA, basepathA;
494 StringUtil::splitFilename(dirA, basenameA, basepathA);
496 StringUtil::toLowerCase(filenameWUIDA);
506 StringUtil::toLowerCase(filenameWUIDB);
507 if (filenameWUIDA != filenameWUIDB)
510 String dnameB = entryB->
dname;
511 StringUtil::toLowerCase(dnameB);
512 StringUtil::trim(dnameB);
513 if (dnameA != dnameB)
517 StringUtil::toLowerCase(dirB);
518 String basenameB, basepathB;
519 StringUtil::splitFilename(dirB, basenameB, basepathB);
520 basenameA = Ogre::StringUtil::replaceAll(basenameA,
" ",
"_");
521 basenameA = Ogre::StringUtil::replaceAll(basenameA,
"-",
"_");
522 basenameB = Ogre::StringUtil::replaceAll(basenameB,
" ",
"_");
523 basenameB = Ogre::StringUtil::replaceAll(basenameB,
"-",
"_");
529 LOG(
"- duplicate: " + entryA->
fpath + entryA->
fname
532 int idx = entryA->
fpath.size() < entryB->
fpath.size() ? i : j;
541 for (
auto duplicate : possible_duplicates)
543 LOG(
"- possible duplicate: ");
544 LOG(
" - " + duplicate.first);
545 LOG(
" - " + duplicate.second);
553 if (modid == entry->number)
563 if (fname == entry->fname)
585 rapidjson::Value j_entry(rapidjson::kObjectType);
588 j_entry.AddMember(
"usagecounter", entry->
usagecounter, j_doc.GetAllocator());
589 j_entry.AddMember(
"addtimestamp",
static_cast<int64_t
>(entry->
addtimestamp), j_doc.GetAllocator());
590 j_entry.AddMember(
"resource_bundle_type", rapidjson::StringRef(entry->
resource_bundle_type.c_str()), j_doc.GetAllocator());
591 j_entry.AddMember(
"resource_bundle_path", rapidjson::StringRef(entry->
resource_bundle_path.c_str()), j_doc.GetAllocator());
592 j_entry.AddMember(
"fpath", rapidjson::StringRef(entry->
fpath.c_str()), j_doc.GetAllocator());
593 j_entry.AddMember(
"fname", rapidjson::StringRef(entry->
fname.c_str()), j_doc.GetAllocator());
594 j_entry.AddMember(
"fname_without_uid", rapidjson::StringRef(entry->
fname_without_uid.c_str()), j_doc.GetAllocator());
595 j_entry.AddMember(
"fext", rapidjson::StringRef(entry->
fext.c_str()), j_doc.GetAllocator());
596 j_entry.AddMember(
"filetime",
static_cast<int64_t
>(entry->
filetime), j_doc.GetAllocator());
597 j_entry.AddMember(
"dname", rapidjson::StringRef(entry->
dname.c_str()), j_doc.GetAllocator());
598 j_entry.AddMember(
"categoryid", entry->
categoryid, j_doc.GetAllocator());
599 j_entry.AddMember(
"uniqueid", rapidjson::StringRef(entry->
uniqueid.c_str()), j_doc.GetAllocator());
600 j_entry.AddMember(
"guid", rapidjson::StringRef(entry->
guid.c_str()), j_doc.GetAllocator());
601 j_entry.AddMember(
"version", entry->
version, j_doc.GetAllocator());
602 j_entry.AddMember(
"filecachename", rapidjson::StringRef(entry->
filecachename.c_str()), j_doc.GetAllocator());
605 rapidjson::Value j_authors(rapidjson::kArrayType);
608 rapidjson::Value j_author(rapidjson::kObjectType);
610 j_author.AddMember(
"type", rapidjson::StringRef(author.
type.c_str()), j_doc.GetAllocator());
611 j_author.AddMember(
"name", rapidjson::StringRef(author.
name.c_str()), j_doc.GetAllocator());
612 j_author.AddMember(
"email", rapidjson::StringRef(author.
email.c_str()), j_doc.GetAllocator());
613 j_author.AddMember(
"id", author.
id, j_doc.GetAllocator());
615 j_authors.PushBack(j_author, j_doc.GetAllocator());
617 j_entry.AddMember(
"authors", j_authors, j_doc.GetAllocator());
620 j_entry.AddMember(
"description", rapidjson::StringRef(entry->
description.c_str()), j_doc.GetAllocator());
621 j_entry.AddMember(
"tags", rapidjson::StringRef(entry->
tags.c_str()), j_doc.GetAllocator());
622 j_entry.AddMember(
"default_skin", rapidjson::StringRef(entry->
default_skin.c_str()), j_doc.GetAllocator());
623 j_entry.AddMember(
"fileformatversion", entry->
fileformatversion, j_doc.GetAllocator());
624 j_entry.AddMember(
"hasSubmeshs", entry->
hasSubmeshs, j_doc.GetAllocator());
625 j_entry.AddMember(
"nodecount", entry->
nodecount, j_doc.GetAllocator());
626 j_entry.AddMember(
"beamcount", entry->
beamcount, j_doc.GetAllocator());
627 j_entry.AddMember(
"shockcount", entry->
shockcount, j_doc.GetAllocator());
628 j_entry.AddMember(
"fixescount", entry->
fixescount, j_doc.GetAllocator());
629 j_entry.AddMember(
"hydroscount", entry->
hydroscount, j_doc.GetAllocator());
630 j_entry.AddMember(
"wheelcount", entry->
wheelcount, j_doc.GetAllocator());
631 j_entry.AddMember(
"propwheelcount", entry->
propwheelcount, j_doc.GetAllocator());
632 j_entry.AddMember(
"commandscount", entry->
commandscount, j_doc.GetAllocator());
633 j_entry.AddMember(
"flarescount", entry->
flarescount, j_doc.GetAllocator());
634 j_entry.AddMember(
"propscount", entry->
propscount, j_doc.GetAllocator());
635 j_entry.AddMember(
"wingscount", entry->
wingscount, j_doc.GetAllocator());
636 j_entry.AddMember(
"turbopropscount", entry->
turbopropscount, j_doc.GetAllocator());
637 j_entry.AddMember(
"turbojetcount", entry->
turbojetcount, j_doc.GetAllocator());
638 j_entry.AddMember(
"rotatorscount", entry->
rotatorscount, j_doc.GetAllocator());
639 j_entry.AddMember(
"exhaustscount", entry->
exhaustscount, j_doc.GetAllocator());
640 j_entry.AddMember(
"flexbodiescount", entry->
flexbodiescount, j_doc.GetAllocator());
641 j_entry.AddMember(
"soundsourcescount", entry->
soundsourcescount, j_doc.GetAllocator());
642 j_entry.AddMember(
"truckmass", entry->
truckmass, j_doc.GetAllocator());
643 j_entry.AddMember(
"loadmass", entry->
loadmass, j_doc.GetAllocator());
644 j_entry.AddMember(
"minrpm", entry->
minrpm, j_doc.GetAllocator());
645 j_entry.AddMember(
"maxrpm", entry->
maxrpm, j_doc.GetAllocator());
646 j_entry.AddMember(
"torque", entry->
torque, j_doc.GetAllocator());
647 j_entry.AddMember(
"customtach", entry->
customtach, j_doc.GetAllocator());
648 j_entry.AddMember(
"custom_particles", entry->
custom_particles, j_doc.GetAllocator());
649 j_entry.AddMember(
"forwardcommands", entry->
forwardcommands, j_doc.GetAllocator());
650 j_entry.AddMember(
"importcommands", entry->
importcommands, j_doc.GetAllocator());
651 j_entry.AddMember(
"rescuer", entry->
rescuer, j_doc.GetAllocator());
652 j_entry.AddMember(
"driveable", entry->
driveable, j_doc.GetAllocator());
653 j_entry.AddMember(
"numgears", entry->
numgears, j_doc.GetAllocator());
654 j_entry.AddMember(
"enginetype", entry->
enginetype, j_doc.GetAllocator());
657 rapidjson::Value j_sectionconfigs(rapidjson::kArrayType);
660 j_sectionconfigs.PushBack(rapidjson::StringRef(module_name.c_str()), j_doc.GetAllocator());
662 j_entry.AddMember(
"sectionconfigs", j_sectionconfigs, j_doc.GetAllocator());
665 rapidjson::Value j_addonguids(rapidjson::kArrayType);
668 j_addonguids.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
670 j_entry.AddMember(
"addonpart_guids", j_addonguids, j_doc.GetAllocator());
672 rapidjson::Value j_addonfnames(rapidjson::kArrayType);
675 j_addonfnames.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
677 j_entry.AddMember(
"addonpart_filenames", j_addonfnames, j_doc.GetAllocator());
680 j_entry.AddMember(
"tuneup_associated_filename", rapidjson::StringRef(entry->
tuneup_associated_filename.c_str()), j_doc.GetAllocator());
683 j_entries.PushBack(j_entry, j_doc.GetAllocator());
689 rapidjson::Document j_doc;
695 rapidjson::Value j_entries(rapidjson::kArrayType);
703 j_doc.AddMember(
"entries", j_entries, j_doc.GetAllocator());
717 String group = entry->resource_group;
720 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
721 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
730 size_t pos = uidstr.find(
"-");
731 if (pos != String::npos && pos >= 3 && uidstr.substr(pos - 3, 3) ==
"UID")
732 return uidstr.substr(pos + 1, uidstr.length() - pos);
738 size_t pos = sha1str.find_first_of(
"-_");
739 if (pos != String::npos && pos >= 20)
740 return sha1str.substr(pos + 1, sha1str.length() - pos);
746 String type = f.archive ? f.archive->getType() :
"FileSystem";
747 String path = f.archive ? f.archive->getName() :
"";
750 { return !entry->deleted && entry->fname == f.filename && entry->resource_bundle_path == path; }) !=
m_entries.end())
753 RoR::LogFormat(
"[RoR|CacheSystem] Preparing to add file '%f'", f.filename.c_str());
757 DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(f.filename, group);
760 std::vector<CacheEntryPtr> new_entries;
765 new_entries.push_back(entry);
767 else if (ext ==
"skin")
770 for (
auto skin_def: new_skins)
774 new_entries.push_back(entry);
777 else if (ext ==
"addonpart")
781 new_entries.push_back(entry);
783 else if (ext ==
"tuneup")
786 for (
auto tuneup_def: new_tuneups)
790 new_entries.push_back(entry);
793 else if (ext ==
"assetpack")
797 new_entries.push_back(entry);
799 else if (ext ==
"dashboard")
803 new_entries.push_back(entry);
805 else if (ext ==
"gadget")
809 new_entries.push_back(entry);
815 new_entries.push_back(entry);
818 for (
auto& entry: new_entries)
820 Ogre::StringUtil::toLowerCase(entry->
guid);
821 entry->
fpath = f.path;
822 entry->
fname = f.filename;
841 catch (Ogre::Exception& e)
843 RoR::LogFormat(
"[RoR|CacheSystem] Error processing file '%s', message :%s",
844 f.filename.c_str(), e.getFullDescription().c_str());
862 if (!def->name.empty())
864 entry->
dname = def->name;
868 entry->
dname =
"@" + file_name;
872 std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
873 for (; desc_itor != def->root_module->description.end(); desc_itor++)
879 std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
880 for (; author_itor != def->root_module->author.end(); author_itor++)
883 author.
email = author_itor->email;
884 author.
id = (author_itor->_has_forum_account) ?
static_cast<int>(author_itor->forum_account_id) : -1;
885 author.
name = author_itor->name;
886 author.
type = author_itor->type;
888 entry->
authors.push_back(author);
892 if (def->root_module->default_skin.size() > 0)
894 entry->
default_skin = def->root_module->default_skin.back().skin_name;
898 std::map<Ogre::String, std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = def->user_modules.begin();
899 for (; module_itor != def->user_modules.end(); module_itor++)
906 if (def->root_module->engine.size() > 0)
908 RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
914 if (def->root_module->engoption.size() > 0)
916 entry->
enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
921 if (def->root_module->fileinfo.size() > 0)
923 RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
941 module_itor = def->user_modules.begin();
942 for (; module_itor != def->user_modules.end(); module_itor++)
944 if (module_itor->second->engine.size() > 0)
946 vehicle_type =
TRUCK;
948 else if (module_itor->second->screwprops.size() > 0)
953 else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
959 if (def->root_module->engine.size() > 0)
961 vehicle_type =
TRUCK;
963 else if (def->root_module->screwprops.size() > 0)
968 else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
973 if (def->root_module->globals.size() > 0)
975 entry->
truckmass = def->root_module->globals[def->root_module->globals.size() - 1].dry_mass;
976 entry->
loadmass = def->root_module->globals[def->root_module->globals.size() - 1].cargo_mass;
982 if (def->root_module->guid.size() > 0)
984 entry->
guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
985 Ogre::StringUtil::toLowerCase(entry->
guid);
988 if (def->root_module->fileformatversion.size() > 0)
990 entry->
fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
992 entry->
hasSubmeshs =
static_cast<int>(def->root_module->submeshes.size() > 0);
993 entry->
nodecount =
static_cast<int>(def->root_module->nodes.size());
994 entry->
beamcount =
static_cast<int>(def->root_module->beams.size());
995 entry->
shockcount =
static_cast<int>(def->root_module->shocks.size() + def->root_module->shocks2.size());
996 entry->
fixescount =
static_cast<int>(def->root_module->fixes.size());
997 entry->
hydroscount =
static_cast<int>(def->root_module->hydros.size());
999 entry->
commandscount =
static_cast<int>(def->root_module->commands2.size());
1000 entry->
flarescount =
static_cast<int>(def->root_module->flares2.size());
1001 entry->
propscount =
static_cast<int>(def->root_module->props.size());
1002 entry->
wingscount =
static_cast<int>(def->root_module->wings.size());
1003 entry->
turbopropscount =
static_cast<int>(def->root_module->turboprops2.size());
1004 entry->
rotatorscount =
static_cast<int>(def->root_module->rotators.size() + def->root_module->rotators2.size());
1005 entry->
exhaustscount =
static_cast<int>(def->root_module->exhausts.size());
1007 entry->
turbojetcount =
static_cast<int>(def->root_module->turbojets.size());
1008 entry->
flexbodiescount =
static_cast<int>(def->root_module->flexbodies.size());
1009 entry->
soundsourcescount =
static_cast<int>(def->root_module->soundsources.size() + def->root_module->soundsources.size());
1013 for (
const auto&
w : def->root_module->wheels)
1019 for (
const auto&
w : def->root_module->wheels2)
1025 for (
const auto&
w : def->root_module->meshwheels)
1031 for (
const auto&
w : def->root_module->meshwheels2)
1037 for (
const auto&
w : def->root_module->flexbodywheels)
1044 if (!def->root_module->axles.empty())
1046 entry->
propwheelcount =
static_cast<int>(def->root_module->axles.size() * 2);
1054 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"dds"))
1057 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"png"))
1060 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"jpg"))
1076 if (entry->
fname.empty())
1079 String bundle_basename, bundle_path;
1084 if (entry->
fext ==
"skin")
1086 if (entry->
skin_def->thumbnail.empty())
1088 src_path = entry->
skin_def->thumbnail;
1089 String mini_fbase, minitype;
1090 StringUtil::splitBaseFilename(entry->
skin_def->thumbnail, mini_fbase, minitype);
1091 dst_path = bundle_basename +
"_" + mini_fbase +
".mini." + minitype;
1096 StringUtil::splitBaseFilename(entry->
fname, fbase, fext);
1097 String minifn = fbase +
"-mini.";
1099 if (minitype.empty())
1101 src_path = minifn + minitype;
1102 dst_path = bundle_basename +
"_" + entry->
fname +
".mini." + minitype;
1107 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(src_path, group);
1108 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(dst_path,
RGN_CACHE,
true);
1109 std::vector<char> buf(src_ds->size());
1110 size_t read = src_ds->read(buf.data(), src_ds->size());
1113 dst_ds->write(buf.data(), read);
1117 catch (Ogre::Exception& e)
1119 LOG(
"error while generating file cache: " + e.getFullDescription());
1122 LOG(
"done generating file cache!");
1127 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.zip");
1128 auto skinzips = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.skinzip");
1129 for (
const auto& skinzip : *skinzips)
1130 files->push_back(skinzip);
1132 int i = 0, count =
static_cast<int>(
files->size());
1135 int progress = ((float)i++ / (
float)count) * 100;
1137 _L(
"Loading zips in group "), group,
file.filename, i, count);
1152 RoR::LogFormat(
"[RoR|ModCache] Adding archive '%s'", path.c_str());
1153 ResourceGroupManager::getSingleton().createResourceGroup(
RGN_TEMP,
false);
1156 ResourceGroupManager::getSingleton().addResourceLocation(path,
"Zip",
RGN_TEMP);
1159 LOG(
"No usable content in: '" + path +
"'");
1162 catch (Ogre::Exception& e)
1164 LOG(
"Error while opening archive: '" + path +
"': " + e.getFullDescription());
1166 ResourceGroupManager::getSingleton().destroyResourceGroup(
RGN_TEMP);
1176 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*." + ext);
1199 fmt::format(
"Mod cache entry not populated - could not load terrain {}", ds->getName()));
1212 entry->
dname = def->name;
1215 entry->
version = def->version;
1220 if (!skin_def->author_name.empty())
1223 a.
id = skin_def->author_id;
1224 a.
name = skin_def->author_name;
1228 entry->
dname = skin_def->name;
1229 entry->
guid = skin_def->guid;
1234 Ogre::StringUtil::toLowerCase(entry->
guid);
1257 Ogre::StringUtil::toLowerCase(guid);
1263 Ogre::StringUtil::toLowerCase(fname);
1296 entry->
authors.push_back(author);
1332 entry->
authors.push_back(author);
1379 entry->
authors.push_back(author);
1404 Ogre::StringUtil::toLowerCase(entry->
guid);
1419 if (assetpack_entry)
1423 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1431 Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->
resource_group);
1432 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->
resource_group);
1434 catch (std::exception
const& e)
1437 fmt::format(
_L(
"Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->
fname, target_entry->
fname, e.what()));
1443 fmt::format(
_L(
"Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->
fname));
1456 LOG(
fmt::format(
"[RoR|CacheSystem] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->
fname));
1462 Ogre::StringUtil::toLowerCase(lower_bundlepath);
1464 std::string lower_dir = dir->
getStr();
1465 Ogre::StringUtil::toLowerCase(lower_dir);
1468 if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir,
true))
1471 ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1472 if (lower_bundlepath.size() > lower_dir.size())
1475 out_rgname =
fmt::format(
"{{bundle {}:{}}}", dir_label, localpath);
1490 std::string rg_name;
1514 if (entry->
fext ==
"skin")
1518 else if (entry->
fext ==
"tuneup")
1556 bool recursive =
false;
1561 if (entry->
fext ==
"terrn2")
1564 ResourceGroupManager::getSingleton().createResourceGroup(group,
true);
1565 ResourceGroupManager::getSingleton().addResourceLocation(
1568 else if (entry->
fext ==
"skin")
1572 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1573 ResourceGroupManager::getSingleton().addResourceLocation(
1577 else if (entry->
fext ==
"tuneup")
1580 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1581 ResourceGroupManager::getSingleton().addResourceLocation(
1585 else if (entry->
fext ==
"gadget")
1588 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1589 ResourceGroupManager::getSingleton().addResourceLocation(
1599 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1600 ResourceGroupManager::getSingleton().addResourceLocation(
1610 ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1620 i_entry->resource_group = group;
1624 catch (Ogre::Exception& e)
1628 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1630 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1660 if (i_entry->resource_group == resource_group)
1663 i_entry->actor_def =
nullptr;
1664 i_entry->tuneup_def =
nullptr;
1665 i_entry->skin_def =
nullptr;
1667 i_entry->resource_group =
"";
1671 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1678 if (entry->dname == skin_name && entry->fext ==
"skin")
1696 if (cache_entry->
skin_def !=
nullptr)
1703 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1707 for (
auto def: new_skins)
1713 && entry->fname == cache_entry->
fname
1714 && entry->dname == def->name)
1716 entry->skin_def = def;
1722 if (cache_entry->
skin_def ==
nullptr)
1724 RoR::LogFormat(
"Definition of skin '%s' was not found in file '%s'",
1725 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1728 catch (Ogre::Exception& oex)
1730 RoR::LogFormat(
"[RoR] Error loading skin file '%s', message: %s",
1731 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1752 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1756 for (
auto def: new_tuneups)
1762 && entry->fname == cache_entry->
fname
1763 && entry->dname == def->name)
1765 entry->tuneup_def = def;
1773 RoR::LogFormat(
"Definition of tuneup '%s' was not found in file '%s'",
1774 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1777 catch (Ogre::Exception& oex)
1779 RoR::LogFormat(
"[RoR] Error loading tuneup file '%s', message: %s",
1780 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1791 fmt::format(
_LC(
"CacheSystem",
"Cannot create project '{}' - no source mod specified!"), request->
cpr_name));
1816 bool project_entry_created =
false;
1827 project_entry_created =
true;
1831 project_entry->
fext =
"tuneup";
1834 Ogre::StringUtil::toLowerCase(project_entry->
guid);
1870 Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1888 std::string temp_rg =
"TempProjectSourceRG";
1894 bool recursive =
false;
1895 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1898 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1901 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg,
"*.*");
1902 for (
size_t i = 0; i < filelist->size(); i++)
1904 Ogre::FileInfo fileinfo = filelist->at(i);
1908 (i+1)/filelist->size(),
1909 fmt::format(
"Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1915 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(fileinfo.filename, temp_rg);
1916 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(fileinfo.filename, project_entry->
resource_group);
1917 std::vector<char> buf(src_ds->size());
1918 size_t read = src_ds->read(buf.data(), src_ds->size());
1921 dst_ds->write(buf.data(), read);
1924 catch (Ogre::Exception& oex)
1927 fmt::format(
_LC(
"CacheSystem",
"Could not copy file '{}' to project '{}', message: {}."),
1928 fileinfo.filename, request->
cpr_name, oex.getDescription()));
1933 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1936 Ogre::FileSystemLayer::renameFile(
1942 if (project_entry_created)
1951 activity_type, project_entry->
number, 0, 0,
1952 project_entry->
fname, project_entry->
fext);
1954 return project_entry;
1979 fmt::format(
_LC(
"Tuning",
"Addon part '{}' was not found in mod cache (probably not installed)."), request->
mpr_subject));
2172 const std::string DELETEPROJ_TEMP_RG =
"DeleteProjectTempRG";
2173 Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG,
false);
2174 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2176 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(DELETEPROJ_TEMP_RG,
"*.*");
2177 LOG(
fmt::format(
"[RoR|ModCache] Deleting project '{}' (resource group '{}'), found {} files to erase.", entry->
fname, entry->
resource_group, filelist->size()));
2178 for (
size_t i = 0; i < filelist->size(); i++)
2180 Ogre::FileInfo fileinfo = filelist->at(i);
2184 fmt::format(
_LC(
"CacheSystem",
"Problem deleting project '{}' - could not delete file '{}'"), entry->
fname, fileinfo.filename));
2188 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2209 std::time_t cur_time = std::time(
nullptr);
2216 if ((entry->fext ==
"addonpart" && entry->addonpart_guids.count(query.
cqy_filter_guid) == 0) ||
2226 if (entry->fext ==
"addonpart"
2227 && entry->addonpart_filenames.size() > 0
2232 else if (entry->fext ==
"tuneup"
2233 && entry->tuneup_associated_filename !=
""
2242 if (entry->fext ==
"terrn2")
2244 if (entry->fext ==
"skin")
2246 else if (entry->fext ==
"addonpart")
2248 else if (entry->fext ==
"tuneup")
2250 else if (entry->fext ==
"assetpack")
2252 else if (entry->fext ==
"dashboard")
2254 else if (entry->fext ==
"gadget")
2256 else if (entry->fext ==
"truck")
2258 else if (entry->fext ==
"car")
2260 else if (entry->fext ==
"boat")
2262 else if (entry->fext ==
"airplane")
2264 else if (entry->fext ==
"trailer")
2266 else if (entry->fext ==
"train")
2268 else if (entry->fext ==
"load")
2302 for (
AuthorInfo const& author: entry->authors)
2314 for (
AuthorInfo const& author: entry->authors)
2322 wheels_str << entry->wheelcount <<
"x" << entry->propwheelcount;
2348 Ogre::StringUtil::toLowerCase(data);
2349 size_t pos = data.find(query);
2350 if (pos != std::string::npos)
2352 out_score = score + pos;
2367 Ogre::StringUtil::toLowerCase(first);
2368 Ogre::StringUtil::toLowerCase(second);
2369 return first < second;