RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  m_known_extensions.push_back("dashboard");
143  m_known_extensions.push_back("gadget");
144 
145  // register the dirs
146  m_content_dirs.push_back("mods");
147  m_content_dirs.push_back("packs");
148  m_content_dirs.push_back("terrains");
149  m_content_dirs.push_back("vehicles");
150  m_content_dirs.push_back("projects");
151 }
152 
154 {
155  m_resource_paths.clear();
157 
158  if (validity != CacheValidity::VALID)
159  {
160  if (validity == CacheValidity::NEEDS_REBUILD)
161  {
162  RoR::Log("[RoR|ModCache] Performing rebuild ...");
163  this->ClearCache();
164  }
165  else
166  {
167  RoR::Log("[RoR|ModCache] Performing update ...");
168  this->ClearResourceGroups();
169  this->PruneCache();
170  }
171  const bool orig_echo = App::diag_log_console_echo->getBool();
176  this->DetectDuplicates();
177  this->WriteCacheFileJson();
178 
179  this->LoadCacheFileJson();
180  }
181 
182  RoR::Log("[RoR|ModCache] Cache loaded");
183  m_loaded = true;
184 }
185 
186 CacheEntryPtr CacheSystem::FindEntryByFilename(LoaderType type, bool partial, const std::string& _filename_maybe_bundlequalified)
187 {
188  // "Bundle-qualified" format also specifies the ZIP/directory in modcache, i.e. "mybundle.zip:myactor.truck"
189  // Like the filename, the bundle name lookup is case-insensitive.
190  // -------------------------------------------------------------------------------------------------
191 
192  std::string filename;
193  std::string bundlename;
194  SplitBundleQualifiedFilename(_filename_maybe_bundlequalified, bundlename, filename);
195  StringUtil::toLowerCase(filename);
196  StringUtil::toLowerCase(bundlename);
197  size_t partial_match_length = std::numeric_limits<size_t>::max();
198  CacheEntryPtr partial_match = nullptr;
199  std::vector<CacheEntryPtr> log_candidates;
200  for (CacheEntryPtr& entry : m_entries)
201  {
202  if ((type == LT_Terrain) != (entry->fext == "terrn2") ||
203  (type == LT_DashBoard) != (entry->fext == "dashboard") ||
204  (type == LT_AllBeam && entry->fext == "skin"))
205  continue;
206 
207  String fname = entry->fname;
208  String fname_without_uid = entry->fname_without_uid;
209  String bname;
210  String _path_placeholder;
211  StringUtil::splitFilename(entry->resource_bundle_path, bname, _path_placeholder);
212  StringUtil::toLowerCase(fname);
213  StringUtil::toLowerCase(fname_without_uid);
214  StringUtil::toLowerCase(bname);
215  if (fname == filename || fname_without_uid == filename)
216  {
217  if (bundlename == "" || bname == bundlename)
218  {
219  return entry;
220  }
221  else
222  {
223  log_candidates.push_back(entry);
224  }
225  }
226  else if (partial &&
227  fname.length() < partial_match_length &&
228  fname.find(filename) != std::string::npos)
229  {
230  if (bundlename == "" || bname == bundlename)
231  {
232  partial_match = entry;
233  partial_match_length = fname.length();
234  }
235  else
236  {
237  log_candidates.push_back(entry);
238  }
239  }
240  }
241 
242  if (log_candidates.size() > 0)
243  {
245  fmt::format(_LC("CacheSystem", "Mod '{}' was not found in cache; candidates ({}) are:"), _filename_maybe_bundlequalified, log_candidates.size()));
246  for (CacheEntryPtr& entry: log_candidates)
247  {
248  std::string bundle_name, bundle_path;
249  StringUtil::toLowerCase(bundle_name);
250  Ogre::StringUtil::splitFilename(entry->resource_bundle_path, bundle_name, bundle_path);
252  fmt::format(_LC("CacheSystem", "* {}:{}"), bundle_name, entry->fname));
253  }
254  }
255 
256  return (partial) ? partial_match : nullptr;
257 }
258 
260 {
262 
263  // Load cache file
264  CacheValidity validity = this->LoadCacheFileJson();
265 
266  if (validity != CacheValidity::VALID)
267  {
268  RoR::Log("[RoR|ModCache] Cannot load cache file: wrong version, corrupted or missing.");
269  return validity;
270  }
271 
272  // Compare stored hash with generated hash
274  {
275  RoR::Log("[RoR|ModCache] Cache file out of date");
277  }
278 
279  for (auto& entry : m_entries)
280  {
281  std::string fn = entry->resource_bundle_path;
282  if (entry->resource_bundle_type == "FileSystem")
283  {
284  fn = PathCombine(fn, entry->fname);
285  }
286 
287  if ((entry->filetime != RoR::GetFileLastModifiedTime(fn)))
288  {
290  }
291  }
292 
293  RoR::Log("[RoR|ModCache] Cache valid");
294  return CacheValidity::VALID;
295 }
296 
297 void CacheSystem::ImportEntryFromJson(rapidjson::Value& j_entry, CacheEntryPtr & out_entry)
298 {
299  // Common details
300  out_entry->usagecounter = j_entry["usagecounter"].GetInt();
301  out_entry->addtimestamp = j_entry["addtimestamp"].GetInt();
302  out_entry->resource_bundle_type = j_entry["resource_bundle_type"].GetString();
303  out_entry->resource_bundle_path = j_entry["resource_bundle_path"].GetString();
304  out_entry->fpath = j_entry["fpath"].GetString();
305  out_entry->fname = j_entry["fname"].GetString();
306  out_entry->fname_without_uid = j_entry["fname_without_uid"].GetString();
307  out_entry->fext = j_entry["fext"].GetString();
308  out_entry->filetime = j_entry["filetime"].GetInt();
309  out_entry->dname = j_entry["dname"].GetString();
310  out_entry->uniqueid = j_entry["uniqueid"].GetString();
311  out_entry->version = j_entry["version"].GetInt();
312  out_entry->filecachename = j_entry["filecachename"].GetString();
313 
314  out_entry->guid = j_entry["guid"].GetString();
315  Ogre::StringUtil::trim(out_entry->guid);
316 
317  // Category
318  int category_id = j_entry["categoryid"].GetInt();
319  auto category_itor = m_categories.find(category_id);
320  if (category_itor == m_categories.end() || category_id >= CID_Max)
321  {
322  category_itor = m_categories.find(CID_Unsorted);
323  }
324  out_entry->categoryname = category_itor->second;
325  out_entry->categoryid = category_itor->first;
326 
327  // Common - Authors
328  for (rapidjson::Value& j_author: j_entry["authors"].GetArray())
329  {
330  AuthorInfo author;
331 
332  author.type = j_author["type"].GetString();
333  author.name = j_author["name"].GetString();
334  author.email = j_author["email"].GetString();
335  author.id = j_author["id"].GetInt();
336 
337  out_entry->authors.push_back(author);
338  }
339 
340  // Vehicle details
341  out_entry->description = j_entry["description"].GetString();
342  out_entry->tags = j_entry["tags"].GetString();
343  out_entry->default_skin = j_entry["default_skin"].GetString();
344  out_entry->fileformatversion = j_entry["fileformatversion"].GetInt();
345  out_entry->hasSubmeshs = j_entry["hasSubmeshs"].GetBool();
346  out_entry->nodecount = j_entry["nodecount"].GetInt();
347  out_entry->beamcount = j_entry["beamcount"].GetInt();
348  out_entry->shockcount = j_entry["shockcount"].GetInt();
349  out_entry->fixescount = j_entry["fixescount"].GetInt();
350  out_entry->hydroscount = j_entry["hydroscount"].GetInt();
351  out_entry->wheelcount = j_entry["wheelcount"].GetInt();
352  out_entry->propwheelcount = j_entry["propwheelcount"].GetInt();
353  out_entry->commandscount = j_entry["commandscount"].GetInt();
354  out_entry->flarescount = j_entry["flarescount"].GetInt();
355  out_entry->propscount = j_entry["propscount"].GetInt();
356  out_entry->wingscount = j_entry["wingscount"].GetInt();
357  out_entry->turbopropscount = j_entry["turbopropscount"].GetInt();
358  out_entry->turbojetcount = j_entry["turbojetcount"].GetInt();
359  out_entry->rotatorscount = j_entry["rotatorscount"].GetInt();
360  out_entry->exhaustscount = j_entry["exhaustscount"].GetInt();
361  out_entry->flexbodiescount = j_entry["flexbodiescount"].GetInt();
362  out_entry->soundsourcescount = j_entry["soundsourcescount"].GetInt();
363  out_entry->truckmass = j_entry["truckmass"].GetFloat();
364  out_entry->loadmass = j_entry["loadmass"].GetFloat();
365  out_entry->minrpm = j_entry["minrpm"].GetFloat();
366  out_entry->maxrpm = j_entry["maxrpm"].GetFloat();
367  out_entry->torque = j_entry["torque"].GetFloat();
368  out_entry->customtach = j_entry["customtach"].GetBool();
369  out_entry->custom_particles = j_entry["custom_particles"].GetBool();
370  out_entry->forwardcommands = j_entry["forwardcommands"].GetBool();
371  out_entry->importcommands = j_entry["importcommands"].GetBool();
372  out_entry->rescuer = j_entry["rescuer"].GetBool();
373  out_entry->driveable = ActorType(j_entry["driveable"].GetInt());
374  out_entry->numgears = j_entry["numgears"].GetInt();
375  out_entry->enginetype = static_cast<char>(j_entry["enginetype"].GetInt());
376 
377  // Vehicle 'section-configs' (aka Modules in RigDef namespace)
378  for (rapidjson::Value& j_module_name: j_entry["sectionconfigs"].GetArray())
379  {
380  out_entry->sectionconfigs.push_back(j_module_name.GetString());
381  }
382 
383  // Addon part suggested mod guids
384  for (rapidjson::Value& j_addonguid: j_entry["addonpart_guids"].GetArray())
385  {
386  out_entry->addonpart_guids.insert(j_addonguid.GetString());
387  }
388 
389  // Addon part suggested mod filenames
390  for (rapidjson::Value& j_addonfname: j_entry["addonpart_filenames"].GetArray())
391  {
392  out_entry->addonpart_filenames.insert(j_addonfname.GetString());
393  }
394 
395  // Tuneup details
396  out_entry->tuneup_associated_filename = j_entry["tuneup_associated_filename"].GetString();
397 }
398 
400 {
401  // Clear existing entries
402  m_entries.clear();
403 
404  rapidjson::Document j_doc;
405  if (!App::GetContentManager()->LoadAndParseJson(CACHE_FILE, RGN_CACHE, j_doc) ||
406  !j_doc.IsObject() || !j_doc.HasMember("entries") || !j_doc["entries"].IsArray())
407  {
408  RoR::Log("[RoR|ModCache] Error, cache file still invalid after check/update, content selector will be empty.");
410  }
411 
412  if (j_doc["format_version"].GetInt() != CACHE_FILE_FORMAT)
413  {
414  RoR::Log("[RoR|ModCache] Invalid cache file format");
416  }
417 
418  for (rapidjson::Value& j_entry: j_doc["entries"].GetArray())
419  {
420  CacheEntryPtr entry = new CacheEntry();
421  this->ImportEntryFromJson(j_entry, entry);
422  entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
423  m_entries.push_back(entry);
424  }
425 
426  m_filenames_hash_loaded = j_doc["global_hash"].GetString();
427 
428  return CacheValidity::VALID;
429 }
430 
432 {
433  this->LoadCacheFileJson();
434 
435  std::vector<String> paths;
436  for (auto& entry : m_entries)
437  {
438  std::string fn = entry->resource_bundle_path;
439  if (entry->resource_bundle_type == "FileSystem")
440  {
441  fn = PathCombine(fn, entry->fname);
442  }
443 
444  if (!RoR::FileExists(fn.c_str()) || (entry->filetime != RoR::GetFileLastModifiedTime(fn)))
445  {
446  if (!entry->deleted)
447  {
448  if (std::find(paths.begin(), paths.end(), fn) == paths.end())
449  {
450  RoR::LogFormat("[RoR|ModCache] Removing '%s'", fn.c_str());
451  paths.push_back(fn);
452  }
453  this->RemoveFileCache(entry);
454  }
455  entry->deleted = true;
456  }
457  else
458  {
459  m_resource_paths.insert(fn);
460  }
461  }
462 }
463 
465 {
466  for (auto& entry : m_entries)
467  {
468  String group = entry->resource_group;
469  if (!group.empty())
470  {
471  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
472  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
473  }
474  }
475 }
476 
478 {
479  RoR::Log("[RoR|ModCache] Searching for duplicates ...");
480  std::map<String, String> possible_duplicates;
481  for (int i=0; i<m_entries.size(); i++)
482  {
483  CacheEntryPtr entryA = m_entries[i];
484 
485  if (entryA->deleted)
486  continue;
487 
488  String dnameA = entryA->dname;
489  StringUtil::toLowerCase(dnameA);
490  StringUtil::trim(dnameA);
491  String dirA = entryA->resource_bundle_path;
492  StringUtil::toLowerCase(dirA);
493  String basenameA, basepathA;
494  StringUtil::splitFilename(dirA, basenameA, basepathA);
495  String filenameWUIDA = entryA->fname_without_uid;
496  StringUtil::toLowerCase(filenameWUIDA);
497 
498  for (int j=i+1; j<m_entries.size(); j++)
499  {
500  CacheEntryPtr entryB = m_entries[j];
501 
502  if (entryB->deleted)
503  continue;
504 
505  String filenameWUIDB = entryB->fname_without_uid;
506  StringUtil::toLowerCase(filenameWUIDB);
507  if (filenameWUIDA != filenameWUIDB)
508  continue;
509 
510  String dnameB = entryB->dname;
511  StringUtil::toLowerCase(dnameB);
512  StringUtil::trim(dnameB);
513  if (dnameA != dnameB)
514  continue;
515 
516  String dirB = entryB->resource_bundle_path;
517  StringUtil::toLowerCase(dirB);
518  String basenameB, basepathB;
519  StringUtil::splitFilename(dirB, basenameB, basepathB);
520  basenameA = Ogre::StringUtil::replaceAll(basenameA, " ", "_");
521  basenameA = Ogre::StringUtil::replaceAll(basenameA, "-", "_");
522  basenameB = Ogre::StringUtil::replaceAll(basenameB, " ", "_");
523  basenameB = Ogre::StringUtil::replaceAll(basenameB, "-", "_");
524  if (StripSHA1fromString(basenameA) != StripSHA1fromString(basenameB))
525  continue;
526 
527  if (entryA->resource_bundle_path == entryB->resource_bundle_path)
528  {
529  LOG("- duplicate: " + entryA->fpath + entryA->fname
530  + " <--> " + entryB->fpath + entryB->fname);
531  LOG(" - " + entryB->resource_bundle_path);
532  int idx = entryA->fpath.size() < entryB->fpath.size() ? i : j;
533  m_entries[idx]->deleted = true;
534  }
535  else
536  {
537  possible_duplicates[entryA->resource_bundle_path] = entryB->resource_bundle_path;
538  }
539  }
540  }
541  for (auto duplicate : possible_duplicates)
542  {
543  LOG("- possible duplicate: ");
544  LOG(" - " + duplicate.first);
545  LOG(" - " + duplicate.second);
546  }
547 }
548 
550 {
551  for (CacheEntryPtr& entry: m_entries)
552  {
553  if (modid == entry->number)
554  return entry;
555  }
556  return 0;
557 }
558 
559 String CacheSystem::GetPrettyName(String fname)
560 {
561  for (CacheEntryPtr& entry: m_entries)
562  {
563  if (fname == entry->fname)
564  return entry->dname;
565  }
566  return "";
567 }
568 
570 {
571  switch (driveable)
572  {
573  case ActorType::NOT_DRIVEABLE: return _LC("MainSelector", "Non-Driveable");
574  case ActorType::TRUCK: return _LC("MainSelector", "Truck");
575  case ActorType::AIRPLANE: return _LC("MainSelector", "Airplane");
576  case ActorType::BOAT: return _LC("MainSelector", "Boat");
577  case ActorType::MACHINE: return _LC("MainSelector", "Machine");
578  case ActorType::AI: return _LC("MainSelector", "A.I.");
579  default: return "";
580  };
581 }
582 
583 void CacheSystem::ExportEntryToJson(rapidjson::Value& j_entries, rapidjson::Document& j_doc, CacheEntryPtr const & entry)
584 {
585  rapidjson::Value j_entry(rapidjson::kObjectType);
586 
587  // Common details
588  j_entry.AddMember("usagecounter", entry->usagecounter, j_doc.GetAllocator());
589  j_entry.AddMember("addtimestamp", static_cast<int64_t>(entry->addtimestamp), j_doc.GetAllocator());
590  j_entry.AddMember("resource_bundle_type", rapidjson::StringRef(entry->resource_bundle_type.c_str()), j_doc.GetAllocator());
591  j_entry.AddMember("resource_bundle_path", rapidjson::StringRef(entry->resource_bundle_path.c_str()), j_doc.GetAllocator());
592  j_entry.AddMember("fpath", rapidjson::StringRef(entry->fpath.c_str()), j_doc.GetAllocator());
593  j_entry.AddMember("fname", rapidjson::StringRef(entry->fname.c_str()), j_doc.GetAllocator());
594  j_entry.AddMember("fname_without_uid", rapidjson::StringRef(entry->fname_without_uid.c_str()), j_doc.GetAllocator());
595  j_entry.AddMember("fext", rapidjson::StringRef(entry->fext.c_str()), j_doc.GetAllocator());
596  j_entry.AddMember("filetime", static_cast<int64_t>(entry->filetime), j_doc.GetAllocator());
597  j_entry.AddMember("dname", rapidjson::StringRef(entry->dname.c_str()), j_doc.GetAllocator());
598  j_entry.AddMember("categoryid", entry->categoryid, j_doc.GetAllocator());
599  j_entry.AddMember("uniqueid", rapidjson::StringRef(entry->uniqueid.c_str()), j_doc.GetAllocator());
600  j_entry.AddMember("guid", rapidjson::StringRef(entry->guid.c_str()), j_doc.GetAllocator());
601  j_entry.AddMember("version", entry->version, j_doc.GetAllocator());
602  j_entry.AddMember("filecachename", rapidjson::StringRef(entry->filecachename.c_str()), j_doc.GetAllocator());
603 
604  // Common - Authors
605  rapidjson::Value j_authors(rapidjson::kArrayType);
606  for (AuthorInfo const& author: entry->authors)
607  {
608  rapidjson::Value j_author(rapidjson::kObjectType);
609 
610  j_author.AddMember("type", rapidjson::StringRef(author.type.c_str()), j_doc.GetAllocator());
611  j_author.AddMember("name", rapidjson::StringRef(author.name.c_str()), j_doc.GetAllocator());
612  j_author.AddMember("email", rapidjson::StringRef(author.email.c_str()), j_doc.GetAllocator());
613  j_author.AddMember("id", author.id, j_doc.GetAllocator());
614 
615  j_authors.PushBack(j_author, j_doc.GetAllocator());
616  }
617  j_entry.AddMember("authors", j_authors, j_doc.GetAllocator());
618 
619  // Vehicle details
620  j_entry.AddMember("description", rapidjson::StringRef(entry->description.c_str()), j_doc.GetAllocator());
621  j_entry.AddMember("tags", rapidjson::StringRef(entry->tags.c_str()), j_doc.GetAllocator());
622  j_entry.AddMember("default_skin", rapidjson::StringRef(entry->default_skin.c_str()), j_doc.GetAllocator());
623  j_entry.AddMember("fileformatversion", entry->fileformatversion, j_doc.GetAllocator());
624  j_entry.AddMember("hasSubmeshs", entry->hasSubmeshs, j_doc.GetAllocator());
625  j_entry.AddMember("nodecount", entry->nodecount, j_doc.GetAllocator());
626  j_entry.AddMember("beamcount", entry->beamcount, j_doc.GetAllocator());
627  j_entry.AddMember("shockcount", entry->shockcount, j_doc.GetAllocator());
628  j_entry.AddMember("fixescount", entry->fixescount, j_doc.GetAllocator());
629  j_entry.AddMember("hydroscount", entry->hydroscount, j_doc.GetAllocator());
630  j_entry.AddMember("wheelcount", entry->wheelcount, j_doc.GetAllocator());
631  j_entry.AddMember("propwheelcount", entry->propwheelcount, j_doc.GetAllocator());
632  j_entry.AddMember("commandscount", entry->commandscount, j_doc.GetAllocator());
633  j_entry.AddMember("flarescount", entry->flarescount, j_doc.GetAllocator());
634  j_entry.AddMember("propscount", entry->propscount, j_doc.GetAllocator());
635  j_entry.AddMember("wingscount", entry->wingscount, j_doc.GetAllocator());
636  j_entry.AddMember("turbopropscount", entry->turbopropscount, j_doc.GetAllocator());
637  j_entry.AddMember("turbojetcount", entry->turbojetcount, j_doc.GetAllocator());
638  j_entry.AddMember("rotatorscount", entry->rotatorscount, j_doc.GetAllocator());
639  j_entry.AddMember("exhaustscount", entry->exhaustscount, j_doc.GetAllocator());
640  j_entry.AddMember("flexbodiescount", entry->flexbodiescount, j_doc.GetAllocator());
641  j_entry.AddMember("soundsourcescount", entry->soundsourcescount, j_doc.GetAllocator());
642  j_entry.AddMember("truckmass", entry->truckmass, j_doc.GetAllocator());
643  j_entry.AddMember("loadmass", entry->loadmass, j_doc.GetAllocator());
644  j_entry.AddMember("minrpm", entry->minrpm, j_doc.GetAllocator());
645  j_entry.AddMember("maxrpm", entry->maxrpm, j_doc.GetAllocator());
646  j_entry.AddMember("torque", entry->torque, j_doc.GetAllocator());
647  j_entry.AddMember("customtach", entry->customtach, j_doc.GetAllocator());
648  j_entry.AddMember("custom_particles", entry->custom_particles, j_doc.GetAllocator());
649  j_entry.AddMember("forwardcommands", entry->forwardcommands, j_doc.GetAllocator());
650  j_entry.AddMember("importcommands", entry->importcommands, j_doc.GetAllocator());
651  j_entry.AddMember("rescuer", entry->rescuer, j_doc.GetAllocator());
652  j_entry.AddMember("driveable", entry->driveable, j_doc.GetAllocator());
653  j_entry.AddMember("numgears", entry->numgears, j_doc.GetAllocator());
654  j_entry.AddMember("enginetype", entry->enginetype, j_doc.GetAllocator());
655 
656  // Vehicle 'section-configs' (aka Modules in RigDef namespace)
657  rapidjson::Value j_sectionconfigs(rapidjson::kArrayType);
658  for (std::string const & module_name: entry->sectionconfigs)
659  {
660  j_sectionconfigs.PushBack(rapidjson::StringRef(module_name.c_str()), j_doc.GetAllocator());
661  }
662  j_entry.AddMember("sectionconfigs", j_sectionconfigs, j_doc.GetAllocator());
663 
664  // Addon part details
665  rapidjson::Value j_addonguids(rapidjson::kArrayType);
666  for (std::string const & ag: entry->addonpart_guids)
667  {
668  j_addonguids.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
669  }
670  j_entry.AddMember("addonpart_guids", j_addonguids, j_doc.GetAllocator());
671 
672  rapidjson::Value j_addonfnames(rapidjson::kArrayType);
673  for (std::string const & ag: entry->addonpart_filenames)
674  {
675  j_addonfnames.PushBack(rapidjson::StringRef(ag.c_str()), j_doc.GetAllocator());
676  }
677  j_entry.AddMember("addonpart_filenames", j_addonfnames, j_doc.GetAllocator());
678 
679  // Tuneup details
680  j_entry.AddMember("tuneup_associated_filename", rapidjson::StringRef(entry->tuneup_associated_filename.c_str()), j_doc.GetAllocator());
681 
682  // Add entry to list
683  j_entries.PushBack(j_entry, j_doc.GetAllocator());
684 }
685 
687 {
688  // Basic file structure
689  rapidjson::Document j_doc;
690  j_doc.SetObject();
691  j_doc.AddMember("format_version", CACHE_FILE_FORMAT, j_doc.GetAllocator());
692  j_doc.AddMember("global_hash", rapidjson::StringRef(m_filenames_hash_generated.c_str()), j_doc.GetAllocator());
693 
694  // Entries
695  rapidjson::Value j_entries(rapidjson::kArrayType);
696  for (CacheEntryPtr const& entry : m_entries)
697  {
698  if (!entry->deleted)
699  {
700  this->ExportEntryToJson(j_entries, j_doc, entry);
701  }
702  }
703  j_doc.AddMember("entries", j_entries, j_doc.GetAllocator());
704 
705  // Write to file
706  if (App::GetContentManager()->SerializeAndWriteJson(CACHE_FILE, RGN_CACHE, j_doc)) // Logs errors
707  {
708  RoR::LogFormat("[RoR|ModCache] File '%s' written OK", CACHE_FILE);
709  }
710 }
711 
713 {
715  for (auto& entry : m_entries)
716  {
717  String group = entry->resource_group;
718  if (!group.empty())
719  {
720  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
721  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
722  }
723  this->RemoveFileCache(entry);
724  }
725  m_entries.clear();
726 }
727 
728 Ogre::String CacheSystem::StripUIDfromString(Ogre::String uidstr)
729 {
730  size_t pos = uidstr.find("-");
731  if (pos != String::npos && pos >= 3 && uidstr.substr(pos - 3, 3) == "UID")
732  return uidstr.substr(pos + 1, uidstr.length() - pos);
733  return uidstr;
734 }
735 
736 Ogre::String CacheSystem::StripSHA1fromString(Ogre::String sha1str)
737 {
738  size_t pos = sha1str.find_first_of("-_");
739  if (pos != String::npos && pos >= 20)
740  return sha1str.substr(pos + 1, sha1str.length() - pos);
741  return sha1str;
742 }
743 
744 void CacheSystem::AddFile(String group, Ogre::FileInfo f, String ext)
745 {
746  String type = f.archive ? f.archive->getType() : "FileSystem";
747  String path = f.archive ? f.archive->getName() : "";
748 
749  if (std::find_if(m_entries.begin(), m_entries.end(), [&](CacheEntryPtr& entry)
750  { return !entry->deleted && entry->fname == f.filename && entry->resource_bundle_path == path; }) != m_entries.end())
751  return;
752 
753  RoR::LogFormat("[RoR|CacheSystem] Preparing to add file '%f'", f.filename.c_str());
754 
755  try
756  {
757  DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(f.filename, group);
758  // ds closes automatically, so do _not_ close it explicitly below
759 
760  std::vector<CacheEntryPtr> new_entries;
761  if (ext == "terrn2")
762  {
763  CacheEntryPtr entry = new CacheEntry();
764  FillTerrainDetailInfo(entry, ds, f.filename);
765  new_entries.push_back(entry);
766  }
767  else if (ext == "skin")
768  {
769  auto new_skins = RoR::SkinParser::ParseSkins(ds);
770  for (auto skin_def: new_skins)
771  {
772  CacheEntryPtr entry = new CacheEntry();
773  FillSkinDetailInfo(entry, skin_def);
774  new_entries.push_back(entry);
775  }
776  }
777  else if (ext == "addonpart")
778  {
779  CacheEntryPtr entry = new CacheEntry();
780  FillAddonPartDetailInfo(entry, ds);
781  new_entries.push_back(entry);
782  }
783  else if (ext == "tuneup")
784  {
785  auto new_tuneups = RoR::TuneupUtil::ParseTuneups(ds);
786  for (auto tuneup_def: new_tuneups)
787  {
788  CacheEntryPtr entry = new CacheEntry();
789  FillTuneupDetailInfo(entry, tuneup_def);
790  new_entries.push_back(entry);
791  }
792  }
793  else if (ext == "assetpack")
794  {
795  CacheEntryPtr entry = new CacheEntry();
796  FillAssetPackDetailInfo(entry, ds);
797  new_entries.push_back(entry);
798  }
799  else if (ext == "dashboard")
800  {
801  CacheEntryPtr entry = new CacheEntry();
802  FillDashboardDetailInfo(entry, ds);
803  new_entries.push_back(entry);
804  }
805  else if (ext == "gadget")
806  {
807  CacheEntryPtr entry = new CacheEntry();
808  FillGadgetDetailInfo(entry, ds);
809  new_entries.push_back(entry);
810  }
811  else
812  {
813  CacheEntryPtr entry = new CacheEntry();
814  FillTruckDetailInfo(entry, ds, f.filename, group);
815  new_entries.push_back(entry);
816  }
817 
818  for (auto& entry: new_entries)
819  {
820  Ogre::StringUtil::toLowerCase(entry->guid); // Important for comparsion
821  entry->fpath = f.path;
822  entry->fname = f.filename;
823  entry->fname_without_uid = StripUIDfromString(f.filename);
824  entry->fext = ext;
825  if (type == "Zip")
826  {
827  entry->filetime = RoR::GetFileLastModifiedTime(path);
828  }
829  else
830  {
831  entry->filetime = RoR::GetFileLastModifiedTime(PathCombine(path, f.filename));
832  }
833  entry->resource_bundle_type = type;
834  entry->resource_bundle_path = path;
835  entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
836  entry->addtimestamp = m_update_time;
837  this->GenerateFileCache(entry, group);
838  m_entries.push_back(entry);
839  }
840  }
841  catch (Ogre::Exception& e)
842  {
843  RoR::LogFormat("[RoR|CacheSystem] Error processing file '%s', message :%s",
844  f.filename.c_str(), e.getFullDescription().c_str());
845  }
846 }
847 
848 void CacheSystem::FillTruckDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr stream, String file_name, String group)
849 {
850  /* LOAD AND PARSE THE VEHICLE */
851  RigDef::Parser parser;
852  parser.Prepare();
853  parser.ProcessOgreStream(stream.get(), group);
854  parser.GetSequentialImporter()->Disable();
855  parser.Finalize();
856 
857  /* RETRIEVE DATA */
858 
859  RigDef::DocumentPtr def = parser.GetFile();
860 
861  /* Name */
862  if (!def->name.empty())
863  {
864  entry->dname = def->name; // Use retrieved name
865  }
866  else
867  {
868  entry->dname = "@" + file_name; // Fallback
869  }
870 
871  /* Description */
872  std::vector<Ogre::String>::iterator desc_itor = def->root_module->description.begin();
873  for (; desc_itor != def->root_module->description.end(); desc_itor++)
874  {
875  entry->description += *desc_itor + "\n";
876  }
877 
878  /* Authors */
879  std::vector<RigDef::Author>::iterator author_itor = def->root_module->author.begin();
880  for (; author_itor != def->root_module->author.end(); author_itor++)
881  {
882  AuthorInfo author;
883  author.email = author_itor->email;
884  author.id = (author_itor->_has_forum_account) ? static_cast<int>(author_itor->forum_account_id) : -1;
885  author.name = author_itor->name;
886  author.type = author_itor->type;
887 
888  entry->authors.push_back(author);
889  }
890 
891  /* Default skin */
892  if (def->root_module->default_skin.size() > 0)
893  {
894  entry->default_skin = def->root_module->default_skin.back().skin_name;
895  }
896 
897  /* Modules (previously called "sections") */
898  std::map<Ogre::String, std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = def->user_modules.begin();
899  for (; module_itor != def->user_modules.end(); module_itor++)
900  {
901  entry->sectionconfigs.push_back(module_itor->second->name);
902  }
903 
904  /* Engine */
905  /* TODO: Handle engines in modules */
906  if (def->root_module->engine.size() > 0)
907  {
908  RigDef::Engine& engine = def->root_module->engine[def->root_module->engine.size() - 1];
909  entry->numgears = static_cast<int>(engine.gear_ratios.size());
910  entry->minrpm = engine.shift_down_rpm;
911  entry->maxrpm = engine.shift_up_rpm;
912  entry->torque = engine.torque;
913  entry->enginetype = 't'; /* Truck (default) */
914  if (def->root_module->engoption.size() > 0)
915  {
916  entry->enginetype = (char)def->root_module->engoption[def->root_module->engoption.size() - 1].type;
917  }
918  }
919 
920  /* File info */
921  if (def->root_module->fileinfo.size() > 0)
922  {
923  RigDef::Fileinfo& data = def->root_module->fileinfo[def->root_module->fileinfo.size() - 1];
924 
925  entry->uniqueid = data.unique_id;
926  entry->categoryid = static_cast<int>(data.category_id);
927  entry->version = static_cast<int>(data.file_version);
928  }
929  else
930  {
931  entry->uniqueid = "-1";
932  entry->categoryid = -1;
933  entry->version = -1;
934  }
935 
936  /* Vehicle type */
937  /* NOTE: RigDef::Document allows modularization of vehicle type. Cache only supports single type.
938  This is a temporary solution which has undefined results for mixed-type vehicles.
939  */
940  ActorType vehicle_type = NOT_DRIVEABLE;
941  module_itor = def->user_modules.begin();
942  for (; module_itor != def->user_modules.end(); module_itor++)
943  {
944  if (module_itor->second->engine.size() > 0)
945  {
946  vehicle_type = TRUCK;
947  }
948  else if (module_itor->second->screwprops.size() > 0)
949  {
950  vehicle_type = BOAT;
951  }
952  /* Note: Sections 'turboprops' and 'turboprops2' are unified in TruckParser2013 */
953  else if (module_itor->second->turbojets.size() > 0 || module_itor->second->pistonprops.size() > 0 || module_itor->second->turboprops2.size() > 0)
954  {
955  vehicle_type = AIRPLANE;
956  }
957  }
958  /* Root module */
959  if (def->root_module->engine.size() > 0)
960  {
961  vehicle_type = TRUCK;
962  }
963  else if (def->root_module->screwprops.size() > 0)
964  {
965  vehicle_type = BOAT;
966  }
967  /* Note: Sections 'turboprops' and 'turboprops2' are unified in TruckParser2013 */
968  else if (def->root_module->turbojets.size() > 0 || def->root_module->pistonprops.size() > 0 || def->root_module->turboprops2.size() > 0)
969  {
970  vehicle_type = AIRPLANE;
971  }
972 
973  if (def->root_module->globals.size() > 0)
974  {
975  entry->truckmass = def->root_module->globals[def->root_module->globals.size() - 1].dry_mass;
976  entry->loadmass = def->root_module->globals[def->root_module->globals.size() - 1].cargo_mass;
977  }
978 
979  entry->forwardcommands = def->forward_commands;
980  entry->importcommands = def->import_commands;
981  entry->rescuer = def->rescuer;
982  if (def->root_module->guid.size() > 0)
983  {
984  entry->guid = def->root_module->guid[def->root_module->guid.size() - 1].guid;
985  Ogre::StringUtil::toLowerCase(entry->guid);
986  }
987  entry->fileformatversion = 0;
988  if (def->root_module->fileformatversion.size() > 0)
989  {
990  entry->fileformatversion = def->root_module->fileformatversion[def->root_module->fileformatversion.size() - 1].version;
991  }
992  entry->hasSubmeshs = static_cast<int>(def->root_module->submeshes.size() > 0);
993  entry->nodecount = static_cast<int>(def->root_module->nodes.size());
994  entry->beamcount = static_cast<int>(def->root_module->beams.size());
995  entry->shockcount = static_cast<int>(def->root_module->shocks.size() + def->root_module->shocks2.size());
996  entry->fixescount = static_cast<int>(def->root_module->fixes.size());
997  entry->hydroscount = static_cast<int>(def->root_module->hydros.size());
998  entry->driveable = vehicle_type;
999  entry->commandscount = static_cast<int>(def->root_module->commands2.size());
1000  entry->flarescount = static_cast<int>(def->root_module->flares2.size());
1001  entry->propscount = static_cast<int>(def->root_module->props.size());
1002  entry->wingscount = static_cast<int>(def->root_module->wings.size());
1003  entry->turbopropscount = static_cast<int>(def->root_module->turboprops2.size());
1004  entry->rotatorscount = static_cast<int>(def->root_module->rotators.size() + def->root_module->rotators2.size());
1005  entry->exhaustscount = static_cast<int>(def->root_module->exhausts.size());
1006  entry->custom_particles = def->root_module->particles.size() > 0;
1007  entry->turbojetcount = static_cast<int>(def->root_module->turbojets.size());
1008  entry->flexbodiescount = static_cast<int>(def->root_module->flexbodies.size());
1009  entry->soundsourcescount = static_cast<int>(def->root_module->soundsources.size() + def->root_module->soundsources.size());
1010 
1011  entry->wheelcount = 0;
1012  entry->propwheelcount = 0;
1013  for (const auto& w : def->root_module->wheels)
1014  {
1015  entry->wheelcount++;
1016  if (w.propulsion != WheelPropulsion::NONE)
1017  entry->propwheelcount++;
1018  }
1019  for (const auto& w : def->root_module->wheels2)
1020  {
1021  entry->wheelcount++;
1022  if (w.propulsion != WheelPropulsion::NONE)
1023  entry->propwheelcount++;
1024  }
1025  for (const auto& w : def->root_module->meshwheels)
1026  {
1027  entry->wheelcount++;
1028  if (w.propulsion != WheelPropulsion::NONE)
1029  entry->propwheelcount++;
1030  }
1031  for (const auto& w : def->root_module->meshwheels2)
1032  {
1033  entry->wheelcount++;
1034  if (w.propulsion != WheelPropulsion::NONE)
1035  entry->propwheelcount++;
1036  }
1037  for (const auto& w : def->root_module->flexbodywheels)
1038  {
1039  entry->wheelcount++;
1040  if (w.propulsion != WheelPropulsion::NONE)
1041  entry->propwheelcount++;
1042  }
1043 
1044  if (!def->root_module->axles.empty())
1045  {
1046  entry->propwheelcount = static_cast<int>(def->root_module->axles.size() * 2);
1047  }
1048 
1049  /* NOTE: std::shared_ptr cleans everything up. */
1050 }
1051 
1052 Ogre::String detectMiniType(String filename, String group)
1053 {
1054  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "dds"))
1055  return "dds";
1056 
1057  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "png"))
1058  return "png";
1059 
1060  if (ResourceGroupManager::getSingleton().resourceExists(group, filename + "jpg"))
1061  return "jpg";
1062 
1063  return "";
1064 }
1065 
1067 {
1068  if (!entry->filecachename.empty())
1069  {
1071  }
1072 }
1073 
1075 {
1076  if (entry->fname.empty())
1077  return;
1078 
1079  String bundle_basename, bundle_path;
1080  StringUtil::splitFilename(entry->resource_bundle_path, bundle_basename, bundle_path);
1081 
1082  String src_path;
1083  String dst_path;
1084  if (entry->fext == "skin")
1085  {
1086  if (entry->skin_def->thumbnail.empty())
1087  return;
1088  src_path = entry->skin_def->thumbnail;
1089  String mini_fbase, minitype;
1090  StringUtil::splitBaseFilename(entry->skin_def->thumbnail, mini_fbase, minitype);
1091  dst_path = bundle_basename + "_" + mini_fbase + ".mini." + minitype;
1092  }
1093  else
1094  {
1095  String fbase, fext;
1096  StringUtil::splitBaseFilename(entry->fname, fbase, fext);
1097  String minifn = fbase + "-mini.";
1098  String minitype = detectMiniType(minifn, group);
1099  if (minitype.empty())
1100  return;
1101  src_path = minifn + minitype;
1102  dst_path = bundle_basename + "_" + entry->fname + ".mini." + minitype;
1103  }
1104 
1105  try
1106  {
1107  DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(src_path, group);
1108  DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(dst_path, RGN_CACHE, true);
1109  std::vector<char> buf(src_ds->size());
1110  size_t read = src_ds->read(buf.data(), src_ds->size());
1111  if (read > 0)
1112  {
1113  dst_ds->write(buf.data(), read);
1114  entry->filecachename = dst_path;
1115  }
1116  }
1117  catch (Ogre::Exception& e)
1118  {
1119  LOG("error while generating file cache: " + e.getFullDescription());
1120  }
1121 
1122  LOG("done generating file cache!");
1123 }
1124 
1126 {
1127  auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group, "*.zip");
1128  auto skinzips = ResourceGroupManager::getSingleton().findResourceFileInfo(group, "*.skinzip");
1129  for (const auto& skinzip : *skinzips)
1130  files->push_back(skinzip);
1131 
1132  int i = 0, count = static_cast<int>(files->size());
1133  for (const auto& file : *files)
1134  {
1135  int progress = ((float)i++ / (float)count) * 100;
1136  std::string text = fmt::format("{}{}\n{}\n{}/{}",
1137  _L("Loading zips in group "), group, file.filename, i, count);
1139 
1140  String path = PathCombine(file.archive->getName(), file.filename);
1141  this->ParseSingleZip(path);
1142  }
1143 
1146 }
1147 
1149 {
1150  if (std::find(m_resource_paths.begin(), m_resource_paths.end(), path) == m_resource_paths.end())
1151  {
1152  RoR::LogFormat("[RoR|ModCache] Adding archive '%s'", path.c_str());
1153  ResourceGroupManager::getSingleton().createResourceGroup(RGN_TEMP, false);
1154  try
1155  {
1156  ResourceGroupManager::getSingleton().addResourceLocation(path, "Zip", RGN_TEMP);
1158  {
1159  LOG("No usable content in: '" + path + "'");
1160  }
1161  }
1162  catch (Ogre::Exception& e)
1163  {
1164  LOG("Error while opening archive: '" + path + "': " + e.getFullDescription());
1165  }
1166  ResourceGroupManager::getSingleton().destroyResourceGroup(RGN_TEMP);
1167  m_resource_paths.insert(path);
1168  }
1169 }
1170 
1171 bool CacheSystem::ParseKnownFiles(Ogre::String group)
1172 {
1173  bool empty = true;
1174  for (auto ext : m_known_extensions)
1175  {
1176  auto files = ResourceGroupManager::getSingleton().findResourceFileInfo(group, "*." + ext);
1177  for (const auto& file : *files)
1178  {
1179  this->AddFile(group, file, ext);
1180  empty = false;
1181  }
1182  }
1183  return empty;
1184 }
1185 
1187 {
1188  std::string filenames = App::GetContentManager()->ListAllUserContent();
1189  m_filenames_hash_generated = HashData(filenames.c_str(), static_cast<int>(filenames.size()));
1190 }
1191 
1192 void CacheSystem::FillTerrainDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr ds, Ogre::String fname)
1193 {
1194  Terrn2Parser parser;
1195  Terrn2DocumentPtr def = parser.LoadTerrn2(ds);
1196  if (!def)
1197  {
1199  fmt::format("Mod cache entry not populated - could not load terrain {}", ds->getName()));
1200  return;
1201  }
1202 
1203  for (Terrn2Author& author : def->authors)
1204  {
1205  AuthorInfo a;
1206  a.id = -1;
1207  a.name = author.name;
1208  a.type = author.type;
1209  entry->authors.push_back(a);
1210  }
1211 
1212  entry->dname = def->name;
1213  entry->categoryid = def->category_id;
1214  entry->uniqueid = def->guid;
1215  entry->version = def->version;
1216 }
1217 
1218 void CacheSystem::FillSkinDetailInfo(CacheEntryPtr &entry, std::shared_ptr<SkinDocument>& skin_def)
1219 {
1220  if (!skin_def->author_name.empty())
1221  {
1222  AuthorInfo a;
1223  a.id = skin_def->author_id;
1224  a.name = skin_def->author_name;
1225  entry->authors.push_back(a);
1226  }
1227 
1228  entry->dname = skin_def->name;
1229  entry->guid = skin_def->guid;
1230  entry->description = skin_def->description;
1231  entry->categoryid = -1;
1232  entry->skin_def = skin_def; // Needed to generate preview image
1233 
1234  Ogre::StringUtil::toLowerCase(entry->guid);
1235 }
1236 
1237 void CacheSystem::FillAddonPartDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
1238 {
1239  GenericDocumentPtr doc = new GenericDocument();
1241  doc->loadFromDataStream(ds, options);
1242 
1243  GenericDocContextPtr ctx = new GenericDocContext(doc);
1244  while (!ctx->endOfFile())
1245  {
1246  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_name")
1247  {
1248  entry->dname = ctx->getTokString(1);
1249  }
1250  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_description")
1251  {
1252  entry->description = ctx->getTokString(1);
1253  }
1254  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_guid")
1255  {
1256  std::string guid = ctx->getTokString(1);
1257  Ogre::StringUtil::toLowerCase(guid);
1258  entry->addonpart_guids.insert(guid);
1259  }
1260  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "addonpart_filename")
1261  {
1262  std::string fname = ctx->getTokString(1);
1263  Ogre::StringUtil::toLowerCase(fname);
1264  entry->addonpart_filenames.insert(fname);
1265  }
1266 
1267  ctx->seekNextLine();
1268  }
1269 }
1270 
1271 void CacheSystem::FillAssetPackDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
1272 {
1273  GenericDocumentPtr doc = new GenericDocument();
1275  doc->loadFromDataStream(ds, options);
1276 
1277  GenericDocContextPtr ctx = new GenericDocContext(doc);
1278  while (!ctx->endOfFile())
1279  {
1280  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_name")
1281  {
1282  entry->dname = ctx->getTokString(1);
1283  }
1284  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_description")
1285  {
1286  entry->description = ctx->getTokString(1);
1287  }
1288  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "assetpack_author")
1289  {
1290  int n = ctx->countLineArgs();
1291  AuthorInfo author;
1292  if (n > 1) { author.type = ctx->getTokString(1); }
1293  if (n > 2) { author.id = (int)ctx->getTokFloat(2); }
1294  if (n > 3) { author.name = ctx->getTokString(3); }
1295  if (n > 4) { author.email = ctx->getTokString(4); }
1296  entry->authors.push_back(author);
1297  }
1298 
1299  ctx->seekNextLine();
1300  }
1301 }
1302 
1303 void CacheSystem::FillDashboardDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr ds)
1304 {
1305  GenericDocumentPtr doc = new GenericDocument();
1307  doc->loadFromDataStream(ds, options);
1308 
1309  GenericDocContextPtr ctx = new GenericDocContext(doc);
1310  while (!ctx->endOfFile())
1311  {
1312  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "dashboard_name" && ctx->isTokString(1))
1313  {
1314  entry->dname = ctx->getTokString(1);
1315  }
1316  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "dashboard_description" && ctx->isTokString(1))
1317  {
1318  entry->description = ctx->getTokString(1);
1319  }
1320  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "dashboard_category" && ctx->isTokInt(1))
1321  {
1322  entry->categoryid = ctx->getTokInt(1);
1323  }
1324  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "dashboard_author")
1325  {
1326  int n = ctx->countLineArgs();
1327  AuthorInfo author;
1328  if (n > 1) { author.type = ctx->getTokString(1); }
1329  if (n > 2) { author.id = ctx->getTokInt(2); }
1330  if (n > 3) { author.name = ctx->getTokString(3); }
1331  if (n > 4) { author.email = ctx->getTokString(4); }
1332  entry->authors.push_back(author);
1333  }
1334 
1335  ctx->seekNextLine();
1336  }
1337 
1338 }
1339 
1340 void CacheSystem::FillGadgetDetailInfo(CacheEntryPtr& entry, Ogre::DataStreamPtr ds)
1341 {
1342  GenericDocumentPtr doc = new GenericDocument();
1343  BitMask_t options
1346  doc->loadFromDataStream(ds, options);
1347 
1348  GenericDocContextPtr ctx = new GenericDocContext(doc);
1349  while (!ctx->endOfFile())
1350  {
1351  if (ctx->isTokKeyword() && ctx->getTokKeyword() == "gadget_name" && ctx->isTokString(1))
1352  {
1353  entry->dname = ctx->getTokString(1);
1354  }
1355  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "gadget_description" && ctx->isTokString(1))
1356  {
1357  if (entry->description == "")
1358  {
1359  entry->description = ctx->getTokString(1);
1360  }
1361  else
1362  {
1363  entry->description += "\n" + ctx->getTokString(1);
1364  }
1365  }
1366  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "gadget_category" && ctx->isTokInt(1))
1367  {
1368  entry->categoryid = ctx->getTokInt(1);
1369  }
1370  else if (ctx->isTokKeyword() && ctx->getTokKeyword() == "gadget_author")
1371  {
1372  int n = ctx->countLineArgs();
1373  AuthorInfo author;
1374  if (n > 1) { author.type = ctx->getTokString(1); }
1375  if (n > 2) { author.id = ctx->getTokInt(2); }
1376  if (n > 3) { author.name = ctx->getTokString(3); }
1377  if (n > 4) { author.email = ctx->getTokString(4); }
1378  entry->authors.push_back(author);
1379  }
1380 
1381  ctx->seekNextLine();
1382  }
1383 
1384 }
1385 
1387 {
1388  if (!tuneup_def->author_name.empty())
1389  {
1390  AuthorInfo a;
1391  a.id = tuneup_def->author_id;
1392  a.name = tuneup_def->author_name;
1393  entry->authors.push_back(a);
1394  }
1395 
1396  entry->dname = tuneup_def->name;
1397  entry->guid = tuneup_def->guid;
1398  entry->description = tuneup_def->description;
1399  entry->categoryid = tuneup_def->category_id;
1400  entry->tuneup_def = tuneup_def; // Needed to generate preview image
1401  entry->tuneup_associated_filename = tuneup_def->filename;
1402 
1403  Ogre::StringUtil::toLowerCase(entry->guid);
1404  Ogre::StringUtil::toLowerCase(entry->tuneup_associated_filename);
1405 }
1406 
1407 void CacheSystem::LoadAssetPack(CacheEntryPtr& target_entry, Ogre::String const & assetpack_filename)
1408 {
1409  // Load asset packs into the mod-bundle's resource group (quick & dirty approach).
1410  // See also `ContentManager::resourceCollision()` - we always keep the original file and dump the colliding one.
1411  // --------------------------------------------------------------------------------------------------------------
1412 
1413  ROR_ASSERT(!target_entry->deleted);
1414  ROR_ASSERT(target_entry->resource_group != "");
1415  ROR_ASSERT(assetpack_filename != "");
1416 
1417  CacheEntryPtr assetpack_entry = App::GetCacheSystem()->FindEntryByFilename(LT_AssetPack, /*partial=*/false, assetpack_filename);
1418  if (assetpack_entry)
1419  {
1420  try
1421  {
1422  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1423  assetpack_entry->resource_bundle_path, // name (source)
1424  assetpack_entry->resource_bundle_type, // type (source)
1425  target_entry->resource_group, // resGroup (target)
1426  false, // recursive
1427  assetpack_entry->resource_bundle_type != "FileSystem"); // readOnly
1428 
1429  // This is messy but there's no other way - OGRE resource groups cannot update incrementally.
1430  Ogre::ResourceGroupManager::getSingleton().clearResourceGroup(target_entry->resource_group);
1431  Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(target_entry->resource_group);
1432  }
1433  catch (std::exception const& e)
1434  {
1436  fmt::format(_L("Failed to load asset pack '{}' (requested by '{}'): {}"), assetpack_entry->fname, target_entry->fname, e.what()));
1437  }
1438  }
1439  else
1440  {
1442  fmt::format(_L("Asset pack '{}' (requested by '{}') not found"), assetpack_filename, target_entry->fname));
1443  }
1444 }
1445 
1446 static bool CheckAndReplacePathIgnoreCase(const CacheEntryPtr& entry, CVar* dir, const std::string& dir_label, std::string& out_rgname)
1447 {
1448  // Helper for `ComposeResourceGroupName()`
1449  // ---------------------------------------
1450 
1451  // Sanity check - assert on Debug, minimize damage on Release
1452  ROR_ASSERT(entry->resource_bundle_path != "");
1453  if (entry->resource_bundle_path == "")
1454  {
1455  LOG(fmt::format("[RoR|CacheSystem] CheckAndReplacePathIgnoreCase(): INTERNAL ERROR - entry '{}' has no bundle path!", entry->fname));
1456  return false;
1457  }
1458 
1459  // Lowercase everything
1460  std::string lower_bundlepath = entry->resource_bundle_path;
1461  Ogre::StringUtil::toLowerCase(lower_bundlepath);
1462 
1463  std::string lower_dir = dir->getStr();
1464  Ogre::StringUtil::toLowerCase(lower_dir);
1465 
1466  // Look for match and replace
1467  if (Ogre::StringUtil::startsWith(lower_bundlepath, lower_dir, /*lowercase:*/true))
1468  {
1469  // Sanity check; Should be guaranteed by the `startsWith()` check, but just to be sure...
1470  ROR_ASSERT(lower_bundlepath.size() > lower_dir.size());
1471  if (lower_bundlepath.size() > lower_dir.size())
1472  {
1473  std::string localpath = entry->resource_bundle_path.substr(lower_dir.length());
1474  out_rgname = fmt::format("{{bundle {}:{}}}", dir_label, localpath);
1475  return true;
1476  }
1477  }
1478  return false;
1479 }
1480 
1482 {
1483  // Compose group name as "{bundle <local path>}", where 'local path' means either:
1484  // - under `sys_user_dir` (by default 'Documenst\My Games\Rigs of Rods')
1485  // - under `app_extra_mod_path` (empty by default)
1486  // - under 'sys_process_dir' (autodetected)
1487  // -------------------------------------------------------------------------------
1488 
1489  std::string rg_name;
1490  if (CheckAndReplacePathIgnoreCase(entry, App::sys_user_dir, "USER", rg_name) ||
1491  CheckAndReplacePathIgnoreCase(entry, App::sys_process_dir, "BIN", rg_name) ||
1492  CheckAndReplacePathIgnoreCase(entry, App::app_extra_mod_path, "EXTRA", rg_name))
1493  {
1494  return rg_name;
1495  }
1496  else
1497  {
1498  return fmt::format("{{bundle FULL:{}}}", entry->resource_bundle_path);
1499  }
1500 }
1501 
1503 {
1504  // Because we use one resource group per bundle and multiple entries can share the same bundle,
1505  // we need to load the supplementary documents even if the bundle is already loaded.
1506  // -------------------------------------------------------------------------------------------
1507 
1508  if (!entry)
1509  return;
1510 
1511  ROR_ASSERT(entry->resource_group != "");
1512 
1513  if (entry->fext == "skin")
1514  {
1515  this->LoadAssociatedSkinDef(entry);
1516  }
1517  else if (entry->fext == "tuneup")
1518  {
1519  this->LoadAssociatedTuneupDef(entry);
1520  }
1521 }
1522 
1523 bool CacheSystem::IsPathContentDirRoot(const std::string& path) const
1524 {
1525  // Helper for `LoadResource()` because OGRE's 'readOnly' flag, see explanation in `ContentManager::InitModCache()`
1526  // --------------------------------------------------------------------------------------------------------------
1527 
1528  for (const std::string& cdir: m_content_dirs)
1529  {
1530  if (path == PathCombine(App::sys_user_dir->getStr(), cdir))
1531  {
1532  return true;
1533  }
1534  }
1535  return false;
1536 }
1537 
1539 {
1540  if (!entry)
1541  return;
1542 
1543  // Check if already loaded for this entry->
1544  if (entry->resource_group != "")
1545  {
1546  this->LoadSupplementaryDocuments(entry);
1547  return;
1548  }
1549 
1550  Ogre::String group = CacheSystem::ComposeResourceGroupName(entry);
1551 
1552  // Make "FileSystem" (directory) bundles writable (Default is read-only), except if it's a root directory.
1553  // See explanation of `readOnly` OGRE flag in `ContentManager::InitModCache()`.
1554  bool readonly = entry->resource_bundle_type == "Zip" || this->IsPathContentDirRoot(entry->resource_bundle_path);
1555  bool recursive = false;
1556 
1557  // Load now.
1558  try
1559  {
1560  if (entry->fext == "terrn2")
1561  {
1562  // PagedGeometry is hardcoded to use `Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME`
1563  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/true);
1564  ResourceGroupManager::getSingleton().addResourceLocation(
1565  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1566  }
1567  else if (entry->fext == "skin")
1568  {
1569  // This is a SkinZip bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1570  // 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->
1571  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1572  ResourceGroupManager::getSingleton().addResourceLocation(
1573  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1575  }
1576  else if (entry->fext == "tuneup")
1577  {
1578  // This is a .tuneup bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1579  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1580  ResourceGroupManager::getSingleton().addResourceLocation(
1581  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1583  }
1584  else if (entry->fext == "gadget")
1585  {
1586  // This is a .gadget bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1587  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1588  ResourceGroupManager::getSingleton().addResourceLocation(
1589  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1591  // Allow using builtin include scripts
1593  }
1594  else
1595  {
1596  // A vehicle bundle - use `inGlobalPool=false` to prevent resource name conflicts.
1597  // See bottom 'note' at https://ogrecave.github.io/ogre/api/latest/_resource-_management.html#Resource-Groups
1598  ResourceGroupManager::getSingleton().createResourceGroup(group, /*inGlobalPool=*/false);
1599  ResourceGroupManager::getSingleton().addResourceLocation(
1600  entry->resource_bundle_path, entry->resource_bundle_type, group, recursive, readonly);
1601 
1606  }
1607 
1608  // Initialize resource group
1609  ResourceGroupManager::getSingleton().initialiseResourceGroup(group);
1610  entry->resource_group = group;
1611 
1612  this->LoadSupplementaryDocuments(entry);
1613 
1614  // Inform other entries sharing this bundle (i.e. '.skin' entries in vehicle bundles)
1615  for (CacheEntryPtr& i_entry: m_entries)
1616  {
1617  if (i_entry->resource_bundle_path == entry->resource_bundle_path)
1618  {
1619  i_entry->resource_group = group; // Mark as loaded
1620  }
1621  }
1622  }
1623  catch (Ogre::Exception& e)
1624  {
1625  RoR::LogFormat("[RoR] Error while loading '%s', message: %s",
1626  entry->resource_bundle_path.c_str(), e.getFullDescription().c_str());
1627  if (ResourceGroupManager::getSingleton().resourceGroupExists(group))
1628  {
1629  ResourceGroupManager::getSingleton().destroyResourceGroup(group);
1630  }
1631  }
1632 }
1633 
1635 {
1636  if (entry->resource_group == "")
1637  {
1638  return; // Not loaded - nothing to do
1639  }
1640 
1641  // IMPORTANT! No actors must use the bundle while reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED
1642 
1643  this->UnLoadResource(entry);
1644  this->LoadResource(entry); // Will create the same resource group again
1645 }
1646 
1648 {
1649  if (entry->resource_group == "")
1650  {
1651  return; // Not loaded - nothing to do
1652  }
1653 
1654  // IMPORTANT! No actors must use the bundle after reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED
1655 
1656  std::string resource_group = entry->resource_group; // Keep local copy, the CacheEntry will be blanked!
1657  for (CacheEntryPtr& i_entry: m_entries)
1658  {
1659  if (i_entry->resource_group == resource_group)
1660  {
1661  // Delete cached documents - force reload from disk
1662  i_entry->actor_def = nullptr;
1663  i_entry->tuneup_def = nullptr;
1664  i_entry->skin_def = nullptr;
1665  // Mark as unloaded
1666  i_entry->resource_group = "";
1667  }
1668  }
1669 
1670  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group);
1671 }
1672 
1673 CacheEntryPtr CacheSystem::FetchSkinByName(std::string const & skin_name)
1674 {
1675  for (CacheEntryPtr & entry: m_entries)
1676  {
1677  if (entry->dname == skin_name && entry->fext == "skin")
1678  {
1679  return entry;
1680  }
1681  }
1682  return nullptr;
1683 }
1684 
1686 {
1687  // A .skin file defines multiple skins, so we need to locate and update all associated cache entries.
1688  // --------------------------------------------------------------------------------------------------
1689 
1690  if (!cache_entry)
1691  return;
1692 
1693  ROR_ASSERT(cache_entry->resource_group != ""); // Must be already loaded
1694 
1695  if (cache_entry->skin_def != nullptr) // If already parsed, re-use
1696  {
1697  return;
1698  }
1699 
1700  try
1701  {
1702  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1703  .openResource(cache_entry->fname, cache_entry->resource_group);
1704 
1705  auto new_skins = RoR::SkinParser::ParseSkins(ds); // Load the '.skin' file
1706  for (auto def: new_skins)
1707  {
1708  for (CacheEntryPtr& entry: m_entries)
1709  {
1710  if (entry->resource_bundle_path == cache_entry->resource_bundle_path
1711  && entry->resource_bundle_type == cache_entry->resource_bundle_type
1712  && entry->fname == cache_entry->fname
1713  && entry->dname == def->name)
1714  {
1715  entry->skin_def = def;
1716  entry->resource_group = cache_entry->resource_group;
1717  }
1718  }
1719  }
1720 
1721  if (cache_entry->skin_def == nullptr)
1722  {
1723  RoR::LogFormat("Definition of skin '%s' was not found in file '%s'",
1724  cache_entry->dname.c_str(), cache_entry->fname.c_str());
1725  }
1726  }
1727  catch (Ogre::Exception& oex)
1728  {
1729  RoR::LogFormat("[RoR] Error loading skin file '%s', message: %s",
1730  cache_entry->fname.c_str(), oex.getFullDescription().c_str());
1731  }
1732 }
1733 
1735 {
1736  // A .tuneup file defines multiple tuneups, so we need to locate and update all associated cache entries.
1737  // --------------------------------------------------------------------------------------------------
1738 
1739  if (!cache_entry)
1740  return;
1741 
1742  ROR_ASSERT(cache_entry->resource_group != ""); // Must be already loaded
1743 
1744  if (cache_entry->tuneup_def != nullptr) // If already parsed, re-use
1745  {
1746  return;
1747  }
1748 
1749  try
1750  {
1751  Ogre::DataStreamPtr ds = Ogre::ResourceGroupManager::getSingleton()
1752  .openResource(cache_entry->fname, cache_entry->resource_group);
1753 
1754  auto new_tuneups = RoR::TuneupUtil::ParseTuneups(ds); // Load the '.tuneup' file
1755  for (auto def: new_tuneups)
1756  {
1757  for (CacheEntryPtr& entry: m_entries)
1758  {
1759  if (entry->resource_bundle_path == cache_entry->resource_bundle_path
1760  && entry->resource_bundle_type == cache_entry->resource_bundle_type
1761  && entry->fname == cache_entry->fname
1762  && entry->dname == def->name)
1763  {
1764  entry->tuneup_def = def;
1765  entry->resource_group = cache_entry->resource_group;
1766  }
1767  }
1768  }
1769 
1770  if (cache_entry->tuneup_def == nullptr)
1771  {
1772  RoR::LogFormat("Definition of tuneup '%s' was not found in file '%s'",
1773  cache_entry->dname.c_str(), cache_entry->fname.c_str());
1774  }
1775  }
1776  catch (Ogre::Exception& oex)
1777  {
1778  RoR::LogFormat("[RoR] Error loading tuneup file '%s', message: %s",
1779  cache_entry->fname.c_str(), oex.getFullDescription().c_str());
1780  }
1781 }
1782 
1784 {
1785 
1786  // Validate the request
1787  if (!request->cpr_source_entry)
1788  {
1790  fmt::format(_LC("CacheSystem", "Cannot create project '{}' - no source mod specified!"), request->cpr_name));
1791  return nullptr;
1792  }
1793 
1794  // Make sure projects folder exists
1796 
1797  // Create subfolder
1798  std::string project_path = PathCombine(App::sys_projects_dir->getStr(), request->cpr_name);
1799  if (FolderExists(project_path) && !request->cpr_overwrite)
1800  {
1802  fmt::format(_LC("CacheSystem", "Project directory '{}' already exists!"), request->cpr_name));
1803  return nullptr;
1804  }
1805  CreateFolder(project_path);
1806  if (!FolderExists(project_path))
1807  {
1809  fmt::format(_LC("CacheSystem", "Project directory '{}' could not be created!"), request->cpr_name));
1810  return nullptr;
1811  }
1812 
1813  // Check if a project with the same name already exists
1814  CacheEntryPtr project_entry;
1815  bool project_entry_created = false;
1816  if (request->cpr_overwrite)
1817  {
1818  project_entry = this->FindEntryByFilename(LT_Tuneup, /*partial:*/false, fmt::format("{}.tuneup", request->cpr_name));
1819  this->LoadResource(project_entry); // This fills `entry.resource_group`
1820  }
1821 
1822  if (!project_entry)
1823  {
1824  // Create preliminary cache entry
1825  project_entry = new CacheEntry();
1826  project_entry_created = true;
1827 
1829  {
1830  project_entry->fext = "tuneup"; // Tell modcache what it is.
1831  project_entry->categoryid = CID_Tuneups; // For display in modcache
1832  project_entry->guid = request->cpr_source_entry->guid; // For lookup of tuneups by vehicle GUID.
1833  Ogre::StringUtil::toLowerCase(project_entry->guid);
1834  project_entry->tuneup_associated_filename = request->cpr_source_entry->fname; // For additional filtering of results (GUID marks a family, not individual mod).
1835  Ogre::StringUtil::toLowerCase(project_entry->tuneup_associated_filename);
1836  }
1837  else
1838  {
1839  project_entry->fext = request->cpr_source_entry->fext; // Tell modcache what it is.
1840  project_entry->categoryid = CID_Projects; // To list projects easily from cache
1841  }
1842  project_entry->categoryname = m_categories[project_entry->categoryid];
1843  project_entry->resource_bundle_type = "FileSystem"; // Tell modcache how to load it.
1844  project_entry->resource_bundle_path = project_path; // Tell modcache where to load it from.
1845  project_entry->fname = fmt::format("{}.{}", request->cpr_name, project_entry->fext); // Compose target mod filename
1846  project_entry->dname = request->cpr_name;
1847  project_entry->description = request->cpr_description;
1848  project_entry->number = static_cast<int>(m_entries.size() + 1); // Let's number mods from 1
1849  this->LoadResource(project_entry); // This fills `entry.resource_group`
1850  }
1851 
1853  {
1854  // Tuneup projects don't contain any media, just the .tuneup file which lists addonparts to use.
1855 
1856  // Prepare the .tuneup document
1857  ROR_ASSERT(request->cpr_source_actor);
1859 
1860  TuneupDefPtr tuneup = request->cpr_source_actor->getWorkingTuneupDef()->clone();
1861  tuneup->guid = request->cpr_source_entry->guid; // For lookup of tuneups by vehicle GUID.
1862  tuneup->filename = request->cpr_source_entry->fname; // For additional filtering of results (GUID marks a family, not individual mod).
1863  tuneup->name = request->cpr_name;
1864  tuneup->description = request->cpr_description;
1865  tuneup->thumbnail = request->cpr_source_entry->filecachename;
1866  tuneup->category_id = (CacheCategoryId)project_entry->categoryid;
1867 
1868  // Write out the .tuneup file.
1869  Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().createResource(
1870  project_entry->fname, project_entry->resource_group, request->cpr_overwrite);
1871  TuneupUtil::ExportTuneup(datastream, tuneup);
1872 
1873  // Attach the document to the entry in memory
1874  project_entry->tuneup_def = tuneup;
1875 
1876  // In the likely case this was invoked from TopMenubarUI, update it.
1877  if (App::GetGuiManager()->TopMenubar.tuning_savebox_visible)
1878  {
1880  App::GetGuiManager()->TopMenubar.tuning_actor = nullptr; // Force refresh
1881  }
1882  }
1883  else
1884  {
1885 
1886  // Create temporary resource group with only the data we want.
1887  std::string temp_rg = "TempProjectSourceRG";
1888  // Apart from `Resources` and resource groups, OGRE also keeps `Archives` in `ArchiveManager`
1889  // These aren't unloaded on destroying resource groups, and keep a 'readOnly' flag (defaults to true).
1890  // Upon loading/creating new resource groups, OGRE complains if the submitted flag doesn't match.
1891  // Since we want to make subdirs (with upacked mods) writable, we must purge subdir-archives now.
1892  bool readonly = request->cpr_source_entry->resource_bundle_type == "Zip";
1893  bool recursive = false;
1894  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
1896  request->cpr_source_entry->resource_bundle_type, temp_rg, recursive, readonly);
1897  Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(temp_rg);
1898 
1899  // Copy the files, one by one
1900  Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(temp_rg, "*.*");
1901  for (size_t i = 0; i < filelist->size(); i++)
1902  {
1903  Ogre::FileInfo fileinfo = filelist->at(i);
1904 
1906  {
1907  std::string basename, ext;
1908  Ogre::StringUtil::splitBaseFilename(fileinfo.filename, basename, ext);
1909  // Skip all actor files - the one we care about will be added manually.
1910  if (ext == "truck" || ext == "car" || ext == "load" || ext == "fixed" || ext == "boat" || ext == "airplane" || ext == "train" || ext == "trailer")
1911  {
1912  continue;
1913  }
1914  }
1915 
1916  // Render a frame with a progress window on it.
1918  (i+1)/filelist->size(),
1919  fmt::format("Creating project from existing mod...\nCopying file {}/{} '{}'", i, filelist->size(), fileinfo.filename),
1920  /*render_frame:*/true);
1921 
1922  // Copy one file
1923  try
1924  {
1925  DataStreamPtr src_ds = ResourceGroupManager::getSingleton().openResource(fileinfo.filename, temp_rg);
1926  DataStreamPtr dst_ds = ResourceGroupManager::getSingleton().createResource(fileinfo.filename, project_entry->resource_group);
1927  std::vector<char> buf(src_ds->size());
1928  size_t read = src_ds->read(buf.data(), src_ds->size());
1929  if (read > 0)
1930  {
1931  dst_ds->write(buf.data(), read);
1932  }
1933  }
1934  catch (Ogre::Exception& oex)
1935  {
1937  fmt::format(_LC("CacheSystem", "Could not copy file '{}' to project '{}', message: {}."),
1938  fileinfo.filename, request->cpr_name, oex.getDescription()));
1939  }
1940  }
1941 
1943  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(temp_rg);
1944  }
1945 
1947  {
1948  // Load the project file to perform fixups (name & category)
1949  GenericDocumentPtr doc = new GenericDocument();
1955  if (!doc->loadFromResource(request->cpr_source_entry->fname, request->cpr_source_entry->resource_group, flags))
1956  {
1958  fmt::format(_LC("CacheSystem", "Could not load project file '{}' to perform fixups."),
1959  project_entry->fname));
1960  return nullptr;
1961  }
1962 
1963  // fixup the document..
1964 
1965  GenericDocContextPtr ctx = new GenericDocContext(doc);
1966  // >> seek the name
1967  while (!ctx->isTokString())
1968  {
1969  ctx->seekNextLine();
1970  }
1971  // >> change the name
1972  if (!ctx->endOfFile())
1973  {
1974  ctx->setTokString(0, project_entry->dname);
1975  }
1976  // >> seek fileinfo
1977  while (!ctx->endOfFile() && (!ctx->isTokKeyword() || ctx->getTokKeyword() != "fileinfo"))
1978  {
1979  ctx->seekNextLine();
1980  }
1981  // change the fileinfo param #2 categoryid (if found)
1982  if (!ctx->endOfFile() && ctx->isTokKeyword() && ctx->getTokKeyword() == "fileinfo" && !ctx->endOfFile(2))
1983  {
1984  ctx->setTokFloat(2, CID_Projects);
1985  }
1986 
1987  // Write the document
1988  if (!doc->saveToResource(project_entry->fname, project_entry->resource_group))
1989  {
1991  fmt::format(_LC("CacheSystem", "Could not save fixed-up project file '{}'."),
1992  project_entry->fname));
1993  return nullptr;
1994  }
1995  }
1996 
1997  if (project_entry_created)
1998  {
1999  // Add the new entry to database
2000  m_entries.push_back(project_entry);
2001  }
2002 
2003  // notify script
2004  modCacheActivityType activity_type = (project_entry_created) ? MODCACHEACTIVITY_ENTRY_ADDED : MODCACHEACTIVITY_ENTRY_MODIFIED;
2006  /*ints*/ activity_type, project_entry->number, 0, 0,
2007  /*strings*/ project_entry->fname, project_entry->fext);
2008 
2009  // Unload the preliminary resource group - force proper load of complete bundle.
2010  this->UnLoadResource(project_entry);
2011 
2012  return project_entry;
2013 }
2014 
2016 {
2017  ROR_ASSERT(request->mpr_target_actor);
2019 
2020 
2021  switch (request->mpr_type)
2022  {
2024  {
2026  if (request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.count(request->mpr_subject) != 0)
2027  {
2029  fmt::format(_LC("Tuning", "Addon part '{}' is already equipped."), request->mpr_subject));
2030  return; // Nothing to do!
2031  }
2032 
2033  CacheEntryPtr subject_entry = this->FindEntryByFilename(LT_AddonPart, /*partial=*/false, request->mpr_subject);
2034  if (!subject_entry)
2035  {
2037  fmt::format(_LC("Tuning", "Addon part '{}' was not found in mod cache (probably not installed)."), request->mpr_subject));
2038  return; // Nothing to do!
2039  }
2040 
2042  {
2043  return; // Error message box already shown
2044  }
2045  else
2046  {
2047  request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.insert(request->mpr_subject);
2048  }
2049 
2050  break;
2051  }
2052 
2055  request->mpr_target_actor->getWorkingTuneupDef()->use_addonparts.erase(request->mpr_subject);
2056  break;
2057 
2061  break;
2062 
2066  break;
2067 
2071  break;
2072 
2076  break;
2077 
2081  break;
2082 
2086  break;
2087 
2091  break;
2092 
2096  break;
2097 
2101  break;
2102 
2106  break;
2107 
2111  break;
2112 
2116  break;
2117 
2121  break;
2122 
2126  break;
2127 
2131  break;
2132 
2136  break;
2137 
2141  break;
2142 
2146  break;
2147 
2151  break;
2152 
2156  break;
2157 
2161  break;
2162 
2166  break;
2167 
2171  break;
2172 
2176  break;
2177 
2181  break;
2182 
2186  break;
2187 
2189  {
2190  // Instead of loading with the saved tuneup directly, keep the autogenerated and sync it with the save.
2191  // That way, subsequent editing doesn't modify the save until user saves again.
2192  CacheEntryPtr save_entry = App::GetCacheSystem()->FindEntryByFilename(LT_Tuneup, /*partial:*/false, request->mpr_subject);
2193  if (!save_entry)
2194  {
2196  fmt::format(_LC("CacheSystem", "Error loading tuneup: file '{}', not found in mod cache"), request->mpr_subject));
2197  return;
2198  }
2199  this->LoadResource(save_entry);
2200  ROR_ASSERT(save_entry->tuneup_def);
2201  request->mpr_target_actor->getWorkingTuneupDef() = save_entry->tuneup_def->clone();
2203  break;
2204  }
2205 
2209  break;
2210 
2212  {
2213  const bool actor_ok(request->mpr_target_actor && request->mpr_target_actor->ar_state != ActorState::DISPOSED);
2214  if (!actor_ok)
2215  {
2217  fmt::format(_LC("CacheSystem", "Error updating truck file: actor not found or disposed")));
2218  return;
2219  }
2221  const bool entry_ok(entry && entry->resource_bundle_type == "FileSystem");
2222  if (!entry_ok)
2223  {
2225  fmt::format(_LC("CacheSystem", "Error updating truck file: cache entry missing or not a project")));
2226  return;
2227  }
2230  break;
2231  }
2232 
2233  default:
2234  break;
2235  }
2236 
2237  // Create spawn request while actor still exists
2238  // Note we don't use `ActorModifyRequest::Type::RELOAD` because we don't need the bundle reloaded.
2240  srq->asr_position = Ogre::Vector3(request->mpr_target_actor->getPosition().x, request->mpr_target_actor->getMinHeight(), request->mpr_target_actor->getPosition().z);
2241  srq->asr_rotation = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(request->mpr_target_actor->getRotation()), Ogre::Vector3::UNIT_Y);
2242  srq->asr_config = request->mpr_target_actor->getSectionConfig();
2246  srq->asr_debugview = (int)request->mpr_target_actor->GetGfxActor()->GetDebugView();
2248 
2249  // Remove the actor
2251 
2252  // Load our actor again, but only after it was deleted.
2254 }
2255 
2257 {
2258 
2259  this->UnLoadResource(entry);
2260 
2261  // Delete the files, one by one
2262  const std::string DELETEPROJ_TEMP_RG = "DeleteProjectTempRG";
2263  Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DELETEPROJ_TEMP_RG, /*inGlobalPool=*/false);
2264  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
2265  entry->resource_bundle_path, entry->resource_bundle_type, DELETEPROJ_TEMP_RG, /*recursive=*/false, /*readOnly=*/false);
2266  Ogre::FileInfoListPtr filelist = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(DELETEPROJ_TEMP_RG, "*.*");
2267  LOG(fmt::format("[RoR|ModCache] Deleting project '{}' (resource group '{}'), found {} files to erase.", entry->fname, entry->resource_group, filelist->size()));
2268  for (size_t i = 0; i < filelist->size(); i++)
2269  {
2270  Ogre::FileInfo fileinfo = filelist->at(i);
2271  if (!Ogre::FileSystemLayer::removeFile(PathCombine(entry->resource_bundle_path, fileinfo.filename)))
2272  {
2274  fmt::format(_LC("CacheSystem", "Problem deleting project '{}' - could not delete file '{}'"), entry->fname, fileinfo.filename));
2275  }
2276  }
2277 
2278  Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DELETEPROJ_TEMP_RG);
2279 
2280  // Delete the directory itself
2281  if (!Ogre::FileSystemLayer::removeDirectory(entry->resource_bundle_path))
2282  {
2284  fmt::format(_LC("CacheSystem", "Problem deleting project '{}' - could not delete directory '{}'"), entry->fname, entry->resource_bundle_path));
2285  }
2286 
2287  // Remove the entry
2288  RoR::EraseIf(m_entries, [entry](CacheEntryPtr& e) { return e == entry; });
2289 
2290  // Force update of Tuning menu in TopMenubarUI.
2292 }
2293 
2295 {
2296  Ogre::StringUtil::toLowerCase(query.cqy_search_string);
2297  Ogre::StringUtil::toLowerCase(query.cqy_filter_guid);
2298  Ogre::StringUtil::toLowerCase(query.cqy_filter_target_filename);
2299  std::time_t cur_time = std::time(nullptr);
2300  for (CacheEntryPtr& entry: m_entries)
2301  {
2302  // Filter by GUID
2303  if (query.cqy_filter_guid != "")
2304  {
2305  // Addon parts have `guid` empty
2306  if ((entry->fext == "addonpart" && entry->addonpart_guids.count(query.cqy_filter_guid) == 0) ||
2307  (entry->fext != "addonpart" && entry->guid != query.cqy_filter_guid))
2308  {
2309  continue;
2310  }
2311  }
2312 
2313  // Filter by target filename; pass items which have no target filenames listed.
2314  if (query.cqy_filter_target_filename != "")
2315  {
2316  if (entry->fext == "addonpart"
2317  && entry->addonpart_filenames.size() > 0
2318  && entry->addonpart_filenames.count(query.cqy_filter_target_filename) == 0)
2319  {
2320  continue;
2321  }
2322  else if (entry->fext == "tuneup"
2323  && entry->tuneup_associated_filename != ""
2324  && entry->tuneup_associated_filename != query.cqy_filter_target_filename)
2325  {
2326  continue;
2327  }
2328  }
2329 
2330  // Filter by entry type
2331  bool add = false;
2332  if (entry->fext == "terrn2")
2333  add = (query.cqy_filter_type == LT_Terrain);
2334  if (entry->fext == "skin")
2335  add = (query.cqy_filter_type == LT_Skin);
2336  else if (entry->fext == "addonpart")
2337  add = (query.cqy_filter_type == LT_AddonPart);
2338  else if (entry->fext == "tuneup")
2339  add = (query.cqy_filter_type == LT_Tuneup);
2340  else if (entry->fext == "assetpack")
2341  add = (query.cqy_filter_type == LT_AssetPack);
2342  else if (entry->fext == "dashboard")
2343  add = (query.cqy_filter_type == LT_DashBoard);
2344  else if (entry->fext == "gadget")
2345  add = (query.cqy_filter_type == LT_Gadget);
2346  else if (entry->fext == "truck")
2347  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Vehicle || query.cqy_filter_type == LT_Truck);
2348  else if (entry->fext == "car")
2349  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);
2350  else if (entry->fext == "boat")
2351  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Boat);
2352  else if (entry->fext == "airplane")
2353  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Airplane);
2354  else if (entry->fext == "trailer")
2355  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Trailer || query.cqy_filter_type == LT_Extension);
2356  else if (entry->fext == "train")
2357  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Train);
2358  else if (entry->fext == "load")
2359  add = (query.cqy_filter_type == LT_AllBeam || query.cqy_filter_type == LT_Load || query.cqy_filter_type == LT_Extension);
2360 
2361  if (!add)
2362  {
2363  continue;
2364  }
2365 
2366  // Category usage stats
2367  query.cqy_res_category_usage[entry->categoryid]++;
2368 
2370 
2371  const bool is_fresh = (cur_time - entry->addtimestamp) < CACHE_FILE_FRESHNESS;
2372  if (is_fresh)
2374 
2375  // Filter by category
2376  if ((query.cqy_filter_category_id <= CacheCategoryId::CID_Max && query.cqy_filter_category_id != entry->categoryid) ||
2377  (query.cqy_filter_category_id == CID_Fresh && !is_fresh))
2378  {
2379  continue;
2380  }
2381 
2382  // Search
2383  size_t score = 0;
2384  bool match = false;
2385  Str<100> wheels_str;
2386  switch (query.cqy_search_method)
2387  {
2389  if (match = this->Match(score, entry->dname, query.cqy_search_string, 0)) { break; }
2390  if (match = this->Match(score, entry->fname, query.cqy_search_string, 100)) { break; }
2391  if (match = this->Match(score, entry->description, query.cqy_search_string, 200)) { break; }
2392  for (AuthorInfo const& author: entry->authors)
2393  {
2394  if (match = this->Match(score, author.name, query.cqy_search_string, 300)) { break; }
2395  if (match = this->Match(score, author.email, query.cqy_search_string, 400)) { break; }
2396  }
2397  break;
2398 
2400  match = this->Match(score, entry->guid, query.cqy_search_string, 0);
2401  break;
2402 
2404  for (AuthorInfo const& author: entry->authors)
2405  {
2406  if (match = this->Match(score, author.name, query.cqy_search_string, 0)) { break; }
2407  if (match = this->Match(score, author.email, query.cqy_search_string, 0)) { break; }
2408  }
2409  break;
2410 
2412  wheels_str << entry->wheelcount << "x" << entry->propwheelcount;
2413  match = this->Match(score, wheels_str.ToCStr(), query.cqy_search_string, 0);
2414  break;
2415 
2417  match = this->Match(score, entry->fname, query.cqy_search_string, 100);
2418  break;
2419 
2420  default: // CacheSearchMethod::
2421  match = true;
2422  break;
2423  };
2424 
2425  if (match)
2426  {
2427  query.cqy_results.emplace_back(entry, score);
2428  query.cqy_res_last_update = std::max(query.cqy_res_last_update, entry->addtimestamp);
2429  }
2430  }
2431 
2432  std::sort(query.cqy_results.begin(), query.cqy_results.end());
2433  return query.cqy_results.size();
2434 }
2435 
2436 bool CacheSystem::Match(size_t& out_score, std::string data, std::string const& query, size_t score)
2437 {
2438  Ogre::StringUtil::toLowerCase(data);
2439  size_t pos = data.find(query);
2440  if (pos != std::string::npos)
2441  {
2442  out_score = score + pos;
2443  return true;
2444  }
2445  else
2446  {
2447  return false;
2448  }
2449 }
2450 
2452 {
2453  if (cqr_score == other.cqr_score)
2454  {
2455  Ogre::String first = this->cqr_entry->dname;
2456  Ogre::String second = other.cqr_entry->dname;
2457  Ogre::StringUtil::toLowerCase(first);
2458  Ogre::StringUtil::toLowerCase(second);
2459  return first < second;
2460  }
2461 
2462  return cqr_score < other.cqr_score;
2463 }
2464 
RoR::App::sys_user_dir
CVar * sys_user_dir
Definition: Application.cpp:163
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:673
RoR::CacheQueryResult::cqr_score
size_t cqr_score
Definition: CacheSystem.h:154
RoR::CacheSystem::m_known_extensions
std::vector< Ogre::String > m_known_extensions
the extensions we track in the cache system
Definition: CacheSystem.h:380
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:1407
RoR::App::GetContentManager
ContentManager * GetContentManager()
Definition: Application.cpp:271
RoR::CacheSystem::UnLoadResource
void UnLoadResource(CacheEntryPtr &t)
Unloads associated bundle, destroying all spawned actors.
Definition: CacheSystem.cpp:1647
RoR::WheelSide
WheelSide
Used by rig-def/addonpart/tuneup formats to specify wheel rim mesh orientation.
Definition: Application.h:531
RoR::CacheSystem::FillTerrainDetailInfo
void FillTerrainDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds, Ogre::String fname)
Definition: CacheSystem.cpp:1192
RoR::ModifyProjectRequest::mpr_subject
std::string mpr_subject
Definition: CacheSystem.h:260
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: Application.h:482
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:140
RGN_CACHE
#define RGN_CACHE
Definition: Application.h:46
RoR::TuneupUtil::ParseTuneups
static std::vector< TuneupDefPtr > ParseTuneups(Ogre::DataStreamPtr &stream)
Definition: TuneupFileFormat.cpp:599
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:261
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:211
RoR::GenericDocContext::isTokInt
bool isTokInt(int offset=0) const
Definition: GenericFileFormat.h:123
RoR::MACHINE
@ MACHINE
its a machine
Definition: SimData.h:88
RoR::Actor::ensureWorkingTuneupDef
void ensureWorkingTuneupDef()
Creates a working tuneup def if it doesn't exist yet.
Definition: Actor.cpp:4754
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:85
RoR::CacheSystem::DeleteProject
void DeleteProject(CacheEntryPtr &entry)
Definition: CacheSystem.cpp:2256
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::CacheSystem::FillDashboardDetailInfo
void FillDashboardDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
Definition: CacheSystem.cpp:1303
RoR::CacheQuery::cqy_filter_category_id
int cqy_filter_category_id
Definition: CacheSystem.h:170
RoR::CacheEntry::tuneup_def
TuneupDefPtr tuneup_def
Cached tuning info, added on first use or during cache rebuild.
Definition: CacheSystem.h:93
RoR::LT_AssetPack
@ LT_AssetPack
Definition: Application.h:461
RoR::CacheSystem::FillGadgetDetailInfo
void FillGadgetDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
Definition: CacheSystem.cpp:1340
RoR::LT_AddonPart
@ LT_AddonPart
Definition: Application.h:459
RoR::ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_RESET
@ TUNEUP_FORCED_VCAM_ROLE_RESET
'subject_id' is video camera ID.
RoR::Terrn2Parser
Definition: Terrn2FileFormat.h:81
RoR::GenericDocContext::isTokKeyword
bool isTokKeyword(int offset=0) const
Definition: GenericFileFormat.h:125
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:821
RoR::App::GetGuiManager
GUIManager * GetGuiManager()
Definition: Application.cpp:273
GUI_GameMainMenu.h
RoR::ContentManager::DeleteDiskFile
bool DeleteDiskFile(std::string const &filename, std::string const &rg_name)
Definition: ContentManager.cpp:522
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_PROP_RESET
@ TUNEUP_FORCEREMOVE_PROP_RESET
'subject_id' is prop ID.
RoR::Actor::propagateNodeBeamChangesToDef
void propagateNodeBeamChangesToDef()
Back-propagates changes done by N/B-utils UI to the def-document.
Definition: ActorExport.cpp:127
RoR::AuthorInfo::type
Ogre::String type
Definition: CacheSystem.h:50
RigDef::Engine::gear_ratios
std::vector< float > gear_ratios
Definition: RigDef_File.h:678
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:464
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:1066
RigDef::Parser::GetFile
RigDef::DocumentPtr GetFile()
Definition: RigDef_Parser.h:77
RoR::CacheQuery::cqy_search_method
CacheSearchMethod cqy_search_method
Definition: CacheSystem.h:173
RigDef::Parser::GetSequentialImporter
SequentialImporter * GetSequentialImporter()
Definition: RigDef_Parser.h:82
RoR::LT_Skin
@ LT_Skin
Definition: Application.h:457
RigDef::Parser::Finalize
void Finalize()
Definition: RigDef_Parser.cpp:3000
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:376
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:379
RoR::CacheSystem::LoadModCache
void LoadModCache(CacheValidity validity)
Definition: CacheSystem.cpp:153
RoR::GenericDocument::OPTION_ALLOW_SEPARATOR_COLON
static const BitMask_t OPTION_ALLOW_SEPARATOR_COLON
Allow ':' as separator between tokens.
Definition: GenericFileFormat.h:71
RoR::CacheSystem::AddFile
void AddFile(Ogre::String group, Ogre::FileInfo f, Ogre::String ext)
Definition: CacheSystem.cpp:744
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:460
RoR::CreateProjectRequest::cpr_type
CreateProjectRequestType cpr_type
Definition: CacheSystem.h:214
RoR::CacheSystem::m_entries
std::vector< CacheEntryPtr > m_entries
Definition: CacheSystem.h:379
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:89
RoR::GenericDocument::OPTION_ALLOW_SLASH_COMMENTS
static const BitMask_t OPTION_ALLOW_SLASH_COMMENTS
Allow comments starting with //.
Definition: GenericFileFormat.h:69
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::CacheQuery
Definition: CacheSystem.h:167
RoR::ModifyProjectRequestType::ACTOR_UPDATE_DEF_DOCUMENT
@ ACTOR_UPDATE_DEF_DOCUMENT
'subject' is empty; 'target_actor' is the actual subject. Propagates modifications from the live acto...
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:428
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:239
RoR::CacheSystem::GetEntryByNumber
CacheEntryPtr GetEntryByNumber(int modid)
Definition: CacheSystem.cpp:549
RoR::HashData
Ogre::String HashData(const char *key, int len)
Definition: Utils.cpp:54
RoR::TuneupUtil::ExportTuneup
static void ExportTuneup(Ogre::DataStreamPtr &stream, TuneupDefPtr &tuneup)
Definition: TuneupFileFormat.cpp:691
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: Application.h:478
RoR::GenericDocContext::getTokString
std::string getTokString(int offset=0) const
Definition: GenericFileFormat.h:113
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:103
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:1237
RoR::CacheEntry::hasSubmeshs
bool hasSubmeshs
Definition: CacheSystem.h:109
RoR::LT_Load
@ LT_Load
Definition: Application.h:455
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:452
RoR::CacheSystem::ModifyProject
void ModifyProject(ModifyProjectRequest *request)
Definition: CacheSystem.cpp:2015
RoR::GenericDocContext::seekNextLine
bool seekNextLine()
Definition: GenericFileFormat.cpp:1129
RoR::ActorSpawnRequest::asr_working_tuneup
TuneupDefPtr asr_working_tuneup
Only filled when editing tuneup via Tuning menu.
Definition: SimData.h:820
TuneupFileFormat.h
The vehicle tuning system; applies addonparts and user overrides to vehicles.
RoR::GenericDocument::loadFromResource
virtual bool loadFromResource(std::string resource_name, std::string resource_group_name, BitMask_t options=0)
Definition: GenericFileFormat.cpp:1097
detectMiniType
Ogre::String detectMiniType(String filename, String group)
Definition: CacheSystem.cpp:1052
RoR::GenericDocContext::setTokString
bool setTokString(int offset, const std::string &str)
Definition: GenericFileFormat.h:144
RoR::Actor::GetGfxActor
GfxActor * GetGfxActor()
Definition: Actor.h:281
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:672
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:114
RoR::CID_None
@ CID_None
Definition: Application.h:468
RoR::LT_Car
@ LT_Car
Definition: Application.h:450
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:583
Utils.h
RoR::NOT_DRIVEABLE
@ NOT_DRIVEABLE
not drivable at all
Definition: SimData.h:84
RoR::CacheSystem::StripSHA1fromString
static Ogre::String StripSHA1fromString(Ogre::String sha1str)
Definition: CacheSystem.cpp:736
RoR::CacheSystem::ImportEntryFromJson
void ImportEntryFromJson(rapidjson::Value &j_entry, CacheEntryPtr &out_entry)
Definition: CacheSystem.cpp:297
RoR::CacheEntry::enginetype
char enginetype
Definition: CacheSystem.h:141
Language.h
RoR::CacheEntry::minrpm
float minrpm
Definition: CacheSystem.h:130
RoR::Terrn2DocumentPtr
std::shared_ptr< Terrn2Document > Terrn2DocumentPtr
Definition: ForwardDeclarations.h:223
RoR::Terrn2Author
Definition: Terrn2FileFormat.h:37
RoR::CacheEntry::description
Ogre::String description
Definition: CacheSystem.h:105
RoR::LT_Extension
@ LT_Extension
Definition: Application.h:456
RoR::CacheQueryResult::cqr_entry
CacheEntryPtr cqr_entry
Definition: CacheSystem.h:153
RoR::App::app_extra_mod_path
CVar * app_extra_mod_path
Definition: Application.cpp:87
RefCountingObjectPtr< CacheEntry >
RoR::Console::CONSOLE_SYSTEM_ERROR
@ CONSOLE_SYSTEM_ERROR
Definition: Console.h:52
RoR::CacheSystem::PruneCache
void PruneCache()
Definition: CacheSystem.cpp:431
RigDef::Parser::ProcessOgreStream
void ProcessOgreStream(Ogre::DataStream *stream, Ogre::String resource_group)
Definition: RigDef_Parser.cpp:3572
GUIManager.h
RoR::CreateProjectRequest::cpr_source_entry
CacheEntryPtr cpr_source_entry
The original mod to copy files from.
Definition: CacheSystem.h:212
Actor.h
RoR::CreateProjectRequest::cpr_name
std::string cpr_name
Directory and also the mod file (without extension).
Definition: CacheSystem.h:210
RoR::Terrn2Author::name
std::string name
Definition: Terrn2FileFormat.h:40
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:1523
RoR::GenericDocument::saveToResource
virtual bool saveToResource(std::string resource_name, std::string resource_group_name)
Definition: GenericFileFormat.cpp:1113
RoR::GUIManager::LoadingWindow
GUI::LoadingWindow LoadingWindow
Definition: GUIManager.h:132
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:138
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:795
RoR::CacheEntry::beamcount
int beamcount
Definition: CacheSystem.h:111
RoR::getTimeStamp
std::time_t getTimeStamp()
Definition: Utils.cpp:77
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::CacheQueryResult::operator<
bool operator<(CacheQueryResult const &other) const
Definition: CacheSystem.cpp:2451
RoR::CacheSystem::LoadCacheFileJson
CacheValidity LoadCacheFileJson()
Definition: CacheSystem.cpp:399
RoR::GenericDocContext::isTokString
bool isTokString(int offset=0) const
Definition: GenericFileFormat.h:121
RoR::LT_Boat
@ LT_Boat
Definition: Application.h:451
RoR::CacheEntry::shockcount
int shockcount
Definition: CacheSystem.h:112
RigDef::Fileinfo
Definition: RigDef_File.h:734
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:736
RoR::LT_Truck
@ LT_Truck
Definition: Application.h:449
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:177
RoR::CacheSystem::LoadAssociatedSkinDef
void LoadAssociatedSkinDef(CacheEntryPtr &cache_entry)
Loads+parses the .skin file and updates all related CacheEntries.
Definition: CacheSystem.cpp:1685
RoR::ActorSpawnRequest::asr_config
Ogre::String asr_config
Definition: SimData.h:814
RoR::GenericDocContext::countLineArgs
int countLineArgs()
Definition: GenericFileFormat.cpp:1147
RoR::CreateProjectRequestType::ACTOR_PROJECT
@ ACTOR_PROJECT
Like DEFAULT but fixes up name + category in the truckfile.
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:848
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:73
RoR::Actor::getMinHeight
float getMinHeight(bool skip_virtual_nodes=true)
Definition: Actor.cpp:1557
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:4763
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:186
RoR::CacheSystem::ClearCache
void ClearCache()
Definition: CacheSystem.cpp:712
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:2436
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:1125
RoR::CacheEntry::propscount
int propscount
Definition: CacheSystem.h:119
RoR::CacheSystem::DetectDuplicates
void DetectDuplicates()
Definition: CacheSystem.cpp:477
RoR::TuneupDef::protected_wheels
std::set< WheelID_t > protected_wheels
Wheels that cannot be altered via 'addonpart_tweak_wheel'.
Definition: TuneupFileFormat.h:137
RoR::SkinParser::ParseSkins
static std::vector< SkinDocumentPtr > ParseSkins(Ogre::DataStreamPtr &stream)
Definition: SkinFileFormat.cpp:34
RoR::CacheValidity
CacheValidity
Definition: CacheSystem.h:188
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:1446
RoR::ActorSpawnRequest::asr_cache_entry
CacheEntryPtr asr_cache_entry
Optional, overrides 'asr_filename' and 'asr_cache_entry_num'.
Definition: SimData.h:812
RoR::ContentManager::ResourcePack::SCRIPTS
static const ResourcePack SCRIPTS
Definition: ContentManager.h:68
RoR::CacheQueryResult
Definition: CacheSystem.h:147
ScriptEngine.h
RigDef::Engine::torque
float torque
Definition: RigDef_File.h:674
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:66
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:243
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:738
RoR::CacheSystem::ParseSingleZip
void ParseSingleZip(Ogre::String path)
Definition: CacheSystem.cpp:1148
RoR::CacheSystem::FillTuneupDetailInfo
void FillTuneupDetailInfo(CacheEntryPtr &entry, TuneupDefPtr &tuneup_def)
Definition: CacheSystem.cpp:1386
RoR::CacheSystem::LoadAssociatedTuneupDef
void LoadAssociatedTuneupDef(CacheEntryPtr &cache_entry)
Loads+parses the .tuneup file and updates all related CacheEntries.
Definition: CacheSystem.cpp:1734
RoR::MODCACHEACTIVITY_ENTRY_ADDED
@ MODCACHEACTIVITY_ENTRY_ADDED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
Definition: ScriptEvents.h:93
RoR::CacheSystem::GetPrettyName
Ogre::String GetPrettyName(Ogre::String fname)
Definition: CacheSystem.cpp:559
RoR::GUI::LoadingWindow::SetVisible
void SetVisible(bool v)
Definition: GUI_LoadingWindow.h:41
RoR::CacheSystem::ParseKnownFiles
bool ParseKnownFiles(Ogre::String group)
Definition: CacheSystem.cpp:1171
RoR::CacheEntry::skin_def
SkinDocumentPtr skin_def
Cached skin info, added on first use or during cache rebuild.
Definition: CacheSystem.h:92
RoR::CacheEntry::actor_def
RigDef::DocumentPtr actor_def
Cached actor definition (aka truckfile) after first spawn.
Definition: CacheSystem.h:91
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:371
RoR::TuneupDef::protected_managedmats
std::set< std::string > protected_managedmats
Managed materials which cannot be altered via 'addonpart_tweak_managedmaterial' directive.
Definition: TuneupFileFormat.h:142
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::LT_Gadget
@ LT_Gadget
Definition: Application.h:463
RoR::CacheSearchMethod::WHEELS
@ WHEELS
Wheel configuration, i.e. 4x4.
RoR::LT_Vehicle
@ LT_Vehicle
Definition: Application.h:448
RoR::LT_Trailer
@ LT_Trailer
Definition: Application.h:453
RoR::CacheCategoryId
CacheCategoryId
Definition: Application.h:466
RoR::LoaderType
LoaderType
< Search mode for ModCache::Query() & Operation mode for GUI::MainSelector
Definition: Application.h:444
RoR::ModifyProjectRequestType::TUNEUP_FORCEREMOVE_EXHAUST_RESET
@ TUNEUP_FORCEREMOVE_EXHAUST_RESET
'subject_id' is exhaust ID.
RoR::CacheEntry::rescuer
bool rescuer
Definition: CacheSystem.h:137
RoR::ModifyProjectRequest::mpr_target_actor
ActorPtr mpr_target_actor
Definition: CacheSystem.h:256
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:274
RoR::CacheSystem::m_filenames_hash_loaded
std::string m_filenames_hash_loaded
hash from cachefile, for quick update detection
Definition: CacheSystem.h:377
RoR::LT_DashBoard
@ LT_DashBoard
Definition: Application.h:462
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:2869
RoR::CacheQuery::cqy_search_string
std::string cqy_search_string
Definition: CacheSystem.h:174
RoR::AddonPartUtility::DoubleCheckForAddonpartConflict
static bool DoubleCheckForAddonpartConflict(ActorPtr target_actor, CacheEntryPtr addonpart_entry)
Definition: AddonPartFileFormat.cpp:911
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:381
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:284
RoR::CacheSystem::m_categories
std::map< int, Ogre::String > m_categories
Definition: CacheSystem.h:383
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:378
RoR::AIRPLANE
@ AIRPLANE
its an airplane
Definition: SimData.h:86
RoR::CacheQuery::cqy_res_last_update
std::time_t cqy_res_last_update
Definition: CacheSystem.h:178
RoR::CacheSystem::GenerateFileCache
void GenerateFileCache(CacheEntryPtr &entry, Ogre::String group)
Definition: CacheSystem.cpp:1074
CACHE_FILE_FORMAT
#define CACHE_FILE_FORMAT
Definition: CacheSystem.h:42
RoR::GenericDocument::OPTION_FIRST_LINE_IS_TITLE
static const BitMask_t OPTION_FIRST_LINE_IS_TITLE
First non-empty & non-comment line is a naked string with spaces.
Definition: GenericFileFormat.h:70
RoR::CacheEntry::uniqueid
Ogre::String uniqueid
file's unique id
Definition: CacheSystem.h:76
RoR::CacheSystem::EvaluateCacheValidity
CacheValidity EvaluateCacheValidity()
Definition: CacheSystem.cpp:259
RoR::ActorSpawnRequest::asr_skin_entry
CacheEntryPtr asr_skin_entry
Definition: SimData.h:818
RoR::AuthorInfo
Definition: CacheSystem.h:47
RoR::ModifyProjectRequest::mpr_value_int
int mpr_value_int
Definition: CacheSystem.h:262
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:4739
_LC
#define _LC(ctx, str)
Definition: Language.h:38
RoR::GUIManager::TopMenubar
GUI::TopMenubar TopMenubar
Definition: GUIManager.h:133
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:1783
RoR::CacheSystem::LoadSupplementaryDocuments
void LoadSupplementaryDocuments(CacheEntryPtr &t)
Loads the associated .truck*, .skin and .tuneup files.
Definition: CacheSystem.cpp:1502
RoR::CacheSystem::FillSkinDetailInfo
void FillSkinDetailInfo(CacheEntryPtr &entry, std::shared_ptr< SkinDocument > &skin_def)
Definition: CacheSystem.cpp:1218
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::ActorManager::ExportActorDef
void ExportActorDef(RigDef::DocumentPtr def, std::string filename, std::string rg_name)
Definition: ActorManager.cpp:1328
RoR::ModifyProjectRequest
Definition: CacheSystem.h:254
RoR::CID_Fresh
@ CID_Fresh
Definition: Application.h:484
RoR::GenericDocContext::endOfFile
bool endOfFile(int offset=0) const
Definition: GenericFileFormat.h:110
RoR::CreateProjectRequest
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
Definition: CacheSystem.h:205
RoR::LT_Terrain
@ LT_Terrain
Definition: Application.h:447
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:131
RoR::CacheSystem::ActorTypeToName
std::string ActorTypeToName(ActorType driveable)
Definition: CacheSystem.cpp:569
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:1481
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:213
RoR::TuneupDef::author_id
int author_id
Definition: TuneupFileFormat.h:103
RoR::App::GetCacheSystem
CacheSystem * GetCacheSystem()
Definition: Application.cpp:276
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:99
RoR::CacheSystem::FetchSkinByName
CacheEntryPtr FetchSkinByName(std::string const &skin_name)
Definition: CacheSystem.cpp:1673
RoR::CacheValidity::NEEDS_REBUILD
@ NEEDS_REBUILD
RoR::CID_Tuneups
@ CID_Tuneups
For unsorted tuneup files.
Definition: Application.h:479
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::TuneupDef::force_video_cam_roles
std::map< VideoCameraID_t, VideoCamRole > force_video_cam_roles
UI overrides.
Definition: TuneupFileFormat.h:128
RoR::Actor::getRotation
float getRotation()
Definition: Actor.cpp:356
RoR::TuneupDef::protected_exhausts
std::set< ExhaustID_t > protected_exhausts
Exhausts which cannot be altered via 'addonpart_unwanted_exhaust' directive.
Definition: TuneupFileFormat.h:141
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:139
RoR::CacheQuery::cqy_filter_type
RoR::LoaderType cqy_filter_type
Definition: CacheSystem.h:169
SkinFileFormat.h
RoR::GetFileLastModifiedTime
std::time_t GetFileLastModifiedTime(std::string const &path)
Definition: PlatformUtils.cpp:238
RoR::VideoCamRole
VideoCamRole
Definition: Application.h:579
RoR::CacheSystem::LoadResource
void LoadResource(CacheEntryPtr &t)
Loads the associated resource bundle if not already done.
Definition: CacheSystem.cpp:1538
RoR::GenericDocument
Definition: GenericFileFormat.h:66
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:686
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: Application.h:481
RoR::TuneupDef::filename
std::string filename
target vehicle filename
Definition: TuneupFileFormat.h:99
_L
#define _L
Definition: ErrorUtils.cpp:35
RoR::Actor::getUsedSkinEntry
CacheEntryPtr & getUsedSkinEntry()
Definition: Actor.cpp:4744
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:670
RoR::CreateProjectRequest::cpr_overwrite
bool cpr_overwrite
Definition: CacheSystem.h:215
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:822
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:121
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:1634
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:75
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:225
RoR::MSG_SIM_DELETE_ACTOR_REQUESTED
@ MSG_SIM_DELETE_ACTOR_REQUESTED
Payload = RoR::ActorPtr* (owner)
Definition: Application.h:123
RoR::LT_AllBeam
@ LT_AllBeam
Definition: Application.h:458
RoR::CacheEntry::truckmass
float truckmass
Definition: CacheSystem.h:128
RoR::TuneupDef::category_id
CacheCategoryId category_id
Definition: TuneupFileFormat.h:104
RoR::GenericDocContext::getTokKeyword
std::string getTokKeyword(int offset=0) const
Definition: GenericFileFormat.h:118
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:89
RoR::CacheQuery::cqy_filter_guid
std::string cqy_filter_guid
Exact match (case-insensitive); leave empty to disable.
Definition: CacheSystem.h:171
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:129
RoR::ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_SET
@ TUNEUP_FORCED_VCAM_ROLE_SET
'subject_id' is video camera ID, 'value_int' is RoR::VideoCamRole
RoR::WheelPropulsion::NONE
@ NONE
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:1007
RoR::GfxActor::GetDebugView
DebugViewType GetDebugView() const
Definition: GfxActor.h:145
RigDef::DocumentPtr
std::shared_ptr< Document > DocumentPtr
Definition: ForwardDeclarations.h:278
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:39
RoR::CacheEntry::hydroscount
int hydroscount
Definition: CacheSystem.h:114
RoR::Console::CONSOLE_MSGTYPE_INFO
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition: Console.h:60
RoR::ActorSpawnRequest::asr_position
Ogre::Vector3 asr_position
Definition: SimData.h:815
RoR::ModifyProjectRequest::mpr_type
ModifyProjectRequestType mpr_type
Definition: CacheSystem.h:257
RoR::GenericDocContext::setTokFloat
bool setTokFloat(int offset, float val)
Definition: GenericFileFormat.h:145
RoR::TuneupDef::guid
std::string guid
target vehicle GUID
Definition: TuneupFileFormat.h:98
RoR::ActorType
ActorType
< Aka 'Driveable'
Definition: SimData.h:80
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:87
RoR::CacheSystem::FillAssetPackDetailInfo
void FillAssetPackDetailInfo(CacheEntryPtr &entry, Ogre::DataStreamPtr ds)
Definition: CacheSystem.cpp:1271
RoR::GUI::GameMainMenu::CacheUpdatedNotice
void CacheUpdatedNotice()
Definition: GUI_GameMainMenu.cpp:56
RoR::Actor::ar_state
ActorState ar_state
Definition: Actor.h:488
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:434
GenericFileFormat.h
Generic text file parser.
RoR::AI
@ AI
machine controlled by an Artificial Intelligence
Definition: SimData.h:89
RoR::GenericDocument::OPTION_ALLOW_NAKED_STRINGS
static const BitMask_t OPTION_ALLOW_NAKED_STRINGS
Allow strings without quotes, for backwards compatibility.
Definition: GenericFileFormat.h:68
RoR::CID_All
@ CID_All
Definition: Application.h:483
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:172
RoR::CacheEntry::commandscount
int commandscount
Definition: CacheSystem.h:117
RoR::ActorSpawnRequest::asr_rotation
Ogre::Quaternion asr_rotation
Definition: SimData.h:816
RoR::Actor::getWorkingTuneupDef
TuneupDefPtr & getWorkingTuneupDef()
Definition: Actor.cpp:4749
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:94
RoR::CacheSystem::Query
size_t Query(CacheQuery &query)
Definition: CacheSystem.cpp:2294
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:130
RoR::Log
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
Definition: Application.cpp:423
RoR::GameContext::GetActorManager
ActorManager * GetActorManager()
Definition: GameContext.h:127
RoR::GUIManager::GameMainMenu
GUI::GameMainMenu GameMainMenu
Definition: GUIManager.h:117
RoR::CacheQuery::cqy_results
std::vector< CacheQueryResult > cqy_results
Definition: CacheSystem.h:176
RoR::LT_Train
@ LT_Train
Definition: Application.h:454
RoR::CacheEntry::default_skin
std::string default_skin
Definition: CacheSystem.h:107
RoR::GenericDocument::OPTION_PARENTHESES_CAPTURE_SPACES
static const BitMask_t OPTION_PARENTHESES_CAPTURE_SPACES
If non-empty NAKED string encounters '(', following spaces will be captured until matching ')' is fou...
Definition: GenericFileFormat.h:72
RoR::CacheSystem::GenerateHashFromFilenames
void GenerateHashFromFilenames()
For quick detection of added/removed content.
Definition: CacheSystem.cpp:1186
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
RoR::Terrn2Parser::LoadTerrn2
Terrn2DocumentPtr LoadTerrn2(Ogre::DataStreamPtr &ds)
Definition: Terrn2FileFormat.cpp:38
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:382
RoR::CacheEntry::flarescount
int flarescount
Definition: CacheSystem.h:118
RoR::CacheSystem::m_loaded
bool m_loaded
Definition: CacheSystem.h:375
RoR::CacheSystem::StripUIDfromString
static Ogre::String StripUIDfromString(Ogre::String uidstr)
Definition: CacheSystem.cpp:728
RigDef::Fileinfo::category_id
int category_id
Definition: RigDef_File.h:737
RoR::CacheEntry::fname
Ogre::String fname
filename
Definition: CacheSystem.h:67
RoR::GenericDocContext::getTokInt
int getTokInt(int offset=0) const
Definition: GenericFileFormat.h:115
RoR::CacheEntry::fname_without_uid
Ogre::String fname_without_uid
filename
Definition: CacheSystem.h:68