Skip to content

Commit

Permalink
Implement bomb beep sound visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkrupinski committed Nov 16, 2023
1 parent ff84d56 commit ee1473b
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Source/CS2/Constants/SoundNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ namespace cs2
#if IS_WIN64()
constexpr std::string_view kPlayerFootstepSoundsPath = "sounds\\player\\footsteps\\";
constexpr std::string_view kBombPlantSoundPath = "sounds\\weapons\\c4\\c4_initiate.vsnd";
constexpr std::string_view kBombSoundsPath = "sounds\\weapons\\c4\\";
#elif IS_LINUX()
constexpr std::string_view kPlayerFootstepSoundsPath = "sounds/player/footsteps/";
constexpr std::string_view kBombPlantSoundPath = "sounds/weapons/c4/c4_initiate.vsnd";
constexpr std::string_view kBombSoundsPath = "sounds/weapons/c4/";
#endif

constexpr std::string_view kPlayerSuitSoundPrefix = "suit";
constexpr std::string_view kBombBeepSoundsPrefix = "c4_beep";

}
16 changes: 11 additions & 5 deletions Source/FeatureHelpers/FeatureHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,38 @@
#include "Hud/BombTimerHelpers.h"
#include "Hud/DefusingAlertHelpers.h"
#include "Hud/KillfeedPreserverHelpers.h"
#include "Sound/BombBeepVisualizerHelpers.h"
#include "Sound/BombPlantVisualizerHelpers.h"
#include "Sound/FootstepVisualizerHelpers.h"
#include "WorldToClipSpaceConverter.h"

