Index: binaries/data/mods/public/gui/session/Ambient.js
===================================================================
--- binaries/data/mods/public/gui/session/Ambient.js
+++ binaries/data/mods/public/gui/session/Ambient.js
@@ -5,7 +5,7 @@
{
constructor()
{
- Engine.PlayAmbientSound(pickRandom(this.Tracks), true);
+ // Engine.PlayAmbientSound(pickRandom(this.Tracks), true);
}
}
Index: binaries/data/mods/public/simulation/components/Sound.js
===================================================================
--- binaries/data/mods/public/simulation/components/Sound.js
+++ binaries/data/mods/public/simulation/components/Sound.js
@@ -8,6 +8,7 @@
"actor/human/movement/walk.xml" +
"attack/weapon/sword.xml" +
"actor/human/death/death.xml" +
+ "ambient/water/river_slow.xml" +
"" +
"" +
"" +
@@ -21,6 +22,7 @@
Sound.prototype.Init = function()
{
+ this.hasAmbientEmitter = !!this.template.SoundGroups.ambientEmitter;
};
Sound.prototype.Serialize = null; // we have no dynamic state to save
@@ -50,4 +52,37 @@
}
};
+Sound.prototype.OnOwnershipChanged = function(msg)
+{
+ if (!this.hasAmbientEmitter || msg.to != INVALID_PLAYER)
+ return;
+
+ let cmpSoundManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager);
+ cmpSoundManager.RemoveAmbientEmitter(this.entity);
+ this.emitsAmbientSound = false;
+};
+
+// This may be performace-intensive for moving ents with ambient emitters
+Sound.prototype.OnPositionChanged = function(msg)
+{
+ if (!this.hasAmbientEmitter || !msg.inWorld)
+ return;
+
+ if (this.emitsAmbientSound) {
+ let cmpSoundManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager);
+ cmpSoundManager.UpdateAmbientEmitterPosition(this.entity);
+ }
+ else
+ this.AddAmbientEmitter();
+
+};
+
+Sound.prototype.AddAmbientEmitter = function()
+{
+ let cmpSoundManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager);
+ this.emitsAmbientSound = cmpSoundManager.AddAmbientEmitter(this.template.SoundGroups.ambientEmitter, this.entity);
+}
+
+
+
Engine.RegisterComponentType(IID_Sound, "Sound", Sound);
Index: source/simulation2/components/CCmpSoundManager.cpp
===================================================================
--- source/simulation2/components/CCmpSoundManager.cpp
+++ source/simulation2/components/CCmpSoundManager.cpp
@@ -80,14 +80,14 @@
if (cmpOwnership)
playerOwned = cmpOwnership->GetOwner() == currentPlayer;
- CVector3D sourcePos = CVector3D(cmpPosition->GetPosition());
- g_SoundManager->PlayAsGroup(name, sourcePos, source, playerOwned);
+ g_SoundManager->PlayAsGroup(name, CVector3D(cmpPosition->GetPosition()), source, playerOwned);
}
virtual void PlaySoundGroupAtPosition(const std::wstring& name, const CFixedVector3D& sourcePos)
{
if (!g_SoundManager)
return;
+
g_SoundManager->PlayAsGroup(name, CVector3D(sourcePos), INVALID_ENTITY, false);
}
@@ -98,6 +98,36 @@
g_SoundManager->Pause(true);
}
+ virtual bool AddAmbientEmitter(const VfsPath& name, entity_id_t source)
+ {
+ if (!g_SoundManager)
+ return false;
+
+ CmpPtr cmpPosition(GetSimContext(), source);
+ if (!cmpPosition || !cmpPosition->IsInWorld())
+ return false;
+
+ return g_SoundManager->AddAmbientEmitter(name, CVector3D(cmpPosition->GetPosition()), source);
+ }
+
+ virtual void RemoveAmbientEmitter(entity_id_t source)
+ {
+ if (!g_SoundManager)
+ return;
+ g_SoundManager->RemoveAmbientEmitter(source);
+ }
+
+ virtual void UpdateAmbientEmitterPosition(entity_id_t source)
+ {
+ if (!g_SoundManager)
+ return;
+
+ CmpPtr cmpPosition(GetSimContext(), source);
+ if (!cmpPosition || !cmpPosition->IsInWorld())
+ return;
+
+ g_SoundManager->UpdateAmbientEmitterPosition(source, CVector3D(cmpPosition->GetPosition()));
+ }
};
REGISTER_COMPONENT_TYPE(SoundManager)
Index: source/simulation2/components/ICmpSoundManager.h
===================================================================
--- source/simulation2/components/ICmpSoundManager.h
+++ source/simulation2/components/ICmpSoundManager.h
@@ -42,6 +42,12 @@
*/
virtual void PlaySoundGroupAtPosition(const std::wstring& name, const CFixedVector3D& sourcePos) = 0;
+ virtual bool AddAmbientEmitter(const VfsPath& name, entity_id_t source) = 0;
+
+ virtual void RemoveAmbientEmitter(entity_id_t source) = 0;
+
+ virtual void UpdateAmbientEmitterPosition(entity_id_t source) = 0;
+
virtual void StopMusic() = 0;
DECLARE_INTERFACE_TYPE(SoundManager)
Index: source/simulation2/components/ICmpSoundManager.cpp
===================================================================
--- source/simulation2/components/ICmpSoundManager.cpp
+++ source/simulation2/components/ICmpSoundManager.cpp
@@ -25,4 +25,7 @@
DEFINE_INTERFACE_METHOD_2("PlaySoundGroup", void, ICmpSoundManager, PlaySoundGroup, std::wstring, entity_id_t)
DEFINE_INTERFACE_METHOD_2("PlaySoundGroupAtPosition", void, ICmpSoundManager, PlaySoundGroupAtPosition, std::wstring, CFixedVector3D)
DEFINE_INTERFACE_METHOD_0("StopMusic", void, ICmpSoundManager, StopMusic)
+DEFINE_INTERFACE_METHOD_2("AddAmbientEmitter", bool, ICmpSoundManager, AddAmbientEmitter, VfsPath, entity_id_t)
+DEFINE_INTERFACE_METHOD_1("RemoveAmbientEmitter", void, ICmpSoundManager, RemoveAmbientEmitter, entity_id_t)
+DEFINE_INTERFACE_METHOD_1("UpdateAmbientEmitterPosition", void, ICmpSoundManager, UpdateAmbientEmitterPosition, entity_id_t)
END_INTERFACE_WRAPPER(SoundManager)
Index: source/soundmanager/ISoundManager.h
===================================================================
--- source/soundmanager/ISoundManager.h
+++ source/soundmanager/ISoundManager.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -49,6 +49,10 @@
virtual void PlayAsAmbient(const VfsPath& itemPath, bool looping) = 0;
virtual void PlayAsGroup(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source, bool ownedSound) = 0;
+ virtual bool AddAmbientEmitter(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source) = 0;
+ virtual void RemoveAmbientEmitter(entity_id_t source) = 0;
+ virtual void UpdateAmbientEmitterPosition(entity_id_t source, const CVector3D& sourcePos) = 0;
+
virtual bool InDistress() = 0;
};
Index: source/soundmanager/SoundManager.h
===================================================================
--- source/soundmanager/SoundManager.h
+++ source/soundmanager/SoundManager.h
@@ -64,6 +64,12 @@
ALSourceHolder* m_ALSourceBuffer;
ISoundItem* m_CurrentTune;
ISoundItem* m_CurrentEnvirons;
+ struct SAmbientEmitterData {
+ ISoundItem* soundItem;
+ CVector3D position;
+ entity_id_t id;
+ };
+ std::vector m_AmbientEmitters;
CSoundManagerWorker* m_Worker;
std::mutex m_DistressMutex;
PlayList* m_PlayListItems;
@@ -139,7 +145,7 @@
void PlayAsAmbient(const VfsPath& itemPath, bool looping);
void PlayAsUI(const VfsPath& itemPath, bool looping);
void PlayAsGroup(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source, bool ownedSound);
-
+ CSoundGroup* GetSoundGroup(const VfsPath& groupPath);
void PlayGroupItem(ISoundItem* anItem, ALfloat groupGain);
bool InDistress();
@@ -149,6 +155,7 @@
void Pause(bool pauseIt);
void PauseMusic(bool pauseIt);
void PauseAmbient(bool pauseIt);
+ void PauseAmbientEmitters(bool pause);
void PauseAction(bool pauseIt);
void SetAmbientItem(ISoundItem* anItem);
@@ -158,6 +165,11 @@
void SetActionGain(float gain);
void SetUIGain(float gain);
+ float GetAmbientEmitterGain(const CVector3D& emitterPos) const;
+ bool AddAmbientEmitter(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source);
+ void RemoveAmbientEmitter(entity_id_t source);
+ void UpdateAmbientEmitterPosition(entity_id_t source, const CVector3D& sourcePos);
+
protected:
void InitListener();
Status AlcInit();
Index: source/soundmanager/SoundManager.cpp
===================================================================
--- source/soundmanager/SoundManager.cpp
+++ source/soundmanager/SoundManager.cpp
@@ -24,11 +24,13 @@
#include "items/CSoundItem.h"
#include "items/CStreamItem.h"
+#include "graphics/GameView.h"
#include "lib/external_libraries/libsdl.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "ps/ConfigDB.h"
#include "ps/Filesystem.h"
+#include "ps/Game.h"
#include "ps/Profiler2.h"
#include "ps/XML/Xeromyces.h"
@@ -586,6 +588,13 @@
if (m_CurrentEnvirons)
m_CurrentEnvirons->EnsurePlay();
+ if (g_Game && g_Game->GetView())
+ for (const SAmbientEmitterData& ambientEmitter : m_AmbientEmitters)
+ {
+ ambientEmitter.soundItem->EnsurePlay();
+ ambientEmitter.soundItem->SetGain(GetAmbientEmitterGain(ambientEmitter.position));
+ }
+
if (m_Worker)
m_Worker->CleanupItems();
}
@@ -638,7 +647,7 @@
m_MusicEnabled = isEnabled;
}
-void CSoundManager::PlayAsGroup(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source, bool ownedSound)
+CSoundGroup* CSoundManager::GetSoundGroup(const VfsPath& groupPath)
{
// Make sure the sound group is loaded
CSoundGroup* group;
@@ -649,7 +658,7 @@
{
LOGERROR("Failed to load sound group '%s'", groupPath.string8());
delete group;
- group = NULL;
+ group = nullptr;
}
// Cache the sound group (or the null, if it failed)
m_SoundGroups[groupPath.string()] = group;
@@ -659,11 +668,90 @@
group = m_SoundGroups[groupPath.string()];
}
+ return group;
+}
+
+void CSoundManager::PlayAsGroup(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source, bool ownedSound)
+{
+ CSoundGroup* group = GetSoundGroup(groupPath);
// Failed to load group -> do nothing
if (group && (ownedSound || !group->TestFlag(eOwnerOnly)))
group->PlayNext(sourcePos, source);
}
+float CSoundManager::GetAmbientEmitterGain(const CVector3D& emitterPos) const
+{
+ const CVector3D& cameraPos = g_Game->GetView()->GetCameraPosition();
+ float itemDist = (emitterPos - cameraPos).Length();
+ return std::max(1.0f - itemDist / 200.f, 0.f); // TODO: Use something better
+}
+
+bool CSoundManager::AddAmbientEmitter(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source)
+{
+ if (!m_Enabled)
+ return false;
+
+ CSoundGroup* group = GetSoundGroup(groupPath);
+ if (!group)
+ return false;
+
+ CSoundData* sndData = group->GetRandomSound();
+ if (!sndData)
+ return false;
+
+ ISoundItem* ambientItem = static_cast(g_SoundManager)->ItemForEntity(source, sndData);
+ if (!ambientItem)
+ return false;
+
+ // Use the ambient gain config option for ambient emitters
+ if (m_AmbientGain > 0.0f)
+ {
+ ambientItem->SetGain(group->GetGain());
+ ambientItem->PlayLoop();
+ }
+
+ SAmbientEmitterData ambientEmitter;
+ ambientEmitter.soundItem = ambientItem;
+ ambientEmitter.position = sourcePos;
+ ambientEmitter.id = source;
+
+ m_AmbientEmitters.emplace_back(ambientEmitter);
+
+ return true;
+}
+
+void CSoundManager::RemoveAmbientEmitter(entity_id_t source)
+{
+ for (const SAmbientEmitterData& ambientEmitter : m_AmbientEmitters)
+ {
+ if (ambientEmitter.id == source)
+ {
+ ambientEmitter.soundItem->FadeAndDelete(3.00);
+ break;
+ }
+ }
+
+ m_AmbientEmitters.erase(
+ std::remove_if(m_AmbientEmitters.begin(), m_AmbientEmitters.end(),
+ [&](SAmbientEmitterData& emitterData)
+ {
+ return emitterData.id == source;
+ }
+ ), m_AmbientEmitters.end());
+}
+
+void CSoundManager::UpdateAmbientEmitterPosition(entity_id_t source, const CVector3D& sourcePos)
+{
+ for (SAmbientEmitterData& ambientEmitter : m_AmbientEmitters)
+ {
+ if (ambientEmitter.id == source)
+ {
+ ambientEmitter.position = sourcePos;
+ break;
+ }
+ }
+}
+
void CSoundManager::PlayAsMusic(const VfsPath& itemPath, bool looping)
{
if (m_Enabled)
@@ -712,6 +800,7 @@
PauseMusic(pauseIt);
PauseAmbient(pauseIt);
PauseAction(pauseIt);
+ PauseAmbientEmitters(pauseIt);
}
void CSoundManager::PauseMusic(bool pauseIt)
@@ -739,6 +828,13 @@
m_AmbientPaused = pauseIt;
}
+void CSoundManager::PauseAmbientEmitters(bool pause)
+{
+ for (SAmbientEmitterData& emitterData : m_AmbientEmitters)
+ if (emitterData.soundItem)
+ pause ? emitterData.soundItem->Pause() : emitterData.soundItem->Resume();
+}
+
void CSoundManager::PauseAction(bool pauseIt)
{
m_ActionPaused = pauseIt;
Index: source/soundmanager/scripting/SoundGroup.h
===================================================================
--- source/soundmanager/scripting/SoundGroup.h
+++ source/soundmanager/scripting/SoundGroup.h
@@ -60,8 +60,11 @@
// Load a group
bool LoadSoundGroup(const VfsPath& pathnameXML);
+ CSoundData* CSoundGroup::GetRandomSound();
void Reload();
+ float GetGain() const;
+
// Release all remaining loaded handles
void ReleaseGroup();
@@ -77,7 +80,7 @@
private:
void SetGain(float gain);
- void UploadPropertiesAndPlay(size_t theIndex, const CVector3D& position, entity_id_t source);
+ void UploadPropertiesAndPlay(const CVector3D& position, entity_id_t source);
void SetDefaultValues();
#if CONFIG2_AUDIO
Index: source/soundmanager/scripting/SoundGroup.cpp
===================================================================
--- source/soundmanager/scripting/SoundGroup.cpp
+++ source/soundmanager/scripting/SoundGroup.cpp
@@ -140,7 +140,21 @@
return answer;
}
-void CSoundGroup::UploadPropertiesAndPlay(size_t index, const CVector3D& position, entity_id_t source)
+CSoundData* CSoundGroup::GetRandomSound()
+{
+ m_CurrentSoundIndex = rand(0, m_Filenames.size());
+
+ if (m_SoundGroups.empty())
+ Reload();
+
+ if (m_SoundGroups.size() <= m_CurrentSoundIndex)
+ return nullptr;
+
+ return m_SoundGroups[m_CurrentSoundIndex];
+}
+
+
+void CSoundGroup::UploadPropertiesAndPlay(const CVector3D& position, entity_id_t source)
{
#if !CONFIG2_AUDIO
UNUSED2(index);
@@ -150,6 +164,10 @@
if (!g_SoundManager)
return;
+ CSoundData* sndData = GetRandomSound();
+ if (!sndData)
+ return;
+
bool isOnscreen = false;
ALfloat itemRollOff = 0.1f;
float offset = RadiansOffCenter(position, isOnscreen, itemRollOff);
@@ -157,16 +175,6 @@
if (!isOnscreen && !TestFlag(eDistanceless) && !TestFlag(eOmnipresent))
return;
- if (m_SoundGroups.empty())
- Reload();
-
- if (m_SoundGroups.size() <= index)
- return;
-
- CSoundData* sndData = m_SoundGroups[index];
- if (!sndData)
- return;
-
ISoundItem* hSound = static_cast(g_SoundManager)->ItemForEntity(source, sndData);
if (!hSound)
return;
@@ -218,8 +226,7 @@
if (m_Filenames.empty())
return;
- m_CurrentSoundIndex = rand(0, m_Filenames.size());
- UploadPropertiesAndPlay(m_CurrentSoundIndex, position, source);
+ UploadPropertiesAndPlay(position, source);
}
void CSoundGroup::Reload()
@@ -246,6 +253,11 @@
#endif
}
+float CSoundGroup::GetGain() const
+{
+ return m_Gain;
+}
+
void CSoundGroup::ReleaseGroup()
{
#if CONFIG2_AUDIO