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 bc2e9caaa5..c8ef9c65b1 100644 --- a/source/main/GameContext.cpp +++ b/source/main/GameContext.cpp @@ -279,27 +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); - 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/gui/panels/GUI_MainSelector.cpp b/source/main/gui/panels/GUI_MainSelector.cpp index 71fe674631..6df9428c94 100644 --- a/source/main/gui/panels/GUI_MainSelector.cpp +++ b/source/main/gui/panels/GUI_MainSelector.cpp @@ -633,12 +633,8 @@ MainSelector::DisplayEntry::DisplayEntry(CacheEntry* entry): { sde_addtime_str = asctime(gmtime(&sde_entry->addtimestamp)); } - if (sde_entry->nodecount > 0) - { - static const char* str[] = - {_LC("MainSelector", "Non-Driveable"), _LC("MainSelector", "Truck"), _LC("MainSelector", "Airplane"), _LC("MainSelector", "Boat"), _LC("MainSelector", "Machine")}; - sde_driveable_str = str[sde_entry->driveable]; - } + + sde_driveable_str = App::GetCacheSystem()->ActorTypeToName(sde_entry->driveable); } MainSelector::DisplayCategory::DisplayCategory(int id, std::string const& name, size_t usage) diff --git a/source/main/main.cpp b/source/main/main.cpp index cfc625ebec..6c7f830ef2 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -672,6 +672,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/physics/SimData.h b/source/main/physics/SimData.h index 24032706d7..d7b8b0d756 100644 --- a/source/main/physics/SimData.h +++ b/source/main/physics/SimData.h @@ -74,12 +74,14 @@ enum HookState enum ActorType //!< Aka 'Driveable' { - NOT_DRIVEABLE, //!< not drivable at all - TRUCK, //!< its a truck (or other land vehicle) - AIRPLANE, //!< its an airplane - BOAT, //!< its a boat - MACHINE, //!< its a machine - AI, //!< machine controlled by an Artificial Intelligence + // DO NOT MODIFY NUMBERS - serialized into cache file, see RoR::CacheEntry + + NOT_DRIVEABLE = 0, //!< not drivable at all + TRUCK = 1, //!< its a truck (or other land vehicle) + AIRPLANE = 2, //!< its an airplane + BOAT = 3, //!< its a boat + MACHINE = 4, //!< its a machine + AI = 5, //!< machine controlled by an Artificial Intelligence }; enum SpecialBeam: short diff --git a/source/main/resources/CacheSystem.cpp b/source/main/resources/CacheSystem.cpp index fc66cbc76c..9e7a7d509f 100644 --- a/source/main/resources/CacheSystem.cpp +++ b/source/main/resources/CacheSystem.cpp @@ -428,6 +428,20 @@ String CacheSystem::GetPrettyName(String fname) return ""; } +std::string CacheSystem::ActorTypeToName(ActorType driveable) +{ + switch (driveable) + { + case ActorType::NOT_DRIVEABLE: return _LC("MainSelector", "Non-Driveable"); + case ActorType::TRUCK: return _LC("MainSelector", "Truck"); + case ActorType::AIRPLANE: return _LC("MainSelector", "Airplane"); + case ActorType::BOAT: return _LC("MainSelector", "Boat"); + case ActorType::MACHINE: return _LC("MainSelector", "Machine"); + case ActorType::AI: return _LC("MainSelector", "A.I."); + default: return ""; + }; +} + void CacheSystem::ExportEntryToJson(rapidjson::Value& j_entries, rapidjson::Document& j_doc, CacheEntry const & entry) { rapidjson::Value j_entry(rapidjson::kObjectType); @@ -1102,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 d0d1808ca5..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; } @@ -211,6 +212,7 @@ class CacheSystem : public ZeroedMemoryAllocator CacheEntry *GetEntry(int modid); Ogre::String GetPrettyName(Ogre::String fname); + std::string ActorTypeToName(ActorType driveable); private: