diff --git a/data/sounds/.gitignore b/data/sounds/.gitignore new file mode 100644 index 0000000000..7c9d611b59 --- /dev/null +++ b/data/sounds/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!README.md diff --git a/data/sounds/README.md b/data/sounds/README.md new file mode 100644 index 0000000000..8fbbb7d748 --- /dev/null +++ b/data/sounds/README.md @@ -0,0 +1,9 @@ +# Adding client versions + +Create a version folder and drop your soundbank in it. + +For the list of supported client versions see `modules/gamelib/game.lua` + +# Example configuration + +`data/sounds/1340/ (catalog-sound.json and all sound files)` diff --git a/data/things/.gitignore b/data/things/.gitignore index d6b7ef32c8..7c9d611b59 100644 --- a/data/things/.gitignore +++ b/data/things/.gitignore @@ -1,2 +1,3 @@ * !.gitignore +!README.md diff --git a/data/things/README.md b/data/things/README.md new file mode 100644 index 0000000000..731a9c149c --- /dev/null +++ b/data/things/README.md @@ -0,0 +1,13 @@ +# Adding client versions + +Create a version folder and drop your sprite files or assets in it. + +For the list of supported client versions see `modules/gamelib/game.lua` + +# Example configurations + +spr/dat: +`data/things/860/ (spr and dat files there)` + +assets: +`data/things/1340/ (catalog-content.json and all asset files)` diff --git a/meta.lua b/meta.lua index a6c4269b8d..f5ba6de77e 100644 --- a/meta.lua +++ b/meta.lua @@ -157,10 +157,6 @@ function g_things.loadAppearances(file) end ---@return boolean function g_things.loadStaticData(file) end ----@param file string ----@return boolean -function g_things.loadSounds(file) end - ---@param file string ---@return boolean function g_things.loadDat(file) end @@ -5835,6 +5831,14 @@ function g_sounds.createSoundEffect() end ---@return boolean function g_sounds.isEaxEnabled() end +---@param file string +---@return boolean +function g_sounds.loadClientFiles(directory) end + +---@param audioFileId string +---@return string +function g_sounds.getAudioFileNameById(audioFileId) end + -------------------------------- --------- SoundSource ---------- -------------------------------- diff --git a/mods/game_bot/default_configs/vBot_4.8/vBot/alarms.lua b/mods/game_bot/default_configs/vBot_4.8/vBot/alarms.lua index 80c95409e9..290868be38 100644 --- a/mods/game_bot/default_configs/vBot_4.8/vBot/alarms.lua +++ b/mods/game_bot/default_configs/vBot_4.8/vBot/alarms.lua @@ -114,18 +114,16 @@ addAlarm("creatureDetected", "Creature Detected", false, 1, 1) addAlarm("playerDetected", "Player Detected", false, 1, 1) addAlarm("creatureName", "Creature Name:", "", 3, 1, "You can add a name or part of it, that if found in any visible creature name will trigger alert.\nYou can add many, just separate them by comma.") - local lastCall = now local function alarm(file, windowText) if now - lastCall < 2000 then return end -- 2s delay lastCall = now if not g_resources.fileExists(file) then - file = "/sounds/alarm.ogg" + file = "sounds/alarm.ogg" lastCall = now + 4000 -- alarm.ogg length is 6s end - if modules.game_bot.g_app.getOs() == "windows" and config.flashClient.enabled then g_window.flash() end @@ -137,7 +135,7 @@ end onTextMessage(function(mode, text) if not config.enabled then return end if mode == 22 and config.damageTaken.enabled then - return alarm('/sounds/magnum.ogg', "Damage Received!") + return alarm('sounds/magnum.ogg', "Damage Received!") end if config.customMessage.enabled then @@ -152,7 +150,7 @@ onTextMessage(function(mode, text) part = part:lower() if text:find(part) then - return alarm('/sounds/magnum.ogg', "Special Message!") + return alarm('sounds/magnum.ogg', "Special Message!") end end end @@ -166,11 +164,11 @@ onTalk(function(name, level, mode, text, channelId, pos) if config.ignoreFriends.enabled and isFriend(name) then return end -- ignore friends if enabled if mode == 1 and config.defaultMsg.enabled then - return alarm("/sounds/magnum.ogg", "Default Message!") + return alarm("sounds/magnum.ogg", "Default Message!") end if mode == 4 and config.privateMsg.enabled then - return alarm("/sounds/Private_Message.ogg", "Private Message!") + return alarm("sounds/Private_Message.ogg", "Private Message!") end end) @@ -179,13 +177,13 @@ macro(100, function() if not config.enabled then return end if config.lowHealth.enabled then if hppercent() < config.lowHealth.value then - return alarm("/sounds/Low_Health.ogg", "Low Health!") + return alarm("sounds/Low_Health.ogg", "Low Health!") end end if config.lowMana.enabled then if hppercent() < config.lowMana.value then - return alarm("/sounds/Low_Mana.ogg", "Low Mana!") + return alarm("sounds/Low_Mana.ogg", "Low Mana!") end end @@ -193,15 +191,15 @@ macro(100, function() if not spec:isLocalPlayer() and not (config.ignoreFriends.enabled and isFriend(spec)) then if config.creatureDetected.enabled then - return alarm("/sounds/magnum.ogg", "Creature Detected!") + return alarm("sounds/magnum.ogg", "Creature Detected!") end if spec:isPlayer() then if spec:isTimedSquareVisible() and config.playerAttack.enabled then - return alarm("/sounds/Player_Attack.ogg", "Player Attack!") + return alarm("sounds/Player_Attack.ogg", "Player Attack!") end if config.playerDetected.enabled then - return alarm("/sounds/Player_Detected.ogg", "Player Detected!") + return alarm("sounds/Player_Detected.ogg", "Player Detected!") end end @@ -213,7 +211,7 @@ macro(100, function() local frag = fragments[i]:trim():lower() if name:lower():find(frag) then - return alarm("/sounds/alarm.ogg", "Special Creature Detected!") + return alarm("sounds/alarm.ogg", "Special Creature Detected!") end end end diff --git a/mods/game_bot/functions/sound.lua b/mods/game_bot/functions/sound.lua index c7fffeefd4..62ceee53e5 100644 --- a/mods/game_bot/functions/sound.lua +++ b/mods/game_bot/functions/sound.lua @@ -27,5 +27,5 @@ context.stopSound = function() end context.playAlarm = function() - return context.playSound("/sounds/alarm.ogg") + return context.playSound("sounds/alarm.ogg") end diff --git a/data/sounds/Creature_Detected.ogg b/mods/game_bot/sounds/Creature_Detected.ogg similarity index 100% rename from data/sounds/Creature_Detected.ogg rename to mods/game_bot/sounds/Creature_Detected.ogg diff --git a/data/sounds/Low_Health.ogg b/mods/game_bot/sounds/Low_Health.ogg similarity index 100% rename from data/sounds/Low_Health.ogg rename to mods/game_bot/sounds/Low_Health.ogg diff --git a/data/sounds/Low_Mana.ogg b/mods/game_bot/sounds/Low_Mana.ogg similarity index 100% rename from data/sounds/Low_Mana.ogg rename to mods/game_bot/sounds/Low_Mana.ogg diff --git a/data/sounds/Player_Attack.ogg b/mods/game_bot/sounds/Player_Attack.ogg similarity index 100% rename from data/sounds/Player_Attack.ogg rename to mods/game_bot/sounds/Player_Attack.ogg diff --git a/data/sounds/Player_Detected.ogg b/mods/game_bot/sounds/Player_Detected.ogg similarity index 100% rename from data/sounds/Player_Detected.ogg rename to mods/game_bot/sounds/Player_Detected.ogg diff --git a/data/sounds/Private_Message.ogg b/mods/game_bot/sounds/Private_Message.ogg similarity index 100% rename from data/sounds/Private_Message.ogg rename to mods/game_bot/sounds/Private_Message.ogg diff --git a/data/sounds/alarm.ogg b/mods/game_bot/sounds/alarm.ogg similarity index 100% rename from data/sounds/alarm.ogg rename to mods/game_bot/sounds/alarm.ogg diff --git a/data/sounds/magnum.ogg b/mods/game_bot/sounds/magnum.ogg similarity index 100% rename from data/sounds/magnum.ogg rename to mods/game_bot/sounds/magnum.ogg diff --git a/modules/client/client.lua b/modules/client/client.lua index fcdccc3bca..ce83bf84ff 100644 --- a/modules/client/client.lua +++ b/modules/client/client.lua @@ -1,4 +1,4 @@ -local musicFilename = '/sounds/startup' +local musicFilename = 'sounds/startup' local musicChannel = nil if g_sounds then musicChannel = g_sounds.getChannel(SoundChannels.Music) @@ -14,7 +14,6 @@ function setMusic(filename) end function startup() - -- Play startup music (The Silver Tree, by Mattias Westlund) if musicChannel then musicChannel:enqueue(musicFilename, 3) connect(g_game, { diff --git a/data/sounds/startup.ogg b/modules/client/sounds/startup.ogg similarity index 100% rename from data/sounds/startup.ogg rename to modules/client/sounds/startup.ogg diff --git a/modules/game_things/things.lua b/modules/game_things/things.lua index 35c1bd2973..a042e87fe8 100644 --- a/modules/game_things/things.lua +++ b/modules/game_things/things.lua @@ -59,21 +59,27 @@ function load(version) end loaded = #errorList == 0 + if loaded then + -- loading client files was successful, try to load sounds now + -- sound files are optional, this means that failing to load them + -- will not block logging into game + g_sounds.loadClientFiles(resolvepath(string.format('/sounds/%d/', version))) + return + end - if not loaded then - local messageBox = displayErrorBox(tr('Error'), table.concat(errorList, "\n")) - addEvent(function() - messageBox:raise() - messageBox:focus() - end) + -- loading client files failed, show an error + local messageBox = displayErrorBox(tr('Error'), table.concat(errorList, "\n")) + addEvent(function() + messageBox:raise() + messageBox:focus() + end) - disconnect(g_game, { - onClientVersionChange = load - }) - g_game.setClientVersion(0) - g_game.setProtocolVersion(0) - connect(g_game, { - onClientVersionChange = load - }) - end + disconnect(g_game, { + onClientVersionChange = load + }) + g_game.setClientVersion(0) + g_game.setProtocolVersion(0) + connect(g_game, { + onClientVersionChange = load + }) end diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index d2ce76dfa9..74c9494b95 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -68,7 +68,6 @@ void Client::registerLuaFunctions() g_lua.registerSingletonClass("g_things"); g_lua.bindSingletonFunction("g_things", "loadAppearances", &ThingTypeManager::loadAppearances, &g_things); g_lua.bindSingletonFunction("g_things", "loadStaticData", &ThingTypeManager::loadStaticData, &g_things); - g_lua.bindSingletonFunction("g_things", "loadSounds", &ThingTypeManager::loadSounds, &g_things); g_lua.bindSingletonFunction("g_things", "loadDat", &ThingTypeManager::loadDat, &g_things); g_lua.bindSingletonFunction("g_things", "loadOtml", &ThingTypeManager::loadOtml, &g_things); g_lua.bindSingletonFunction("g_things", "isDatLoaded", &ThingTypeManager::isDatLoaded, &g_things); diff --git a/src/client/thingtypemanager.cpp b/src/client/thingtypemanager.cpp index 8edc69c76f..5d594be4a6 100644 --- a/src/client/thingtypemanager.cpp +++ b/src/client/thingtypemanager.cpp @@ -38,7 +38,6 @@ #include #include -#include #include @@ -288,13 +287,6 @@ bool ThingTypeManager::loadStaticData(const std::string& file) return false; } -bool ThingTypeManager::loadSounds(const std::string& /* file */) -{ - // to be implemented - // to be moved to g_sounds - return false; -} - const ThingTypeList& ThingTypeManager::getThingTypes(const ThingCategory category) { if (category < ThingLastCategory) diff --git a/src/client/thingtypemanager.h b/src/client/thingtypemanager.h index 120b77c633..daec118e84 100644 --- a/src/client/thingtypemanager.h +++ b/src/client/thingtypemanager.h @@ -43,7 +43,6 @@ class ThingTypeManager bool loadOtml(std::string file); bool loadAppearances(const std::string& file); bool loadStaticData(const std::string& file); - bool loadSounds(const std::string& file); #ifdef FRAMEWORK_EDITOR void parseItemType(uint16_t id, pugi::xml_node node); diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index e7042b5317..78a0b813aa 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -1004,6 +1004,8 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_sounds", "setPosition", &SoundManager::setPosition, &g_sounds); g_lua.bindSingletonFunction("g_sounds", "createSoundEffect", &SoundManager::createSoundEffect, &g_sounds); g_lua.bindSingletonFunction("g_sounds", "isEaxEnabled", &SoundManager::isEaxEnabled, &g_sounds); + g_lua.bindSingletonFunction("g_sounds", "loadClientFiles", &SoundManager::loadClientFiles, &g_sounds); + g_lua.bindSingletonFunction("g_sounds", "getAudioFileNameById", &SoundManager::getAudioFileNameById, &g_sounds); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", [] { return std::make_shared(); }); diff --git a/src/framework/sound/soundmanager.cpp b/src/framework/sound/soundmanager.cpp index 086c1ffd89..dfbf32efe6 100644 --- a/src/framework/sound/soundmanager.cpp +++ b/src/framework/sound/soundmanager.cpp @@ -31,9 +31,15 @@ #include #include #include +#include +#include #include "soundchannel.h" +using namespace otclient::protobuf; + +using json = nlohmann::json; + class StreamSoundSource; class CombinedSoundSource; class SoundFile; @@ -339,4 +345,194 @@ bool SoundManager::isEaxEnabled() return true; } return false; -} \ No newline at end of file +} + +using ProtobufSoundFiles = google::protobuf::RepeatedPtrField; +using ProtobufSoundEffects = google::protobuf::RepeatedPtrField; +using ProtobufLocationAmbiences = google::protobuf::RepeatedPtrField; +using ProtobufItemAmbiences = google::protobuf::RepeatedPtrField; +using ProtobufMusicTracks = google::protobuf::RepeatedPtrField; + +bool SoundManager::loadFromProtobuf(const std::string& directory, const std::string& fileName) +{ + /* + * file structure + Sounds + | + | + | * audio file id -> audio file name (ogg) + |-+- (Sound) sound + | |----> (u32) id + | |----> (string) filename (sound-abcd.ogg) + | |----> (string) original_filename (unused) + | |----> (bool) is_stream + | + | + | * sound effect + |-+- (NumericSoundEffect) numeric_sound_effect + | |----> (u32) id (the id you request in sound effect packet) + | |----> (enum - ENumericSoundType) numeric_sound_type + | |-+--> (MinMaxFloat) random_pitch + | | |------> (float) min + | | |------> (float) max + | | + | |-+--> (MinMaxFloat) random_volume + | | |------> (float) min + | | |------> (float) max + | | + | |-+--> (SimpleSoundEffect) simple_sound_effect + | | |------> (u32) sound_id (audio file id) + | | + | |-+--> (RandomSoundEffect) random_sound_effect + | |------> (u32) random_sound_id (audio file id) + | + | + | * ambient sound for location (needs to be triggered with a packet) + |-+- (AmbienceStream) ambience_stream + | |----> (u32) id + | |----> (u32) looping_sound_id (audio file id) + | |-+--> (DelayedSoundEffect) delayed_effects + | |------> (u32) numeric_sound_effect_id (sound effect id) + | |------> (u32) delay_seconds + | + | + | * sound of items placed on the map + |-+- (AmbienceObjectStream) ambience_object_stream + | |----> (u32) id (ID OF THIS EFFECT, NOT ITEM ID!) + | |----> (u32) counted_appearance_types (ITEM CLIENT IDS that will have this sound, eg. waterfall or campfire) + | |-+--> (AppearanceTypesCountSoundEffect) sound_effects + | | |------> (u32) count (how many on the screen are required to trigger, eg. 3 are required for the swamp tiles to play sound) + | | |------> (u32) looping_sound_id (audio file id) + | |----> (u32) max_sound_distance (how far can it be heard) + | + | + | * music for location (needs to be triggered with a packet) + |-+- (MusicTemplate) music_template + |----> (u32) id + |----> (u32) sound_id (audio file id) + |----> (enum - EMusicType) music_type + */ + + // create the sound bank from protobuf file + try { + std::stringstream fileInputStream; + g_resources.readFileStream(g_resources.resolvePath(stdext::format("%s%s", directory, fileName)), fileInputStream); + + // read the soundbank + auto protobufSounds = sounds::Sounds(); + if (!protobufSounds.ParseFromIstream(&fileInputStream)) { + throw stdext::exception("Couldn't parse appearances lib."); + } + + // deserialize audio files + for (const auto& protobufAudioFile : protobufSounds.sound()) { + m_clientSoundFiles[protobufAudioFile.id()] = protobufAudioFile.filename(); + } + + // deserialize sound effects + for (const auto& protobufSoundEffect : protobufSounds.numeric_sound_effect()) { + const auto& pitch = protobufSoundEffect.random_pitch(); + const auto& volume = protobufSoundEffect.random_volume(); + std::vector randomSounds = {}; + if (protobufSoundEffect.has_random_sound_effect()) { + for (const uint32_t& audioFileId : protobufSoundEffect.random_sound_effect().random_sound_id()) { + randomSounds.push_back(audioFileId); + } + } + + uint32_t effectId = protobufSoundEffect.id(); + m_clientSoundEffects.emplace(effectId, ClientSoundEffect{ + effectId, + static_cast(protobufSoundEffect.numeric_sound_type()), + pitch.min_value(), + pitch.max_value(), + volume.max_value(), + volume.max_value(), + protobufSoundEffect.has_simple_sound_effect() ? protobufSoundEffect.simple_sound_effect().sound_id() : 0, + std::move(randomSounds) + }); + } + + // deserialize location ambients + for (const auto& protobufLocationAmbient : protobufSounds.ambience_stream()) { + uint32_t effectId = protobufLocationAmbient.id(); + DelayedSoundEffects effects = {}; + for (const auto& delayedEffect : protobufLocationAmbient.delayed_effects()) { + effects.push_back({delayedEffect.numeric_sound_effect_id(), delayedEffect.delay_seconds()}); + } + + m_clientAmbientEffects.emplace(effectId, ClientLocationAmbient{ + effectId, + protobufLocationAmbient.looping_sound_id(), + std::move(effects) + }); + } + + // deserialize item ambients + for (const auto& protobufItemAmbient : protobufSounds.ambience_object_stream()) { + std::vector itemClientIds = {}; + for (const auto& itemId : protobufItemAmbient.counted_appearance_types()) { + itemClientIds.push_back(itemId); + } + + ItemCountSoundEffects soundEffects = {}; + for (const auto& soundEffect : protobufItemAmbient.sound_effects()) { + soundEffects.push_back({soundEffect.looping_sound_id(), soundEffect.count()}); + } + + uint32_t effectId = protobufItemAmbient.id(); + m_clientItemAmbientEffects.emplace(effectId, ClientItemAmbient{ + effectId, + std::move(itemClientIds), + std::move(soundEffects) + }); + } + + // deserialize music + for (const auto& protobufMusicTemplate : protobufSounds.music_template()) { + uint32_t effectId = protobufMusicTemplate.id(); + m_clientMusic.emplace(effectId, ClientMusic{ + effectId, + protobufMusicTemplate.sound_id(), + static_cast(protobufMusicTemplate.music_type()) + }); + } + + return true; + } catch (const std::exception& e) { + g_logger.error(stdext::format("Failed to load soundbank '%s': %s", fileName, e.what())); + return false; + } +} + +bool SoundManager::loadClientFiles(const std::string& directory) +{ + // find catalog from json file + try { + json document = json::parse(g_resources.readFileContents(g_resources.resolvePath(g_resources.guessFilePath(directory + "catalog-sound", "json")))); + for (const auto& obj : document) { + const auto& type = obj["type"]; + if (type == "sounds") { + // dat file encoded with protobuf + loadFromProtobuf(directory, obj["file"]); + } + } + + return true; + } catch (const std::exception& e) { + if (g_game.getClientVersion() >= 1300) { + g_logger.warning(stdext::format("Failed to load '%s' (Sounds): %s", directory, e.what())); + } + + return false; + } +} + +std::string SoundManager::getAudioFileNameById(int32_t audioFileId) +{ + if (m_clientSoundFiles.contains(audioFileId)) { + return m_clientSoundFiles[audioFileId]; + } + + return ""; +} diff --git a/src/framework/sound/soundmanager.h b/src/framework/sound/soundmanager.h index 79222b15f5..fbc753f85c 100644 --- a/src/framework/sound/soundmanager.h +++ b/src/framework/sound/soundmanager.h @@ -23,10 +23,96 @@ #pragma once #include "declarations.h" +#include "client/game.h" #include "soundsource.h" #include #include +using DelayedSoundEffect = std::pair; +using DelayedSoundEffects = std::vector; +using ItemCountSoundEffect = std::pair; +using ItemCountSoundEffects = std::vector; + +enum ClientSoundType +{ + NUMERIC_SOUND_TYPE_UNKNOWN = 0, + NUMERIC_SOUND_TYPE_SPELL_ATTACK = 1, + NUMERIC_SOUND_TYPE_SPELL_HEALING = 2, + NUMERIC_SOUND_TYPE_SPELL_SUPPORT = 3, + NUMERIC_SOUND_TYPE_WEAPON_ATTACK = 4, + NUMERIC_SOUND_TYPE_CREATURE_NOISE = 5, + NUMERIC_SOUND_TYPE_CREATURE_DEATH = 6, + NUMERIC_SOUND_TYPE_CREATURE_ATTACK = 7, + NUMERIC_SOUND_TYPE_AMBIENCE_STREAM = 8, + NUMERIC_SOUND_TYPE_FOOD_AND_DRINK = 9, + NUMERIC_SOUND_TYPE_ITEM_MOVEMENT = 10, + NUMERIC_SOUND_TYPE_EVENT = 11, + NUMERIC_SOUND_TYPE_UI = 12, + NUMERIC_SOUND_TYPE_WHISPER_WITHOUT_OPEN_CHAT = 13, + NUMERIC_SOUND_TYPE_CHAT_MESSAGE = 14, + NUMERIC_SOUND_TYPE_PARTY = 15, + NUMERIC_SOUND_TYPE_VIP_LIST = 16, + NUMERIC_SOUND_TYPE_RAID_ANNOUNCEMENT = 17, + NUMERIC_SOUND_TYPE_SERVER_MESSAGE = 18, + NUMERIC_SOUND_TYPE_SPELL_GENERIC = 19 +}; + +enum ClientMusicType +{ + MUSIC_TYPE_UNKNOWN = 0, + MUSIC_TYPE_MUSIC = 1, + MUSIC_TYPE_MUSIC_IMMEDIATE = 2, + MUSIC_TYPE_MUSIC_TITLE = 3, +}; + +// client sound effect parsed from the protobuf file +struct ClientSoundEffect +{ + uint32_t clientId; + ClientSoundType type; + float pitchMin; + float pitchMax; + float volumeMin; + float volumeMax; + uint32_t soundId = 0; + std::vector randomSoundId; +}; + +// client location ambient parsed from the protobuf file +struct ClientLocationAmbient +{ + uint32_t clientId; + uint32_t loopedAudioFileId; + + // vector of pairs, where the pair is: + // < effect clientId, delay in seconds > + DelayedSoundEffects delayedSoundEffects; +}; + +// client item ambient parsed from the protobuf file +struct ClientItemAmbient +{ + uint32_t id; + std::vector clientIds; + + // this is a very specific client mechanic + // depending on how many items are on the game screen + // a different looped ambient effect will be played + // for example, configuration like this: + // 1 -> 630 + // 5 -> 625 + // means that when there is one item on the screen, an audio file number 630 should play + // once there are 5 of them, the client should play an audio file number 625 + ItemCountSoundEffects itemCountSoundEffects; +}; + +struct ClientMusic +{ + uint32_t id; // track id + uint32_t audioFileId; // audio file id + ClientMusicType musicType; +}; + //@bindsingleton g_sounds class SoundManager { @@ -47,6 +133,8 @@ class SoundManager void stopAll(); void setPosition(const Point& pos); bool isEaxEnabled(); + bool loadClientFiles(const std::string& directory); + std::string getAudioFileNameById(int32_t audioFileId); void preload(std::string filename); SoundSourcePtr play(const std::string& filename, float fadetime = 0, float gain = 0, float pitch = 0); @@ -58,6 +146,7 @@ class SoundManager private: SoundSourcePtr createSoundSource(const std::string& name); + bool loadFromProtobuf(const std::string& directory, const std::string& fileName); ALCdevice* m_device{}; ALCcontext* m_context{}; @@ -69,6 +158,13 @@ class SoundManager std::unordered_map m_channels; std::unordered_map m_effects; + // soundbanks for protocol 13 and newer + std::map m_clientSoundFiles; + std::map m_clientSoundEffects; + std::map m_clientAmbientEffects; + std::map m_clientItemAmbientEffects; + std::map m_clientMusic; + std::vector m_sources; bool m_audioEnabled{ true }; }; diff --git a/src/protobuf/sounds.proto b/src/protobuf/sounds.proto index 784728fef4..2833887dbc 100644 --- a/src/protobuf/sounds.proto +++ b/src/protobuf/sounds.proto @@ -432,6 +432,6 @@ message AppearanceTypesCountSoundEffect { } message MinMaxFloat { - optional float min = 1; - optional float max = 2; + optional float min_value = 1; + optional float max_value = 2; }