Skip to content

Commit

Permalink
Tuneup: added savegame support, dropped autoloading.
Browse files Browse the repository at this point in the history
This required an internal overhaul as the 'working tuneup' is no longer a CacheEntry (common to all instances of the given mod), but an individual TuneupDef instance (specific to each spawned actor).

SIGNIFFICANT CODE CHANGES:
* Actor.h - Replaced `CacheEntryPtr     m_used_tuneup_entry;` with `TuneupDefPtr      m_working_tuneup_def;`
* TuneupFileFormat: added `isFooTweaked()` helpers (where Foo is Prop/Wheel etc...) used by all specific `getTweaked*()` helpers.
* Savegame.cpp - Added a "tuneup_document" field to actor entries, carrying the entire .tuneup file content.
* CacheSystem: only user-saved tuneups are now placed to modcache, the working tuneups are just in memory.
  • Loading branch information
ohlidalp committed Jan 22, 2024
1 parent 80973b8 commit cf9ff5b
Show file tree
Hide file tree
Showing 17 changed files with 581 additions and 448 deletions.
3 changes: 3 additions & 0 deletions source/main/ForwardDeclarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ namespace RoR
typedef int RefelemID_t; //!< index to `PointColDetector::m_ref_list`, use `RoR::REFELEMID_INVALID` as empty value.
static const RefelemID_t REFELEMID_INVALID = -1;

typedef int CacheEntryID_t; //!< index to `CacheSystem::m_cache_entries`, use `RoR::CACHEENTRYNUM_INVALID` as empty value.
static const CacheEntryID_t CACHEENTRYID_INVALID = -1;

typedef uint16_t NodeNum_t; //!< Node position within `Actor::ar_nodes`; use RoR::NODENUM_INVALID as empty value.
static const NodeNum_t NODENUM_INVALID = std::numeric_limits<NodeNum_t>::max();

Expand Down
44 changes: 9 additions & 35 deletions source/main/GameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,38 +189,9 @@ ActorPtr GameContext::SpawnActor(ActorSpawnRequest& rq)
{
m_last_cache_selection = rq.asr_cache_entry;
m_last_skin_selection = rq.asr_skin_entry;
m_last_tuneup_selection = rq.asr_tuneup_entry;
m_last_section_config = rq.asr_config;

// Make sure the actor has a default .tuneup project assigned. If not, create it.
if (App::sim_tuning_enabled->getBool())
{
CacheQuery query;
query.cqy_filter_type = LT_Tuneup;
query.cqy_filter_category_id = CID_TuneupsAuto;
query.cqy_filter_guid = rq.asr_cache_entry->guid;
if (App::GetCacheSystem()->Query(query) > 0)
{
rq.asr_tuneup_entry = query.cqy_results[0].cqr_entry;
}
else
{
CreateProjectRequest req;
req.cpr_type = CreateProjectRequestType::CREATE_TUNEUP;
req.cpr_source_entry = rq.asr_cache_entry;
req.cpr_name = fmt::format("tuned_{}", rq.asr_cache_entry->fname);
req.cpr_description = fmt::format("Customized {}", rq.asr_cache_entry->dname);

rq.asr_tuneup_entry = App::GetCacheSystem()->CreateProject(&req); // Do it synchronously

if (!rq.asr_tuneup_entry)
{
Str<500> msg; msg <<"Cannot spawn actor; .tuneup project could not be created.";
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_ACTOR, Console::CONSOLE_SYSTEM_ERROR, msg.ToCStr());
return nullptr;
}
}
}

if (rq.asr_spawnbox == nullptr)
{
if (m_player_actor != nullptr)
Expand Down Expand Up @@ -267,12 +238,15 @@ ActorPtr GameContext::SpawnActor(ActorSpawnRequest& rq)
}
}

if (rq.asr_tuneup_entry)
if (App::sim_tuning_enabled->getBool())
{
App::GetCacheSystem()->LoadResource(rq.asr_tuneup_entry); // Also loads associated .tuneup file.
if (!rq.asr_tuneup_entry->tuneup_def) // Make sure .tuneup was loaded OK.
if (rq.asr_tuneup_entry)
{
rq.asr_tuneup_entry = nullptr; // Error already logged
App::GetCacheSystem()->LoadResource(rq.asr_tuneup_entry); // Also loads associated .tuneup file.
if (!rq.asr_tuneup_entry->tuneup_def)
{
rq.asr_tuneup_entry = nullptr; // Error already logged
}
}
}

