From f60097b7e3e94133e876e222914e69abc08379d5 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 26 Nov 2017 19:06:53 -1000 Subject: [PATCH] Implement CScriptSound and bug fixes --- DataSpec/DNAMP1/ScriptObjects/Midi.hpp | 3 +- DataSpec/DNAMP1/ScriptObjects/Sound.hpp | 32 ++-- Runtime/Audio/CStreamAudioManager.cpp | 12 ++ Runtime/Audio/CStreamAudioManager.hpp | 1 + Runtime/CStateManager.cpp | 35 ++-- Runtime/CStateManager.hpp | 2 +- Runtime/Character/CAnimData.cpp | 2 +- Runtime/Character/CAnimSourceReader.cpp | 1 + Runtime/Character/CBodyState.cpp | 8 +- Runtime/Character/CCharAnimTime.cpp | 2 +- Runtime/Character/CFBStreamedAnimReader.cpp | 3 +- Runtime/Character/CPOINode.cpp | 5 +- Runtime/Collision/CCollisionActor.cpp | 2 +- Runtime/IMain.hpp | 1 + Runtime/World/CGameArea.cpp | 4 +- Runtime/World/CGameArea.hpp | 2 +- Runtime/World/CScriptCoverPoint.cpp | 2 +- Runtime/World/CScriptDock.cpp | 2 +- Runtime/World/CScriptSound.cpp | 197 +++++++++++++++++--- Runtime/World/CScriptSound.hpp | 56 +++--- Runtime/World/CWorld.cpp | 77 +++++++- Runtime/World/CWorld.hpp | 11 +- Runtime/World/ScriptLoader.cpp | 34 ++-- Runtime/World/ScriptObjectSupport.cpp | 8 +- Runtime/World/ScriptObjectSupport.hpp | 8 +- amuse | 2 +- 26 files changed, 369 insertions(+), 143 deletions(-) diff --git a/DataSpec/DNAMP1/ScriptObjects/Midi.hpp b/DataSpec/DNAMP1/ScriptObjects/Midi.hpp index 622c3909c..342629d3a 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Midi.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Midi.hpp @@ -30,7 +30,8 @@ struct Midi : IScriptObject void gatherDependencies(std::vector &pathsOut) const { - g_curSpec->flattenDependencies(song, pathsOut); + // Dedicated PAK for this + //g_curSpec->flattenDependencies(song, pathsOut); } }; } diff --git a/DataSpec/DNAMP1/ScriptObjects/Sound.hpp b/DataSpec/DNAMP1/ScriptObjects/Sound.hpp index 03cbd7f12..fffe4eddc 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Sound.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Sound.hpp @@ -16,22 +16,22 @@ struct Sound : IScriptObject Value location; Value orientation; Value soundID; - Value unknown1; - Value unknown2; - Value unknown3; - Value unknown4; - Value unknown5; - Value unknown6; - Value unknown7; - Value unknown8; - Value unknown9; - Value unknown10; - Value unknown11; - Value unknown12; - Value unknown13; - Value unknown14; - Value unknown15; - Value unknown16; + Value active; + Value maxDist; + Value distComp; + Value startDelay; + Value minVol; + Value vol; + Value prio; + Value pan; + Value loop; + Value nonEmitter; + Value autoStart; + Value occlusionTest; + Value acoustics; + Value worldSfx; + Value allowDuplicates; + Value pitch; }; } } diff --git a/Runtime/Audio/CStreamAudioManager.cpp b/Runtime/Audio/CStreamAudioManager.cpp index a56509e6b..5c005d06c 100644 --- a/Runtime/Audio/CStreamAudioManager.cpp +++ b/Runtime/Audio/CStreamAudioManager.cpp @@ -289,6 +289,9 @@ struct SDSPStream : boo::IAudioVoiceCallback stream.m_booVoice.reset(); stream.x0_active = false; stream.xd4_ringBuffer.reset(); + stream.m_readReqs[0].reset(); + stream.m_readReqs[1].reset(); + stream.m_file = std::experimental::nullopt; } } @@ -1196,6 +1199,15 @@ void CStreamAudioManager::Initialize() CDSPStreamManager::Initialize(); } +void CStreamAudioManager::StopOneShot() +{ + CStreamAudioManager::StopStreaming(true); + SDSPPlayer& p = s_Players[1]; + p = SDSPPlayer(); + SDSPPlayer& qp = s_QueuedPlayers[1]; + qp = SDSPPlayer(); +} + void CStreamAudioManager::Shutdown() { CDSPStreamManager::Shutdown(); diff --git a/Runtime/Audio/CStreamAudioManager.hpp b/Runtime/Audio/CStreamAudioManager.hpp index 75f88f011..09a9902f8 100644 --- a/Runtime/Audio/CStreamAudioManager.hpp +++ b/Runtime/Audio/CStreamAudioManager.hpp @@ -32,6 +32,7 @@ public: static void SetMusicVolume(u8 volume); static void Initialize(); + static void StopOneShot(); static void Shutdown(); }; diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index d871766d2..e289fd282 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -1891,7 +1891,7 @@ void CStateManager::Update(float dt) x884_actorModelParticles->Update(dt, *this); if (x904_gameState == EGameState::Running || x904_gameState == EGameState::SoftPaused) - ThinkEffectsAndActors(dt); + Think(dt); if (x904_gameState != EGameState::SoftPaused) x870_cameraManager->Update(dt, *this); @@ -2039,17 +2039,17 @@ void CStateManager::MoveDoors(float dt) if (doThink && ai->GetAreaIdAlways() != kInvalidAreaId) { const CGameArea* area = x850_world->GetAreaAlways(ai->GetAreaIdAlways()); - float f1; + float occTime; if (area->IsPostConstructed()) - f1 = area->GetPostConstructed()->x10e4_; + occTime = area->GetPostConstructed()->x10e4_occludedTime; else - f1 = 0.f; - if (f1 > 5.f) + occTime = 0.f; + if (occTime > 5.f) doThink = false; } if (!doThink) SendScriptMsgAlways(ai->GetUniqueId(), kInvalidUniqueId, - EScriptObjectMessage::InternalMessage26); + EScriptObjectMessage::SuspendedMove); else if (x84c_player.get() != ent) if (!GetPlatformAndDoorObjectList().IsPlatform(*ent)) CGameCollision::Move(*this, physActor, dt, nullptr); @@ -2102,7 +2102,7 @@ void CStateManager::CrossTouchActors() } } -void CStateManager::ThinkEffectsAndActors(float dt) +void CStateManager::Think(float dt) { if (x84c_player->x9f4_deathTime > 0.f) { @@ -2119,26 +2119,27 @@ void CStateManager::ThinkEffectsAndActors(float dt) else { for (CEntity* ent : GetAllObjectList()) + { if (TCastToPtr ai = ent) { bool doThink = !xf94_29_cinematicPause; if (doThink && ai->GetAreaIdAlways() != kInvalidAreaId) { const CGameArea* area = x850_world->GetAreaAlways(ai->GetAreaIdAlways()); - float f1; + float occTime; if (area->IsPostConstructed()) - f1 = area->GetPostConstructed()->x10e4_; + occTime = area->GetPostConstructed()->x10e4_occludedTime; else - f1 = 0.f; - if (f1 > 5.f) + occTime = 0.f; + if (occTime > 5.f) doThink = false; } - if (doThink) - { - CEntity* ent2 = GetAllObjectList().GetObjectById(ai->GetUniqueId()); - ent2->Think(dt, *this); - } + if (!doThink) + continue; } + if (!GetCameraObjectList().GetObjectById(ent->GetUniqueId())) + ent->Think(dt, *this); + } } } @@ -2207,7 +2208,7 @@ void CStateManager::InitializeState(CAssetId mlvlId, TAreaId aid, CAssetId mreaI UpdateRoomAcoustics(x8cc_nextAreaId); for (CEntity* ent : GetAllObjectList()) - SendScriptMsg(ent, kInvalidUniqueId, EScriptObjectMessage::InternalMessage14); + SendScriptMsg(ent, kInvalidUniqueId, EScriptObjectMessage::WorldInitialized); for (CEntity* ent : GetAllObjectList()) { diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 036dccaa0..2c3bf02d8 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -336,7 +336,7 @@ public: void MovePlatforms(float dt); void MoveDoors(float dt); void CrossTouchActors(); - void ThinkEffectsAndActors(float dt); + void Think(float dt); void PostUpdatePlayer(float dt); void ShowPausedHUDMemo(CAssetId strg, float time); void ClearGraveyard(); diff --git a/Runtime/Character/CAnimData.cpp b/Runtime/Character/CAnimData.cpp index ea77351a2..851677ce7 100644 --- a/Runtime/Character/CAnimData.cpp +++ b/Runtime/Character/CAnimData.cpp @@ -827,7 +827,7 @@ SAdvancementDeltas CAnimData::DoAdvance(float dt, bool& suspendParticles, CRando else { CCharAnimTime remTime = x1f8_animRoot->VGetTimeRemaining(); - while (remTime.GreaterThanZero() && !remTime.EpsilonZero()) + while (!remTime.EpsilonZero() && !time.EpsilonZero()) { x210_passedIntCount += x1f8_animRoot->GetInt32POIList(time, g_Int32POINodes.data(), 16, x210_passedIntCount, 0); x20c_passedBoolCount += x1f8_animRoot->GetBoolPOIList(time, g_BoolPOINodes.data(), 16, x20c_passedBoolCount, 0); diff --git a/Runtime/Character/CAnimSourceReader.cpp b/Runtime/Character/CAnimSourceReader.cpp index 15e46a3e3..be9536bf6 100644 --- a/Runtime/Character/CAnimSourceReader.cpp +++ b/Runtime/Character/CAnimSourceReader.cpp @@ -3,6 +3,7 @@ #include "CInt32POINode.hpp" #include "CParticlePOINode.hpp" #include "CSoundPOINode.hpp" +#include "CFBStreamedAnimReader.hpp" namespace urde { diff --git a/Runtime/Character/CBodyState.cpp b/Runtime/Character/CBodyState.cpp index a03457391..55d7c8def 100644 --- a/Runtime/Character/CBodyState.cpp +++ b/Runtime/Character/CBodyState.cpp @@ -1074,7 +1074,7 @@ void CBSJump::PlayJumpLoop(CStateManager& mgr, CBodyController& bc) if (TCastToPtr act = bc.GetOwner()) { mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::Falling); - mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::InternalMessage18); + mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::Jumped); x30_24_bodyForceSet = false; x18_velocity = act->GetVelocity(); } @@ -1195,7 +1195,7 @@ void CBSHurled::Start(CBodyController& bc, CStateManager& mgr) const CPASAnimState* hurledState = bc.GetPASDatabase().GetAnimState(14); xc_animSeries = hurledState->GetAnimParmData(best.second, 0).GetInt32Value(); mgr.SendScriptMsg(&bc.GetOwner(), kInvalidUniqueId, EScriptObjectMessage::Falling); - mgr.SendScriptMsg(&bc.GetOwner(), kInvalidUniqueId, EScriptObjectMessage::InternalMessage18); + mgr.SendScriptMsg(&bc.GetOwner(), kInvalidUniqueId, EScriptObjectMessage::Jumped); if (!zeus::close_enough(cmd->GetLaunchVelocity(), zeus::CVector3f::skZero, 0.0001f)) if (TCastToPtr act = bc.GetOwner()) act->SetConstantForce(act->GetMass() * cmd->GetLaunchVelocity()); @@ -1729,7 +1729,7 @@ pas::EAnimationState CBSWallHang::UpdateBody(float dt, CBodyController& bc, CSta } if (TCastToPtr act = bc.GetOwner()) { - mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::InternalMessage18); + mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::Jumped); if (TCastToPtr wp = mgr.ObjectById(x8_wpId)) { zeus::CVector3f toWp = wp->GetTranslation() - act->GetTranslation(); @@ -1837,7 +1837,7 @@ pas::EAnimationState CBSWallHang::UpdateBody(float dt, CBodyController& bc, CSta } if (TCastToPtr act = bc.GetOwner()) { - mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::InternalMessage18); + mgr.SendScriptMsg(act.GetPtr(), kInvalidUniqueId, EScriptObjectMessage::Jumped); x18_24_launched = false; if (TCastToPtr wp = mgr.ObjectById(x8_wpId)) { diff --git a/Runtime/Character/CCharAnimTime.cpp b/Runtime/Character/CCharAnimTime.cpp index 489889023..16ce5a11e 100644 --- a/Runtime/Character/CCharAnimTime.cpp +++ b/Runtime/Character/CCharAnimTime.cpp @@ -23,7 +23,7 @@ bool CCharAnimTime::EqualsZero() const bool CCharAnimTime::EpsilonZero() const { - return (std::fabs(x0_time) < FLT_EPSILON); + return (std::fabs(x0_time) < 0.00001f); } bool CCharAnimTime::GreaterThanZero() const diff --git a/Runtime/Character/CFBStreamedAnimReader.cpp b/Runtime/Character/CFBStreamedAnimReader.cpp index 416d544d5..d8168df4c 100644 --- a/Runtime/Character/CFBStreamedAnimReader.cpp +++ b/Runtime/Character/CFBStreamedAnimReader.cpp @@ -498,7 +498,8 @@ SAdvancementResults CFBStreamedAnimReader::VAdvanceView(const CCharAnimTime& dt) xc_curTime = nextTime; x7c_totals.SetTime(x108_bitLoader, xc_curTime); - UpdatePOIStates(); + if (x54_source->HasPOIData()) + UpdatePOIStates(); zeus::CQuaternion nextQ = GetRotation(3); zeus::CVector3f nextV = GetOffset(3); diff --git a/Runtime/Character/CPOINode.cpp b/Runtime/Character/CPOINode.cpp index e521d67ee..aaa9fc723 100644 --- a/Runtime/Character/CPOINode.cpp +++ b/Runtime/Character/CPOINode.cpp @@ -70,14 +70,15 @@ u32 _getPOIList(const CCharAnimTime& time, return ret; CCharAnimTime nodeTime = stream[passedCount].GetTime(); - while (nodeTime <= targetTime) + while (passedCount < stream.size() && nodeTime <= targetTime) { u32 idx = iterator + ret; if (idx < capacity) listOut[idx] = T::CopyNodeMinusStartTime(stream[passedCount], curTime); ++passedCount; ++ret; - nodeTime = stream[passedCount].GetTime(); + if (passedCount < stream.size()) + nodeTime = stream[passedCount].GetTime(); } } return ret; diff --git a/Runtime/Collision/CCollisionActor.cpp b/Runtime/Collision/CCollisionActor.cpp index e3914f163..eefb2da0e 100644 --- a/Runtime/Collision/CCollisionActor.cpp +++ b/Runtime/Collision/CCollisionActor.cpp @@ -166,7 +166,7 @@ void CCollisionActor::OnScanStateChanged(CActor::EScanState state, CStateManager void CCollisionActor::Touch(CActor& actor, CStateManager& mgr) { x2fc_lastTouched = actor.GetUniqueId(); - mgr.SendScriptMsgAlways(x25c_owner, GetUniqueId(), EScriptObjectMessage::InternalMessage08); + mgr.SendScriptMsgAlways(x25c_owner, GetUniqueId(), EScriptObjectMessage::Touched); } zeus::CVector3f CCollisionActor::GetOrbitPosition(const CStateManager&) const { return GetTouchBounds()->center(); } diff --git a/Runtime/IMain.hpp b/Runtime/IMain.hpp index eb9671202..28f29fd83 100644 --- a/Runtime/IMain.hpp +++ b/Runtime/IMain.hpp @@ -41,6 +41,7 @@ public: virtual bool Proc()=0; virtual void Shutdown()=0; virtual boo::IWindow* GetMainWindow() const= 0; + virtual EFlowState GetFlowState() const = 0; virtual void SetFlowState(EFlowState) = 0; virtual size_t GetExpectedIdSize() const = 0; virtual void WarmupShaders() = 0; diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index 3e62ce533..c64a007b8 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -730,9 +730,9 @@ void CGameArea::UpdateWeaponWorldLighting(float dt) void CGameArea::AliveUpdate(float dt) { if (x12c_postConstructed->x10dc_occlusionState == EOcclusionState::Occluded) - x12c_postConstructed->x10e4_ += dt; + x12c_postConstructed->x10e4_occludedTime += dt; else - x12c_postConstructed->x10e4_ = 0.f; + x12c_postConstructed->x10e4_occludedTime = 0.f; UpdateFog(dt); UpdateThermalVisor(dt); UpdateWeaponWorldLighting(dt); diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 79a53b6e0..eb1940c66 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -238,7 +238,7 @@ public: const CScriptAreaAttributes* x10d8_areaAttributes = nullptr; EOcclusionState x10dc_occlusionState = EOcclusionState::Occluded; u32 x10e0_ = 0; - float x10e4_ = 5.f; + float x10e4_occludedTime = 5.f; u32 x10e8_ = -1; u32 x10ec_ = 0; // std::vector x10f0_tokens; diff --git a/Runtime/World/CScriptCoverPoint.cpp b/Runtime/World/CScriptCoverPoint.cpp index cf13a040f..20d611610 100644 --- a/Runtime/World/CScriptCoverPoint.cpp +++ b/Runtime/World/CScriptCoverPoint.cpp @@ -121,7 +121,7 @@ void CScriptCoverPoint::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, { CActor::AcceptScriptMsg(msg, uid, mgr); - if (msg == EScriptObjectMessage::InternalMessage14) + if (msg == EScriptObjectMessage::WorldInitialized) { for (const SConnection& con : x20_conns) if (con.x0_state == EScriptObjectState::Retreat) diff --git a/Runtime/World/CScriptDock.cpp b/Runtime/World/CScriptDock.cpp index e248c6c5b..b543581c2 100644 --- a/Runtime/World/CScriptDock.cpp +++ b/Runtime/World/CScriptDock.cpp @@ -106,7 +106,7 @@ void CScriptDock::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStat case EScriptObjectMessage::InitializedInArea: AreaLoaded(mgr); break; - case EScriptObjectMessage::InternalMessage14: + case EScriptObjectMessage::WorldInitialized: { UpdateAreaActivateFlags(mgr); CMaterialList exclude = GetMaterialFilter().GetExcludeList(); diff --git a/Runtime/World/CScriptSound.cpp b/Runtime/World/CScriptSound.cpp index 6ebaaa9ae..ad029c81b 100644 --- a/Runtime/World/CScriptSound.cpp +++ b/Runtime/World/CScriptSound.cpp @@ -11,31 +11,32 @@ namespace urde bool CScriptSound::sFirstInFrame = false; CScriptSound::CScriptSound(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, - s16 soundId, bool active, float f1, float f2, float f3, u32 w1, u32 w2, u32 w3, u32 w4, - u32 w5, u32 w6, bool b1, bool b2, bool autoStart, bool b4, bool b5, bool b6, bool b7, u32 w7) + u16 soundId, bool active, float maxDist, float distComp, float startDelay, u32 minVol, + u32 vol, u32 w3, u32 prio, u32 pan, u32 w6, bool looped, bool nonEmitter, bool autoStart, + bool occlusionTest, bool acoustics, bool worldSfx, bool allowDuplicates, s32 pitch) : CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::Unknown), CActorParameters::None(), kInvalidUniqueId) -, xfc_(f3) +, xfc_startDelay(startDelay) , x100_soundId(CSfxManager::TranslateSFXID(soundId)) -, x104_(f1) -, x108_(f2) -, x10c_(w1) -, x10e_(w2) +, x104_maxDist(maxDist) +, x108_distComp(distComp) +, x10c_minVol(minVol / 127.f) +, x10e_vol(vol / 127.f) , x110_(w3) -, x112_(w4) -, x114_(w5) +, x112_prio(s16(prio)) +, x114_pan(pan / 64.f - 1.f) , x116_(w6) -, x118_(w7 + 8192) +, x118_pitch(pitch / 8192.f) { - x11c_25_ = b1; - x11c_26_ = b2; + x11c_25_looped = looped; + x11c_26_nonEmitter = nonEmitter; x11c_27_autoStart = autoStart; - x11c_28_ = b4; - x11c_29_ = b5; - x11c_30_ = b6; - x11d_24_ = b7; - if (x11c_30_ && (!x11c_26_ || !x11c_25_)) - x11c_30_ = false; + x11c_28_occlusionTest = occlusionTest; + x11c_29_acoustics = acoustics; + x11c_30_worldSfx = worldSfx; + x11d_24_allowDuplicates = allowDuplicates; + if (x11c_30_worldSfx && (!x11c_26_nonEmitter || !x11c_25_looped)) + x11c_30_worldSfx = false; } void CScriptSound::Accept(IVisitor& visitor) { visitor.Visit(this); } @@ -44,11 +45,120 @@ void CScriptSound::PreThink(float dt, CStateManager& mgr) { CEntity::PreThink(dt, mgr); sFirstInFrame = true; - x11d_25_ = false; + x11d_25_processedThisFrame = false; +} + +static const CMaterialFilter kSolidFilter = + CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough}); + +float CScriptSound::GetOccludedVolumeAmount(const zeus::CVector3f& pos, const CStateManager& mgr) +{ + zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr); + zeus::CVector3f soundToCam = camXf.origin - pos; + float soundToCamMag = soundToCam.magnitude(); + zeus::CVector3f soundToCamNorm = soundToCam * (1.f / soundToCamMag); + zeus::CVector3f thirdEdge = zeus::CVector3f::skUp - soundToCamNorm * soundToCamNorm.dot(zeus::CVector3f::skUp); + zeus::CVector3f cross = soundToCamNorm.cross(thirdEdge); + static float kInfluenceAmount = 3.f / soundToCamMag; + static float kInfluenceIncrement = kInfluenceAmount; + + int totalCount = 0; + int invalCount = 0; + float f17 = -kInfluenceAmount; + while (f17 <= kInfluenceAmount) + { + zeus::CVector3f angledDir = thirdEdge * f17 + soundToCamNorm; + float f16 = -kInfluenceAmount; + while (f16 <= kInfluenceAmount) + { + if (mgr.RayStaticIntersection(pos, (cross * f16 + angledDir).normalized(), + soundToCamMag, kSolidFilter).IsInvalid()) + ++invalCount; + ++totalCount; + f16 += kInfluenceIncrement; + } + f17 += kInfluenceIncrement; + } + + return invalCount / float(totalCount) * 0.42f + 0.58f; } void CScriptSound::Think(float dt, CStateManager& mgr) { + if (x11c_31_selfFree && (!GetActive() || x11c_25_looped || !x11c_27_autoStart)) + { + mgr.FreeScriptObject(GetUniqueId()); + } + else if (GetActive()) + { + if (!x11c_25_looped && x11c_27_autoStart && !x11c_24_playRequested && + xec_sfxHandle && !CSfxManager::IsPlaying(xec_sfxHandle)) + mgr.FreeScriptObject(GetUniqueId()); + + if (!x11c_26_nonEmitter && xec_sfxHandle) + { + if (xf8_updateTimer <= 0.f) + { + xf8_updateTimer = 0.25f; + CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::CVector3f::skZero, xf2_maxVolUpd); + } + else + { + xf8_updateTimer -= dt; + } + } + + if (xec_sfxHandle && !x11c_26_nonEmitter && x11c_28_occlusionTest) + { + if (xe8_occUpdateTimer <= 0.f && sFirstInFrame) + { + sFirstInFrame = false; + float occVol = GetOccludedVolumeAmount(GetTranslation(), mgr); + float newMaxVol = std::max(occVol * x10e_vol, x10c_minVol); + if (newMaxVol != xf0_maxVol) + { + xf0_maxVol = newMaxVol; + float delta = xf0_maxVol - xf2_maxVolUpd; + xf4_maxVolUpdDelta = delta / 10.5f; + if (xf4_maxVolUpdDelta == 0.f) + { + if (xf2_maxVolUpd < xf0_maxVol) + xf4_maxVolUpdDelta = 1.f / 127.f; + else + xf4_maxVolUpdDelta = -1.f / 127.f; + } + } + xe8_occUpdateTimer = 0.5f; + } + else + { + xe8_occUpdateTimer -= dt; + } + + if (xf2_maxVolUpd != xf0_maxVol) + { + xf2_maxVolUpd += xf4_maxVolUpdDelta; + if (xf4_maxVolUpdDelta > 0.f && xf2_maxVolUpd > xf0_maxVol) + xf2_maxVolUpd = xf0_maxVol; + if (xf4_maxVolUpdDelta < 0.f && xf2_maxVolUpd < xf0_maxVol) + xf2_maxVolUpd = xf0_maxVol; + CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::CVector3f::skZero, xf2_maxVolUpd); + } + } + + if (x11c_24_playRequested) + { + xfc_startDelay -= dt; + if (xfc_startDelay <= 0.f) + { + x11c_24_playRequested = false; + PlaySound(mgr); + } + } + + if (x118_pitch != 0.f && xec_sfxHandle) + CSfxManager::PitchBend(xec_sfxHandle, x118_pitch); + } } void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) @@ -60,8 +170,8 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta case EScriptObjectMessage::Registered: { if (GetActive() && x11c_27_autoStart) - x11c_24_ = true; - x11c_31_ = mgr.GetIsGeneratingObject(); + x11c_24_playRequested = true; + x11c_31_selfFree = mgr.GetIsGeneratingObject(); } break; case EScriptObjectMessage::Play: @@ -85,12 +195,12 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta case EScriptObjectMessage::Activate: { if(GetActive()) - x11c_24_ = true; + x11c_24_playRequested = true; } break; case EScriptObjectMessage::Deleted: { - if (!x11c_30_) + if (!x11c_30_worldSfx) StopSound(mgr); } break; @@ -98,21 +208,52 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta } } -void CScriptSound::PlaySound(CStateManager&) +void CScriptSound::PlaySound(CStateManager& mgr) { + if ((x11d_24_allowDuplicates || !xec_sfxHandle) && !x11d_25_processedThisFrame) + { + x11d_25_processedThisFrame = true; + if (x11c_26_nonEmitter) + { + if (!x11c_30_worldSfx || !mgr.GetWorld()->HasGlobalSound(x100_soundId)) + { + xec_sfxHandle = CSfxManager::SfxStart(x100_soundId, x10e_vol, x114_pan, + x11c_29_acoustics, x112_prio, x11c_25_looped, + x11c_30_worldSfx ? kInvalidAreaId : GetAreaIdAlways()); + if (x11c_30_worldSfx) + mgr.WorldNC()->AddGlobalSound(xec_sfxHandle); + } + } + else + { + float occVol = x11c_28_occlusionTest ? GetOccludedVolumeAmount(GetTranslation(), mgr) : 1.f; + xf0_maxVol = xf2_maxVolUpd = x10e_vol * occVol; + CAudioSys::C3DEmitterParmData data = {}; + data.x0_pos = GetTranslation(); + data.x18_maxDist = x104_maxDist; + data.x1c_distComp = x108_distComp; + data.x20_flags = 1; // Continuous parameter update + data.x24_sfxId = x100_soundId; + data.x26_maxVol = xf0_maxVol; + data.x27_minVol = x10c_minVol; + data.x29_prio = 0x7f; + xec_sfxHandle = CSfxManager::AddEmitter(data, x11c_29_acoustics, x112_prio, + x11c_25_looped, GetAreaIdAlways()); + } + } } void CScriptSound::StopSound(CStateManager& mgr) { - x11c_24_ = false; - if (x11c_30_ && x11c_26_) + x11c_24_playRequested = false; + if (x11c_30_worldSfx && x11c_26_nonEmitter) { - mgr.WorldNC()->StopSound(x100_soundId); + mgr.WorldNC()->StopGlobalSound(x100_soundId); xec_sfxHandle.reset(); } else if (xec_sfxHandle) { - CSfxManager::RemoveEmitter(*xec_sfxHandle.get()); + CSfxManager::RemoveEmitter(xec_sfxHandle); xec_sfxHandle.reset(); } } diff --git a/Runtime/World/CScriptSound.hpp b/Runtime/World/CScriptSound.hpp index be04b543e..4dcec8cac 100644 --- a/Runtime/World/CScriptSound.hpp +++ b/Runtime/World/CScriptSound.hpp @@ -10,50 +10,54 @@ class CScriptSound : public CActor { static bool sFirstInFrame; - float xe8_ = 0.f; - std::unique_ptr xec_sfxHandle; - s16 xf0_ = 0; - s16 xf4_ = 0; - float xf8_ = 0.f; - float xfc_; - s16 x100_soundId; - float x104_; - float x108_; - s16 x10c_; - s16 x10e_; + float xe8_occUpdateTimer = 0.f; + CSfxHandle xec_sfxHandle; + float xf0_maxVol = 0.f; + float xf2_maxVolUpd = 0.f; + float xf4_maxVolUpdDelta = 0.f; + float xf8_updateTimer = 0.f; + float xfc_startDelay; + u16 x100_soundId; + float x104_maxDist; + float x108_distComp; + float x10c_minVol; + float x10e_vol; s16 x110_; - s16 x112_; - s16 x114_; + s16 x112_prio; + float x114_pan; bool x116_; - u32 x118_; + float x118_pitch; union { struct { - bool x11c_24_ : 1; - bool x11c_25_ : 1; - bool x11c_26_ : 1; + bool x11c_24_playRequested : 1; + bool x11c_25_looped : 1; + bool x11c_26_nonEmitter : 1; bool x11c_27_autoStart : 1; - bool x11c_28_ : 1; - bool x11c_29_ : 1; - bool x11c_30_ : 1; - bool x11c_31_ : 1; - bool x11d_24_ : 1; - bool x11d_25_ : 1; + bool x11c_28_occlusionTest : 1; + bool x11c_29_acoustics : 1; + bool x11c_30_worldSfx : 1; + bool x11c_31_selfFree : 1; + bool x11d_24_allowDuplicates : 1; + bool x11d_25_processedThisFrame : 1; }; u32 x11c_dummy = 0; }; + static float GetOccludedVolumeAmount(const zeus::CVector3f& pos, const CStateManager& mgr); + public: - CScriptSound(TUniqueId, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, s16 soundId, - bool, float, float, float, u32, u32, u32, u32, u32, u32, bool, bool, bool, bool, bool, bool, bool, u32); + CScriptSound(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, + u16 soundId, bool active, float maxDist, float distComp, float startDelay, u32 minVol, + u32 vol, u32 w3, u32 prio, u32 pan, u32 w6, bool looped, bool nonEmitter, bool autoStart, + bool occlusionTest, bool acoustics, bool worldSfx, bool allowDuplicates, s32 pitch); void Accept(IVisitor& visitor); void AddToRenderer(const zeus::CFrustum&, const CStateManager&) const {} void PreThink(float, CStateManager&); void Think(float, CStateManager&); void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); - void GetOccludedVolumeAmount(const zeus::CVector3f&, const CStateManager&); void PlaySound(CStateManager&); void StopSound(CStateManager&); }; diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index 07f4b1863..901bba485 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -6,6 +6,9 @@ #include "CGameState.hpp" #include "Graphics/CBooRenderer.hpp" #include "World/CScriptAreaAttributes.hpp" +#include "IMain.hpp" +#include "Audio/CStreamAudioManager.hpp" +#include "CScriptRoomAcoustics.hpp" namespace urde { @@ -175,8 +178,6 @@ bool CDummyWorld::ICheckWorldComplete() default: return false; } - - return false; } std::string CDummyWorld::IGetDefaultAudioTrack() const { return {}; } @@ -192,6 +193,18 @@ CWorld::CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId) resFactory.LoadResourceAsync(tag, x40_loadBuf.get()); } +CWorld::~CWorld() +{ + StopSounds(); + if (g_GameState->GetWorldTransitionManager()->IsTransitionEnabled() && + g_Main->GetFlowState() == EFlowState::None) + CStreamAudioManager::StopOneShot(); + else + CStreamAudioManager::StopAll(); + UnloadSoundGroups(); + CScriptRoomAcoustics::DisableAuxCallbacks(); +} + CAssetId CWorld::IGetWorldAssetId() const { return x8_mlvlId; } CAssetId CWorld::IGetStringTableAssetId() const { return xc_strgId; } @@ -242,10 +255,35 @@ void CWorld::MoveAreaToAliveChain(TAreaId aid) MoveToChain(x18_areas[aid].get(), EChain::Alive); } -void CWorld::LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data) {} +void CWorld::LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data) +{ + if (!CAudioSys::SysLoadGroupSet(g_SimplePool, agscId)) + { + auto name = CAudioSys::SysGetGroupSetName(agscId); + CAudioSys::SysAddGroupIntoAmuse(name); + data.xc_name = name; + ++x6c_loadedAudioGrpCount; + } +} void CWorld::LoadSoundGroups() {} +void CWorld::UnloadSoundGroups() +{ + for (CSoundGroupData& data : x74_soundGroupData) + { + CAudioSys::SysRemoveGroupFromAmuse(data.xc_name); + CAudioSys::SysUnloadAudioGroupSet(data.xc_name); + } +} + +void CWorld::StopSounds() +{ + for (CSfxHandle& hnd : xc8_globalSfxHandles) + CSfxManager::RemoveEmitter(hnd); + xc8_globalSfxHandles.clear(); +} + bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId) { if (mreaId.IsValid()) @@ -654,12 +692,10 @@ void CWorld::PreRender() void CWorld::TouchSky() { -#if 0 - if (xa4_skyboxB.IsLoaded()) - xa4_skyboxB->Touch(); - if (xb4_skyboxC.IsLoaded()) - xb4_skyboxC->Touch(); -#endif + if (xa4_skyboxWorldLoaded.IsLoaded()) + xa4_skyboxWorldLoaded->Touch(0); + if (xb4_skyboxOverride.IsLoaded()) + xb4_skyboxOverride->Touch(0); } void CWorld::DrawSky(const zeus::CTransform& xf) const @@ -686,7 +722,28 @@ void CWorld::DrawSky(const zeus::CTransform& xf) const CGraphics::SetDepthRange(0.125f, 1.f); } -void CWorld::StopSound(s16) +void CWorld::StopGlobalSound(u16 id) { + auto search = std::find_if(xc8_globalSfxHandles.begin(), xc8_globalSfxHandles.end(), + [id](CSfxHandle& hnd) { return hnd->GetSfxId() == id; }); + if (search != xc8_globalSfxHandles.end()) + { + CSfxManager::RemoveEmitter(*search); + xc8_globalSfxHandles.erase(search); + } +} + +bool CWorld::HasGlobalSound(u16 id) const +{ + auto search = std::find_if(xc8_globalSfxHandles.begin(), xc8_globalSfxHandles.end(), + [id](const CSfxHandle& hnd) { return hnd->GetSfxId() == id; }); + return search != xc8_globalSfxHandles.end(); +} + +void CWorld::AddGlobalSound(const CSfxHandle& hnd) +{ + if (xc8_globalSfxHandles.size() >= xc8_globalSfxHandles.capacity()) + return; + xc8_globalSfxHandles.push_back(hnd); } } diff --git a/Runtime/World/CWorld.hpp b/Runtime/World/CWorld.hpp index 3b838e5a4..4cecd2df0 100644 --- a/Runtime/World/CWorld.hpp +++ b/Runtime/World/CWorld.hpp @@ -129,7 +129,7 @@ private: IObjectStore& x60_objectStore; IFactory& x64_resFactory; TAreaId x68_curAreaId = kInvalidAreaId; - u32 x6c_ = 0; + u32 x6c_loadedAudioGrpCount = 0; union { @@ -148,10 +148,12 @@ private: TLockedToken xa4_skyboxWorldLoaded; TLockedToken xb4_skyboxOverride; EEnvFxType xc4_neededFx = EEnvFxType::None; - std::vector xc8_sfxHandles; + rstl::reserved_vector xc8_globalSfxHandles; void LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data); void LoadSoundGroups(); + void UnloadSoundGroups(); + void StopSounds(); public: @@ -169,6 +171,7 @@ public: void SetPauseState(bool paused); CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId); + ~CWorld(); bool DoesAreaExist(TAreaId area) const; const std::vector>& GetGameAreas() const { return x18_areas; } @@ -200,7 +203,9 @@ public: void PreRender(); void TouchSky(); void DrawSky(const zeus::CTransform& xf) const; - void StopSound(s16); + void StopGlobalSound(u16 id); + bool HasGlobalSound(u16 id) const; + void AddGlobalSound(const CSfxHandle& hnd); EEnvFxType GetNeededEnvFx() const { return xc4_neededFx; } }; diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index 41be8258a..318da1a2d 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -667,28 +667,28 @@ CEntity* ScriptLoader::LoadSound(CStateManager& mgr, CInputStream& in, int propC SActorHead head = LoadActorHead(in, mgr); s32 soundId = in.readInt32Big(); bool active = in.readBool(); - float maxDistance = in.readFloatBig(); - float minDistance = in.readFloatBig(); - float f3 = in.readFloatBig(); - u32 priority = in.readUint32Big(); - u32 maxVolume = in.readUint32Big(); - u32 minVolume = in.readUint32Big(); - u32 panning = in.readUint32Big(); + float maxDist = in.readFloatBig(); + float distComp = in.readFloatBig(); + float startDelay = in.readFloatBig(); + u32 minVol = in.readUint32Big(); + u32 vol = in.readUint32Big(); + u32 prio = in.readUint32Big(); + u32 pan = in.readUint32Big(); bool loop = in.readBool(); - bool persistent = in.readBool(); - bool triggered = in.readBool(); - bool b4 = in.readBool(); - bool roomAcoustic = in.readBool(); - bool b6 = in.readBool(); - bool b7 = in.readBool(); - u32 w5 = in.readUint32Big(); + bool nonEmitter = in.readBool(); + bool autoStart = in.readBool(); + bool occlusionTest = in.readBool(); + bool acoustics = in.readBool(); + bool worldSfx = in.readBool(); + bool allowDuplicates = in.readBool(); + u32 pitch = in.readUint32Big(); if (soundId < 0) return nullptr; - return new CScriptSound(mgr.AllocateUniqueId(), head.x0_name, info, head.x10_transform, soundId, active, - maxDistance, minDistance, f3, priority, maxVolume, 0, minVolume, panning, 0, loop, - persistent, triggered, b4, roomAcoustic, b6, b7, w5); + return new CScriptSound(mgr.AllocateUniqueId(), head.x0_name, info, head.x10_transform, u16(soundId), active, + maxDist, distComp, startDelay, minVol, vol, 0, prio, pan, 0, loop, + nonEmitter, autoStart, occlusionTest, acoustics, worldSfx, allowDuplicates, pitch); } CEntity* ScriptLoader::LoadGenerator(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) diff --git a/Runtime/World/ScriptObjectSupport.cpp b/Runtime/World/ScriptObjectSupport.cpp index f43afead8..6126f6acc 100644 --- a/Runtime/World/ScriptObjectSupport.cpp +++ b/Runtime/World/ScriptObjectSupport.cpp @@ -216,17 +216,17 @@ std::string_view ScriptObjectMessageToStr(EScriptObjectMessage message) case EScriptObjectMessage::OnIceSurface: return "OnIceSurface"sv; case EScriptObjectMessage::OnMudSlowSurface: return "OnMudSlowSurface"sv; case EScriptObjectMessage::OnNormalSurface: return "OnNormalSurface"sv; - case EScriptObjectMessage::InternalMessage08: return "InternalMessage08"sv; + case EScriptObjectMessage::Touched: return "Touched"sv; case EScriptObjectMessage::AddPlatformRider: return "AddPlatformRider"sv; case EScriptObjectMessage::LandOnNotFloor: return "LandOnNotFloor"sv; case EScriptObjectMessage::Registered: return "Registered"sv; case EScriptObjectMessage::Deleted: return "Deleted"sv; case EScriptObjectMessage::InitializedInArea: return "InitializedInArea"sv; - case EScriptObjectMessage::InternalMessage14: return "InternalMessage14"sv; + case EScriptObjectMessage::WorldInitialized: return "WorldInitialized"sv; case EScriptObjectMessage::AddSplashInhabitant: return "AddSplashInhabitant"sv; case EScriptObjectMessage::UpdateSplashInhabitant: return "UpdateSplashInhabitant"sv; case EScriptObjectMessage::RemoveSplashInhabitant: return "RemoveSplashInhabitant"sv; - case EScriptObjectMessage::InternalMessage18: return "InternalMessage18"sv; + case EScriptObjectMessage::Jumped: return "Jumped"sv; case EScriptObjectMessage::Damage: return "Damage"sv; case EScriptObjectMessage::InvulnDamage: return "InvulnDamage"sv; case EScriptObjectMessage::ProjectileCollide: return "ProjectileCollide"sv; @@ -234,7 +234,7 @@ std::string_view ScriptObjectMessageToStr(EScriptObjectMessage message) case EScriptObjectMessage::AddPhazonPoolInhabitant: return "AddPhazonPoolInhabitant"sv; case EScriptObjectMessage::UpdatePhazonPoolInhabitant: return "UpdatePhazonPoolInhabitant"sv; case EScriptObjectMessage::RemovePhazonPoolInhabitant: return "RemovePhazonPoolInhabitant"sv; - case EScriptObjectMessage::InternalMessage26: return "InternalMessage26"sv; + case EScriptObjectMessage::SuspendedMove: return "SuspendedMove"sv; default: return "..."sv; } } diff --git a/Runtime/World/ScriptObjectSupport.hpp b/Runtime/World/ScriptObjectSupport.hpp index 8a2f83eb1..3463cba86 100644 --- a/Runtime/World/ScriptObjectSupport.hpp +++ b/Runtime/World/ScriptObjectSupport.hpp @@ -209,17 +209,17 @@ enum class EScriptObjectMessage OnIceSurface = 27, OnMudSlowSurface = 28, OnNormalSurface = 29, - InternalMessage08 = 30, + Touched = 30, AddPlatformRider = 31, LandOnNotFloor = 32, Registered = 33, Deleted = 34, InitializedInArea = 35, - InternalMessage14 = 36, + WorldInitialized = 36, AddSplashInhabitant = 37, UpdateSplashInhabitant = 38, RemoveSplashInhabitant = 39, - InternalMessage18 = 40, + Jumped = 40, Damage = 41, InvulnDamage = 42, ProjectileCollide = 43, @@ -227,7 +227,7 @@ enum class EScriptObjectMessage AddPhazonPoolInhabitant = 45, UpdatePhazonPoolInhabitant = 46, RemovePhazonPoolInhabitant = 47, - InternalMessage26 = 48 + SuspendedMove = 48 }; #ifndef NDEBUG diff --git a/amuse b/amuse index cab740210..ebe6f1889 160000 --- a/amuse +++ b/amuse @@ -1 +1 @@ -Subproject commit cab740210479ae8f5090ec847dfc4dd76c816dac +Subproject commit ebe6f18898411aa8fa6aa6f5556333e463bbfff9