diff --git a/Runtime/CDvdFile.cpp b/Runtime/CDvdFile.cpp index c0a9a8282..b4e20fd51 100644 --- a/Runtime/CDvdFile.cpp +++ b/Runtime/CDvdFile.cpp @@ -5,6 +5,7 @@ namespace urde { hecl::ProjectPath CDvdFile::m_DvdRoot; +std::unordered_map CDvdFile::m_caseInsensitiveMap; class CFileDvdRequest : public IDvdRequest { std::shared_ptr m_reader; @@ -90,8 +91,34 @@ std::shared_ptr CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOr return ret; } +hecl::ProjectPath CDvdFile::ResolvePath(std::string_view path) { + auto start = path.begin(); + while (*start == '/') ++start; + std::string lowerChStr(start, path.end()); + std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower); + auto search = m_caseInsensitiveMap.find(lowerChStr); + if (search == m_caseInsensitiveMap.end()) + return {}; + return hecl::ProjectPath(m_DvdRoot, search->second); +} + +void CDvdFile::RecursiveBuildCaseInsensitiveMap(const hecl::ProjectPath& path, std::string::size_type prefixLen) { + for (const auto& p : path.enumerateDir()) { + if (p.m_isDir) { + RecursiveBuildCaseInsensitiveMap(hecl::ProjectPath(path, p.m_name), prefixLen); + } else { + hecl::ProjectPath ch(path, p.m_name); + std::string chStr(ch.getAbsolutePathUTF8().begin() + prefixLen, ch.getAbsolutePathUTF8().end()); + std::string lowerChStr(chStr); + std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower); + m_caseInsensitiveMap[lowerChStr] = chStr; + } + } +} + void CDvdFile::Initialize(const hecl::ProjectPath& path) { m_DvdRoot = path; + RecursiveBuildCaseInsensitiveMap(path, path.getAbsolutePathUTF8().length() + 1); if (m_WorkerRun.load()) return; m_WorkerRun.store(true); diff --git a/Runtime/CDvdFile.hpp b/Runtime/CDvdFile.hpp index accfbe68c..ad4a495f0 100644 --- a/Runtime/CDvdFile.hpp +++ b/Runtime/CDvdFile.hpp @@ -18,6 +18,7 @@ class CDvdFile { friend class CResLoader; friend class CFileDvdRequest; static hecl::ProjectPath m_DvdRoot; + static std::unordered_map m_caseInsensitiveMap; static std::thread m_WorkerThread; static std::mutex m_WorkerMutex; static std::condition_variable m_WorkerCV; @@ -29,16 +30,19 @@ class CDvdFile { std::string x18_path; std::shared_ptr m_reader; + static hecl::ProjectPath ResolvePath(std::string_view path); + static void RecursiveBuildCaseInsensitiveMap(const hecl::ProjectPath& path, std::string::size_type prefixLen); + public: static void Initialize(const hecl::ProjectPath& path); static void Shutdown(); CDvdFile(std::string_view path) : x18_path(path) - , m_reader(std::make_shared(hecl::ProjectPath(m_DvdRoot, path).getAbsolutePath())) {} + , m_reader(std::make_shared(ResolvePath(path).getAbsolutePath())) {} operator bool() const { return m_reader->isOpen(); } void UpdateFilePos(int pos) { m_reader->seek(pos, athena::SeekOrigin::Begin); } - static bool FileExists(std::string_view path) { return hecl::ProjectPath(m_DvdRoot, path).isFile(); } + static bool FileExists(std::string_view path) { return ResolvePath(path).isFile(); } void CloseFile() { m_reader->close(); } std::shared_ptr AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off, std::function&& cb = {}); diff --git a/Runtime/CResFactory.cpp b/Runtime/CResFactory.cpp index 76ce35a1c..e83a605c9 100644 --- a/Runtime/CResFactory.cpp +++ b/Runtime/CResFactory.cpp @@ -97,6 +97,19 @@ void CResFactory::CancelBuild(const SObjectTag& tag) { } } +void CResFactory::LoadPersistentResources(CSimplePool& sp) { + const auto& paks = x4_loader.GetPaks(); + for (auto it = paks.begin(); it != paks.end(); ++it) { + if (!(*it)->IsWorldPak()) { + for (const CAssetId& id : (*it)->GetDepList()) { + SObjectTag tag(GetResourceTypeById(id), id); + m_nonWorldTokens.push_back(sp.GetObj(tag)); + m_nonWorldTokens.back().Lock(); + } + } + } +} + void CResFactory::LoadOriginalIDs(CSimplePool& sp) { #if RUNTIME_ORIGINAL_IDS m_origIds = sp.GetObj("MP1OriginalIDs"); diff --git a/Runtime/CResFactory.hpp b/Runtime/CResFactory.hpp index 6da47676a..a0419ee71 100644 --- a/Runtime/CResFactory.hpp +++ b/Runtime/CResFactory.hpp @@ -38,6 +38,7 @@ public: private: std::list m_loadList; std::unordered_map::iterator> m_loadMap; + std::vector m_nonWorldTokens; /* URDE: always keep non-world resources resident */ void AddToLoadList(SLoadingData&& data); CFactoryFnReturn BuildSync(const SObjectTag&, const CVParamTransfer&, CObjectReference* selfRef); bool PumpResource(SLoadingData& data); @@ -87,6 +88,9 @@ public: return x4_loader.EnumerateNamedResources(lambda); } + void LoadPersistentResources(CSimplePool& sp); + void UnloadPersistentResources() { m_nonWorldTokens.clear(); } + void LoadOriginalIDs(CSimplePool& sp); CAssetId TranslateOriginalToNew(CAssetId id) const; CAssetId TranslateNewToOriginal(CAssetId id) const; diff --git a/Runtime/Character/CMetaAnimBlend.cpp b/Runtime/Character/CMetaAnimBlend.cpp index 149900e17..3577089a2 100644 --- a/Runtime/Character/CMetaAnimBlend.cpp +++ b/Runtime/Character/CMetaAnimBlend.cpp @@ -1,5 +1,6 @@ #include "CMetaAnimBlend.hpp" #include "CMetaAnimFactory.hpp" +#include "CAnimTreeBlend.hpp" namespace urde { @@ -17,8 +18,14 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set& primsOut) const { std::shared_ptr CMetaAnimBlend::VGetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const { - // CMetaAnimTreeBuildOrders buildOrders = CMetaAnimTreeBuildOrders::NoSpecialOrders(); - return {}; + CMetaAnimTreeBuildOrders oa = CMetaAnimTreeBuildOrders::NoSpecialOrders(); + CMetaAnimTreeBuildOrders ob = orders.x0_recursiveAdvance ? + CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.x0_recursiveAdvance) : + CMetaAnimTreeBuildOrders::NoSpecialOrders(); + auto a = x4_animA->GetAnimationTree(animSys, oa); + auto b = x8_animB->GetAnimationTree(animSys, ob); + return std::make_shared(x10_, a, b, xc_blend, + CAnimTreeBlend::CreatePrimitiveName(a, b, xc_blend)); } } // namespace urde diff --git a/Runtime/Character/CMetaAnimPhaseBlend.cpp b/Runtime/Character/CMetaAnimPhaseBlend.cpp index b74ec7ed9..d98942d45 100644 --- a/Runtime/Character/CMetaAnimPhaseBlend.cpp +++ b/Runtime/Character/CMetaAnimPhaseBlend.cpp @@ -1,5 +1,7 @@ #include "CMetaAnimPhaseBlend.hpp" #include "CMetaAnimFactory.hpp" +#include "CAnimTreeTimeScale.hpp" +#include "CAnimTreeBlend.hpp" namespace urde { @@ -17,7 +19,24 @@ void CMetaAnimPhaseBlend::GetUniquePrimitives(std::set& primsOut) co std::shared_ptr CMetaAnimPhaseBlend::VGetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const { - return {}; + if (orders.x0_recursiveAdvance) + return GetAnimationTree(animSys, CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.x0_recursiveAdvance)); + + auto a = x4_animA->GetAnimationTree(animSys, CMetaAnimTreeBuildOrders::NoSpecialOrders()); + auto b = x8_animB->GetAnimationTree(animSys, CMetaAnimTreeBuildOrders::NoSpecialOrders()); + auto da = a->GetContributionOfHighestInfluence().GetSteadyStateAnimInfo().GetDuration(); + auto db = b->GetContributionOfHighestInfluence().GetSteadyStateAnimInfo().GetDuration(); + auto dblend = da + (db - da) * xc_blend; + float fa = da / dblend; + float fb = db / dblend; + + auto tsa = std::make_shared(a, fa, + CAnimTreeTimeScale::CreatePrimitiveName(a, fa, CCharAnimTime::Infinity(), -1.f)); + auto tsb = std::make_shared(b, fb, + CAnimTreeTimeScale::CreatePrimitiveName(b, fb, CCharAnimTime::Infinity(), -1.f)); + + return std::make_shared(x10_, tsa, tsb, xc_blend, + CAnimTreeBlend::CreatePrimitiveName(tsa, tsb, xc_blend)); } } // namespace urde diff --git a/Runtime/Character/CMetaAnimPlay.cpp b/Runtime/Character/CMetaAnimPlay.cpp index 72a0c5d07..06125eb70 100644 --- a/Runtime/Character/CMetaAnimPlay.cpp +++ b/Runtime/Character/CMetaAnimPlay.cpp @@ -12,17 +12,13 @@ void CMetaAnimPlay::GetUniquePrimitives(std::set& primsOut) const { std::shared_ptr CMetaAnimPlay::VGetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const { - if (orders.x0_recursiveAdvance) { - CMetaAnimTreeBuildOrders modOrders; - modOrders.PreAdvanceForAll(*orders.x0_recursiveAdvance); - return GetAnimationTree(animSys, modOrders); - } + if (orders.x0_recursiveAdvance) + return GetAnimationTree(animSys, CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.x0_recursiveAdvance)); TLockedToken prim = animSys.xc_store.GetObj(SObjectTag{FOURCC('ANIM'), x4_primitive.GetAnimResId()}); - std::shared_ptr ret = std::make_shared( + return std::make_shared( x4_primitive.GetName(), CAllFormatsAnimSource::GetNewReader(prim, x1c_startTime), x4_primitive.GetAnimDbIdx()); - return ret; } } // namespace urde diff --git a/Runtime/Character/CMetaAnimSequence.cpp b/Runtime/Character/CMetaAnimSequence.cpp index 8cee94cbb..270a4baee 100644 --- a/Runtime/Character/CMetaAnimSequence.cpp +++ b/Runtime/Character/CMetaAnimSequence.cpp @@ -24,25 +24,20 @@ void CMetaAnimSequence::GetUniquePrimitives(std::set& primsOut) cons std::shared_ptr CMetaAnimSequence::VGetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const { - if (orders.x0_recursiveAdvance) { - CMetaAnimTreeBuildOrders modOrders; - modOrders.PreAdvanceForAll(*orders.x0_recursiveAdvance); - return GetAnimationTree(animSys, modOrders); - } + if (orders.x0_recursiveAdvance) + return GetAnimationTree(animSys, CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.x0_recursiveAdvance)); #if 0 - std::vector anims; - anims.reserve(anims.size()); - for (const std::shared_ptr& anim : x4_sequence) - { - std::shared_ptr chNode = anim->GetAnimationTree(animSys, orders); - anims.emplace_back(chNode->GetName()); - } + /* Originally used to generate name string */ + std::vector anims; + anims.reserve(anims.size()); + for (const std::shared_ptr& anim : x4_sequence) { + std::shared_ptr chNode = anim->GetAnimationTree(animSys, orders); + anims.emplace_back(chNode->GetName()); + } #endif - std::shared_ptr ret = std::make_shared(x4_sequence, animSys, ""); - - return ret; + return std::make_shared(x4_sequence, animSys, ""); } } // namespace urde diff --git a/Runtime/Character/CTransitionDatabaseGame.cpp b/Runtime/Character/CTransitionDatabaseGame.cpp index 16b87b581..edc46e665 100644 --- a/Runtime/Character/CTransitionDatabaseGame.cpp +++ b/Runtime/Character/CTransitionDatabaseGame.cpp @@ -11,10 +11,14 @@ CTransitionDatabaseGame::CTransitionDatabaseGame(const std::vector& x14_transitions.reserve(transitions.size()); for (const CTransition& trans : transitions) x14_transitions.emplace_back(trans.GetAnimPair(), trans.GetMetaTrans()); + std::sort(x14_transitions.begin(), x14_transitions.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); x24_halfTransitions.reserve(halfTransitions.size()); for (const CHalfTransition& trans : halfTransitions) x24_halfTransitions.emplace_back(trans.GetId(), trans.GetMetaTrans()); + std::sort(x24_halfTransitions.begin(), x24_halfTransitions.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); } const std::shared_ptr& CTransitionDatabaseGame::GetMetaTrans(u32 a, u32 b) const { diff --git a/Runtime/Character/IMetaAnim.hpp b/Runtime/Character/IMetaAnim.hpp index 2c4640bac..7e469a41c 100644 --- a/Runtime/Character/IMetaAnim.hpp +++ b/Runtime/Character/IMetaAnim.hpp @@ -46,7 +46,6 @@ struct CMetaAnimTreeBuildOrders { static CMetaAnimTreeBuildOrders NoSpecialOrders() { return {}; } static CMetaAnimTreeBuildOrders PreAdvanceForAll(const CPreAdvanceIndicator& ind) { CMetaAnimTreeBuildOrders ret; - ret.x0_recursiveAdvance.emplace(ind); ret.x44_singleAdvance.emplace(ind); return ret; } diff --git a/Runtime/Collision/CCollisionActor.cpp b/Runtime/Collision/CCollisionActor.cpp index 51cab51fb..29c2ac68d 100644 --- a/Runtime/Collision/CCollisionActor.cpp +++ b/Runtime/Collision/CCollisionActor.cpp @@ -117,7 +117,7 @@ zeus::CVector3f CCollisionActor::GetScanObjectIndicatorPosition(const CStateMana } scanScale *= 3.0f; zeus::CVector3f orbitPos = GetOrbitPosition(mgr); - return (scanScale * (orbitPos - gameCamera->GetTransform().origin).normalized()) - orbitPos; + return orbitPos - scanScale * (orbitPos - gameCamera->GetTranslation()).normalized(); } const CCollisionPrimitive* CCollisionActor::GetCollisionPrimitive() const { diff --git a/Runtime/GuiSys/CGuiModel.cpp b/Runtime/GuiSys/CGuiModel.cpp index 33120f07a..6b9ffec0b 100644 --- a/Runtime/GuiSys/CGuiModel.cpp +++ b/Runtime/GuiSys/CGuiModel.cpp @@ -18,11 +18,10 @@ CGuiModel::CGuiModel(const CGuiWidgetParms& parms, CSimplePool* sp, CAssetId mod bool CGuiModel::GetIsFinishedLoadingWidgetSpecific() const { if (!xb8_model) return true; - const CModel* model = xb8_model.GetObj(); - if (!model) + if (!xb8_model.IsLoaded()) return false; - model->GetInstance().Touch(0); - return model->IsLoaded(0); + xb8_model->GetInstance().Touch(0); + return xb8_model->IsLoaded(0); } void CGuiModel::Touch() const { diff --git a/Runtime/MP1/CSamusHud.cpp b/Runtime/MP1/CSamusHud.cpp index 1c65b37cf..3505150b9 100644 --- a/Runtime/MP1/CSamusHud.cpp +++ b/Runtime/MP1/CSamusHud.cpp @@ -358,7 +358,8 @@ void CSamusHud::UpdateEnergy(float dt, const CStateManager& mgr, bool init) { float curLastTankEnergy = x2d0_playerHealth; while (curLastTankEnergy > CPlayerState::GetBaseHealthCapacity()) curLastTankEnergy -= CPlayerState::GetEnergyTankCapacity(); - x28c_energyIntf->SetCurrEnergy(lastTankEnergy, curLastTankEnergy < lastTankEnergy); + x28c_energyIntf->SetCurrEnergy(lastTankEnergy, + curLastTankEnergy > lastTankEnergy != x2d0_playerHealth > energy); } x2d0_playerHealth = energy; if (x28c_energyIntf) { diff --git a/Runtime/MP1/MP1.cpp b/Runtime/MP1/MP1.cpp index 5c2208d26..07a3b65a9 100644 --- a/Runtime/MP1/MP1.cpp +++ b/Runtime/MP1/MP1.cpp @@ -759,6 +759,10 @@ bool CMain::Proc() { // Warmup cycle overrides update if (m_warmupTags.size()) return false; + if (!m_loadedPersistentResources) { + x128_globalObjects.m_gameResFactory->LoadPersistentResources(*g_SimplePool); + m_loadedPersistentResources = true; + } m_console->proc(); if (!m_console->isOpen()) { @@ -832,6 +836,7 @@ void CMain::ShutdownSubsystems() { void CMain::Shutdown() { m_console->unregisterCommand("Give"); + x128_globalObjects.m_gameResFactory->UnloadPersistentResources(); x164_archSupport.reset(); ShutdownSubsystems(); CParticleSwooshShaders::Shutdown(); diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 03de55267..b0a5b057c 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -242,6 +242,7 @@ private: std::vector m_warmupTags; std::vector::iterator m_warmupIt; bool m_needsWarmupClear = false; + bool m_loadedPersistentResources = false; bool m_doQuit = false; void InitializeSubsystems(); diff --git a/Runtime/MP1/World/CAtomicAlpha.cpp b/Runtime/MP1/World/CAtomicAlpha.cpp index 880bffe04..b3c18e3ff 100644 --- a/Runtime/MP1/World/CAtomicAlpha.cpp +++ b/Runtime/MP1/World/CAtomicAlpha.cpp @@ -25,7 +25,7 @@ CAtomicAlpha::CAtomicAlpha(TUniqueId uid, std::string_view name, const CEntityIn , x580_pathFind(nullptr, 3, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x668_bombProjectile(bombWeapon, bombDamage) , x690_bombModel(CStaticRes(cmdl, GetModelData()->GetScale())) { - const_cast*>(&x668_bombProjectile.Token())->Lock(); + x668_bombProjectile.Token().Lock(); for (u32 i = 0; i < skBombCount; ++i) { x6dc_bombLocators.push_back( SBomb(skBombLocators[i], pas::ELocomotionType(u32(pas::ELocomotionType::Internal10) + i))); diff --git a/Runtime/MP1/World/CBabygoth.cpp b/Runtime/MP1/World/CBabygoth.cpp index b1eba4a5e..82b482988 100644 --- a/Runtime/MP1/World/CBabygoth.cpp +++ b/Runtime/MP1/World/CBabygoth.cpp @@ -76,7 +76,7 @@ CBabygoth::CBabygoth(TUniqueId uid, std::string_view name, const CEntityInfo& in if (x570_babyData.x148_.IsValid()) xa38_ = g_SimplePool->GetObj({SBIG('PART'), babyData.x148_}); xa48_31_ = true; - const_cast*>(&x958_.Token())->Lock(); + x958_.Token().Lock(); UpdateTouchBounds(); x460_knockBackController.SetEnableFreeze(false); x460_knockBackController.SetAutoResetImpulse(true); diff --git a/Runtime/MP1/World/CNewIntroBoss.cpp b/Runtime/MP1/World/CNewIntroBoss.cpp index b7c507ff3..324b39966 100644 --- a/Runtime/MP1/World/CNewIntroBoss.cpp +++ b/Runtime/MP1/World/CNewIntroBoss.cpp @@ -25,8 +25,9 @@ CNewIntroBoss::CNewIntroBoss(TUniqueId uid, std::string_view name, const CEntity , x5f0_beamContactFxId(beamContactFxId) , x5f4_beamPulseFxId(beamPulseFxId) , x5f8_beamTextureId(beamTextureId) -, x5fc_beamGlowTextureId(beamGlowTextureId) { - const_cast*>(&x5ac_projectileInfo.Token())->Lock(); +, x5fc_beamGlowTextureId(beamGlowTextureId) +, x644_initialXf(xf) { + x5ac_projectileInfo.Token().Lock(); x574_boneTracking.SetActive(true); } @@ -257,7 +258,7 @@ void CNewIntroBoss::Think(float dt, CStateManager& mgr) { curProjectile->ResetBeam(mgr, true); x450_bodyController->SetPlaybackRate(1.f); - SetTransform(x644_); + SetTransform(x644_initialXf); StopRumble(mgr); Death(mgr, GetTransform().frontVector(), EScriptObjectState::DeathRattle); } diff --git a/Runtime/MP1/World/CNewIntroBoss.hpp b/Runtime/MP1/World/CNewIntroBoss.hpp index a4949ef7c..28041f0de 100644 --- a/Runtime/MP1/World/CNewIntroBoss.hpp +++ b/Runtime/MP1/World/CNewIntroBoss.hpp @@ -34,7 +34,7 @@ class CNewIntroBoss : public CPatterned { float x638_ = 0.2f; float x63c_attackTime = 8.f; float x640_initialHp = 0.f; - zeus::CTransform x644_; + zeus::CTransform x644_initialXf; s16 x674_rumbleVoice = -1; TUniqueId x676_curProjectile = kInvalidUniqueId; bool x678_ = false; diff --git a/Runtime/MP1/World/CPuddleSpore.cpp b/Runtime/MP1/World/CPuddleSpore.cpp index ad81fea8b..23c920826 100644 --- a/Runtime/MP1/World/CPuddleSpore.cpp +++ b/Runtime/MP1/World/CPuddleSpore.cpp @@ -38,7 +38,7 @@ CPuddleSpore::CPuddleSpore(TUniqueId uid, std::string_view name, EFlavorType fla x5dc_elemGens.reserve(kEyeCount); for (u32 i = 0; i < kEyeCount; ++i) x5dc_elemGens.emplace_back(new CElementGen(x5d0_)); - const_cast*>(&x5ec_projectileInfo.Token())->Lock(); + x5ec_projectileInfo.Token().Lock(); x460_knockBackController.SetAutoResetImpulse(false); } diff --git a/Runtime/MP1/World/CSeedling.cpp b/Runtime/MP1/World/CSeedling.cpp index a943b2c6f..c864d127d 100644 --- a/Runtime/MP1/World/CSeedling.cpp +++ b/Runtime/MP1/World/CSeedling.cpp @@ -22,7 +22,7 @@ CSeedling::CSeedling(TUniqueId uid, std::string_view name, const CEntityInfo& in , x6e8_deathDamage(dInfo2) , x722_24_renderOnlyClusterA(true) , x722_25_curNeedleCluster(false) { - const_cast*>(&x6c0_projectileInfo.Token())->Lock(); + x6c0_projectileInfo.Token().Lock(); CreateShadow(false); MakeThermalColdAndHot(); } diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index 3d8cf0b64..d9397e301 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -237,7 +237,7 @@ bool CElementGen::Update(double t) { if (pswtElem && !x26d_25_warmedUp) { int pswt = 0; pswtElem->GetValue(x74_curFrame, pswt); - Log.report(logvisor::Info, "Running warmup on particle system 0x%08x for %d ticks.", desc, pswt); + //Log.report(logvisor::Info, "Running warmup on particle system 0x%08x for %d ticks.", desc, pswt); InternalUpdate((1.f / 60.f) * pswt); x26d_25_warmedUp = true; } diff --git a/Runtime/World/CScriptSpecialFunction.cpp b/Runtime/World/CScriptSpecialFunction.cpp index ccbcf5677..cf5dd9764 100644 --- a/Runtime/World/CScriptSpecialFunction.cpp +++ b/Runtime/World/CScriptSpecialFunction.cpp @@ -27,16 +27,16 @@ CScriptSpecialFunction::CScriptSpecialFunction(TUniqueId uid, std::string_view n kInvalidUniqueId) , xe8_function(func) , xec_locatorName(lcName) -, xfc_(f1) -, x100_(f2) -, x104_(f3) -, x108_(f4) -, x10c_(vec) -, x118_(col) +, xfc_float1(f1) +, x100_float2(f2) +, x104_float3(f3) +, x108_float4(f4) +, x10c_vector3f(vec) +, x118_color(col) , x11c_damageInfo(dInfo) -, x170_(CSfxManager::TranslateSFXID(sId1)) -, x172_(CSfxManager::TranslateSFXID(sId2)) -, x174_(CSfxManager::TranslateSFXID(sId3)) +, x170_sfx1(CSfxManager::TranslateSFXID(sId1)) +, x172_sfx2(CSfxManager::TranslateSFXID(sId2)) +, x174_sfx3(CSfxManager::TranslateSFXID(sId3)) , x1bc_areaSaveId(aId1) , x1c0_layerIdx(aId2) , x1c4_item(itemType) { @@ -126,12 +126,12 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId switch (xe8_function) { case ESpecialFunction::HUDFadeIn: { if (msg == EScriptObjectMessage::Action) - mgr.Player()->SetHudDisable(xfc_, 0.f, 0.5f); + mgr.Player()->SetHudDisable(xfc_float1, 0.f, 0.5f); break; } case ESpecialFunction::EscapeSequence: { - if (msg == EScriptObjectMessage::Action && xfc_ >= 0.f) - mgr.ResetEscapeSequenceTimer(xfc_); + if (msg == EScriptObjectMessage::Action && xfc_float1 >= 0.f) + mgr.ResetEscapeSequenceTimer(xfc_float1); break; } case ESpecialFunction::SpinnerController: { @@ -165,7 +165,7 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId break; } case EScriptObjectMessage::SetToZero: { - x16c_ = -0.5f * x104_; + x16c_ = -0.5f * x104_float3; break; } default: @@ -210,10 +210,10 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId break; } case ESpecialFunction::IntroBossRingController: { - if (x1a8_ != 3) { + if (x1a8_ringState != ERingState::Breakup) { switch (msg) { case EScriptObjectMessage::Play: { - if (x1a8_ != 0) + if (x1a8_ringState != ERingState::Scramble) RingScramble(mgr); for (SRingController& cont : x198_ringControllers) { @@ -223,14 +223,14 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId cont.xc_ = zeus::skForward; } - x1a8_ = 3; + x1a8_ringState = ERingState::Breakup; break; } case EScriptObjectMessage::SetToZero: { - x1a8_ = 1; - x1ac_ = GetTranslation() - mgr.GetPlayer().GetTranslation(); - x1ac_.z() = 0.f; - x1ac_.normalize(); + x1a8_ringState = ERingState::Rotate; + x1ac_ringRotateTarget = GetTranslation() - mgr.GetPlayer().GetTranslation(); + x1ac_ringRotateTarget.z() = 0.f; + x1ac_ringRotateTarget.normalize(); break; } case EScriptObjectMessage::Action: { @@ -250,8 +250,20 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId act->RemoveMaterial(EMaterialTypes::Occluder, mgr); } } + } - // std::sort(x198_ringControllers.begin(), x198_ringControllers.end()); + std::sort(x198_ringControllers.begin(), x198_ringControllers.end(), + [&mgr](const SRingController& a, const SRingController& b) { + TCastToConstPtr actA(mgr.GetObjectById(a.x0_id)); + TCastToConstPtr actB(mgr.GetObjectById(b.x0_id)); + if (actA && actB) + return actA->GetTranslation().z() < actB->GetTranslation().z(); + return false; + }); + + for (auto& rc : x198_ringControllers) { + rc.x4_rotateSpeed = (x1b8_ringReverse ? 1.f : -1.f) * xfc_float1; + rc.x8_reachedTarget = false; } break; } @@ -264,7 +276,7 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId case ESpecialFunction::RadialDamage: { if (msg == EScriptObjectMessage::Action) { CDamageInfo dInfo = x11c_damageInfo; - dInfo.SetRadius(xfc_); + dInfo.SetRadius(xfc_float1); mgr.ApplyDamageToWorld(GetUniqueId(), *this, GetTranslation(), dInfo, CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull})); } @@ -272,7 +284,7 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId } case ESpecialFunction::BossEnergyBar: { if (msg == EScriptObjectMessage::Increment) - mgr.SetBossParams(uid, xfc_, u32(x100_) + 86); + mgr.SetBossParams(uid, xfc_float1, u32(x100_float2) + 86); else if (msg == EScriptObjectMessage::Decrement) mgr.SetBossParams(kInvalidUniqueId, 0.f, 0); break; @@ -332,12 +344,12 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId */ case ESpecialFunction::EnvFxDensityController: { if (msg == EScriptObjectMessage::Action) - mgr.GetEnvFxManager()->SetFxDensity(s32(x100_), xfc_); + mgr.GetEnvFxManager()->SetFxDensity(s32(x100_float2), xfc_float1); break; } case ESpecialFunction::RumbleEffect: if (msg == EScriptObjectMessage::Action) { - s32 rumbFx = s32(x100_); + s32 rumbFx = s32(x100_float2); /* Retro originally did not check the upper bounds, this could potentially cause a crash * with some runtimes, so let's make sure we're not out of bounds in either direction */ @@ -367,7 +379,7 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId } case ESpecialFunction::DropBomb: { if (msg == EScriptObjectMessage::Action) { - if (xfc_ >= 1.f) + if (xfc_float1 >= 1.f) mgr.GetPlayer().GetPlayerGun()->DropBomb(CPlayerGun::EBWeapon::PowerBomb, mgr); else mgr.GetPlayer().GetPlayerGun()->DropBomb(CPlayerGun::EBWeapon::Bomb, mgr); @@ -389,13 +401,13 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId const SObjectTag* objectTag = g_ResFactory->GetResourceIdByName(xec_locatorName); CAssetId assetId = objectTag ? objectTag->id : CAssetId(); - mgr.SetPendingOnScreenTex(assetId, {int(x104_), int(x108_)}, {int(xfc_), int(x100_)}); + mgr.SetPendingOnScreenTex(assetId, {int(x104_float3), int(x108_float4)}, {int(xfc_float1), int(x100_float2)}); if (objectTag) { x1e8_ = g_SimplePool->GetObj(*objectTag); x1e5_26_displayBillboard = true; } } else if (msg == EScriptObjectMessage::Decrement) { - mgr.SetPendingOnScreenTex({}, {int(x104_), int(x108_)}, {int(xfc_), int(x100_)}); + mgr.SetPendingOnScreenTex({}, {int(x104_float3), int(x108_float4)}, {int(xfc_float1), int(x100_float2)}); if (x1e8_) x1e8_ = TLockedToken(); x1e5_26_displayBillboard = false; @@ -418,9 +430,9 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId } case ESpecialFunction::FogFader: { if (msg == EScriptObjectMessage::Increment) - mgr.GetCameraManager()->SetFogDensity(x100_, xfc_); + mgr.GetCameraManager()->SetFogDensity(x100_float2, xfc_float1); else if (msg == EScriptObjectMessage::Decrement) - mgr.GetCameraManager()->SetFogDensity(x100_, 1.f); + mgr.GetCameraManager()->SetFogDensity(x100_float2, 1.f); break; } case ESpecialFunction::EnterLogbook: { @@ -429,7 +441,7 @@ void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId break; } case ESpecialFunction::Ending: { - if (msg == EScriptObjectMessage::Action && GetSpecialEnding(mgr) == u32(xfc_)) + if (msg == EScriptObjectMessage::Action && GetSpecialEnding(mgr) == u32(xfc_float1)) SendScriptMsgs(EScriptObjectState::Zero, mgr, EScriptObjectMessage::None); break; } @@ -450,15 +462,83 @@ void CScriptSpecialFunction::SkipCinematic(CStateManager& stateMgr) { stateMgr.SetSkipCinematicSpecialFunction(kInvalidUniqueId); } -void CScriptSpecialFunction::RingMoveCloser(CStateManager&, float) {} +void CScriptSpecialFunction::RingScramble(CStateManager& mgr) { + SendScriptMsgs(EScriptObjectState::Zero, mgr, EScriptObjectMessage::None); + x1a8_ringState = ERingState::Scramble; + x1b8_ringReverse = !x1b8_ringReverse; + float dir = (x1b8_ringReverse ? 1.f : -1.f); + for (auto& rc : x198_ringControllers) { + rc.x4_rotateSpeed = dir * mgr.GetActiveRandom()->Range(x100_float2, x104_float3); + dir = -dir; + rc.x8_reachedTarget = false; + } +} -void CScriptSpecialFunction::RingMoveAway(CStateManager&, float) {} - -void CScriptSpecialFunction::ThinkRingPuller(float, CStateManager&) {} - -void CScriptSpecialFunction::RingScramble(CStateManager&) {} - -void CScriptSpecialFunction::ThinkIntroBossRingController(float, CStateManager&) {} +void CScriptSpecialFunction::ThinkIntroBossRingController(float dt, CStateManager& mgr) { + if (x1a8_ringState != ERingState::Breakup) { + for (const auto& rc : x198_ringControllers) { + if (TCastToPtr act = mgr.ObjectById(rc.x0_id)) { + zeus::CTransform newXf = act->GetTransform(); + newXf.rotateLocalZ(zeus::degToRad(rc.x4_rotateSpeed * dt)); + act->SetTransform(newXf); + } + } + } + switch (x1a8_ringState) { + case ERingState::Breakup: { + float minMag = 0.f; + for (const auto& rc : x198_ringControllers) { + if (TCastToPtr act = mgr.ObjectById(rc.x0_id)) { + act->SetTranslation(act->GetTransform().basis[1] * 50.f * dt + act->GetTranslation()); + minMag = std::min(act->GetTranslation().magnitude(), minMag); + } + } + CalculateRenderBounds(); + if (minMag != 0.f) { + /* Never actually happens */ + for (const auto& rc : x198_ringControllers) { + if (CEntity* ent = mgr.ObjectById(rc.x0_id)) + ent->SetActive(false); + } + SetActive(false); + } + break; + } + case ERingState::Rotate: { + x1ac_ringRotateTarget = + zeus::CQuaternion::fromAxisAngle(zeus::skUp, + zeus::degToRad(xfc_float1 * (x1b8_ringReverse ? 1.f : -1.f) * dt)).transform(x1ac_ringRotateTarget); + bool allReachedTarget = true; + for (auto& rc : x198_ringControllers) { + if (TCastToPtr act = mgr.ObjectById(rc.x0_id)) { + zeus::CVector3f lookDirFlat = act->GetTransform().basis[1]; + lookDirFlat.z() = 0.f; + lookDirFlat.normalize(); + if (std::acos(zeus::clamp(-1.f, lookDirFlat.dot(x1ac_ringRotateTarget), 1.f)) <= + zeus::degToRad((xfc_float1 + std::fabs(rc.x4_rotateSpeed)) / 30.f)) { + zeus::CTransform newXf = zeus::lookAt(zeus::skZero3f, x1ac_ringRotateTarget); + newXf.origin = act->GetTranslation(); + act->SetTransform(newXf); + rc.x4_rotateSpeed = (x1b8_ringReverse ? 1.f : -1.f) * xfc_float1; + rc.x8_reachedTarget = true; + } else { + allReachedTarget = false; + break; + } + } + } + if (allReachedTarget) { + SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None); + x1a8_ringState = ERingState::Stopped; + for (auto& rc : x198_ringControllers) + rc.x8_reachedTarget = false; + } + break; + } + default: + break; + } +} void CScriptSpecialFunction::ThinkPlayerFollowLocator(float, CStateManager&) {} @@ -498,7 +578,7 @@ void CScriptSpecialFunction::ThinkObjectFollowObject(float, CStateManager&) {} void CScriptSpecialFunction::ThinkChaffTarget(float, CStateManager&) {} void CScriptSpecialFunction::ThinkActorScale(float dt, CStateManager& mgr) { - float deltaScale = dt * xfc_; + float deltaScale = dt * xfc_float1; for (const SConnection& conn : x20_conns) { if (conn.x0_state != EScriptObjectState::Play || conn.x4_msg != EScriptObjectMessage::Activate) @@ -509,9 +589,9 @@ void CScriptSpecialFunction::ThinkActorScale(float dt, CStateManager& mgr) { zeus::CVector3f scale = mData->GetScale(); if (deltaScale > 0.f) - scale = zeus::min(zeus::CVector3f(deltaScale) + scale, zeus::CVector3f(x100_)); + scale = zeus::min(zeus::CVector3f(deltaScale) + scale, zeus::CVector3f(x100_float2)); else - scale = zeus::max(zeus::CVector3f(deltaScale) + scale, zeus::CVector3f(x100_)); + scale = zeus::max(zeus::CVector3f(deltaScale) + scale, zeus::CVector3f(x100_float2)); mData->SetScale(scale); } @@ -575,6 +655,6 @@ u32 CScriptSpecialFunction::GetSpecialEnding(const CStateManager& mgr) const { return 2; } -CScriptSpecialFunction::SRingController::SRingController(TUniqueId uid, float f, bool b) : x0_id(uid), x4_(f), x8_(b) {} +CScriptSpecialFunction::SRingController::SRingController(TUniqueId uid, float f, bool b) : x0_id(uid), x4_rotateSpeed(f), x8_reachedTarget(b) {} } // namespace urde diff --git a/Runtime/World/CScriptSpecialFunction.hpp b/Runtime/World/CScriptSpecialFunction.hpp index f516be080..7aaab27bd 100644 --- a/Runtime/World/CScriptSpecialFunction.hpp +++ b/Runtime/World/CScriptSpecialFunction.hpp @@ -53,10 +53,17 @@ public: One, }; + enum class ERingState { + Scramble, + Rotate, + Stopped, + Breakup + }; + struct SRingController { TUniqueId x0_id; - float x4_; - bool x8_; + float x4_rotateSpeed; + bool x8_reachedTarget; zeus::CVector3f xc_; SRingController(TUniqueId uid, float f, bool b); }; @@ -64,28 +71,28 @@ public: private: ESpecialFunction xe8_function; std::string xec_locatorName; - float xfc_; - float x100_; - float x104_; - float x108_; - zeus::CVector3f x10c_; - zeus::CColor x118_; + float xfc_float1; + float x100_float2; + float x104_float3; + float x108_float4; + zeus::CVector3f x10c_vector3f; + zeus::CColor x118_color; CDamageInfo x11c_damageInfo; float x138_ = 0.f; zeus::CTransform x13c_ = zeus::CTransform(); float x16c_ = 0.f; - s16 x170_; - s16 x172_; - s16 x174_; + s16 x170_sfx1; + s16 x172_sfx2; + s16 x174_sfx3; CSfxHandle x178_sfxHandle; u32 x17c_; float x180_ = 0.f; std::vector x184_; float x194_ = 0.f; std::vector x198_ringControllers; - u32 x1a8_ = 2; - zeus::CVector3f x1ac_ = zeus::skZero3f; - bool x1b8_ = true; + ERingState x1a8_ringState = ERingState::Stopped; + zeus::CVector3f x1ac_ringRotateTarget = zeus::skZero3f; + bool x1b8_ringReverse = true; s32 x1bc_areaSaveId; s32 x1c0_layerIdx; CPlayerState::EItemType x1c4_item; @@ -120,9 +127,6 @@ public: void Render(const CStateManager&) const; void SkipCinematic(CStateManager&); - void RingMoveCloser(CStateManager&, float); - void RingMoveAway(CStateManager&, float); - void ThinkRingPuller(float, CStateManager&); void RingScramble(CStateManager&); void ThinkIntroBossRingController(float, CStateManager&); void ThinkPlayerFollowLocator(float, CStateManager&); diff --git a/Runtime/World/CScriptStreamedMusic.cpp b/Runtime/World/CScriptStreamedMusic.cpp index 03a9be3bf..69f2111d5 100644 --- a/Runtime/World/CScriptStreamedMusic.cpp +++ b/Runtime/World/CScriptStreamedMusic.cpp @@ -47,11 +47,7 @@ CScriptStreamedMusic::CScriptStreamedMusic(TUniqueId id, const CEntityInfo& info , x47_music(music) , x48_fadeIn(fadeIn) , x4c_fadeOut(fadeOut) -, x50_volume(volume) { - size_t pos; - while ((pos = x34_fileName.find("audio/")) != std::string::npos) - x34_fileName.replace(pos, 6, "Audio/"); -} +, x50_volume(volume) {} void CScriptStreamedMusic::Stop(CStateManager& mgr) { if (x45_fileIsDsp) diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index 8c4c6570b..647df806b 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -18,7 +18,8 @@ CWorld::CSoundGroupData::CSoundGroupData(int grpId, CAssetId agsc) : x0_groupId( CDummyWorld::CDummyWorld(CAssetId mlvlId, bool loadMap) : x4_loadMap(loadMap), xc_mlvlId(mlvlId) { SObjectTag tag{FOURCC('MLVL'), mlvlId}; - x34_loadBuf.reset(new u8[g_ResFactory->ResourceSize(tag)]); + x38_bufSz = g_ResFactory->ResourceSize(tag); + x34_loadBuf.reset(new u8[x38_bufSz]); x30_loadToken = g_ResFactory->LoadResourceAsync(tag, x34_loadBuf.get()); } @@ -99,10 +100,9 @@ void CWorldLayers::ReadWorldLayers(athena::io::MemoryReader& r, int version, CAs bool CDummyWorld::ICheckWorldComplete() { switch (x8_phase) { case Phase::Loading: { - if (x30_loadToken && !x30_loadToken->IsComplete()) + if (!x30_loadToken->IsComplete()) return false; - x30_loadToken.reset(); - athena::io::MemoryReader r(x34_loadBuf.get(), UINT32_MAX, false); + athena::io::MemoryReader r(x34_loadBuf.get(), x38_bufSz); r.readUint32Big(); int version = r.readUint32Big(); x10_strgId = r.readUint32Big(); @@ -141,6 +141,10 @@ bool CDummyWorld::ICheckWorldComplete() { CWorldLayers::ReadWorldLayers(r, version, xc_mlvlId); + x30_loadToken.reset(); + x34_loadBuf.reset(); + x38_bufSz = 0; + if (x4_loadMap) x8_phase = Phase::LoadingMap; else { @@ -179,8 +183,9 @@ CWorld::CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId) : x8_mlvlId(mlvlId), x60_objectStore(objStore), x64_resFactory(resFactory) { x70_24_currentAreaNeedsAllocation = true; SObjectTag tag{FOURCC('MLVL'), mlvlId}; - x40_loadBuf.reset(new u8[resFactory.ResourceSize(tag)]); - resFactory.LoadResourceAsync(tag, x40_loadBuf.get()); + x44_bufSz = resFactory.ResourceSize(tag); + x40_loadBuf.reset(new u8[x44_bufSz]); + x3c_loadToken = resFactory.LoadResourceAsync(tag, x40_loadBuf.get()); } CWorld::~CWorld() { @@ -277,9 +282,9 @@ bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId) switch (x4_phase) { case Phase::Loading: { - if (!x40_loadBuf) + if (!x3c_loadToken->IsComplete()) return false; - athena::io::MemoryReader r(x40_loadBuf.get(), UINT32_MAX); + athena::io::MemoryReader r(x40_loadBuf.get(), x44_bufSz); r.readUint32Big(); int version = r.readUint32Big(); xc_strgId = r.readUint32Big(); @@ -338,6 +343,9 @@ bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId) CWorldLayers::ReadWorldLayers(r, version, x8_mlvlId); + x3c_loadToken.reset(); + x40_loadBuf.reset(); + x44_bufSz = 0; x4_phase = Phase::LoadingMap; [[fallthrough]]; } diff --git a/Runtime/World/CWorld.hpp b/Runtime/World/CWorld.hpp index d4529e401..b879b0585 100644 --- a/Runtime/World/CWorld.hpp +++ b/Runtime/World/CWorld.hpp @@ -47,7 +47,7 @@ class CDummyWorld : public IWorld { TLockedToken x2c_mapWorld; std::shared_ptr x30_loadToken; std::unique_ptr x34_loadBuf; - // u32 x38_bufSz; + u32 x38_bufSz; TAreaId x3c_curAreaId = kInvalidAreaId; public: @@ -116,9 +116,9 @@ private: CAssetId x24_mapwId; TLockedToken x28_mapWorld; std::vector x2c_relays; - // AsyncTask x3c_loadToken; + std::shared_ptr x3c_loadToken; std::unique_ptr x40_loadBuf; - // u32 x44_bufSz; + u32 x44_bufSz; u32 x48_chainCount = 0; CGameArea* x4c_chainHeads[5] = {}; diff --git a/amuse b/amuse index a4b8946ee..aa5abd5ff 160000 --- a/amuse +++ b/amuse @@ -1 +1 @@ -Subproject commit a4b8946ee2a395477683e40088aaa5d1d2245194 +Subproject commit aa5abd5ff5561f3b105a20046588fa1d8bd7785c