RigsofRods
Soft-body Physics Simulation
CacheSystem.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2023 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
25 
26 #include "CacheSystem.h"
27 
28 #include "Actor.h"
29 #include "AddonPartFileFormat.h"
30 #include "Application.h"
31 #include "SimData.h"
32 #include "ContentManager.h"
33 #include "ErrorUtils.h"
34 #include "GUI_LoadingWindow.h"
35 #include "GUI_GameMainMenu.h"
36 #include "GUIManager.h"
37 #include "GenericFileFormat.h"
38 #include "GfxActor.h"
39 #include "GfxScene.h"
40 #include "Language.h"
41 #include "PlatformUtils.h"
42 #include "RigDef_Parser.h"
43 #include "ScriptEngine.h"
44 #include "SkinFileFormat.h"
45 #include "Terrain.h"
46 #include "Terrn2FileFormat.h"
47 #include "TuneupFileFormat.h"
48 #include "Utils.h"
49 
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>
57 #include <fstream>
58 
59 using namespace Ogre;
60 using namespace RoR;
61 
62 CacheEntry::CacheEntry() :
63  addtimestamp(0),
64  beamcount(0),
65  categoryid(CID_None),
66  commandscount(0),
67  custom_particles(false),
68  customtach(false),
69  deleted(false),
70  driveable(NOT_DRIVEABLE),
71  enginetype('t'), // enginetype = t = truck is default
72  exhaustscount(0),
73  fileformatversion(0),
74  filetime(0),
75  fixescount(0),
76  flarescount(0),
77  flexbodiescount(0),
78  forwardcommands(false),
79  hasSubmeshs(false),
80  hydroscount(0),
81  importcommands(false),
82  loadmass(0),
83  maxrpm(0),
84  minrpm(0),
85  nodecount(0),
86  number(0),
87  numgears(0),
88  propscount(0),
89  propwheelcount(0),
90  rescuer(false),
91  rotatorscount(0),
92  shockcount(0),
93  soundsourcescount(0),
94  torque(0),
95  truckmass(0),
96  turbojetcount(0),
97  turbopropscount(0),
98  usagecounter(0),
99  version(0),
100  wheelcount(0),
101  wingscount(0)
102 {
103 }
104 
106 {
107  // Destructs `TuneupDefPtr` which is a `RefCountingObjectPtr<>` so it doesn't compile without `#include "TuneupFileFormat.h"` and thus should not be in header.
108 }
109 
111 {
112  // Constructs `ActorPtr` - doesn't compile without `#include Actor.h` - not pretty if in header (even if auto-generated by C++).
113 }
114 
116 {
117  // Destructs `ActorPtr` - doesn't compile without `#include Actor.h` - not pretty if in header (even if auto-generated by C++).
118 }
119 
121  cqr_entry(entry),
122  cqr_score(score)
123 {}
124 
126 {
127  // register the extensions
128  m_known_extensions.push_back("machine");
129  m_known_extensions.push_back("fixed");
130  m_known_extensions.push_back("terrn2");
131  m_known_extensions.push_back("truck");
132  m_known_extensions.push_back("car");
133  m_known_extensions.push_back("boat");
134  m_known_extensions.push_back("airplane");
135  m_known_extensions.push_back("trailer");
136  m_known_extensions.push_back("load");
137  m_known_extensions.push_back("train");
138  m_known_extensions.push_back("skin");
139  m_known_extensions.push_back("addonpart");
140  m_known_extensions.push_back("tuneup");
141  m_known_extensions.push_back("assetpack");
142 
143  // register the dirs
144  m_content_dirs.push_back("mods");
145  m_content_dirs.push_back("packs");
146  m_content_dirs.push_back("terrains");
147  m_content_dirs.push_back("vehicles");
148  m_content_dirs.push_back("projects");
149 }
150 
152 {
153  m_resource_paths.clear();
155 
156  if (validity != CacheValidity::VALID)
157  {
158  if (validity == CacheValidity::NEEDS_REBUILD)
159  {
160  RoR::Log("[RoR|ModCache] Performing rebuild ...");
161  this->ClearCache();
162  }
163  else
164  {
165  RoR::Log("[RoR|ModCache] Performing update ...");
166  this->ClearResourceGroups();
167  this->PruneCache();
168  }
169  const bool orig_echo = App::diag_log_console_echo->getBool();
174  this->DetectDuplicates();
175  this->WriteCacheFileJson();
176 
177  this->LoadCacheFileJson();
178  }
179 
180  RoR::Log("[RoR|ModCache] Cache loaded");
181  m_loaded = true;
182 }
183 
184 CacheEntryPtr CacheSystem::FindEntryByFilename(LoaderType type, bool partial, const std::string& _filename_maybe_bundlequalified)
185 {
186  // "Bundle-qualified" format also specifies the ZIP/directory in modcache, i.e. "mybundle.zip:myactor.truck"
187  // Like the filename, the bundle name lookup is case-insensitive.
188  // -------------------------------------------------------------------------------------------------
189 
190  std::string filename;
191  std::string bundlename;
192  SplitBundleQualifiedFilename(_filename_maybe_bundlequalified, bundlename, filename);
193  StringUtil::toLowerCase(filename);
194  StringUtil::toLowerCase(bundlename);
195  size_t partial_match_length = std::numeric_limits<size_t>::max();
196  CacheEntryPtr partial_match = nullptr;
197  std::vector<CacheEntryPtr> log_candidates;
198  for (CacheEntryPtr& entry : m_entries)
199  {
200  if ((type == LT_Terrain) != (entry->fext == "terrn2") ||
201  (type == LT_AllBeam && entry->fext == "skin"))
202  continue;
203 
204  String fname = entry->fname;
205  String fname_without_uid = entry->fname_without_uid;
206  String bname;
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)
213  {
214  if (bundlename == "" || bname == bundlename)
215  {
216  return entry;
217  }
218  else
219  {
220  log_candidates.push_back(entry);
221  }
222  }
223  else if (partial &&
224  fname.length() < partial_match_length &&
225  fname.find(filename) != std::string::npos)
226  {
227  if (bundlename == "" || bname == bundlename)
228  {
229  partial_match = entry;
230  partial_match_length = fname.length();
231  }
232  else
233  {
234  log_candidates.push_back(entry);
235  }
236  }
237  }
238 
239  if (log_candidates.size() > 0)
240  {
242  fmt::format(_LC("CacheSystem", "Mod '{}' was not found in cache; candidates ({}) are:"), _filename_maybe_bundlequalified, log_candidates.size()));
243  for (CacheEntryPtr& entry: log_candidates)
244  {
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));
250  }
251  }
252 
253  return (partial) ? partial_match : nullptr;
254 }
255 
257 {
259 
260  // Load cache file
261  CacheValidity validity = this->LoadCacheFileJson();
262 
263  if (validity != CacheValidity::VALID)
264  {
265  RoR::Log("[RoR|ModCache] Cannot load cache file: wrong version, corrupted or missing.");
266  return validity;
267  }
268 
269  // Compare stored hash with generated hash
271  {
272  RoR::Log("[RoR|ModCache] Cache file out of date");
274  }
275 
276  for (auto& entry : m_entries)
277  {
278  std::string fn = entry->resource_bundle_path;
279  if (entry->resource_bundle_type == "FileSystem")
280  {
281  fn = PathCombine(fn, entry->fname);
282  }
283 
284  if ((entry->filetime != RoR::GetFileLastModifiedTime(fn)))
285  {
287  }
288  }
289 
290  RoR::Log("[RoR|ModCache] Cache valid");
291  return CacheValidity::VALID;
292 }
293 
294 void CacheSystem::ImportEntryFromJson(rapidjson::Value& j_entry, CacheEntryPtr & out_entry)
295 {
296  // Common details
297  out_entry->usagecounter = j_entry["usagecounter"].GetInt();
298  out_entry->addtimestamp = j_entry["addtimestamp"].GetInt();
299  out_entry->resource_bundle_type = j_entry["resource_bundle_type"].GetString();
300  out_entry->resource_bundle_path = j_entry["resource_bundle_path"].GetString();
301  out_entry->fpath = j_entry["fpath"].GetString();
302  out_entry->fname = j_entry["fname"].GetString();
303  out_entry->fname_without_uid = j_entry["fname_without_uid"].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();
310 
311  out_entry->guid = j_entry["guid"].GetString();
312  Ogre::StringUtil::trim(out_entry->guid);
313 
314  // Category
315  int category_id = j_entry["categoryid"].GetInt();
316  auto category_itor = m_categories.find(category_id);
317  if (category_itor == m_categories.end() || category_id >= CID_Max)
318  {
319  category_itor = m_categories.find(CID_Unsorted);
320  }
321  out_entry->categoryname = category_itor->second;
322  out_entry->categoryid = category_itor->first;
323 
324  // Common - Authors
325  for (rapidjson::Value& j_author: j_entry["authors"].GetArray())
326  {
327  AuthorInfo author;
328 
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();
333 
334  out_entry->authors.push_back(author);
335  }
336 
337  // Vehicle details
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();
341  out_entry->fileformatversion = j_entry["fileformatversion"].GetInt();
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();
349  out_entry->propwheelcount = j_entry["propwheelcount"].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();
354  out_entry->turbopropscount = j_entry["turbopropscount"].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();
358  out_entry->flexbodiescount = j_entry["flexbodiescount"].GetInt();
359  out_entry->soundsourcescount = j_entry["soundsourcescount"].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();
366  out_entry->custom_particles = j_entry["custom_particles"].GetBool();
367  out_entry->forwardcommands = j_entry["forwardcommands"].GetBool();
368  out_entry->importcommands = j_entry["importcommands"].GetBool();
369  out_entry->rescuer = j_entry["rescuer"].GetBool();
370  out_entry->driveable = ActorType(j_entry["driveable"].GetInt());
371  out_entry->numgears = j_entry["numgears"].GetInt();
372  out_entry->enginetype = static_cast<char>(j_entry["enginetype"].GetInt());
373 
374  // Vehicle 'section-configs' (aka Modules in RigDef namespace)
375  for (rapidjson::Value& j_module_name: j_entry["sectionconfigs"].GetArray())
376  {
377  out_entry->sectionconfigs.push_back(j_module_name.GetString());
378  }
379 
380  // Addon part suggested mod guids
381  for (rapidjson::Value& j_addonguid: j_entry["addonpart_guids"].GetArray())
382  {
383  out_entry->addonpart_guids.insert(j_addonguid.GetString());
384  }
385 
386  // Addon part suggested mod filenames
387  for (rapidjson::Value& j_addonfname: j_entry["addonpart_filenames"].GetArray())
388  {
389  out_entry->addonpart_filenames.insert(j_addonfname.GetString());
390  }
391 
392  // Tuneup details
393  out_entry->tuneup_associated_filename = j_entry["tuneup_associated_filename"].GetString();
394 }
395 
397 {
398  // Clear existing entries
399  m_entries.clear();
400 
401  rapidjson::Document j_doc;
402  if (!App::GetContentManager()->LoadAndParseJson(CACHE_FILE, RGN_CACHE, j_doc) ||
403  !j_doc.IsObject() || !j_doc.HasMember("entries") || !j_doc["entries"].IsArray())
404  {
405  RoR::Log("[RoR|ModCache] Error, cache file still invalid after check/update, content selector will be empty.");
407  }
408 
409  if (j_doc["format_version"].GetInt() != CACHE_FILE_FORMAT)
410  {
411  RoR::Log("[RoR|ModCache] Invalid cache file format");
413  }
414 
415  for (rapidjson::Value& j_entry: j_doc["entries"].GetArray())
416  {
417  CacheEntryPtr entry = new CacheEntry();
418  this->ImportEntryFromJson(j_entry, entry);
419  entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
420  m_entries.push_back(entry);
421  }
422 
423  m_filenames_hash_loaded = j_doc["global_hash"].GetString();
424 
425  return CacheValidity::VALID;
426 }
427 
429 {
430  this->LoadCacheFileJson();
431 
432  std::vector<String> paths;
433  for (auto& entry : m_entries)
434  {
435  std::string fn = entry->resource_bundle_path;
436  if (entry->resource_bundle_type == "FileSystem")
437  {
438  fn = PathCombine(fn, entry->fname);
439  }
440 
441  if (!RoR::FileExists(fn.c_str()) || (entry->filetime != RoR::GetFileLastModifiedTime(fn)))
442  {
443  if (!entry->deleted)
444  {
445  if (std::find(paths.begin(), paths.end(), fn) == paths.end())
446  {
447  RoR::LogFormat("[RoR|ModCache] Removing '%s'", fn.c_str());
448  paths.push_back(fn);
449  }
450  this->RemoveFileCache(entry);
451  }
452  entry->deleted = true;
453  }
454  else
455  {
456  m_resource_paths.insert(fn);
457  }
458  }
459 }
460 
462 {
463  for (auto& entry : m_entries)
464  {
465  String group = entry->resource_group;
466  if (!group.empty())
467  {
468  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
469  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
470  }
471  }
472 }
473 
475 {
476  RoR::Log("[RoR|ModCache] Searching for duplicates ...");
477  std::map<String, String> possible_duplicates;
478  for (int i=0; i<m_entries.size(); i++)
479  {
480  CacheEntryPtr entryA = m_entries[i];
481 
482  if (entryA->deleted)
483  continue;
484 
485  String dnameA = entryA->dname;
486  StringUtil::toLowerCase(dnameA);
487  StringUtil::trim(dnameA);
488  String dirA = entryA->resource_bundle_path;
489  StringUtil::toLowerCase(dirA);
490  String basenameA, basepathA;
491  StringUtil::splitFilename(dirA, basenameA, basepathA);
492  String filenameWUIDA = entryA->fname_without_uid;
493  StringUtil::toLowerCase(filenameWUIDA);
494 
495  for (int j=i+1; j<m_entries.size(); j++)
496  {
497  CacheEntryPtr entryB = m_entries[j];
498 
499  if (entryB->deleted)
500  continue;
501 
502  String filenameWUIDB = entryB->fname_without_uid;
503  StringUtil::toLowerCase(filenameWUIDB);
504  if (filenameWUIDA != filenameWUIDB)
505  continue;
506 
507  String dnameB = entryB->dname;
508  StringUtil::toLowerCase(dnameB);
509  StringUtil::trim(dnameB);
510  if (dnameA != dnameB)
511  continue;
512 
513  String dirB = entryB->resource_bundle_path;
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, "-", "_");
521  if (StripSHA1fromString(basenameA) != StripSHA1fromString(basenameB))
522  continue;
523 
524  if (entryA->resource_bundle_path == entryB->resource_bundle_path)
525  {
526  LOG("- duplicate: " + entryA->fpath + entryA->fname
527  + " <--> " + entryB->fpath + entryB->fname);
528  LOG(" - " + entryB->resource_bundle_path);
529  int idx = entryA->fpath.size() < entryB->fpath.size() ? i : j;
530  m_entries[idx]->deleted = true;
531  }
532  else
533  {
534  possible_duplicates[entryA->resource_bundle_path] = entryB->resource_bundle_path;
535  }
536  }
537  }
538  for (auto duplicate : possible_duplicates)
539  {
540  LOG("- possible duplicate: ");
541  LOG(" - " + duplicate.first);
542  LOG(" - " + duplicate.second);
543  }
544 }
545 
547 {
548  for (CacheEntryPtr& entry: m_entries)
549  {
550  if (modid == entry->number)
551  return entry;
552  }
553  return 0;
554 }
555 
556 String CacheSystem::GetPrettyName(String fname)
557 {
558  for (CacheEntryPtr& entry: m_entries)
559  {
560  if (fname == entry->fname)
561  return entry->dname;
562  }
563  return "";
564 }
565 
567 {
568  switch (driveable)
569  {
570  case ActorType::NOT_DRIVEABLE: return _LC("MainSelector", "Non-Driveable");
571  case ActorType::TRUCK: return _LC("MainSelector", "Truck");
572  case ActorType::AIRPLANE: return _LC("MainSelector", "Airplane");
573  case ActorType::BOAT: return _LC("MainSelector", "Boat");
574  case ActorType::MACHINE: return _LC("MainSelector", "Machine");
575  case ActorType::AI: return _LC("MainSelector", "A.I.");
576  default: return "";
577  };
578 }
579 
580 void CacheSystem::ExportEntryToJson(rapidjson::Value& j_entries, rapidjson::Document& j_doc, CacheEntryPtr const & entry)
581 {
582  rapidjson::Value j_entry(rapidjson::kObjectType);
583 
584  // Common details
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());
600 
601  // Common - Authors
602  rapidjson::Value j_authors(rapidjson::kArrayType);
603  for (AuthorInfo const& author: entry->authors)
604  {
605  rapidjson::Value j_author(rapidjson::kObjectType);
606 
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());
611 
612  j_authors.PushBack(j_author, j_doc.GetAllocator());
613  }
614  j_entry.AddMember("authors", j_authors, j_doc.GetAllocator());
615 
616  // Vehicle details
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());
652 
653  // Vehicle 'section-configs' (aka Modules in RigDef namespace)
654  rapidjson::Value j_sectionconfigs(rapidjson::kArrayType);
655  for (std::string const & module_name: entry->sectionconfigs)
656  {
657  j_sectionconfigs.PushBack(rapidjson::StringRef(module_name.c_str()), j_doc.GetAllocator());
658  }
659  j_entry.AddMember("sectionconfigs", j_sectionconfigs, j_doc.GetAllocator());
660 
661  // Addon part details
662  rapidjson::Value j_addonguids(rapidjson::kArrayType);
663  for (std::string const & ag: entry->addonpart_guids)
664  {
665  j_addonguids.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
666  }
667  j_entry.AddMember("addonpart_guids", j_addonguids, j_doc.GetAllocator());
668 
669  rapidjson::Value j_addonfnames(rapidjson::kArrayType);
670  for (std::string const & ag: entry->addonpart_filenames)
671  {
672  j_addonfnames.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
673  }
674  j_entry.AddMember("addonpart_filenames", j_addonfnames, j_doc.GetAllocator());
675 
676  // Tuneup details
677  j_entry.AddMember("tuneup_associated_filename", rapidjson::StringRef(entry->tuneup_associated_filename.c_str()), j_doc.GetAllocator());
678 
679  // Add entry to list
680  j_entries.PushBack(j_entry, j_doc.GetAllocator());
681 }
682 
684 {
685  // Basic file structure
686  rapidjson::Document j_doc;
687  j_doc.SetObject();
688  j_doc.AddMember("format_version", CACHE_FILE_FORMAT, j_doc.GetAllocator());
689  j_doc.AddMember("global_hash", rapidjson::StringRef(m_filenames_hash_generated.c_str()), j_doc.GetAllocator());
690 
691  // Entries
692  rapidjson::Value j_entries(rapidjson::kArrayType);
693  for (CacheEntryPtr const& entry : m_entries)
694  {
695  if (!entry->deleted)
696  {
697  this->ExportEntryToJson(j_entries, j_doc, entry);
698  }
699  }
700  j_doc.AddMember("entries", j_entries, j_doc.GetAllocator());
701 
702  // Write to file
703  if (App::GetContentManager()->SerializeAndWriteJson(CACHE_FILE, RGN_CACHE, j_doc)) // Logs errors
704  {
705  RoR::LogFormat("[RoR|ModCache] File '%s' written OK", CACHE_FILE);
706  }
707 }
708 
710 {
712  for (auto& entry : m_entries)
713  {
714  String group = entry->resource_group;
715  if (!group.empty())
716  {
717  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
718  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
719  }
720  this->RemoveFileCache(entry);
721  }
722  m_entries.clear();
723 }
724 
725 Ogre::String CacheSystem::StripUIDfromString(Ogre::String uidstr)
726 {
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);
730  return uidstr;
731 }
732 
733 Ogre::String CacheSystem::StripSHA1fromString(Ogre::String sha1str)
734 {
735  size_t pos = sha1str.find_first_of("-_");
736  if (pos != String::npos && pos >= 20)
737  return sha1str.substr(pos + 1, sha1str.length() - pos);
738  return sha1str;
739 }
740 
741 void CacheSystem::AddFile(String group, Ogre::FileInfo f, String ext)
742 {
743  String type = f.archive ? f.archive->getType() : "FileSystem";
744  String path = f.archive ? f.archive->getName() : "";
745 
746  if (std::find_if(m_entries.begin(), m_entries.end(), [&](CacheEntryPtr& entry)
747  { return !entry->deleted && entry->fname == f.filename && entry->resource_bundle_path == path; }) != m_entries.end())
748  return;
749 
750  RoR::LogFormat("[RoR|CacheSystem] Preparing to add file '%f'", f.filename.c_str());
751 
752  try
753  {
754  DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(f.filename, group);
755  // ds closes automatically, so do _not_ close it explicitly below
756 
757  std::vector<CacheEntryPtr> new_entries;
758  if (ext == "terrn2")
759  {
760  CacheEntryPtr entry = new CacheEntry();
761  FillTerrainDetailInfo(entry, ds, f.filename);
762  new_entries.push_back(entry);
763  }
764  else if (ext == "skin")
765  {
766  auto new_skins = RoR::SkinParser::ParseSkins(ds);
767  for (auto skin_def: new_skins)
768  {
769  CacheEntryPtr entry = new CacheEntry();
770  FillSkinDetailInfo(entry, skin_def);
771  new_entries.push_back(entry);
772  }
773  }
774  else if (ext == "addonpart")
775  {
776  CacheEntryPtr entry = new CacheEntry();
777  FillAddonPartDetailInfo(entry, ds);
778  new_entries.push_back(entry);
779  }
780  else if (ext == "tuneup")
781  {
782  auto new_tuneups = RoR::TuneupUtil::ParseTuneups(ds);
783  for (auto tuneup_def: new_tuneups)
784  {
785  CacheEntryPtr entry = new CacheEntry();
786  FillTuneupDetailInfo(entry, tuneup_def);
787  new_entries.push_back(entry);
788  }
789  }
790  else if (ext == "assetpack")
791  {
792  CacheEntryPtr entry = new CacheEntry();
793  FillAssetPackDetailInfo(entry, ds);
794  new_entries.push_back(entry);
795  }
796  else
797  {
798  CacheEntryPtr entry = new CacheEntry();
799  FillTruckDetailInfo(entry, ds, f.filename, group);
800  new_entries.push_back(entry);
801  }
802 
803  for (auto& entry: new_entries)
804  {
805  Ogre::StringUtil::toLowerCase(entry->guid); // Important for comparsion
806  entry->fpath = f.path;
807  entry->fname = f.filename;
808  entry->fname_without_uid = StripUIDfromString(f.filename);
809  entry->fext = ext;
810  if (type == "Zip")
811  {
812  entry->filetime = RoR::GetFileLastModifiedTime(path);
813  }
814  else
815  {
816  entry->filetime = RoR::GetFileLastModifiedTime(PathCombine(path, f.filename));
817  }
818  entry->resource_bundle_type = type;
819  entry->resource_bundle_path = path;
820  entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
821  entry->addtimestamp = m_update_time;
822  this->GenerateFileCache(entry, group);
823  m_entries.push_back(entry);
824  }
825  }
826  catch (Ogre::Exception& e)
827  {
828  RoR::LogFormat("[RoR|CacheSystem] Error processing file '%s', message :%s",
829  f.filename.c_str(), e.getFullDescription().c_str());
830  }
831 }
832 
833 void CacheSystem::FillTruckDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr stream, String file_name, String group)
834 {
835  /* LOAD AND PARSE THE VEHICLE */
836  RigDef::Parser parser;
837  parser.Prepare();
838  parser.ProcessOgreStream(stream.getPointer(), group);
839  parser.GetSequentialImporter()->Disable();
840  parser.Finalize();
841 
842  /* RETRIEVE DATA */
843 
844  RigDef::DocumentPtr def = parser.GetFile();
845 
846  /* Name */
847  if (!def->name.empty())
848  {
849  entry->dname = def->name; // Use retrieved name
850  }
851  else
852  {
853  entry->dname = "@" + file_name; // Fallback
854  }
855 
856  /* Description */
857  std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
858  for (; desc_itor != def->root_module->description.end(); desc_itor++)
859  {
860  entry->description += *desc_itor + "\n";
861  }
862 
863  /* Authors */
864  std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
865  for (; author_itor != def->root_module->author.end(); author_itor++)
866  {
867  AuthorInfo author;
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;
872 
873  entry->authors.push_back(author);
874  }
875 
876  /* Default skin */
877  if (def->root_module->default_skin.size() > 0)
878  {
879  entry->default_skin = def->root_module->default_skin.back().skin_name;
880  }
881 
882  /* Modules (previously called "sections") */
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++)
885  {
886  entry->sectionconfigs.push_back(module_itor->second->name);
887  }
888 
889  /* Engine */
890  /* TODO: Handle engines in modules */
891  if (def->root_module->engine.size() > 0)
892  {
893  RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
894  entry->numgears = static_cast<int>(engine.gear_ratios.size());
895  entry->minrpm = engine.shift_down_rpm;
896  entry->maxrpm = engine.shift_up_rpm;
897  entry->torque = engine.torque;
898  entry->enginetype = 't'; /* Truck (default) */
899  if (def->root_module->engoption.size() > 0)
900  {
901  entry->enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
902  }
903  }
904 
905  /* File info */
906  if (def->root_module->fileinfo.size() > 0)
907  {
908  RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
909 
910  entry->uniqueid = data.unique_id;
911  entry->categoryid = static_cast<int>(data.category_id);
912  entry->version = static_cast<int>(data.file_version);
913  }
914  else
915  {
916  entry->uniqueid = "-1";
917  entry->categoryid = -1;
918  entry->version = -1;
919  }
920 
921  /* Vehicle type */
922  /* NOTE: RigDef::Document allows modularization of vehicle type. Cache only supports single type.
923  This is a temporary solution which has undefined results for mixed-type vehicles.
924  */
925  ActorType vehicle_type = NOT_DRIVEABLE;
926  module_itor = def->user_modules.begin();
927  for (; module_itor != def->user_modules.end(); module_itor++)
928  {
929  if (module_itor->second->engine.size() > 0)
930  {
931  vehicle_type = TRUCK;
932  }
933  else if (module_itor->second->screwprops.size() > 0)
934  {
935  vehicle_type = BOAT;
936  }
937  /* Note: Sections 'turboprops' and 'turboprops2' are unified in TruckParser2013 */
938  else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
939  {
940  vehicle_type = AIRPLANE;
941  }
942  }
943  /* Root module */
944  if (def->root_module->engine.size() > 0)
945  {
946  vehicle_type = TRUCK;
947  }
948  else if (def->root_module->screwprops.size() > 0)
949  {
950  vehicle_type = BOAT;
951  }
952  /* Note: Sections 'turboprops' and 'turboprops2' are unified in TruckParser2013 */
953  else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
954  {
955  vehicle_type = AIRPLANE;
956  }
957 
958  if (def->root_module->globals.size() > 0)
959  {
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;
962  }
963 
964  entry->forwardcommands = def->forward_commands;
965  entry->importcommands = def->import_commands;
966  entry->rescuer = def->rescuer;
967  if (def->root_module->guid.size() > 0)
968  {
969  entry->guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
970  Ogre::StringUtil::toLowerCase(entry->guid);
971  }
972  entry->fileformatversion = 0;
973  if (def->root_module->fileformatversion.size() > 0)
974  {
975  entry->fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
976  }
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());
983  entry->driveable = vehicle_type;
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());
991  entry->custom_particles = def->root_module->particles.size() > 0;
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());
995 
996  entry->wheelcount = 0;
997  entry->propwheelcount = 0;
998  for (const auto& w : def->root_module->wheels)
999  {
1000  entry->wheelcount++;
1001  if (w.propulsion != RigDef::WheelPropulsion::NONE)
1002  entry->propwheelcount++;
1003  }
1004  for (const auto& w : def->root_module->wheels2)
1005  {
1006  entry->wheelcount++;
1007  if (w.propulsion != RigDef::WheelPropulsion::NONE)
1008  entry->propwheelcount++;
1009  }
1010  for (const auto& w : def->root_module->meshwheels)
1011  {
1012  entry->wheelcount++;
1013  if (w.propulsion != RigDef::WheelPropulsion::NONE)
1014  entry->propwheelcount++;
1015  }
1016  for (const auto& w : def->root_module->meshwheels2)
1017  {
1018  entry->wheelcount++;
1019  if (w.propulsion != RigDef::WheelPropulsion::NONE)
1020  entry->propwheelcount++;
1021  }
1022  for (const auto& w : def->root_module->flexbodywheels)
1023  {
1024  entry->wheelcount++;
1025  if (w.propulsion != RigDef::WheelPropulsion::NONE)
1026  entry->propwheelcount++;
1027  }
1028 
1029  if (!def->root_module->axles.empty())
1030  {
1031  entry->propwheelcount = static_cast<int>(def->root_module->axles.size() * 2);
1032  }
1033 
1034  /* NOTE: std::shared_ptr cleans everything up. */
1035 }
1036 
1037 Ogre::String detectMiniType(String filename, String group)
1038 {
1039  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "dds"))
1040  return "dds";
1041 
1042  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "png"))
1043  return "png";
1044 
1045  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "jpg"))
1046  return "jpg";
1047 
1048  return "";
1049 }
1050 
1052 {
1053  if (!entry->filecachename.empty())
1054  {
1056  }
1057 }
1058 
1060 {
1061  if (entry->fname.empty())
1062  return;
1063 
1064  String bundle_basename, bundle_path;
1065  StringUtil::splitFilename(entry->resource_bundle_path, bundle_basename, bundle_path);
1066 
1067  String src_path;
1068  String dst_path;
1069  if (entry->fext == "skin")
1070  {
1071  if (entry->skin_def->thumbnail.empty())
1072  return;
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;
1077  }
1078  else
1079  {
1080  String fbase, fext;
1081  StringUtil::splitBaseFilename(entry->fname, fbase, fext);
1082  String minifn = fbase + "-mini.";
1083  String minitype = detectMiniType(minifn, group);
1084  if (minitype.empty())
1085  return;
1086  src_path = minifn + minitype;
1087  dst_path = bundle_basename + "_" + entry->fname + ".mini." + minitype;
1088  }
1089 
1090  try
1091  {
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());
1096  if (read > 0)
1097  {
1098  dst_ds->write(buf.data(), read);
1099  entry->filecachename = dst_path;
1100  }
1101  }
1102  catch (Ogre::Exception& e)
1103  {
1104  LOG("error while generating file cache: " + e.getFullDescription());
1105  }
1106 
1107  LOG("done generating file cache!");
1108 }
1109 
1111 {
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);
1116 
1117  int i = 0, count = static_cast<int>(files->size());
1118  for (const auto& file : *files)
1119  {
1120  int progress = ((float)i++ / (float)count) * 100;
1121  std::string text = fmt::format("{}{}\n{}\n{}/{}",
1122  _L("Loading zips in group "), group, file.filename, i, count);
1124 
1125  String path = PathCombine(file.archive->getName(), file.filename);
1126  this->ParseSingleZip(path);
1127  }
1128 
1131 }
1132 
1134 {
1135  if (std::find(m_resource_paths.begin(), m_resource_paths.end(), path) == m_resource_paths.end())
1136  {
1137  RoR::LogFormat("[RoR|ModCache] Adding archive '%s'", path.c_str());
1138  ResourceGroupManager::getSingleton().createResourceGroup(RGN_TEMP, false);
1139  try
1140  {
1141  ResourceGroupManager::getSingleton().addResourceLocation(path, "Zip", RGN_TEMP);
1143  {
1144  LOG("No usable content in: '" + path + "'");
1145  }
1146  }
1147  catch (Ogre::Exception& e)
1148  {
1149  LOG("Error while opening archive: '" + path + "': " + e.getFullDescription());
1150  }
1151  ResourceGroupManager::getSingleton().destroyResourceGroup(RGN_TEMP);
1152  m_resource_paths.insert(path);
1153  }
1154 }
1155 
1156 bool CacheSystem::ParseKnownFiles(Ogre::String group)
1157 {
1158  bool empty = true;
1159  for (auto ext : m_known_extensions)
1160  {
1161  auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group, "*." + ext);
1162  for (const auto& file : *files)
1163  {
1164  this->AddFile(group, file, ext);
1165  empty = false;
1166  }
1167  }
1168  return empty;
1169 }
1170 
1172 {
1173  std::string filenames = App::GetContentManager()->ListAllUserContent();
1174  m_filenames_hash_generated = HashData(filenames.c_str(), static_cast<int>(filenames.size()));
1175 }
1176 
1177 void CacheSystem::FillTerrainDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr ds, Ogre::String fname)
1178 {
1179  Terrn2Def def;
1180  Terrn2Parser parser;
1181  parser.LoadTerrn2(def, ds);
1182 
1183  for (Terrn2Author& author : def.authors)
1184  {
1185  AuthorInfo a;
1186  a.id = -1;
1187  a.name = author.name;
1188  a.type = author.type;
1189  entry->authors.push_back(a);
1190  }
1191 
1192  entry->dname = def.name;
1193  entry->categoryid = def.category_id;
1194  entry->uniqueid = def.guid;
1195  entry->version = def.version;
1196 }
1197 
1198 void CacheSystem::FillSkinDetailInfo(CacheEntryPtr &entry, std::shared_ptr<SkinDef>& skin_def)
1199 {
1200  if (!skin_def->author_name.empty())
1201  {
1202  AuthorInfo a;
1203  a.id = skin_def->author_id;
1204  a.name = skin_def->author_name;
1205  entry->authors.push_back(a);
1206  }
1207 
1208  entry->dname = skin_def->name;
1209  entry->guid = skin_def->guid;
1210  entry->description = skin_def->description;
1211  entry->categoryid = -1;
1212  entry->skin_def = skin_def; // Needed to generate preview image
1213 
1214  Ogre::StringUtil::toLowerCase(entry->guid);
1215 }
1216 
1217 void CacheSystem::FillAddonPartDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
1218 {
1219  GenericDocumentPtr doc = new GenericDocument();
1221  doc->loadFromDataStream(ds, options);
1222 
1223  GenericDocContextPtr ctx = new GenericDocContext(doc);
1224  while (!ctx->endOfFile())
1225  {
1226  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_name")
1227  {
1228  entry->dname = ctx->getTokString(1);
1229  }
1230  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_description")
1231  {
1232  entry->description = ctx->getTokString(1);
1233  }
1234  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_guid")
1235  {
1236  std::string guid = ctx->getTokString(1);
1237  Ogre::StringUtil::toLowerCase(guid);
1238  entry->addonpart_guids.insert(guid);
1239  }
1240  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_filename")
1241  {
1242  std::string fname = ctx->getTokString(1);
1243  Ogre::StringUtil::toLowerCase(fname);
1244  entry->addonpart_filenames.insert(fname);
1245  }
1246 
1247  ctx->seekNextLine();
1248  }
1249 }
1250 
1251 void CacheSystem::FillAssetPackDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
1252 {
1253  GenericDocumentPtr doc = new GenericDocument();
1255  doc->loadFromDataStream(ds, options);
1256 
1257  GenericDocContextPtr ctx = new GenericDocContext(doc);
1258  while (!ctx->endOfFile())
1259  {
1260  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_name")
1261  {
1262  entry->dname = ctx->getTokString(1);
1263  }
1264  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_description")
1265  {
1266  entry->description = ctx->getTokString(1);
1267  }
1268  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_author")
1269  {
1270  int n = ctx->countLineArgs();
1271  AuthorInfo author;
1272  if (n > 1) { author.type = ctx->getTokString(1); }
1273  if (n > 2) { author.id = (int)ctx->getTokFloat(2); }
1274  if (n > 3) { author.name = ctx->getTokString(3); }
1275  if (n > 4) { author.email = ctx->getTokString(4); }
1276  entry->authors.push_back(author);
1277  }
1278 
1279  ctx->seekNextLine();
1280  }
1281 }
1282 
1284 {
1285  if (!tuneup_def->author_name.empty())
1286  {
1287  AuthorInfo a;
1288  a.id = tuneup_def->author_id;
1289  a.name = tuneup_def->author_name;
1290  entry->authors.push_back(a);
1291  }
1292 
1293  entry->dname = tuneup_def->name;
1294  entry->guid = tuneup_def->guid;
1295  entry->description = tuneup_def->description;
1296  entry->categoryid = tuneup_def->category_id;
1297  entry->tuneup_def = tuneup_def; // Needed to generate preview image
1298  entry->tuneup_associated_filename = tuneup_def->filename;
1299 
1300  Ogre::StringUtil::toLowerCase(entry->guid);
1301  Ogre::StringUtil::toLowerCase(entry->tuneup_associated_filename);
1302 }
1303 
1304 void CacheSystem::LoadAssetPack(CacheEntryPtr& target_entry, Ogre::String const & assetpack_filename)
1305 {
1306  // Load asset packs into the mod-bundle's resource group (quick & dirty approach).
1307  // See also `ContentManager::resourceCollision()` - we always keep the original file and dump the colliding one.
1308  // --------------------------------------------------------------------------------------------------------------
1309 
1310  ROR_ASSERT(!target_entry->deleted);
1311  ROR_ASSERT(target_entry->resource_group != "");
1312  ROR_ASSERT(assetpack_filename != "");
1313 
1314  CacheEntryPtr assetpack_entry = App::GetCacheSystem()->FindEntryByFilename(LT_AssetPack, /*partial=*/false, assetpack_filename);
1315  if (assetpack_entry)
1316  {
1317  try
1318  {
1319  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1320  assetpack_entry->resource_bundle_path, // name (source)
1321  assetpack_entry->resource_bundle_type, // type (source)
1322  target_entry->resource_group, // resGroup (target)
1323  false, // recursive
1324  assetpack_entry->resource_bundle_type != "FileSystem"); // readOnly
1325 
1326  // This is messy but there's no other way - OGRE resource groups cannot update incrementally.
1327  Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->resource_group);
1328  Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->resource_group);
1329  }
1330  catch (std::exception const& e)
1331  {
1333  fmt::format(_L("Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->fname, target_entry->fname, e.what()));
1334  }
1335  }
1336  else
1337  {
1339  fmt::format(_L("Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->fname));
1340  }
1341 }
1342 
1343 static bool CheckAndReplacePathIgnoreCase(const CacheEntryPtr& entry, CVar* dir, const std::string& dir_label, std::string& out_rgname)
1344 {
1345  // Helper for `ComposeResourceGroupName()`
1346  // ---------------------------------------
1347 
1348  // Sanity check - assert on Debug, minimize damage on Release
1349  ROR_ASSERT(entry->resource_bundle_path != "");
1350  if (entry->resource_bundle_path == "")
1351  {
1352  LOG(fmt::format("[RoR|CacheSystem] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->fname));
1353  return false;
1354  }
1355 
1356  // Lowercase everything
1357  std::string lower_bundlepath = entry->resource_bundle_path;
1358  Ogre::StringUtil::toLowerCase(lower_bundlepath);
1359 
1360  std::string lower_dir = dir->getStr();
1361  Ogre::StringUtil::toLowerCase(lower_dir);
1362 
1363  // Look for match and replace
1364  if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir, /*lowercase:*/true))
1365  {
1366  // Sanity check; Should be guaranteed by the `startsWith()` check, but just to be sure...
1367  ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1368  if (lower_bundlepath.size() > lower_dir.size())
1369  {
1370  std::string localpath = entry->resource_bundle_path.substr(lower_dir.length());
1371  out_rgname = fmt::format("{{bundle {}:{}}}", dir_label, localpath);
1372  return true;
1373  }
1374  }
1375  return false;
1376 }
1377 
1379 {
1380  // Compose group name as "{bundle <local path>}", where 'local path' means either:
1381  // - under `sys_user_dir` (by default 'Documenst\My Games\Rigs of Rods')
1382  // - under `app_extra_mod_path` (empty by default)
1383  // - under 'sys_process_dir' (autodetected)
1384  // -------------------------------------------------------------------------------
1385 
1386  std::string rg_name;
1387  if (CheckAndReplacePathIgnoreCase(entry, App::sys_user_dir, "USER", rg_name) ||
1388  CheckAndReplacePathIgnoreCase(entry, App::sys_process_dir, "BIN", rg_name) ||
1389  CheckAndReplacePathIgnoreCase(entry, App::app_extra_mod_path, "EXTRA", rg_name))
1390  {
1391  return rg_name;
1392  }
1393  else
1394  {
1395  return fmt::format("{{bundle FULL:{}}}", entry->resource_bundle_path);
1396  }
1397 }
1398 
1400 {
1401  // Because we use one resource group per bundle and multiple entries can share the same bundle,
1402  // we need to load the supplementary documents even if the bundle is already loaded.
1403  // -------------------------------------------------------------------------------------------
1404 
1405  if (!entry)
1406  return;
1407 
1408  ROR_ASSERT(entry->resource_group != "");
1409 
1410  if (entry->fext == "skin")
1411  {
1412  this->LoadAssociatedSkinDef(entry);
1413  }
1414  else if (entry->fext == "tuneup")
1415  {
1416  this->LoadAssociatedTuneupDef(entry);
1417  }
1418 }
1419 
1420 bool CacheSystem::IsPathContentDirRoot(const std::string& path) const
1421 {
1422  // Helper for `LoadResource()` because OGRE's 'readOnly' flag, see explanation in `ContentManager::InitModCache()`
1423  // --------------------------------------------------------------------------------------------------------------
1424 
1425  for (const std::string& cdir: m_content_dirs)
1426  {
1427  if (path == PathCombine(App::sys_user_dir->getStr(), cdir))
1428  {
1429  return true;
1430  }
1431  }
1432  return false;
1433 }
1434 
1436 {
1437  if (!entry)
1438  return;
1439 
1440  // Check if already loaded for this entry->
1441  if (entry->resource_group != "")
1442  {
1443  this->LoadSupplementaryDocuments(entry);
1444  return;
1445  }
1446 
1447  Ogre::String group = CacheSystem::ComposeResourceGroupName(entry);
1448 
1449  // Make "FileSystem" (directory) bundles writable (Default is read-only), except if it's a root directory.
1450  // See explanation of `readOnly` OGRE flag in `ContentManager::InitModCache()`.
1451  bool readonly = entry->resource_bundle_type == "Zip" || this->IsPathContentDirRoot(entry->resource_bundle_path);
1452  bool recursive = false;
1453 
1454  // Load now.
1455  try
1456  {
1457  if (entry->fext == "terrn2")
1458  {
1459  // PagedGeometry is hardcoded to use `Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME`
1460  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/true);
1461  ResourceGroupManager::getSingleton().addResourceLocation(
1462  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1463  }
1464  else if (entry->fext == "skin")
1465  {
1466  // This is a SkinZip bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1467  // Note: this code won't execute for .skin files in vehicle-bundles because in such case the bundle is already loaded by the vehicle's Cacheentry->
1468  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1469  ResourceGroupManager::getSingleton().addResourceLocation(
1470  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1472  }
1473  else if (entry->fext == "tuneup")
1474  {
1475  // This is a .tuneup bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1476  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1477  ResourceGroupManager::getSingleton().addResourceLocation(
1478  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1480  }
1481  else
1482  {
1483  // A vehicle bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1484  // See bottom 'note' at https://ogrecave.github.io/ogre/api/latest/_resource-_management.html#Resource-Groups
1485  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1486  ResourceGroupManager::getSingleton().addResourceLocation(
1487  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1488 
1493  }
1494 
1495  // Initialize resource group
1496  ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1497  entry->resource_group = group;
1498 
1499  this->LoadSupplementaryDocuments(entry);
1500 
1501  // Inform other entries sharing this bundle (i.e. '.skin' entries in vehicle bundles)
1502  for (CacheEntryPtr& i_entry: m_entries)
1503  {
1504  if (i_entry->resource_bundle_path == entry->resource_bundle_path)
1505  {
1506  i_entry->resource_group = group; // Mark as loaded
1507  }
1508  }
1509  }
1510  catch (Ogre::Exception& e)
1511  {
1512  RoR::LogFormat("[RoR] Error while loading '%s', message: %s",
1513  entry->resource_bundle_path.c_str(), e.getFullDescription().c_str());
1514  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1515  {
1516  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1517  }
1518  }
1519 }
1520 
1522 {
1523  if (entry->resource_group == "")
1524  {
1525  return; // Not loaded - nothing to do
1526  }
1527 
1528  // IMPORTANT! No actors must use the bundle while reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED
1529 
1530  this->UnLoadResource(entry);
1531  this->LoadResource(entry); // Will create the same resource group again
1532 }
1533 
1535 {
1536  if (entry->resource_group == "")
1537  {
1538  return; // Not loaded - nothing to do
1539  }
1540 
1541  // IMPORTANT! No actors must use the bundle after reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED
1542 
1543  std::string resource_group = entry->resource_group; // Keep local copy, the CacheEntry will be blanked!
1544  for (CacheEntryPtr& i_entry: m_entries)
1545  {
1546  if (i_entry->resource_group == resource_group)
1547  {
1548  // Delete cached documents - force reload from disk
1549  i_entry->actor_def = nullptr;
1550  i_entry->tuneup_def = nullptr;
1551  i_entry->skin_def = nullptr;
1552  // Mark as unloaded
1553  i_entry->resource_group = "";
1554  }
1555  }
1556 
1557  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1558 }
1559 
1560 CacheEntryPtr CacheSystem::FetchSkinByName(std::string const & skin_name)
1561 {
1562  for (CacheEntryPtr & entry: m_entries)
1563  {
1564  if (entry->dname == skin_name && entry->fext == "skin")
1565  {
1566  return entry;
1567  }
1568  }
1569  return nullptr;
1570 }
1571 
1573 {
1574  // A .skin file defines multiple skins, so we need to locate and update all associated cache entries.
1575  // --------------------------------------------------------------------------------------------------
1576 
1577  if (!cache_entry)
1578  return;
1579 
1580  ROR_ASSERT(cache_entry->resource_group != ""); // Must be already loaded
1581 
1582  if (cache_entry->skin_def != nullptr) // If already parsed, re-use
1583  {
1584  return;
1585  }
1586 
1587  try
1588  {
1589  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1590  .openResource(cache_entry->fname, cache_entry->resource_group);
1591 
1592  auto new_skins = RoR::SkinParser::ParseSkins(ds); // Load the '.skin' file
1593  for (auto def: new_skins)
1594  {
1595  for (CacheEntryPtr& entry: m_entries)
1596  {
1597  if (entry->resource_bundle_path == cache_entry->resource_bundle_path
1598  && entry->resource_bundle_type == cache_entry->resource_bundle_type
1599  && entry->fname == cache_entry->fname
1600  && entry->dname == def->name)
1601  {
1602  entry->skin_def = def;
1603  entry->resource_group = cache_entry->resource_group;
1604  }
1605  }
1606  }
1607 
1608  if (cache_entry->skin_def == nullptr)
1609  {
1610  RoR::LogFormat("Definition of skin '%s' was not found in file '%s'",
1611  cache_entry->dname.c_str(), cache_entry->fname.c_str());
1612  }
1613  }
1614  catch (Ogre::Exception& oex)
1615  {
1616  RoR::LogFormat("[RoR] Error loading skin file '%s', message: %s",
1617  cache_entry->fname.c_str(), oex.getFullDescription().c_str());
1618  }
1619 }
1620 
1622 {
1623  // A .tuneup file defines multiple tuneups, so we need to locate and update all associated cache entries.
1624  // --------------------------------------------------------------------------------------------------
1625 
1626  if (!cache_entry)
1627  return;
1628 
1629  ROR_ASSERT(cache_entry->resource_group != ""); // Must be already loaded
1630 
1631  if (cache_entry->tuneup_def != nullptr) // If already parsed, re-use
1632  {
1633  return;
1634  }
1635 
1636  try
1637  {
1638  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1639  .openResource(cache_entry->fname, cache_entry->resource_group);
1640 
1641  auto new_tuneups = RoR::TuneupUtil::ParseTuneups(ds); // Load the '.tuneup' file
1642  for (auto def: new_tuneups)
1643  {
1644  for (CacheEntryPtr& entry: m_entries)
1645  {
1646  if (entry->resource_bundle_path == cache_entry->resource_bundle_path
1647  && entry->resource_bundle_type == cache_entry->resource_bundle_type
1648  && entry->fname == cache_entry->fname
1649  && entry->dname == def->name)
1650  {
1651  entry->tuneup_def = def;
1652  entry->resource_group = cache_entry->resource_group;
1653  }
1654  }
1655  }
1656 
1657  if (cache_entry->tuneup_def == nullptr)
1658  {
1659  RoR::LogFormat("Definition of tuneup '%s' was not found in file '%s'",
1660  cache_entry->dname.c_str(), cache_entry->fname.c_str());
1661  }
1662  }
1663  catch (Ogre::Exception& oex)
1664  {
1665  RoR::LogFormat("[RoR] Error loading tuneup file '%s', message: %s",
1666  cache_entry->fname.c_str(), oex.getFullDescription().c_str());
1667  }
1668 }
1669 
1671 {
1672 
1673  // Validate the request
1674  if (!request->cpr_source_entry)
1675  {
1677  fmt::format(_LC("CacheSystem", "Cannot create project '{}' - no source mod specified!"), request->cpr_name));
1678  return nullptr;
1679  }
1680 
1681  // Make sure projects folder exists
1683 
1684  // Create subfolder
1685  std::string project_path = PathCombine(App::sys_projects_dir->getStr(), request->cpr_name);
1686  if (FolderExists(project_path) && !request->cpr_overwrite)
1687  {
1689  fmt::format(_LC("CacheSystem", "Project directory '{}' already exists!"), request->cpr_name));
1690  return nullptr;
1691  }
1692  CreateFolder(project_path);
1693  if (!FolderExists(project_path))
1694  {
1696  fmt::format(_LC("CacheSystem", "Project directory '{}' could not be created!"), request->cpr_name));
1697  return nullptr;
1698  }
1699 
1700  // Check if a project with the same name already exists
1701  CacheEntryPtr project_entry;
1702  bool project_entry_created = false;
1703  if (request->cpr_overwrite)
1704  {
1705  project_entry = this->FindEntryByFilename(LT_Tuneup, /*partial:*/false, fmt::format("{}.tuneup", request->cpr_name));
1706  this->LoadResource(project_entry); // This fills `entry.resource_group`
1707  }
1708 
1709  if (!project_entry)
1710  {
1711  // Create preliminary cache entry
1712  project_entry = new CacheEntry();
1713  project_entry_created = true;
1714 
1716  {
1717  project_entry->fext = "tuneup"; // Tell modcache what it is.
1718  project_entry->categoryid = CID_Tuneups; // For display in modcache
1719  project_entry->guid = request->cpr_source_entry->guid; // For lookup of tuneups by vehicle GUID.
1720  Ogre::StringUtil::toLowerCase(project_entry->guid);
1721  project_entry->tuneup_associated_filename = request->cpr_source_entry->fname; // For additional filtering of results (GUID marks a family, not individual mod).
1722  Ogre::StringUtil::toLowerCase(project_entry->tuneup_associated_filename);
1723  }
1724  else
1725  {
1726  project_entry->fext = request->cpr_source_entry->fext; // Tell modcache what it is.
1727  project_entry->categoryid = CID_Projects; // To list projects easily from cache
1728  }
1729  project_entry->categoryname = m_categories[project_entry->categoryid];
1730  project_entry->resource_bundle_type = "FileSystem"; // Tell modcache how to load it.
1731  project_entry->resource_bundle_path = project_path; // Tell modcache where to load it from.
1732  project_entry->fname = fmt::format("{}.{}", request->cpr_name, project_entry->fext); // Compose target mod filename
1733  project_entry->dname = request->cpr_name;
1734  project_entry->description = request->cpr_description;
1735  project_entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
1736  this->LoadResource(project_entry); // This fills `entry.resource_group`
1737  }
1738 
1740  {
1741  // Tuneup projects don't contain any media, just the .tuneup file which lists addonparts to use.
1742 
1743  // Prepare the .tuneup document
1744  ROR_ASSERT(request->cpr_source_actor);
1746 
1747  TuneupDefPtr tuneup = request->cpr_source_actor->getWorkingTuneupDef()->clone();
1748  tuneup->guid = request->cpr_source_entry->guid; // For lookup of tuneups by vehicle GUID.
1749  tuneup->filename = request->cpr_source_entry->fname; // For additional filtering of results (GUID marks a family, not individual mod).
1750  tuneup->name = request->cpr_name;
1751  tuneup->description = request->cpr_description;
1752  tuneup->thumbnail = request->cpr_source_entry->filecachename;
1753  tuneup->category_id = (CacheCategoryId)project_entry->categoryid;
1754 
1755  // Write out the .tuneup file.
1756  Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1757  project_entry->fname, project_entry->resource_group, request->cpr_overwrite);
1758  TuneupUtil::ExportTuneup(datastream, tuneup);
1759 
1760  // Attach the document to the entry in memory
1761  project_entry->tuneup_def = tuneup;
1762 
1763  // In the likely case this was invoked from TopMenubarUI, update it.
1764  if (App::GetGuiManager()->TopMenubar.tuning_savebox_visible)
1765  {
1767  App::GetGuiManager()->TopMenubar.tuning_actor = nullptr; // Force refresh
1768  }
1769  }
1770  else
1771  {
1772 
1773  // Create temporary resource group with only the data we want.
1774  std::string temp_rg = "TempProjectSourceRG";
1775  // Apart from `Resources` and resource groups, OGRE also keeps `Archives` in `ArchiveManager`
1776  // These aren't unloaded on destroying resource groups, and keep a 'readOnly' flag (defaults to true).
1777  // Upon loading/creating new resource groups, OGRE complains if the submitted flag doesn't match.
1778  // Since we want to make subdirs (with upacked mods) writable, we must purge subdir-archives now.
1779  bool readonly = request->cpr_source_entry->resource_bundle_type == "Zip";
1780  bool recursive = false;
1781  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1783  request->cpr_source_entry->resource_bundle_type, temp_rg, recursive, readonly);
1784  Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1785 
1786  // Copy the files, one by one
1787  Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg, "*.*");
1788  for (size_t i = 0; i < filelist->size(); i++)
1789  {
1790  Ogre::FileInfo fileinfo = filelist->at(i);
1791 
1792  // Render a frame with a progress window on it.
1794  (i+1)/filelist->size(),
1795  fmt::format("Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1796  /*render_frame:*/true);
1797 
1798  // Copy one file
1799  try
1800  {
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());
1805  if (read > 0)
1806  {
1807  dst_ds->write(buf.data(), read);
1808  }
1809  }
1810  catch (Ogre::Exception& oex)
1811  {
1813  fmt::format(_LC("CacheSystem", "Could not copy file '{}' to project '{}', message: {}."),
1814  fileinfo.filename, request->cpr_name, oex.getDescription()));
1815  }
1816  }
1817 
1819  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1820 
1821  // Finally rename the mod file
1822  Ogre::FileSystemLayer::renameFile(
1823  /*oldPath:*/ PathCombine(project_path, request->cpr_source_entry->fname),
1824  /*newPath:*/ PathCombine(project_path, project_entry->fname));
1825  }
1826 
1827 
1828  if (project_entry_created)
1829  {
1830  // Add the new entry to database
1831  m_entries.push_back(project_entry);
1832  }
1833 
1834  // notify script
1835  modCacheActivityType activity_type = (project_entry_created) ? MODCACHEACTIVITY_ENTRY_ADDED : MODCACHEACTIVITY_ENTRY_MODIFIED;
1837  /*ints*/ activity_type, project_entry->number, 0, 0,
1838  /*strings*/ project_entry->fname, project_entry->fext);
1839 
1840  return project_entry;
1841 }
1842 
1844 {
1845  ROR_ASSERT(request->mpr_target_actor);
1847 
1848 
1849  switch (request->mpr_type)
1850  {
1852  {
1854  if (request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.count(request->mpr_subject) != 0)
1855  {
1857  fmt::format(_LC("Tuning", "Addon part '{}' is already equipped."), request->mpr_subject));
1858  return; // Nothing to do!
1859  }
1860 
1861  CacheEntryPtr subject_entry = this->FindEntryByFilename(LT_AddonPart, /*partial=*/false, request->mpr_subject);
1862  if (!subject_entry)
1863  {
1865  fmt::format(_LC("Tuning", "Addon part '{}' was not found in mod cache (probably not installed)."), request->mpr_subject));
1866  return; // Nothing to do!
1867  }
1868 
1870  {
1871  return; // Error message box already shown
1872  }
1873  else
1874  {
1875  request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.insert(request->mpr_subject);
1876  }
1877 
1878  break;
1879  }
1880 
1883  request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.erase(request->mpr_subject);
1884  break;
1885 
1889  break;
1890 
1894  break;
1895 
1899  break;
1900 
1904  break;
1905 
1909  break;
1910 
1914  break;
1915 
1919  break;
1920 
1924  break;
1925 
1929  break;
1930 
1934  break;
1935 
1939  break;
1940 
1944  break;
1945 
1949  break;
1950 
1954  break;
1955 
1959  break;
1960 
1964  break;
1965 
1969  break;
1970 
1974  break;
1975 
1979  break;
1980 
1984  break;
1985 
1989  break;
1990 
1994  break;
1995 
1999  break;
2000 
2004  break;
2005 
2007  {
2008  // Instead of loading with the saved tuneup directly, keep the autogenerated and sync it with the save.
2009  // That way, subsequent editing doesn't modify the save until user saves again.
2010  CacheEntryPtr save_entry = App::GetCacheSystem()->FindEntryByFilename(LT_Tuneup, /*partial:*/false, request->mpr_subject);
2011  if (!save_entry)
2012  {
2014  fmt::format(_LC("CacheSystem", "Error loading tuneup: file '{}', not found in mod cache"), request->mpr_subject));
2015  return;
2016  }
2017  this->LoadResource(save_entry);
2018  ROR_ASSERT(save_entry->tuneup_def);
2019  request->mpr_target_actor->getWorkingTuneupDef() = save_entry->tuneup_def->clone();
2021  break;
2022  }
2023 
2027  break;
2028 
2029  default:
2030  break;
2031  }
2032 
2033  // Create spawn request while actor still exists
2034  // Note we don't use `ActorModifyRequest::Type::RELOAD` because we don't need the bundle reloaded.
2036  srq->asr_position = Ogre::Vector3(request->mpr_target_actor->getPosition().x, request->mpr_target_actor->getMinHeight(), request->mpr_target_actor->getPosition().z);
2037  srq->asr_rotation = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(request->mpr_target_actor->getRotation()), Ogre::Vector3::UNIT_Y);
2038  srq->asr_config = request->mpr_target_actor->getSectionConfig();
2042  srq->asr_debugview = (int)request->mpr_target_actor->GetGfxActor()->GetDebugView();
2044 
2045  // Remove the actor
2047 
2048  // Load our actor again, but only after it was deleted.
2050 }
2051 
2053 {
2054 
2055  this->UnLoadResource(entry);
2056 
2057  // Delete the files, one by one
2058  const std::string DELETEPROJ_TEMP_RG = "DeleteProjectTempRG";
2059  Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG, /*inGlobalPool=*/false);
2060  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2061  entry->resource_bundle_path, entry->resource_bundle_type, DELETEPROJ_TEMP_RG, /*recursive=*/false, /*readOnly=*/false);
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++)
2065  {
2066  Ogre::FileInfo fileinfo = filelist->at(i);
2067  if (!Ogre::FileSystemLayer::removeFile(PathCombine(entry->resource_bundle_path, fileinfo.filename)))
2068  {
2070  fmt::format(_LC("CacheSystem", "Problem deleting project '{}' - could not delete file '{}'"), entry->fname, fileinfo.filename));
2071  }
2072  }
2073 
2074  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2075 
2076  // Delete the directory itself
2077  if (!Ogre::FileSystemLayer::removeDirectory(entry->resource_bundle_path))
2078  {
2080  fmt::format(_LC("CacheSystem", "Problem deleting project '{}' - could not delete directory '{}'"), entry->fname, entry->resource_bundle_path));
2081  }
2082 
2083  // Remove the entry
2084  RoR::EraseIf(m_entries, [entry](CacheEntryPtr& e) { return e == entry; });
2085 
2086  // Force update of Tuning menu in TopMenubarUI.
2088 }
2089 
2091 {
2092  Ogre::StringUtil::toLowerCase(query.cqy_search_string);
2093  Ogre::StringUtil::toLowerCase(query.cqy_filter_guid);
2094  Ogre::StringUtil::toLowerCase(query.cqy_filter_target_filename);
2095  std::time_t cur_time = std::time(nullptr);
2096  for (CacheEntryPtr& entry: m_entries)
2097  {
2098  // Filter by GUID
2099  if (query.cqy_filter_guid != "")
2100  {
2101  // Addon parts have `guid` empty
2102  if ((entry->fext == "addonpart" && entry->addonpart_guids.count(query.cqy_filter_guid) == 0) ||
2103  (entry->fext != "addonpart" && entry->guid != query.cqy_filter_guid))
2104  {
2105  continue;
2106  }
2107  }
2108 
2109  // Filter by target filename; pass items which have no target filenames listed.
2110  if (query.cqy_filter_target_filename != "")
2111  {
2112  if (entry->fext == "addonpart"
2113  && entry->addonpart_filenames.size() > 0
2114  && entry->addonpart_filenames.count(query.cqy_filter_target_filename) == 0)
2115  {
2116  continue;
2117  }
2118  else if (entry->fext == "tuneup"
2119  && entry->tuneup_associated_filename != ""
2120  && entry->tuneup_associated_filename != query.cqy_filter_target_filename)
2121  {
2122  continue;
2123  }
2124  }
2125 
2126  // Filter by entry type
2127  bool add = false;
2128  if (entry->fext == "terrn2")
2129  add = (query.cqy_filter_type == LT_Terrain);
2130  if (entry->fext == "skin")
2131  add = (query.cqy_filter_type == LT_Skin);
2132  else if (entry->fext == "addonpart")
2133  add = (query.cqy_filter_type == LT_AddonPart);
2134  else if (entry->fext == "tuneup")
2135  add = (query.cqy_filter_type == LT_Tuneup);
2136  else if (entry->fext == "assetpack")
2137  add = (query.cqy_filter_type == LT_AssetPack);
2138  else if (entry->fext == "truck")
2139  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Vehicle || query.cqy_filter_type == LT_Truck);
2140  else if (entry->fext == "car")
2141  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Vehicle || query.cqy_filter_type == LT_Truck || query.cqy_filter_type == LT_Car);
2142  else if (entry->fext == "boat")
2143  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Boat);
2144  else if (entry->fext == "airplane")
2145  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Airplane);
2146  else if (entry->fext == "trailer")
2147  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Trailer || query.cqy_filter_type == LT_Extension);
2148  else if (entry->fext == "train")
2149  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Train);
2150  else if (entry->fext == "load")
2151  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Load || query.cqy_filter_type == LT_Extension);
2152 
2153  if (!add)
2154  {
2155  continue;
2156  }
2157 
2158  // Category usage stats
2159  query.cqy_res_category_usage[entry->categoryid]++;
2160 
2162 
2163  const bool is_fresh = (cur_time - entry->addtimestamp) < CACHE_FILE_FRESHNESS;
2164  if (is_fresh)
2166 
2167  // Filter by category
2168  if ((query.cqy_filter_category_id <= CacheCategoryId::CID_Max && query.cqy_filter_category_id != entry->categoryid) ||
2169  (query.cqy_filter_category_id == CID_Fresh && !is_fresh))
2170  {
2171  continue;
2172  }
2173 
2174  // Search
2175  size_t score = 0;
2176  bool match = false;
2177  Str<100> wheels_str;
2178  switch (query.cqy_search_method)
2179  {
2181  if (match = this->Match(score, entry->dname, query.cqy_search_string, 0)) { break; }
2182  if (match = this->Match(score, entry->fname, query.cqy_search_string, 100)) { break; }
2183  if (match = this->Match(score, entry->description, query.cqy_search_string, 200)) { break; }
2184  for (AuthorInfo const& author: entry->authors)
2185  {
2186  if (match = this->Match(score, author.name, query.cqy_search_string, 300)) { break; }
2187  if (match = this->Match(score, author.email, query.cqy_search_string, 400)) { break; }
2188  }
2189  break;
2190 
2192  match = this->Match(score, entry->guid, query.cqy_search_string, 0);
2193  break;
2194 
2196  for (AuthorInfo const& author: entry->authors)
2197  {
2198  if (match = this->Match(score, author.name, query.cqy_search_string, 0)) { break; }
2199  if (match = this->Match(score, author.email, query.cqy_search_string, 0)) { break; }
2200  }
2201  break;
2202 
2204  wheels_str << entry->wheelcount << "x" << entry->propwheelcount;
2205  match = this->Match(score, wheels_str.ToCStr(), query.cqy_search_string, 0);
2206  break;
2207 
2209  match = this->Match(score, entry->fname, query.cqy_search_string, 100);
2210  break;
2211 
2212  default: // CacheSearchMethod::
2213  match = true;
2214  break;
2215  };
2216 
2217  if (match)
2218  {
2219  query.cqy_results.emplace_back(entry, score);
2220  query.cqy_res_last_update = std::max(query.cqy_res_last_update, entry->addtimestamp);
2221  }
2222  }
2223 
2224  std::sort(query.cqy_results.begin(), query.cqy_results.end());
2225  return query.cqy_results.size();
2226 }
2227 
2228 bool CacheSystem::Match(size_t& out_score, std::string data, std::string const& query, size_t score)
2229 {
2230  Ogre::StringUtil::toLowerCase(data);
2231  size_t pos = data.find(query);
2232  if (pos != std::string::npos)
2233  {
2234  out_score = score + pos;
2235  return true;
2236  }
2237  else
2238  {
2239  return false;
2240  }
2241 }
2242 
2244 {
2245  if (cqr_score == other.cqr_score)
2246  {
2247  Ogre::String first = this->cqr_entry->dname;
2248  Ogre::String second = other.cqr_entry->dname;
2249  Ogre::StringUtil::toLowerCase(first);
2250  Ogre::StringUtil::toLowerCase(second);
2251  return first < second;
2252  }
2253 
2254  return cqr_score < other.cqr_score;
2255 }
2256 
RoR::App::sys_user_dir
CVar * sys_user_dir
Definition: Application.cpp:163
RoR::Terrn2Def::authors
std::list< Terrn2Author > authors
Definition: Terrn2FileFormat.h:62
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
RoR::CacheEntry::resource_bundle_type
std::string resource_bundle_type
Archive type recognized by OGRE resource system: 'FileSystem' or 'Zip'.
Definition: CacheSystem.h:80
RoR::CacheEntry::addonpart_guids
std::set< std::string > addonpart_guids
GUIDs of all vehicles this addonpart is used with.
Definition: CacheSystem.h:98
RigDef::Engine::shift_up_rpm
float shift_up_rpm
Definition: RigDef_File.h:808
RoR::CacheQueryResult::cqr_score
size_t cqr_score
Definition: CacheSystem.h:169
RoR::CacheSystem::m_known_extensions
std::vector< Ogre::String > m_known_extensions
the extensions we track in the cache system
Definition: CacheSystem.h:389
RoR::CacheSystem::LoadAssetPack
void LoadAssetPack(CacheEntryPtr &t_dest, Ogre::String const &assetpack_filename)
Adds asset pack to the requesting cache entry's resource group.
Definition: CacheSystem.cpp:1304
RoR::App::GetContentManager
ContentManager * GetContentManager()
Definition: Application.cpp:267
RoR::CacheSystem::UnLoadResource
void UnLoadResource(CacheEntryPtr &t)
Unloads associated bundle, destroying all spawned actors.
Definition: CacheSystem.cpp:1534
RoR::CacheSystem::FillTerrainDetailInfo
void FillTerrainDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds, Ogre::String fname)
Definition: CacheSystem.cpp:1177
RoR::ModifyProjectRequest::mpr_subject
std::string mpr_subject
Definition: CacheSystem.h:271
RoR::TuneupDef::clone
TuneupDefPtr clone()
Definition: TuneupFileFormat.cpp:38
RoR::TuneupDef::force_remove_flexbodies
std::set< FlexbodyID_t > force_remove_flexbodies
UI overrides.
Definition: TuneupFileFormat.h:126
RoR::CID_Unsorted
@ CID_Unsorted
Definition: CacheSystem.h:155
RoR::CacheEntry::categoryid
int categoryid
category id
Definition: CacheSystem.h:72
RoR::CacheEntry::dname
Ogre::String dname
name parsed from the file
Definition: CacheSystem.h:70
RoR::CacheSearchMethod::GUID
@ GUID
Partial match in: guid.
RoR::TuneupDef::protected_flares
std::set< FlareID_t > protected_flares
Flares which cannot be altered via 'addonpart_unwanted_flare' directive.
Definition: TuneupFileFormat.h:139
RGN_CACHE
#define RGN_CACHE
Definition: Application.h:46
RoR::TuneupUtil::ParseTuneups
static std::vector< TuneupDefPtr > ParseTuneups(Ogre::DataStreamPtr &stream)
Definition: TuneupFileFormat.cpp:546
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_PROP_SET
@ TUNEUP_FORCEREMOVE_PROP_SET
'subject_id' is prop ID.
RoR::ModifyProjectRequest::mpr_subject_id
int mpr_subject_id
Definition: CacheSystem.h:272
RoR::CacheEntry::tags
Ogre::String tags
Definition: CacheSystem.h:106
RoR::CreateProjectRequest::cpr_description
std::string cpr_description
Optional, implemented for tuneups.
Definition: CacheSystem.h:225
RoR::Terrn2Def
Definition: Terrn2FileFormat.h:48
RoR::MACHINE
@ MACHINE
its a machine
Definition: SimData.h:96
RoR::Actor::ensureWorkingTuneupDef
void ensureWorkingTuneupDef()
Creates a working tuneup def if it doesn't exist yet.
Definition: Actor.cpp:4729
RoR::CacheEntry::deleted
bool deleted
is this mod deleted?
Definition: CacheSystem.h:84
RoR::TRUCK
@ TRUCK
its a truck (or other land vehicle)
Definition: SimData.h:93
RoR::CacheSystem::DeleteProject
void DeleteProject(CacheEntryPtr &entry)
Definition: CacheSystem.cpp:2052
RoR::Console::CONSOLE_MSGTYPE_TERRN
@ CONSOLE_MSGTYPE_TERRN
Parsing/spawn/simulation messages for terrain.
Definition: Console.h:64
RoR::TuneupDef::force_remove_props
std::set< PropID_t > force_remove_props
UI overrides.
Definition: TuneupFileFormat.h:125
RoR::CacheQuery::cqy_filter_category_id
int cqy_filter_category_id
Definition: CacheSystem.h:185
RoR::LT_AssetPack
@ LT_AssetPack
Definition: Application.h:306
RoR::LT_AddonPart
@ LT_AddonPart
Definition: Application.h:304
RoR::Terrn2Parser
Definition: Terrn2FileFormat.h:80
RoR::GenericDocContext::isTokKeyword
bool isTokKeyword(int offset=0) const
Definition: GenericFileFormat.h:123
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_FLEXBODY_SET
@ TUNEUP_PROTECTED_FLEXBODY_SET
'subject_id' is flexbody ID.
RoR::ActorSpawnRequest::asr_origin
Origin asr_origin
Definition: SimData.h:857
RoR::App::GetGuiManager
GUIManager * GetGuiManager()
Definition: Application.cpp:269
GUI_GameMainMenu.h
RoR::ContentManager::DeleteDiskFile
bool DeleteDiskFile(std::string const &filename, std::string const &rg_name)
Definition: ContentManager.cpp:515
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_PROP_RESET
@ TUNEUP_FORCEREMOVE_PROP_RESET
'subject_id' is prop ID.
RoR::CacheEntry::skin_def
std::shared_ptr< RoR::SkinDef > skin_def
Cached skin info, added on first use or during cache rebuild.
Definition: CacheSystem.h:92
RoR::AuthorInfo::type
Ogre::String type
Definition: CacheSystem.h:50
RigDef::Engine::gear_ratios
std::vector< float > gear_ratios
Definition: RigDef_File.h:813
RoR::CacheEntry::version
int version
file's version
Definition: CacheSystem.h:78
file
This is a raw Ogre binding for Imgui No project cmake file
Definition: README-OgreImGui.txt:3
RoR::CacheSystem::ClearResourceGroups
void ClearResourceGroups()
Definition: CacheSystem.cpp:461
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLEXBODY_SET
@ TUNEUP_FORCEREMOVE_FLEXBODY_SET
'subject_id' is flexbody ID.
RoR::CacheSystem::RemoveFileCache
void RemoveFileCache(CacheEntryPtr &entry)
Definition: CacheSystem.cpp:1051
RigDef::Parser::GetFile
RigDef::DocumentPtr GetFile()
Definition: RigDef_Parser.h:77
RoR::CacheQuery::cqy_search_method
CacheSearchMethod cqy_search_method
Definition: CacheSystem.h:188
RigDef::Parser::GetSequentialImporter
SequentialImporter * GetSequentialImporter()
Definition: RigDef_Parser.h:82
RoR::LT_Skin
@ LT_Skin
Definition: Application.h:302
RigDef::Parser::Finalize
void Finalize()
Definition: RigDef_Parser.cpp:2824
ContentManager.h
RoR::CreateProjectRequestType::SAVE_TUNEUP
@ SAVE_TUNEUP
Dumps .tuneup file with CID_Tuneup from source actor, will not overwrite existing unless explicitly i...
RoR::CacheSystem::m_update_time
std::time_t m_update_time
Ensures that all inserted files share the same timestamp.
Definition: CacheSystem.h:385
RoR::CreateProjectRequest::~CreateProjectRequest
~CreateProjectRequest()
Definition: CacheSystem.cpp:115
format
Truck file format(technical spec)
RoR::ContentManager::InitManagedMaterials
void InitManagedMaterials(std::string const &rg_name)
Definition: ContentManager.cpp:372
RoR::CacheSystem::LoadModCache
void LoadModCache(CacheValidity validity)
Definition: CacheSystem.cpp:151
RoR::CacheSystem::AddFile
void AddFile(Ogre::String group, Ogre::FileInfo f, Ogre::String ext)
Definition: CacheSystem.cpp:741
RoR::CacheEntry::driveable
ActorType driveable
Definition: CacheSystem.h:139
RoR::ActorState::DISPOSED
@ DISPOSED
removed from simulation, still in memory to satisfy pointers.
RoR::CacheEntry::number
CacheEntryID_t number
Sequential number, assigned internally, used by Selector-GUI.
Definition: CacheSystem.h:64
RoR::CacheEntry::importcommands
bool importcommands
Definition: CacheSystem.h:136
Terrn2FileFormat.h
RoR::LT_Tuneup
@ LT_Tuneup
Definition: Application.h:305
RoR::CreateProjectRequest::cpr_type
CreateProjectRequestType cpr_type
Definition: CacheSystem.h:228
RoR::CacheSystem::m_entries
std::vector< CacheEntryPtr > m_entries
Definition: CacheSystem.h:388
RoR::CacheSearchMethod::FILENAME
@ FILENAME
Partial match in file name.
RoR::CVar::getBool
bool getBool() const
Definition: CVar.h:98
RoR::TRIGGER_EVENT_ASYNC
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(),...
Definition: ScriptEngine.h:51
RoR::modCacheActivityType
modCacheActivityType
Argument #2 of script event RoR::SE_GENERIC_MODCACHE_ACTIVITY
Definition: ScriptEvents.h:88
RoR::GenericDocument::OPTION_ALLOW_SLASH_COMMENTS
static const BitMask_t OPTION_ALLOW_SLASH_COMMENTS
Allow comments starting with //.
Definition: GenericFileFormat.h:68
RoR::ModifyProjectRequestType::TUNEUP_USE_ADDONPART_RESET
@ TUNEUP_USE_ADDONPART_RESET
'subject' is addonpart filename.
RigDef::Parser
Checks the rig-def file syntax and pulls data to File object.
Definition: RigDef_Parser.h:56
RoR::CacheEntry::tuneup_def
RoR::TuneupDefPtr tuneup_def
Cached tuning info, added on first use or during cache rebuild.
Definition: CacheSystem.h:93
RoR::CacheQuery
Definition: CacheSystem.h:182
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:424
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_WHEEL_RESET
@ TUNEUP_PROTECTED_WHEEL_RESET
'subject_id' is wheel ID.
RoR::SplitBundleQualifiedFilename
void SplitBundleQualifiedFilename(const std::string &bundleQualifiedFilename, std::string &out_bundleName, std::string &out_filename)
Definition: Utils.cpp:228
RoR::CacheSystem::GetEntryByNumber
CacheEntryPtr GetEntryByNumber(int modid)
Definition: CacheSystem.cpp:546
RoR::HashData
Ogre::String HashData(const char *key, int len)
Definition: Utils.cpp:51
RoR::TuneupUtil::ExportTuneup
static void ExportTuneup(Ogre::DataStreamPtr &stream, TuneupDefPtr &tuneup)
Definition: TuneupFileFormat.cpp:638
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_FLEXBODY_RESET
@ TUNEUP_PROTECTED_FLEXBODY_RESET
'subject_id' is flexbody ID.
RoR::CID_Projects
@ CID_Projects
For truck files under 'projects/' directory, to allow listing from editors.
Definition: CacheSystem.h:151
RoR::GenericDocContext::getTokString
std::string getTokString(int offset=0) const
Definition: GenericFileFormat.h:114
RoR::TuneupDef::name
std::string name
Definition: TuneupFileFormat.h:97
RoR::CacheEntry::propwheelcount
int propwheelcount
Definition: CacheSystem.h:116
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RoR::SE_GENERIC_MODCACHE_ACTIVITY
@ SE_GENERIC_MODCACHE_ACTIVITY
Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see RoR::mo...
Definition: ScriptEvents.h:62
RoR::CacheEntry::tuneup_associated_filename
std::string tuneup_associated_filename
Value of 'filename' field in the tuneup file; always lowercase.
Definition: CacheSystem.h:102
RoR::CacheSystem::FillAddonPartDetailInfo
void FillAddonPartDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
Definition: CacheSystem.cpp:1217
RoR::CacheEntry::hasSubmeshs
bool hasSubmeshs
Definition: CacheSystem.h:109
RoR::LT_Load
@ LT_Load
Definition: Application.h:300
RoR::CacheEntry::resource_group
Ogre::String resource_group
Resource group of the loaded bundle. Empty if not loaded yet.
Definition: CacheSystem.h:89
RoR::LT_Airplane
@ LT_Airplane
Definition: Application.h:297
RoR::CacheSystem::ModifyProject
void ModifyProject(ModifyProjectRequest *request)
Definition: CacheSystem.cpp:1843
RoR::GenericDocContext::seekNextLine
bool seekNextLine()
Definition: GenericFileFormat.cpp:1115
RoR::ActorSpawnRequest::asr_working_tuneup
TuneupDefPtr asr_working_tuneup
Only filled when editing tuneup via Tuning menu.
Definition: SimData.h:856
TuneupFileFormat.h
The vehicle tuning system; applies addonparts and user overrides to vehicles.
detectMiniType
Ogre::String detectMiniType(String filename, String group)
Definition: CacheSystem.cpp:1037
RoR::Actor::GetGfxActor
GfxActor * GetGfxActor()
Definition: Actor.h:269
RoR::FolderExists
bool FolderExists(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:169
RoR::TuneupDef::use_addonparts
std::set< std::string > use_addonparts
Addonpart filenames.
Definition: TuneupFileFormat.h:109
RigDef::Engine::shift_down_rpm
float shift_down_rpm
Definition: RigDef_File.h:807
RoR::ModifyProjectRequestType::TUNEUP_USE_ADDONPART_SET
@ TUNEUP_USE_ADDONPART_SET
'subject' is addonpart filename.
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_EXHAUST_RESET
@ TUNEUP_PROTECTED_EXHAUST_RESET
'subject_id' is exhaust ID.
RoR::GenericDocContext::getTokFloat
float getTokFloat(int offset=0) const
Definition: GenericFileFormat.h:115
RoR::CID_None
@ CID_None
Definition: CacheSystem.h:149
RoR::LT_Car
@ LT_Car
Definition: Application.h:295
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_MANAGEDMAT_SET
@ TUNEUP_PROTECTED_MANAGEDMAT_SET
'subject' is managed material name.
RoR::CreateProjectRequest::CreateProjectRequest
CreateProjectRequest()
Definition: CacheSystem.cpp:110
RoR::CacheEntry::customtach
bool customtach
Definition: CacheSystem.h:133
RoR::CacheEntry::sectionconfigs
std::vector< Ogre::String > sectionconfigs
Definition: CacheSystem.h:142
RoR::CacheSystem::ExportEntryToJson
void ExportEntryToJson(rapidjson::Value &j_entries, rapidjson::Document &j_doc, CacheEntryPtr const &entry)
Definition: CacheSystem.cpp:580
Utils.h
RoR::NOT_DRIVEABLE
@ NOT_DRIVEABLE
not drivable at all
Definition: SimData.h:92
RoR::CacheSystem::StripSHA1fromString
static Ogre::String StripSHA1fromString(Ogre::String sha1str)
Definition: CacheSystem.cpp:733
RoR::CacheSystem::ImportEntryFromJson
void ImportEntryFromJson(rapidjson::Value &j_entry, CacheEntryPtr &out_entry)
Definition: CacheSystem.cpp:294
RoR::CacheEntry::enginetype
char enginetype
Definition: CacheSystem.h:141
Language.h
RoR::CacheEntry::minrpm
float minrpm
Definition: CacheSystem.h:130
RoR::Terrn2Author
Definition: Terrn2FileFormat.h:36
RoR::CacheEntry::description
Ogre::String description
Definition: CacheSystem.h:105
RoR::LT_Extension
@ LT_Extension
Definition: Application.h:301
RoR::CacheQueryResult::cqr_entry
CacheEntryPtr cqr_entry
Definition: CacheSystem.h:168
RoR::App::app_extra_mod_path
CVar * app_extra_mod_path
Definition: Application.cpp:87
RefCountingObjectPtr< CacheEntry >
RoR::CacheSystem::FillSkinDetailInfo
void FillSkinDetailInfo(CacheEntryPtr &entry, std::shared_ptr< SkinDef > &skin_def)
Definition: CacheSystem.cpp:1198
RoR::Console::CONSOLE_SYSTEM_ERROR
@ CONSOLE_SYSTEM_ERROR
Definition: Console.h:52
RoR::CacheSystem::PruneCache
void PruneCache()
Definition: CacheSystem.cpp:428
RigDef::Parser::ProcessOgreStream
void ProcessOgreStream(Ogre::DataStream *stream, Ogre::String resource_group)
Definition: RigDef_Parser.cpp:3379
GUIManager.h
RoR::CreateProjectRequest::cpr_source_entry
CacheEntryPtr cpr_source_entry
The original mod to copy files from.
Definition: CacheSystem.h:226
Actor.h
RoR::CreateProjectRequest::cpr_name
std::string cpr_name
Directory and also the mod file (without extension).
Definition: CacheSystem.h:224
RoR::Terrn2Author::name
std::string name
Definition: Terrn2FileFormat.h:39
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_MANAGEDMAT_SET
@ TUNEUP_FORCEREMOVE_MANAGEDMAT_SET
'subject' is managed material name.
RoR::CacheSystem::IsPathContentDirRoot
bool IsPathContentDirRoot(const std::string &path) const
Definition: CacheSystem.cpp:1420
RoR::GUIManager::LoadingWindow
GUI::LoadingWindow LoadingWindow
Definition: GUIManager.h:119
RoR::TuneupDef::protected_props
std::set< PropID_t > protected_props
Props which cannot be altered via 'addonpart_tweak_prop' or 'addonpart_unwanted_prop' directive.
Definition: TuneupFileFormat.h:137
w
float w
Definition: (ValueTypes) quaternion.h:4
RoR::CacheEntry::forwardcommands
bool forwardcommands
Definition: CacheSystem.h:135
RoR::Console::CONSOLE_SYSTEM_NOTICE
@ CONSOLE_SYSTEM_NOTICE
Definition: Console.h:51
RoR::ActorSpawnRequest
Definition: SimData.h:832
RoR::CacheEntry::beamcount
int beamcount
Definition: CacheSystem.h:111
RoR::getTimeStamp
std::time_t getTimeStamp()
Definition: Utils.cpp:74
RoR::GUI::TopMenubar::tuning_savebox_visible
bool tuning_savebox_visible
User pressed 'save active' to open savebox.
Definition: GUI_TopMenubar.h:117
RoR::CacheEntry::addonpart_filenames
std::set< std::string > addonpart_filenames
File names of all vehicles this addonpart is used with. If empty, any filename goes.
Definition: CacheSystem.h:99
RoR::Terrn2Parser::LoadTerrn2
bool LoadTerrn2(Terrn2Def &def, Ogre::DataStreamPtr &ds)
Definition: Terrn2FileFormat.cpp:38
RoR::CacheQueryResult::operator<
bool operator<(CacheQueryResult const &other) const
Definition: CacheSystem.cpp:2243
RoR::CacheSystem::LoadCacheFileJson
CacheValidity LoadCacheFileJson()
Definition: CacheSystem.cpp:396
RoR::LT_Boat
@ LT_Boat
Definition: Application.h:296
RoR::CacheEntry::shockcount
int shockcount
Definition: CacheSystem.h:112
RigDef::Fileinfo
Definition: RigDef_File.h:869
RoR::ModifyProjectRequestType::TUNEUP_FORCED_WHEEL_SIDE_SET
@ TUNEUP_FORCED_WHEEL_SIDE_SET
'subject_id' is wheel ID, 'value_int' is RoR::WheelSide
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_FLARE_RESET
@ TUNEUP_PROTECTED_FLARE_RESET
'subject_id' is flare ID.
RigDef::Fileinfo::unique_id
Ogre::String unique_id
Definition: RigDef_File.h:871
RoR::LT_Truck
@ LT_Truck
Definition: Application.h:294
RoR::CacheQuery::cqy_res_category_usage
std::map< int, size_t > cqy_res_category_usage
Total usage (ignores search params + category filter)
Definition: CacheSystem.h:192
RoR::CacheSystem::LoadAssociatedSkinDef
void LoadAssociatedSkinDef(CacheEntryPtr &cache_entry)
Loads+parses the .skin file and updates all related CacheEntries.
Definition: CacheSystem.cpp:1572
RoR::ActorSpawnRequest::asr_config
Ogre::String asr_config
Definition: SimData.h:850
RoR::GenericDocContext::countLineArgs
int countLineArgs()
Definition: GenericFileFormat.cpp:1132
RoR::CacheSearchMethod::AUTHORS
@ AUTHORS
Partial match in: author name/email.
RoR::CacheEntry::rotatorscount
int rotatorscount
Definition: CacheSystem.h:123
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLARE_RESET
@ TUNEUP_FORCEREMOVE_FLARE_RESET
'subject_id' is flare ID.
RoR::CacheEntry::soundsourcescount
int soundsourcescount
Definition: CacheSystem.h:126
RoR::CacheSystem::FillTruckDetailInfo
void FillTruckDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds, Ogre::String fname, Ogre::String group)
Definition: CacheSystem.cpp:833
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_FLARE_SET
@ TUNEUP_PROTECTED_FLARE_SET
'subject_id' is flare ID.
RoR::GameContext::ChainMessage
void ChainMessage(Message m)
Add to last pushed message's chain.
Definition: GameContext.cpp:72
RoR::Actor::getMinHeight
float getMinHeight(bool skip_virtual_nodes=true)
Definition: Actor.cpp:1508
RoR::CVar::getStr
std::string const & getStr() const
Definition: CVar.h:95
RoR::Actor::removeWorkingTuneupDef
void removeWorkingTuneupDef()
Deletes the working tuneup def object if it exists.
Definition: Actor.cpp:4738
RoR::CacheEntry::torque
float torque
Definition: CacheSystem.h:132
RoR::Str
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition: Str.h:35
RoR::CacheSystem::FindEntryByFilename
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,...
Definition: CacheSystem.cpp:184
RoR::CacheSystem::ClearCache
void ClearCache()
Definition: CacheSystem.cpp:709
SimData.h
Core data structures for simulation; Everything affected by by either physics, network or user intera...
RoR::CacheSystem::Match
bool Match(size_t &out_score, std::string data, std::string const &query, size_t)
Definition: CacheSystem.cpp:2228
RoR::CacheEntry::authors
std::vector< AuthorInfo > authors
authors
Definition: CacheSystem.h:86
RoR::PathCombine
std::string PathCombine(std::string a, std::string b)
Definition: PlatformUtils.h:48
GUI_LoadingWindow.h
RoR::CacheEntry::filecachename
Ogre::String filecachename
preview image filename
Definition: CacheSystem.h:87
CacheSystem.h
A database of user-installed content alias 'mods' (vehicles, terrains...)
RoR::CacheSystem::ParseZipArchives
void ParseZipArchives(Ogre::String group)
Definition: CacheSystem.cpp:1110
RoR::CacheEntry::propscount
int propscount
Definition: CacheSystem.h:119
RoR::CacheSystem::DetectDuplicates
void DetectDuplicates()
Definition: CacheSystem.cpp:474
RoR::TuneupDef::protected_wheels
std::set< WheelID_t > protected_wheels
Wheels that cannot be altered via 'addonpart_tweak_wheel'.
Definition: TuneupFileFormat.h:136
RoR::CacheValidity
CacheValidity
Definition: CacheSystem.h:203
ErrorUtils.h
RGN_TEMP
#define RGN_TEMP
Definition: Application.h:45
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_EXHAUST_SET
@ TUNEUP_PROTECTED_EXHAUST_SET
'subject_id' is exhaust ID.
CheckAndReplacePathIgnoreCase
static bool CheckAndReplacePathIgnoreCase(const CacheEntryPtr &entry, CVar *dir, const std::string &dir_label, std::string &out_rgname)
Definition: CacheSystem.cpp:1343
RoR::ActorSpawnRequest::asr_cache_entry
CacheEntryPtr asr_cache_entry
Optional, overrides 'asr_filename' and 'asr_cache_entry_num'.
Definition: SimData.h:848
RoR::CacheQueryResult
Definition: CacheSystem.h:162
ScriptEngine.h
RigDef::Engine::torque
float torque
Definition: RigDef_File.h:809
RoR::CacheEntry::addtimestamp
std::time_t addtimestamp
timestamp when this file was added to the cache
Definition: CacheSystem.h:75
RoR::AuthorInfo::id
int id
Definition: CacheSystem.h:49
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:65
CACHE_FILE_FRESHNESS
#define CACHE_FILE_FRESHNESS
Definition: CacheSystem.h:43
RoR::ContentManager::ResourcePack::TEXTURES
static const ResourcePack TEXTURES
Definition: ContentManager.h:70
RoR::Actor::getSectionConfig
Ogre::String getSectionConfig()
Definition: Actor.h:230
RoR::CacheEntry::~CacheEntry
~CacheEntry()
Definition: CacheSystem.cpp:105
RoR::AuthorInfo::email
Ogre::String email
Definition: CacheSystem.h:52
RoR::TuneupDef::thumbnail
std::string thumbnail
Definition: TuneupFileFormat.h:100
RoR::Str::ToCStr
const char * ToCStr() const
Definition: Str.h:46
RigDef::Fileinfo::file_version
int file_version
Definition: RigDef_File.h:873
RoR::CacheSystem::ParseSingleZip
void ParseSingleZip(Ogre::String path)
Definition: CacheSystem.cpp:1133
RoR::CacheSystem::FillTuneupDetailInfo
void FillTuneupDetailInfo(CacheEntryPtr &entry, TuneupDefPtr &tuneup_def)
Definition: CacheSystem.cpp:1283
RoR::CacheSystem::LoadAssociatedTuneupDef
void LoadAssociatedTuneupDef(CacheEntryPtr &cache_entry)
Loads+parses the .tuneup file and updates all related CacheEntries.
Definition: CacheSystem.cpp:1621
RoR::MODCACHEACTIVITY_ENTRY_ADDED
@ MODCACHEACTIVITY_ENTRY_ADDED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
Definition: ScriptEvents.h:92
RoR::CacheSystem::GetPrettyName
Ogre::String GetPrettyName(Ogre::String fname)
Definition: CacheSystem.cpp:556
RoR::GUI::LoadingWindow::SetVisible
void SetVisible(bool v)
Definition: GUI_LoadingWindow.h:41
RoR::CacheSystem::ParseKnownFiles
bool ParseKnownFiles(Ogre::String group)
Definition: CacheSystem.cpp:1156
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_MANAGEDMAT_RESET
@ TUNEUP_FORCEREMOVE_MANAGEDMAT_RESET
'subject' is managed material name.
RoR::GUI::LoadingWindow::SetProgress
void SetProgress(int _percent, const std::string &_text="", bool render_frame=true)
Definition: GUI_LoadingWindow.cpp:33
RoR::Actor::getPosition
Ogre::Vector3 getPosition()
Definition: Actor.cpp:424
RoR::TuneupDef::protected_managedmats
std::set< std::string > protected_managedmats
Managed materials which cannot be altered via 'addonpart_tweak_managedmaterial' directive.
Definition: TuneupFileFormat.h:141
RoR::CreateFolder
void CreateFolder(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:175
GfxScene.h
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
RoR::CacheEntry::fpath
Ogre::String fpath
filepath relative to the .zip file
Definition: CacheSystem.h:66
RoR::CacheSearchMethod::FULLTEXT
@ FULLTEXT
Partial match in: name, filename, description, author name/mail.
RoR::CacheSearchMethod::WHEELS
@ WHEELS
Wheel configuration, i.e. 4x4.
RoR::LT_Vehicle
@ LT_Vehicle
Definition: Application.h:293
RoR::LT_Trailer
@ LT_Trailer
Definition: Application.h:298
RoR::CacheCategoryId
CacheCategoryId
Definition: CacheSystem.h:147
RoR::LoaderType
LoaderType
< Search mode for ModCache::Query() & Operation mode for GUI::MainSelector
Definition: Application.h:289
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_EXHAUST_RESET
@ TUNEUP_FORCEREMOVE_EXHAUST_RESET
'subject_id' is exhaust ID.
RoR::Terrn2Def::version
int version
Definition: Terrn2FileFormat.h:58
RoR::CacheEntry::rescuer
bool rescuer
Definition: CacheSystem.h:137
RoR::ModifyProjectRequest::mpr_target_actor
ActorPtr mpr_target_actor
Definition: CacheSystem.h:267
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:270
RoR::CacheSystem::m_filenames_hash_loaded
std::string m_filenames_hash_loaded
hash from cachefile, for quick update detection
Definition: CacheSystem.h:386
RoR::CacheQueryResult::CacheQueryResult
CacheQueryResult(CacheEntryPtr entry, size_t score)
Definition: CacheSystem.cpp:120
RoR::TuneupDef::description
std::string description
Definition: TuneupFileFormat.h:101
RigDef::Parser::Prepare
void Prepare()
Definition: RigDef_Parser.cpp:2707
RoR::CacheQuery::cqy_search_string
std::string cqy_search_string
Definition: CacheSystem.h:189
RoR::AddonPartUtility::DoubleCheckForAddonpartConflict
static bool DoubleCheckForAddonpartConflict(ActorPtr target_actor, CacheEntryPtr addonpart_entry)
Definition: AddonPartFileFormat.cpp:910
RoR::CacheSystem::m_content_dirs
std::vector< std::string > m_content_dirs
the various mod directories we track in the cache system
Definition: CacheSystem.h:390
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::CacheSystem::m_categories
std::map< int, Ogre::String > m_categories
Definition: CacheSystem.h:392
RoR::CacheEntry
Definition: CacheSystem.h:55
files
This is a raw Ogre binding for Imgui No project cmake no just four source files
Definition: README-OgreImGui.txt:3
RGN_CONTENT
#define RGN_CONTENT
Definition: Application.h:49
RoR::ContentManager::ResourcePack::MATERIALS
static const ResourcePack MATERIALS
Definition: ContentManager.h:59
RoR::CacheSystem::m_filenames_hash_generated
std::string m_filenames_hash_generated
stores hash over the content, for quick update detection
Definition: CacheSystem.h:387
RoR::AIRPLANE
@ AIRPLANE
its an airplane
Definition: SimData.h:94
RoR::CacheQuery::cqy_res_last_update
std::time_t cqy_res_last_update
Definition: CacheSystem.h:193
RoR::CacheSystem::GenerateFileCache
void GenerateFileCache(CacheEntryPtr &entry, Ogre::String group)
Definition: CacheSystem.cpp:1059
CACHE_FILE_FORMAT
#define CACHE_FILE_FORMAT
Definition: CacheSystem.h:42
RoR::CacheEntry::uniqueid
Ogre::String uniqueid
file's unique id
Definition: CacheSystem.h:76
RoR::CacheSystem::EvaluateCacheValidity
CacheValidity EvaluateCacheValidity()
Definition: CacheSystem.cpp:256
RoR::ActorSpawnRequest::asr_skin_entry
CacheEntryPtr asr_skin_entry
Definition: SimData.h:854
RoR::AuthorInfo
Definition: CacheSystem.h:47
RoR::ModifyProjectRequest::mpr_value_int
int mpr_value_int
Definition: CacheSystem.h:273
RoR::CacheEntry::loadmass
float loadmass
Definition: CacheSystem.h:129
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_EXHAUST_SET
@ TUNEUP_FORCEREMOVE_EXHAUST_SET
'subject_id' is exhaust ID.
RoR::CacheEntry::fixescount
int fixescount
Definition: CacheSystem.h:113
RoR::Actor::getUsedActorEntry
CacheEntryPtr & getUsedActorEntry()
The actor entry itself.
Definition: Actor.cpp:4714
_LC
#define _LC(ctx, str)
Definition: Language.h:42
RoR::GUIManager::TopMenubar
GUI::TopMenubar TopMenubar
Definition: GUIManager.h:120
RoR::CacheSystem::CreateProject
CacheEntryPtr CreateProject(CreateProjectRequest *request)
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
Definition: CacheSystem.cpp:1670
RoR::CacheSystem::LoadSupplementaryDocuments
void LoadSupplementaryDocuments(CacheEntryPtr &t)
Loads the associated .truck*, .skin and .tuneup files.
Definition: CacheSystem.cpp:1399
RoR::CVar
Quake-style console variable, defined in RoR.cfg or crated via Console UI and scripts.
Definition: CVar.h:52
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLARE_SET
@ TUNEUP_FORCEREMOVE_FLARE_SET
'subject_id' is flare ID.
RoR::App::diag_log_console_echo
CVar * diag_log_console_echo
Definition: Application.cpp:146
RoR::ModifyProjectRequest
Definition: CacheSystem.h:265
RoR::CID_Fresh
@ CID_Fresh
Definition: CacheSystem.h:157
RoR::GenericDocContext::endOfFile
bool endOfFile(int offset=0) const
Definition: GenericFileFormat.h:111
RoR::CreateProjectRequest
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
Definition: CacheSystem.h:219
RoR::LT_Terrain
@ LT_Terrain
Definition: Application.h:292
RoR::ModifyProjectRequestType::PROJECT_LOAD_TUNEUP
@ PROJECT_LOAD_TUNEUP
'subject' is tuneup filename. This overwrites the auto-generated tuneup with the save.
RoR::TuneupDef::force_remove_managedmats
std::set< std::string > force_remove_managedmats
User unticked an UI checkbox in Tuning menu, section Managed Materials.
Definition: TuneupFileFormat.h:130
RoR::CacheSystem::ActorTypeToName
std::string ActorTypeToName(ActorType driveable)
Definition: CacheSystem.cpp:566
RoR::CacheEntry::fileformatversion
int fileformatversion
Definition: CacheSystem.h:108
RoR::CacheEntry::numgears
int numgears
Definition: CacheSystem.h:140
RoR::CacheSystem::ComposeResourceGroupName
static std::string ComposeResourceGroupName(const CacheEntryPtr &entry)
Definition: CacheSystem.cpp:1378
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_PROP_SET
@ TUNEUP_PROTECTED_PROP_SET
'subject_id' is prop ID.
RoR::CreateProjectRequest::cpr_source_actor
ActorPtr cpr_source_actor
Only for type SAVE_TUNEUP
Definition: CacheSystem.h:227
RoR::TuneupDef::author_id
int author_id
Definition: TuneupFileFormat.h:103
RoR::Terrn2Def::guid
std::string guid
Definition: Terrn2FileFormat.h:57
RoR::App::GetCacheSystem
CacheSystem * GetCacheSystem()
Definition: Application.cpp:272
RoR::CacheValidity::VALID
@ VALID
RoR::ContentManager::AddResourcePack
void AddResourcePack(ResourcePack const &resource_pack, std::string const &override_rgn="")
Loads resources if not already loaded.
Definition: ContentManager.cpp:98
RoR::CacheSystem::FetchSkinByName
CacheEntryPtr FetchSkinByName(std::string const &skin_name)
Definition: CacheSystem.cpp:1560
RoR::CacheValidity::NEEDS_REBUILD
@ NEEDS_REBUILD
RoR::CID_Tuneups
@ CID_Tuneups
For unsorted tuneup files.
Definition: CacheSystem.h:152
RoR::CacheEntry::usagecounter
int usagecounter
how much it was used already
Definition: CacheSystem.h:85
RoR::CacheValidity::NEEDS_UPDATE
@ NEEDS_UPDATE
RoR::CacheEntry::fext
Ogre::String fext
file's extension
Definition: CacheSystem.h:69
RoR::TuneupDef::author_name
std::string author_name
Definition: TuneupFileFormat.h:102
RoR::Actor::getRotation
float getRotation()
Definition: Actor.cpp:409
RoR::TuneupDef::protected_exhausts
std::set< ExhaustID_t > protected_exhausts
Exhausts which cannot be altered via 'addonpart_unwanted_exhaust' directive.
Definition: TuneupFileFormat.h:140
RoR::TuneupDef::protected_flexbodies
std::set< FlexbodyID_t > protected_flexbodies
Flexbodies which cannot be altered via 'addonpart_tweak_flexbody' or 'addonpart_unwanted_flexbody' di...
Definition: TuneupFileFormat.h:138
RoR::CacheQuery::cqy_filter_type
RoR::LoaderType cqy_filter_type
Definition: CacheSystem.h:184
SkinFileFormat.h
RoR::GetFileLastModifiedTime
std::time_t GetFileLastModifiedTime(std::string const &path)
Definition: PlatformUtils.cpp:238
RoR::CacheSystem::LoadResource
void LoadResource(CacheEntryPtr &t)
Loads the associated resource bundle if not already done.
Definition: CacheSystem.cpp:1435
RoR::GenericDocument
Definition: GenericFileFormat.h:65
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
RoR::CacheEntry::wheelcount
int wheelcount
Definition: CacheSystem.h:115
RoR::CacheSystem::WriteCacheFileJson
void WriteCacheFileJson()
Definition: CacheSystem.cpp:683
RoR::CVar::setVal
void setVal(T val)
Definition: CVar.h:72
RoR::CID_Max
@ CID_Max
SPECIAL VALUE - Maximum allowed to be present in any mod files.
Definition: CacheSystem.h:154
RoR::TuneupDef::filename
std::string filename
target vehicle filename
Definition: TuneupFileFormat.h:99
_L
#define _L
Definition: ErrorUtils.cpp:34
RoR::Actor::getUsedSkinEntry
CacheEntryPtr & getUsedSkinEntry()
Definition: Actor.cpp:4719
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLEXBODY_RESET
@ TUNEUP_FORCEREMOVE_FLEXBODY_RESET
'subject_id' is flexbody ID.
RoR::CacheEntry::nodecount
int nodecount
Definition: CacheSystem.h:110
RigDef::Engine
Definition: RigDef_File.h:805
RoR::CreateProjectRequest::cpr_overwrite
bool cpr_overwrite
Definition: CacheSystem.h:229
RoR::CacheEntry::resource_bundle_path
std::string resource_bundle_path
Path of ZIP or directory which contains the media. Shared between CacheEntries, loaded only once.
Definition: CacheSystem.h:81
RoR::ActorSpawnRequest::asr_debugview
int asr_debugview
Definition: SimData.h:858
RoR::CacheEntry::flexbodiescount
int flexbodiescount
Definition: CacheSystem.h:125
RigDef_Parser.h
Checks the rig-def file syntax and loads data to memory.
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_PROP_RESET
@ TUNEUP_PROTECTED_PROP_RESET
'subject_id' is prop ID.
RoR::CacheEntry::wingscount
int wingscount
Definition: CacheSystem.h:120
RoR::App::sys_projects_dir
CVar * sys_projects_dir
Definition: Application.cpp:173
RoR::MSG_SIM_SPAWN_ACTOR_REQUESTED
@ MSG_SIM_SPAWN_ACTOR_REQUESTED
Payload = RoR::ActorSpawnRequest* (owner)
Definition: Application.h:119
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_MANAGEDMAT_RESET
@ TUNEUP_PROTECTED_MANAGEDMAT_RESET
'subject' is managed material name.
RoR::CacheSystem::ReLoadResource
void ReLoadResource(CacheEntryPtr &t)
Forces reloading the associated bundle.
Definition: CacheSystem.cpp:1521
RoR::CacheEntry::categoryname
Ogre::String categoryname
category name
Definition: CacheSystem.h:73
RoR::EraseIf
void EraseIf(std::vector< T, A > &c, Predicate pred)
Definition: Utils.h:74
RoR::CacheEntry::exhaustscount
int exhaustscount
Definition: CacheSystem.h:124
RoR::ModifyProjectRequestType::TUNEUP_PROTECTED_WHEEL_SET
@ TUNEUP_PROTECTED_WHEEL_SET
'subject_id' is wheel ID.
RoR::ActorPtr
RefCountingObjectPtr< Actor > ActorPtr
Definition: ForwardDeclarations.h:194
RoR::MSG_SIM_DELETE_ACTOR_REQUESTED
@ MSG_SIM_DELETE_ACTOR_REQUESTED
Payload = RoR::ActorPtr* (owner)
Definition: Application.h:121
RoR::LT_AllBeam
@ LT_AllBeam
Definition: Application.h:303
RoR::CacheEntry::truckmass
float truckmass
Definition: CacheSystem.h:128
RoR::TuneupDef::category_id
CacheCategoryId category_id
Definition: TuneupFileFormat.h:104
RoR::SkinParser::ParseSkins
static std::vector< std::shared_ptr< RoR::SkinDef > > ParseSkins(Ogre::DataStreamPtr &stream)
Definition: SkinFileFormat.cpp:34
RoR::GenericDocContext::getTokKeyword
std::string getTokKeyword(int offset=0) const
Definition: GenericFileFormat.h:117
Terrain.h
RoR::CacheEntry::maxrpm
float maxrpm
Definition: CacheSystem.h:131
RoR::ModifyProjectRequestType::PROJECT_RESET_TUNEUP
@ PROJECT_RESET_TUNEUP
'subject' is empty. This resets the auto-generated tuneup to orig. values.
RoR::CacheSystem::CacheSystem
CacheSystem()
Definition: CacheSystem.cpp:125
RoR::CacheEntry::turbopropscount
int turbopropscount
Definition: CacheSystem.h:121
BitMask_t
uint32_t BitMask_t
Definition: BitFlags.h:7
RigDef::SequentialImporter::Disable
void Disable()
Definition: RigDef_SequentialImporter.h:120
RoR::GenericDocContext
Definition: GenericFileFormat.h:90
RoR::CacheQuery::cqy_filter_guid
std::string cqy_filter_guid
Exact match (case-insensitive); leave empty to disable.
Definition: CacheSystem.h:186
RoR::TuneupDef::force_remove_flares
std::set< FlareID_t > force_remove_flares
User unticked an UI checkbox in Tuning menu, section Flares.
Definition: TuneupFileFormat.h:128
Ogre
Definition: ExtinguishableFireAffector.cpp:35
GfxActor.h
Manager for all visuals belonging to a single actor.
RoR::CacheEntry::turbojetcount
int turbojetcount
Definition: CacheSystem.h:122
RoR::ActorSpawnRequest::Origin::USER
@ USER
Direct selection by user via GUI.
RoR::Console::CONSOLE_MSGTYPE_ACTOR
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition: Console.h:63
RoR::App::sys_process_dir
CVar * sys_process_dir
Definition: Application.cpp:162
AddonPartFileFormat.h
RoR::GenericDocument::loadFromDataStream
virtual void loadFromDataStream(Ogre::DataStreamPtr datastream, BitMask_t options=0)
Definition: GenericFileFormat.cpp:1000
RoR::GfxActor::GetDebugView
DebugViewType GetDebugView() const
Definition: GfxActor.h:138
RigDef::DocumentPtr
std::shared_ptr< Document > DocumentPtr
Definition: RigDef_Prerequisites.h:38
RoR::Console::CONSOLE_SYSTEM_WARNING
@ CONSOLE_SYSTEM_WARNING
Definition: Console.h:53
RoR::TuneupDef::force_wheel_sides
std::map< WheelID_t, WheelSide > force_wheel_sides
UI overrides.
Definition: TuneupFileFormat.h:127
RoR::Terrn2Author::type
std::string type
Definition: Terrn2FileFormat.h:38
RoR::CacheEntry::hydroscount
int hydroscount
Definition: CacheSystem.h:114
RoR::Console::CONSOLE_MSGTYPE_INFO
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition: Console.h:60
RoR::WheelSide
WheelSide
Used by rig-def/addonpart/tuneup formats to specify wheel rim mesh orientation.
Definition: GfxData.h:115
RoR::Terrn2Def::category_id
int category_id
Definition: Terrn2FileFormat.h:55
RoR::ActorSpawnRequest::asr_position
Ogre::Vector3 asr_position
Definition: SimData.h:851
RoR::ModifyProjectRequest::mpr_type
ModifyProjectRequestType mpr_type
Definition: CacheSystem.h:268
RoR::TuneupDef::guid
std::string guid
target vehicle GUID
Definition: TuneupFileFormat.h:98
RoR::ActorType
ActorType
< Aka 'Driveable'
Definition: SimData.h:88
RoR::ModifyProjectRequestType::TUNEUP_FORCED_WHEEL_SIDE_RESET
@ TUNEUP_FORCED_WHEEL_SIDE_RESET
'subject_id' is wheel ID.
RoR::CacheEntry::filetime
std::time_t filetime
filetime
Definition: CacheSystem.h:83
RoR::BOAT
@ BOAT
its a boat
Definition: SimData.h:95
RoR::Terrn2Def::name
std::string name
Definition: Terrn2FileFormat.h:52
RoR::CacheSystem::FillAssetPackDetailInfo
void FillAssetPackDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
Definition: CacheSystem.cpp:1251
RoR::GUI::GameMainMenu::CacheUpdatedNotice
void CacheUpdatedNotice()
Definition: GUI_GameMainMenu.cpp:56
RoR::Actor::ar_state
ActorState ar_state
Definition: Actor.h:446
RoR::CacheEntry::custom_particles
bool custom_particles
Definition: CacheSystem.h:134
RoR::ContentManager::ListAllUserContent
std::string ListAllUserContent()
Used by ModCache for quick detection of added/removed content.
Definition: ContentManager.cpp:427
GenericFileFormat.h
Generic text file parser.
RoR::AI
@ AI
machine controlled by an Artificial Intelligence
Definition: SimData.h:97
RoR::GenericDocument::OPTION_ALLOW_NAKED_STRINGS
static const BitMask_t OPTION_ALLOW_NAKED_STRINGS
Allow strings without quotes, for backwards compatibility.
Definition: GenericFileFormat.h:67
RoR::CID_All
@ CID_All
Definition: CacheSystem.h:156
RoR::AuthorInfo::name
Ogre::String name
Definition: CacheSystem.h:51
RoR::CacheQuery::cqy_filter_target_filename
std::string cqy_filter_target_filename
Exact match (case-insensitive); leave empty to disable (currently only used with addonparts)
Definition: CacheSystem.h:187
RoR::CacheEntry::commandscount
int commandscount
Definition: CacheSystem.h:117
RoR::ActorSpawnRequest::asr_rotation
Ogre::Quaternion asr_rotation
Definition: SimData.h:852
RoR::Actor::getWorkingTuneupDef
TuneupDefPtr & getWorkingTuneupDef()
Definition: Actor.cpp:4724
RoR
Definition: AppContext.h:36
RoR::MODCACHEACTIVITY_ENTRY_MODIFIED
@ MODCACHEACTIVITY_ENTRY_MODIFIED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
Definition: ScriptEvents.h:93
RoR::CacheSystem::Query
size_t Query(CacheQuery &query)
Definition: CacheSystem.cpp:2090
RoR::ContentManager::ResourcePack::MESHES
static const ResourcePack MESHES
Definition: ContentManager.h:60
RoR::TuneupDef::force_remove_exhausts
std::set< ExhaustID_t > force_remove_exhausts
User unticked an UI checkbox in Tuning menu, section Exhausts.
Definition: TuneupFileFormat.h:129
RoR::Log
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
Definition: Application.cpp:419
RoR::GUIManager::GameMainMenu
GUI::GameMainMenu GameMainMenu
Definition: GUIManager.h:104
RoR::CacheQuery::cqy_results
std::vector< CacheQueryResult > cqy_results
Definition: CacheSystem.h:191
RoR::LT_Train
@ LT_Train
Definition: Application.h:299
RoR::CacheEntry::default_skin
std::string default_skin
Definition: CacheSystem.h:107
RoR::CacheSystem::GenerateHashFromFilenames
void GenerateHashFromFilenames()
For quick detection of added/removed content.
Definition: CacheSystem.cpp:1171
RoR::FileExists
bool FileExists(const char *path)
Path must be UTF-8 encoded.
Definition: PlatformUtils.cpp:163
RoR::CacheEntry::guid
Ogre::String guid
global unique id; Type "addonpart" leaves this empty and uses addonpart_guids; Always lowercase.
Definition: CacheSystem.h:77
CACHE_FILE
#define CACHE_FILE
Definition: CacheSystem.h:41
RoR::GUI::TopMenubar::tuning_actor
ActorPtr tuning_actor
Detecting actor change to update cached values.
Definition: GUI_TopMenubar.h:111
RoR::CacheSystem::m_resource_paths
std::set< Ogre::String > m_resource_paths
A temporary list of existing resource paths.
Definition: CacheSystem.h:391
RoR::CacheEntry::flarescount
int flarescount
Definition: CacheSystem.h:118
RigDef::WheelPropulsion::NONE
@ NONE
RoR::CacheSystem::m_loaded
bool m_loaded
Definition: CacheSystem.h:384
RoR::CacheSystem::StripUIDfromString
static Ogre::String StripUIDfromString(Ogre::String uidstr)
Definition: CacheSystem.cpp:725
RigDef::Fileinfo::category_id
int category_id
Definition: RigDef_File.h:872
RoR::CacheEntry::fname
Ogre::String fname
filename
Definition: CacheSystem.h:67
RoR::CacheEntry::fname_without_uid
Ogre::String fname_without_uid
filename
Definition: CacheSystem.h:68