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),
160 RoR::Log(
"[RoR|ModCache] Performing rebuild ...");
165 RoR::Log(
"[RoR|ModCache] Performing update ...");
180 RoR::Log(
"[RoR|ModCache] Cache loaded");
190 std::string filename;
191 std::string bundlename;
193 StringUtil::toLowerCase(filename);
194 StringUtil::toLowerCase(bundlename);
195 size_t partial_match_length = std::numeric_limits<size_t>::max();
197 std::vector<CacheEntryPtr> log_candidates;
200 if ((type ==
LT_Terrain) != (entry->fext ==
"terrn2") ||
201 (type ==
LT_AllBeam && entry->fext ==
"skin"))
204 String fname = entry->
fname;
205 String fname_without_uid = entry->fname_without_uid;
207 String _path_placeholder;
208 StringUtil::splitFilename(entry->resource_bundle_path, bname, _path_placeholder);
209 StringUtil::toLowerCase(fname);
210 StringUtil::toLowerCase(fname_without_uid);
211 StringUtil::toLowerCase(bname);
212 if (fname == filename || fname_without_uid == filename)
214 if (bundlename ==
"" || bname == bundlename)
220 log_candidates.push_back(entry);
224 fname.length() < partial_match_length &&
225 fname.find(filename) != std::string::npos)
227 if (bundlename ==
"" || bname == bundlename)
229 partial_match = entry;
230 partial_match_length = fname.length();
234 log_candidates.push_back(entry);
239 if (log_candidates.size() > 0)
242 fmt::format(
_LC(
"CacheSystem",
"Mod '{}' was not found in cache; candidates ({}) are:"), _filename_maybe_bundlequalified, log_candidates.size()));
245 std::string bundle_name, bundle_path;
246 StringUtil::toLowerCase(bundle_name);
247 Ogre::StringUtil::splitFilename(entry->resource_bundle_path, bundle_name, bundle_path);
249 fmt::format(
_LC(
"CacheSystem",
"* {}:{}"), bundle_name, entry->fname));
253 return (partial) ? partial_match :
nullptr;
265 RoR::Log(
"[RoR|ModCache] Cannot load cache file: wrong version, corrupted or missing.");
272 RoR::Log(
"[RoR|ModCache] Cache file out of date");
278 std::string fn = entry->resource_bundle_path;
279 if (entry->resource_bundle_type ==
"FileSystem")
290 RoR::Log(
"[RoR|ModCache] Cache valid");
297 out_entry->
usagecounter = j_entry[
"usagecounter"].GetInt();
298 out_entry->
addtimestamp = j_entry[
"addtimestamp"].GetInt();
301 out_entry->
fpath = j_entry[
"fpath"].GetString();
302 out_entry->
fname = j_entry[
"fname"].GetString();
304 out_entry->
fext = j_entry[
"fext"].GetString();
305 out_entry->
filetime = j_entry[
"filetime"].GetInt();
306 out_entry->
dname = j_entry[
"dname"].GetString();
307 out_entry->
uniqueid = j_entry[
"uniqueid"].GetString();
308 out_entry->
version = j_entry[
"version"].GetInt();
309 out_entry->
filecachename = j_entry[
"filecachename"].GetString();
311 out_entry->
guid = j_entry[
"guid"].GetString();
312 Ogre::StringUtil::trim(out_entry->
guid);
315 int category_id = j_entry[
"categoryid"].GetInt();
325 for (rapidjson::Value& j_author: j_entry[
"authors"].GetArray())
329 author.
type = j_author[
"type"].GetString();
330 author.
name = j_author[
"name"].GetString();
331 author.
email = j_author[
"email"].GetString();
332 author.
id = j_author[
"id"].GetInt();
334 out_entry->
authors.push_back(author);
338 out_entry->
description = j_entry[
"description"].GetString();
339 out_entry->
tags = j_entry[
"tags"].GetString();
340 out_entry->
default_skin = j_entry[
"default_skin"].GetString();
342 out_entry->
hasSubmeshs = j_entry[
"hasSubmeshs"].GetBool();
343 out_entry->
nodecount = j_entry[
"nodecount"].GetInt();
344 out_entry->
beamcount = j_entry[
"beamcount"].GetInt();
345 out_entry->
shockcount = j_entry[
"shockcount"].GetInt();
346 out_entry->
fixescount = j_entry[
"fixescount"].GetInt();
347 out_entry->
hydroscount = j_entry[
"hydroscount"].GetInt();
348 out_entry->
wheelcount = j_entry[
"wheelcount"].GetInt();
350 out_entry->
commandscount = j_entry[
"commandscount"].GetInt();
351 out_entry->
flarescount = j_entry[
"flarescount"].GetInt();
352 out_entry->
propscount = j_entry[
"propscount"].GetInt();
353 out_entry->
wingscount = j_entry[
"wingscount"].GetInt();
355 out_entry->
turbojetcount = j_entry[
"turbojetcount"].GetInt();
356 out_entry->
rotatorscount = j_entry[
"rotatorscount"].GetInt();
357 out_entry->
exhaustscount = j_entry[
"exhaustscount"].GetInt();
360 out_entry->
truckmass = j_entry[
"truckmass"].GetFloat();
361 out_entry->
loadmass = j_entry[
"loadmass"].GetFloat();
362 out_entry->
minrpm = j_entry[
"minrpm"].GetFloat();
363 out_entry->
maxrpm = j_entry[
"maxrpm"].GetFloat();
364 out_entry->
torque = j_entry[
"torque"].GetFloat();
365 out_entry->
customtach = j_entry[
"customtach"].GetBool();
369 out_entry->
rescuer = j_entry[
"rescuer"].GetBool();
371 out_entry->
numgears = j_entry[
"numgears"].GetInt();
372 out_entry->
enginetype =
static_cast<char>(j_entry[
"enginetype"].GetInt());
375 for (rapidjson::Value& j_module_name: j_entry[
"sectionconfigs"].GetArray())
381 for (rapidjson::Value& j_addonguid: j_entry[
"addonpart_guids"].GetArray())
387 for (rapidjson::Value& j_addonfname: j_entry[
"addonpart_filenames"].GetArray())
401 rapidjson::Document j_doc;
403 !j_doc.IsObject() || !j_doc.HasMember(
"entries") || !j_doc[
"entries"].IsArray())
405 RoR::Log(
"[RoR|ModCache] Error, cache file still invalid after check/update, content selector will be empty.");
411 RoR::Log(
"[RoR|ModCache] Invalid cache file format");
415 for (rapidjson::Value& j_entry: j_doc[
"entries"].GetArray())
432 std::vector<String> paths;
435 std::string fn = entry->resource_bundle_path;
436 if (entry->resource_bundle_type ==
"FileSystem")
445 if (std::find(paths.begin(), paths.end(), fn) == paths.end())
452 entry->deleted =
true;
465 String group = entry->resource_group;
468 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
469 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
476 RoR::Log(
"[RoR|ModCache] Searching for duplicates ...");
477 std::map<String, String> possible_duplicates;
485 String dnameA = entryA->
dname;
486 StringUtil::toLowerCase(dnameA);
487 StringUtil::trim(dnameA);
489 StringUtil::toLowerCase(dirA);
490 String basenameA, basepathA;
491 StringUtil::splitFilename(dirA, basenameA, basepathA);
493 StringUtil::toLowerCase(filenameWUIDA);
503 StringUtil::toLowerCase(filenameWUIDB);
504 if (filenameWUIDA != filenameWUIDB)
507 String dnameB = entryB->
dname;
508 StringUtil::toLowerCase(dnameB);
509 StringUtil::trim(dnameB);
510 if (dnameA != dnameB)
514 StringUtil::toLowerCase(dirB);
515 String basenameB, basepathB;
516 StringUtil::splitFilename(dirB, basenameB, basepathB);
517 basenameA = Ogre::StringUtil::replaceAll(basenameA,
" ",
"_");
518 basenameA = Ogre::StringUtil::replaceAll(basenameA,
"-",
"_");
519 basenameB = Ogre::StringUtil::replaceAll(basenameB,
" ",
"_");
520 basenameB = Ogre::StringUtil::replaceAll(basenameB,
"-",
"_");
526 LOG(
"- duplicate: " + entryA->
fpath + entryA->
fname
529 int idx = entryA->
fpath.size() < entryB->
fpath.size() ? i : j;
538 for (
auto duplicate : possible_duplicates)
540 LOG(
"- possible duplicate: ");
541 LOG(
" - " + duplicate.first);
542 LOG(
" - " + duplicate.second);
550 if (modid == entry->number)
560 if (fname == entry->fname)
582 rapidjson::Value j_entry(rapidjson::kObjectType);
585 j_entry.AddMember(
"usagecounter", entry->
usagecounter, j_doc.GetAllocator());
586 j_entry.AddMember(
"addtimestamp",
static_cast<int64_t
>(entry->
addtimestamp), j_doc.GetAllocator());
587 j_entry.AddMember(
"resource_bundle_type", rapidjson::StringRef(entry->
resource_bundle_type.c_str()), j_doc.GetAllocator());
588 j_entry.AddMember(
"resource_bundle_path", rapidjson::StringRef(entry->
resource_bundle_path.c_str()), j_doc.GetAllocator());
589 j_entry.AddMember(
"fpath", rapidjson::StringRef(entry->
fpath.c_str()), j_doc.GetAllocator());
590 j_entry.AddMember(
"fname", rapidjson::StringRef(entry->
fname.c_str()), j_doc.GetAllocator());
591 j_entry.AddMember(
"fname_without_uid", rapidjson::StringRef(entry->
fname_without_uid.c_str()), j_doc.GetAllocator());
592 j_entry.AddMember(
"fext", rapidjson::StringRef(entry->
fext.c_str()), j_doc.GetAllocator());
593 j_entry.AddMember(
"filetime",
static_cast<int64_t
>(entry->
filetime), j_doc.GetAllocator());
594 j_entry.AddMember(
"dname", rapidjson::StringRef(entry->
dname.c_str()), j_doc.GetAllocator());
595 j_entry.AddMember(
"categoryid", entry->
categoryid, j_doc.GetAllocator());
596 j_entry.AddMember(
"uniqueid", rapidjson::StringRef(entry->
uniqueid.c_str()), j_doc.GetAllocator());
597 j_entry.AddMember(
"guid", rapidjson::StringRef(entry->
guid.c_str()), j_doc.GetAllocator());
598 j_entry.AddMember(
"version", entry->
version, j_doc.GetAllocator());
599 j_entry.AddMember(
"filecachename", rapidjson::StringRef(entry->
filecachename.c_str()), j_doc.GetAllocator());
602 rapidjson::Value j_authors(rapidjson::kArrayType);
605 rapidjson::Value j_author(rapidjson::kObjectType);
607 j_author.AddMember(
"type", rapidjson::StringRef(author.
type.c_str()), j_doc.GetAllocator());
608 j_author.AddMember(
"name", rapidjson::StringRef(author.
name.c_str()), j_doc.GetAllocator());
609 j_author.AddMember(
"email", rapidjson::StringRef(author.
email.c_str()), j_doc.GetAllocator());
610 j_author.AddMember(
"id", author.
id, j_doc.GetAllocator());
612 j_authors.PushBack(j_author, j_doc.GetAllocator());
614 j_entry.AddMember(
"authors", j_authors, j_doc.GetAllocator());
617 j_entry.AddMember(
"description", rapidjson::StringRef(entry->
description.c_str()), j_doc.GetAllocator());
618 j_entry.AddMember(
"tags", rapidjson::StringRef(entry->
tags.c_str()), j_doc.GetAllocator());
619 j_entry.AddMember(
"default_skin", rapidjson::StringRef(entry->
default_skin.c_str()), j_doc.GetAllocator());
620 j_entry.AddMember(
"fileformatversion", entry->
fileformatversion, j_doc.GetAllocator());
621 j_entry.AddMember(
"hasSubmeshs", entry->
hasSubmeshs, j_doc.GetAllocator());
622 j_entry.AddMember(
"nodecount", entry->
nodecount, j_doc.GetAllocator());
623 j_entry.AddMember(
"beamcount", entry->
beamcount, j_doc.GetAllocator());
624 j_entry.AddMember(
"shockcount", entry->
shockcount, j_doc.GetAllocator());
625 j_entry.AddMember(
"fixescount", entry->
fixescount, j_doc.GetAllocator());
626 j_entry.AddMember(
"hydroscount", entry->
hydroscount, j_doc.GetAllocator());
627 j_entry.AddMember(
"wheelcount", entry->
wheelcount, j_doc.GetAllocator());
628 j_entry.AddMember(
"propwheelcount", entry->
propwheelcount, j_doc.GetAllocator());
629 j_entry.AddMember(
"commandscount", entry->
commandscount, j_doc.GetAllocator());
630 j_entry.AddMember(
"flarescount", entry->
flarescount, j_doc.GetAllocator());
631 j_entry.AddMember(
"propscount", entry->
propscount, j_doc.GetAllocator());
632 j_entry.AddMember(
"wingscount", entry->
wingscount, j_doc.GetAllocator());
633 j_entry.AddMember(
"turbopropscount", entry->
turbopropscount, j_doc.GetAllocator());
634 j_entry.AddMember(
"turbojetcount", entry->
turbojetcount, j_doc.GetAllocator());
635 j_entry.AddMember(
"rotatorscount", entry->
rotatorscount, j_doc.GetAllocator());
636 j_entry.AddMember(
"exhaustscount", entry->
exhaustscount, j_doc.GetAllocator());
637 j_entry.AddMember(
"flexbodiescount", entry->
flexbodiescount, j_doc.GetAllocator());
638 j_entry.AddMember(
"soundsourcescount", entry->
soundsourcescount, j_doc.GetAllocator());
639 j_entry.AddMember(
"truckmass", entry->
truckmass, j_doc.GetAllocator());
640 j_entry.AddMember(
"loadmass", entry->
loadmass, j_doc.GetAllocator());
641 j_entry.AddMember(
"minrpm", entry->
minrpm, j_doc.GetAllocator());
642 j_entry.AddMember(
"maxrpm", entry->
maxrpm, j_doc.GetAllocator());
643 j_entry.AddMember(
"torque", entry->
torque, j_doc.GetAllocator());
644 j_entry.AddMember(
"customtach", entry->
customtach, j_doc.GetAllocator());
645 j_entry.AddMember(
"custom_particles", entry->
custom_particles, j_doc.GetAllocator());
646 j_entry.AddMember(
"forwardcommands", entry->
forwardcommands, j_doc.GetAllocator());
647 j_entry.AddMember(
"importcommands", entry->
importcommands, j_doc.GetAllocator());
648 j_entry.AddMember(
"rescuer", entry->
rescuer, j_doc.GetAllocator());
649 j_entry.AddMember(
"driveable", entry->
driveable, j_doc.GetAllocator());
650 j_entry.AddMember(
"numgears", entry->
numgears, j_doc.GetAllocator());
651 j_entry.AddMember(
"enginetype", entry->
enginetype, j_doc.GetAllocator());
654 rapidjson::Value j_sectionconfigs(rapidjson::kArrayType);
657 j_sectionconfigs.PushBack(rapidjson::StringRef(module_name.c_str()), j_doc.GetAllocator());
659 j_entry.AddMember(
"sectionconfigs", j_sectionconfigs, j_doc.GetAllocator());
662 rapidjson::Value j_addonguids(rapidjson::kArrayType);
665 j_addonguids.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
667 j_entry.AddMember(
"addonpart_guids", j_addonguids, j_doc.GetAllocator());
669 rapidjson::Value j_addonfnames(rapidjson::kArrayType);
672 j_addonfnames.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
674 j_entry.AddMember(
"addonpart_filenames", j_addonfnames, j_doc.GetAllocator());
677 j_entry.AddMember(
"tuneup_associated_filename", rapidjson::StringRef(entry->
tuneup_associated_filename.c_str()), j_doc.GetAllocator());
680 j_entries.PushBack(j_entry, j_doc.GetAllocator());
686 rapidjson::Document j_doc;
692 rapidjson::Value j_entries(rapidjson::kArrayType);
700 j_doc.AddMember(
"entries", j_entries, j_doc.GetAllocator());
714 String group = entry->resource_group;
717 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
718 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
727 size_t pos = uidstr.find(
"-");
728 if (pos != String::npos && pos >= 3 && uidstr.substr(pos - 3, 3) ==
"UID")
729 return uidstr.substr(pos + 1, uidstr.length() - pos);
735 size_t pos = sha1str.find_first_of(
"-_");
736 if (pos != String::npos && pos >= 20)
737 return sha1str.substr(pos + 1, sha1str.length() - pos);
743 String type = f.archive ? f.archive->getType() :
"FileSystem";
744 String path = f.archive ? f.archive->getName() :
"";
747 { return !entry->deleted && entry->fname == f.filename && entry->resource_bundle_path == path; }) !=
m_entries.end())
750 RoR::LogFormat(
"[RoR|CacheSystem] Preparing to add file '%f'", f.filename.c_str());
754 DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(f.filename, group);
757 std::vector<CacheEntryPtr> new_entries;
762 new_entries.push_back(entry);
764 else if (ext ==
"skin")
767 for (
auto skin_def: new_skins)
771 new_entries.push_back(entry);
774 else if (ext ==
"addonpart")
778 new_entries.push_back(entry);
780 else if (ext ==
"tuneup")
783 for (
auto tuneup_def: new_tuneups)
787 new_entries.push_back(entry);
790 else if (ext ==
"assetpack")
794 new_entries.push_back(entry);
800 new_entries.push_back(entry);
803 for (
auto& entry: new_entries)
805 Ogre::StringUtil::toLowerCase(entry->
guid);
806 entry->
fpath = f.path;
807 entry->
fname = f.filename;
826 catch (Ogre::Exception& e)
828 RoR::LogFormat(
"[RoR|CacheSystem] Error processing file '%s', message :%s",
829 f.filename.c_str(), e.getFullDescription().c_str());
847 if (!def->name.empty())
849 entry->
dname = def->name;
853 entry->
dname =
"@" + file_name;
857 std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
858 for (; desc_itor != def->root_module->description.end(); desc_itor++)
864 std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
865 for (; author_itor != def->root_module->author.end(); author_itor++)
868 author.
email = author_itor->email;
869 author.
id = (author_itor->_has_forum_account) ?
static_cast<int>(author_itor->forum_account_id) : -1;
870 author.
name = author_itor->name;
871 author.
type = author_itor->type;
873 entry->
authors.push_back(author);
877 if (def->root_module->default_skin.size() > 0)
879 entry->
default_skin = def->root_module->default_skin.back().skin_name;
883 std::map<Ogre::String, std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = def->user_modules.begin();
884 for (; module_itor != def->user_modules.end(); module_itor++)
891 if (def->root_module->engine.size() > 0)
893 RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
899 if (def->root_module->engoption.size() > 0)
901 entry->
enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
906 if (def->root_module->fileinfo.size() > 0)
908 RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
926 module_itor = def->user_modules.begin();
927 for (; module_itor != def->user_modules.end(); module_itor++)
929 if (module_itor->second->engine.size() > 0)
931 vehicle_type =
TRUCK;
933 else if (module_itor->second->screwprops.size() > 0)
938 else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
944 if (def->root_module->engine.size() > 0)
946 vehicle_type =
TRUCK;
948 else if (def->root_module->screwprops.size() > 0)
953 else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
958 if (def->root_module->globals.size() > 0)
960 entry->
truckmass = def->root_module->globals[def->root_module->globals.size() - 1].dry_mass;
961 entry->
loadmass = def->root_module->globals[def->root_module->globals.size() - 1].cargo_mass;
967 if (def->root_module->guid.size() > 0)
969 entry->
guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
970 Ogre::StringUtil::toLowerCase(entry->
guid);
973 if (def->root_module->fileformatversion.size() > 0)
975 entry->
fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
977 entry->
hasSubmeshs =
static_cast<int>(def->root_module->submeshes.size() > 0);
978 entry->
nodecount =
static_cast<int>(def->root_module->nodes.size());
979 entry->
beamcount =
static_cast<int>(def->root_module->beams.size());
980 entry->
shockcount =
static_cast<int>(def->root_module->shocks.size() + def->root_module->shocks2.size());
981 entry->
fixescount =
static_cast<int>(def->root_module->fixes.size());
982 entry->
hydroscount =
static_cast<int>(def->root_module->hydros.size());
984 entry->
commandscount =
static_cast<int>(def->root_module->commands2.size());
985 entry->
flarescount =
static_cast<int>(def->root_module->flares2.size());
986 entry->
propscount =
static_cast<int>(def->root_module->props.size());
987 entry->
wingscount =
static_cast<int>(def->root_module->wings.size());
988 entry->
turbopropscount =
static_cast<int>(def->root_module->turboprops2.size());
989 entry->
rotatorscount =
static_cast<int>(def->root_module->rotators.size() + def->root_module->rotators2.size());
990 entry->
exhaustscount =
static_cast<int>(def->root_module->exhausts.size());
992 entry->
turbojetcount =
static_cast<int>(def->root_module->turbojets.size());
993 entry->
flexbodiescount =
static_cast<int>(def->root_module->flexbodies.size());
994 entry->
soundsourcescount =
static_cast<int>(def->root_module->soundsources.size() + def->root_module->soundsources.size());
998 for (
const auto&
w : def->root_module->wheels)
1004 for (
const auto&
w : def->root_module->wheels2)
1010 for (
const auto&
w : def->root_module->meshwheels)
1016 for (
const auto&
w : def->root_module->meshwheels2)
1022 for (
const auto&
w : def->root_module->flexbodywheels)
1029 if (!def->root_module->axles.empty())
1031 entry->
propwheelcount =
static_cast<int>(def->root_module->axles.size() * 2);
1039 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"dds"))
1042 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"png"))
1045 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"jpg"))
1061 if (entry->
fname.empty())
1064 String bundle_basename, bundle_path;
1069 if (entry->
fext ==
"skin")
1071 if (entry->
skin_def->thumbnail.empty())
1073 src_path = entry->
skin_def->thumbnail;
1074 String mini_fbase, minitype;
1075 StringUtil::splitBaseFilename(entry->
skin_def->thumbnail, mini_fbase, minitype);
1076 dst_path = bundle_basename +
"_" + mini_fbase +
".mini." + minitype;
1081 StringUtil::splitBaseFilename(entry->
fname, fbase, fext);
1082 String minifn = fbase +
"-mini.";
1084 if (minitype.empty())
1086 src_path = minifn + minitype;
1087 dst_path = bundle_basename +
"_" + entry->
fname +
".mini." + minitype;
1092 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(src_path, group);
1093 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(dst_path,
RGN_CACHE,
true);
1094 std::vector<char> buf(src_ds->size());
1095 size_t read = src_ds->read(buf.data(), src_ds->size());
1098 dst_ds->write(buf.data(), read);
1102 catch (Ogre::Exception& e)
1104 LOG(
"error while generating file cache: " + e.getFullDescription());
1107 LOG(
"done generating file cache!");
1112 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.zip");
1113 auto skinzips = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.skinzip");
1114 for (
const auto& skinzip : *skinzips)
1115 files->push_back(skinzip);
1117 int i = 0, count =
static_cast<int>(
files->size());
1120 int progress = ((float)i++ / (
float)count) * 100;
1122 _L(
"Loading zips in group "), group,
file.filename, i, count);
1137 RoR::LogFormat(
"[RoR|ModCache] Adding archive '%s'", path.c_str());
1138 ResourceGroupManager::getSingleton().createResourceGroup(
RGN_TEMP,
false);
1141 ResourceGroupManager::getSingleton().addResourceLocation(path,
"Zip",
RGN_TEMP);
1144 LOG(
"No usable content in: '" + path +
"'");
1147 catch (Ogre::Exception& e)
1149 LOG(
"Error while opening archive: '" + path +
"': " + e.getFullDescription());
1151 ResourceGroupManager::getSingleton().destroyResourceGroup(
RGN_TEMP);
1161 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*." + ext);
1200 if (!skin_def->author_name.empty())
1203 a.
id = skin_def->author_id;
1204 a.
name = skin_def->author_name;
1208 entry->
dname = skin_def->name;
1209 entry->
guid = skin_def->guid;
1214 Ogre::StringUtil::toLowerCase(entry->
guid);
1237 Ogre::StringUtil::toLowerCase(guid);
1243 Ogre::StringUtil::toLowerCase(fname);
1276 entry->
authors.push_back(author);
1300 Ogre::StringUtil::toLowerCase(entry->
guid);
1315 if (assetpack_entry)
1319 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1327 Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->
resource_group);
1328 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->
resource_group);
1330 catch (std::exception
const& e)
1333 fmt::format(
_L(
"Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->
fname, target_entry->
fname, e.what()));
1339 fmt::format(
_L(
"Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->
fname));
1352 LOG(
fmt::format(
"[RoR|CacheSystem] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->
fname));
1358 Ogre::StringUtil::toLowerCase(lower_bundlepath);
1360 std::string lower_dir = dir->
getStr();
1361 Ogre::StringUtil::toLowerCase(lower_dir);
1364 if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir,
true))
1367 ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1368 if (lower_bundlepath.size() > lower_dir.size())
1371 out_rgname =
fmt::format(
"{{bundle {}:{}}}", dir_label, localpath);
1386 std::string rg_name;
1410 if (entry->
fext ==
"skin")
1414 else if (entry->
fext ==
"tuneup")
1452 bool recursive =
false;
1457 if (entry->
fext ==
"terrn2")
1460 ResourceGroupManager::getSingleton().createResourceGroup(group,
true);
1461 ResourceGroupManager::getSingleton().addResourceLocation(
1464 else if (entry->
fext ==
"skin")
1468 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1469 ResourceGroupManager::getSingleton().addResourceLocation(
1473 else if (entry->
fext ==
"tuneup")
1476 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1477 ResourceGroupManager::getSingleton().addResourceLocation(
1485 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1486 ResourceGroupManager::getSingleton().addResourceLocation(
1496 ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1506 i_entry->resource_group = group;
1510 catch (Ogre::Exception& e)
1514 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1516 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1546 if (i_entry->resource_group == resource_group)
1549 i_entry->actor_def =
nullptr;
1550 i_entry->tuneup_def =
nullptr;
1551 i_entry->skin_def =
nullptr;
1553 i_entry->resource_group =
"";
1557 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1564 if (entry->dname == skin_name && entry->fext ==
"skin")
1582 if (cache_entry->
skin_def !=
nullptr)
1589 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1593 for (
auto def: new_skins)
1599 && entry->fname == cache_entry->
fname
1600 && entry->dname == def->name)
1602 entry->skin_def = def;
1608 if (cache_entry->
skin_def ==
nullptr)
1610 RoR::LogFormat(
"Definition of skin '%s' was not found in file '%s'",
1611 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1614 catch (Ogre::Exception& oex)
1616 RoR::LogFormat(
"[RoR] Error loading skin file '%s', message: %s",
1617 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1638 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1642 for (
auto def: new_tuneups)
1648 && entry->fname == cache_entry->
fname
1649 && entry->dname == def->name)
1651 entry->tuneup_def = def;
1659 RoR::LogFormat(
"Definition of tuneup '%s' was not found in file '%s'",
1660 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1663 catch (Ogre::Exception& oex)
1665 RoR::LogFormat(
"[RoR] Error loading tuneup file '%s', message: %s",
1666 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1677 fmt::format(
_LC(
"CacheSystem",
"Cannot create project '{}' - no source mod specified!"), request->
cpr_name));
1702 bool project_entry_created =
false;
1713 project_entry_created =
true;
1717 project_entry->
fext =
"tuneup";
1720 Ogre::StringUtil::toLowerCase(project_entry->
guid);
1756 Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1774 std::string temp_rg =
"TempProjectSourceRG";
1780 bool recursive =
false;
1781 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1784 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1787 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg,
"*.*");
1788 for (
size_t i = 0; i < filelist->size(); i++)
1790 Ogre::FileInfo fileinfo = filelist->at(i);
1794 (i+1)/filelist->size(),
1795 fmt::format(
"Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1801 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(fileinfo.filename, temp_rg);
1802 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(fileinfo.filename, project_entry->
resource_group);
1803 std::vector<char> buf(src_ds->size());
1804 size_t read = src_ds->read(buf.data(), src_ds->size());
1807 dst_ds->write(buf.data(), read);
1810 catch (Ogre::Exception& oex)
1813 fmt::format(
_LC(
"CacheSystem",
"Could not copy file '{}' to project '{}', message: {}."),
1814 fileinfo.filename, request->
cpr_name, oex.getDescription()));
1819 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1822 Ogre::FileSystemLayer::renameFile(
1828 if (project_entry_created)
1837 activity_type, project_entry->
number, 0, 0,
1838 project_entry->
fname, project_entry->
fext);
1840 return project_entry;
1865 fmt::format(
_LC(
"Tuning",
"Addon part '{}' was not found in mod cache (probably not installed)."), request->
mpr_subject));
2058 const std::string DELETEPROJ_TEMP_RG =
"DeleteProjectTempRG";
2059 Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG,
false);
2060 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2062 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(DELETEPROJ_TEMP_RG,
"*.*");
2063 LOG(
fmt::format(
"[RoR|ModCache] Deleting project '{}' (resource group '{}'), found {} files to erase.", entry->
fname, entry->
resource_group, filelist->size()));
2064 for (
size_t i = 0; i < filelist->size(); i++)
2066 Ogre::FileInfo fileinfo = filelist->at(i);
2070 fmt::format(
_LC(
"CacheSystem",
"Problem deleting project '{}' - could not delete file '{}'"), entry->
fname, fileinfo.filename));
2074 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2095 std::time_t cur_time = std::time(
nullptr);
2102 if ((entry->fext ==
"addonpart" && entry->addonpart_guids.count(query.
cqy_filter_guid) == 0) ||
2112 if (entry->fext ==
"addonpart"
2113 && entry->addonpart_filenames.size() > 0
2118 else if (entry->fext ==
"tuneup"
2119 && entry->tuneup_associated_filename !=
""
2128 if (entry->fext ==
"terrn2")
2130 if (entry->fext ==
"skin")
2132 else if (entry->fext ==
"addonpart")
2134 else if (entry->fext ==
"tuneup")
2136 else if (entry->fext ==
"assetpack")
2138 else if (entry->fext ==
"truck")
2140 else if (entry->fext ==
"car")
2142 else if (entry->fext ==
"boat")
2144 else if (entry->fext ==
"airplane")
2146 else if (entry->fext ==
"trailer")
2148 else if (entry->fext ==
"train")
2150 else if (entry->fext ==
"load")
2184 for (
AuthorInfo const& author: entry->authors)
2196 for (
AuthorInfo const& author: entry->authors)
2204 wheels_str << entry->wheelcount <<
"x" << entry->propwheelcount;
2230 Ogre::StringUtil::toLowerCase(data);
2231 size_t pos = data.find(query);
2232 if (pos != std::string::npos)
2234 out_score = score + pos;
2249 Ogre::StringUtil::toLowerCase(first);
2250 Ogre::StringUtil::toLowerCase(second);
2251 return first < second;