struct FeatureHelpers {
[[nodiscard]] BombPlantVisualizerHelpers getBombPlantVisualizerHelpers() noexcept
[[nodiscard]] BombBeepVisualizerHelpers getBombBeepVisualizerHelpers() const noexcept
{
return BombBeepVisualizerHelpers{ HudInWorldPanelFactory{hudProvider}, globalVarsProvider, transformFactory, worldtoClipSpaceConverter };
}

[[nodiscard]] BombPlantVisualizerHelpers getBombPlantVisualizerHelpers() const noexcept
{
return BombPlantVisualizerHelpers{ HudInWorldPanelFactory{hudProvider}, globalVarsProvider, transformFactory, worldtoClipSpaceConverter };
}

[[nodiscard]] FootstepVisualizerHelpers getFootstepVisualizerHelpers() noexcept
[[nodiscard]] FootstepVisualizerHelpers getFootstepVisualizerHelpers() const noexcept
{
return FootstepVisualizerHelpers{ HudInWorldPanelFactory{hudProvider}, globalVarsProvider, transformFactory, worldtoClipSpaceConverter };
}

[[nodiscard]] BombTimerHelpers getBombTimerHelpers() noexcept
[[nodiscard]] BombTimerHelpers getBombTimerHelpers() const noexcept
{
return BombTimerHelpers{ plantedC4Provider, hudProvider, globalVarsProvider };
}

[[nodiscard]] DefusingAlertHelpers getDefusingAlertHelpers() noexcept
[[nodiscard]] DefusingAlertHelpers getDefusingAlertHelpers() const noexcept
{
return DefusingAlertHelpers{ plantedC4Provider, hudProvider, globalVarsProvider };
}

[[nodiscard]] KillfeedPreserverHelpers getKillfeedPreserverHelpers() noexcept
[[nodiscard]] KillfeedPreserverHelpers getKillfeedPreserverHelpers() const noexcept
{
return KillfeedPreserverHelpers{ hudProvider, globalVarsProvider };
}
Expand Down
31 changes: 31 additions & 0 deletions Source/FeatureHelpers/Sound/BombBeepSound.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <algorithm>
#include <cassert>
#include <string_view>

#include <CS2/Constants/SoundNames.h>

struct BombBeepSound {
static constexpr auto kFadeAwayStart = 0.0f;
static constexpr auto kFadeAwayDuration = 0.3f;

[[nodiscard]] static constexpr float getScale(float clipSpaceZ) noexcept
{
return (std::max)(1.0f - clipSpaceZ / 1000.0f, 0.4f);
}

[[nodiscard]] static constexpr float getOpacity(float timeAlive) noexcept
{
if (timeAlive >= kFadeAwayStart) {
return 1.0f - (std::min)((timeAlive - kFadeAwayStart) / kFadeAwayDuration, 1.0f);
} else {
return 1.0f;
}
}

[[nodiscard]] static constexpr bool isSound(std::string_view soundName) noexcept
{
return soundName.starts_with(cs2::kBombSoundsPath) && std::string_view{ soundName.data() + cs2::kBombSoundsPath.length(), soundName.length() - cs2::kBombSoundsPath.length() }.starts_with(cs2::kBombBeepSoundsPrefix);
}
};
13 changes: 13 additions & 0 deletions Source/FeatureHelpers/Sound/BombBeepVisualizerHelpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <FeatureHelpers/GlobalVarsProvider.h>
#include <FeatureHelpers/HudInWorldPanelFactory.h>
#include <FeatureHelpers/WorldToClipSpaceConverter.h>
#include <Helpers/PanoramaTransformFactory.h>

struct BombBeepVisualizerHelpers {
HudInWorldPanelFactory hudInWorldPanelFactory;
GlobalVarsProvider globalVarsProvider;
PanoramaTransformFactory transformFactory;
WorldToClipSpaceConverter worldtoClipSpaceConverter;
};
3 changes: 2 additions & 1 deletion Source/FeatureHelpers/Sound/SoundWatcher.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#pragma once

#include "BombBeepSound.h"
#include "BombPlantSound.h"
#include "FootstepSound.h"
#include "SoundWatcherImpl.h"

using SoundWatcher = SoundWatcherImpl<FootstepSound, BombPlantSound>;
using SoundWatcher = SoundWatcherImpl<FootstepSound, BombPlantSound, BombBeepSound>;
168 changes: 168 additions & 0 deletions Source/Features/Sound/BombBeepVisualizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#pragma once

#include <algorithm>

#include <CS2/Classes/Panorama.h>
#include <CS2/Constants/SoundNames.h>
#include <FeatureHelpers/HudInWorldPanelFactory.h>
#include <FeatureHelpers/Sound/BombBeepVisualizerHelpers.h>
#include <FeatureHelpers/Sound/SoundWatcher.h>
#include <FeatureHelpers/TogglableFeature.h>
#include <FeatureHelpers/WorldToClipSpaceConverter.h>
#include <GameClasses/Panel.h>
#include <GameClasses/PanoramaUiEngine.h>
#include <Helpers/HudProvider.h>
#include <Helpers/PanoramaPanelPointer.h>
#include <Helpers/PanoramaTransformFactory.h>
#include <Hooks/ViewRenderHook.h>

struct BombBeepPanels {
void createPanels(const HudInWorldPanelFactory& inWorldFactory) noexcept
{
if (bombBeepContainerPanelPointer.get())
return;

const auto bombBeepContainer = inWorldFactory.createPanel("BombBeepContainer");
if (!bombBeepContainer)
return;

bombBeepContainerPanelPointer = bombBeepContainer->uiPanel;

for (std::size_t i = 0; i < kMaxNumberOfBombBeepsToDraw; ++i) {
PanoramaUiEngine::runScript(bombBeepContainer->uiPanel,
R"(
(function() {
var bombBeepPanel = $.CreatePanel('Panel', $.GetContextPanel().FindChildInLayoutFile("BombBeepContainer"), '', {
style: 'width: 100px; height: 100px; x: -50px; y: -50px;'
});
$.CreatePanel('Image', bombBeepPanel, '', {
src: "s2r://panorama/images/icons/ui/bomb_c4.svg",
style: "horizontal-align: center; vertical-align: center; img-shadow: 0px 0px 1px 3 #000000;",
textureheight: "40"
});
})();)", "", 0);
}
}

[[nodiscard]] PanoramaUiPanel getPanel(std::size_t index) const noexcept
{
const auto containerPanel = bombBeepContainerPanelPointer.get();
if (!containerPanel)
return PanoramaUiPanel{ nullptr };

if (const auto children = containerPanel.children()) {
if (children->size > 0 && static_cast<std::size_t>(children->size) > index)
return PanoramaUiPanel{ children->memory[index] };
}
return PanoramaUiPanel{ nullptr };
}

void hidePanels(std::size_t fromPanelIndex) const noexcept
{
for (std::size_t i = fromPanelIndex; i < kMaxNumberOfBombBeepsToDraw; ++i) {
const auto panel = getPanel(i);
if (!panel)
break;

if (const auto style = panel.getStyle())
style.setOpacity(0.0f);
}
}

PanoramaPanelPointer bombBeepContainerPanelPointer;

private:
static constexpr auto kMaxNumberOfBombBeepsToDraw = 5;
};

class BombBeepVisualizer : public TogglableFeature<BombBeepVisualizer> {
public:
explicit BombBeepVisualizer(ViewRenderHook& viewRenderHook, SoundWatcher& soundWatcher) noexcept
: viewRenderHook{ viewRenderHook }
, soundWatcher{ soundWatcher }
{
enable();
}

~BombBeepVisualizer() noexcept
{
if (panels.bombBeepContainerPanelPointer.getHandle().isValid())
PanoramaUiEngine::onDeletePanel(panels.bombBeepContainerPanelPointer.getHandle());
}

void run(const BombBeepVisualizerHelpers& params) noexcept
{
if (!isEnabled())
return;

if (!params.globalVarsProvider || !params.globalVarsProvider.getGlobalVars())
return;

if (!params.worldtoClipSpaceConverter)
return;

panels.createPanels(params.hudInWorldPanelFactory);

std::size_t currentIndex = 0;
std::as_const(soundWatcher).getSoundsOfType<BombBeepSound>().forEach([this, &currentIndex, params](const PlayedSound& sound) {
const auto soundInClipSpace = params.worldtoClipSpaceConverter.toClipSpace(sound.origin);
if (!soundInClipSpace.onScreen())
return;

const auto opacity = BombBeepSound::getOpacity(sound.getTimeAlive(params.globalVarsProvider.getGlobalVars()->curtime));
if (opacity <= 0.0f)
return;

const auto panel = panels.getPanel(currentIndex);
if (!panel)
return;

const auto style = panel.getStyle();
if (!style)
return;

style.setOpacity(opacity);

const auto deviceCoordinates = soundInClipSpace.toNormalizedDeviceCoordinates();
cs2::CTransform3D* transformations[]{ params.transformFactory.create<cs2::CTransformScale3D>(
BombBeepSound::getScale(soundInClipSpace.z), BombBeepSound::getScale(soundInClipSpace.z), 1.0f
), params.transformFactory.create<cs2::CTransformTranslate3D>(
deviceCoordinates.getX(),
deviceCoordinates.getY(),
cs2::CUILength{ 0.0f, cs2::CUILength::k_EUILengthLength }
) };

cs2::CUtlVector<cs2::CTransform3D*> dummyVector;
dummyVector.allocationCount = 2;
dummyVector.memory = transformations;
dummyVector.growSize = 0;
dummyVector.size = 2;

style.setTransform3D(dummyVector);
++currentIndex;
});

panels.hidePanels(currentIndex);
}

private:
friend TogglableFeature;

void onEnable() noexcept
{
viewRenderHook.incrementReferenceCount();
soundWatcher.startWatching<BombBeepSound>();
}

void onDisable() noexcept
{
viewRenderHook.decrementReferenceCount();
soundWatcher.stopWatching<BombBeepSound>();
panels.hidePanels(0);
}

BombBeepPanels panels;
ViewRenderHook& viewRenderHook;
SoundWatcher& soundWatcher;
};
3 changes: 3 additions & 0 deletions Source/Features/Sound/SoundFeatures.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "BombBeepVisualizer.h"
#include "BombPlantVisualizer.h"
#include "FootstepVisualizer.h"
#include <Helpers/HudProvider.h>
Expand All @@ -9,9 +10,11 @@ struct SoundFeatures {
SoundFeatures(ViewRenderHook& viewRenderHook, SoundWatcher& soundWatcher) noexcept
: footstepVisualizer{ viewRenderHook, soundWatcher }
, bombPlantVisualizer{ viewRenderHook, soundWatcher }
, bombBeepVisualizer{ viewRenderHook, soundWatcher }
{
}

FootstepVisualizer footstepVisualizer;
BombPlantVisualizer bombPlantVisualizer;
BombBeepVisualizer bombBeepVisualizer;
};
1 change: 1 addition & 0 deletions Source/GlobalContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct GlobalContext {
soundWatcher->update(featureHelpers->globalVarsProvider.getGlobalVars()->curtime);
features->soundFeatures.footstepVisualizer.run(featureHelpers->getFootstepVisualizerHelpers());
features->soundFeatures.bombPlantVisualizer.run(featureHelpers->getBombPlantVisualizerHelpers());
features->soundFeatures.bombBeepVisualizer.run(featureHelpers->getBombBeepVisualizerHelpers());
}

private:
Expand Down
3 changes: 3 additions & 0 deletions Source/Osiris.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
<ClInclude Include="FeatureHelpers\Hud\DefusingAlertHelpers.h" />
<ClInclude Include="FeatureHelpers\Hud\KillfeedPreserverHelpers.h" />
<ClInclude Include="FeatureHelpers\NormalizedDeviceCoordinates.h" />
<ClInclude Include="FeatureHelpers\Sound\BombBeepSound.h" />
<ClInclude Include="FeatureHelpers\Sound\BombBeepVisualizerHelpers.h" />
<ClInclude Include="FeatureHelpers\Sound\BombPlantSound.h" />
<ClInclude Include="FeatureHelpers\Sound\BombPlantVisualizerHelpers.h" />
<ClInclude Include="FeatureHelpers\Sound\FootstepSound.h" />
Expand All @@ -57,6 +59,7 @@
<ClInclude Include="Features\Hud\DefusingAlert.h" />
<ClInclude Include="Features\Hud\HudFeatures.h" />
<ClInclude Include="Features\Hud\KillfeedPreserver.h" />
<ClInclude Include="Features\Sound\BombBeepVisualizer.h" />
<ClInclude Include="Features\Sound\BombPlantVisualizer.h" />
<ClInclude Include="Features\Sound\FootstepVisualizer.h" />
<ClInclude Include="Features\Sound\SoundFeatures.h" />
Expand Down
9 changes: 9 additions & 0 deletions Source/Osiris.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,15 @@
<ClInclude Include="FeatureHelpers\Sound\SoundExpiryChecker.h">
<Filter>FeatureHelpers\Sound</Filter>
</ClInclude>
<ClInclude Include="FeatureHelpers\Sound\BombBeepSound.h">
<Filter>FeatureHelpers\Sound</Filter>
</ClInclude>
<ClInclude Include="Features\Sound\BombBeepVisualizer.h">
<Filter>Features\Sound</Filter>
</ClInclude>
<ClInclude Include="FeatureHelpers\Sound\BombBeepVisualizerHelpers.h">
<Filter>FeatureHelpers\Sound</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="UI\Panorama\CreateGUI.js">
Expand Down
2 changes: 2 additions & 0 deletions Source/UI/Panorama/CreateGUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ $.Osiris = (function () {
createYesNoDropDown(visualization, "Visualize Player Footsteps", 'sound', 'visualize_player_footsteps');
$.CreatePanel('Panel', visualization, '', { class: "horizontal-separator" });
createYesNoDropDown(visualization, "Visualize Bomb Plant", 'sound', 'visualize_bomb_plant');
$.CreatePanel('Panel', visualization, '', { class: "horizontal-separator" });
createYesNoDropDown(visualization, "Visualize Bomb Beep", 'sound', 'visualize_bomb_beep');

$.Osiris.navigateToTab('hud');
})();
Expand Down
4 changes: 3 additions & 1 deletion Source/UI/Panorama/SetCommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ struct SetCommandHandler {
handleTogglableFeature(features.soundFeatures.footstepVisualizer);
} else if (feature == "visualize_bomb_plant") {
handleTogglableFeature(features.soundFeatures.bombPlantVisualizer);
}
} else if (feature == "visualize_bomb_beep") {
handleTogglableFeature(features.soundFeatures.bombBeepVisualizer);
}
}

void handleVisualsSection() const noexcept
Expand Down

0 comments on commit ee1473b

Please sign in to comment.