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");
186 std::string filename = _filename;
187 StringUtil::toLowerCase(filename);
188 size_t partial_match_length = std::numeric_limits<size_t>::max();
192 if ((type ==
LT_Terrain) != (entry->fext ==
"terrn2") ||
193 (type ==
LT_AllBeam && entry->fext ==
"skin"))
196 String fname = entry->
fname;
197 String fname_without_uid = entry->fname_without_uid;
198 StringUtil::toLowerCase(fname);
199 StringUtil::toLowerCase(fname_without_uid);
200 if (fname == filename || fname_without_uid == filename)
204 fname.length() < partial_match_length &&
205 fname.find(filename) != std::string::npos)
207 partial_match = entry;
208 partial_match_length = fname.length();
212 return (partial) ? partial_match :
nullptr;
224 RoR::Log(
"[RoR|ModCache] Cannot load cache file: wrong version, corrupted or missing.");
231 RoR::Log(
"[RoR|ModCache] Cache file out of date");
237 std::string fn = entry->resource_bundle_path;
238 if (entry->resource_bundle_type ==
"FileSystem")
249 RoR::Log(
"[RoR|ModCache] Cache valid");
256 out_entry->
usagecounter = j_entry[
"usagecounter"].GetInt();
257 out_entry->
addtimestamp = j_entry[
"addtimestamp"].GetInt();
260 out_entry->
fpath = j_entry[
"fpath"].GetString();
261 out_entry->
fname = j_entry[
"fname"].GetString();
263 out_entry->
fext = j_entry[
"fext"].GetString();
264 out_entry->
filetime = j_entry[
"filetime"].GetInt();
265 out_entry->
dname = j_entry[
"dname"].GetString();
266 out_entry->
uniqueid = j_entry[
"uniqueid"].GetString();
267 out_entry->
version = j_entry[
"version"].GetInt();
268 out_entry->
filecachename = j_entry[
"filecachename"].GetString();
270 out_entry->
guid = j_entry[
"guid"].GetString();
271 Ogre::StringUtil::trim(out_entry->
guid);
274 int category_id = j_entry[
"categoryid"].GetInt();
284 for (rapidjson::Value& j_author: j_entry[
"authors"].GetArray())
288 author.
type = j_author[
"type"].GetString();
289 author.
name = j_author[
"name"].GetString();
290 author.
email = j_author[
"email"].GetString();
291 author.
id = j_author[
"id"].GetInt();
293 out_entry->
authors.push_back(author);
297 out_entry->
description = j_entry[
"description"].GetString();
298 out_entry->
tags = j_entry[
"tags"].GetString();
299 out_entry->
default_skin = j_entry[
"default_skin"].GetString();
301 out_entry->
hasSubmeshs = j_entry[
"hasSubmeshs"].GetBool();
302 out_entry->
nodecount = j_entry[
"nodecount"].GetInt();
303 out_entry->
beamcount = j_entry[
"beamcount"].GetInt();
304 out_entry->
shockcount = j_entry[
"shockcount"].GetInt();
305 out_entry->
fixescount = j_entry[
"fixescount"].GetInt();
306 out_entry->
hydroscount = j_entry[
"hydroscount"].GetInt();
307 out_entry->
wheelcount = j_entry[
"wheelcount"].GetInt();
309 out_entry->
commandscount = j_entry[
"commandscount"].GetInt();
310 out_entry->
flarescount = j_entry[
"flarescount"].GetInt();
311 out_entry->
propscount = j_entry[
"propscount"].GetInt();
312 out_entry->
wingscount = j_entry[
"wingscount"].GetInt();
314 out_entry->
turbojetcount = j_entry[
"turbojetcount"].GetInt();
315 out_entry->
rotatorscount = j_entry[
"rotatorscount"].GetInt();
316 out_entry->
exhaustscount = j_entry[
"exhaustscount"].GetInt();
319 out_entry->
truckmass = j_entry[
"truckmass"].GetFloat();
320 out_entry->
loadmass = j_entry[
"loadmass"].GetFloat();
321 out_entry->
minrpm = j_entry[
"minrpm"].GetFloat();
322 out_entry->
maxrpm = j_entry[
"maxrpm"].GetFloat();
323 out_entry->
torque = j_entry[
"torque"].GetFloat();
324 out_entry->
customtach = j_entry[
"customtach"].GetBool();
328 out_entry->
rescuer = j_entry[
"rescuer"].GetBool();
330 out_entry->
numgears = j_entry[
"numgears"].GetInt();
331 out_entry->
enginetype =
static_cast<char>(j_entry[
"enginetype"].GetInt());
334 for (rapidjson::Value& j_module_name: j_entry[
"sectionconfigs"].GetArray())
340 for (rapidjson::Value& j_addonguid: j_entry[
"addonpart_guids"].GetArray())
346 for (rapidjson::Value& j_addonfname: j_entry[
"addonpart_filenames"].GetArray())
360 rapidjson::Document j_doc;
362 !j_doc.IsObject() || !j_doc.HasMember(
"entries") || !j_doc[
"entries"].IsArray())
364 RoR::Log(
"[RoR|ModCache] Error, cache file still invalid after check/update, content selector will be empty.");
370 RoR::Log(
"[RoR|ModCache] Invalid cache file format");
374 for (rapidjson::Value& j_entry: j_doc[
"entries"].GetArray())
391 std::vector<String> paths;
394 std::string fn = entry->resource_bundle_path;
395 if (entry->resource_bundle_type ==
"FileSystem")
404 if (std::find(paths.begin(), paths.end(), fn) == paths.end())
411 entry->deleted =
true;
424 String group = entry->resource_group;
427 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
428 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
435 RoR::Log(
"[RoR|ModCache] Searching for duplicates ...");
436 std::map<String, String> possible_duplicates;
444 String dnameA = entryA->
dname;
445 StringUtil::toLowerCase(dnameA);
446 StringUtil::trim(dnameA);
448 StringUtil::toLowerCase(dirA);
449 String basenameA, basepathA;
450 StringUtil::splitFilename(dirA, basenameA, basepathA);
452 StringUtil::toLowerCase(filenameWUIDA);
462 StringUtil::toLowerCase(filenameWUIDB);
463 if (filenameWUIDA != filenameWUIDB)
466 String dnameB = entryB->
dname;
467 StringUtil::toLowerCase(dnameB);
468 StringUtil::trim(dnameB);
469 if (dnameA != dnameB)
473 StringUtil::toLowerCase(dirB);
474 String basenameB, basepathB;
475 StringUtil::splitFilename(dirB, basenameB, basepathB);
476 basenameA = Ogre::StringUtil::replaceAll(basenameA,
" ",
"_");
477 basenameA = Ogre::StringUtil::replaceAll(basenameA,
"-",
"_");
478 basenameB = Ogre::StringUtil::replaceAll(basenameB,
" ",
"_");
479 basenameB = Ogre::StringUtil::replaceAll(basenameB,
"-",
"_");
485 LOG(
"- duplicate: " + entryA->
fpath + entryA->
fname
488 int idx = entryA->
fpath.size() < entryB->
fpath.size() ? i : j;
497 for (
auto duplicate : possible_duplicates)
499 LOG(
"- possible duplicate: ");
500 LOG(
" - " + duplicate.first);
501 LOG(
" - " + duplicate.second);
509 if (modid == entry->number)
519 if (fname == entry->fname)
541 rapidjson::Value j_entry(rapidjson::kObjectType);
544 j_entry.AddMember(
"usagecounter", entry->
usagecounter, j_doc.GetAllocator());
545 j_entry.AddMember(
"addtimestamp",
static_cast<int64_t
>(entry->
addtimestamp), j_doc.GetAllocator());
546 j_entry.AddMember(
"resource_bundle_type", rapidjson::StringRef(entry->
resource_bundle_type.c_str()), j_doc.GetAllocator());
547 j_entry.AddMember(
"resource_bundle_path", rapidjson::StringRef(entry->
resource_bundle_path.c_str()), j_doc.GetAllocator());
548 j_entry.AddMember(
"fpath", rapidjson::StringRef(entry->
fpath.c_str()), j_doc.GetAllocator());
549 j_entry.AddMember(
"fname", rapidjson::StringRef(entry->
fname.c_str()), j_doc.GetAllocator());
550 j_entry.AddMember(
"fname_without_uid", rapidjson::StringRef(entry->
fname_without_uid.c_str()), j_doc.GetAllocator());
551 j_entry.AddMember(
"fext", rapidjson::StringRef(entry->
fext.c_str()), j_doc.GetAllocator());
552 j_entry.AddMember(
"filetime",
static_cast<int64_t
>(entry->
filetime), j_doc.GetAllocator());
553 j_entry.AddMember(
"dname", rapidjson::StringRef(entry->
dname.c_str()), j_doc.GetAllocator());
554 j_entry.AddMember(
"categoryid", entry->
categoryid, j_doc.GetAllocator());
555 j_entry.AddMember(
"uniqueid", rapidjson::StringRef(entry->
uniqueid.c_str()), j_doc.GetAllocator());
556 j_entry.AddMember(
"guid", rapidjson::StringRef(entry->
guid.c_str()), j_doc.GetAllocator());
557 j_entry.AddMember(
"version", entry->
version, j_doc.GetAllocator());
558 j_entry.AddMember(
"filecachename", rapidjson::StringRef(entry->
filecachename.c_str()), j_doc.GetAllocator());
561 rapidjson::Value j_authors(rapidjson::kArrayType);
564 rapidjson::Value j_author(rapidjson::kObjectType);
566 j_author.AddMember(
"type", rapidjson::StringRef(author.
type.c_str()), j_doc.GetAllocator());
567 j_author.AddMember(
"name", rapidjson::StringRef(author.
name.c_str()), j_doc.GetAllocator());
568 j_author.AddMember(
"email", rapidjson::StringRef(author.
email.c_str()), j_doc.GetAllocator());
569 j_author.AddMember(
"id", author.
id, j_doc.GetAllocator());
571 j_authors.PushBack(j_author, j_doc.GetAllocator());
573 j_entry.AddMember(
"authors", j_authors, j_doc.GetAllocator());
576 j_entry.AddMember(
"description", rapidjson::StringRef(entry->
description.c_str()), j_doc.GetAllocator());
577 j_entry.AddMember(
"tags", rapidjson::StringRef(entry->
tags.c_str()), j_doc.GetAllocator());
578 j_entry.AddMember(
"default_skin", rapidjson::StringRef(entry->
default_skin.c_str()), j_doc.GetAllocator());
579 j_entry.AddMember(
"fileformatversion", entry->
fileformatversion, j_doc.GetAllocator());
580 j_entry.AddMember(
"hasSubmeshs", entry->
hasSubmeshs, j_doc.GetAllocator());
581 j_entry.AddMember(
"nodecount", entry->
nodecount, j_doc.GetAllocator());
582 j_entry.AddMember(
"beamcount", entry->
beamcount, j_doc.GetAllocator());
583 j_entry.AddMember(
"shockcount", entry->
shockcount, j_doc.GetAllocator());
584 j_entry.AddMember(
"fixescount", entry->
fixescount, j_doc.GetAllocator());
585 j_entry.AddMember(
"hydroscount", entry->
hydroscount, j_doc.GetAllocator());
586 j_entry.AddMember(
"wheelcount", entry->
wheelcount, j_doc.GetAllocator());
587 j_entry.AddMember(
"propwheelcount", entry->
propwheelcount, j_doc.GetAllocator());
588 j_entry.AddMember(
"commandscount", entry->
commandscount, j_doc.GetAllocator());
589 j_entry.AddMember(
"flarescount", entry->
flarescount, j_doc.GetAllocator());
590 j_entry.AddMember(
"propscount", entry->
propscount, j_doc.GetAllocator());
591 j_entry.AddMember(
"wingscount", entry->
wingscount, j_doc.GetAllocator());
592 j_entry.AddMember(
"turbopropscount", entry->
turbopropscount, j_doc.GetAllocator());
593 j_entry.AddMember(
"turbojetcount", entry->
turbojetcount, j_doc.GetAllocator());
594 j_entry.AddMember(
"rotatorscount", entry->
rotatorscount, j_doc.GetAllocator());
595 j_entry.AddMember(
"exhaustscount", entry->
exhaustscount, j_doc.GetAllocator());
596 j_entry.AddMember(
"flexbodiescount", entry->
flexbodiescount, j_doc.GetAllocator());
597 j_entry.AddMember(
"soundsourcescount", entry->
soundsourcescount, j_doc.GetAllocator());
598 j_entry.AddMember(
"truckmass", entry->
truckmass, j_doc.GetAllocator());
599 j_entry.AddMember(
"loadmass", entry->
loadmass, j_doc.GetAllocator());
600 j_entry.AddMember(
"minrpm", entry->
minrpm, j_doc.GetAllocator());
601 j_entry.AddMember(
"maxrpm", entry->
maxrpm, j_doc.GetAllocator());
602 j_entry.AddMember(
"torque", entry->
torque, j_doc.GetAllocator());
603 j_entry.AddMember(
"customtach", entry->
customtach, j_doc.GetAllocator());
604 j_entry.AddMember(
"custom_particles", entry->
custom_particles, j_doc.GetAllocator());
605 j_entry.AddMember(
"forwardcommands", entry->
forwardcommands, j_doc.GetAllocator());
606 j_entry.AddMember(
"importcommands", entry->
importcommands, j_doc.GetAllocator());
607 j_entry.AddMember(
"rescuer", entry->
rescuer, j_doc.GetAllocator());
608 j_entry.AddMember(
"driveable", entry->
driveable, j_doc.GetAllocator());
609 j_entry.AddMember(
"numgears", entry->
numgears, j_doc.GetAllocator());
610 j_entry.AddMember(
"enginetype", entry->
enginetype, j_doc.GetAllocator());
613 rapidjson::Value j_sectionconfigs(rapidjson::kArrayType);
616 j_sectionconfigs.PushBack(rapidjson::StringRef(module_name.c_str()), j_doc.GetAllocator());
618 j_entry.AddMember(
"sectionconfigs", j_sectionconfigs, j_doc.GetAllocator());
621 rapidjson::Value j_addonguids(rapidjson::kArrayType);
624 j_addonguids.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
626 j_entry.AddMember(
"addonpart_guids", j_addonguids, j_doc.GetAllocator());
628 rapidjson::Value j_addonfnames(rapidjson::kArrayType);
631 j_addonfnames.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
633 j_entry.AddMember(
"addonpart_filenames", j_addonfnames, j_doc.GetAllocator());
636 j_entry.AddMember(
"tuneup_associated_filename", rapidjson::StringRef(entry->
tuneup_associated_filename.c_str()), j_doc.GetAllocator());
639 j_entries.PushBack(j_entry, j_doc.GetAllocator());
645 rapidjson::Document j_doc;
651 rapidjson::Value j_entries(rapidjson::kArrayType);
659 j_doc.AddMember(
"entries", j_entries, j_doc.GetAllocator());
673 String group = entry->resource_group;
676 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
677 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
686 size_t pos = uidstr.find(
"-");
687 if (pos != String::npos && pos >= 3 && uidstr.substr(pos - 3, 3) ==
"UID")
688 return uidstr.substr(pos + 1, uidstr.length() - pos);
694 size_t pos = sha1str.find_first_of(
"-_");
695 if (pos != String::npos && pos >= 20)
696 return sha1str.substr(pos + 1, sha1str.length() - pos);
702 String type = f.archive ? f.archive->getType() :
"FileSystem";
703 String path = f.archive ? f.archive->getName() :
"";
706 { return !entry->deleted && entry->fname == f.filename && entry->resource_bundle_path == path; }) !=
m_entries.end())
709 RoR::LogFormat(
"[RoR|CacheSystem] Preparing to add file '%f'", f.filename.c_str());
713 DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(f.filename, group);
716 std::vector<CacheEntryPtr> new_entries;
721 new_entries.push_back(entry);
723 else if (ext ==
"skin")
726 for (
auto skin_def: new_skins)
730 new_entries.push_back(entry);
733 else if (ext ==
"addonpart")
737 new_entries.push_back(entry);
739 else if (ext ==
"tuneup")
742 for (
auto tuneup_def: new_tuneups)
746 new_entries.push_back(entry);
749 else if (ext ==
"assetpack")
753 new_entries.push_back(entry);
759 new_entries.push_back(entry);
762 for (
auto& entry: new_entries)
764 Ogre::StringUtil::toLowerCase(entry->
guid);
765 entry->
fpath = f.path;
766 entry->
fname = f.filename;
785 catch (Ogre::Exception& e)
787 RoR::LogFormat(
"[RoR|CacheSystem] Error processing file '%s', message :%s",
788 f.filename.c_str(), e.getFullDescription().c_str());
806 if (!def->name.empty())
808 entry->
dname = def->name;
812 entry->
dname =
"@" + file_name;
816 std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
817 for (; desc_itor != def->root_module->description.end(); desc_itor++)
823 std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
824 for (; author_itor != def->root_module->author.end(); author_itor++)
827 author.
email = author_itor->email;
828 author.
id = (author_itor->_has_forum_account) ?
static_cast<int>(author_itor->forum_account_id) : -1;
829 author.
name = author_itor->name;
830 author.
type = author_itor->type;
832 entry->
authors.push_back(author);
836 if (def->root_module->default_skin.size() > 0)
838 entry->
default_skin = def->root_module->default_skin.back().skin_name;
842 std::map<Ogre::String, std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = def->user_modules.begin();
843 for (; module_itor != def->user_modules.end(); module_itor++)
850 if (def->root_module->engine.size() > 0)
852 RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
858 if (def->root_module->engoption.size() > 0)
860 entry->
enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
865 if (def->root_module->fileinfo.size() > 0)
867 RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
885 module_itor = def->user_modules.begin();
886 for (; module_itor != def->user_modules.end(); module_itor++)
888 if (module_itor->second->engine.size() > 0)
890 vehicle_type =
TRUCK;
892 else if (module_itor->second->screwprops.size() > 0)
897 else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
903 if (def->root_module->engine.size() > 0)
905 vehicle_type =
TRUCK;
907 else if (def->root_module->screwprops.size() > 0)
912 else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
917 if (def->root_module->globals.size() > 0)
919 entry->
truckmass = def->root_module->globals[def->root_module->globals.size() - 1].dry_mass;
920 entry->
loadmass = def->root_module->globals[def->root_module->globals.size() - 1].cargo_mass;
926 if (def->root_module->guid.size() > 0)
928 entry->
guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
929 Ogre::StringUtil::toLowerCase(entry->
guid);
932 if (def->root_module->fileformatversion.size() > 0)
934 entry->
fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
936 entry->
hasSubmeshs =
static_cast<int>(def->root_module->submeshes.size() > 0);
937 entry->
nodecount =
static_cast<int>(def->root_module->nodes.size());
938 entry->
beamcount =
static_cast<int>(def->root_module->beams.size());
939 entry->
shockcount =
static_cast<int>(def->root_module->shocks.size() + def->root_module->shocks2.size());
940 entry->
fixescount =
static_cast<int>(def->root_module->fixes.size());
941 entry->
hydroscount =
static_cast<int>(def->root_module->hydros.size());
943 entry->
commandscount =
static_cast<int>(def->root_module->commands2.size());
944 entry->
flarescount =
static_cast<int>(def->root_module->flares2.size());
945 entry->
propscount =
static_cast<int>(def->root_module->props.size());
946 entry->
wingscount =
static_cast<int>(def->root_module->wings.size());
947 entry->
turbopropscount =
static_cast<int>(def->root_module->turboprops2.size());
948 entry->
rotatorscount =
static_cast<int>(def->root_module->rotators.size() + def->root_module->rotators2.size());
949 entry->
exhaustscount =
static_cast<int>(def->root_module->exhausts.size());
951 entry->
turbojetcount =
static_cast<int>(def->root_module->turbojets.size());
952 entry->
flexbodiescount =
static_cast<int>(def->root_module->flexbodies.size());
953 entry->
soundsourcescount =
static_cast<int>(def->root_module->soundsources.size() + def->root_module->soundsources.size());
957 for (
const auto&
w : def->root_module->wheels)
963 for (
const auto&
w : def->root_module->wheels2)
969 for (
const auto&
w : def->root_module->meshwheels)
975 for (
const auto&
w : def->root_module->meshwheels2)
981 for (
const auto&
w : def->root_module->flexbodywheels)
988 if (!def->root_module->axles.empty())
990 entry->
propwheelcount =
static_cast<int>(def->root_module->axles.size() * 2);
998 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"dds"))
1001 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"png"))
1004 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"jpg"))
1020 if (entry->
fname.empty())
1023 String bundle_basename, bundle_path;
1028 if (entry->
fext ==
"skin")
1030 if (entry->
skin_def->thumbnail.empty())
1032 src_path = entry->
skin_def->thumbnail;
1033 String mini_fbase, minitype;
1034 StringUtil::splitBaseFilename(entry->
skin_def->thumbnail, mini_fbase, minitype);
1035 dst_path = bundle_basename +
"_" + mini_fbase +
".mini." + minitype;
1040 StringUtil::splitBaseFilename(entry->
fname, fbase, fext);
1041 String minifn = fbase +
"-mini.";
1043 if (minitype.empty())
1045 src_path = minifn + minitype;
1046 dst_path = bundle_basename +
"_" + entry->
fname +
".mini." + minitype;
1051 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(src_path, group);
1052 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(dst_path,
RGN_CACHE,
true);
1053 std::vector<char> buf(src_ds->size());
1054 size_t read = src_ds->read(buf.data(), src_ds->size());
1057 dst_ds->write(buf.data(), read);
1061 catch (Ogre::Exception& e)
1063 LOG(
"error while generating file cache: " + e.getFullDescription());
1066 LOG(
"done generating file cache!");
1071 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.zip");
1072 auto skinzips = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.skinzip");
1073 for (
const auto& skinzip : *skinzips)
1074 files->push_back(skinzip);
1076 int i = 0, count =
static_cast<int>(
files->size());
1079 int progress = ((float)i++ / (
float)count) * 100;
1081 _L(
"Loading zips in group "), group,
file.filename, i, count);
1096 RoR::LogFormat(
"[RoR|ModCache] Adding archive '%s'", path.c_str());
1097 ResourceGroupManager::getSingleton().createResourceGroup(
RGN_TEMP,
false);
1100 ResourceGroupManager::getSingleton().addResourceLocation(path,
"Zip",
RGN_TEMP);
1103 LOG(
"No usable content in: '" + path +
"'");
1106 catch (Ogre::Exception& e)
1108 LOG(
"Error while opening archive: '" + path +
"': " + e.getFullDescription());
1110 ResourceGroupManager::getSingleton().destroyResourceGroup(
RGN_TEMP);
1120 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*." + ext);
1159 if (!skin_def->author_name.empty())
1162 a.
id = skin_def->author_id;
1163 a.
name = skin_def->author_name;
1167 entry->
dname = skin_def->name;
1168 entry->
guid = skin_def->guid;
1173 Ogre::StringUtil::toLowerCase(entry->
guid);
1196 Ogre::StringUtil::toLowerCase(guid);
1202 Ogre::StringUtil::toLowerCase(fname);
1235 entry->
authors.push_back(author);
1259 Ogre::StringUtil::toLowerCase(entry->
guid);
1274 if (assetpack_entry)
1278 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1286 Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->
resource_group);
1287 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->
resource_group);
1289 catch (std::exception
const& e)
1292 fmt::format(
_L(
"Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->
fname, target_entry->
fname, e.what()));
1298 fmt::format(
_L(
"Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->
fname));
1304 Ogre::String group =
"";
1313 if (ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(filename))
1315 group = ResourceGroupManager::getSingleton().findGroupContainingResource(filename);
1322 String fname = entry->fname;
1323 String fname_without_uid = entry->fname_without_uid;
1324 StringUtil::toLowerCase(fname);
1325 StringUtil::toLowerCase(filename);
1326 StringUtil::toLowerCase(fname_without_uid);
1327 if (fname == filename || fname_without_uid == filename)
1331 filename = entry->fname;
1332 group = entry->resource_group;
1333 return !group.empty() && ResourceGroupManager::getSingleton().resourceExists(group, filename);
1337 catch (Ogre::Exception) {}
1351 LOG(
fmt::format(
"[RoR|CacheSystem] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->
fname));
1357 Ogre::StringUtil::toLowerCase(lower_bundlepath);
1359 std::string lower_dir = dir->
getStr();
1360 Ogre::StringUtil::toLowerCase(lower_dir);
1363 if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir,
true))
1366 ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1367 if (lower_bundlepath.size() > lower_dir.size())
1370 out_rgname =
fmt::format(
"{{bundle {}:{}}}", dir_label, localpath);
1385 std::string rg_name;
1409 if (entry->
fext ==
"skin")
1413 else if (entry->
fext ==
"tuneup")
1451 bool recursive =
false;
1456 if (entry->
fext ==
"terrn2")
1459 ResourceGroupManager::getSingleton().createResourceGroup(group,
true);
1460 ResourceGroupManager::getSingleton().addResourceLocation(
1463 else if (entry->
fext ==
"skin")
1467 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1468 ResourceGroupManager::getSingleton().addResourceLocation(
1472 else if (entry->
fext ==
"tuneup")
1475 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1476 ResourceGroupManager::getSingleton().addResourceLocation(
1484 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1485 ResourceGroupManager::getSingleton().addResourceLocation(
1495 ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1505 i_entry->resource_group = group;
1509 catch (Ogre::Exception& e)
1513 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1515 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1545 if (i_entry->resource_group == resource_group)
1548 i_entry->actor_def =
nullptr;
1549 i_entry->tuneup_def =
nullptr;
1550 i_entry->skin_def =
nullptr;
1552 i_entry->resource_group =
"";
1556 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1563 if (entry->dname == skin_name && entry->fext ==
"skin")
1581 if (cache_entry->
skin_def !=
nullptr)
1588 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1592 for (
auto def: new_skins)
1598 && entry->fname == cache_entry->
fname
1599 && entry->dname == def->name)
1601 entry->skin_def = def;
1607 if (cache_entry->
skin_def ==
nullptr)
1609 RoR::LogFormat(
"Definition of skin '%s' was not found in file '%s'",
1610 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1613 catch (Ogre::Exception& oex)
1615 RoR::LogFormat(
"[RoR] Error loading skin file '%s', message: %s",
1616 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1637 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1641 for (
auto def: new_tuneups)
1647 && entry->fname == cache_entry->
fname
1648 && entry->dname == def->name)
1650 entry->tuneup_def = def;
1658 RoR::LogFormat(
"Definition of tuneup '%s' was not found in file '%s'",
1659 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1662 catch (Ogre::Exception& oex)
1664 RoR::LogFormat(
"[RoR] Error loading tuneup file '%s', message: %s",
1665 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1676 fmt::format(
_LC(
"CacheSystem",
"Cannot create project '{}' - no source mod specified!"), request->
cpr_name));
1701 bool project_entry_created =
false;
1712 project_entry_created =
true;
1716 project_entry->
fext =
"tuneup";
1719 Ogre::StringUtil::toLowerCase(project_entry->
guid);
1755 Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1773 std::string temp_rg =
"TempProjectSourceRG";
1779 bool recursive =
false;
1780 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1783 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1786 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg,
"*.*");
1787 for (
size_t i = 0; i < filelist->size(); i++)
1789 Ogre::FileInfo fileinfo = filelist->at(i);
1793 (i+1)/filelist->size(),
1794 fmt::format(
"Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1800 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(fileinfo.filename, temp_rg);
1801 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(fileinfo.filename, project_entry->
resource_group);
1802 std::vector<char> buf(src_ds->size());
1803 size_t read = src_ds->read(buf.data(), src_ds->size());
1806 dst_ds->write(buf.data(), read);
1809 catch (Ogre::Exception& oex)
1812 fmt::format(
_LC(
"CacheSystem",
"Could not copy file '{}' to project '{}', message: {}."),
1813 fileinfo.filename, request->
cpr_name, oex.getDescription()));
1818 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1821 Ogre::FileSystemLayer::renameFile(
1827 if (project_entry_created)
1836 activity_type, project_entry->
number, 0, 0,
1837 project_entry->
fname, project_entry->
fext);
1839 return project_entry;
1864 fmt::format(
_LC(
"Tuning",
"Addon part '{}' was not found in mod cache (probably not installed)."), request->
mpr_subject));
2057 const std::string DELETEPROJ_TEMP_RG =
"DeleteProjectTempRG";
2058 Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG,
false);
2059 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2061 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(DELETEPROJ_TEMP_RG,
"*.*");
2062 LOG(
fmt::format(
"[RoR|ModCache] Deleting project '{}' (resource group '{}'), found {} files to erase.", entry->
fname, entry->
resource_group, filelist->size()));
2063 for (
size_t i = 0; i < filelist->size(); i++)
2065 Ogre::FileInfo fileinfo = filelist->at(i);
2069 fmt::format(
_LC(
"CacheSystem",
"Problem deleting project '{}' - could not delete file '{}'"), entry->
fname, fileinfo.filename));
2073 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2094 std::time_t cur_time = std::time(
nullptr);
2101 if ((entry->fext ==
"addonpart" && entry->addonpart_guids.count(query.
cqy_filter_guid) == 0) ||
2111 if (entry->fext ==
"addonpart"
2112 && entry->addonpart_filenames.size() > 0
2117 else if (entry->fext ==
"tuneup"
2118 && entry->tuneup_associated_filename !=
""
2127 if (entry->fext ==
"terrn2")
2129 if (entry->fext ==
"skin")
2131 else if (entry->fext ==
"addonpart")
2133 else if (entry->fext ==
"tuneup")
2135 else if (entry->fext ==
"assetpack")
2137 else if (entry->fext ==
"truck")
2139 else if (entry->fext ==
"car")
2141 else if (entry->fext ==
"boat")
2143 else if (entry->fext ==
"airplane")
2145 else if (entry->fext ==
"trailer")
2147 else if (entry->fext ==
"train")
2149 else if (entry->fext ==
"load")
2183 for (
AuthorInfo const& author: entry->authors)
2195 for (
AuthorInfo const& author: entry->authors)
2203 wheels_str << entry->wheelcount <<
"x" << entry->propwheelcount;
2229 Ogre::StringUtil::toLowerCase(data);
2230 size_t pos = data.find(query);
2231 if (pos != std::string::npos)
2233 out_score = score + pos;
2248 Ogre::StringUtil::toLowerCase(first);
2249 Ogre::StringUtil::toLowerCase(second);
2250 return first < second;