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>
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,
"-",
"_");
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 LOG(fmt::format(
"[RoR|ModCache] Preparing to add file '{}'", f.filename));
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;
843 catch (Ogre::Exception& e)
845 RoR::LogFormat(
"[RoR|ModCache] Error processing file '%s', message :%s",
846 f.filename.c_str(), e.getFullDescription().c_str());
864 if (!def->name.empty())
866 entry->
dname = def->name;
870 entry->
dname =
"@" + file_name;
874 std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
875 for (; desc_itor != def->root_module->description.end(); desc_itor++)
881 std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
882 for (; author_itor != def->root_module->author.end(); author_itor++)
885 author.
email = author_itor->email;
886 author.
id = (author_itor->_has_forum_account) ?
static_cast<int>(author_itor->forum_account_id) : -1;
887 author.
name = author_itor->name;
888 author.
type = author_itor->type;
890 entry->
authors.push_back(author);
894 if (def->root_module->default_skin.size() > 0)
896 entry->
default_skin = def->root_module->default_skin.back().skin_name;
900 std::map<Ogre::String, std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = def->user_modules.begin();
901 for (; module_itor != def->user_modules.end(); module_itor++)
908 if (def->root_module->engine.size() > 0)
910 RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
916 if (def->root_module->engoption.size() > 0)
918 entry->
enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
923 if (def->root_module->fileinfo.size() > 0)
925 RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
943 module_itor = def->user_modules.begin();
944 for (; module_itor != def->user_modules.end(); module_itor++)
946 if (module_itor->second->engine.size() > 0)
948 vehicle_type =
TRUCK;
950 else if (module_itor->second->screwprops.size() > 0)
955 else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
961 if (def->root_module->engine.size() > 0)
963 vehicle_type =
TRUCK;
965 else if (def->root_module->screwprops.size() > 0)
970 else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
975 if (def->root_module->globals.size() > 0)
977 entry->
truckmass = def->root_module->globals[def->root_module->globals.size() - 1].dry_mass;
978 entry->
loadmass = def->root_module->globals[def->root_module->globals.size() - 1].cargo_mass;
984 if (def->root_module->guid.size() > 0)
986 entry->
guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
987 Ogre::StringUtil::toLowerCase(entry->
guid);
990 if (def->root_module->fileformatversion.size() > 0)
992 entry->
fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
994 entry->
hasSubmeshs =
static_cast<int>(def->root_module->submeshes.size() > 0);
995 entry->
nodecount =
static_cast<int>(def->root_module->nodes.size());
996 entry->
beamcount =
static_cast<int>(def->root_module->beams.size());
997 entry->
shockcount =
static_cast<int>(def->root_module->shocks.size() + def->root_module->shocks2.size());
998 entry->
fixescount =
static_cast<int>(def->root_module->fixes.size());
999 entry->
hydroscount =
static_cast<int>(def->root_module->hydros.size());
1001 entry->
commandscount =
static_cast<int>(def->root_module->commands2.size());
1002 entry->
flarescount =
static_cast<int>(def->root_module->flares2.size());
1003 entry->
propscount =
static_cast<int>(def->root_module->props.size());
1004 entry->
wingscount =
static_cast<int>(def->root_module->wings.size());
1005 entry->
turbopropscount =
static_cast<int>(def->root_module->turboprops2.size());
1006 entry->
rotatorscount =
static_cast<int>(def->root_module->rotators.size() + def->root_module->rotators2.size());
1007 entry->
exhaustscount =
static_cast<int>(def->root_module->exhausts.size());
1009 entry->
turbojetcount =
static_cast<int>(def->root_module->turbojets.size());
1010 entry->
flexbodiescount =
static_cast<int>(def->root_module->flexbodies.size());
1011 entry->
soundsourcescount =
static_cast<int>(def->root_module->soundsources.size() + def->root_module->soundsources.size());
1015 for (
const auto&
w : def->root_module->wheels)
1021 for (
const auto&
w : def->root_module->wheels2)
1027 for (
const auto&
w : def->root_module->meshwheels)
1033 for (
const auto&
w : def->root_module->meshwheels2)
1039 for (
const auto&
w : def->root_module->flexbodywheels)
1046 if (!def->root_module->axles.empty())
1048 entry->
propwheelcount =
static_cast<int>(def->root_module->axles.size() * 2);
1056 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"dds"))
1059 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"png"))
1062 if (ResourceGroupManager::getSingleton().resourceExists(group, filename +
"jpg"))
1078 if (entry->
fname.empty())
1081 String bundle_basename, bundle_path;
1086 if (entry->
fext ==
"skin")
1088 if (entry->
skin_def->thumbnail.empty())
1090 src_path = entry->
skin_def->thumbnail;
1091 String mini_fbase, minitype;
1092 StringUtil::splitBaseFilename(entry->
skin_def->thumbnail, mini_fbase, minitype);
1093 dst_path = bundle_basename +
"_" + mini_fbase +
".mini." + minitype;
1098 StringUtil::splitBaseFilename(entry->
fname, fbase, fext);
1099 String minifn = fbase +
"-mini.";
1101 if (minitype.empty())
1103 src_path = minifn + minitype;
1104 dst_path = bundle_basename +
"_" + entry->
fname +
".mini." + minitype;
1109 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(src_path, group);
1110 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(dst_path,
RGN_CACHE,
true);
1111 std::vector<char> buf(src_ds->size());
1112 size_t read = src_ds->read(buf.data(), src_ds->size());
1115 dst_ds->write(buf.data(), read);
1119 catch (Ogre::Exception& e)
1121 LOG(
"error while generating file cache: " + e.getFullDescription());
1124 LOG(
"done generating file cache!");
1129 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.zip");
1130 auto skinzips = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*.skinzip");
1131 for (
const auto& skinzip : *skinzips)
1132 files->push_back(skinzip);
1134 int i = 0, count =
static_cast<int>(files->size());
1135 for (
const auto& file : *files)
1137 int progress = ((float)i++ / (
float)count) * 100;
1138 std::string text = fmt::format(
"{}{}\n{}\n{}/{}",
1139 _L(
"Loading zips in group "), group, file.filename, i, count);
1142 String path =
PathCombine(file.archive->getName(), file.filename);
1154 RoR::LogFormat(
"[RoR|ModCache] Adding archive '%s'", path.c_str());
1155 ResourceGroupManager::getSingleton().createResourceGroup(
RGN_TEMP,
false);
1158 ResourceGroupManager::getSingleton().addResourceLocation(path,
"Zip",
RGN_TEMP);
1161 LOG(
"No usable content in: '" + path +
"'");
1164 catch (Ogre::Exception& e)
1166 LOG(
"Error while opening archive: '" + path +
"': " + e.getFullDescription());
1168 ResourceGroupManager::getSingleton().destroyResourceGroup(
RGN_TEMP);
1178 auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group,
"*." + ext);
1179 for (
const auto& file : *files)
1181 this->
AddFile(group, file, ext);
1201 fmt::format(
"Mod cache entry not populated - could not load terrain {}", ds->getName()));
1209 a.
name = author.name;
1210 a.
type = author.type;
1214 entry->
dname = def->name;
1217 entry->
version = def->version;
1222 if (!skin_def->author_name.empty())
1225 a.
id = skin_def->author_id;
1226 a.
name = skin_def->author_name;
1230 entry->
dname = skin_def->name;
1231 entry->
guid = skin_def->guid;
1236 Ogre::StringUtil::toLowerCase(entry->
guid);
1259 Ogre::StringUtil::toLowerCase(guid);
1265 Ogre::StringUtil::toLowerCase(fname);
1298 entry->
authors.push_back(author);
1334 entry->
authors.push_back(author);
1380 entry->
authors.push_back(author);
1405 Ogre::StringUtil::toLowerCase(entry->
guid);
1420 if (assetpack_entry)
1424 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1432 Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->
resource_group);
1433 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->
resource_group);
1435 catch (std::exception
const& e)
1438 fmt::format(
_L(
"Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->
fname, target_entry->
fname, e.what()));
1444 fmt::format(
_L(
"Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->
fname));
1457 LOG(fmt::format(
"[RoR|ModCache] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->
fname));
1463 Ogre::StringUtil::toLowerCase(lower_bundlepath);
1465 std::string lower_dir = dir->
getStr();
1466 Ogre::StringUtil::toLowerCase(lower_dir);
1469 if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir,
true))
1472 ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1473 if (lower_bundlepath.size() > lower_dir.size())
1476 out_rgname = fmt::format(
"{{bundle {}:{}}}", dir_label, localpath);
1491 std::string rg_name;
1515 if (entry->
fext ==
"skin")
1519 else if (entry->
fext ==
"tuneup")
1557 bool recursive =
false;
1562 if (entry->
fext ==
"terrn2")
1565 ResourceGroupManager::getSingleton().createResourceGroup(group,
true);
1566 ResourceGroupManager::getSingleton().addResourceLocation(
1569 else if (entry->
fext ==
"skin")
1573 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1574 ResourceGroupManager::getSingleton().addResourceLocation(
1578 else if (entry->
fext ==
"tuneup")
1581 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1582 ResourceGroupManager::getSingleton().addResourceLocation(
1586 else if (entry->
fext ==
"gadget")
1589 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1590 ResourceGroupManager::getSingleton().addResourceLocation(
1600 ResourceGroupManager::getSingleton().createResourceGroup(group,
false);
1601 ResourceGroupManager::getSingleton().addResourceLocation(
1611 ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1621 i_entry->resource_group = group;
1625 catch (Ogre::Exception& e)
1629 if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1631 ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1661 if (i_entry->resource_group == resource_group)
1664 i_entry->actor_def =
nullptr;
1665 i_entry->tuneup_def =
nullptr;
1666 i_entry->skin_def =
nullptr;
1668 i_entry->resource_group =
"";
1672 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1679 if (entry->dname == skin_name && entry->fext ==
"skin")
1697 if (cache_entry->
skin_def !=
nullptr)
1704 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1708 for (
auto def: new_skins)
1714 && entry->fname == cache_entry->
fname
1715 && entry->dname == def->name)
1717 entry->skin_def = def;
1723 if (cache_entry->
skin_def ==
nullptr)
1725 RoR::LogFormat(
"Definition of skin '%s' was not found in file '%s'",
1726 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1729 catch (Ogre::Exception& oex)
1731 RoR::LogFormat(
"[RoR] Error loading skin file '%s', message: %s",
1732 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1753 Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1757 for (
auto def: new_tuneups)
1763 && entry->fname == cache_entry->
fname
1764 && entry->dname == def->name)
1766 entry->tuneup_def = def;
1774 RoR::LogFormat(
"Definition of tuneup '%s' was not found in file '%s'",
1775 cache_entry->
dname.c_str(), cache_entry->
fname.c_str());
1778 catch (Ogre::Exception& oex)
1780 RoR::LogFormat(
"[RoR] Error loading tuneup file '%s', message: %s",
1781 cache_entry->
fname.c_str(), oex.getFullDescription().c_str());
1792 fmt::format(
_LC(
"CacheSystem",
"Cannot create project '{}' - no source mod specified!"), request->
cpr_name));
1804 fmt::format(
_LC(
"CacheSystem",
"Project directory '{}' already exists!"), request->
cpr_name));
1811 fmt::format(
_LC(
"CacheSystem",
"Project directory '{}' could not be created!"), request->
cpr_name));
1817 bool project_entry_created =
false;
1828 project_entry_created =
true;
1832 project_entry->
fext =
"tuneup";
1835 Ogre::StringUtil::toLowerCase(project_entry->
guid);
1847 project_entry->
fname = fmt::format(
"{}.{}", request->
cpr_name, project_entry->
fext);
1871 Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1889 std::string temp_rg =
"TempProjectSourceRG";
1895 bool recursive =
false;
1896 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1899 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1902 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg,
"*.*");
1903 for (
size_t i = 0; i < filelist->size(); i++)
1905 Ogre::FileInfo fileinfo = filelist->at(i);
1909 std::string basename, ext;
1910 Ogre::StringUtil::splitBaseFilename(fileinfo.filename, basename, ext);
1912 if (ext ==
"truck" || ext ==
"car" || ext ==
"load" || ext ==
"fixed" || ext ==
"boat" || ext ==
"airplane" || ext ==
"train" || ext ==
"trailer")
1920 (i+1)/filelist->size(),
1921 fmt::format(
"Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1927 DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(fileinfo.filename, temp_rg);
1928 DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(fileinfo.filename, project_entry->
resource_group);
1929 std::vector<char> buf(src_ds->size());
1930 size_t read = src_ds->read(buf.data(), src_ds->size());
1933 dst_ds->write(buf.data(), read);
1936 catch (Ogre::Exception& oex)
1939 fmt::format(
_LC(
"CacheSystem",
"Could not copy file '{}' to project '{}', message: {}."),
1940 fileinfo.filename, request->
cpr_name, oex.getDescription()));
1945 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1960 fmt::format(
_LC(
"CacheSystem",
"Could not load project file '{}' to perform fixups."),
1961 project_entry->
fname));
1993 fmt::format(
_LC(
"CacheSystem",
"Could not save fixed-up project file '{}'."),
1994 project_entry->
fname));
1999 if (project_entry_created)
2011 activity_type, project_entry->
number, 0, 0,
2012 project_entry->
fname, project_entry->
fext);
2014 return project_entry;
2031 fmt::format(
_LC(
"Tuning",
"Addon part '{}' is already equipped."), request->
mpr_subject));
2039 fmt::format(
_LC(
"Tuning",
"Addon part '{}' was not found in mod cache (probably not installed)."), request->
mpr_subject));
2198 fmt::format(
_LC(
"CacheSystem",
"Error loading tuneup: file '{}', not found in mod cache"), request->
mpr_subject));
2219 fmt::format(
_LC(
"CacheSystem",
"Error updating truck file: actor not found or disposed")));
2227 fmt::format(
_LC(
"CacheSystem",
"Error updating truck file: cache entry missing or not a project")));
2264 const std::string DELETEPROJ_TEMP_RG =
"DeleteProjectTempRG";
2265 Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG,
false);
2266 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2268 Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(DELETEPROJ_TEMP_RG,
"*.*");
2269 LOG(fmt::format(
"[RoR|ModCache] Deleting project '{}' (resource group '{}'), found {} files to erase.", entry->
fname, entry->
resource_group, filelist->size()));
2270 for (
size_t i = 0; i < filelist->size(); i++)
2272 Ogre::FileInfo fileinfo = filelist->at(i);
2276 fmt::format(
_LC(
"CacheSystem",
"Problem deleting project '{}' - could not delete file '{}'"), entry->
fname, fileinfo.filename));
2280 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2286 fmt::format(
_LC(
"CacheSystem",
"Problem deleting project '{}' - could not delete directory '{}'"), entry->
fname, entry->
resource_bundle_path));
2301 std::time_t cur_time = std::time(
nullptr);
2308 if ((entry->fext ==
"addonpart" && entry->addonpart_guids.count(query.
cqy_filter_guid) == 0) ||
2318 if (entry->fext ==
"addonpart"
2319 && entry->addonpart_filenames.size() > 0
2324 else if (entry->fext ==
"tuneup"
2325 && entry->tuneup_associated_filename !=
""
2334 if (entry->fext ==
"terrn2")
2336 if (entry->fext ==
"skin")
2338 else if (entry->fext ==
"addonpart")
2340 else if (entry->fext ==
"tuneup")
2342 else if (entry->fext ==
"assetpack")
2344 else if (entry->fext ==
"dashboard")
2346 else if (entry->fext ==
"gadget")
2348 else if (entry->fext ==
"truck")
2350 else if (entry->fext ==
"car")
2352 else if (entry->fext ==
"boat")
2354 else if (entry->fext ==
"airplane")
2356 else if (entry->fext ==
"trailer")
2358 else if (entry->fext ==
"train")
2360 else if (entry->fext ==
"load")
2394 for (
AuthorInfo const& author: entry->authors)
2406 for (
AuthorInfo const& author: entry->authors)
2414 wheels_str << entry->wheelcount <<
"x" << entry->propwheelcount;
2440 Ogre::StringUtil::toLowerCase(data);
2441 size_t pos = data.find(query);
2442 if (pos != std::string::npos)
2444 out_score = score + pos;
2459 Ogre::StringUtil::toLowerCase(first);
2460 Ogre::StringUtil::toLowerCase(second);
2461 return first < second;
2469 std::string bundle_path;
2473 fmt::format(
_LC(
"CacheSystem",
"Could not delete resource bundle '{}': not found in mod cache."), bundle_filename));
2480 if (entry->resource_bundle_path == bundle_path)
2482 entry->deleted =
true;
2486 fmt::format(
_LC(
"CacheSystem",
"Deleted {} '{}' because bundle {} is being removed."), entry->fext, entry->dname, bundle_filename));
2496 Ogre::ArchiveManager::getSingleton().unload(bundle_path);
2497 if (!Ogre::FileSystemLayer::removeFile(bundle_path))
2500 fmt::format(
_LC(
"CacheSystem",
"Could not delete resource bundle file '{}' from disk."), bundle_filename));
2507 catch (Ogre::Exception& oex)
2510 fmt::format(
_LC(
"CacheSystem",
"Could not delete resource bundle '{}', message: {}."), bundle_filename, oex.getDescription()));
2518 std::string path, basename;
2519 Ogre::StringUtil::splitFilename(entry->resource_bundle_path, basename, path);
2520 if (basename == repo_filename)
2522 out_filepath = entry->resource_bundle_path;
Central state/object manager and communications hub.
#define ROR_ASSERT(_EXPR)
void LOG(const char *msg)
Legacy alias - formerly a macro.
Ogre::String detectMiniType(String filename, String group)
static bool CheckAndReplacePathIgnoreCase(const CacheEntryPtr &entry, CVar *dir, const std::string &dir_label, std::string &out_rgname)
A database of user-installed content alias 'mods' (vehicles, terrains...)
#define CACHE_FILE_FRESHNESS
#define CACHE_FILE_FORMAT
Manager for all visuals belonging to a single actor.
Checks the rig-def file syntax and loads data to memory.
Core data structures for simulation; Everything affected by by either physics, network or user intera...
Checks the rig-def file syntax and pulls data to File object.
SequentialImporter * GetSequentialImporter()
RigDef::DocumentPtr GetFile()
void ProcessOgreStream(Ogre::DataStream *stream, Ogre::String resource_group)
CacheEntryPtr & getUsedSkinEntry()
float getMinHeight(bool skip_virtual_nodes=true)
void removeWorkingTuneupDef()
Deletes the working tuneup def object if it exists.
Ogre::Vector3 getPosition()
void ensureWorkingTuneupDef()
Creates a working tuneup def if it doesn't exist yet.
void propagateNodeBeamChangesToDef()
Back-propagates changes done by N/B-utils UI to the def-document.
Ogre::String getSectionConfig()
CacheEntryPtr & getUsedActorEntry()
The actor entry itself.
TuneupDefPtr & getWorkingTuneupDef()
void ExportActorDef(RigDef::DocumentPtr def, std::string filename, std::string rg_name)
static bool DoubleCheckForAddonpartConflict(ActorPtr target_actor, CacheEntryPtr addonpart_entry)
Quake-style console variable, defined in RoR.cfg or crated via Console UI and scripts.
std::string const & getStr() const
CacheEntryID_t number
Sequential number, assigned internally, used by Selector-GUI.
std::vector< Ogre::String > sectionconfigs
Ogre::String fname
filename
int version
file's version
Ogre::String fext
file's extension
std::set< std::string > addonpart_guids
GUIDs of all vehicles this addonpart is used with.
Ogre::String fpath
filepath relative to the .zip file
std::string tuneup_associated_filename
Value of 'filename' field in the tuneup file; always lowercase.
int categoryid
category id
Ogre::String dname
name parsed from the file
std::vector< AuthorInfo > authors
authors
SkinDocumentPtr skin_def
Cached skin info, added on first use or during cache rebuild.
std::time_t addtimestamp
timestamp when this file was added to the cache
CacheEntry()
default constructor resets the data.
Ogre::String resource_group
Resource group of the loaded bundle. Empty if not loaded yet.
TuneupDefPtr tuneup_def
Cached tuning info, added on first use or during cache rebuild.
std::set< std::string > addonpart_filenames
File names of all vehicles this addonpart is used with. If empty, any filename goes.
int usagecounter
how much it was used already
Ogre::String fname_without_uid
filename
std::string resource_bundle_type
Archive type recognized by OGRE resource system: 'FileSystem' or 'Zip'.
std::string resource_bundle_path
Path of ZIP or directory which contains the media. Shared between CacheEntries, loaded only once.
bool deleted
is this mod deleted?
Ogre::String categoryname
category name
Ogre::String filecachename
preview image filename
RigDef::DocumentPtr actor_def
Cached actor definition (aka truckfile) after first spawn.
std::time_t filetime
filetime
Ogre::String uniqueid
file's unique id
Ogre::String guid
global unique id; Type "addonpart" leaves this empty and uses addonpart_guids; Always lowercase.
void ReLoadResource(CacheEntryPtr &t)
Forces reloading the associated bundle.
void GenerateFileCache(CacheEntryPtr &entry, Ogre::String group)
void LoadSupplementaryDocuments(CacheEntryPtr &t)
Loads the associated .truck*, .skin and .tuneup files.
std::vector< std::string > m_content_dirs
the various mod directories we track in the cache system
std::vector< Ogre::String > m_known_extensions
the extensions we track in the cache system
void FillTerrainDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds, Ogre::String fname)
void UnLoadResource(CacheEntryPtr &t)
Unloads associated bundle, destroying all spawned actors.
void ParseZipArchives(Ogre::String group)
bool Match(size_t &out_score, std::string data, std::string const &query, size_t)
void RemoveFileCache(CacheEntryPtr &entry)
std::set< Ogre::String > m_resource_paths
A temporary list of existing resource paths.
void ModifyProject(ModifyProjectRequest *request)
std::time_t m_update_time
Ensures that all inserted files share the same timestamp.
const std::vector< CacheEntryPtr > & GetEntries() const
void LoadAssetPack(CacheEntryPtr &t_dest, Ogre::String const &assetpack_filename)
Adds asset pack to the requesting cache entry's resource group.
static Ogre::String StripSHA1fromString(Ogre::String sha1str)
void FillTuneupDetailInfo(CacheEntryPtr &entry, TuneupDefPtr &tuneup_def)
void FillTruckDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds, Ogre::String fname, Ogre::String group)
void FillSkinDetailInfo(CacheEntryPtr &entry, std::shared_ptr< SkinDocument > &skin_def)
void ClearResourceGroups()
std::string m_filenames_hash_loaded
hash from cachefile, for quick update detection
std::vector< CacheEntryPtr > m_entries
bool ParseKnownFiles(Ogre::String group)
void FillGadgetDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
CacheEntryPtr FindEntryByFilename(RoR::LoaderType type, bool partial, const std::string &_filename_maybe_bundlequalified)
Returns NULL if none found; "Bundle-qualified" format also specifies the ZIP/directory in modcache,...
Ogre::String GetPrettyName(Ogre::String fname)
void GenerateHashFromFilenames()
For quick detection of added/removed content.
void ImportEntryFromJson(rapidjson::Value &j_entry, CacheEntryPtr &out_entry)
void DeleteProject(CacheEntryPtr &entry)
void ParseSingleZip(Ogre::String path)
std::string ActorTypeToName(ActorType driveable)
CacheEntryPtr FetchSkinByName(std::string const &skin_name)
static Ogre::String StripUIDfromString(Ogre::String uidstr)
size_t Query(CacheQuery &query)
void LoadAssociatedTuneupDef(CacheEntryPtr &cache_entry)
Loads+parses the .tuneup file and updates all related CacheEntries.
std::map< int, Ogre::String > m_categories
void LoadAssociatedSkinDef(CacheEntryPtr &cache_entry)
Loads+parses the .skin file and updates all related CacheEntries.
void AddFile(Ogre::String group, Ogre::FileInfo f, Ogre::String ext)
void WriteCacheFileJson()
CacheEntryPtr CreateProject(CreateProjectRequest *request)
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
bool IsPathContentDirRoot(const std::string &path) const
bool IsRepoFileInstalled(const std::string &repo_filename, std::string &out_filepath)
Checks whether a ZIP archive from the online repository is installed in the local modcache.
CacheEntryPtr GetEntryByNumber(int modid)
void FillAddonPartDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
CacheValidity EvaluateCacheValidity()
void ExportEntryToJson(rapidjson::Value &j_entries, rapidjson::Document &j_doc, CacheEntryPtr const &entry)
void FillDashboardDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
std::string m_filenames_hash_generated
stores hash over the content, for quick update detection
void LoadResource(CacheEntryPtr &t)
Loads the associated resource bundle if not already done.
static std::string ComposeResourceGroupName(const CacheEntryPtr &entry)
void FillAssetPackDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
void LoadModCache(CacheValidity validity)
CacheValidity LoadCacheFileJson()
void DeleteResourceBundleByFilename(const std::string &bundle_filename)
Deletes all CacheEntries which share the given resource bundle (ZIP or directory).
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
@ CONSOLE_MSGTYPE_INFO
Generic message.
@ CONSOLE_MSGTYPE_TERRN
Parsing/spawn/simulation messages for terrain.
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
void AddResourcePack(ResourcePack const &resource_pack, std::string const &override_rgn="")
Loads resources if not already loaded.
bool DeleteDiskFile(std::string const &filename, std::string const &rg_name)
std::string ListAllUserContent()
Used by ModCache for quick detection of added/removed content.
void InitManagedMaterials(std::string const &rg_name)
void CacheUpdatedNotice()
void SetProgress(int _percent, const std::string &_text="", bool render_frame=true)
GUI::TopMenubar TopMenubar
GUI::LoadingWindow LoadingWindow
GUI::GameMainMenu GameMainMenu
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
void ChainMessage(Message m)
Add to last pushed message's chain.
ActorManager * GetActorManager()
DebugViewType GetDebugView() const
static std::vector< SkinDocumentPtr > ParseSkins(Ogre::DataStreamPtr &stream)
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
const char * ToCStr() const
Terrn2DocumentPtr LoadTerrn2(Ogre::DataStreamPtr &ds)
static void ExportTuneup(Ogre::DataStreamPtr &stream, TuneupDefPtr &tuneup)
static std::vector< TuneupDefPtr > ParseTuneups(Ogre::DataStreamPtr &stream)
std::time_t GetFileLastModifiedTime(std::string const &path)
void CreateFolder(const char *path)
Path must be UTF-8 encoded.
bool FolderExists(const char *path)
Path must be UTF-8 encoded.
std::string PathCombine(std::string a, std::string b)
bool FileExists(const char *path)
Path must be UTF-8 encoded.
ActorType
< Aka 'Driveable'
@ TRUCK
its a truck (or other land vehicle)
@ NOT_DRIVEABLE
not drivable at all
@ AIRPLANE
its an airplane
@ AI
machine controlled by an Artificial Intelligence
@ MSG_SIM_SPAWN_ACTOR_REQUESTED
Payload = RoR::ActorSpawnRequest* (owner)
@ MSG_SIM_DELETE_ACTOR_REQUESTED
Payload = RoR::ActorPtr* (owner)
@ DISPOSED
removed from simulation, still in memory to satisfy pointers.
void TRIGGER_EVENT_ASYNC(scriptEvents type, int arg1, int arg2ex=0, int arg3ex=0, int arg4ex=0, std::string arg5ex="", std::string arg6ex="", std::string arg7ex="", std::string arg8ex="")
Asynchronously (via MSG_SIM_SCRIPT_EVENT_TRIGGERED) invoke script function eventCallbackEx(),...
std::shared_ptr< Document > DocumentPtr
ContentManager * GetContentManager()
GUIManager * GetGuiManager()
GameContext * GetGameContext()
CacheSystem * GetCacheSystem()
CVar * diag_log_console_echo
CVar * app_extra_mod_path
Ogre::String HashData(const char *key, int len)
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
LoaderType
< Search mode for ModCache::Query() & Operation mode for GUI::MainSelector
@ SAVE_TUNEUP
Dumps .tuneup file with CID_Tuneup from source actor, will not overwrite existing unless explicitly i...
@ ACTOR_PROJECT
Like DEFAULT but fixes up name + category in the truckfile.
@ TUNEUP_PROTECTED_WHEEL_RESET
'subject_id' is wheel ID.
@ TUNEUP_FORCED_VCAM_ROLE_RESET
'subject_id' is video camera ID.
@ TUNEUP_FORCEREMOVE_MANAGEDMAT_RESET
'subject' is managed material name.
@ TUNEUP_FORCEREMOVE_FLEXBODY_SET
'subject_id' is flexbody ID.
@ TUNEUP_PROTECTED_WHEEL_SET
'subject_id' is wheel ID.
@ TUNEUP_PROTECTED_MANAGEDMAT_SET
'subject' is managed material name.
@ TUNEUP_FORCEREMOVE_EXHAUST_SET
'subject_id' is exhaust ID.
@ TUNEUP_USE_ADDONPART_RESET
'subject' is addonpart filename.
@ TUNEUP_PROTECTED_PROP_SET
'subject_id' is prop ID.
@ TUNEUP_USE_ADDONPART_SET
'subject' is addonpart filename.
@ TUNEUP_FORCEREMOVE_PROP_SET
'subject_id' is prop ID.
@ TUNEUP_PROTECTED_EXHAUST_SET
'subject_id' is exhaust ID.
@ TUNEUP_PROTECTED_FLARE_SET
'subject_id' is flare ID.
@ TUNEUP_FORCED_WHEEL_SIDE_RESET
'subject_id' is wheel ID.
@ TUNEUP_FORCEREMOVE_MANAGEDMAT_SET
'subject' is managed material name.
@ TUNEUP_PROTECTED_FLEXBODY_RESET
'subject_id' is flexbody ID.
@ TUNEUP_PROTECTED_FLEXBODY_SET
'subject_id' is flexbody ID.
@ TUNEUP_FORCED_WHEEL_SIDE_SET
'subject_id' is wheel ID, 'value_int' is RoR::WheelSide
@ ACTOR_UPDATE_DEF_DOCUMENT
'subject' is empty; 'target_actor' is the actual subject. Propagates modifications from the live acto...
@ TUNEUP_PROTECTED_EXHAUST_RESET
'subject_id' is exhaust ID.
@ TUNEUP_PROTECTED_MANAGEDMAT_RESET
'subject' is managed material name.
@ TUNEUP_FORCED_VCAM_ROLE_SET
'subject_id' is video camera ID, 'value_int' is RoR::VideoCamRole
@ PROJECT_RESET_TUNEUP
'subject' is empty. This resets the auto-generated tuneup to orig. values.
@ TUNEUP_FORCEREMOVE_FLARE_RESET
'subject_id' is flare ID.
@ TUNEUP_PROTECTED_PROP_RESET
'subject_id' is prop ID.
@ TUNEUP_FORCEREMOVE_FLEXBODY_RESET
'subject_id' is flexbody ID.
@ TUNEUP_FORCEREMOVE_PROP_RESET
'subject_id' is prop ID.
@ TUNEUP_PROTECTED_FLARE_RESET
'subject_id' is flare ID.
@ TUNEUP_FORCEREMOVE_EXHAUST_RESET
'subject_id' is exhaust ID.
@ PROJECT_LOAD_TUNEUP
'subject' is tuneup filename. This overwrites the auto-generated tuneup with the save.
@ TUNEUP_FORCEREMOVE_FLARE_SET
'subject_id' is flare ID.
modCacheActivityType
Argument #1 of script event RoR::SE_GENERIC_MODCACHE_ACTIVITY
@ MODCACHEACTIVITY_BUNDLE_DELETED
Args: #1 type, #2 entry number.
@ MODCACHEACTIVITY_ENTRY_DELETED
Flagged as deleted, managed by shared pointers; Args: #1 type, #2 entry number, –,...
@ MODCACHEACTIVITY_ENTRY_MODIFIED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
@ MODCACHEACTIVITY_ENTRY_ADDED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
@ AUTHORS
Partial match in: author name/email.
@ FILENAME
Partial match in file name.
@ WHEELS
Wheel configuration, i.e. 4x4.
@ GUID
Partial match in: guid.
@ FULLTEXT
Partial match in: name, filename, description, author name/mail.
WheelSide
Used by rig-def/addonpart/tuneup formats to specify wheel rim mesh orientation.
std::shared_ptr< Terrn2Document > Terrn2DocumentPtr
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
RefCountingObjectPtr< Actor > ActorPtr
@ SE_GENERIC_MODCACHE_ACTIVITY
Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see RoR::mo...
void EraseIf(std::vector< T, A > &c, Predicate pred)
void SplitBundleQualifiedFilename(const std::string &bundleQualifiedFilename, std::string &out_bundleName, std::string &out_filename)
@ CID_Max
SPECIAL VALUE - Maximum allowed to be present in any mod files.
@ CID_Projects
For truck files under 'projects/' directory, to allow listing from editors.
@ CID_Tuneups
For unsorted tuneup files.
std::time_t getTimeStamp()
std::vector< float > gear_ratios
CacheEntryPtr asr_cache_entry
Optional, overrides 'asr_filename' and 'asr_cache_entry_num'.
TuneupDefPtr asr_working_tuneup
Only filled when editing tuneup via Tuning menu.
Ogre::Vector3 asr_position
CacheEntryPtr asr_skin_entry
Ogre::Quaternion asr_rotation
@ USER
Direct selection by user via GUI.
int cqy_filter_category_id
std::string cqy_filter_target_filename
Exact match (case-insensitive); leave empty to disable (currently only used with addonparts)
std::string cqy_filter_guid
Exact match (case-insensitive); leave empty to disable.
std::map< int, size_t > cqy_res_category_usage
Total usage (ignores search params + category filter)
std::time_t cqy_res_last_update
std::string cqy_search_string
CacheSearchMethod cqy_search_method
std::vector< CacheQueryResult > cqy_results
RoR::LoaderType cqy_filter_type
CacheQueryResult(CacheEntryPtr entry, size_t score)
bool operator<(CacheQueryResult const &other) const
static const ResourcePack TEXTURES
static const ResourcePack MESHES
static const ResourcePack SCRIPTS
static const ResourcePack MATERIALS
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
std::string cpr_description
Optional, implemented for tuneups.
CreateProjectRequestType cpr_type
CacheEntryPtr cpr_source_entry
The original mod to copy files from.
std::string cpr_name
Directory and also the mod file (without extension).
ActorPtr cpr_source_actor
Only for type SAVE_TUNEUP
bool isTokKeyword(int offset=0) const
std::string getTokKeyword(int offset=0) const
float getTokFloat(int offset=0) const
bool endOfFile(int offset=0) const
std::string getTokString(int offset=0) const
bool isTokString(int offset=0) const
bool isTokInt(int offset=0) const
int getTokInt(int offset=0) const
bool setTokString(int offset, const std::string &str)
bool setTokFloat(int offset, float val)
static const BitMask_t OPTION_ALLOW_SLASH_COMMENTS
Allow comments starting with //.
static const BitMask_t OPTION_ALLOW_SEPARATOR_COLON
Allow ':' as separator between tokens.
virtual bool saveToResource(std::string resource_name, std::string resource_group_name)
virtual void loadFromDataStream(Ogre::DataStreamPtr datastream, BitMask_t options=0)
virtual bool loadFromResource(std::string resource_name, std::string resource_group_name, BitMask_t options=0)
static const BitMask_t OPTION_FIRST_LINE_IS_TITLE
First non-empty & non-comment line is a naked string with spaces.
static const BitMask_t OPTION_ALLOW_NAKED_STRINGS
Allow strings without quotes, for backwards compatibility.
static const BitMask_t OPTION_PARENTHESES_CAPTURE_SPACES
If non-empty NAKED string encounters '(', following spaces will be captured until matching ')' is fou...
Unified game event system - all requests and state changes are reported using a message.
ModifyProjectRequestType mpr_type
ActorPtr mpr_target_actor
std::string filename
target vehicle filename
std::set< WheelID_t > protected_wheels
Wheels that cannot be altered via 'addonpart_tweak_wheel'.
std::set< FlareID_t > protected_flares
Flares which cannot be altered via 'addonpart_unwanted_flare' directive.
std::set< std::string > protected_managedmats
Managed materials which cannot be altered via 'addonpart_tweak_managedmaterial' directive.
std::set< ExhaustID_t > protected_exhausts
Exhausts which cannot be altered via 'addonpart_unwanted_exhaust' directive.
std::map< VideoCameraID_t, VideoCamRole > force_video_cam_roles
UI overrides.
std::set< FlexbodyID_t > protected_flexbodies
Flexbodies which cannot be altered via 'addonpart_tweak_flexbody' or 'addonpart_unwanted_flexbody' di...
std::set< std::string > force_remove_managedmats
User unticked an UI checkbox in Tuning menu, section Managed Materials.
std::set< std::string > use_addonparts
Addonpart filenames.
std::set< ExhaustID_t > force_remove_exhausts
User unticked an UI checkbox in Tuning menu, section Exhausts.
CacheCategoryId category_id
std::set< PropID_t > force_remove_props
UI overrides.
std::set< FlareID_t > force_remove_flares
User unticked an UI checkbox in Tuning menu, section Flares.
std::set< PropID_t > protected_props
Props which cannot be altered via 'addonpart_tweak_prop' or 'addonpart_unwanted_prop' directive.
std::string guid
target vehicle GUID
std::set< FlexbodyID_t > force_remove_flexbodies
UI overrides.
std::map< WheelID_t, WheelSide > force_wheel_sides
UI overrides.