From 28f2cf07276e6bc68d4e93e865ee63b5c83641b3 Mon Sep 17 00:00:00 2001 From: Petr Ohlidal Date: Sat, 13 Mar 2021 18:39:04 +0100 Subject: [PATCH] :video_game: Reloading vehicle now reloads resources, too. Reloading vehicle will now reload all it's resources (materials, textures, everything). Works both for zipped and unzipped mods. The compromise is that all spawned actors using the same resource bundle must be deleted. --- source/main/Application.h | 3 ++- source/main/GameContext.cpp | 31 +++++++++++---------------- source/main/main.cpp | 27 +++++++++++++++++++++++ source/main/resources/CacheSystem.cpp | 28 ++++++++++++++++++++++-- source/main/resources/CacheSystem.h | 1 + 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/source/main/Application.h b/source/main/Application.h index 61379346c9..28aeff713d 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -91,12 +91,13 @@ enum MsgType // GUI MSG_GUI_OPEN_MENU_REQUESTED, MSG_GUI_CLOSE_MENU_REQUESTED, - MSG_GUI_OPEN_SELECTOR_REQUESTED, //!< Payload = LoaderType* (owner), Description = GUID | empty + MSG_GUI_OPEN_SELECTOR_REQUESTED, //!< Payload = LoaderType* (owner), Description = GUID | empty MSG_GUI_CLOSE_SELECTOR_REQUESTED, // Editing MSG_EDI_MODIFY_GROUNDMODEL_REQUESTED, //!< Payload = ground_model_t* (weak) MSG_EDI_ENTER_TERRN_EDITOR_REQUESTED, MSG_EDI_LEAVE_TERRN_EDITOR_REQUESTED, + MSG_EDI_RELOAD_BUNDLE_REQUESTED, //!< Payload = RoR::CacheEntry* (weak) }; enum class AppState diff --git a/source/main/GameContext.cpp b/source/main/GameContext.cpp index 21d4b608e1..c8ef9c65b1 100644 --- a/source/main/GameContext.cpp +++ b/source/main/GameContext.cpp @@ -279,28 +279,21 @@ void GameContext::ModifyActor(ActorModifyRequest& rq) return; } - auto reload_pos = rq.amr_actor->getPosition(); - auto reload_dir = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(m_player_actor->getRotation()), Ogre::Vector3::UNIT_Y); - auto debug_view = rq.amr_actor->GetGfxActor()->GetDebugView(); - auto asr_config = rq.amr_actor->GetSectionConfig(); - auto used_skin = rq.amr_actor->GetUsedSkin(); - - reload_pos.y = m_player_actor->GetMinHeight(); - - m_prev_player_actor = nullptr; - this->DeleteActor(rq.amr_actor); - entry->actor_def = nullptr; - App::GetCacheSystem()->ReLoadResource(*entry); - + // Create spawn request while actor still exists ActorSpawnRequest* srq = new ActorSpawnRequest; - srq->asr_position = reload_pos; - srq->asr_rotation = reload_dir; - srq->asr_config = asr_config; - srq->asr_skin_entry = used_skin; + srq->asr_position = Ogre::Vector3(rq.amr_actor->getPosition().x, rq.amr_actor->GetMinHeight(), rq.amr_actor->getPosition().z); + srq->asr_rotation = Ogre::Quaternion(Ogre::Degree(270) - Ogre::Radian(rq.amr_actor->getRotation()), Ogre::Vector3::UNIT_Y); + srq->asr_config = rq.amr_actor->GetSectionConfig(); + srq->asr_skin_entry = rq.amr_actor->GetUsedSkin(); srq->asr_cache_entry= entry; - srq->asr_debugview = (int)debug_view; + srq->asr_debugview = (int)rq.amr_actor->GetGfxActor()->GetDebugView(); srq->asr_origin = ActorSpawnRequest::Origin::USER; - this->PushMessage(Message(MSG_SIM_SPAWN_ACTOR_REQUESTED, (void*)srq)); + + // This deletes all actors using the resource bundle, including the one we're reloading. + this->PushMessage(Message(MSG_EDI_RELOAD_BUNDLE_REQUESTED, (void*)entry)); + + // Load our actor again, but only after all actors are deleted. + this->ChainMessage(Message(MSG_SIM_SPAWN_ACTOR_REQUESTED, (void*)srq)); } } diff --git a/source/main/main.cpp b/source/main/main.cpp index b637aed193..e9e779652c 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -676,6 +676,33 @@ int main(int argc, char *argv[]) } break; + case MSG_EDI_RELOAD_BUNDLE_REQUESTED: + { + // To reload the bundle, it's resource group must be destroyed and re-created. All actors using it must be deleted. + CacheEntry* entry = reinterpret_cast(m.payload); + bool all_clear = true; + for (Actor* actor: App::GetGameContext()->GetActorManager()->GetActors()) + { + if (actor->GetGfxActor()->GetResourceGroup() == entry->resource_group) + { + App::GetGameContext()->PushMessage(Message(MSG_SIM_DELETE_ACTOR_REQUESTED, actor)); + all_clear = false; + } + } + + if (all_clear) + { + // Nobody uses the RG anymore -> destroy and re-create it. + App::GetCacheSystem()->ReLoadResource(*entry); + } + else + { + // Re-post the same message again so that it's message chain is executed later. + App::GetGameContext()->PushMessage(m); + failed_m = true; + } + } + default:; } diff --git a/source/main/resources/CacheSystem.cpp b/source/main/resources/CacheSystem.cpp index 228a666f89..9e7a7d509f 100644 --- a/source/main/resources/CacheSystem.cpp +++ b/source/main/resources/CacheSystem.cpp @@ -1116,8 +1116,32 @@ void CacheSystem::ReLoadResource(CacheEntry& t) return; // Not loaded - nothing to do } - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(t.resource_group); - t.resource_group = ""; + // IMPORTANT! No actors must use the bundle while reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED + + this->UnLoadResource(t); + this->LoadResource(t); // Will create the same resource group again +} + +void CacheSystem::UnLoadResource(CacheEntry& t) +{ + if (t.resource_group == "") + { + return; // Not loaded - nothing to do + } + + // IMPORTANT! No actors must use the bundle after reloading, use RoR::MsgType::MSG_EDI_RELOAD_BUNDLE_REQUESTED + + std::string resource_group = t.resource_group; // Keep local copy, the CacheEntry will be blanked! + for (CacheEntry& i_entry: m_entries) + { + if (i_entry.resource_group == resource_group) + { + i_entry.actor_def = nullptr; // Delete cached truck file - force reload from disk + i_entry.resource_group = ""; // Mark as unloaded + } + } + + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(resource_group); this->LoadResource(t); // Will create the same resource group again } diff --git a/source/main/resources/CacheSystem.h b/source/main/resources/CacheSystem.h index 186d56283c..6ed3ed5c28 100644 --- a/source/main/resources/CacheSystem.h +++ b/source/main/resources/CacheSystem.h @@ -203,6 +203,7 @@ class CacheSystem : public ZeroedMemoryAllocator bool CheckResourceLoaded(Ogre::String &in_out_filename); //!< Finds + loads the associated resource bundle if not already done. bool CheckResourceLoaded(Ogre::String &in_out_filename, Ogre::String &out_group); //!< Finds given resource, outputs group name. Also loads the associated resource bundle if not already done. void ReLoadResource(CacheEntry& t); //!< Forces reloading the associated bundle. + void UnLoadResource(CacheEntry& t); //!< Unloads associated bundle, destroying all spawned actors. const std::vector &GetEntries() const { return m_entries; } const CategoryIdNameMap &GetCategories() const { return m_categories; }