Expand Down Expand Up @@ -413,7 +387,7 @@ void GameContext::ModifyActor(ActorModifyRequest& rq)
srq->asr_rotation = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(actor->getRotation()), Ogre::Vector3::UNIT_Y);
srq->asr_config = actor->getSectionConfig();
srq->asr_skin_entry = actor->getUsedSkinEntry();
srq->asr_tuneup_entry = actor->getUsedTuneupEntry();
srq->asr_working_tuneup = actor->getWorkingTuneupDef();
srq->asr_cache_entry= entry;
srq->asr_debugview = (int)actor->GetGfxActor()->GetDebugView();
srq->asr_origin = ActorSpawnRequest::Origin::USER;
Expand Down
1 change: 1 addition & 0 deletions source/main/GameContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class GameContext

CacheEntryPtr m_last_cache_selection; //!< Vehicle/load
CacheEntryPtr m_last_skin_selection;
CacheEntryPtr m_last_tuneup_selection;
Ogre::String m_last_section_config;
ActorSpawnRequest m_current_selection; //!< Context of the loader UI
CacheEntryPtr m_dummy_cache_selection;
Expand Down
61 changes: 31 additions & 30 deletions source/main/gui/panels/GUI_TopMenubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1449,12 +1449,8 @@ void TopMenubar::Draw(float dt)
else
{
ROR_ASSERT(tuning_actor->getUsedActorEntry());
CacheEntryPtr& tuneup_entry = tuning_actor->getUsedTuneupEntry();
if (tuneup_entry)
{
ROR_ASSERT(tuneup_entry->resource_group != "");
ROR_ASSERT(tuneup_entry->tuneup_def != nullptr);
}
TuneupDefPtr& tuneup_def = tuning_actor->getWorkingTuneupDef();


// KILL SWITCH

Expand Down Expand Up @@ -1594,13 +1590,13 @@ void TopMenubar::Draw(float dt)

ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver);
std::string addonparts_title = fmt::format(_LC("TopMenubar", "Addon parts ({})"), tuning_addonparts.size());
if (ImGui::CollapsingHeader(addonparts_title.c_str()) && tuneup_entry)
if (ImGui::CollapsingHeader(addonparts_title.c_str()))
{
for (CacheEntryPtr& addonpart_entry: tuning_addonparts)
{
ImGui::PushID(addonpart_entry->fname.c_str());

bool used = tuneup_entry->tuneup_def->use_addonparts.count(addonpart_entry->fname) > 0;
bool used = TuneupUtil::isAddonPartUsed(tuneup_def, addonpart_entry->fname);
if (ImGui::Checkbox(addonpart_entry->dname.c_str(), &used))
{
ModifyProjectRequest* req = new ModifyProjectRequest();
Expand All @@ -1624,7 +1620,7 @@ void TopMenubar::Draw(float dt)
srq->asr_rotation = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(tuning_actor->getRotation()), Ogre::Vector3::UNIT_Y);
srq->asr_config = tuning_actor->getSectionConfig();
srq->asr_skin_entry = tuning_actor->getUsedSkinEntry();
srq->asr_tuneup_entry = tuneup_entry;
srq->asr_working_tuneup = tuning_actor->getWorkingTuneupDef();
srq->asr_cache_entry = tuning_actor->getUsedActorEntry();
srq->asr_debugview = (int)tuning_actor->GetGfxActor()->GetDebugView();
srq->asr_origin = ActorSpawnRequest::Origin::USER;
Expand All @@ -1649,7 +1645,7 @@ void TopMenubar::Draw(float dt)
// Draw props
size_t total_props = tuning_actor->GetGfxActor()->getProps().size();
std::string props_title = fmt::format(_LC("Tuning", "Props ({})"), total_props);
if (ImGui::CollapsingHeader(props_title.c_str()) && tuneup_entry)
if (ImGui::CollapsingHeader(props_title.c_str()))
{
// Draw all props (those removed by addonparts are also present as placeholders)
for (Prop const& p: tuning_actor->GetGfxActor()->getProps())
Expand All @@ -1662,8 +1658,8 @@ void TopMenubar::Draw(float dt)
this->DrawTuningForceRemoveControls(
p.pp_id,
p.pp_media[0],
tuneup_entry->tuneup_def->isPropUnwanted(p.pp_id),
tuneup_entry->tuneup_def->isPropForceRemoved(p.pp_id),
tuneup_def && tuneup_def->isPropUnwanted(p.pp_id),
tuneup_def && tuneup_def->isPropForceRemoved(p.pp_id),
ModifyProjectRequestType::TUNEUP_FORCEREMOVE_PROP_SET,
ModifyProjectRequestType::TUNEUP_FORCEREMOVE_PROP_RESET);

Expand Down Expand Up @@ -1694,7 +1690,7 @@ void TopMenubar::Draw(float dt)

this->DrawTuningProtectedChkRightAligned(
p.pp_id,
tuneup_entry->tuneup_def->isPropProtected(p.pp_id),
tuneup_def && tuneup_def->isPropProtected(p.pp_id),
ModifyProjectRequestType::TUNEUP_PROTECTED_PROP_SET,
ModifyProjectRequestType::TUNEUP_PROTECTED_PROP_RESET);

Expand All @@ -1707,7 +1703,7 @@ void TopMenubar::Draw(float dt)
// Ditto for flexbodies
size_t total_flexbodies = tuning_actor->GetGfxActor()->GetFlexbodies().size();
std::string flexbodies_title = fmt::format(_LC("Tuning", "Flexbodies ({})"), total_flexbodies);
if (ImGui::CollapsingHeader(flexbodies_title.c_str()) && tuneup_entry)
if (ImGui::CollapsingHeader(flexbodies_title.c_str()))
{
// Draw all flexbodies (those removed by addonparts are also present as placeholders)
for (FlexBody* flexbody: tuning_actor->GetGfxActor()->GetFlexbodies())
Expand All @@ -1720,14 +1716,14 @@ void TopMenubar::Draw(float dt)
this->DrawTuningForceRemoveControls(
flexbody->getID(),
flexbody->getOrigMeshName(),
tuneup_entry->tuneup_def->isFlexbodyUnwanted(flexbody->getID()),
tuneup_entry->tuneup_def->isFlexbodyForceRemoved(flexbody->getID()),
tuneup_def && tuneup_def->isFlexbodyUnwanted(flexbody->getID()),
tuneup_def && tuneup_def->isFlexbodyForceRemoved(flexbody->getID()),
ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLEXBODY_SET,
ModifyProjectRequestType::TUNEUP_FORCEREMOVE_FLEXBODY_RESET);

this->DrawTuningProtectedChkRightAligned(
flexbody->getID(),
tuneup_entry->tuneup_def->isFlexbodyProtected(flexbody->getID()),
tuneup_def && tuneup_def->isFlexbodyProtected(flexbody->getID()),
ModifyProjectRequestType::TUNEUP_PROTECTED_FLEXBODY_SET,
ModifyProjectRequestType::TUNEUP_PROTECTED_FLEXBODY_RESET);

Expand All @@ -1738,7 +1734,7 @@ void TopMenubar::Draw(float dt)
// Draw wheels
const int total_wheels = tuning_actor->ar_num_wheels;
std::string wheels_title = fmt::format(_LC("TopMenubar", "Wheels ({})"), total_wheels);
if (ImGui::CollapsingHeader(wheels_title.c_str()) && tuneup_entry)
if (ImGui::CollapsingHeader(wheels_title.c_str()))
{
for (WheelID_t i = 0; i < total_wheels; i++)
{
Expand All @@ -1748,12 +1744,13 @@ void TopMenubar::Draw(float dt)
this->DrawTuningBoxedSubjectIdInline(i);

// Draw R/L radio buttons
if (tuneup_entry->tuneup_def->isWheelSideForced(i))
WheelSide forced_side = WheelSide::INVALID;
if (tuneup_def && tuneup_def->isWheelSideForced(i, /*[out]*/forced_side))
{
ImGui::PushStyleColor(ImGuiCol_Border, ORANGE_TEXT);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f);
}
const RoR::WheelSide active_side = TuneupUtil::getTweakedWheelSide(tuneup_entry, i, tuning_actor->GetGfxActor()->getWheelSide(i));
const RoR::WheelSide active_side = TuneupUtil::getTweakedWheelSide(tuneup_def, i, tuning_actor->GetGfxActor()->getWheelSide(i));
RoR::WheelSide selected_side = active_side;
if (ImGui::RadioButton("##L", active_side == WheelSide::LEFT))
selected_side = WheelSide::LEFT;
Expand All @@ -1770,7 +1767,7 @@ void TopMenubar::Draw(float dt)
// Draw reset button

bool resetPressed = false;
if (tuneup_entry->tuneup_def->isWheelSideForced(i))
if (tuneup_def && tuneup_def->isWheelSideForced(i, forced_side))
{
ImGui::SameLine();
ImGui::SameLine();
Expand Down Expand Up @@ -1802,7 +1799,7 @@ void TopMenubar::Draw(float dt)

this->DrawTuningProtectedChkRightAligned(
i,
tuneup_entry->tuneup_def->isWheelProtected(i),
tuneup_def && tuneup_def->isWheelProtected(i),
ModifyProjectRequestType::TUNEUP_PROTECTED_WHEEL_SET,
ModifyProjectRequestType::TUNEUP_PROTECTED_WHEEL_RESET);

Expand Down Expand Up @@ -2268,10 +2265,11 @@ void TopMenubar::GetPresets()
void TopMenubar::RefreshTuningMenu()
{
const ActorPtr& current_actor = App::GetGameContext()->GetPlayerActor();
if (App::sim_tuning_enabled->getBool() && current_actor && (tuning_actor != current_actor || tuning_force_refresh))
if (App::sim_tuning_enabled->getBool()
&& current_actor
&& (tuning_actor != current_actor || tuning_force_refresh))
{
ROR_ASSERT(current_actor->getUsedActorEntry());
ROR_ASSERT(current_actor->getUsedTuneupEntry());

tuning_addonparts.clear();
tuning_saves.resetResults();
Expand All @@ -2290,21 +2288,24 @@ void TopMenubar::RefreshTuningMenu()
}

// Addonparts force-installed via [browse all] button; watch for duplicates.
for (std::string const& use_addonpart_fname: current_actor->getUsedTuneupEntry()->tuneup_def->use_addonparts)
if (current_actor->getWorkingTuneupDef())
{
CacheEntryPtr entry = App::GetCacheSystem()->FindEntryByFilename(LT_AddonPart, /*partial:*/false, use_addonpart_fname);
if (entry)
for (std::string const& use_addonpart_fname: current_actor->getWorkingTuneupDef()->use_addonparts)
{
if (std::find(tuning_addonparts.begin(), tuning_addonparts.end(), entry) == tuning_addonparts.end())
CacheEntryPtr entry = App::GetCacheSystem()->FindEntryByFilename(LT_AddonPart, /*partial:*/false, use_addonpart_fname);
if (entry)
{
tuning_addonparts.push_back(entry);
if (std::find(tuning_addonparts.begin(), tuning_addonparts.end(), entry) == tuning_addonparts.end())
{
tuning_addonparts.push_back(entry);
}
}
}
}

tuning_saves.cqy_filter_type = LT_Tuneup;
tuning_saves.cqy_filter_guid = current_actor->getUsedActorEntry()->guid;
tuning_saves.cqy_filter_category_id = CID_TuneupsUser; // Exclude auto-generated entries
tuning_saves.cqy_filter_category_id = CID_Tuneups; // Exclude auto-generated entries
tuning_saves.resetResults();
App::GetCacheSystem()->Query(tuning_saves);

Expand Down
17 changes: 13 additions & 4 deletions source/main/physics/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "SlideNode.h"
#include "SoundScriptManager.h"
#include "Terrain.h"
#include "TuneupFileFormat.h"
#include "TurboJet.h"
#include "TurboProp.h"
#include "Utils.h"
Expand Down Expand Up @@ -4329,7 +4330,7 @@ Actor::Actor(
, m_section_config(rq.asr_config)
, m_used_actor_entry(rq.asr_cache_entry)
, m_used_skin_entry(rq.asr_skin_entry)
, m_used_tuneup_entry(rq.asr_tuneup_entry)
, m_working_tuneup_def(rq.asr_working_tuneup)

// Public bit flags
, ar_update_physics(false)
Expand Down Expand Up @@ -4590,7 +4591,15 @@ CacheEntryPtr& Actor::getUsedSkinEntry()
return m_used_skin_entry;
}

CacheEntryPtr& Actor::getUsedTuneupEntry()
TuneupDefPtr& Actor::getWorkingTuneupDef()
{
return m_used_tuneup_entry;
}
return m_working_tuneup_def;
}

void Actor::ensureWorkingTuneupDef()
{
if (!m_working_tuneup_def)
{
m_working_tuneup_def = new TuneupDef();
}
}
7 changes: 4 additions & 3 deletions source/main/physics/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ class Actor : public RefCountingObject<Actor>
// not exported to scripting:
CacheEntryPtr& getUsedActorEntry(); //!< The actor entry itself.
CacheEntryPtr& getUsedSkinEntry();
CacheEntryPtr& getUsedTuneupEntry();
TuneupDefPtr& getWorkingTuneupDef();
void ensureWorkingTuneupDef();
bool isPreloadedWithTerrain() const { return m_preloaded_with_terrain; };
std::vector<authorinfo_t> getAuthors();
std::vector<std::string> getDescription();
Expand Down Expand Up @@ -296,7 +297,7 @@ class Actor : public RefCountingObject<Actor>
std::vector<Ogre::Vector3> ar_initial_node_positions;
std::vector<std::pair<float, float>> ar_initial_beam_defaults;
std::vector<wheeldetacher_t> ar_wheeldetachers;
ActorPtrVec ar_linked_actors; //!< Sim state; other actors linked using 'hooks'
ActorPtrVec ar_linked_actors; //!< Sim state; other actors linked using 'hooks'
std::vector<std::vector<int>> ar_node_to_node_connections;
std::vector<std::vector<int>> ar_node_to_beam_connections;
std::vector<Ogre::AxisAlignedBox> ar_collision_bounding_boxes; //!< smart bounding boxes, used for determining the state of an actor (every box surrounds only a subset of nodes)
Expand Down Expand Up @@ -569,7 +570,7 @@ ActorPtrVec ar_linked_actors; //!< Sim state
std::unique_ptr<Buoyance> m_buoyance; //!< Physics
CacheEntryPtr m_used_actor_entry;
CacheEntryPtr m_used_skin_entry; //!< Graphics
CacheEntryPtr m_used_tuneup_entry;
TuneupDefPtr m_working_tuneup_def; //!< Each actor gets unique instance, even if loaded from .tuneup file in modcache.
Skidmark* m_skid_trails[MAX_WHEELS*2] = {};
bool m_antilockbrake = false; //!< GUI state
bool m_tractioncontrol = false; //!< GUI state
Expand Down
3 changes: 2 additions & 1 deletion source/main/physics/ActorManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "SoundScriptManager.h"
#include "Terrain.h"
#include "ThreadPool.h"
#include "TuneupFileFormat.h"
#include "Utils.h"
#include "VehicleAI.h"

Expand Down Expand Up @@ -88,7 +89,7 @@ ActorPtr ActorManager::CreateNewActor(ActorSpawnRequest rq, RigDef::DocumentPtr

ActorSpawner spawner;
spawner.ConfigureSections(actor->m_section_config, def);
spawner.ConfigureAddonParts(actor->m_used_tuneup_entry);
spawner.ConfigureAddonParts(actor->m_working_tuneup_def);
spawner.ProcessNewActor(actor, rq, def);

if (App::diag_actor_dump->getBool())
Expand Down
Loading

0 comments on commit cf9ff5b

Please sign in to comment.