#include "Contents/Repute/ReputeMgr.h" #include "UI/Window/UIEnums.h" #include "UI/Window/WindowId.h" #include "Client/Application/ErrorDialog.h" #include "Render/DeviceContext/DCSurface.h" #include "Contents/Tables/MessageTable.h" #include "File/File.h" #include "Network/TextEncoding.h" #include "UI/Window/UIWindow.h" #include "UI/Window/UIWindowMgr.h" #include "Resource/Json/JsonCppLoader.h" #include "Resource/MSGSTRINGID.h" #include #include #include extern "C" void JsonDestroy(); struct JsonValueCopy { /* 0000 */ JsonValue value; // INLINED JsonValueCopy(const JsonValue& other) { reinterpret_cast(JsonCopyConstruct)(&this->value, &other); } JsonValueCopy(const JsonValueCopy&) = delete; // INLINED ~JsonValueCopy() { reinterpret_cast(JsonDestroy)(&this->value); } }; // OFFSET: 0x0050AE30 // FUNCTION: fn_00894 bool JsonCppLoader::GetReputeGroupData(std::map* out) { if (!this->loaded) { this->Fail("초기화가 되어야 합니다."); return false; } const JsonValue* groups = nullptr; if (const JsonObject* root = this->document.ObjectRange()) { for (const JsonMember& entry : *root) { if (entry.first == "ReputeGroup") { groups = &entry.second; break; } } } if (groups == nullptr) { this->Fail("키에 해당하는 데이터가 없습니다. (key : %s)", "ReputeGroup"); return false; } if (const JsonObject* members = groups->ObjectRange()) { for (const JsonMember& member : *members) { const std::string name = member.first; const JsonValueCopy node(member.second); ReputeGroupRecord record; this->GetStringValue(node.value, "ID", &record.id); this->GetStringValue(node.value, "Name", &record.name); this->GetIntVectorValue(node.value, "ReputeList", &record.reputes); if (!out->insert(std::pair(std::stoi(name), record)).second) { this->Fail("중복키가 입력되었습니다. (name : %s)", name.c_str()); return false; } } } return this->succeeded; } // OFFSET: 0x0050B830 // FUNCTION: fn_00895 bool JsonCppLoader::GetReputeInfoData(std::map* out) { if (!this->loaded) { this->Fail("초기화가 되어야 합니다."); return false; } const JsonValue* infos = nullptr; if (const JsonObject* root = this->document.ObjectRange()) { for (const JsonMember& entry : *root) { if (entry.first == "reputeInfo") { infos = &entry.second; break; } } } if (infos == nullptr) { this->Fail("키에 해당하는 데이터가 없습니다. (key : %s)", "reputeInfo"); return false; } if (const JsonObject* members = infos->ObjectRange()) { for (const JsonMember& member : *members) { const std::string name = member.first; const JsonValueCopy node(member.second); ReputeInfoRecord record; this->GetStringValue(node.value, "Name", &record.name); this->GetIntValue(node.value, "MaxPoint_Positive", &record.maxPointPositive); this->GetIntValue(node.value, "MaxPoint_Negative", &record.maxPointNegative); this->GetStringValue(node.value, "Invisible", &record.invisible); if (!out->insert(std::pair(std::stoi(name), record)).second) { this->Fail("중복키가 입력되었습니다. (key : %s)", name.c_str()); return false; } } } return this->succeeded; } // OFFSET: 0x0060DC70 // FUNCTION: fn_04294 bool CReputeMgr::LoadReputeGroupData(std::map& groups) { std::string path = "ContentData\\Repute\\ReputeGroupData.bson"; CFile file; if (!file.Open(path.c_str(), 0, true, false)) { return false; } JsonCppLoader loader; const auto* data = static_cast(file.GetData()); bool parsed; { std::vector buffer(data, data + file.GetSize()); parsed = loader.Load(buffer, true); } if (!parsed) { return false; } std::map records; if (!loader.GetReputeGroupData(&records)) { return false; } groups.clear(); std::for_each(records.begin(), records.end(), GroupInserter{this, &groups}); return true; } // OFFSET: 0x0060E090 // FUNCTION: fn_04295 bool CReputeMgr::LoadReputeInfoData(std::map& infos) { std::string path = "ContentData\\Repute\\ReputeInfoData.bson"; CFile file; if (!file.Open(path.c_str(), 0, true, false)) { return false; } JsonCppLoader loader; const auto* data = static_cast(file.GetData()); bool parsed; { std::vector buffer(data, data + file.GetSize()); parsed = loader.Load(buffer, true); } if (!parsed) { return false; } std::map records; if (!loader.GetReputeInfoData(&records)) { return false; } infos.clear(); std::for_each(records.begin(), records.end(), InfoInserter{this, &infos}); return true; } // OFFSET: 0x0060C5D0 // FUNCTION: fn_04283 CReputeMgr::CReputeMgr() { } // OFFSET: 0x0060D8B0 // FUNCTION: fn_04290 std::vector CReputeMgr::GetGroupNames() const { std::vector names; std::for_each(this->m_groups.begin(), this->m_groups.end(), [&names](const std::pair& entry) { std::pair group = entry; names.push_back(group.second.name); }); return names; } // OFFSET: 0x0060D930 // FUNCTION: fn_04291 std::vector CReputeMgr::GetGroupReputes(const std::string& groupName) const { std::vector reputes; for (auto group = this->m_groups.begin(); group != this->m_groups.end(); ++group) { if (group->second.name == groupName) { for (auto id = group->second.reputes.begin(); id != group->second.reputes.end(); ++id) { auto found = this->m_infos.find(*id); if (found == this->m_infos.end()) { continue; } const ReputeVisibility visibility = found->second.visibility; if (REPUTE_VISIBLE == visibility || (visibility == REPUTE_VISIBLE_WITH_POINT && 0 != found->second.point)) { reputes.push_back(&found->second); } } } } return reputes; } // OFFSET: 0x0060DAB0 // FUNCTION: fn_04292 std::vector CReputeMgr::GetAllReputes() const { std::vector reputes; for (auto group = this->m_groups.begin(); group != this->m_groups.end(); ++group) { for (auto id = group->second.reputes.begin(); id != group->second.reputes.end(); ++id) { auto found = this->m_infos.find(*id); if (found == this->m_infos.end()) { continue; } const ReputeVisibility visibility = found->second.visibility; if (REPUTE_VISIBLE == visibility || (visibility == REPUTE_VISIBLE_WITH_POINT && 0 != found->second.point)) { reputes.push_back(&found->second); } } } return reputes; } // OFFSET: 0x0060DBF0 // FUNCTION: fn_04293 bool CReputeMgr::Load() { if (!this->LoadReputeInfoData(this->m_infos)) { ShowErrorDialog(GetRenderSystemHolder()->system, "Failed : LoadReputeInfoData", 0); return false; } if (!this->LoadReputeGroupData(this->m_groups)) { return false; } return true; } // OFFSET: 0x0060E4A0 // FUNCTION: fn_04296 void CReputeMgr::OpenRepute(std::uint64_t groupId, std::uint64_t reputeId) { UIWindow* window = g_windowMgr.EnsureWindow(WID_REPUTEWND); if (!window) { return; } const unsigned int groupIdLow = static_cast(groupId); const unsigned int groupIdHigh = static_cast(groupId >> 32); if (groupIdLow == 0 && groupIdHigh == 0) { window->SendMsg(nullptr, UM_TAB, reinterpret_cast(LookupMessage(MSI_ENCHANT)), 0, 0, 0); } else { auto group = this->m_groups.find(groupId); if (group != this->m_groups.end()) { window->SendMsg(nullptr, UM_TAB, reinterpret_cast(group->second.name.c_str()), 0, 0, 0); } } auto info = this->m_infos.find(reputeId); if (info != this->m_infos.end()) { info->second.updated = true; window->Invalidate(); } } // OFFSET: 0x0060E5B0 // FUNCTION: fn_04297 void CReputeMgr::SetPoint(std::uint64_t id, std::int64_t point) { auto found = this->m_infos.find(id); if (found != this->m_infos.end()) { found->second.point = point; } } // OFFSET: 0x0060E610 // FUNCTION: fn_04298 std::vector CReputeMgr::FindReputes(const std::string& keyword) const { std::vector reputes; for (auto entry = this->m_infos.begin(); entry != this->m_infos.end(); ++entry) { if (entry->second.name.find(keyword) == std::string::npos) { continue; } if (REPUTE_VISIBLE == entry->second.visibility || (REPUTE_VISIBLE_WITH_POINT == entry->second.visibility && 0 != entry->second.point)) { reputes.push_back(&entry->second); } } return reputes; } // OFFSET: 0x0060E830 // FUNCTION: fn_04299 void CReputeMgr::SetPointsReceived(bool received) { this->m_waitingForPoints = !received; if (received == true) { UIWindow* window = g_windowMgr.LookupWindow(WID_REPUTEWND); if (window) { window->SendMsg(nullptr, UM_REFRESH_REPUTE_FILTER, 0, 0, 0, 0); } } } // OFFSET: 0x0060D440 // FUNCTION: fn_04287 void CReputeMgr::InfoInserter::operator()(const std::pair& entry) const { ReputeInfo info; info.name = static_cast(FromUtf8(entry.second.name, g_textCodePage)); info.maxPointPositive = entry.second.maxPointPositive; info.maxPointNegative = entry.second.maxPointNegative; const std::string invisible = FromUtf8(entry.second.invisible, g_textCodePage); const char* text = invisible.c_str(); if (invisible.size() == 12 && text[0] == 'V' && text[1] == 'I' && text[2] == 'S' && text[3] == 'I' && text[4] == 'B' && text[5] == 'L' && text[6] == 'E' && text[7] == '_' && text[8] == 'T' && text[9] == 'R' && text[10] == 'U' && text[11] == 'E') { info.visibility = REPUTE_VISIBLE; } else if (invisible == "VISIBLE_FALSE") { info.visibility = REPUTE_HIDDEN; } else { info.visibility = REPUTE_VISIBLE_WITH_POINT; } (*this->dest)[entry.first] = info; } // OFFSET: 0x0060D060 // FUNCTION: fn_04286 void CReputeMgr::GroupInserter::operator()(const std::pair& entry) const { ReputeGroup group; group.name = static_cast(FromUtf8(entry.second.name, g_textCodePage)); group.reputes = std::vector(entry.second.reputes.begin(), entry.second.reputes.end()); (*this->dest)[static_cast(entry.first)] = group; }