From 60f4a6e98f33a2dcf4e49890a35fe68b121a4952 Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Wed, 5 Oct 2022 00:07:04 +0200 Subject: [PATCH] Remove old unused stuff --- src/client/component/database.cpp | 1 - src/client/component/fastfiles.cpp | 10 - src/client/component/mapents.cpp | 318 ---------- src/client/component/mapents.hpp | 7 - src/client/component/materials.cpp | 269 --------- src/client/component/materials.hpp | 7 - src/client/component/mods.cpp | 7 - src/client/component/sound.cpp | 933 ----------------------------- src/client/component/sound.hpp | 9 - 9 files changed, 1561 deletions(-) delete mode 100644 src/client/component/mapents.hpp delete mode 100644 src/client/component/materials.cpp delete mode 100644 src/client/component/materials.hpp delete mode 100644 src/client/component/sound.hpp diff --git a/src/client/component/database.cpp b/src/client/component/database.cpp index 3a41546e..7089a9e0 100644 --- a/src/client/component/database.cpp +++ b/src/client/component/database.cpp @@ -7,7 +7,6 @@ #include "filesystem.hpp" #include "console.hpp" #include "command.hpp" -#include "sound.hpp" #include #include diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index 0f9ad256..f488221e 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -5,7 +5,6 @@ #include "command.hpp" #include "console.hpp" #include "localized_strings.hpp" -#include "sound.hpp" #include #include @@ -32,15 +31,6 @@ namespace fastfiles game::XAssetHeader db_find_xasset_header_stub(game::XAssetType type, const char* name, int allow_create_default) { - if (type == game::ASSET_TYPE_SOUND) - { - const auto res = sound::find_sound(name); - if (res.sound != nullptr) - { - return res; - } - } - const auto start = game::Sys_Milliseconds(); const auto result = db_find_xasset_header.invoke(type, name, allow_create_default); const auto diff = game::Sys_Milliseconds() - start; diff --git a/src/client/component/mapents.cpp b/src/client/component/mapents.cpp index caba7b26..b0fbf48c 100644 --- a/src/client/component/mapents.cpp +++ b/src/client/component/mapents.cpp @@ -4,19 +4,14 @@ #include "game/dvars.hpp" #include "fastfiles.hpp" -#include "filesystem.hpp" #include "console.hpp" -#include "scheduler.hpp" -#include "mapents.hpp" #include "command.hpp" #include "game/scripting/functions.hpp" #include #include -#include #include -#include #include #include @@ -24,296 +19,6 @@ namespace mapents { namespace { - game::dvar_t* addon_mapname = nullptr; - utils::memory::allocator allocator; - - std::unordered_map custom_fields; - - unsigned int token_id_start = 0x16000; - - // zonetool/iw4/addonmapents.cpp - class asset_reader - { - public: - asset_reader(char* data) - : data_(data) - { - } - - template - T read() - { - const auto value = *reinterpret_cast(this->data_); - this->data_ += sizeof(T); - return value; - } - - std::uint32_t read_int() - { - const auto type = this->read(); - if (type != 0) - { - printf("asset_reader: invalid type %i for int\n", type); - return 0; - } - - return this->read(); - } - - template - T* read_array() - { - const auto type = this->read(); - if (type != 3) - { - printf("asset_reader: invalid type %i for array\n", type); - return nullptr; - } - - const auto size = this->read(); - if (size <= 0) - { - printf("asset_reader: array size <= 0\n"); - return nullptr; - } - - const auto array_ = allocator.allocate_array(size); - const auto total_size = sizeof(T) * size; - std::memcpy(array_, this->data_, total_size); - this->data_ += total_size; - - return array_; - } - - private: - char* data_ = nullptr; - }; - - std::string parse_mapents(const std::string& source) - { - std::string out_buffer{}; - const auto lines = utils::string::split(source, '\n'); - - bool in_map_ent = false; - bool empty = false; - int line_index{}; - for (const auto& line : lines) - { - const auto _0 = gsl::finally([&]() - { - line_index++; - }); - - if (line[0] == '{' && !in_map_ent) - { - in_map_ent = true; - out_buffer.append("{\n"); - continue; - } - - if (line[0] == '{' && in_map_ent) - { - throw std::runtime_error(utils::string::va("[addon_map_ents parser] '{' on line %i", line_index)); - } - - if (line[0] == '}' && in_map_ent) - { - if (empty) - { - out_buffer.append("\n}\n"); - } - else if (line_index < static_cast(lines.size()) - 1) - { - out_buffer.append("}\n"); - } - else - { - out_buffer.append("}\0"); - } - - in_map_ent = false; - continue; - } - - if (line[0] == '}' && !in_map_ent) - { - throw std::runtime_error(utils::string::va("[addon_map_ents parser] Unexpected '}' on line %i", line_index)); - } - - std::regex expr(R"~((.+) "(.*)")~"); - std::smatch match{}; - if (!std::regex_search(line, match, expr)) - { - console::warn("[addon_map_ents parser] Failed to parse line %i", line_index); - continue; - } - - auto key = utils::string::to_lower(match[1].str()); - const auto value = match[2].str(); - - if (key.size() <= 0 || value.size() <= 0) - { - console::warn("[addon_map_ents parser] Invalid key/value ('%s' '%s') pair on line %i", key.data(), value.data(), line_index); - continue; - } - - empty = false; - - auto key_id = std::atoi(key.data()); - if (key_id != 0) - { - out_buffer.append(utils::string::va("%i \"%s\"\n", key_id, value.data())); - continue; - } - - if (key.size() < 3 || (!key.starts_with("\"") || !key.ends_with("\""))) - { - console::warn("[addon_map_ents parser] Bad key '%s' on line %i", key.data(), line_index); - continue; - } - - const auto key_ = key.substr(1, key.size() - 2); - const auto id = xsk::gsc::h2::resolver::token_id(key_); - if (id == 0) - { - console::warn("[addon_map_ents parser] Key '%s' not found, on line %i", key_.data(), line_index); - continue; - } - - out_buffer.append(utils::string::va("%i \"%s\"\n", id, value.data())); - } - - return out_buffer; - } - - std::optional get_mapents_data(std::string* real_path = nullptr) - { - std::string data{}; - if (addon_mapname->current.string != ""s && - filesystem::read_file("addon_map_ents/"s + addon_mapname->current.string + ".mapents"s, &data, real_path)) - { - return {data}; - } - - static const auto mapname = game::Dvar_FindVar("mapname"); - - if (filesystem::read_file("addon_map_ents/"s + mapname->current.string + ".mapents"s, &data, real_path)) - { - return {data}; - } - - return {}; - } - - bool should_load_addon_mapents() - { - return get_mapents_data().has_value(); - } - - bool should_load_addon_mapents_stub(const char* a1, void* a2) - { - if (should_load_addon_mapents()) - { - return true; - } - - return utils::hook::invoke(0x140609570, a1, a2); // Com_IsAddonMap - } - - void try_parse_mapents(const std::string& path, const std::string& data, game::AddonMapEnts* mapents) - { - const auto parsed = parse_mapents(data); - utils::io::write_file("parsed_mapents.txt", parsed, false); - - mapents->entityString = allocator.duplicate_string(parsed.data()); - mapents->numEntityChars = static_cast(parsed.size()) + 1; - - std::string triggers{}; - if (utils::io::read_file(path + ".triggers", &triggers)) - { - asset_reader reader(triggers.data()); - - mapents->trigger.modelCount = reader.read_int(); - mapents->trigger.models = reader.read_array(); - - mapents->trigger.hullCount = reader.read_int(); - mapents->trigger.hulls = reader.read_array(); - - mapents->trigger.slabCount = reader.read_int(); - mapents->trigger.slabs = reader.read_array(); - } - } - - game::XAssetHeader db_find_xasset_header_stub(game::XAssetType type, const char* name, int allow_create_default) - { - if (!should_load_addon_mapents()) - { - return game::DB_FindXAssetHeader(type, name, allow_create_default); - } - - const auto _0 = gsl::finally(&mapents::clear_dvars); - - const auto mapents = allocator.allocate(); - mapents->name = allocator.duplicate_string(name); - mapents->entityString = allocator.duplicate_string("{\n}"); - mapents->numEntityChars = 4; - - std::string real_path{}; - const auto data = get_mapents_data(&real_path); - if (!data.has_value()) - { - return static_cast(mapents); - } - - try - { - try_parse_mapents(real_path, data.value(), mapents); - } - catch (const std::exception& e) - { - console::error("Failed to parse addon_map_ents file %s: %s\n", name, e.what()); - } - - return static_cast(mapents); - } - - void cm_trigger_model_bounds_stub(void* a1, void* a2) - { - __try - { - utils::hook::invoke(0x14058BEB0, a1, a2); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - game::Com_Error(game::ERR_DROP, "CM_TriggerModelBounds: you are probably missing a mapents.triggers file"); - } - } - - void add_field(const std::string& name, game::scriptType_e type) - { - const auto id = token_id_start++; - custom_fields[id] = type; - xsk::gsc::h2::resolver::add_token(name, static_cast(id)); - } - - void add_field(const std::string& name, game::scriptType_e type, unsigned int id) - { - custom_fields[id] = type; - xsk::gsc::h2::resolver::add_token(name, static_cast(id)); - } - - utils::hook::detour scr_find_field_hook; - unsigned int scr_find_field_stub(unsigned int name, game::scriptType_e* type) - { - if (custom_fields.find(name) != custom_fields.end()) - { - *type = custom_fields[name]; - return name; - } - - return scr_find_field_hook.invoke(name, type); - } - std::string replace_mapents_keys(const std::string& data) { std::string buffer{}; @@ -350,28 +55,11 @@ namespace mapents } } - void clear_dvars() - { - game::Dvar_SetString(addon_mapname, ""); - } - - void clear() - { - allocator.clear(); - } - class component final : public component_interface { public: void post_unpack() override { - scr_find_field_hook.create(0x1405C5240, scr_find_field_stub); - - scheduler::once([]() - { - addon_mapname = dvars::register_string("addon_mapname", "", 0, ""); - }, scheduler::pipeline::main); - command::add("dumpMapEnts", []() { if (!game::SV_Loaded()) @@ -395,12 +83,6 @@ namespace mapents console::info("Mapents dumped to %s\n", dest); }, true); }); - - utils::hook::call(0x14058BDD3, db_find_xasset_header_stub); - utils::hook::call(0x14058BD6B, should_load_addon_mapents_stub); - utils::hook::call(0x1406B3384, cm_trigger_model_bounds_stub); - - add_field("script_specialops", game::SCRIPT_INTEGER, 0xEFFF); } }; } diff --git a/src/client/component/mapents.hpp b/src/client/component/mapents.hpp deleted file mode 100644 index 8b19d317..00000000 --- a/src/client/component/mapents.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace mapents -{ - void clear(); - void clear_dvars(); -} diff --git a/src/client/component/materials.cpp b/src/client/component/materials.cpp deleted file mode 100644 index 9320344d..00000000 --- a/src/client/component/materials.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include -#include "loader/component_loader.hpp" - -#include "materials.hpp" -#include "console.hpp" -#include "filesystem.hpp" -#include "command.hpp" - -#include "game/game.hpp" -#include "game/dvars.hpp" - -#include -#include -#include -#include -#include -#include - -namespace materials -{ - namespace - { - utils::hook::detour db_material_streaming_fail_hook; - utils::hook::detour material_register_handle_hook; - utils::hook::detour db_get_material_index_hook; - - struct material_data_t - { - std::unordered_map materials; - std::unordered_map images; - }; - - char constant_table[0x20] = {}; - - utils::concurrency::container material_data; - - game::GfxImage* setup_image(game::GfxImage* image, const utils::image& raw_image) - { - image->imageFormat = 0x1000003; - image->resourceSize = -1; - - D3D11_SUBRESOURCE_DATA data{}; - data.SysMemPitch = raw_image.get_width() * 4; - data.SysMemSlicePitch = data.SysMemPitch * raw_image.get_height(); - data.pSysMem = raw_image.get_buffer(); - - game::Image_Setup(image, raw_image.get_width(), raw_image.get_height(), image->depth, image->numElements, - image->imageFormat, DXGI_FORMAT_R8G8B8A8_UNORM, 0, image->name, &data); - - return image; - } - - game::Material* create_material(const std::string& name, const utils::image& raw_image) - { - const auto white = *reinterpret_cast(0x141B09208); - - const auto material = utils::memory::get_allocator()->allocate(); - const auto texture_table = utils::memory::get_allocator()->allocate(); - const auto image = utils::memory::get_allocator()->allocate(); - - std::memcpy(material, white, sizeof(game::Material)); - std::memcpy(texture_table, white->textureTable, sizeof(game::MaterialTextureDef)); - std::memcpy(image, white->textureTable->u.image, sizeof(game::GfxImage)); - - material->constantTable = &constant_table; - material->name = utils::memory::get_allocator()->duplicate_string(name); - image->name = material->name; - - material->textureTable = texture_table; - material->textureTable->u.image = setup_image(image, raw_image); - - return material; - } - - void free_material(game::Material* material) - { - material->textureTable->u.image->textures.___u0.map->Release(); - material->textureTable->u.image->textures.shaderView->Release(); - utils::memory::get_allocator()->free(material->textureTable->u.image); - utils::memory::get_allocator()->free(material->textureTable); - utils::memory::get_allocator()->free(material->name); - utils::memory::get_allocator()->free(material); - } - - game::Material* load_material(const std::string& name) - { - return material_data.access([&](material_data_t& data_) -> game::Material* - { - if (const auto i = data_.materials.find(name); i != data_.materials.end()) - { - return i->second; - } - - std::string data{}; - if (const auto i = data_.images.find(name); i != data_.images.end()) - { - data = i->second; - } - - if (!data.empty()) - { - const auto material = create_material(name, data); - data_.materials[name] = material; - return material; - } - - if (filesystem::read_file(utils::string::va("materials/%s.stbi_img", name.data()), &data)) - { - const auto buffer = data.data(); - const auto width = *reinterpret_cast(buffer); - const auto height = *reinterpret_cast(buffer + 4); - const auto image_data = std::string(reinterpret_cast(buffer + 8), data.size() - 8); - - const auto image = utils::image(image_data, width, height); - - const auto material = create_material(name, image); - data_.materials[name] = material; - - return material; - } - - if (filesystem::read_file(utils::string::va("materials/%s.png", name.data()), &data)) - { - const auto material = create_material(name, data); - data_.materials[name] = material; - return material; - } - - data_.materials[name] = nullptr; - return nullptr; - }); - } - - game::Material* try_load_material(const std::string& name) - { - if (name == "white") - { - return nullptr; - } - - try - { - return load_material(name); - } - catch (const std::exception& e) - { - console::error("Failed to load material %s: %s\n", name.data(), e.what()); - } - - return nullptr; - } - - game::Material* material_register_handle_stub(const char* name) - { - auto result = try_load_material(name); - if (result == nullptr) - { - result = material_register_handle_hook.invoke(name); - } - return result; - } - - int db_material_streaming_fail_stub(game::Material* material) - { - if (material->constantTable == &constant_table) - { - return 0; - } - - return db_material_streaming_fail_hook.invoke(material); - } - - unsigned int db_get_material_index_stub(game::Material* material) - { - if (material->constantTable == &constant_table) - { - return 0; - } - - return db_get_material_index_hook.invoke(material); - } - } - - void add(const std::string& name, const std::string& data) - { - material_data.access([&](material_data_t& data_) - { - data_.images[name] = data; - }); - } - - void clear() - { - material_data.access([&](material_data_t& data_) - { - for (auto& material : data_.materials) - { - if (material.second == nullptr) - { - continue; - } - - free_material(material.second); - } - - data_.materials.clear(); - }); - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - material_register_handle_hook.create(game::Material_RegisterHandle.get(), material_register_handle_stub); - db_material_streaming_fail_hook.create(0x14041D140, db_material_streaming_fail_stub); - db_get_material_index_hook.create(0x140413BC0, db_get_material_index_stub); - - command::add("preloadImage", [](const command::params& params) - { - if (params.size() < 2) - { - return; - } - - const auto image_name = params.join(1); - if (!utils::io::file_exists(image_name)) - { - console::error("Image file not found\n"); - return; - } - - const auto data = utils::io::read_file(image_name); - - try - { - const auto image = utils::image{ data }; - const auto last_of = image_name.find_last_of('.'); - const auto new_name = image_name.substr(0, last_of) + ".stbi_img"; - - auto width = image.get_width(); - auto height = image.get_height(); - - /* - int width; - int height; - char* data; - */ - - std::string buffer{}; - buffer.append(reinterpret_cast(&width), 4); - buffer.append(reinterpret_cast(&height), 4); - buffer.append(image.get_data()); - - utils::io::write_file(new_name, buffer, false); - - console::info("Image saved to %s\n", new_name.data()); - } - catch (const std::exception& e) - { - console::error("Error processing image: %s\n", e.what()); - } - - }); - } - }; -} - -REGISTER_COMPONENT(materials::component) diff --git a/src/client/component/materials.hpp b/src/client/component/materials.hpp deleted file mode 100644 index 3a548548..00000000 --- a/src/client/component/materials.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace materials -{ - void add(const std::string& name, const std::string& data); - void clear(); -} diff --git a/src/client/component/mods.cpp b/src/client/component/mods.cpp index 01ede170..e1bc36f6 100644 --- a/src/client/component/mods.cpp +++ b/src/client/component/mods.cpp @@ -7,13 +7,10 @@ #include "console.hpp" #include "scheduler.hpp" #include "filesystem.hpp" -#include "materials.hpp" #include "fonts.hpp" #include "mods.hpp" -#include "mapents.hpp" #include "localized_strings.hpp" #include "loadscreen.hpp" -#include "sound.hpp" #include #include @@ -31,15 +28,11 @@ namespace mods { if (release_assets) { - materials::clear(); fonts::clear(); - mapents::clear_dvars(); loadscreen::clear(); } - mapents::clear(); localized_strings::clear(); - sound::clear(); db_release_xassets_hook.invoke(); } diff --git a/src/client/component/sound.cpp b/src/client/component/sound.cpp index 40b2e0f6..03b7d752 100644 --- a/src/client/component/sound.cpp +++ b/src/client/component/sound.cpp @@ -4,578 +4,15 @@ #include "game/game.hpp" #include "game/dvars.hpp" -#include "sound.hpp" -#include "filesystem.hpp" #include "console.hpp" -#include "scheduler.hpp" -#include "command.hpp" #include -#include #include -#include -#include - -// https://github.com/skkuull/h1-zonetool/blob/main/src/client/zonetool/assets/sound.cpp -// https://github.com/skkuull/h1-zonetool/blob/main/src/client/zonetool/assets/loadedsound.cpp namespace sound { namespace { - utils::memory::allocator sound_allocator; - using loaded_sound_map = std::unordered_map; - utils::concurrency::container loaded_sounds; - std::hash hasher; - -#define FATAL(...) \ - throw std::runtime_error(utils::string::va(__VA_ARGS__)); \ - -#define SOUND_STRING(entry, optional) \ - if (j.HasMember(#entry) && j[#entry].IsString()) \ - { \ - asset->entry = sound_allocator.duplicate_string(j[#entry].GetString()); \ - } \ - else if (!optional) \ - { \ - FATAL("member '%s' does not exist or isn't of type 'String'\n", #entry); \ - } \ - -#define SOUND_FLOAT(entry, optional) \ - if (j.HasMember(#entry) && (j[#entry].IsFloat() || j[#entry].IsInt())) \ - { \ - asset->entry = j[#entry].GetFloat(); \ - } \ - else if (!optional) \ - { \ - FATAL("member '%s' does not exist or isn't of type 'Float'\n", #entry); \ - } \ - - -#define SOUND_INT(entry, optional) \ - if (j.HasMember(#entry) && j[#entry].IsInt()) \ - { \ - asset->entry = j[#entry].GetInt(); \ - } \ - else if (!optional) \ - { \ - FATAL("member '%s' does not exist or isn't of type 'Int'\n", #entry); \ - } \ - -#define SOUND_CHAR(entry, optional) \ - if (j.HasMember(#entry) && j[#entry].IsInt()) \ - { \ - asset->entry = static_cast(j[#entry].GetInt()); \ - } \ - else if (!optional) \ - { \ - FATAL("member '%s' does not exist or isn't of type 'Char'\n", #entry); \ - } \ - -#define JSON_GET(parent, name, type, parent_name) \ - (parent.HasMember(name) && parent[name].Is##type()) \ - ? parent[name].Get##type() \ - : FATAL("'%s' member '%s' does not exist or it isn't of type '%s'", parent_name, name, #type) \ - -#define JSON_GET_OPTIONAL(parent, name, type, default_value) \ - (parent.HasMember(name) && parent[name].Is##type()) \ - ? parent[name].Get##type() \ - : default_value \ - -#define JSON_GET_CAST(parent, name, type, cast_type, parent_name) \ - (parent.HasMember(name) && parent[name].Is##type()) \ - ? static_cast(parent[name].Get##type()) \ - : FATAL("'%s' member '%s' does not exist or it isn't of type '%s'", parent_name, name, #type) \ - -#define JSON_CHECK(parent, name, type, parent_name) \ - if (!parent.HasMember(name) || !parent[name].Is##type()) \ - { \ - FATAL("'%s' member '%s' does not exist or it isn't of type '%s'", parent_name, name, #type) \ - } \ - - std::string rapidjson_get_object_bytes(const rapidjson::Value& value) - { - std::string buffer{}; - - if (!value.IsArray()) - { - return buffer; - } - - for (auto i = 0; i < static_cast(value.Size()); i++) - { - buffer += static_cast(value[i].GetInt()); - } - return buffer; - } - - rapidjson::Value rapidjson_bytes_to_object(const std::vector& bytes, rapidjson::Document& j) - { - rapidjson::Value arr{rapidjson::kArrayType}; - - for (const auto& byte : bytes) - { - arr.PushBack(byte, j.GetAllocator()); - } - - return arr; - } - - game::LoadedSound* parse_flac(const std::string& name) - { - const auto path = "loaded_sound/"s + name + ".flac"; - std::string data{}; - if (!filesystem::read_file(path, &data)) - { - return nullptr; - } - - console::info("[Sound] Parsing flac %s\n", path.data()); - - auto* result = sound_allocator.allocate(); - result->name = sound_allocator.duplicate_string(name); - result->info.loadedSize = static_cast(data.size()); - result->info.data = sound_allocator.allocate_array(result->info.loadedSize); - std::memcpy(result->info.data, data.data(), data.size()); - - return result; - } - - game::LoadedSound* parse_wav(const std::string& name) - { - const auto path = "loaded_sound/"s + name + ".wav"; - std::string full_path{}; - if (!filesystem::find_file(path, &full_path)) - { - return nullptr; - } - - console::info("[Sound] Parsing wav %s\n", path.data()); - - std::ifstream file; - file.open(full_path, std::ios::binary); - - if (!file.is_open()) - { - FATAL("failed to open loaded sound file: %s\n", name.data()); - } - - const auto result = sound_allocator.allocate(); - - unsigned int chunk_id_buffer{}; - unsigned int chunk_size{}; - - file.read(reinterpret_cast(&chunk_id_buffer), 4); - if (chunk_id_buffer != 0x46464952) // RIFF - { - FATAL("%s: Invalid RIFF Header 0x%lX.", name.data(), chunk_id_buffer); - } - - file.read(reinterpret_cast(&chunk_size), 4); - file.read(reinterpret_cast(&chunk_id_buffer), 4); - - if (chunk_id_buffer != 0x45564157) // WAVE - { - FATAL("%s: Invalid WAVE Header 0x%lX.", name.data(), chunk_id_buffer); - } - - while (!result->info.data && !file.eof()) - { - file.read(reinterpret_cast(&chunk_id_buffer), 4); - file.read(reinterpret_cast(&chunk_size), 4); - - switch (chunk_id_buffer) - { - case 0x20746D66: // fmt - if (chunk_size >= 16) - { - short format{}; - file.read(reinterpret_cast(&format), 2); - if (format != 1 && format != 17) - { - FATAL("%s: Invalid wave format %i.", name.data(), format); - } - result->info.format = format; - - short num_channels{}; - file.read(reinterpret_cast(&num_channels), 2); - result->info.channels = static_cast(num_channels); - - int sample_rate{}; - file.read(reinterpret_cast(&sample_rate), 4); - result->info.sampleRate = sample_rate; - - int byte_rate{}; - file.read(reinterpret_cast(&byte_rate), 4); - - short block_align{}; - file.read(reinterpret_cast(&block_align), 2); - result->info.blockAlign = static_cast(block_align); - - short bit_per_sample{}; - file.read(reinterpret_cast(&bit_per_sample), 2); - result->info.numBits = static_cast(bit_per_sample); - - if (chunk_size > 16) - { - file.seekg(chunk_size - 16, std::ios::cur); - } - } - break; - - case 0x61746164: // data - result->info.data = sound_allocator.allocate_array(chunk_size); - file.read(result->info.data, chunk_size); - - result->info.loadedSize = chunk_size; - result->info.dataByteCount = result->info.loadedSize; - - result->info.numSamples = result->info.dataByteCount / (result->info.channels * result->info.numBits / 8); - break; - - default: - if (chunk_size > 0) - { - file.seekg(chunk_size, std::ios::cur); - } - break; - } - } - - if (!result->info.data) - { - FATAL("%s: Could not read sounddata.", name.data()); - return nullptr; - } - - result->name = sound_allocator.duplicate_string(name); - return result; - } - - game::LoadedSound* parse_loaded_sound(const std::string& name) - { - std::string full_path{}; - auto path = "loaded_sound/"s + name; - - if (filesystem::find_file(path + ".wav", &full_path)) - { - return parse_wav(name); - } - - if (filesystem::find_file(path + ".flac", &full_path)) - { - return parse_flac(name); - } - - console::warn("Sound %s not found, falling back to default sound\n", path.data()); - return game::DB_FindXAssetHeader(game::ASSET_TYPE_LOADED_SOUND, name.data(), true).loaded_sound; - } - - void parse_sound_alias(const rapidjson::Value& j, game::snd_alias_t* asset) - { - SOUND_STRING(aliasName, false); - SOUND_STRING(secondaryAliasName, true); - SOUND_STRING(chainAliasName, true); - SOUND_STRING(subtitle, true); - SOUND_STRING(mixerGroup, true); - - if (!j.HasMember("soundfile") || !j["soundfile"].IsObject()) - { - FATAL("missing 'soundfile' object"); - } - - const auto& sound_file = j["soundfile"]; - const auto sound_file_type = JSON_GET(sound_file, "type", Int, "soundfile"); - - asset->soundFile = sound_allocator.allocate(); - asset->soundFile->type = static_cast(sound_file_type); - asset->soundFile->exists = true; - - if (asset->soundFile->type == game::SAT_LOADED) - { - const auto name = JSON_GET(sound_file, "name", String, "soundfile is missing 'name'"); - asset->soundFile->u.loadSnd = parse_loaded_sound(name); - } - else if (asset->soundFile->type == game::SAT_STREAMED) - { - asset->soundFile->u.streamSnd.totalMsec = - JSON_GET(sound_file, "totalMsec", Uint, "soundfile"); - asset->soundFile->u.streamSnd.filename.isLocalized = - JSON_GET(sound_file, "isLocalized", Bool, "soundfile"); - asset->soundFile->u.streamSnd.filename.isStreamed = - JSON_GET(sound_file, "isStreamed", Bool, "soundfile"); - asset->soundFile->u.streamSnd.filename.fileIndex = - JSON_GET_CAST(sound_file, "fileIndex", Int, unsigned short, "soundfile"); - - if (asset->soundFile->u.streamSnd.filename.fileIndex) - { - JSON_CHECK(sound_file, "packed", Object, "soundfile"); - - asset->soundFile->u.streamSnd.filename.info.packed.offset = - JSON_GET(sound_file["packed"], "offset", Uint64, "soundfile.raw"); - asset->soundFile->u.streamSnd.filename.info.packed.length = - JSON_GET(sound_file["packed"], "length", Uint64, "soundfile.raw"); - } - else - { - JSON_CHECK(sound_file, "raw", Object, "soundfile"); - - const auto dir = JSON_GET(sound_file["raw"], "dir", String, "soundfile.raw"); - const auto name = JSON_GET(sound_file["raw"], "name", String, "soundfile.raw"); - - asset->soundFile->u.streamSnd.filename.info.raw.dir = sound_allocator.duplicate_string(dir); - asset->soundFile->u.streamSnd.filename.info.raw.name = sound_allocator.duplicate_string(name); - } - } - else - { - FATAL("Sound alias has invalid soundFile type %i", asset->soundFile->type); - } - - SOUND_INT(flags, false); - SOUND_INT(sequence, false); - SOUND_FLOAT(volMin, false); - SOUND_FLOAT(volMax, false); - SOUND_INT(volModIndex, false); - SOUND_FLOAT(pitchMin, false); - SOUND_FLOAT(pitchMax, false); - SOUND_FLOAT(distMin, false); - SOUND_FLOAT(distMax, false); - SOUND_FLOAT(velocityMin, false); - SOUND_CHAR(masterPriority, false); - SOUND_FLOAT(masterPercentage, false); - SOUND_FLOAT(slavePercentage, false); - SOUND_FLOAT(probability, false); - SOUND_INT(startDelay, false); - - if (j.HasMember("sndContext") && j["sndContext"].IsString()) - { - asset->sndContext = game::DB_FindXAssetHeader(game::ASSET_TYPE_SNDCONTEXT, - j["sndContext"].GetString(), false).snd_context; - } - - if (j.HasMember("sndCurve") && j["sndCurve"].IsString()) - { - asset->sndCurve = game::DB_FindXAssetHeader(game::ASSET_TYPE_SNDCURVE, - j["sndCurve"].GetString(), false).snd_curve; - } - - if (j.HasMember("lpfCurve") && j["lpfCurve"].IsString()) - { - asset->lpfCurve = game::DB_FindXAssetHeader(game::ASSET_TYPE_LPFCURVE, - j["lpfCurve"].GetString(), false).snd_curve; - } - - if (j.HasMember("hpfCurve") && j["hpfCurve"].IsString()) - { - asset->hpfCurve = game::DB_FindXAssetHeader(game::ASSET_TYPE_LPFCURVE, - j["hpfCurve"].GetString(), false).snd_curve; - } - - if (j.HasMember("reverbSendCurve") && j["reverbSendCurve"].IsString()) - { - asset->reverbSendCurve = game::DB_FindXAssetHeader(game::ASSET_TYPE_REVERBSENDCURVE, - j["reverbSendCurve"].GetString(), false).snd_curve; - } - - if (j.HasMember("speakerMap") && j["speakerMap"].IsObject()) - { - asset->speakerMap = sound_allocator.allocate(); - const auto& speaker_map = j["speakerMap"]; - - const auto speaker_map_name = JSON_GET(speaker_map, "name", String, "speakerMap"); - const auto is_default = JSON_GET(speaker_map, "isDefault", Bool, "speakerMap"); - - asset->speakerMap->name = sound_allocator.duplicate_string(speaker_map_name); - asset->speakerMap->isDefault = is_default; - - if (speaker_map.HasMember("channelMaps") && speaker_map["channelMaps"].IsArray()) - { - const auto& channel_maps = speaker_map["channelMaps"]; - for (char x = 0; x < 2; x++) - { - for (char y = 0; y < 2; y++) - { - const auto index = static_cast((x & 0x01) << 1 | y & 0x01); - if (index >= channel_maps.Size() || !channel_maps[index].IsObject()) - { - FATAL("channelMaps at index %i does not exist", index); - } - - const auto& channel_map = channel_maps[index]; - asset->speakerMap->channelMaps[x][y].speakerCount = JSON_GET(channel_map, - "speakerCount", Int, "speakerMap.channelMaps[]"); - - if (!channel_map.HasMember("speakers") || !channel_map["speakers"].IsArray()) - { - FATAL("channelMap does not have a 'speakers' member or it isn't an array"); - } - - const auto& speakers = channel_map["speakers"]; - - for (auto speaker = 0; speaker < asset->speakerMap->channelMaps[x][y].speakerCount; - speaker++) - { - if (static_cast(speaker) < speakers.Size() && speakers[speaker].IsObject()) - { - const auto& jspeaker = speakers[speaker]; - asset->speakerMap->channelMaps[x][y].speakers[speaker].speaker = - JSON_GET_CAST(jspeaker, "speaker", Int, char, "speakerMap.channelMaps.speakers[]"); - asset->speakerMap->channelMaps[x][y].speakers[speaker].numLevels = - JSON_GET_CAST(jspeaker, "numLevels", Int, char, "speakerMap.channelMaps.speakers[]"); - asset->speakerMap->channelMaps[x][y].speakers[speaker].levels[0] = - JSON_GET(jspeaker, "levels0", Float, "speakerMap.channelMaps.speakers[]"); - asset->speakerMap->channelMaps[x][y].speakers[speaker].levels[1] = - JSON_GET(jspeaker, "levels1", Float, "speakerMap.channelMaps.speakers[]"); - } - else - { - FATAL("speaker at index %i does not exist or is not an object", speaker); - } - } - } - } - } - } - - /*SOUND_CHAR(allowDoppler); - if (j.HasMember("dopplerPreset") && !j["dopplerPreset"].IsNull()) - { - asset->dopplerPreset = game::DB_FindXAssetHeader(game::ASSET_TYPE_DOPPLERPRESET, - j["dopplerPreset"].GetString(), false).doppler_preset; - }*/ - - if (j.HasMember("unknown") && j["unknown"].IsObject()) - { - const auto& snd_unknown = j["unknown"]; - - const auto& pad0 = rapidjson_get_object_bytes(snd_unknown["pad"][0]); - const auto& pad1 = rapidjson_get_object_bytes(snd_unknown["pad"][1]); - const auto& pad2 = rapidjson_get_object_bytes(snd_unknown["pad"][2]); - const auto& pad3 = rapidjson_get_object_bytes(snd_unknown["pad"][3]); - - std::memcpy(asset->__pad0, pad0.data(), pad0.size()); - std::memcpy(asset->__pad1, pad1.data(), pad1.size()); - std::memcpy(asset->__pad2, pad2.data(), pad2.size()); - std::memcpy(asset->__pad3, pad3.data(), pad3.size()); - - asset->u4 = JSON_GET_OPTIONAL(snd_unknown, "u4", Int, 0); - asset->u5 = JSON_GET_OPTIONAL(snd_unknown, "u5", Int, 0); - asset->u18 = static_cast(JSON_GET_OPTIONAL(snd_unknown, "u18", Int, 0)); - asset->u20 = static_cast(JSON_GET_OPTIONAL(snd_unknown, "u20", Int, 0)); - asset->u34 = JSON_GET_OPTIONAL(snd_unknown, "u34", Float, 0.f); - } - } - - game::snd_alias_list_t* parse_sound_alias_list(const rapidjson::Document& j) - { - const auto asset = sound_allocator.allocate(); - - SOUND_STRING(aliasName, false); - - asset->count = JSON_GET_CAST(j, "count", Int, char, "sound"); - asset->head = sound_allocator.allocate_array(asset->count); - - JSON_CHECK(j, "head", Array, "sound"); - - const auto head = j["head"].GetArray(); - for (auto i = 0; i < static_cast(asset->count) && head.Size(); i++) - { - parse_sound_alias(head[i], &asset->head[i]); - } - - if (j.HasMember("unknownArray") && j["unknownArray"].IsArray()) - { - const auto& unk = j["unknownArray"]; - asset->unkCount = static_cast(unk.Size()); - asset->unk = sound_allocator.allocate_array(asset->unkCount); - - for (unsigned char i = 0; i < asset->unkCount && unk.Size(); i++) - { - asset->unk[i] = static_cast(unk[i].GetInt()); - } - } - - return asset; - } - - bool sound_exists(const char* name) - { - return sound::find_sound(name).sound != nullptr; - } - - utils::hook::detour db_is_xasset_default_hook; - int db_is_xasset_default_stub(game::XAssetType type, const char* name) - { - if (type != game::ASSET_TYPE_SOUND) - { - return db_is_xasset_default_hook.invoke(type, name); - } - - const auto res = db_is_xasset_default_hook.invoke(type, name); - if (!res) - { - return res; - } - - return !sound_exists(name); - } - - utils::hook::detour db_xasset_exists_hook; - int db_xasset_exists_stub(game::XAssetType type, const char* name) - { - const auto res = utils::hook::invoke(0x140417FD0, type, name); - if (res) - { - return true; - } - - return sound_exists(name); - } - - utils::hook::detour scr_table_lookup_hook; - void scr_table_lookup_stub() - { - const auto table = game::Scr_GetString(0); - const auto search_column = game::Scr_GetInt(1); - const auto search_value = game::Scr_GetString(2); - const auto return_row = game::Scr_GetInt(3); - - if (table != "mp/sound/soundlength.csv"s || search_column != 0 || return_row != 1) - { - return scr_table_lookup_hook.invoke(); - } - - std::optional new_value{}; - loaded_sounds.access([&](loaded_sound_map& map) - { - const auto i = map.find(hasher(search_value)); - if (i == map.end()) - { - return; - } - - const auto sound_list = i->second; - if (sound_list->count) - { - const auto sound = &sound_list->head[0]; - if (sound->soundFile && sound->soundFile->type == game::SAT_STREAMED) - { - new_value = sound->soundFile->u.streamSnd.totalMsec; - } - } - }); - - if (new_value.has_value()) - { - game::Scr_AddString(utils::string::va("%i\n", new_value.value())); - } - else - { - scr_table_lookup_hook.invoke(); - } - } - void com_sprintf_raw_sound_localized_stub(char* buffer, int size, const char* fmt, const char* lang, const char* name, const char* extension) { @@ -598,344 +35,6 @@ namespace sound return snd_is_music_playing_hook.invoke(a1); } - - void load_sound(const std::string& name, const std::string& path) - { - try - { - const auto data = utils::io::read_file(path); - - rapidjson::Document j; - j.Parse(data.data()); - - console::info("[Sound] Loading sound %s\n", name.data()); - const auto sound = parse_sound_alias_list(j); - - const auto h = hasher(name.data()); - loaded_sounds.access([&](loaded_sound_map& map) - { - map[h] = sound; - }); - } - catch (const std::exception& e) - { - console::error("[Sound] Error loading sound %s: %s\n", name.data(), e.what()); - } - } - - void load_sounds() - { - const auto paths = filesystem::get_search_paths(); - for (const auto& path : paths) - { - const auto dir = path + "/sounds"; - if (!utils::io::directory_exists(dir)) - { - continue; - } - - const auto sound_files = utils::io::list_files(dir); - for (const auto& file : sound_files) - { - const auto last = file.find_last_of("\\/"); - std::string name = file; - if (last != std::string::npos) - { - name = file.substr(last + 1); - } - - load_sound(name, file); - } - } - } - } - - bool dump_sound(game::snd_alias_list_t* asset) - { - if (asset == nullptr) - { - return false; - } - - rapidjson::Document j; - j.SetObject(); - - j.AddMember("aliasName", rapidjson::StringRef(asset->aliasName), j.GetAllocator()); - j.AddMember("count", asset->count, j.GetAllocator()); - - rapidjson::Value head{rapidjson::kArrayType}; - - for (auto i = 0; i < asset->count; i++) - { - const auto snd_head = &asset->head[i]; - rapidjson::Value entry{rapidjson::kObjectType}; - entry.AddMember("aliasName", rapidjson::StringRef(snd_head->aliasName), j.GetAllocator()); - - if (snd_head->secondaryAliasName) - { - entry.AddMember("secondaryAliasName", rapidjson::StringRef(snd_head->secondaryAliasName), j.GetAllocator()); - } - - else - { - entry.AddMember("secondaryAliasName", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->chainAliasName) - { - entry.AddMember("chainAliasName", rapidjson::StringRef(snd_head->chainAliasName), j.GetAllocator()); - } - else - { - entry.AddMember("chainAliasName", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->subtitle) - { - entry.AddMember("subtitle", rapidjson::StringRef(snd_head->subtitle), j.GetAllocator()); - } - else - { - entry.AddMember("subtitle", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->mixerGroup) - { - entry.AddMember("mixerGroup", rapidjson::StringRef(snd_head->mixerGroup), j.GetAllocator()); - } - else - { - entry.AddMember("mixerGroup", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->soundFile) - { - rapidjson::Value sound_file{rapidjson::kObjectType}; - sound_file.AddMember("type", snd_head->soundFile->type, j.GetAllocator()); - - if (snd_head->soundFile->exists) - { - if (snd_head->soundFile->type == game::SAT_LOADED) - { - sound_file.AddMember("name", rapidjson::StringRef(snd_head->soundFile->u.loadSnd->name), j.GetAllocator()); - } - else if (snd_head->soundFile->type == game::SAT_STREAMED) - { - sound_file.AddMember("totalMsec", snd_head->soundFile->u.streamSnd.totalMsec, j.GetAllocator()); - sound_file.AddMember("isLocalized", snd_head->soundFile->u.streamSnd.filename.isLocalized, j.GetAllocator()); - sound_file.AddMember("isStreamed", snd_head->soundFile->u.streamSnd.filename.isStreamed, j.GetAllocator()); - sound_file.AddMember("fileIndex", snd_head->soundFile->u.streamSnd.filename.fileIndex, j.GetAllocator()); - - if (snd_head->soundFile->u.streamSnd.filename.fileIndex) - { - rapidjson::Value packed{rapidjson::kObjectType}; - packed.AddMember("offset", snd_head->soundFile->u.streamSnd.filename.info.packed.offset, j.GetAllocator()); - packed.AddMember("length", snd_head->soundFile->u.streamSnd.filename.info.packed.length, j.GetAllocator()); - sound_file.AddMember("packed", packed, j.GetAllocator()); - } - else - { - rapidjson::Value raw{rapidjson::kObjectType}; - raw.AddMember("dir", rapidjson::StringRef(snd_head->soundFile->u.streamSnd.filename.info.raw.dir), j.GetAllocator()); - raw.AddMember("name", rapidjson::StringRef(snd_head->soundFile->u.streamSnd.filename.info.raw.name), j.GetAllocator()); - sound_file.AddMember("packed", raw, j.GetAllocator()); - } - } - } - - entry.AddMember("soundfile", sound_file, j.GetAllocator()); - } - - entry.AddMember("flags", snd_head->flags, j.GetAllocator()); - entry.AddMember("sequence", snd_head->sequence, j.GetAllocator()); - entry.AddMember("volMin", snd_head->volMin, j.GetAllocator()); - entry.AddMember("volMax", snd_head->volMax, j.GetAllocator()); - entry.AddMember("volModIndex", snd_head->volModIndex, j.GetAllocator()); - entry.AddMember("pitchMin", snd_head->pitchMin, j.GetAllocator()); - entry.AddMember("pitchMax", snd_head->pitchMax, j.GetAllocator()); - entry.AddMember("distMin", snd_head->distMin, j.GetAllocator()); - entry.AddMember("distMax", snd_head->distMax, j.GetAllocator()); - entry.AddMember("velocityMin", snd_head->velocityMin, j.GetAllocator()); - entry.AddMember("masterPriority", snd_head->masterPriority, j.GetAllocator()); - entry.AddMember("masterPercentage", snd_head->masterPercentage, j.GetAllocator()); - entry.AddMember("slavePercentage", snd_head->slavePercentage, j.GetAllocator()); - entry.AddMember("probability", snd_head->probability, j.GetAllocator()); - entry.AddMember("startDelay", snd_head->startDelay, j.GetAllocator()); - - if (snd_head->sndContext) - { - entry.AddMember("sndContext", rapidjson::StringRef(snd_head->sndContext->name), j.GetAllocator()); - } - else - { - entry.AddMember("sndContext", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->sndCurve) - { - entry.AddMember("sndCurve", rapidjson::StringRef(snd_head->sndCurve->name), j.GetAllocator()); - } - else - { - entry.AddMember("sndCurve", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->lpfCurve) - { - entry.AddMember("lpfCurve", rapidjson::StringRef(snd_head->lpfCurve->name), j.GetAllocator()); - } - else - { - entry.AddMember("lpfCurve", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->hpfCurve) - { - entry.AddMember("hpfCurve", rapidjson::StringRef(snd_head->hpfCurve->name), j.GetAllocator()); - } - else - { - entry.AddMember("hpfCurve", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->reverbSendCurve) - { - entry.AddMember("reverbSendCurve", rapidjson::StringRef(snd_head->reverbSendCurve->name), j.GetAllocator()); - } - else - { - entry.AddMember("reverbSendCurve", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - if (snd_head->speakerMap) - { - rapidjson::Value speaker_map{rapidjson::kObjectType}; - rapidjson::Value channel_maps{rapidjson::kArrayType}; - - for (char x = 0; x < 2; x++) - { - for (char y = 0; y < 2; y++) - { - rapidjson::Value channel_map{rapidjson::kObjectType}; - - channel_map.AddMember("speakerCount", snd_head->speakerMap->channelMaps[x][y].speakerCount, j.GetAllocator()); - - rapidjson::Value speakers{rapidjson::kArrayType}; - for (int speaker = 0; speaker < snd_head->speakerMap->channelMaps[x][y].speakerCount; speaker++) - { - rapidjson::Value jspeaker{rapidjson::kObjectType}; - - jspeaker.AddMember("speaker", snd_head->speakerMap->channelMaps[x][y].speakers[speaker].speaker, j.GetAllocator()); - jspeaker.AddMember("numLevels", snd_head->speakerMap->channelMaps[x][y].speakers[speaker].numLevels, j.GetAllocator()); - jspeaker.AddMember("levels0", snd_head->speakerMap->channelMaps[x][y].speakers[speaker].levels[0], j.GetAllocator()); - jspeaker.AddMember("levels1", snd_head->speakerMap->channelMaps[x][y].speakers[speaker].levels[1], j.GetAllocator()); - - speakers.PushBack(jspeaker, j.GetAllocator()); - } - - channel_map.AddMember("speakers", speakers, j.GetAllocator()); - channel_maps.PushBack(channel_map, j.GetAllocator()); - } - } - - speaker_map.AddMember("name", rapidjson::StringRef(snd_head->speakerMap->name), j.GetAllocator()); - speaker_map.AddMember("isDefault", snd_head->speakerMap->isDefault, j.GetAllocator()); - - speaker_map.AddMember("channelMaps", channel_maps, j.GetAllocator()); - entry.AddMember("speakerMap", speaker_map, j.GetAllocator()); - } - else - { - j.AddMember("speakerMap", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - } - - /*entry.AddMember("allowDoppler", snd_head->allowDoppler, j.GetAllocator()); - if (snd_head->dopplerPreset) - { - entry.AddMember("dopplerPreset", rapidjson::StringRef(snd_head->dopplerPreset->name), j.GetAllocator()); - } - else - { - entry.AddMember("dopplerPreset", rapidjson::Value{rapidjson::kNullType}, j.GetAllocator()); - }*/ - - rapidjson::Value unknown{rapidjson::kObjectType}; - rapidjson::Value pad{rapidjson::kArrayType}; - - const auto pad0 = std::vector(snd_head->__pad0, snd_head->__pad0 + sizeof(snd_head->__pad0)); - const auto pad1 = std::vector(snd_head->__pad1, snd_head->__pad1 + sizeof(snd_head->__pad1)); - const auto pad2 = std::vector(snd_head->__pad2, snd_head->__pad2 + sizeof(snd_head->__pad2)); - const auto pad3 = std::vector(snd_head->__pad3, snd_head->__pad3 + sizeof(snd_head->__pad3)); - - auto rpad0 = rapidjson_bytes_to_object(pad0, j); - auto rpad1 = rapidjson_bytes_to_object(pad1, j); - auto rpad2 = rapidjson_bytes_to_object(pad2, j); - auto rpad3 = rapidjson_bytes_to_object(pad3, j); - - pad.PushBack(rpad0, j.GetAllocator()); - pad.PushBack(rpad1, j.GetAllocator()); - pad.PushBack(rpad2, j.GetAllocator()); - pad.PushBack(rpad3, j.GetAllocator()); - - unknown.AddMember("pad", pad, j.GetAllocator()); - unknown.AddMember("u4", snd_head->u4, j.GetAllocator()); - unknown.AddMember("u5", snd_head->u5, j.GetAllocator()); - unknown.AddMember("u18", snd_head->u18, j.GetAllocator()); - unknown.AddMember("u20", snd_head->u20, j.GetAllocator()); - unknown.AddMember("u34", snd_head->u34, j.GetAllocator()); - - entry.AddMember("unknown", unknown, j.GetAllocator()); - - head.PushBack(entry, j.GetAllocator()); - } - - j.AddMember("head", head, j.GetAllocator()); - - - rapidjson::Value unknown_array{rapidjson::kArrayType}; - for (unsigned char i = 0; i < asset->unkCount; i++) - { - unknown_array.PushBack(asset->unk[i], j.GetAllocator()); - } - - j.AddMember("unknownArray", unknown_array, j.GetAllocator()); - - std::string path = "dumps/sounds/"s + asset->aliasName; - - rapidjson::StringBuffer buffer{}; - rapidjson::PrettyWriter> - writer(buffer); - writer.SetIndent(' ', 4); - j.Accept(writer); - - utils::io::write_file(path, std::string{buffer.GetString(), buffer.GetLength()}, false); - return true; - } - - game::XAssetHeader find_sound(const char* name) - { - const auto hash = hasher(name); - return loaded_sounds.access([&](loaded_sound_map& map) - { - const auto i = map.find(hash); - if (i != map.end()) - { - return static_cast(i->second); - } - - return static_cast(nullptr); - }); - } - - void clear() - { - sound_allocator.clear(); - loaded_sounds.access([](loaded_sound_map& map) - { - map.clear(); - }); - - load_sounds(); } class component final : public component_interface @@ -943,44 +42,12 @@ namespace sound public: void post_unpack() override { - db_is_xasset_default_hook.create(0x1404143C0, db_is_xasset_default_stub); - utils::hook::call(0x140616DD1, db_xasset_exists_stub); - scr_table_lookup_hook.create(0x1404EFD40, scr_table_lookup_stub); - // remove raw/sound or raw/language/sound prefix when loading raw sounds utils::hook::call(0x140622FEF, com_sprintf_raw_sound_localized_stub); utils::hook::call(0x14062306C, com_sprintf_raw_sound_stub); // fix playing non-existing music crashing snd_is_music_playing_hook.create(0x1407C58A0, snd_is_music_playing_stub); - - scheduler::once(clear, scheduler::pipeline::main); - - command::add("dumpSoundAlias", [](const command::params& params) - { - if (params.size() < 2) - { - console::info("Usage: dumpSoundAlias \n"); - return; - } - - const auto name = params.get(1); - const auto sound = game::DB_FindXAssetHeader(game::ASSET_TYPE_SOUND, name, false).sound; - if (sound == nullptr) - { - console::error("Sound %s does not exist\n", name); - return; - } - - if (dump_sound(sound)) - { - console::info("Sound dumped to dumps/sound/%s\n", name); - } - else - { - console::error("Failed to dump sound %s\n", name); - } - }); } }; } diff --git a/src/client/component/sound.hpp b/src/client/component/sound.hpp deleted file mode 100644 index c034e399..00000000 --- a/src/client/component/sound.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace sound -{ - bool dump_sound(game::snd_alias_list_t* asset); - game::XAssetHeader find_sound(const char* name); - - void clear(); -}