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