mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +00:00
Merge pull request #277 from Laupetin/refactor/sound-bank-loading-dumping
refactor: sound bank loading dumping
This commit is contained in:
commit
1fc31b8c44
@ -6228,9 +6228,9 @@ namespace T6
|
|||||||
unsigned int distanceLpf : 1; // 2
|
unsigned int distanceLpf : 1; // 2
|
||||||
unsigned int doppler : 1; // 3
|
unsigned int doppler : 1; // 3
|
||||||
unsigned int isBig : 1; // 4
|
unsigned int isBig : 1; // 4
|
||||||
unsigned int pauseable : 1; // 5
|
unsigned int pausable : 1; // 5
|
||||||
unsigned int isMusic : 1; // 6
|
unsigned int isMusic : 1; // 6
|
||||||
unsigned int stopOnDeath : 1; // 7
|
unsigned int stopOnEntDeath : 1; // 7
|
||||||
unsigned int timescale : 1; // 8
|
unsigned int timescale : 1; // 8
|
||||||
unsigned int voiceLimit : 1; // 9
|
unsigned int voiceLimit : 1; // 9
|
||||||
unsigned int ignoreMaxDist : 1; // 10
|
unsigned int ignoreMaxDist : 1; // 10
|
||||||
@ -6249,7 +6249,9 @@ namespace T6
|
|||||||
unsigned int reverbFalloffCurve : 6; // 8-13
|
unsigned int reverbFalloffCurve : 6; // 8-13
|
||||||
unsigned int volumeMinFalloffCurve : 6; // 14-19
|
unsigned int volumeMinFalloffCurve : 6; // 14-19
|
||||||
unsigned int reverbMinFalloffCurve : 6; // 20-25
|
unsigned int reverbMinFalloffCurve : 6; // 20-25
|
||||||
unsigned int unknown1_1 : 6; // 26-31
|
unsigned int unknown1_1 : 1; // 26
|
||||||
|
unsigned int isCinematic : 1; // 27
|
||||||
|
unsigned int unknown1_2 : 4; // 28-31
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SndAlias
|
struct SndAlias
|
||||||
@ -6257,7 +6259,7 @@ namespace T6
|
|||||||
const char* name;
|
const char* name;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
const char* subtitle;
|
const char* subtitle;
|
||||||
const char* secondaryname;
|
const char* secondaryName;
|
||||||
unsigned int assetId;
|
unsigned int assetId;
|
||||||
const char* assetFileName;
|
const char* assetFileName;
|
||||||
SndAliasFlags flags;
|
SndAliasFlags flags;
|
||||||
|
34
src/ObjCommon/Csv/CsvHeaderRow.cpp
Normal file
34
src/ObjCommon/Csv/CsvHeaderRow.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "Csv/CsvHeaderRow.h"
|
||||||
|
|
||||||
|
CsvHeaderRow::CsvHeaderRow() = default;
|
||||||
|
|
||||||
|
bool CsvHeaderRow::Read(const CsvInputStream& inputStream)
|
||||||
|
{
|
||||||
|
if (!m_header_row.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return inputStream.NextRow(m_header_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& CsvHeaderRow::HeaderNameForColumn(const unsigned columnIndex) const
|
||||||
|
{
|
||||||
|
return m_header_row[columnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CsvHeaderRow::RequireIndexForHeader(const std::string& headerName, unsigned& out) const
|
||||||
|
{
|
||||||
|
const auto existingHeader = std::ranges::find(m_header_row, headerName);
|
||||||
|
if (existingHeader == m_header_row.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out = std::distance(m_header_row.begin(), existingHeader);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<unsigned> CsvHeaderRow::GetIndexForHeader(const std::string& headerName) const
|
||||||
|
{
|
||||||
|
unsigned result;
|
||||||
|
if (!RequireIndexForHeader(headerName, result))
|
||||||
|
return std::nullopt;
|
||||||
|
return result;
|
||||||
|
}
|
22
src/ObjCommon/Csv/CsvHeaderRow.h
Normal file
22
src/ObjCommon/Csv/CsvHeaderRow.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Csv/CsvStream.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CsvHeaderRow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CsvHeaderRow();
|
||||||
|
|
||||||
|
bool Read(const CsvInputStream& inputStream);
|
||||||
|
|
||||||
|
const std::string& HeaderNameForColumn(unsigned columnIndex) const;
|
||||||
|
bool RequireIndexForHeader(const std::string& headerName, unsigned& out) const;
|
||||||
|
[[nodiscard]] std::optional<unsigned> GetIndexForHeader(const std::string& headerName) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_header_row;
|
||||||
|
};
|
@ -1,14 +1,88 @@
|
|||||||
#include "CsvStream.h"
|
#include "CsvStream.h"
|
||||||
|
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
constexpr char CSV_SEPARATOR = ',';
|
constexpr char CSV_SEPARATOR = ',';
|
||||||
|
|
||||||
|
CsvCell::CsvCell(std::string value)
|
||||||
|
: m_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CsvCell::AsFloat(float& out) const
|
||||||
|
{
|
||||||
|
const char* startPtr = m_value.c_str();
|
||||||
|
char* endPtr;
|
||||||
|
out = std::strtof(startPtr, &endPtr);
|
||||||
|
|
||||||
|
if (endPtr == startPtr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto* c = endPtr; *c; c++)
|
||||||
|
{
|
||||||
|
if (!isspace(*c))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CsvCell::AsInt32(int32_t& out) const
|
||||||
|
{
|
||||||
|
const char* startPtr = m_value.c_str();
|
||||||
|
char* endPtr;
|
||||||
|
out = std::strtol(startPtr, &endPtr, 0);
|
||||||
|
|
||||||
|
if (endPtr == startPtr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto* c = endPtr; *c; c++)
|
||||||
|
{
|
||||||
|
if (!isspace(*c))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CsvCell::AsUInt32(uint32_t& out) const
|
||||||
|
{
|
||||||
|
const char* startPtr = m_value.c_str();
|
||||||
|
char* endPtr;
|
||||||
|
out = std::strtoul(startPtr, &endPtr, 0);
|
||||||
|
|
||||||
|
if (endPtr == startPtr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto* c = endPtr; *c; c++)
|
||||||
|
{
|
||||||
|
if (!isspace(*c))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
CsvInputStream::CsvInputStream(std::istream& stream)
|
CsvInputStream::CsvInputStream(std::istream& stream)
|
||||||
: m_stream(stream)
|
: m_stream(stream)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CsvInputStream::NextRow(std::vector<CsvCell>& out) const
|
||||||
|
{
|
||||||
|
if (!out.empty())
|
||||||
|
out.clear();
|
||||||
|
|
||||||
|
return EmitNextRow(
|
||||||
|
[&out](std::string value)
|
||||||
|
{
|
||||||
|
out.emplace_back(std::move(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool CsvInputStream::NextRow(std::vector<std::string>& out) const
|
bool CsvInputStream::NextRow(std::vector<std::string>& out) const
|
||||||
{
|
{
|
||||||
if (!out.empty())
|
if (!out.empty())
|
||||||
@ -38,13 +112,17 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
|||||||
auto c = m_stream.get();
|
auto c = m_stream.get();
|
||||||
const auto isEof = c == EOF;
|
const auto isEof = c == EOF;
|
||||||
std::ostringstream col;
|
std::ostringstream col;
|
||||||
|
auto content = false;
|
||||||
while (c != EOF)
|
while (c != EOF)
|
||||||
{
|
{
|
||||||
if (c == CSV_SEPARATOR)
|
if (c == CSV_SEPARATOR)
|
||||||
{
|
{
|
||||||
cb(col.str());
|
auto value = col.str();
|
||||||
|
utils::StringTrimR(value);
|
||||||
|
cb(std::move(value));
|
||||||
col.clear();
|
col.clear();
|
||||||
col.str(std::string());
|
col.str(std::string());
|
||||||
|
content = false;
|
||||||
}
|
}
|
||||||
else if (c == '\r')
|
else if (c == '\r')
|
||||||
{
|
{
|
||||||
@ -57,8 +135,14 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (isspace(c))
|
||||||
|
{
|
||||||
|
if (content)
|
||||||
|
col << static_cast<char>(c);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
content = true;
|
||||||
col << static_cast<char>(c);
|
col << static_cast<char>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +151,9 @@ bool CsvInputStream::EmitNextRow(const std::function<void(std::string)>& cb) con
|
|||||||
|
|
||||||
if (!isEof)
|
if (!isEof)
|
||||||
{
|
{
|
||||||
cb(col.str());
|
auto value = col.str();
|
||||||
|
utils::StringTrimR(value);
|
||||||
|
cb(std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return !isEof;
|
return !isEof;
|
||||||
|
@ -1,16 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Utils/MemoryManager.h"
|
#include "Utils/MemoryManager.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class CsvCell
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CsvCell(std::string value);
|
||||||
|
|
||||||
|
bool AsFloat(float& out) const;
|
||||||
|
bool AsInt32(int32_t& out) const;
|
||||||
|
bool AsUInt32(uint32_t& out) const;
|
||||||
|
|
||||||
|
std::string m_value;
|
||||||
|
};
|
||||||
|
|
||||||
class CsvInputStream
|
class CsvInputStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CsvInputStream(std::istream& stream);
|
explicit CsvInputStream(std::istream& stream);
|
||||||
|
|
||||||
|
bool NextRow(std::vector<CsvCell>& out) const;
|
||||||
bool NextRow(std::vector<std::string>& out) const;
|
bool NextRow(std::vector<std::string>& out) const;
|
||||||
bool NextRow(std::vector<const char*>& out, MemoryManager& memory) const;
|
bool NextRow(std::vector<const char*>& out, MemoryManager& memory) const;
|
||||||
|
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
#include "Csv/ParsedCsv.h"
|
|
||||||
|
|
||||||
ParsedCsvRow::ParsedCsvRow(std::unordered_map<std::string, size_t>& headers, std::vector<std::string> row)
|
|
||||||
: headers(headers),
|
|
||||||
values(std::move(row))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ParsedCsvRow::GetValue(const std::string& header, const bool required) const
|
|
||||||
{
|
|
||||||
if (this->headers.find(header) == this->headers.end())
|
|
||||||
{
|
|
||||||
if (required)
|
|
||||||
std::cerr << "ERROR: Required column \"" << header << "\" was not found\n";
|
|
||||||
else
|
|
||||||
std::cerr << "WARNING: Expected column \"" << header << "\" was not found\n";
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& value = this->values.at(this->headers[header]);
|
|
||||||
if (required && value.empty())
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: Required column \"" << header << "\" does not have a value\n";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ParsedCsvRow::GetValueFloat(const std::string& header, const bool required) const
|
|
||||||
{
|
|
||||||
const auto& value = this->GetValue(header, required);
|
|
||||||
if (!value.empty())
|
|
||||||
{
|
|
||||||
std::istringstream ss(value);
|
|
||||||
float out;
|
|
||||||
ss >> out;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ParsedCsv::ParsedCsv(const CsvInputStream& inputStream, const bool hasHeaders)
|
|
||||||
{
|
|
||||||
std::vector<std::vector<std::string>> csvLines;
|
|
||||||
std::vector<std::string> currentLine;
|
|
||||||
|
|
||||||
while (inputStream.NextRow(currentLine))
|
|
||||||
{
|
|
||||||
csvLines.emplace_back(std::move(currentLine));
|
|
||||||
currentLine = std::vector<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasHeaders)
|
|
||||||
{
|
|
||||||
const auto& headersRow = csvLines[0];
|
|
||||||
for (auto i = 0u; i < headersRow.size(); i++)
|
|
||||||
{
|
|
||||||
this->headers[headersRow[i]] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i = hasHeaders ? 1u : 0u; i < csvLines.size(); i++)
|
|
||||||
{
|
|
||||||
auto& rowValues = csvLines[i];
|
|
||||||
this->rows.emplace_back(this->headers, std::move(rowValues));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ParsedCsv::Size() const
|
|
||||||
{
|
|
||||||
return this->rows.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
ParsedCsvRow ParsedCsv::operator[](const size_t index) const
|
|
||||||
{
|
|
||||||
return this->rows.at(index);
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Csv/CsvStream.h"
|
|
||||||
#include "Utils/ClassUtils.h"
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class ParsedCsvRow
|
|
||||||
{
|
|
||||||
std::unordered_map<std::string, size_t>& headers;
|
|
||||||
std::vector<std::string> values;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ParsedCsvRow(std::unordered_map<std::string, size_t>& headers, std::vector<std::string> row);
|
|
||||||
_NODISCARD std::string GetValue(const std::string& header, bool required = false) const;
|
|
||||||
_NODISCARD float GetValueFloat(const std::string& header, bool required = false) const;
|
|
||||||
|
|
||||||
template<typename T> T GetValueInt(const std::string& header, const bool required = false) const
|
|
||||||
{
|
|
||||||
const auto& value = this->GetValue(header, required);
|
|
||||||
if (!value.empty())
|
|
||||||
{
|
|
||||||
std::istringstream ss(value);
|
|
||||||
long long out;
|
|
||||||
ss >> out;
|
|
||||||
return static_cast<T>(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ParsedCsv
|
|
||||||
{
|
|
||||||
std::unordered_map<std::string, size_t> headers;
|
|
||||||
std::vector<ParsedCsvRow> rows;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ParsedCsv(const CsvInputStream& inputStream, bool hasHeaders = true);
|
|
||||||
|
|
||||||
_NODISCARD size_t Size() const;
|
|
||||||
|
|
||||||
ParsedCsvRow operator[](size_t index) const;
|
|
||||||
};
|
|
@ -95,6 +95,43 @@ namespace T6
|
|||||||
"snp_x3",
|
"snp_x3",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// From SndDriverGlobals
|
||||||
|
inline constexpr const char* SOUND_PANS[]{
|
||||||
|
"default",
|
||||||
|
"music",
|
||||||
|
"wpn_all",
|
||||||
|
"wpn_fnt",
|
||||||
|
"wpn_rear",
|
||||||
|
"wpn_left",
|
||||||
|
"wpn_right",
|
||||||
|
"music_all",
|
||||||
|
"fly_foot_all",
|
||||||
|
"front",
|
||||||
|
"back",
|
||||||
|
"front_mostly",
|
||||||
|
"back_mostly",
|
||||||
|
"all",
|
||||||
|
"center",
|
||||||
|
"front_and_center",
|
||||||
|
"lfe",
|
||||||
|
"quad",
|
||||||
|
"front_mostly_some_center",
|
||||||
|
"front_halfback",
|
||||||
|
"halffront_back",
|
||||||
|
"test",
|
||||||
|
"brass_right",
|
||||||
|
"brass_left",
|
||||||
|
"veh_back",
|
||||||
|
"tst_left",
|
||||||
|
"tst_center",
|
||||||
|
"tst_right",
|
||||||
|
"tst_surround_left",
|
||||||
|
"tst_surround_right",
|
||||||
|
"tst_lfe",
|
||||||
|
"pip",
|
||||||
|
"movie_vo",
|
||||||
|
};
|
||||||
|
|
||||||
inline constexpr const char* SOUND_LIMIT_TYPES[]{
|
inline constexpr const char* SOUND_LIMIT_TYPES[]{
|
||||||
"none",
|
"none",
|
||||||
"oldest",
|
"oldest",
|
||||||
@ -138,9 +175,23 @@ namespace T6
|
|||||||
|
|
||||||
// From executable
|
// From executable
|
||||||
inline constexpr const char* SOUND_RANDOMIZE_TYPES[]{
|
inline constexpr const char* SOUND_RANDOMIZE_TYPES[]{
|
||||||
"",
|
|
||||||
"volume",
|
"volume",
|
||||||
"pitch",
|
"pitch",
|
||||||
"variant",
|
"variant",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline constexpr const char* SOUND_NO_YES[]{
|
||||||
|
"no",
|
||||||
|
"yes",
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr const char* SOUND_LOOP_TYPES[]{
|
||||||
|
"nonlooping",
|
||||||
|
"looping",
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr const char* SOUND_PAN_TYPES[]{
|
||||||
|
"2d",
|
||||||
|
"3d",
|
||||||
|
};
|
||||||
} // namespace T6
|
} // namespace T6
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
@ -102,13 +103,41 @@ namespace utils
|
|||||||
c = static_cast<char>(toupper(static_cast<unsigned char>(c)));
|
c = static_cast<char>(toupper(static_cast<unsigned char>(c)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> StringSplit(const std::string& str, const char delim)
|
void StringTrimL(std::string& str)
|
||||||
|
{
|
||||||
|
str.erase(str.begin(),
|
||||||
|
std::ranges::find_if(str,
|
||||||
|
[](const unsigned char ch)
|
||||||
|
{
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringTrimR(std::string& str)
|
||||||
|
{
|
||||||
|
str.erase(std::find_if(str.rbegin(),
|
||||||
|
str.rend(),
|
||||||
|
[](const unsigned char ch)
|
||||||
|
{
|
||||||
|
return !std::isspace(ch);
|
||||||
|
})
|
||||||
|
.base(),
|
||||||
|
str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringTrim(std::string& str)
|
||||||
|
{
|
||||||
|
StringTrimR(str);
|
||||||
|
StringTrimL(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> StringSplit(const std::string& str, const char delimiter)
|
||||||
{
|
{
|
||||||
std::vector<std::string> strings;
|
std::vector<std::string> strings;
|
||||||
std::istringstream stream(str);
|
std::istringstream stream(str);
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
while (std::getline(stream, s, delim))
|
while (std::getline(stream, s, delimiter))
|
||||||
{
|
{
|
||||||
strings.emplace_back(std::move(s));
|
strings.emplace_back(std::move(s));
|
||||||
}
|
}
|
||||||
|
@ -16,5 +16,9 @@ namespace utils
|
|||||||
void MakeStringLowerCase(std::string& str);
|
void MakeStringLowerCase(std::string& str);
|
||||||
void MakeStringUpperCase(std::string& str);
|
void MakeStringUpperCase(std::string& str);
|
||||||
|
|
||||||
std::vector<std::string> StringSplit(const std::string& str, const char delim);
|
void StringTrimL(std::string& str);
|
||||||
|
void StringTrimR(std::string& str);
|
||||||
|
void StringTrim(std::string& str);
|
||||||
|
|
||||||
|
std::vector<std::string> StringSplit(const std::string& str, char delimiter);
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
@ -21,7 +21,7 @@ set count head count;
|
|||||||
use SndAlias;
|
use SndAlias;
|
||||||
set string name;
|
set string name;
|
||||||
set string subtitle;
|
set string subtitle;
|
||||||
set string secondaryname;
|
set string secondaryName;
|
||||||
set string assetFileName;
|
set string assetFileName;
|
||||||
|
|
||||||
// SndDuck
|
// SndDuck
|
||||||
|
Loading…
x
Reference in New Issue
Block a user