diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 33b5778..c19a894 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,4 +14,5 @@ add_subdirectory(SpeedTreeLib) add_subdirectory(SphereLib) add_subdirectory(UserInterface) add_subdirectory(PackMaker) +add_subdirectory(DumpProto) add_subdirectory(PackLib) diff --git a/src/DumpProto/CMakeLists.txt b/src/DumpProto/CMakeLists.txt new file mode 100644 index 0000000..19db608 --- /dev/null +++ b/src/DumpProto/CMakeLists.txt @@ -0,0 +1,10 @@ +file(GLOB_RECURSE FILE_SOURCES "*.h" "*.c" "*.cpp") + +add_executable(DumpProto ${FILE_SOURCES}) +set_target_properties(DumpProto PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +) + +target_link_libraries(DumpProto + lzo2 +) \ No newline at end of file diff --git a/src/DumpProto/CsvFile.cpp b/src/DumpProto/CsvFile.cpp new file mode 100644 index 0000000..8c0d85c --- /dev/null +++ b/src/DumpProto/CsvFile.cpp @@ -0,0 +1,432 @@ +#include "CsvFile.h" +#include +#include + +#ifndef Assert + #include + #define Assert assert + #define LogToFile (void)(0); +#endif + +namespace +{ + /// �Ľ̿� state ���Ű� + enum ParseState + { + STATE_NORMAL = 0, ///< �Ϲ� ���� + STATE_QUOTE ///< ����ǥ ���� ���� + }; + + /// ���ڿ� �¿��� ������ �����ؼ� ��ȯ�Ѵ�. + std::string Trim(std::string str) + { + str = str.erase(str.find_last_not_of(" \t\r\n") + 1); + str = str.erase(0, str.find_first_not_of(" \t\r\n")); + return str; + } + + /// \brief �־��� ���忡 �ִ� ���ĺ��� ��� �ҹ��ڷ� �ٲ۴�. + std::string Lower(std::string original) + { + std::transform(original.begin(), original.end(), original.begin(), tolower); + return original; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ���� �׼����� ��, ���� ��� ����� �̸��� ����Ѵ�. +/// \param name �� �̸� +/// \param index �� �ε��� +//////////////////////////////////////////////////////////////////////////////// +void cCsvAlias::AddAlias(const char* name, size_t index) +{ + std::string converted(Lower(name)); + + Assert(m_Name2Index.find(converted) == m_Name2Index.end()); + Assert(m_Index2Name.find(index) == m_Index2Name.end()); + + m_Name2Index.insert(NAME2INDEX_MAP::value_type(converted, index)); + m_Index2Name.insert(INDEX2NAME_MAP::value_type(index, name)); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ��� �����͸� �����Ѵ�. +//////////////////////////////////////////////////////////////////////////////// +void cCsvAlias::Destroy() +{ + m_Name2Index.clear(); + m_Index2Name.clear(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ���� �ε����� �̸����� ��ȯ�Ѵ�. +/// \param index ���� �ε��� +/// \return const char* �̸� +//////////////////////////////////////////////////////////////////////////////// +const char* cCsvAlias::operator [] (size_t index) const +{ + INDEX2NAME_MAP::const_iterator itr(m_Index2Name.find(index)); + if (itr == m_Index2Name.end()) + { + LogToFile(NULL, "cannot find suitable conversion for %d", index); + Assert(false && "cannot find suitable conversion"); + return NULL; + } + + return itr->second.c_str(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief �̸��� ���� �ε����� ��ȯ�Ѵ�. +/// \param name �̸� +/// \return size_t ���� �ε��� +//////////////////////////////////////////////////////////////////////////////// +size_t cCsvAlias::operator [] (const char* name) const +{ + NAME2INDEX_MAP::const_iterator itr(m_Name2Index.find(Lower(name))); + if (itr == m_Name2Index.end()) + { + LogToFile(NULL, "cannot find suitable conversion for %s", name); + Assert(false && "cannot find suitable conversion"); + return 0; + } + + return itr->second; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ������ �̸��� CSV ������ �ε��Ѵ�. +/// \param fileName CSV ���� �̸� +/// \param seperator �ʵ� �и��ڷ� ����� ����. �⺻���� ','�̴�. +/// \param quote ����ǥ�� ����� ����. �⺻���� '"'�̴�. +/// \return bool ������ �ε��ߴٸ� true, �ƴ϶�� false +//////////////////////////////////////////////////////////////////////////////// +bool cCsvFile::Load(const char* fileName, const char seperator, const char quote) +{ + Assert(seperator != quote); + + // Open file in binary mode to preserve UTF-8 encoding + std::ifstream file(fileName, std::ios::in | std::ios::binary); + if (!file) return false; + + Destroy(); // ������ �����͸� ���� + + cCsvRow* row = NULL; + ParseState state = STATE_NORMAL; + std::string token = ""; + char buf[2048+1] = {0,}; + + while (file.good()) + { + file.getline(buf, 2048); + buf[sizeof(buf)-1] = 0; + + std::string line(Trim(buf)); + if (line.empty() || (state == STATE_NORMAL && line[0] == '#')) continue; + + std::string text = std::string(line) + " "; // �Ľ� lookahead ������ �ٿ��ش�. + size_t cur = 0; + + while (cur < text.size()) + { + // ���� ��尡 QUOTE ����� ��, + if (state == STATE_QUOTE) + { + // '"' ������ ������ �� �����̴�. + // 1. �� ���ο� Ư�� ���ڰ� ���� ��� �̸� �˸��� �� �¿��� �� + // 2. �� ������ '"' ���ڰ� '"' 2���� ġȯ�� �� + // �� �� ù��° ����� ������ �ִ� ���� CSV ������ �������̶��, + // ������ STATE_NORMAL�� �ɸ��� �Ǿ��ִ�. + // �׷��Ƿ� ���⼭ �ɸ��� ���� 1���� ���� ��쳪, 2�� ��� ���̴�. + // 2���� ��쿡�� ������ '"' ���ڰ� 2���� ��Ÿ����. ������ 1���� + // ���� ��쿡�� �ƴϴ�. �̸� �������� �ؼ� �ڵ带 ¥��... + if (text[cur] == quote) + { + // ���� ���ڰ� '"' ���ڶ��, �� ���ӵ� '"' ���ڶ�� + // �̴� �� ������ '"' ���ڰ� ġȯ�� ���̴�. + if (text[cur+1] == quote) + { + token += quote; + ++cur; + } + // ���� ���ڰ� '"' ���ڰ� �ƴ϶�� + // ������ '"'���ڴ� ���� ���� �˸��� ���ڶ�� �� �� �ִ�. + else + { + state = STATE_NORMAL; + } + } + else + { + token += text[cur]; + } + } + // ���� ��尡 NORMAL ����� ��, + else if (state == STATE_NORMAL) + { + if (row == NULL) + row = new cCsvRow(); + + // ',' ���ڸ� �����ٸ� ���� ���� �ǹ��Ѵ�. + // ��ū���μ� �� ����Ʈ���ٰ� ����ְ�, ��ū�� �ʱ�ȭ�Ѵ�. + if (text[cur] == seperator) + { + row->push_back(token); + token.clear(); + } + // '"' ���ڸ� �����ٸ�, QUOTE ���� ��ȯ�Ѵ�. + else if (text[cur] == quote) + { + state = STATE_QUOTE; + } + // �ٸ� �Ϲ� ���ڶ�� ���� ��ū���ٰ� �����δ�. + else + { + token += text[cur]; + } + } + + ++cur; + } + + // ������ ���� ���� ',' ���ڰ� ���� ������ ���⼭ �߰�������Ѵ�. + // ��, ó���� �Ľ� lookahead ������ ���� �����̽� ���� �� ���� ����. + if (state == STATE_NORMAL) + { + Assert(row != NULL); + row->push_back(token.substr(0, token.size()-2)); + m_Rows.push_back(row); + token.clear(); + row = NULL; + } + else + { + token = token.substr(0, token.size()-2) + "\r\n"; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ������ �ִ� ������ CSV ���Ͽ��� �����Ѵ�. +/// \param fileName CSV ���� �̸� +/// \param append true�� ���, ������ ���Ͽ��� �����δ�. false�� ��쿡�� +/// ������ ���� ������ �����ϰ�, ���� ����. +/// \param seperator �ʵ� �и��ڷ� ����� ����. �⺻���� ','�̴�. +/// \param quote ����ǥ�� ����� ����. �⺻���� '"'�̴�. +/// \return bool ������ �����ߴٸ� true, ������ ���� ��쿡�� false +//////////////////////////////////////////////////////////////////////////////// +bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quote) const +{ + Assert(seperator != quote); + + // ��� ��忡 ���� ������ ������ �÷��׷� �����Ѵ�. + std::ofstream file; + if (append) { file.open(fileName, std::ios::out | std::ios::app); } + else { file.open(fileName, std::ios::out | std::ios::trunc); } + + // ������ ���� ���ߴٸ�, false�� �����Ѵ�. + if (!file) return false; + + char special_chars[5] = { seperator, quote, '\r', '\n', 0 }; + char quote_escape_string[3] = { quote, quote, 0 }; + + // ��� ���� Ⱦ���ϸ鼭... + for (size_t i=0; isize(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief �ε����� �̿��� int ������ �� ���� ��ȯ�Ѵ�. +/// \param index �� �ε��� +/// \return int �� �� +//////////////////////////////////////////////////////////////////////////////// +int cCsvTable::AsInt(size_t index) const +{ + const cCsvRow* const row = CurRow(); + Assert(row); + Assert(index < row->size()); + return row->AsInt(index); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief �ε����� �̿��� double ������ �� ���� ��ȯ�Ѵ�. +/// \param index �� �ε��� +/// \return double �� �� +//////////////////////////////////////////////////////////////////////////////// +double cCsvTable::AsDouble(size_t index) const +{ + const cCsvRow* const row = CurRow(); + Assert(row); + Assert(index < row->size()); + return row->AsDouble(index); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief �ε����� �̿��� std::string ������ �� ���� ��ȯ�Ѵ�. +/// \param index �� �ε��� +/// \return const char* �� �� +//////////////////////////////////////////////////////////////////////////////// +const char* cCsvTable::AsStringByIndex(size_t index) const +{ + const cCsvRow* const row = CurRow(); + Assert(row); + Assert(index < row->size()); + return row->AsString(index); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief alias�� ������ ��� �����͸� �����Ѵ�. +//////////////////////////////////////////////////////////////////////////////// +void cCsvTable::Destroy() +{ + m_File.Destroy(); + m_Alias.Destroy(); + m_CurRow = -1; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \brief ���� ���� ��ȯ�Ѵ�. +/// \return const cCsvRow* �׼����� ������ ���� ���� �����ϴ� ��쿡�� �� ���� +/// �����͸� ��ȯ�ϰ�, �� �̻� �׼��� ������ ���� ���� ��쿡�� NULL�� +/// ��ȯ�Ѵ�. +//////////////////////////////////////////////////////////////////////////////// +const cCsvRow* const cCsvTable::CurRow() const +{ + if (m_CurRow < 0) + { + Assert(false && "call Next() first!"); + return NULL; + } + else if (m_CurRow >= (int)m_File.GetRowCount()) + { + Assert(false && "no more rows!"); + return NULL; + } + + return m_File[m_CurRow]; +} + + + diff --git a/src/DumpProto/CsvFile.h b/src/DumpProto/CsvFile.h new file mode 100644 index 0000000..90c02c7 --- /dev/null +++ b/src/DumpProto/CsvFile.h @@ -0,0 +1,325 @@ +#ifndef __CSVFILE_H__ +#define __CSVFILE_H__ + +#include +#include + +#if _MSC_VER + //#include + #include +#else + #include +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// \class cCsvAlias +/// \brief CSV ߻ϴ ε ̱ +/// ü. +/// +/// 0 ÷ A ϰ, 1 ÷ B +/// ϰ ־µ... +/// +///
+/// int a = row.AsInt(0);
+/// int b = row.AsInt(1);
+/// 
+/// +/// ̿ C ϴ ÷ , ϵڵǾ ִ +/// 1 ãƼ ľ ϴµ, ߻ϱ ۾̴. +/// +///
+/// int a = row.AsInt(0);
+/// int c = row.AsInt(1);
+/// int b = row.AsInt(2); <--  κ  Ű Ѵ.
+/// 
+/// +/// κ ڿ óϸ  ణ̳ +/// ִ. +//////////////////////////////////////////////////////////////////////////////// + +class cCsvAlias +{ +private: +#if _MSC_VER + //typedef stdext::hash_map NAME2INDEX_MAP; + //typedef stdext::hash_map INDEX2NAME_MAP; + typedef std::unordered_map NAME2INDEX_MAP; + typedef std::unordered_map INDEX2NAME_MAP; +#else + typedef std::map NAME2INDEX_MAP; + typedef std::map INDEX2NAME_MAP; +#endif + + NAME2INDEX_MAP m_Name2Index; ///< ε ϱ ̸ + INDEX2NAME_MAP m_Index2Name; ///< ߸ alias ˻ϱ ߰ + + +public: + /// \brief + cCsvAlias() {} + + /// \brief Ҹ + virtual ~cCsvAlias() {} + + +public: + /// \brief ׼ , ̸ Ѵ. + void AddAlias(const char* name, size_t index); + + /// \brief ͸ Ѵ. + void Destroy(); + + /// \brief ε ̸ ȯѴ. + const char* operator [] (size_t index) const; + + /// \brief ̸ ε ȯѴ. + size_t operator [] (const char* name) const; + + +private: + /// \brief + cCsvAlias(const cCsvAlias&) {} + + /// \brief + const cCsvAlias& operator = (const cCsvAlias&) { return *this; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// \class cCsvRow +/// \brief CSV ĸȭ Ŭ +/// +/// CSV ⺻ ̴ ϳ ',' ڷ ̴. +/// , ȿ Ư ڷ ̴ ',' ڳ '"' ڰ  , +/// ణ ̻ϰ Ѵ. ȭ ̴. +/// +///
+///  ̴  |  CSV Ͽ ִ 
+/// ---------------------+----------------------------------------------------
+/// ItemPrice            | ItemPrice
+/// Item,Price           | "Item,Price"
+/// Item"Price           | "Item""Price"
+/// "ItemPrice"          | """ItemPrice"""
+/// "Item,Price"         | """Item,Price"""
+/// Item",Price          | "Item"",Price"
+/// 
+/// +/// μ ִ. +/// - ο ',' Ǵ '"' ڰ  , ¿쿡 '"' ڰ . +/// - '"' ڴ 2 ġȯȴ. +/// +/// \sa cCsvFile +//////////////////////////////////////////////////////////////////////////////// + +class cCsvRow : public std::vector +{ +public: + /// \brief ⺻ + cCsvRow() {} + + /// \brief Ҹ + ~cCsvRow() {} + + +public: + /// \brief ش ͸ int ȯѴ. + int AsInt(size_t index) const { return atoi(at(index).c_str()); } + + /// \brief ش ͸ double ȯѴ. + double AsDouble(size_t index) const { return atof(at(index).c_str()); } + + /// \brief ش ͸ ڿ ȯѴ. + const char* AsString(size_t index) const { return at(index).c_str(); } + + /// \brief شϴ ̸ ͸ int ȯѴ. + int AsInt(const char* name, const cCsvAlias& alias) const { + return atoi( at(alias[name]).c_str() ); + } + + /// \brief شϴ ̸ ͸ int ȯѴ. + double AsDouble(const char* name, const cCsvAlias& alias) const { + return atof( at(alias[name]).c_str() ); + } + + /// \brief شϴ ̸ ͸ ڿ ȯѴ. + const char* AsString(const char* name, const cCsvAlias& alias) const { + return at(alias[name]).c_str(); + } + + +private: + /// \brief + cCsvRow(const cCsvRow&) {} + + /// \brief + const cCsvRow& operator = (const cCsvRow&) { return *this; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// \class cCsvFile +/// \brief CSV(Comma Seperated Values) read/writeϱ Ŭ +/// +/// sample +///
+/// cCsvFile file;
+///
+/// cCsvRow row1, row2, row3;
+/// row1.push_back("ItemPrice");
+/// row1.push_back("Item,Price");
+/// row1.push_back("Item\"Price");
+///
+/// row2.reserve(3);
+/// row2[0] = "\"ItemPrice\"";
+/// row2[1] = "\"Item,Price\"";
+/// row2[2] = "Item\",Price\"";
+///
+/// row3 = "\"ItemPrice\"\"Item,Price\"Item\",Price\"";
+///
+/// file.add(row1);
+/// file.add(row2);
+/// file.add(row3);
+/// file.save("test.csv", false);
+/// 
+/// +/// \todo Ͽ о ƴ϶, ޸ ҽκ д Լ +/// ־ ϴ. +//////////////////////////////////////////////////////////////////////////////// + +class cCsvFile +{ +private: + typedef std::vector ROWS; + + ROWS m_Rows; ///< ÷ + + +public: + /// \brief + cCsvFile() {} + + /// \brief Ҹ + virtual ~cCsvFile() { Destroy(); } + + +public: + /// \brief ̸ CSV εѴ. + bool Load(const char* fileName, const char seperator=',', const char quote='"'); + + /// \brief ִ CSV Ͽ Ѵ. + bool Save(const char* fileName, bool append=false, char seperator=',', char quote='"') const; + + /// \brief ͸ ޸𸮿 Ѵ. + void Destroy(); + + /// \brief شϴ ε ȯѴ. + cCsvRow* operator [] (size_t index); + + /// \brief شϴ ε ȯѴ. + const cCsvRow* operator [] (size_t index) const; + + /// \brief ȯѴ. + size_t GetRowCount() const { return m_Rows.size(); } + + +private: + /// \brief + cCsvFile(const cCsvFile&) {} + + /// \brief + const cCsvFile& operator = (const cCsvFile&) { return *this; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// \class cCsvTable +/// \brief CSV ̿ ̺ ͸ εϴ 찡 , Ŭ +/// ۾ ϱ ƿƼ Ŭ. +/// +/// CSV εϴ , ڸ ̿ ׼ؾ ϴµ, CSV +/// ٲ , ڵ Ѵ. ۾ +/// Ű 䱸ϴ ٰ, ߻ϱ . ׷Ƿ ڷ +/// ׼ϱ⺸ٴ ڿ ׼ϴ ణ ٰ ִ. +/// +/// sample +///
+/// cCsvTable table;
+///
+/// table.alias(0, "ItemClass");
+/// table.alias(1, "ItemType");
+///
+/// if (table.load("test.csv"))
+/// {
+///     while (table.next())
+///     {
+///         std::string item_class = table.AsString("ItemClass");
+///         int         item_type  = table.AsInt("ItemType"); 
+///     }
+/// }
+/// 
+//////////////////////////////////////////////////////////////////////////////// + +class cCsvTable +{ +public : + cCsvFile m_File; ///< CSV ü +private: + cCsvAlias m_Alias; ///< ڿ ε ȯϱ ü + int m_CurRow; ///< Ⱦ ȣ + + +public: + /// \brief + cCsvTable(); + + /// \brief Ҹ + virtual ~cCsvTable(); + + +public: + /// \brief ̸ CSV εѴ. + bool Load(const char* fileName, const char seperator=',', const char quote='"'); + + /// \brief ׼ , ̸ Ѵ. + void AddAlias(const char* name, size_t index) { m_Alias.AddAlias(name, index); } + + /// \brief Ѿ. + bool Next(); + + /// \brief ڸ ȯѴ. + size_t ColCount() const; + + /// \brief ε ̿ int ȯѴ. + int AsInt(size_t index) const; + + /// \brief ε ̿ double ȯѴ. + double AsDouble(size_t index) const; + + /// \brief ε ̿ std::string ȯѴ. + const char* AsStringByIndex(size_t index) const; + + /// \brief ̸ ̿ int ȯѴ. + int AsInt(const char* name) const { return AsInt(m_Alias[name]); } + + /// \brief ̸ ̿ double ȯѴ. + double AsDouble(const char* name) const { return AsDouble(m_Alias[name]); } + + /// \brief ̸ ̿ std::string ȯѴ. + const char* AsString(const char* name) const { return AsStringByIndex(m_Alias[name]); } + + /// \brief alias ͸ Ѵ. + void Destroy(); + + +private: + /// \brief ȯѴ. + const cCsvRow* const CurRow() const; + + /// \brief + cCsvTable(const cCsvTable&) {} + + /// \brief + const cCsvTable& operator = (const cCsvTable&) { return *this; } +}; + +#endif //__CSVFILE_H__ diff --git a/src/DumpProto/ItemCSVReader.cpp b/src/DumpProto/ItemCSVReader.cpp new file mode 100644 index 0000000..547d747 --- /dev/null +++ b/src/DumpProto/ItemCSVReader.cpp @@ -0,0 +1,566 @@ +#include +#include "ItemCSVReader.h" + + + +using namespace std; + +inline string trim_left(const string& str) +{ + string::size_type n = str.find_first_not_of(" \t\v\n\r"); + return n == string::npos ? str : str.substr(n, str.length()); +} + +inline string trim_right(const string& str) +{ + string::size_type n = str.find_last_not_of(" \t\v\n\r"); + return n == string::npos ? str : str.substr(0, n + 1); +} + +string trim(const string& str){return trim_left(trim_right(str));} + +static string* StringSplit(string strOrigin, string strTok) +{ + int cutAt; //ڸġ + int index = 0; //ڿε + string* strResult = new string[30]; //return Һ + + //strTokãݺ + while ((cutAt = strOrigin.find_first_of(strTok)) != strOrigin.npos) + { + if (cutAt > 0) //ڸġ0ũ() + { + strResult[index++] = strOrigin.substr(0, cutAt); //迭߰ + } + strOrigin = strOrigin.substr(cutAt+1); //ڸκѳ + } + + if(strOrigin.length() > 0) //̾ + { + strResult[index++] = strOrigin.substr(0, cutAt); //迭߰ + } + + for( int i=0;i "; + for (int j=0;j "; + for (int j=0;j " << retValue << endl; + + return retValue; +} + +int get_Item_Flag_Value(string inputString) +{ + + string arFlag[] = {"ITEM_TUNABLE", "ITEM_SAVE", "ITEM_STACKABLE", "COUNT_PER_1GOLD", "ITEM_SLOW_QUERY", "ITEM_UNIQUE", + "ITEM_MAKECOUNT", "ITEM_IRREMOVABLE", "CONFIRM_WHEN_USE", "QUEST_USE", "QUEST_USE_MULTIPLE", + "QUEST_GIVE", "ITEM_QUEST", "LOG", "STACKABLE", "SLOW_QUERY", "REFINEABLE", "IRREMOVABLE", "ITEM_APPLICABLE"}; + + + int retValue = 0; + string* arInputString = StringSplit(inputString, "|"); // ܾ ɰ 迭. + for(int i =0;i " << retValue << endl; + + return retValue; +} + +int get_Item_WearFlag_Value(string inputString) +{ + + string arWearrFlag[] = {"WEAR_BODY", "WEAR_HEAD", "WEAR_FOOTS", "WEAR_WRIST", "WEAR_WEAPON", "WEAR_NECK", "WEAR_EAR", "WEAR_SHIELD", "WEAR_UNIQUE", + "WEAR_ARROW", "WEAR_HAIR", "WEAR_ABILITY"}; + + + int retValue = 0; + string* arInputString = StringSplit(inputString, "|"); // ܾ ɰ 迭. + for(int i =0;i " << retValue << endl; + + return retValue; +} + +int get_Item_Immune_Value(string inputString) +{ + + string arImmune[] = {"PARA","CURSE","STUN","SLEEP","SLOW","POISON","TERROR"}; + + int retValue = 0; + string* arInputString = StringSplit(inputString, "|"); // ܾ ɰ 迭. + for(int i =0;i " << retValue << endl; + + return retValue; +} + + + + +int get_Item_LimitType_Value(string inputString) +{ + string arLimitType[] = {"LIMIT_NONE", "LEVEL", "STR", "DEX", "INT", "CON", "PC_BANG", "REAL_TIME", "REAL_TIME_FIRST_USE", "TIMER_BASED_ON_WEAR"}; + + int retInt = -1; + //cout << "LimitType : " << limitTypeStr << " -> "; + for (int j=0;j "; + for (int j=0;j "; + for (int j=0;j "; + for (int j=0;j "; + for (int j=0;j "; + for (int j=0;j " << retValue << endl; + + return retValue; +} +int get_Mob_RaceFlag_Value(string inputString) +{ + string arRaceFlag[] = {"ANIMAL","UNDEAD","DEVIL","HUMAN","ORC","MILGYO","INSECT","FIRE","ICE","DESERT","TREE", + "ATT_ELEC","ATT_FIRE","ATT_ICE","ATT_WIND","ATT_EARTH","ATT_DARK"}; + + int retValue = 0; + string* arInputString = StringSplit(inputString, "|"); // ܾ ɰ 迭. + for(int i =0;i " << retValue << endl; + + return retValue; +} +int get_Mob_ImmuneFlag_Value(string inputString) +{ + string arImmuneFlag[] = {"STUN","SLOW","FALL","CURSE","POISON","TERROR"}; + + int retValue = 0; + string* arInputString = StringSplit(inputString, ","); // ܾ ɰ 迭. + for(int i =0;i " << retValue << endl; + + + return retValue; +} diff --git a/src/DumpProto/ItemCSVReader.h b/src/DumpProto/ItemCSVReader.h new file mode 100644 index 0000000..94d6ce0 --- /dev/null +++ b/src/DumpProto/ItemCSVReader.h @@ -0,0 +1,29 @@ +#ifndef __Item_CSV_READER_H__ +#define __Item_CSV_READER_H__ + +#include + +//csv оͼ ̺ ־ش. +void putItemIntoTable(); //(̺, ׽Ʈ) + +int get_Item_Type_Value(std::string inputString); +int get_Item_SubType_Value(int type_value, std::string inputString); +int get_Item_AntiFlag_Value(std::string inputString); +int get_Item_Flag_Value(std::string inputString); +int get_Item_WearFlag_Value(std::string inputString); +int get_Item_Immune_Value(std::string inputString); +int get_Item_LimitType_Value(std::string inputString); +int get_Item_ApplyType_Value(std::string inputString); + + +// 䵵 ִ. +int get_Mob_Rank_Value(std::string inputString); +int get_Mob_Type_Value(std::string inputString); +int get_Mob_BattleType_Value(std::string inputString); + +int get_Mob_Size_Value(std::string inputString); +int get_Mob_AIFlag_Value(std::string inputString); +int get_Mob_RaceFlag_Value(std::string inputString); +int get_Mob_ImmuneFlag_Value(std::string inputString); + +#endif \ No newline at end of file diff --git a/src/DumpProto/Singleton.h b/src/DumpProto/Singleton.h new file mode 100644 index 0000000..e5d118c --- /dev/null +++ b/src/DumpProto/Singleton.h @@ -0,0 +1,112 @@ +#ifndef __INC_ETERLIB_SINGLETON_H__ +#define __INC_ETERLIB_SINGLETON_H__ + +#include + +template class CSingleton +{ + static T * ms_singleton; + +public: + CSingleton() + { + assert(!ms_singleton); + ms_singleton = (T*) this; + } + + virtual ~CSingleton() + { + assert(ms_singleton); + ms_singleton = 0; + } + + __forceinline static T & Instance() + { + assert(ms_singleton); + return (*ms_singleton); + } + + __forceinline static T * InstancePtr() + { + return (ms_singleton); + } + + __forceinline static T & instance() + { + assert(ms_singleton); + return (*ms_singleton); + } +}; + +template T * CSingleton ::ms_singleton = 0; + +// +// singleton for non-hungarian +// +template class singleton +{ + static T * ms_singleton; + +public: + singleton() + { + assert(!ms_singleton); + ms_singleton = (T*) this; + } + + virtual ~singleton() + { + assert(ms_singleton); + ms_singleton = 0; + } + + __forceinline static T & Instance() + { + assert(ms_singleton); + return (*ms_singleton); + } + + __forceinline static T * InstancePtr() + { + return (ms_singleton); + } + + __forceinline static T & instance() + { + assert(ms_singleton); + return (*ms_singleton); + } +}; + +template T * singleton ::ms_singleton = 0; + +/* +template +class CSingleton : public T +{ + public: + static T & Instance() + { + assert(ms_pInstance != NULL); + return *ms_pInstance; + } + + CSingleton() + { + assert(ms_pInstance == NULL); + ms_pInstance = this; + } + + virtual ~CSingleton() + { + assert(ms_pInstance); + ms_pInstance = 0; + } + + protected: + static T * ms_pInstance; +}; + +template T * CSingleton::ms_pInstance = NULL; +*/ +#endif diff --git a/src/DumpProto/dump_proto.cpp b/src/DumpProto/dump_proto.cpp new file mode 100644 index 0000000..9c955ba --- /dev/null +++ b/src/DumpProto/dump_proto.cpp @@ -0,0 +1,1186 @@ +//#include "../../libthecore/include/stdafx.h" +//#include "" +//#define __WIN32__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lzo.h" + +//������exe���� ����鼭 ���� �߰� : ���� �о�� �� �ֵ��� �Ͽ���. +#include "CsvFile.h" +#include "ItemCSVReader.h" + + +#pragma comment(lib, "lzo2.lib") + + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +enum EMisc +{ + CHARACTER_NAME_MAX_LEN = 64, + MOB_SKILL_MAX_NUM = 5, +}; + +enum EMobEnchants +{ + MOB_ENCHANT_CURSE, + MOB_ENCHANT_SLOW, + MOB_ENCHANT_POISON, + MOB_ENCHANT_STUN, + MOB_ENCHANT_CRITICAL, + MOB_ENCHANT_PENETRATE, + MOB_ENCHANTS_MAX_NUM +}; + +enum EMobResists +{ + MOB_RESIST_SWORD, + MOB_RESIST_TWOHAND, + MOB_RESIST_DAGGER, + MOB_RESIST_BELL, + MOB_RESIST_FAN, + MOB_RESIST_BOW, + MOB_RESIST_FIRE, + MOB_RESIST_ELECT, + MOB_RESIST_MAGIC, + MOB_RESIST_WIND, + MOB_RESIST_POISON, + MOB_RESISTS_MAX_NUM +}; + + +#pragma pack(1) +typedef struct SMobSkillLevel +{ + DWORD dwVnum; + BYTE bLevel; +} TMobSkillLevel; +#pragma pack() + +#pragma pack(1) +typedef struct SMobTable +{ + DWORD dwVnum; + char szName[CHARACTER_NAME_MAX_LEN + 1]; + char szLocaleName[CHARACTER_NAME_MAX_LEN + 1]; + + BYTE bType; // Monster, NPC + BYTE bRank; // PAWN, KNIGHT, KING + BYTE bBattleType; // MELEE, etc.. + BYTE bLevel; // Level + BYTE bSize; + + DWORD dwGoldMin; + DWORD dwGoldMax; + DWORD dwExp; + DWORD dwMaxHP; + BYTE bRegenCycle; + BYTE bRegenPercent; + WORD wDef; + + DWORD dwAIFlag; + DWORD dwRaceFlag; + DWORD dwImmuneFlag; + + BYTE bStr, bDex, bCon, bInt; + DWORD dwDamageRange[2]; + + short sAttackSpeed; + short sMovingSpeed; + BYTE bAggresiveHPPct; + WORD wAggressiveSight; + WORD wAttackRange; + + char cEnchants[MOB_ENCHANTS_MAX_NUM]; + char cResists[MOB_RESISTS_MAX_NUM]; + + DWORD dwResurrectionVnum; + DWORD dwDropItemVnum; + + BYTE bMountCapacity; + BYTE bOnClickType; + + BYTE bEmpire; + char szFolder[64 + 1]; + + float fDamMultiply; + + DWORD dwSummonVnum; + DWORD dwDrainSP; + DWORD dwMobColor; + DWORD dwPolymorphItemVnum; + + TMobSkillLevel Skills[MOB_SKILL_MAX_NUM]; + + BYTE bBerserkPoint; + BYTE bStoneSkinPoint; + BYTE bGodSpeedPoint; + BYTE bDeathBlowPoint; + BYTE bRevivePoint; +} TMobTable; +#pragma pack() + + +using namespace std; + +TMobTable * m_pMobTable = NULL; +int m_iMobTableSize = 0; + + +enum EItemMisc +{ + ITEM_NAME_MAX_LEN = 64, + ITEM_VALUES_MAX_NUM = 6, + ITEM_SMALL_DESCR_MAX_LEN = 256, + ITEM_LIMIT_MAX_NUM = 2, + ITEM_APPLY_MAX_NUM = 3, + ITEM_SOCKET_MAX_NUM = 3, + ITEM_MAX_COUNT = 200, + ITEM_ATTRIBUTE_MAX_NUM = 7, + ITEM_ATTRIBUTE_MAX_LEVEL = 5, + ITEM_AWARD_WHY_MAX_LEN = 50, + + REFINE_MATERIAL_MAX_NUM = 5, + + ITEM_ELK_VNUM = 50026, +}; +#pragma pack(1) +typedef struct SItemLimit +{ + BYTE bType; + long lValue; +} TItemLimit; +#pragma pack() + +#pragma pack(1) +typedef struct SItemApply +{ + BYTE bType; + long lValue; +} TItemApply; +#pragma pack() + +#pragma pack(1) +typedef struct +{ + DWORD dwVnum; + DWORD dwVnumRange; + char szName[ITEM_NAME_MAX_LEN + 1]; + char szLocaleName[ITEM_NAME_MAX_LEN + 1]; + BYTE bType; + BYTE bSubType; + + BYTE bWeight; + BYTE bSize; + + DWORD dwAntiFlags; + DWORD dwFlags; + DWORD dwWearFlags; + DWORD dwImmuneFlag; + + DWORD dwGold; + DWORD dwShopBuyPrice; + + TItemLimit aLimits[ITEM_LIMIT_MAX_NUM]; + TItemApply aApplies[ITEM_APPLY_MAX_NUM]; + long alValues[ITEM_VALUES_MAX_NUM]; + long alSockets[ITEM_SOCKET_MAX_NUM]; + DWORD dwRefinedVnum; + WORD wRefineSet; + BYTE bAlterToMagicItemPct; + BYTE bSpecular; + BYTE bGainSocketPct; +} TClientItemTable; +#pragma pack() +bool operator < (const TClientItemTable& lhs, const TClientItemTable& rhs) +{ + return lhs.dwVnum < rhs.dwVnum; +} + +TClientItemTable * m_pItemTable = NULL; +int m_iItemTableSize = 0; + + +bool Set_Proto_Mob_Table(TMobTable *mobTable, cCsvTable &csvTable, std::map &nameMap) +{ + int col = 0; + + mobTable->dwVnum = atoi(csvTable.AsStringByIndex(col++)); + strncpy(mobTable->szName, csvTable.AsStringByIndex(col++), CHARACTER_NAME_MAX_LEN); + //���� ������ �����ϸ� ������ �о��. + map::iterator it; + it = nameMap.find(mobTable->dwVnum); + if (it != nameMap.end()) { + const char * localeName = it->second; + strncpy(mobTable->szLocaleName, localeName, sizeof (mobTable->szLocaleName)); + } else { //���� ������ ������, �ѱ��� �״�� ���. + strncpy(mobTable->szLocaleName, mobTable->szName, sizeof (mobTable->szLocaleName)); + } + //4. RANK + int rankValue = get_Mob_Rank_Value(csvTable.AsStringByIndex(col++)); + mobTable->bRank = rankValue; + //5. TYPE + int typeValue = get_Mob_Type_Value(csvTable.AsStringByIndex(col++)); + mobTable->bType = typeValue; + //6. BATTLE_TYPE + int battleTypeValue = get_Mob_BattleType_Value(csvTable.AsStringByIndex(col++)); + mobTable->bBattleType = battleTypeValue; + + mobTable->bLevel = atoi(csvTable.AsStringByIndex(col++)); + //8. SIZE + int sizeValue = get_Mob_Size_Value(csvTable.AsStringByIndex(col++)); + mobTable->bSize = sizeValue; + //9. AI_FLAG + int aiFlagValue = get_Mob_AIFlag_Value(csvTable.AsStringByIndex(col++)); + mobTable->dwAIFlag = aiFlagValue; + col++; //mount_capacity; + //10. RACE_FLAG + int raceFlagValue = get_Mob_RaceFlag_Value(csvTable.AsStringByIndex(col++)); + mobTable->dwRaceFlag = raceFlagValue; + //11. IMMUNE_FLAG + int immuneFlagValue = get_Mob_ImmuneFlag_Value(csvTable.AsStringByIndex(col++)); + mobTable->dwImmuneFlag = immuneFlagValue; + + mobTable->bEmpire = atoi(csvTable.AsStringByIndex(col++)); + + //folder + strncpy(mobTable->szFolder, csvTable.AsStringByIndex(col++), sizeof(mobTable->szFolder)); + + + mobTable->bOnClickType = atoi(csvTable.AsStringByIndex(col++)); + + mobTable->bStr = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bDex = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bCon = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bInt = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwDamageRange[0] = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwDamageRange[1] = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwMaxHP = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bRegenCycle = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bRegenPercent = atoi(csvTable.AsStringByIndex(col++)); + + col++; //gold min + col++; //gold max + mobTable->dwExp = atoi(csvTable.AsStringByIndex(col++)); + mobTable->wDef = atoi(csvTable.AsStringByIndex(col++)); + mobTable->sAttackSpeed = atoi(csvTable.AsStringByIndex(col++)); + mobTable->sMovingSpeed = atoi(csvTable.AsStringByIndex(col++)); + mobTable->bAggresiveHPPct = atoi(csvTable.AsStringByIndex(col++)); + mobTable->wAggressiveSight = atoi(csvTable.AsStringByIndex(col++)); + mobTable->wAttackRange = atoi(csvTable.AsStringByIndex(col++)); + + mobTable->dwDropItemVnum = atoi(csvTable.AsStringByIndex(col++)); + col++; //resurrectionVnum + + + for (int i = 0; i < MOB_ENCHANTS_MAX_NUM; ++i) + mobTable->cEnchants[i] = atoi(csvTable.AsStringByIndex(col++)); + + for (int i = 0; i < MOB_RESISTS_MAX_NUM; ++i) + mobTable->cResists[i] = atoi(csvTable.AsStringByIndex(col++)); + + mobTable->fDamMultiply = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwSummonVnum = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwDrainSP = atoi(csvTable.AsStringByIndex(col++)); + mobTable->dwMobColor = atoi(csvTable.AsStringByIndex(col++)); + + return true; +} +bool BuildMobTable(const char* nameFile) +{ + + fprintf(stderr, "sizeof(TMobTable): %u\n", sizeof(TMobTable)); + + + //==============================================================// + //======local�� ���� �̸��� �����ϰ� �ִ� [��] vnum:name======// + //==============================================================// + bool isNameFile = true; + map localMap; + cCsvTable nameData; + if(!nameData.Load(nameFile,'\t')) + { + fprintf(stderr, "%s ������ �о���� ���߽��ϴ�\n", nameFile); + isNameFile = false; + } else { + nameData.Next(); + while(nameData.Next()) { + localMap[atoi(nameData.AsStringByIndex(0))] = nameData.AsStringByIndex(1); + } + } + //______________________________________________________________// + + //=========================================// + //======���͵��� vnum�� ������ [��]======// + // *�׽�Ʈ�� ������ ���� �о�ö�, // + // 1. ������ �ִ� ���������� Ȯ���Ҷ� ���// + //=========================================// + set vnumSet; + //_________________________________________// + + //==================================================// + // 2)'mob_proto_test.txt' ������ �о, + // test_mob_table �� �����, + // vnum:TMobTable ���� �����. + //==================================================// + map test_map_mobTableByVnum; + + //1. ���� �о����. + cCsvTable test_data; + if(!test_data.Load("mob_proto_test.txt",'\t')) + { + fprintf(stderr, "mob_proto_test.txt ������ �о���� ���߽��ϴ�\n"); + //return false; + } else { + test_data.Next(); //���� �ο� �Ѿ��. + + //2. �׽�Ʈ ���� ���̺� ����. + TMobTable * test_mob_table = NULL; + int test_MobTableSize = test_data.m_File.GetRowCount()-1; + test_mob_table = new TMobTable[test_MobTableSize]; + memset(test_mob_table, 0, sizeof(TMobTable) * test_MobTableSize); + + //3. �׽�Ʈ ���� ���̺��� ���� �ְ�, �ʿ����� �ֱ�. + while(test_data.Next()) { + + if (!Set_Proto_Mob_Table(test_mob_table, test_data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + + + test_map_mobTableByVnum.insert(std::map::value_type(test_mob_table->dwVnum, test_mob_table)); + ++test_mob_table; + } + } + + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// + + + //���� �о����. + cCsvTable data; + if(!data.Load("mob_proto.txt",'\t')) + { + fprintf(stderr, "mob_proto.txt ������ �о���� ���߽��ϴ�\n"); + return false; + } + data.Next(); //�� ���� ���� (������ Į���� �����ϴ� �κ�) + + + + //===== �� ���̺� ����=====// + if (m_pMobTable) + { + delete m_pMobTable; + m_pMobTable = NULL; + } + + //���� �߰��Ǵ� ������ �ľ��Ѵ�. + int addNumber = 0; + while(data.Next()) { + int vnum = atoi(data.AsStringByIndex(0)); + std::map::iterator it_map_mobTable; + it_map_mobTable = test_map_mobTableByVnum.find(vnum); + if(it_map_mobTable != test_map_mobTableByVnum.end()) { + addNumber++; + } + } + + + m_iMobTableSize = data.m_File.GetRowCount()-1 + addNumber; + + m_pMobTable = new TMobTable[m_iMobTableSize]; + memset(m_pMobTable, 0, sizeof(TMobTable) * m_iMobTableSize); + + TMobTable * mob_table = m_pMobTable; + + + //data�� �ٽ� ù�ٷ� �ű��.(�ٽ� �о�´�;;) + data.Destroy(); + if(!data.Load("mob_proto.txt",'\t')) + { + fprintf(stderr, "mob_proto.txt ������ �о���� ���߽��ϴ�\n"); + return false; + } + data.Next(); //�� ���� ���� (������ Į���� �����ϴ� �κ�) + + while (data.Next()) + { + int col = 0; + //�׽�Ʈ ���Ͽ� ���� vnum�� �ִ��� ����. + std::map::iterator it_map_mobTable; + it_map_mobTable = test_map_mobTableByVnum.find(atoi(data.AsStringByIndex(col))); + if(it_map_mobTable == test_map_mobTableByVnum.end()) { + + if (!Set_Proto_Mob_Table(mob_table, data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + + } else { //$$$$$$$$$$$$$$$$$$$$$$$ �׽�Ʈ ���� ������ �ִ�! + TMobTable *tempTable = it_map_mobTable->second; + + mob_table->dwVnum = tempTable->dwVnum; + strncpy(mob_table->szName, tempTable->szName, CHARACTER_NAME_MAX_LEN); + strncpy(mob_table->szLocaleName, tempTable->szLocaleName, CHARACTER_NAME_MAX_LEN); + mob_table->bRank = tempTable->bRank; + mob_table->bType = tempTable->bType; + mob_table->bBattleType = tempTable->bBattleType; + mob_table->bLevel = tempTable->bLevel; + mob_table->bSize = tempTable->bSize; + mob_table->dwAIFlag = tempTable->dwAIFlag; + mob_table->dwRaceFlag = tempTable->dwRaceFlag; + mob_table->dwImmuneFlag = tempTable->dwImmuneFlag; + mob_table->bEmpire = tempTable->bEmpire; + strncpy(mob_table->szFolder, tempTable->szFolder, CHARACTER_NAME_MAX_LEN); + mob_table->bOnClickType = tempTable->bOnClickType; + mob_table->bStr = tempTable->bStr; + mob_table->bDex = tempTable->bDex; + mob_table->bCon = tempTable->bCon; + mob_table->bInt = tempTable->bInt; + mob_table->dwDamageRange[0] = tempTable->dwDamageRange[0]; + mob_table->dwDamageRange[1] = tempTable->dwDamageRange[1]; + mob_table->dwMaxHP = tempTable->dwMaxHP; + mob_table->bRegenCycle = tempTable->bRegenCycle; + mob_table->bRegenPercent = tempTable->bRegenPercent; + mob_table->dwExp = tempTable->dwExp; + mob_table->wDef = tempTable->wDef; + mob_table->sAttackSpeed = tempTable->sAttackSpeed; + mob_table->sMovingSpeed = tempTable->sMovingSpeed; + mob_table->bAggresiveHPPct = tempTable->bAggresiveHPPct; + mob_table->wAggressiveSight = tempTable->wAggressiveSight; + mob_table->wAttackRange = tempTable->wAttackRange; + mob_table->dwDropItemVnum = tempTable->dwDropItemVnum; + for (int i = 0; i < MOB_ENCHANTS_MAX_NUM; ++i) + mob_table->cEnchants[i] = tempTable->cEnchants[i]; + for (int i = 0; i < MOB_RESISTS_MAX_NUM; ++i) + mob_table->cResists[i] = tempTable->cResists[i]; + mob_table->fDamMultiply = tempTable->fDamMultiply; + mob_table->dwSummonVnum = tempTable->dwSummonVnum; + mob_table->dwDrainSP = tempTable->dwDrainSP; + mob_table->dwMobColor = tempTable->dwMobColor; + + } + + fprintf(stdout, "MOB #%-5d %-16s %-16s sight: %u color %u[%s]\n", mob_table->dwVnum, mob_table->szName, mob_table->szLocaleName, mob_table->wAggressiveSight, mob_table->dwMobColor, 0); + + //�¿� vnum �߰� + vnumSet.insert(mob_table->dwVnum); + + ++mob_table; + } + + + + //============================// + //===== �׽�Ʈ ���� �߰� =====// + //%%����%% + //%% -> ���ο� ������ �߰��� // + //�ߺ��Ǵ� ������ ������ �߰� // + //============================// + test_data.Destroy(); + if(!test_data.Load("mob_proto_test.txt",'\t')) + { + fprintf(stderr, "mob_proto_test.txt ������ �о���� ���߽��ϴ�\n"); + //return false; + } else { + test_data.Next(); //���� �ο� �Ѿ��. + + while (test_data.Next()) //�׽�Ʈ ������ ������ �Ⱦ����,���ο� ���� �߰��Ѵ�. + { + //�ߺ��Ǵ� �κ��̸� �Ѿ��. + set::iterator itVnum; + itVnum=vnumSet.find(atoi(test_data.AsStringByIndex(0))); + if (itVnum != vnumSet.end()) { + continue; + } + + + if (!Set_Proto_Mob_Table(mob_table, test_data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + + fprintf(stdout, "[New]MOB #%-5d %-16s sight: %u color %u[%s]\n", mob_table->dwVnum, mob_table->szLocaleName, mob_table->wAggressiveSight, mob_table->dwMobColor, test_data.AsStringByIndex(54)); + + //�¿� vnum �߰� + vnumSet.insert(mob_table->dwVnum); + + ++mob_table; + } + } + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// + + printf("BuildMobTable returning TRUE, m_iMobTableSize=%d\n", m_iMobTableSize); + fflush(stdout); + + return true; +} + +bool BuildMobTable() +{ + return BuildMobTable("mob_names.txt"); +} + + + + +DWORD g_adwMobProtoKey[4] = +{ + 4813894, + 18955, + 552631, + 6822045 +}; + + +struct SLocaleFile +{ + std::string locale; + std::string filename; +}; + +static std::vector CollectLocaleFiles(const char* pattern, const char* baseFile, const char* prefix) +{ + std::vector locales; + + _finddata_t data; + intptr_t handle = _findfirst(pattern, &data); + if (handle == -1) + return locales; + + const size_t prefixLen = std::strlen(prefix); + do + { + std::string name = data.name; + if (name == baseFile) + continue; + + size_t underscore = name.find(prefix); + size_t dot = name.rfind('.'); + if (underscore == std::string::npos || dot == std::string::npos || dot <= underscore + prefixLen) + continue; + + std::string locale = name.substr(underscore + prefixLen, dot - (underscore + prefixLen)); + if (!locale.empty()) + locales.push_back({ locale, name }); + } while (_findnext(handle, &data) == 0); + + _findclose(handle); + return locales; +} + +static void EnsureLocaleDirectory(const std::string& locale) +{ + // Create structure: locale/cz instead of locale_cz/locale/cz + std::string root = "locale"; + _mkdir(root.c_str()); + std::string leaf = root + "/" + locale; + _mkdir(leaf.c_str()); +} + +void SaveMobProto(const char* outputPath) +{ + FILE * fp; + + fp = fopen(outputPath, "wb"); + + if (!fp) + { + printf("cannot open %s for writing\n", outputPath); + return; + } + + DWORD fourcc = MAKEFOURCC('M', 'M', 'P', 'T'); + fwrite(&fourcc, sizeof(DWORD), 1, fp); + + DWORD dwElements = m_iMobTableSize; + fwrite(&dwElements, sizeof(DWORD), 1, fp); + + CLZObject zObj; + + printf("sizeof(TMobTable) %d\n", sizeof(TMobTable)); + + if (!CLZO::instance().CompressEncryptedMemory(zObj, m_pMobTable, sizeof(TMobTable) * m_iMobTableSize, g_adwMobProtoKey)) + { + printf("cannot compress\n"); + fclose(fp); + return; + } + + const CLZObject::THeader & r = zObj.GetHeader(); + + printf("MobProto count %u\n%u --Compress--> %u --Encrypt--> %u, GetSize %u\n", + m_iMobTableSize, r.dwRealSize, r.dwCompressedSize, r.dwEncryptSize, zObj.GetSize()); + + DWORD dwDataSize = zObj.GetSize(); + fwrite(&dwDataSize, sizeof(DWORD), 1, fp); + fwrite(zObj.GetBuffer(), dwDataSize, 1, fp); + + fclose(fp); +} + +void SaveMobProto() +{ + SaveMobProto("mob_proto"); +} + +void LoadMobProto() +{ + FILE * fp; + DWORD fourcc, tableSize, dataSize; + + fp = fopen("mob_proto", "rb"); + + fread(&fourcc, sizeof(DWORD), 1, fp); + fread(&tableSize, sizeof(DWORD), 1, fp); + fread(&dataSize, sizeof(DWORD), 1, fp); + BYTE * data = (BYTE *) malloc(dataSize); + + if (data) + { + fread(data, dataSize, 1, fp); + + CLZObject zObj; + + if (CLZO::instance().Decompress(zObj, data, g_adwMobProtoKey)) + { + printf("real_size %u\n", zObj.GetSize()); + + for (DWORD i = 0; i < tableSize; ++i) + { + TMobTable & rTable = *((TMobTable *) zObj.GetBuffer() + i); + printf("%u %s\n", rTable.dwVnum, rTable.szName); + } + } + + free(data); + } + + fclose(fp); +} + + + + +//== ==// +//== ==// +//== ==// +//===== ���⿡������ ������ =====// +//== ==// +//== ==// +//== ==// + +bool Set_Proto_Item_Table(TClientItemTable *itemTable, cCsvTable &csvTable, std::map &nameMap) +{ + // vnum �� vnum range �б�. + { + std::string s(csvTable.AsStringByIndex(0)); + int pos = s.find("~"); + // vnum �ʵ忡 '~'�� ���ٸ� �н� + if (std::string::npos == pos) + { + itemTable->dwVnum = atoi(s.c_str()); + if (0 == itemTable->dwVnum) + { + printf ("INVALID VNUM %s\n", s.c_str()); + return false; + } + itemTable->dwVnumRange = 0; + } + else + { + std::string s_start_vnum (s.substr(0, pos)); + std::string s_end_vnum (s.substr(pos +1 )); + + int start_vnum = atoi(s_start_vnum.c_str()); + int end_vnum = atoi(s_end_vnum.c_str()); + if (0 == start_vnum || (0 != end_vnum && end_vnum < start_vnum)) + { + printf ("INVALID VNUM RANGE%s\n", s.c_str()); + return false; + } + itemTable->dwVnum = start_vnum; + itemTable->dwVnumRange = end_vnum - start_vnum; + } + } + + int col = 1; + + strncpy(itemTable->szName, csvTable.AsStringByIndex(col++), ITEM_NAME_MAX_LEN); + //���� ������ �����ϸ� ������ �о��. + map::iterator it; + it = nameMap.find(itemTable->dwVnum); + if (it != nameMap.end()) { + const char * localeName = it->second; + strncpy(itemTable->szLocaleName, localeName, sizeof(itemTable->szLocaleName)); + } else { //���� ������ �������� ������ �ѱ۷�.. + strncpy(itemTable->szLocaleName, itemTable->szName, sizeof(itemTable->szLocaleName)); + } + itemTable->bType = get_Item_Type_Value(csvTable.AsStringByIndex(col++)); + itemTable->bSubType = get_Item_SubType_Value(itemTable->bType, csvTable.AsStringByIndex(col++)); + itemTable->bSize = atoi(csvTable.AsStringByIndex(col++)); + itemTable->dwAntiFlags = get_Item_AntiFlag_Value(csvTable.AsStringByIndex(col++)); + itemTable->dwFlags = get_Item_Flag_Value(csvTable.AsStringByIndex(col++)); + itemTable->dwWearFlags = get_Item_WearFlag_Value(csvTable.AsStringByIndex(col++)); + itemTable->dwImmuneFlag = get_Item_Immune_Value(csvTable.AsStringByIndex(col++)); + itemTable->dwGold = atoi(csvTable.AsStringByIndex(col++)); + itemTable->dwShopBuyPrice = atoi(csvTable.AsStringByIndex(col++)); + itemTable->dwRefinedVnum = atoi(csvTable.AsStringByIndex(col++)); + itemTable->wRefineSet = atoi(csvTable.AsStringByIndex(col++)); + itemTable->bAlterToMagicItemPct = atoi(csvTable.AsStringByIndex(col++)); + + int i; + + for (i = 0; i < ITEM_LIMIT_MAX_NUM; ++i) + { + itemTable->aLimits[i].bType = get_Item_LimitType_Value(csvTable.AsStringByIndex(col++)); + itemTable->aLimits[i].lValue = atoi(csvTable.AsStringByIndex(col++)); + } + + for (i = 0; i < ITEM_APPLY_MAX_NUM; ++i) + { + itemTable->aApplies[i].bType = get_Item_ApplyType_Value(csvTable.AsStringByIndex(col++)); + itemTable->aApplies[i].lValue = atoi(csvTable.AsStringByIndex(col++)); + } + + for (i = 0; i < ITEM_VALUES_MAX_NUM; ++i) + itemTable->alValues[i] = atoi(csvTable.AsStringByIndex(col++)); + + itemTable->bSpecular = atoi(csvTable.AsStringByIndex(col++)); + itemTable->bGainSocketPct = atoi(csvTable.AsStringByIndex(col++)); + col++; //AddonType + + itemTable->bWeight = 0; + + return true; +} + +bool BuildItemTable(const char* nameFile) +{ + //%%% <�Լ� ����> %%%// + //1. ��� : 'item_proto.txt', 'item_proto_test.txt', 'item_names.txt' ������ �а�, + // m_pItemTable �� �����Ѵ�. + //2. ���� + // 1)'item_names.txt' ������ �о vnum:name ���� �����. + // 2)'item_proto_test.txt' ������ �о, + // test_item_table �� �����, + // vnum:TClientItemTable ���� �����. + // 3)'item_proto.txt' ������ �а�, m_pItemTable�� �����Ѵ�. + // test_item_table�� �ִ� vnum�� �׽�Ʈ �����͸� �ִ´�. + // 4)test_item_table �������߿�, m_pItemTable �� ���� �����͸� �߰��Ѵ�. + //3. �׽�Ʈ + // 1)'item_proto.txt' ������ m_pItemTable�� �� ������. + // 2)'item_names.txt' ������ m_pItemTable�� �� ������. + // 3)'item_proto_test.txt' ���� [��ġ��] ������ m_pItemTable �� �� ������. + // 4)'item_proto_test.txt' ���� [���ο�] ������ m_pItemTable �� �� ������. + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// + + fprintf(stderr, "sizeof(TClientItemTable): %u\n", sizeof(TClientItemTable)); + + //=================================================================// + // 1)'item_names.txt' ������ �о vnum:name ���� �����. + //=================================================================// + bool isNameFile = true; + map localMap; + cCsvTable nameData; + if(!nameData.Load(nameFile,'\t')) + { + fprintf(stderr, "%s ������ �о���� ���߽��ϴ�\n", nameFile); + isNameFile = false; + } else { + nameData.Next(); + while(nameData.Next()) { + localMap[atoi(nameData.AsStringByIndex(0))] = nameData.AsStringByIndex(1); + } + } + //_________________________________________________________________// + + //===================== =======================// + // 2)'item_proto_test.txt' ������ �о, + // test_item_table �� �����, + // vnum:TClientItemTable ���� �����. + //=============================================// + map test_map_itemTableByVnum; + + //1. ���� �о����. + cCsvTable test_data; + if(!test_data.Load("item_proto_test.txt",'\t')) + { + fprintf(stderr, "item_proto_test.txt ������ �о���� ���߽��ϴ�\n"); + //return false; + } else { + test_data.Next(); //���� �ο� �Ѿ��. + + //2. �׽�Ʈ ������ ���̺� ����. + TClientItemTable * test_item_table = NULL; + int test_itemTableSize = test_data.m_File.GetRowCount()-1; + test_item_table = new TClientItemTable[test_itemTableSize]; + memset(test_item_table, 0, sizeof(TClientItemTable) * test_itemTableSize); + + //3. �׽�Ʈ ���� ���̺��� ���� �ְ�, �ʿ����� �ֱ�. + while(test_data.Next()) { + + if (!Set_Proto_Item_Table(test_item_table, test_data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + + + test_map_itemTableByVnum.insert(std::map::value_type(test_item_table->dwVnum, test_item_table)); + ++test_item_table; + } + } + + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// + + + //================================================================// + // 3)'item_proto.txt' ������ �а�, m_pItemTable�� �����Ѵ�. + // test_item_table�� �ִ� vnum�� �׽�Ʈ �����͸� �ִ´�. + //================================================================// + + //vnum���� ������ ��. ���ο� �׽�Ʈ �������� �Ǻ��Ҷ� ���ȴ�. + set vnumSet; + + //���� �о����. + cCsvTable data; + if(!data.Load("item_proto.txt",'\t')) + { + fprintf(stderr, "item_proto.txt ������ �о���� ���߽��ϴ�\n"); + return false; + } + data.Next(); //�� ���� ���� (������ Į���� �����ϴ� �κ�) + + if (m_pItemTable) + { + free(m_pItemTable); + m_pItemTable = NULL; + } + + //===== ������ ���̺� ���� =====// + //���� �߰��Ǵ� ������ �ľ��Ѵ�. + int addNumber = 0; + while(data.Next()) { + int vnum = atoi(data.AsStringByIndex(0)); + std::map::iterator it_map_itemTable; + it_map_itemTable = test_map_itemTableByVnum.find(vnum); + if(it_map_itemTable != test_map_itemTableByVnum.end()) { + addNumber++; + } + } + //data�� �ٽ� ù�ٷ� �ű��.(�ٽ� �о�´�;;) + data.Destroy(); + if(!data.Load("item_proto.txt",'\t')) + { + fprintf(stderr, "item_proto.txt ������ �о���� ���߽��ϴ�\n"); + return false; + } + data.Next(); //�� ���� ���� (������ Į���� �����ϴ� �κ�) + + m_iItemTableSize = data.m_File.GetRowCount()-1+addNumber; + m_pItemTable = new TClientItemTable[m_iItemTableSize]; + memset(m_pItemTable, 0, sizeof(TClientItemTable) * m_iItemTableSize); + + TClientItemTable * item_table = m_pItemTable; + + while (data.Next()) + { + int col = 0; + + //�׽�Ʈ ���Ͽ� ���� vnum�� �ִ��� ����. + std::map::iterator it_map_itemTable; + it_map_itemTable = test_map_itemTableByVnum.find(atoi(data.AsStringByIndex(col))); + if(it_map_itemTable == test_map_itemTableByVnum.end()) { + + + if (!Set_Proto_Item_Table(item_table, data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + } else { //$$$$$$$$$$$$$$$$$$$$$$$ �׽�Ʈ ������ ������ �ִ�! + TClientItemTable *tempTable = it_map_itemTable->second; + + item_table->dwVnum = tempTable->dwVnum; + strncpy(item_table->szName, tempTable->szName, ITEM_NAME_MAX_LEN); + strncpy(item_table->szLocaleName, tempTable->szLocaleName, ITEM_NAME_MAX_LEN); + item_table->bType = tempTable->bType; + item_table->bSubType = tempTable->bSubType; + item_table->bSize = tempTable->bSize; + item_table->dwAntiFlags = tempTable->dwAntiFlags; + item_table->dwFlags = tempTable->dwFlags; + item_table->dwWearFlags = tempTable->dwWearFlags; + item_table->dwImmuneFlag = tempTable->dwImmuneFlag; + item_table->dwGold = tempTable->dwGold; + item_table->dwShopBuyPrice = tempTable->dwShopBuyPrice; + item_table->dwRefinedVnum = tempTable->dwRefinedVnum; + item_table->wRefineSet = tempTable->wRefineSet; + item_table->bAlterToMagicItemPct = tempTable->bAlterToMagicItemPct; + + int i; + for (i = 0; i < ITEM_LIMIT_MAX_NUM; ++i) + { + item_table->aLimits[i].bType = tempTable->aLimits[i].bType; + item_table->aLimits[i].lValue = tempTable->aLimits[i].lValue; + } + + for (i = 0; i < ITEM_APPLY_MAX_NUM; ++i) + { + item_table->aApplies[i].bType = tempTable->aApplies[i].bType; + item_table->aApplies[i].lValue = tempTable->aApplies[i].lValue; + } + + for (i = 0; i < ITEM_VALUES_MAX_NUM; ++i) + item_table->alValues[i] = tempTable->alValues[i]; + + item_table->bSpecular = tempTable->bSpecular; + item_table->bGainSocketPct = tempTable->bGainSocketPct; + + item_table->bWeight = tempTable->bWeight; + + } + + + fprintf(stdout, "ITEM #%-5u %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %u ANTI %u IMMUNE %u REFINE %u\n", + item_table->dwVnum, + item_table->szName, + item_table->szLocaleName, + item_table->alValues[0], + item_table->alValues[1], + item_table->alValues[2], + item_table->alValues[3], + item_table->alValues[4], + item_table->alValues[5], + item_table->dwWearFlags, + item_table->dwAntiFlags, + item_table->dwImmuneFlag, + item_table->dwRefinedVnum); + + //vnum ����. + vnumSet.insert(item_table->dwVnum); + ++item_table; + } + + //==========================================================================// + // 4)test_item_table �������߿�, m_pItemTable �� ���� �����͸� �߰��Ѵ�. + //==========================================================================// + test_data.Destroy(); + if(!test_data.Load("item_proto_test.txt",'\t')) + { + fprintf(stderr, "item_proto_test.txt ������ �о���� ���߽��ϴ�\n"); + //return false; + } else { + test_data.Next(); //���� �ο� �Ѿ��. + + while (test_data.Next()) //�׽�Ʈ ������ ������ �Ⱦ����,���ο� ���� �߰��Ѵ�. + { + //�ߺ��Ǵ� �κ��̸� �Ѿ��. + set::iterator itVnum; + itVnum=vnumSet.find(atoi(test_data.AsStringByIndex(0))); + if (itVnum != vnumSet.end()) { + continue; + } + + if (!Set_Proto_Item_Table(item_table, test_data, localMap)) + { + fprintf(stderr, "�� ������ ���̺� ���� ����.\n"); + } + + fprintf(stdout, "[NEW]ITEM #%-5u %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %u ANTI %u IMMUNE %u REFINE %u\n", + item_table->dwVnum, + item_table->szName, + item_table->szLocaleName, + item_table->alValues[0], + item_table->alValues[1], + item_table->alValues[2], + item_table->alValues[3], + item_table->alValues[4], + item_table->alValues[5], + item_table->dwWearFlags, + item_table->dwAntiFlags, + item_table->dwImmuneFlag, + item_table->dwRefinedVnum); + + + //�¿� vnum �߰� + vnumSet.insert(item_table->dwVnum); + + ++item_table; + + } + } + + return true; +} + +bool BuildItemTable() +{ + return BuildItemTable("item_names.txt"); +} + +DWORD g_adwItemProtoKey[4] = +{ + 173217, + 72619434, + 408587239, + 27973291 +}; + +void SaveItemProto(const char* outputPath) +{ + FILE * fp; + + fp = fopen(outputPath, "wb"); + + if (!fp) + { + printf("cannot open %s for writing\n", outputPath); + return; + } + + DWORD fourcc = MAKEFOURCC('M', 'I', 'P', 'X'); + fwrite(&fourcc, sizeof(DWORD), 1, fp); + + DWORD dwVersion = 0x00000001; + fwrite(&dwVersion, sizeof(DWORD), 1, fp); + + DWORD dwStride = sizeof(TClientItemTable); + fwrite(&dwStride, sizeof(DWORD), 1, fp); + + DWORD dwElements = m_iItemTableSize; + fwrite(&dwElements, sizeof(DWORD), 1, fp); + + CLZObject zObj; + std::vector vec_item_table (&m_pItemTable[0], &m_pItemTable[m_iItemTableSize - 1]); + sort (&m_pItemTable[0], &m_pItemTable[0] + m_iItemTableSize); + if (!CLZO::instance().CompressEncryptedMemory(zObj, m_pItemTable, sizeof(TClientItemTable) * m_iItemTableSize, g_adwItemProtoKey)) + { + printf("cannot compress\n"); + fclose(fp); + return; + } + + const CLZObject::THeader & r = zObj.GetHeader(); + + printf("Elements %d\n%u --Compress--> %u --Encrypt--> %u, GetSize %u\n", + m_iItemTableSize, + r.dwRealSize, + r.dwCompressedSize, + r.dwEncryptSize, + zObj.GetSize()); + + DWORD dwDataSize = zObj.GetSize(); + fwrite(&dwDataSize, sizeof(DWORD), 1, fp); + fwrite(zObj.GetBuffer(), dwDataSize, 1, fp); + + fclose(fp); + + fp = fopen(outputPath, "rb"); + + if (!fp) + { + printf("Error!!\n"); + return; + } + + fread(&fourcc, sizeof(DWORD), 1, fp); + fread(&dwElements, sizeof(DWORD), 1, fp); + + printf("Elements Check %u fourcc match %d\n", dwElements, fourcc == MAKEFOURCC('M', 'I', 'P', 'T')); + fclose(fp); +} + +void SaveItemProto() +{ + SaveItemProto("item_proto"); +} + +static void BuildLocalizedMobProtos() +{ + const std::vector locales = CollectLocaleFiles("mob_names_*.txt", "mob_names.txt", "mob_names_"); + for (const SLocaleFile& locale : locales) + { + EnsureLocaleDirectory(locale.locale); + std::string output = std::string("locale/") + locale.locale + "/mob_proto"; + if (BuildMobTable(locale.filename.c_str())) + { + SaveMobProto(output.c_str()); + } + else + { + fprintf(stderr, "Skipping locale %s because mob table build failed.\n", locale.locale.c_str()); + } + } +} + +static void BuildLocalizedItemProtos() +{ + const std::vector locales = CollectLocaleFiles("item_names_*.txt", "item_names.txt", "item_names_"); + for (const SLocaleFile& locale : locales) + { + EnsureLocaleDirectory(locale.locale); + std::string output = std::string("locale/") + locale.locale + "/item_proto"; + if (BuildItemTable(locale.filename.c_str())) + { + SaveItemProto(output.c_str()); + } + else + { + fprintf(stderr, "Skipping locale %s because item table build failed.\n", locale.locale.c_str()); + } + } +} + + + +int main(int argc, char ** argv) +{ + + printf("=== MAIN START ===\n"); + fflush(stdout); + + if (BuildMobTable()) + { + printf("=== BuildMobTable returned TRUE ===\n"); + fflush(stdout); + printf("=== About to call SaveMobProto ===\n"); + fflush(stdout); + SaveMobProto(); + printf("=== SaveMobProto returned ===\n"); + fflush(stdout); + LoadMobProto(); + cout << "BuildMobTable working normal" << endl; + BuildLocalizedMobProtos(); + } else { + printf("=== BuildMobTable returned FALSE ===\n"); + fflush(stdout); + } + + + + if (BuildItemTable()) + { + SaveItemProto(); + BuildLocalizedItemProtos(); + cout << "BuildItemTable working normal" << endl; + } + + + + return 0; +} + diff --git a/src/DumpProto/lzo.cpp b/src/DumpProto/lzo.cpp new file mode 100644 index 0000000..8fd3b52 --- /dev/null +++ b/src/DumpProto/lzo.cpp @@ -0,0 +1,261 @@ +//#include "common.h" +#include +#include +#include +#include "lzo.h" +#include "tea.h" + +// Global instance of CLZO singleton to initialize the singleton pattern +static CLZO g_lzoInstance; + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) + +DWORD CLZObject::ms_dwFourCC = MAKEFOURCC('M', 'C', 'O', 'Z'); + +CLZObject::CLZObject() +{ + Initialize(); +} + +void CLZObject::Initialize() +{ + m_pHeader = NULL; + m_pbBuffer = NULL; + m_dwBufferSize = 0; + m_pbIn = NULL; + m_bCompressed = false; +} + +void CLZObject::Clear() +{ + if (m_pbBuffer) + delete [] m_pbBuffer; + + Initialize(); +} + +CLZObject::~CLZObject() +{ + Clear(); +} + +DWORD CLZObject::GetSize() +{ + assert(m_pHeader); + + if (m_bCompressed) + { + if (m_pHeader->dwEncryptSize) + return sizeof(THeader) + sizeof(DWORD) + m_pHeader->dwEncryptSize; + else + return sizeof(THeader) + sizeof(DWORD) + m_pHeader->dwCompressedSize; + } + else + return m_pHeader->dwRealSize; +} + +void CLZObject::BeginCompress(const void * pvIn, UINT uiInLen) +{ + m_pbIn = (const BYTE *) pvIn; + + // sizeof(SHeader) + + // ��ȣȭ�� ���� fourCC 4����Ʈ + // ����� �� ������� �� �ִ� �ִ� �뷮 + + // ��ȣȭ�� ���� 8 ����Ʈ + m_dwBufferSize = sizeof(THeader) + sizeof(DWORD) + (uiInLen + uiInLen / 64 + 16 + 3) + 8; + + m_pbBuffer = new BYTE[m_dwBufferSize]; + memset(m_pbBuffer, 0, m_dwBufferSize); + + m_pHeader = (THeader *) m_pbBuffer; + m_pHeader->dwFourCC = ms_dwFourCC; + m_pHeader->dwEncryptSize = m_pHeader->dwCompressedSize = m_pHeader->dwRealSize = 0; + m_pHeader->dwRealSize = uiInLen; +} + + +bool CLZObject::Compress() +{ + BYTE * pbBuffer = m_pbBuffer + sizeof(THeader); + *(DWORD *) pbBuffer = 0x5A4F434D; // 'MOCZ' + pbBuffer += sizeof(DWORD); + + // Calculate available space for compressed data + lzo_uint available_space = (lzo_uint)(m_dwBufferSize - sizeof(THeader) - sizeof(DWORD)); + lzo_uint compressed_size = available_space; + + int r = lzo1x_1_compress( + (BYTE *) m_pbIn, + (lzo_uint)m_pHeader->dwRealSize, + pbBuffer, + &compressed_size, + CLZO::instance().GetWorkMemory() + ); + + if (LZO_E_OK != r) + { + return false; + } + + m_pHeader->dwCompressedSize = (DWORD)compressed_size; + m_bCompressed = true; + + return true; +} + +bool CLZObject::BeginDecompress(const void * pvIn) +{ + THeader * pHeader = (THeader *) pvIn; + + if (pHeader->dwFourCC != ms_dwFourCC) + { + fprintf(stderr, "LZObject: not a valid data"); + return false; + } + + m_pHeader = pHeader; + m_pbIn = (const BYTE *) pvIn + (sizeof(THeader) + sizeof(DWORD)); + + m_pbBuffer = new BYTE[pHeader->dwRealSize]; + memset(m_pbBuffer, 0, pHeader->dwRealSize); + return true; +} + +bool CLZObject::Decompress(DWORD * pdwKey) +{ + UINT uiSize; + int r; + + if (m_pHeader->dwEncryptSize) + { + BYTE * pbDecryptedBuffer = Decrypt(pdwKey); + + if (*(DWORD *) pbDecryptedBuffer != ms_dwFourCC) + { + fprintf(stderr, "LZObject: key incorrect"); + return false; + } + + if (LZO_E_OK != (r = lzo1x_decompress(pbDecryptedBuffer + sizeof(DWORD), m_pHeader->dwCompressedSize, m_pbBuffer, (lzo_uint*)&uiSize, NULL))) + { + fprintf(stderr, "LZObject: Decompress failed(decrypt) ret %d\n", r); + return false; + } + + delete [] pbDecryptedBuffer; + } + else + { + uiSize = m_pHeader->dwRealSize; + + if (LZO_E_OK != (r = lzo1x_decompress_safe(m_pbIn, m_pHeader->dwCompressedSize, m_pbBuffer, (lzo_uint*)&uiSize, NULL))) + { + fprintf(stderr, "LZObject: Decompress failed : ret %d, CompressedSize %d\n", r, m_pHeader->dwCompressedSize); + return false; + } + } + + if (uiSize != m_pHeader->dwRealSize) + { + fprintf(stderr, "LZObject: Size differs"); + return false; + } + + return true; +} + +bool CLZObject::Encrypt(DWORD * pdwKey) +{ + if (!m_bCompressed) + { + assert(!"not compressed yet"); + return false; + } + + BYTE * pbBuffer = m_pbBuffer + sizeof(THeader); + // TEA pads to 8-byte boundaries; encrypt the FourCC + compressed data + DWORD dwSizeToEncrypt = sizeof(DWORD) + m_pHeader->dwCompressedSize; + fprintf(stderr, "Encrypt: dwCompressedSize=%u, dwSizeToEncrypt=%u\n", m_pHeader->dwCompressedSize, dwSizeToEncrypt); + m_pHeader->dwEncryptSize = tea_encrypt((DWORD *) pbBuffer, (const DWORD *) pbBuffer, pdwKey, dwSizeToEncrypt); + fprintf(stderr, "Encrypt: dwEncryptSize=%u (return from tea_encrypt)\n", m_pHeader->dwEncryptSize); + if (m_pHeader->dwEncryptSize == 0) + { + fprintf(stderr, "Encrypt: tea_encrypt failed (returned 0)\n"); + return false; + } + return true; +} + +BYTE * CLZObject::Decrypt(DWORD * pdwKey) +{ + assert(m_pbBuffer); + + BYTE * pbDecryptBuffer = new BYTE[m_pHeader->dwEncryptSize]; + + tea_encrypt((DWORD *) pbDecryptBuffer, (const DWORD *) (m_pbIn - sizeof(DWORD)), pdwKey, m_pHeader->dwEncryptSize); + return pbDecryptBuffer; +} + +CLZO::CLZO() : m_pWorkMem(NULL) +{ + if (lzo_init() != LZO_E_OK) + { + fprintf(stderr, "LZO: cannot initialize\n"); + return; + } + + m_pWorkMem = (BYTE *) malloc(LZO1X_MEM_COMPRESS); + + if (NULL == m_pWorkMem) + { + fprintf(stderr, "LZO: cannot alloc memory\n"); + return; + } +} + +CLZO::~CLZO() +{ + if (m_pWorkMem) + { + free(m_pWorkMem); + m_pWorkMem = NULL; + } +} + +bool CLZO::CompressMemory(CLZObject & rObj, const void * pIn, UINT uiInLen) +{ + rObj.BeginCompress(pIn, uiInLen); + return rObj.Compress(); +} + +bool CLZO::CompressEncryptedMemory(CLZObject & rObj, const void * pIn, UINT uiInLen, DWORD * pdwKey) +{ + rObj.BeginCompress(pIn, uiInLen); + + if (!rObj.Compress()) + { + return false; + } + + return rObj.Encrypt(pdwKey); +} + +bool CLZO::Decompress(CLZObject & rObj, const BYTE * pbBuf, DWORD * pdwKey) +{ + if (!rObj.BeginDecompress(pbBuf)) + return false; + + if (!rObj.Decompress(pdwKey)) + return false; + + return true; +} + + +BYTE * CLZO::GetWorkMemory() +{ + return m_pWorkMem; +} + diff --git a/src/DumpProto/lzo.h b/src/DumpProto/lzo.h new file mode 100644 index 0000000..2c069c3 --- /dev/null +++ b/src/DumpProto/lzo.h @@ -0,0 +1,70 @@ +#ifndef __INC_METIN_II_371GNFBQOCJ_LZO_H__ +#define __INC_METIN_II_371GNFBQOCJ_LZO_H__ + +#include "Singleton.h" +#include +#include + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef unsigned int UINT; + +class CLZObject { +public: +#pragma pack(4) + typedef struct SHeader { + DWORD dwFourCC; + DWORD dwEncryptSize; // ��ȣȭ�� ũ�� + DWORD dwCompressedSize; // ����� ������ ũ�� + DWORD dwRealSize; // ���� ������ ũ�� + } THeader; +#pragma pack() + + CLZObject(); + ~CLZObject(); + + void Clear(); + + void BeginCompress(const void *pvIn, UINT uiInLen); + bool Compress(); + + bool BeginDecompress(const void *pvIn); + bool Decompress(DWORD *pdwKey = NULL); + + bool Encrypt(DWORD *pdwKey); + BYTE *Decrypt(DWORD *pdwKey); + + const THeader &GetHeader() { return *m_pHeader; } + BYTE *GetBuffer() { return m_pbBuffer; } + DWORD GetSize(); + +private: + void Initialize(); + + BYTE *m_pbBuffer; + DWORD m_dwBufferSize; + + THeader *m_pHeader; + const BYTE *m_pbIn; + bool m_bCompressed; + + static DWORD ms_dwFourCC; +}; + +class CLZO : public singleton { +public: + CLZO(); + virtual ~CLZO(); + + bool CompressMemory(CLZObject &rObj, const void *pIn, UINT uiInLen); + bool CompressEncryptedMemory(CLZObject &rObj, const void *pIn, UINT uiInLen, + DWORD *pdwKey); + bool Decompress(CLZObject &rObj, const BYTE *pbBuf, DWORD *pdwKey = NULL); + BYTE *GetWorkMemory(); + +private: + BYTE *m_pWorkMem; +}; + +#endif diff --git a/src/DumpProto/tea.cpp b/src/DumpProto/tea.cpp new file mode 100644 index 0000000..d8c9899 --- /dev/null +++ b/src/DumpProto/tea.cpp @@ -0,0 +1,100 @@ +/* +* Filename: tea.c +* Description: TEA ȣȭ +* +* Author: (aka. , Cronan), ۿ (aka. myevan, ڷ) +*/ +#include "tea.h" +#include + +/* +* TEA Encryption Module Instruction +* Edited by aka. , Cronan +* +* void tea_code(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest) +* void tea_decode(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest) +* 8Ʈ ȣ/ȣȭ Ҷ ȴ. key 16 Ʈ Ѵ. +* sz, sy 8Ʈ Ѵ. +* +* int tea_decrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size); +* int tea_encrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size); +* Ѳ 8 Ʈ ̻ ȣ/ȣȭ Ҷ Ѵ. size +* 8 ƴϸ 8 ũ⸦ "÷" ȣȭ Ѵ. +* +* ex. tea_code(pdwSrc[1], pdwSrc[0], pdwKey, pdwDest); +* tea_decrypt(pdwDest, pdwSrc, pdwKey, nSize); +*/ + +#define TEA_ROUND 32 // 32 ϸ, . +#define DELTA 0x9E3779B9 // DELTA ٲ . + +void tea_code(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest) +{ + register unsigned long y = sy, z = sz, sum = 0; + unsigned long n = TEA_ROUND; + + while (n-- > 0) + { + y += ((z << 4 ^ z >> 5) + z) ^ (sum + key[sum & 3]); + sum += DELTA; + z += ((y << 4 ^ y >> 5) + y) ^ (sum + key[sum >> 11 & 3]); + } + + *(dest++) = y; + *dest = z; +} + +void tea_decode(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest) +{ +#pragma warning(disable:4307) + register unsigned long y = sy, z = sz, sum = DELTA * TEA_ROUND; +#pragma warning(default:4307) + + unsigned long n = TEA_ROUND; + + while (n-- > 0) + { + z -= ((y << 4 ^ y >> 5) + y) ^ (sum + key[sum >> 11 & 3]); + sum -= DELTA; + y -= ((z << 4 ^ z >> 5) + z) ^ (sum + key[sum & 3]); + } + + *(dest++) = y; + *dest = z; +} + +int tea_encrypt(unsigned long *dest, const unsigned long *src, const unsigned long * key, int size) +{ + int i; + int resize; + + if (size % 8 != 0) + { + resize = size + 8 - (size % 8); + memset((char *) src + size, 0, resize - size); + } + else + resize = size; + + for (i = 0; i < resize >> 3; i++, dest += 2, src += 2) + tea_code(*(src + 1), *src, key, dest); + + return (resize); +} + +int tea_decrypt(unsigned long *dest, const unsigned long *src, const unsigned long * key, int size) +{ + int i; + int resize; + + if (size % 8 != 0) + resize = size + 8 - (size % 8); + else + resize = size; + + for (i = 0; i < resize >> 3; i++, dest += 2, src += 2) + tea_decode(*(src + 1), *src, key, dest); + + return (resize); +} + diff --git a/src/DumpProto/tea.h b/src/DumpProto/tea.h new file mode 100644 index 0000000..3555bc2 --- /dev/null +++ b/src/DumpProto/tea.h @@ -0,0 +1,17 @@ +#ifdef __cplusplus +extern "C" { +#endif + + /* TEA is a 64-bit symmetric block cipher with a 128-bit key, developed + by David J. Wheeler and Roger M. Needham, and described in their + paper at . + + This implementation is based on their code in + */ + + int tea_encrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size); + int tea_decrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size); + +#ifdef __cplusplus +}; +#endif diff --git a/src/EterGrnLib/ThingInstance.cpp b/src/EterGrnLib/ThingInstance.cpp index 765c4bf..a418584 100644 --- a/src/EterGrnLib/ThingInstance.cpp +++ b/src/EterGrnLib/ThingInstance.cpp @@ -534,7 +534,7 @@ void CGraphicThingInstance::RegisterMotionThing(DWORD dwMotionKey, CGraphicThing { CGraphicThing::TRef * pMotionRef = new CGraphicThing::TRef; pMotionRef->SetPointer(pMotionThing); - m_roMotionThingMap.insert(std::make_pair(dwMotionKey, pMotionRef)); + m_roMotionThingMap.insert(std::map::value_type(dwMotionKey, pMotionRef)); } void CGraphicThingInstance::ResetLocalTime() diff --git a/src/EterLib/FileLoaderThread.cpp b/src/EterLib/FileLoaderThread.cpp index 46eb531..bd7677a 100644 --- a/src/EterLib/FileLoaderThread.cpp +++ b/src/EterLib/FileLoaderThread.cpp @@ -3,171 +3,86 @@ #include "PackLib/PackManager.h" #include "FileLoaderThread.h" #include "ResourceManager.h" +#include "GameThreadPool.h" -CFileLoaderThread::CFileLoaderThread() : m_bShutdowned(false), m_pArg(NULL), m_hThread(NULL), m_uThreadID(0) +CFileLoaderThread::CFileLoaderThread() : m_bShutdowned(false) { } CFileLoaderThread::~CFileLoaderThread() { - Destroy(); + Shutdown(); } -int CFileLoaderThread::Create(void * arg) +bool CFileLoaderThread::Create(void * arg) { - Arg(arg); - m_hThread = (HANDLE) _beginthreadex(NULL, 0, EntryPoint, this, 0, &m_uThreadID); - - if (!m_hThread) - return false; - - SetThreadPriority(m_hThread, THREAD_PRIORITY_NORMAL); + // Modern implementation doesn't need explicit thread creation + // The global CGameThreadPool handles threading + m_bShutdowned = false; return true; } -UINT CFileLoaderThread::Run(void * arg) -{ - if (!Setup()) - return 0; - - return (Execute(arg)); -} - -/* Static */ -UINT CALLBACK CFileLoaderThread::EntryPoint(void * pThis) -{ - CFileLoaderThread * pThread = (CFileLoaderThread *) pThis; - return pThread->Run(pThread->Arg()); -} - -////////////////////////////////////////////////////////////////////////// -void CFileLoaderThread::Destroy() -{ - if (m_hSemaphore) - { - CloseHandle(m_hSemaphore); - m_hSemaphore = NULL; - } - - stl_wipe(m_pRequestDeque); - stl_wipe(m_pCompleteDeque); -} - -UINT CFileLoaderThread::Setup() -{ - m_hSemaphore = CreateSemaphore(NULL, // no security attributes - 0, // initial count - 65535, // maximum count - NULL); // unnamed semaphore - if (!m_hSemaphore) - return 0; - - return 1; -} - void CFileLoaderThread::Shutdown() { - if (!m_hSemaphore) - return; - - BOOL bRet; - m_bShutdowned = true; - do + // Clear any pending completed items { - bRet = ReleaseSemaphore(m_hSemaphore, 1, NULL); + std::lock_guard lock(m_CompleteMutex); + stl_wipe(m_pCompleteDeque); } - while (!bRet); - - WaitForSingleObject(m_hThread, 10000); // 쓰레드가 종료 되기를 10초 기다림 } -UINT CFileLoaderThread::Execute(void * /*pvArg*/) +void CFileLoaderThread::Request(const std::string& c_rstFileName) { - while (!m_bShutdowned) + if (m_bShutdowned) + return; + + // Enqueue file loading to the global thread pool + CGameThreadPool* pThreadPool = CGameThreadPool::InstancePtr(); + if (pThreadPool) { - DWORD dwWaitResult; - - dwWaitResult = WaitForSingleObject(m_hSemaphore, INFINITE); - - if (m_bShutdowned) - break; - - switch (dwWaitResult) - { - case WAIT_OBJECT_0: - { - Process(); - } - break; - - case WAIT_TIMEOUT: - TraceError("CFileLoaderThread::Execute: Timeout occured while time-out interval is INIFITE"); - break; - } + pThreadPool->Enqueue([this, c_rstFileName]() + { + ProcessFile(c_rstFileName); + }); + } + else + { + // Fallback to synchronous loading if thread pool not available + ProcessFile(c_rstFileName); } - - Destroy(); - return 1; } -void CFileLoaderThread::Request(std::string & c_rstFileName) // called in main thread +bool CFileLoaderThread::Fetch(TData ** ppData) { - TData * pData = new TData; - - pData->File.clear(); - pData->stFileName = c_rstFileName; - - m_RequestMutex.Lock(); - m_pRequestDeque.push_back(pData); - m_RequestMutex.Unlock(); - - ++m_iRestSemCount; - - if (!ReleaseSemaphore(m_hSemaphore, m_iRestSemCount, NULL)) - TraceError("CFileLoaderThread::Request: ReleaseSemaphore error"); - - --m_iRestSemCount; -} - -bool CFileLoaderThread::Fetch(TData ** ppData) // called in main thread -{ - m_CompleteMutex.Lock(); + std::lock_guard lock(m_CompleteMutex); if (m_pCompleteDeque.empty()) - { - m_CompleteMutex.Unlock(); return false; - } *ppData = m_pCompleteDeque.front(); m_pCompleteDeque.pop_front(); - m_CompleteMutex.Unlock(); return true; } -void CFileLoaderThread::Process() // called in loader thread +void CFileLoaderThread::ProcessFile(const std::string& fileName) { - m_RequestMutex.Lock(); - - if (m_pRequestDeque.empty()) - { - m_RequestMutex.Unlock(); + if (m_bShutdowned) return; - } - TData * pData = m_pRequestDeque.front(); - m_pRequestDeque.pop_front(); - - m_RequestMutex.Unlock(); + TData * pData = new TData; + pData->File.clear(); + pData->stFileName = fileName; CPackManager::instance().GetFile(pData->stFileName, pData->File); - m_CompleteMutex.Lock(); - m_pCompleteDeque.push_back(pData); - m_CompleteMutex.Unlock(); + // Add to completed queue + { + std::lock_guard lock(m_CompleteMutex); + m_pCompleteDeque.push_back(pData); + } Sleep(g_iLoadingDelayTime); } diff --git a/src/EterLib/FileLoaderThread.h b/src/EterLib/FileLoaderThread.h index 5fc0f65..74474b9 100644 --- a/src/EterLib/FileLoaderThread.h +++ b/src/EterLib/FileLoaderThread.h @@ -2,11 +2,10 @@ #define __INC_YMIR_ETERLIB_FILELOADERTHREAD_H__ #include -#include "Thread.h" -#include "Mutex.h" +#include #include "PackLib/PackManager.h" -class CFileLoaderThread +class CFileLoaderThread { public: typedef struct SData @@ -19,41 +18,19 @@ class CFileLoaderThread CFileLoaderThread(); ~CFileLoaderThread(); - int Create(void * arg); - + bool Create(void * arg); + void Shutdown(); + public: - void Request(std::string & c_rstFileName); + void Request(const std::string& c_rstFileName); bool Fetch(TData ** ppData); - void Shutdown(); - - protected: - static UINT CALLBACK EntryPoint(void * pThis); - UINT Run(void * arg); - - void * Arg() const { return m_pArg; } - void Arg(void * arg) { m_pArg = arg; } - - HANDLE m_hThread; private: - void * m_pArg; - unsigned m_uThreadID; - - protected: - UINT Setup(); - UINT Execute(void * pvArg); - void Destroy(); - void Process(); + void ProcessFile(const std::string& fileName); private: - std::deque m_pRequestDeque; - Mutex m_RequestMutex; - - std::deque m_pCompleteDeque; - Mutex m_CompleteMutex; - - HANDLE m_hSemaphore; - int m_iRestSemCount; + std::deque m_pCompleteDeque; + std::mutex m_CompleteMutex; bool m_bShutdowned; }; diff --git a/src/EterLib/FileLoaderThreadPool.cpp b/src/EterLib/FileLoaderThreadPool.cpp deleted file mode 100644 index aa078c7..0000000 --- a/src/EterLib/FileLoaderThreadPool.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "StdAfx.h" -#include "FileLoaderThreadPool.h" -#include "BufferPool.h" -#include "ImageDecoder.h" -#include "PackLib/PackManager.h" -#include - -static const bool USE_STAGED_TEXTURE_LOADING = true; - -CFileLoaderThreadPool::CFileLoaderThreadPool() - : m_pCompletedQueue(nullptr) - , m_bShutdown(false) - , m_nextRequestID(0) - , m_activeTasks(0) - , m_threadCount(0) -{ -} - -CFileLoaderThreadPool::~CFileLoaderThreadPool() -{ - Shutdown(); -} - -bool CFileLoaderThreadPool::Initialize(unsigned int threadCount) -{ - if (!m_workers.empty()) - { - TraceError("CFileLoaderThreadPool::Initialize: Already initialized"); - return false; - } - - if (threadCount == 0) - { - threadCount = std::thread::hardware_concurrency(); - if (threadCount == 0) - threadCount = 4; - else - threadCount = std::max(4u, threadCount / 2); - } - - threadCount = std::max(4u, std::min(16u, threadCount)); - m_threadCount = threadCount; - - Tracenf("CFileLoaderThreadPool: Initializing with %u worker threads", threadCount); - - m_pCompletedQueue = new SPSCQueue(COMPLETED_QUEUE_SIZE); - - m_workers.reserve(threadCount); - for (unsigned int i = 0; i < threadCount; ++i) - { - TWorkerThread worker; - worker.pRequestQueue = new SPSCQueue(REQUEST_QUEUE_SIZE); - worker.bBusy.store(false, std::memory_order_relaxed); - - try - { - worker.thread = std::thread(&CFileLoaderThreadPool::WorkerThreadFunction, this, i); - } - catch (const std::exception& e) - { - TraceError("CFileLoaderThreadPool::Initialize: Failed to create thread %u: %s", i, e.what()); - delete worker.pRequestQueue; - worker.pRequestQueue = nullptr; - Shutdown(); - return false; - } - - m_workers.push_back(std::move(worker)); - } - - return true; -} - -void CFileLoaderThreadPool::Shutdown() -{ - if (m_workers.empty()) - return; - - // Signal shutdown - m_bShutdown.store(true, std::memory_order_release); - - // Wait for all workers to finish - for (auto& worker : m_workers) - { - if (worker.thread.joinable()) - worker.thread.join(); - - // Cleanup request queue - if (worker.pRequestQueue) - { - delete worker.pRequestQueue; - worker.pRequestQueue = nullptr; - } - } - - m_workers.clear(); - - // Cleanup completed queue - if (m_pCompletedQueue) - { - delete m_pCompletedQueue; - m_pCompletedQueue = nullptr; - } - - m_threadCount = 0; -} - -bool CFileLoaderThreadPool::Request(const std::string& fileName) -{ - if (m_workers.empty()) - { - TraceError("CFileLoaderThreadPool::Request: Thread pool not initialized"); - return false; - } - - TLoadRequest request; - request.stFileName = fileName; - request.requestID = m_nextRequestID.fetch_add(1, std::memory_order_relaxed); - - request.decodeImage = false; - if (USE_STAGED_TEXTURE_LOADING) - { - size_t dotPos = fileName.find_last_of('.'); - if (dotPos != std::string::npos && dotPos + 1 < fileName.size()) - { - const char* ext = fileName.c_str() + dotPos; - size_t extLen = fileName.size() - dotPos; - - if ((extLen == 4 && (_stricmp(ext, ".dds") == 0 || _stricmp(ext, ".png") == 0 || - _stricmp(ext, ".jpg") == 0 || _stricmp(ext, ".tga") == 0 || _stricmp(ext, ".bmp") == 0)) || - (extLen == 5 && _stricmp(ext, ".jpeg") == 0)) - { - request.decodeImage = true; - } - } - } - - unsigned int targetWorker = SelectLeastBusyWorker(); - - if (!m_workers[targetWorker].pRequestQueue->Push(request)) - { - for (unsigned int i = 0; i < m_threadCount; ++i) - { - unsigned int workerIdx = (targetWorker + i) % m_threadCount; - if (m_workers[workerIdx].pRequestQueue->Push(request)) - { - m_activeTasks.fetch_add(1, std::memory_order_relaxed); - return true; - } - } - - TraceError("CFileLoaderThreadPool::Request: All worker queues full for file: %s", fileName.c_str()); - return false; - } - - m_activeTasks.fetch_add(1, std::memory_order_relaxed); - return true; -} - -bool CFileLoaderThreadPool::Fetch(TLoadResult& result) -{ - if (!m_pCompletedQueue) - return false; - - if (m_pCompletedQueue->Pop(result)) - { - m_activeTasks.fetch_sub(1, std::memory_order_relaxed); - return true; - } - return false; -} - -size_t CFileLoaderThreadPool::GetPendingCount() const -{ - size_t total = 0; - for (const auto& worker : m_workers) - { - if (worker.pRequestQueue) - total += worker.pRequestQueue->Size(); - } - return total; -} - -bool CFileLoaderThreadPool::IsIdle() const -{ - return m_activeTasks.load(std::memory_order_acquire) == 0; -} - -unsigned int CFileLoaderThreadPool::SelectLeastBusyWorker() const -{ - unsigned int leastBusyIdx = 0; - size_t minSize = m_workers[0].pRequestQueue->Size(); - - for (unsigned int i = 1; i < m_threadCount; ++i) - { - size_t queueSize = m_workers[i].pRequestQueue->Size(); - if (queueSize < minSize) - { - minSize = queueSize; - leastBusyIdx = i; - } - } - - return leastBusyIdx; -} - -void CFileLoaderThreadPool::WorkerThreadFunction(unsigned int workerIndex) -{ - TWorkerThread& worker = m_workers[workerIndex]; - SPSCQueue* pRequestQueue = worker.pRequestQueue; - - CBufferPool* pBufferPool = CPackManager::instance().GetBufferPool(); - - Tracenf("CFileLoaderThreadPool: Worker thread %u started", workerIndex); - - int idleCount = 0; - - while (!m_bShutdown.load(std::memory_order_acquire)) - { - TLoadRequest request; - - if (pRequestQueue->Pop(request)) - { - idleCount = 0; - worker.bBusy.store(true, std::memory_order_release); - - TLoadResult result; - result.stFileName = request.stFileName; - result.requestID = request.requestID; - result.File.clear(); - result.hasDecodedImage = false; - - CPackManager::instance().GetFileWithPool(request.stFileName, result.File, pBufferPool); - - if (request.decodeImage && !result.File.empty()) - { - if (CImageDecoder::DecodeImage(result.File.data(), result.File.size(), result.decodedImage)) - { - result.hasDecodedImage = true; - result.File.clear(); - } - } - - while (!m_pCompletedQueue->Push(result)) - { - std::this_thread::yield(); - - if (m_bShutdown.load(std::memory_order_acquire)) - break; - } - - worker.bBusy.store(false, std::memory_order_release); - } - else - { - idleCount++; - if (idleCount > 1000) - { - Sleep(1); - idleCount = 0; - } - else if (idleCount > 10) - { - std::this_thread::yield(); - } - } - } - - Tracenf("CFileLoaderThreadPool: Worker thread %u stopped", workerIndex); -} diff --git a/src/EterLib/FileLoaderThreadPool.h b/src/EterLib/FileLoaderThreadPool.h deleted file mode 100644 index de7c52a..0000000 --- a/src/EterLib/FileLoaderThreadPool.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef __INC_ETERLIB_FILELOADERTHREADPOOL_H__ -#define __INC_ETERLIB_FILELOADERTHREADPOOL_H__ - -#include -#include -#include -#include "SPSCQueue.h" -#include "PackLib/PackManager.h" -#include "DecodedImageData.h" - -class CFileLoaderThreadPool -{ -public: - struct TLoadRequest - { - std::string stFileName; - uint32_t requestID; - bool decodeImage; - }; - - struct TLoadResult - { - std::string stFileName; - TPackFile File; - uint32_t requestID; - TDecodedImageData decodedImage; - bool hasDecodedImage; - }; - -public: - CFileLoaderThreadPool(); - ~CFileLoaderThreadPool(); - - bool Initialize(unsigned int threadCount = 0); - void Shutdown(); - bool Request(const std::string& fileName); - bool Fetch(TLoadResult& result); - size_t GetPendingCount() const; - bool IsIdle() const; - -private: - struct TWorkerThread - { - std::thread thread; - SPSCQueue* pRequestQueue; - std::atomic bBusy; - - TWorkerThread() : pRequestQueue(nullptr), bBusy(false) {} - - TWorkerThread(TWorkerThread&& other) noexcept - : thread(std::move(other.thread)) - , pRequestQueue(other.pRequestQueue) - , bBusy(other.bBusy.load()) - { - other.pRequestQueue = nullptr; - } - - TWorkerThread& operator=(TWorkerThread&& other) noexcept - { - if (this != &other) - { - thread = std::move(other.thread); - pRequestQueue = other.pRequestQueue; - bBusy.store(other.bBusy.load()); - other.pRequestQueue = nullptr; - } - return *this; - } - - TWorkerThread(const TWorkerThread&) = delete; - TWorkerThread& operator=(const TWorkerThread&) = delete; - }; - - void WorkerThreadFunction(unsigned int workerIndex); - unsigned int SelectLeastBusyWorker() const; - -private: - std::vector m_workers; - SPSCQueue* m_pCompletedQueue; - - std::atomic m_bShutdown; - std::atomic m_nextRequestID; - std::atomic m_activeTasks; // Fast IsIdle check - unsigned int m_threadCount; - - static const size_t REQUEST_QUEUE_SIZE = 16384; // Doubled from 8192 - static const size_t COMPLETED_QUEUE_SIZE = 32768; // Doubled from 16384 -}; - -#endif // __INC_ETERLIB_FILELOADERTHREADPOOL_H__ diff --git a/src/EterLib/GameThreadPool.cpp b/src/EterLib/GameThreadPool.cpp index 8289d36..90fdd7a 100644 --- a/src/EterLib/GameThreadPool.cpp +++ b/src/EterLib/GameThreadPool.cpp @@ -4,7 +4,6 @@ CGameThreadPool::CGameThreadPool() : m_bShutdown(false) , m_bInitialized(false) - , m_iNextWorkerIndex(0) { } @@ -15,7 +14,9 @@ CGameThreadPool::~CGameThreadPool() void CGameThreadPool::Initialize(int iWorkerCount) { - if (m_bInitialized) + std::lock_guard lock(m_lifecycleMutex); + + if (m_bInitialized.load(std::memory_order_acquire)) { TraceError("CGameThreadPool::Initialize - Already initialized!"); return; @@ -35,30 +36,43 @@ void CGameThreadPool::Initialize(int iWorkerCount) Tracef("CGameThreadPool::Initialize - Creating %d worker threads\n", iWorkerCount); m_bShutdown.store(false, std::memory_order_release); + m_workers.clear(); m_workers.reserve(iWorkerCount); - // Initialize each worker + // First create all workers for (int i = 0; i < iWorkerCount; ++i) { - std::unique_ptr pWorker(new TWorkerThread()); - pWorker->pTaskQueue.reset(new SPSCQueue(QUEUE_SIZE)); - pWorker->bBusy.store(false, std::memory_order_relaxed); + auto pWorker = std::make_unique(); + pWorker->pTaskQueue = std::make_unique>(QUEUE_SIZE); pWorker->uTaskCount.store(0, std::memory_order_relaxed); - pWorker->thread = std::thread(&CGameThreadPool::WorkerThreadProc, this, i); m_workers.push_back(std::move(pWorker)); } + // Mark as initialized before starting threads m_bInitialized.store(true, std::memory_order_release); + + // Then start threads after all workers are created + for (int i = 0; i < iWorkerCount; ++i) + { + TWorkerThread* pWorker = m_workers[i].get(); + // Pass worker pointer directly instead of index + pWorker->thread = std::thread(&CGameThreadPool::WorkerThreadProc, this, pWorker); + } } void CGameThreadPool::Destroy() { - if (!m_bInitialized) + std::lock_guard lock(m_lifecycleMutex); + + if (!m_bInitialized.load(std::memory_order_acquire)) return; Tracef("CGameThreadPool::Destroy - Shutting down %d worker threads\n", GetWorkerCount()); + // Signal shutdown first m_bShutdown.store(true, std::memory_order_release); + + // Mark as not initialized to prevent new enqueues m_bInitialized.store(false, std::memory_order_release); // Join all worker threads @@ -71,17 +85,23 @@ void CGameThreadPool::Destroy() m_workers.clear(); } -void CGameThreadPool::WorkerThreadProc(int iWorkerIndex) +void CGameThreadPool::WorkerThreadProc(TWorkerThread* pWorker) { - TWorkerThread* pWorker = m_workers[iWorkerIndex].get(); int iIdleCount = 0; while (!m_bShutdown.load(std::memory_order_acquire)) { TTask task; - if (pWorker->pTaskQueue->Pop(task)) + + // Pop from queue with minimal locking + bool bHasTask = false; + { + std::lock_guard lock(pWorker->queueMutex); + bHasTask = pWorker->pTaskQueue->Pop(task); + } + + if (bHasTask) { - pWorker->bBusy.store(true, std::memory_order_relaxed); iIdleCount = 0; // Execute the task @@ -91,15 +111,14 @@ void CGameThreadPool::WorkerThreadProc(int iWorkerIndex) } catch (const std::exception& e) { - TraceError("CGameThreadPool::WorkerThreadProc - Exception in worker %d: %s", iWorkerIndex, e.what()); + TraceError("CGameThreadPool::WorkerThreadProc - Exception: %s", e.what()); } catch (...) { - TraceError("CGameThreadPool::WorkerThreadProc - Unknown exception in worker %d", iWorkerIndex); + TraceError("CGameThreadPool::WorkerThreadProc - Unknown exception"); } pWorker->uTaskCount.fetch_sub(1, std::memory_order_relaxed); - pWorker->bBusy.store(false, std::memory_order_relaxed); } else { @@ -120,9 +139,41 @@ void CGameThreadPool::WorkerThreadProc(int iWorkerIndex) { // Longer sleep for extended idle std::this_thread::sleep_for(std::chrono::milliseconds(1)); + // Reset idle count to prevent overflow + if (iIdleCount > 10000) + iIdleCount = 1000; } } } + + // Process remaining tasks before shutdown + TTask task; + while (true) + { + bool bHasTask = false; + { + std::lock_guard lock(pWorker->queueMutex); + bHasTask = pWorker->pTaskQueue->Pop(task); + } + + if (!bHasTask) + break; + + try + { + task(); + } + catch (const std::exception& e) + { + TraceError("CGameThreadPool::WorkerThreadProc - Exception during shutdown: %s", e.what()); + } + catch (...) + { + TraceError("CGameThreadPool::WorkerThreadProc - Unknown exception during shutdown"); + } + + pWorker->uTaskCount.fetch_sub(1, std::memory_order_relaxed); + } } int CGameThreadPool::SelectLeastBusyWorker() const diff --git a/src/EterLib/GameThreadPool.h b/src/EterLib/GameThreadPool.h index d4c9059..a14ffb4 100644 --- a/src/EterLib/GameThreadPool.h +++ b/src/EterLib/GameThreadPool.h @@ -8,6 +8,7 @@ #include #include #include +#include class CGameThreadPool : public CSingleton { @@ -35,30 +36,29 @@ public: size_t GetPendingTaskCount() const; // Check if pool is initialized - bool IsInitialized() const { return m_bInitialized; } + bool IsInitialized() const { return m_bInitialized.load(std::memory_order_acquire); } private: struct TWorkerThread { std::thread thread; std::unique_ptr> pTaskQueue; - std::atomic bBusy; + std::mutex queueMutex; // Mutex to protect SPSC queue from multiple producers std::atomic uTaskCount; TWorkerThread() - : bBusy(false) - , uTaskCount(0) + : uTaskCount(0) { } }; - void WorkerThreadProc(int iWorkerIndex); + void WorkerThreadProc(TWorkerThread* pWorker); int SelectLeastBusyWorker() const; std::vector> m_workers; std::atomic m_bShutdown; std::atomic m_bInitialized; - std::atomic m_iNextWorkerIndex; // For round-robin distribution + mutable std::mutex m_lifecycleMutex; // Protects initialization/destruction static const size_t QUEUE_SIZE = 8192; }; @@ -67,9 +67,14 @@ private: template std::future CGameThreadPool::Enqueue(TFunc&& func) { - if (!m_bInitialized) + // Lock to ensure thread pool isn't being destroyed + std::unique_lock lock(m_lifecycleMutex); + + if (!m_bInitialized.load(std::memory_order_acquire)) { // If not initialized, execute on calling thread + lock.unlock(); // No need to hold lock + auto promise = std::make_shared>(); auto future = promise->get_future(); try @@ -109,10 +114,24 @@ std::future CGameThreadPool::Enqueue(TFunc&& func) int iWorkerIndex = SelectLeastBusyWorker(); TWorkerThread* pWorker = m_workers[iWorkerIndex].get(); - // Try to enqueue the task - if (!pWorker->pTaskQueue->Push(std::move(task))) + // Increment task count before pushing + pWorker->uTaskCount.fetch_add(1, std::memory_order_relaxed); + + // Try to enqueue the task with mutex protection for SPSC queue + bool bPushed = false; { - // Queue is full, execute on calling thread as fallback + std::lock_guard queueLock(pWorker->queueMutex); + bPushed = pWorker->pTaskQueue->Push(std::move(task)); + } + + if (!bPushed) + { + // Queue is full, decrement count and execute on calling thread as fallback + pWorker->uTaskCount.fetch_sub(1, std::memory_order_relaxed); + + // Release lifecycle lock before executing task + lock.unlock(); + try { (*pFunc)(); @@ -123,10 +142,6 @@ std::future CGameThreadPool::Enqueue(TFunc&& func) promise->set_exception(std::current_exception()); } } - else - { - pWorker->uTaskCount.fetch_add(1, std::memory_order_relaxed); - } return future; } diff --git a/src/EterLib/ResourceManager.cpp b/src/EterLib/ResourceManager.cpp index e030137..777a831 100644 --- a/src/EterLib/ResourceManager.cpp +++ b/src/EterLib/ResourceManager.cpp @@ -71,14 +71,7 @@ void CResourceManager::ProcessBackgroundLoading() //printf("REQ %s\n", stFileName.c_str()); - if (m_pLoaderThreadPool) - { - m_pLoaderThreadPool->Request(stFileName); - } - else - { - ms_loadingThread.Request(stFileName); - } + ms_loadingThread.Request(stFileName); m_WaitingMap.insert(TResourceRequestMap::value_type(dwFileCRC, stFileName)); itor = m_RequestMap.erase(itor); @@ -87,44 +80,7 @@ void CResourceManager::ProcessBackgroundLoading() DWORD dwCurrentTime = ELTimer_GetMSec(); - if (m_pLoaderThreadPool) - { - CFileLoaderThreadPool::TLoadResult result; - while (m_pLoaderThreadPool->Fetch(result)) - { - CResource * pResource = GetResourcePointer(result.stFileName.c_str()); - - if (pResource) - { - if (pResource->IsEmpty()) - { - if (result.hasDecodedImage) - { - CGraphicImage* pImage = dynamic_cast(pResource); - if (pImage) - { - pImage->OnLoadFromDecodedData(result.decodedImage); - } - else - { - pResource->OnLoad(result.File.size(), result.File.data()); - } - } - else - { - pResource->OnLoad(result.File.size(), result.File.data()); - } - - pResource->AddReferenceOnly(); - m_pResRefDecreaseWaitingMap.insert(TResourceRefDecreaseWaitingMap::value_type(dwCurrentTime, pResource)); - } - } - - m_WaitingMap.erase(GetCRC32(result.stFileName.c_str(), result.stFileName.size())); - } - } - - // Process old thread results + // Process thread results CFileLoaderThread::TData * pData; while (ms_loadingThread.Fetch(&pData)) { @@ -580,19 +536,9 @@ void CResourceManager::ReserveDeletingResource(CResource * pResource) } CResourceManager::CResourceManager() - : m_pLoaderThreadPool(nullptr) - , m_pTextureCache(nullptr) + : m_pTextureCache(nullptr) { ms_loadingThread.Create(0); - - m_pLoaderThreadPool = new CFileLoaderThreadPool(); - if (!m_pLoaderThreadPool->Initialize()) - { - TraceError("CResourceManager: Failed to initialize FileLoaderThreadPool"); - delete m_pLoaderThreadPool; - m_pLoaderThreadPool = nullptr; - } - m_pTextureCache = new CTextureCache(512); } @@ -601,12 +547,6 @@ CResourceManager::~CResourceManager() Destroy(); ms_loadingThread.Shutdown(); - if (m_pLoaderThreadPool) - { - delete m_pLoaderThreadPool; - m_pLoaderThreadPool = nullptr; - } - if (m_pTextureCache) { delete m_pTextureCache; diff --git a/src/EterLib/ResourceManager.h b/src/EterLib/ResourceManager.h index 9841d41..facb17f 100644 --- a/src/EterLib/ResourceManager.h +++ b/src/EterLib/ResourceManager.h @@ -2,7 +2,6 @@ #include "Resource.h" #include "FileLoaderThread.h" -#include "FileLoaderThreadPool.h" #include #include @@ -47,7 +46,6 @@ class CResourceManager : public CSingleton void PushBackgroundLoadingSet(std::set & LoadingSet); CTextureCache* GetTextureCache() { return m_pTextureCache; } - CFileLoaderThreadPool* GetLoaderThreadPool() { return m_pLoaderThreadPool; } protected: void __DestroyDeletingResourceMap(); @@ -75,7 +73,6 @@ class CResourceManager : public CSingleton TResourceRefDecreaseWaitingMap m_pResRefDecreaseWaitingMap; static CFileLoaderThread ms_loadingThread; - CFileLoaderThreadPool* m_pLoaderThreadPool; CTextureCache* m_pTextureCache; mutable std::mutex m_ResourceMapMutex; // Thread-safe resource map access diff --git a/src/GameLib/RaceManager.cpp b/src/GameLib/RaceManager.cpp index 306a4cb..de67957 100644 --- a/src/GameLib/RaceManager.cpp +++ b/src/GameLib/RaceManager.cpp @@ -8,8 +8,6 @@ #include #include -bool CRaceManager::s_bPreloaded = false; - bool __IsGuildRace(unsigned race) { if (race >= 14000 && race < 15000) @@ -491,173 +489,3 @@ CRaceManager::~CRaceManager() { Destroy(); } - -void CRaceManager::PreloadPlayerRaceMotions() -{ - if (s_bPreloaded) - return; - - CRaceManager& rkRaceMgr = CRaceManager::Instance(); - - for (DWORD dwRace = 0; dwRace <= 7; ++dwRace) - { - TRaceDataIterator it = rkRaceMgr.m_RaceDataMap.find(dwRace); - if (it == rkRaceMgr.m_RaceDataMap.end()) - { - CRaceData* pRaceData = rkRaceMgr.__LoadRaceData(dwRace); - if (pRaceData) - { - rkRaceMgr.m_RaceDataMap.insert(TRaceDataMap::value_type(pRaceData->GetRaceIndex(), pRaceData)); - } - } - } - - std::set uniqueMotions; - - for (DWORD dwRace = 0; dwRace <= 7; ++dwRace) - { - CRaceData* pRaceData = NULL; - TRaceDataIterator it = rkRaceMgr.m_RaceDataMap.find(dwRace); - if (it != rkRaceMgr.m_RaceDataMap.end()) - pRaceData = it->second; - - if (!pRaceData) - continue; - - CRaceData::TMotionModeDataIterator itor; - if (pRaceData->CreateMotionModeIterator(itor)) - { - do - { - CRaceData::TMotionModeData* pMotionModeData = itor->second; - for (auto& itorMotion : pMotionModeData->MotionVectorMap) - { - const CRaceData::TMotionVector& c_rMotionVector = itorMotion.second; - for (const auto& motion : c_rMotionVector) - { - if (motion.pMotion) - uniqueMotions.insert(motion.pMotion); - } - } - } - while (pRaceData->NextMotionModeIterator(itor)); - } - } - - std::vector motionVec(uniqueMotions.begin(), uniqueMotions.end()); - size_t total = motionVec.size(); - - if (total > 0) - { - CGameThreadPool* pThreadPool = CGameThreadPool::InstancePtr(); - if (pThreadPool && pThreadPool->IsInitialized()) - { - size_t workerCount = pThreadPool->GetWorkerCount(); - size_t chunkSize = (total + workerCount - 1) / workerCount; - - std::vector> futures; - futures.reserve(workerCount); - - for (size_t i = 0; i < workerCount; ++i) - { - size_t start = i * chunkSize; - size_t end = std::min(start + chunkSize, total); - - if (start < end) - { - // Copy values instead of capturing by reference - futures.push_back(pThreadPool->Enqueue([start, end, motionVec]() { - for (size_t k = start; k < end; ++k) - { - motionVec[k]->AddReference(); - } - })); - } - } - - // Wait for all tasks to complete - for (auto& f : futures) - { - f.wait(); - } - } - else - { - // Fallback to sequential if thread pool not available - for (auto* pMotion : motionVec) - { - pMotion->AddReference(); - } - } - } - - s_bPreloaded = true; -} - -void CRaceManager::RequestAsyncRaceLoad(DWORD dwRaceIndex) -{ - // Mark as loading - { - std::lock_guard lock(m_LoadingRacesMutex); - if (m_LoadingRaces.find(dwRaceIndex) != m_LoadingRaces.end()) - { - // Already loading - return; - } - m_LoadingRaces.insert(dwRaceIndex); - } - - // Enqueue async load to game thread pool - CGameThreadPool* pThreadPool = CGameThreadPool::InstancePtr(); - if (pThreadPool) - { - pThreadPool->Enqueue([this, dwRaceIndex]() - { - CRaceData* pRaceData = __LoadRaceData(dwRaceIndex); - - if (pRaceData) - { - // Thread-safe insertion - { - std::lock_guard lock(m_RaceDataMapMutex); - m_RaceDataMap.insert(TRaceDataMap::value_type(dwRaceIndex, pRaceData)); - } - - Tracef("CRaceManager::RequestAsyncRaceLoad: Successfully loaded race %lu asynchronously\n", dwRaceIndex); - } - else - { - TraceError("CRaceManager::RequestAsyncRaceLoad: Failed to load race %lu", dwRaceIndex); - } - - // Remove from loading set - { - std::lock_guard lock(m_LoadingRacesMutex); - m_LoadingRaces.erase(dwRaceIndex); - } - }); - } - else - { - // Fallback to synchronous loading if thread pool not available - CRaceData* pRaceData = __LoadRaceData(dwRaceIndex); - - if (pRaceData) - { - std::lock_guard lock(m_RaceDataMapMutex); - m_RaceDataMap.insert(TRaceDataMap::value_type(dwRaceIndex, pRaceData)); - } - - // Remove from loading set - { - std::lock_guard lock(m_LoadingRacesMutex); - m_LoadingRaces.erase(dwRaceIndex); - } - } -} - -bool CRaceManager::IsRaceLoading(DWORD dwRaceIndex) const -{ - std::lock_guard lock(m_LoadingRacesMutex); - return m_LoadingRaces.find(dwRaceIndex) != m_LoadingRaces.end(); -} diff --git a/src/GameLib/RaceManager.h b/src/GameLib/RaceManager.h index e2e5f27..efcbaa8 100644 --- a/src/GameLib/RaceManager.h +++ b/src/GameLib/RaceManager.h @@ -31,14 +31,6 @@ class CRaceManager : public CSingleton BOOL GetRaceDataPointer(DWORD dwRaceIndex, CRaceData ** ppRaceData); - // Async race loading - void RequestAsyncRaceLoad(DWORD dwRaceIndex); - bool IsRaceLoading(DWORD dwRaceIndex) const; - - // Race motion preloading - static void PreloadPlayerRaceMotions(); - static bool IsPreloaded() { return s_bPreloaded; } - protected: CRaceData* __LoadRaceData(DWORD dwRaceIndex); bool __LoadRaceMotionList(CRaceData& rkRaceData, const char* pathName, const char* motionListFileName); @@ -59,5 +51,4 @@ class CRaceManager : public CSingleton private: std::string m_strPathName; CRaceData * m_pSelectedRaceData; - static bool s_bPreloaded; -}; \ No newline at end of file +}; diff --git a/src/UserInterface/PythonCharacterManagerModule.cpp b/src/UserInterface/PythonCharacterManagerModule.cpp index e1d6690..5549755 100644 --- a/src/UserInterface/PythonCharacterManagerModule.cpp +++ b/src/UserInterface/PythonCharacterManagerModule.cpp @@ -713,12 +713,6 @@ PyObject * chrmgrIsPossibleEmoticon(PyObject* poSelf, PyObject* poArgs) return Py_BuildValue("i", result); } -PyObject * chrmgrPreloadRaceMotions(PyObject* poSelf, PyObject* poArgs) -{ - CRaceManager::PreloadPlayerRaceMotions(); - return Py_BuildNone(); -} - void initchrmgr() { static PyMethodDef s_methods[] = @@ -752,7 +746,6 @@ void initchrmgr() { "SetAffect", chrmgrSetAffect, METH_VARARGS }, { "SetEmoticon", chrmgrSetEmoticon, METH_VARARGS }, { "IsPossibleEmoticon", chrmgrIsPossibleEmoticon, METH_VARARGS }, - { "PreloadRaceMotions", chrmgrPreloadRaceMotions, METH_VARARGS }, { "RegisterEffect", chrmgrRegisterEffect, METH_VARARGS }, { "RegisterCacheEffect", chrmgrRegisterCacheEffect, METH_VARARGS }, { "RegisterPointEffect", chrmgrRegisterPointEffect, METH_VARARGS }, diff --git a/src/UserInterface/PythonSoundManagerModule.cpp b/src/UserInterface/PythonSoundManagerModule.cpp index 3fdd410..e8a4a91 100644 --- a/src/UserInterface/PythonSoundManagerModule.cpp +++ b/src/UserInterface/PythonSoundManagerModule.cpp @@ -96,7 +96,7 @@ PyObject* sndSetMusicVolume(PyObject* poSelf, PyObject* poArgs) return Py_BuildNone(); } -PyObject* sndSetSoundVolumef(PyObject* poSelf, PyObject* poArgs) +PyObject* sndSetSoundVolume(PyObject* poSelf, PyObject* poArgs) { float fVolume; if (!PyTuple_GetFloat(poArgs, 0, &fVolume)) @@ -106,16 +106,6 @@ PyObject* sndSetSoundVolumef(PyObject* poSelf, PyObject* poArgs) return Py_BuildNone(); } -PyObject* sndSetSoundVolume(PyObject* poSelf, PyObject* poArgs) -{ - float volume; - if (!PyTuple_GetFloat(poArgs, 0, &volume)) - return Py_BuildException(); - - SoundEngine::Instance().SetSoundVolume(volume / 100.0f); - return Py_BuildNone(); -} - void initsnd() { static PyMethodDef s_methods[] = @@ -130,7 +120,6 @@ void initsnd() { "SetMasterVolume", sndSetMasterVolume, METH_VARARGS }, { "SetMusicVolume", sndSetMusicVolume, METH_VARARGS }, - { "SetSoundVolumef", sndSetSoundVolumef, METH_VARARGS }, { "SetSoundVolume", sndSetSoundVolume, METH_VARARGS }, { NULL, NULL, NULL }, }; diff --git a/src/UserInterface/PythonSystem.cpp b/src/UserInterface/PythonSystem.cpp index fbeb7c0..7e45a4c 100644 --- a/src/UserInterface/PythonSystem.cpp +++ b/src/UserInterface/PythonSystem.cpp @@ -213,7 +213,7 @@ float CPythonSystem::GetMusicVolume() return m_Config.music_volume; } -int CPythonSystem::GetSoundVolume() +float CPythonSystem::GetSoundVolume() { return m_Config.voice_volume; } @@ -223,9 +223,9 @@ void CPythonSystem::SetMusicVolume(float fVolume) m_Config.music_volume = fVolume; } -void CPythonSystem::SetSoundVolumef(float fVolume) +void CPythonSystem::SetSoundVolume(float fVolume) { - m_Config.voice_volume = int(5 * fVolume); + m_Config.voice_volume = fVolume; } int CPythonSystem::GetDistance() @@ -294,7 +294,7 @@ void CPythonSystem::SetDefaultConfig() m_Config.gamma = 3; m_Config.music_volume = 1.0f; - m_Config.voice_volume = 5; + m_Config.voice_volume = 1.0f; m_Config.bDecompressDDS = 0; m_Config.bSoftwareTiling = 0; @@ -409,15 +409,10 @@ bool CPythonSystem::LoadConfig() m_Config.is_object_culling = atoi(value) ? true : false; else if (!stricmp(command, "VISIBILITY")) m_Config.iDistance = atoi(value); - else if (!stricmp(command, "MUSIC_VOLUME")) { - if(strchr(value, '.') == 0) { // Old compatiability - m_Config.music_volume = pow(10.0f, (-1.0f + (((float) atoi(value)) / 5.0f))); - if(atoi(value) == 0) - m_Config.music_volume = 0.0f; - } else - m_Config.music_volume = atof(value); - } else if (!stricmp(command, "VOICE_VOLUME")) - m_Config.voice_volume = (char) atoi(value); + else if (!stricmp(command, "MUSIC_VOLUME")) + m_Config.music_volume = atof(value); + else if (!stricmp(command, "VOICE_VOLUME")) + m_Config.voice_volume = atof(value); else if (!stricmp(command, "GAMMA")) m_Config.gamma = atoi(value); else if (!stricmp(command, "IS_SAVE_ID")) @@ -503,7 +498,7 @@ bool CPythonSystem::SaveConfig() "OBJECT_CULLING %d\n" "VISIBILITY %d\n" "MUSIC_VOLUME %.3f\n" - "VOICE_VOLUME %d\n" + "VOICE_VOLUME %.3f\n" "GAMMA %d\n" "IS_SAVE_ID %d\n" "SAVE_ID %s\n" diff --git a/src/UserInterface/PythonSystem.h b/src/UserInterface/PythonSystem.h index f70d2b3..8528b83 100644 --- a/src/UserInterface/PythonSystem.h +++ b/src/UserInterface/PythonSystem.h @@ -59,7 +59,7 @@ class CPythonSystem : public CSingleton int iShadowLevel; FLOAT music_volume; - BYTE voice_volume; + FLOAT voice_volume; int gamma; @@ -141,9 +141,9 @@ class CPythonSystem : public CSingleton // Sound float GetMusicVolume(); - int GetSoundVolume(); + float GetSoundVolume(); void SetMusicVolume(float fVolume); - void SetSoundVolumef(float fVolume); + void SetSoundVolume(float fVolume); int GetDistance(); int GetShadowLevel(); diff --git a/src/UserInterface/PythonSystemModule.cpp b/src/UserInterface/PythonSystemModule.cpp index bc4f356..efd9e10 100644 --- a/src/UserInterface/PythonSystemModule.cpp +++ b/src/UserInterface/PythonSystemModule.cpp @@ -134,7 +134,7 @@ PyObject * systemGetMusicVolume(PyObject * poSelf, PyObject * poArgs) PyObject * systemGetSoundVolume(PyObject * poSelf, PyObject * poArgs) { - return Py_BuildValue("i", CPythonSystem::Instance().GetSoundVolume()); + return Py_BuildValue("f", CPythonSystem::Instance().GetSoundVolume()); } PyObject * systemSetMusicVolume(PyObject * poSelf, PyObject * poArgs) @@ -147,13 +147,13 @@ PyObject * systemSetMusicVolume(PyObject * poSelf, PyObject * poArgs) return Py_BuildNone(); } -PyObject * systemSetSoundVolumef(PyObject * poSelf, PyObject * poArgs) +PyObject * systemSetSoundVolume(PyObject * poSelf, PyObject * poArgs) { float fVolume; if (!PyTuple_GetFloat(poArgs, 0, &fVolume)) return Py_BuildException(); - CPythonSystem::Instance().SetSoundVolumef(fVolume); + CPythonSystem::Instance().SetSoundVolume(fVolume); return Py_BuildNone(); } @@ -408,7 +408,7 @@ void initsystem() { "GetSoundVolume", systemGetSoundVolume, METH_VARARGS }, { "SetMusicVolume", systemSetMusicVolume, METH_VARARGS }, - { "SetSoundVolumef", systemSetSoundVolumef, METH_VARARGS }, + { "SetSoundVolume", systemSetSoundVolume, METH_VARARGS }, { "IsSoftwareCursor", systemIsSoftwareCursor, METH_VARARGS }, { "SetViewChatFlag", systemSetViewChatFlag, METH_VARARGS },