diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index eaf195c486..2ada790c9f 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -71,6 +71,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/renderingengine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sky.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sound_maker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/texturepaths.cpp ${CMAKE_CURRENT_SOURCE_DIR}/texturesource.cpp diff --git a/src/client/game.cpp b/src/client/game.cpp index fcc62da4dd..210b17a27b 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -39,6 +39,7 @@ #include "server.h" #include "settings.h" #include "shader.h" +#include "sound_maker.h" #include "threading/lambda.h" #include "translation.h" #include "util/basic_macros.h" @@ -56,125 +57,6 @@ #include "client/sound/sound_openal.h" #endif -class NodeDugEvent : public MtEvent -{ -public: - v3s16 p; - MapNode n; - - NodeDugEvent(v3s16 p, MapNode n): - p(p), - n(n) - {} - Type getType() const { return NODE_DUG; } -}; - -class SoundMaker -{ - ISoundManager *m_sound; - const NodeDefManager *m_ndef; - -public: - bool makes_footstep_sound = true; - float m_player_step_timer = 0.0f; - float m_player_jump_timer = 0.0f; - - SoundSpec m_player_step_sound; - SoundSpec m_player_leftpunch_sound; - // Second sound made on left punch, currently used for item 'use' sound - SoundSpec m_player_leftpunch_sound2; - SoundSpec m_player_rightpunch_sound; - - SoundMaker(ISoundManager *sound, const NodeDefManager *ndef) : - m_sound(sound), m_ndef(ndef) {} - - void playPlayerStep() - { - if (m_player_step_timer <= 0 && m_player_step_sound.exists()) { - m_player_step_timer = 0.03; - if (makes_footstep_sound) - m_sound->playSound(0, m_player_step_sound); - } - } - - void playPlayerJump() - { - if (m_player_jump_timer <= 0.0f) { - m_player_jump_timer = 0.2f; - m_sound->playSound(0, SoundSpec("player_jump", 0.5f)); - } - } - - static void viewBobbingStep(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->playPlayerStep(); - } - - static void playerRegainGround(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->playPlayerStep(); - } - - static void playerJump(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->playPlayerJump(); - } - - static void cameraPunchLeft(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(0, sm->m_player_leftpunch_sound); - sm->m_sound->playSound(0, sm->m_player_leftpunch_sound2); - } - - static void cameraPunchRight(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(0, sm->m_player_rightpunch_sound); - } - - static void nodeDug(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - NodeDugEvent *nde = (NodeDugEvent *)e; - sm->m_sound->playSound(0, sm->m_ndef->get(nde->n).sound_dug); - } - - static void playerDamage(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(0, SoundSpec("player_damage", 0.5)); - } - - static void playerFallingDamage(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(0, SoundSpec("player_falling_damage", 0.5)); - } - - void registerReceiver(MtEventManager *mgr) - { - mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this); - mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this); - mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this); - mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this); - mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this); - mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this); - mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this); - mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this); - } - - void step(float dtime) - { - m_player_step_timer -= dtime; - m_player_jump_timer -= dtime; - } -}; - - typedef s32 SamplerLayer_t; @@ -514,7 +396,7 @@ Game::Game() : Game::~Game() { delete client; - delete soundmaker; + soundmaker.reset(); sound_manager.reset(); delete server; @@ -755,8 +637,7 @@ void Game::shutdown() delete client; client = nullptr; - delete soundmaker; - soundmaker = nullptr; + soundmaker.reset(); sound_manager.reset(); auto stop_thread = runInThread([=] { @@ -841,10 +722,7 @@ bool Game::initSound() sound_manager = std::make_unique(); } - soundmaker = new SoundMaker(sound_manager.get(), nodedef_manager); - if (!soundmaker) - return false; - + soundmaker = std::make_unique(sound_manager.get(), nodedef_manager); soundmaker->registerReceiver(eventmgr); return true; @@ -2738,16 +2616,11 @@ void Game::updateSound(f32 dtime) sound_volume_control(sound_manager.get(), device->isWindowActive()); - // Tell the sound maker whether to make footstep sounds - soundmaker->makes_footstep_sound = player->makes_footstep_sound; - - // Update sound maker - if (player->makes_footstep_sound) - soundmaker->step(dtime); - + // Update sound maker ClientMap &map = client->getEnv().getClientMap(); MapNode n = map.getNode(player->getFootstepNodePos()); - soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep; + soundmaker->update(dtime, player->makes_footstep_sound, + nodedef_manager->get(n).sound_footstep); } diff --git a/src/client/game_internal.h b/src/client/game_internal.h index 44ae1c7fdf..a44625653c 100644 --- a/src/client/game_internal.h +++ b/src/client/game_internal.h @@ -304,7 +304,7 @@ private: std::unique_ptr m_item_visuals_manager; std::unique_ptr sound_manager; - SoundMaker *soundmaker = nullptr; + std::unique_ptr soundmaker; ChatBackend *chat_backend = nullptr; CaptureLogOutput m_chat_log_buf; diff --git a/src/client/sound_maker.cpp b/src/client/sound_maker.cpp new file mode 100644 index 0000000000..3ab7d05ff1 --- /dev/null +++ b/src/client/sound_maker.cpp @@ -0,0 +1,99 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2025 Luanti developers + +#include "sound_maker.h" + +#include "mtevent.h" +#include "nodedef.h" +#include "sound.h" + +void SoundMaker::playPlayerStep() +{ + if (m_player_step_timer <= 0.0f && m_player_step_sound.exists()) { + m_player_step_timer = 0.03f; + if (makes_footstep_sound) + m_sound->playSound(0, m_player_step_sound); + } +} + +void SoundMaker::playPlayerJump() +{ + if (m_player_jump_timer <= 0.0f) { + m_player_jump_timer = 0.2f; + m_sound->playSound(0, SoundSpec("player_jump", 0.5f)); + } +} + +void SoundMaker::viewBobbingStep(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->playPlayerStep(); +} + +void SoundMaker::playerRegainGround(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->playPlayerStep(); +} + +void SoundMaker::playerJump(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->playPlayerJump(); +} + +void SoundMaker::cameraPunchLeft(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->m_sound->playSound(0, sm->m_player_leftpunch_sound); + sm->m_sound->playSound(0, sm->m_player_leftpunch_sound2); +} + +void SoundMaker::cameraPunchRight(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->m_sound->playSound(0, sm->m_player_rightpunch_sound); +} + +void SoundMaker::nodeDug(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + NodeDugEvent *nde = static_cast(e); + sm->m_sound->playSound(0, sm->m_ndef->get(nde->n).sound_dug); +} + +void SoundMaker::playerDamage(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->m_sound->playSound(0, SoundSpec("player_damage", 0.5f)); +} + +void SoundMaker::playerFallingDamage(MtEvent *e, void *data) +{ + SoundMaker *sm = static_cast(data); + sm->m_sound->playSound(0, SoundSpec("player_falling_damage", 0.5f)); +} + +void SoundMaker::registerReceiver(MtEventManager *mgr) +{ + mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this); + mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this); + mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this); + mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this); + mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this); + mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this); + mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this); + mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this); +} + +void SoundMaker::update(f32 dtime, bool makes_footstep_sound, const SoundSpec &sound_footstep) +{ + // Footstep sound and step + this->makes_footstep_sound = makes_footstep_sound; + if (makes_footstep_sound) { + m_player_step_timer -= dtime; + m_player_jump_timer -= dtime; + } + m_player_step_sound = sound_footstep; +} diff --git a/src/client/sound_maker.h b/src/client/sound_maker.h new file mode 100644 index 0000000000..5b156d7ddc --- /dev/null +++ b/src/client/sound_maker.h @@ -0,0 +1,71 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2025 Luanti developers + +#pragma once + +#include "../sound.h" + +class ISoundManager; +class NodeDefManager; +class MtEventManager; +class MtEvent; + +// TODO move this together with the game.cpp interact code to its own file. +#include "mtevent.h" +#include "mapnode.h" +class NodeDugEvent : public MtEvent +{ +public: + v3s16 p; + MapNode n; + + NodeDugEvent(v3s16 p, MapNode n): + p(p), + n(n) + {} + Type getType() const { return NODE_DUG; } +}; + + +// This class handles the playing of sound on MtEventManager events +// and stores which sounds to play. + +class SoundMaker +{ + ISoundManager *m_sound; + const NodeDefManager *m_ndef; + + float m_player_step_timer = 0.0f; + float m_player_jump_timer = 0.0f; + bool makes_footstep_sound = true; + SoundSpec m_player_step_sound; + +public: + SoundSpec m_player_leftpunch_sound; + // Second sound made on left punch, currently used for item 'use' sound + SoundSpec m_player_leftpunch_sound2; + SoundSpec m_player_rightpunch_sound; + + SoundMaker(ISoundManager *sound, const NodeDefManager *ndef) : + m_sound(sound), m_ndef(ndef) {} + + // NOTE if the SoundMaker got registered as a receiver, + // it must not be destructed before the event manager. + void registerReceiver(MtEventManager *mgr); + + void update(f32 dtime, bool makes_footstep_sound, const SoundSpec &sound_footstep); + +private: + void playPlayerStep(); + void playPlayerJump(); + + static void viewBobbingStep(MtEvent *e, void *data); + static void playerRegainGround(MtEvent *e, void *data); + static void playerJump(MtEvent *e, void *data); + static void cameraPunchLeft(MtEvent *e, void *data); + static void cameraPunchRight(MtEvent *e, void *data); + static void nodeDug(MtEvent *e, void *data); + static void playerDamage(MtEvent *e, void *data); + static void playerFallingDamage(MtEvent *e, void *data); +};