diff --git a/Source/Client/Session.h b/Source/Client/Session.h index b96c4ea..04fed98 100644 --- a/Source/Client/Session.h +++ b/Source/Client/Session.h @@ -215,6 +215,8 @@ public: void ClearUnknown1740(int id); void ClearUnknown1738(int id); std::uint32_t SyncServerTime(std::uint32_t serverTime); + void LoadNavigationScripts(); + void LoadRobeAlpha(); std::pair* InsertPair(int key, int value); int SetPairValue(int value, int slot); int SetHotkeyEntry(char enabled, int id, int value, int slot); diff --git a/Source/Contents/ClientTiming.cpp b/Source/Contents/ClientTiming.cpp index c8adcce..a1e1d1b 100644 --- a/Source/Contents/ClientTiming.cpp +++ b/Source/Contents/ClientTiming.cpp @@ -1,10 +1,411 @@ +#include "Client/Application/ApplicationWindow.h" #include "Client/Session.h" +#include "Contents/Configuration/ServiceConfiguration.h" +#include "Contents/NavigationManager.h" +#include "Script/LuaScript.h" #include "UI/Window/UIWindow.h" #include "UI/Window/UIWindowMgr.h" +#include "Utility/Cipher/XorBytes.h" +#include "Utility/Text/FormatString.h" +#include +#include +#include +#include #include #include +// GLOBAL: gl_24705 +int g_serviceMode; + +namespace { + +template +class EncryptedName { +public: + explicit EncryptedName(const std::uint8_t (&source)[Length]) : m_encrypted(true) { + for (std::uint64_t index = 0; index < Length; ++index) { + this->m_text[index] = source[index]; + } + } + + ~EncryptedName() { + for (std::uint64_t index = 0; index < Length; ++index) { + this->m_text[index] = 0; + } + } + + const char* Text() { + if (this->m_encrypted) { + utility::XorBytes(this->m_text, Length, Key); + this->m_encrypted = false; + } + + return reinterpret_cast(this->m_text); + } + +private: + std::uint8_t m_text[Length]; + bool m_encrypted; +}; + +} + +// OFFSET: 0x00B8C870 +// FUNCTION: fn_19426 +CNavi_Object::CNavi_Object() + : id(-1), type(101), index(0), info(nullptr), cellX(0), cellY(0), unknown_0058(0), unknown_005C(0), unknown_0060(0), unknown_0064(0), unknown_0068(0), + unknown_006C(0), unknown_0070(0), unknown_0074(0), unknown_0078(0) { +} + +// OFFSET: 0x00B8C710 +// FUNCTION: fn_19425 +CNavi_Object::CNavi_Object(int type, int index, const char* name, const char* title, int cellX, int cellY, CNaviInfo* info) + : id(-1), type(type), index(index), unknown_0058(0), unknown_005C(0), unknown_0060(0), unknown_0064(0), unknown_0068(0), unknown_006C(0), + unknown_0070(0), unknown_0074(0), unknown_0078(0) { + if (name) { + this->name = name; + } + if (title) { + this->title = title; + } + this->cellX = cellX; + this->cellY = cellY; + this->info = info; +} + +// OFFSET: 0x00B8C2B0 +// FUNCTION: fn_19422 +CNavi_Link::CNavi_Link( + int type, int index, const char* name, const char* title, int cellX, int cellY, CNaviInfo* info, CNaviInfo* linkedInfo, int unknown80, int unknown84 +) + : unknown_0080(0), unknown_0084(0) { + this->type = type; + this->index = index; + if (name) { + this->name = name; + } + if (title) { + this->title = title; + } + this->cellX = cellX; + this->cellY = cellY; + this->info = info; + this->linkedInfo = linkedInfo; + this->unknown_0080 = unknown80; + this->unknown_0084 = unknown84; + this->depth = 0; +} + +// OFFSET: 0x00B8C5E0 +// FUNCTION: fn_19424 +CNaviInfo::CNaviInfo(int index, const char* name, const char* title, int cellX, int cellY, int type) { + this->index = index; + this->type = type; + this->name = name; + this->title = title; + this->cellX = cellX; + this->cellY = cellY; + this->visited = false; +} + +// OFFSET: 0x00B886A0 +// FUNCTION: fn_19372 +bool CNaviData::AddDestination(CNaviInfo* info) { + if (!info) { + return false; + } + this->destinations.push_back(info); + return true; +} + +// OFFSET: 0x00B886E0 +// FUNCTION: fn_19373 +bool CNaviData::AddObject(CNavi_Link* link) { + if (!link) { + return false; + } + this->objects.push_back(link); + return true; +} + +// OFFSET: 0x00B9E580 +// FUNCTION: fn_19629 +bool CNavigationManager::LoadScript(LuaScript* script) { + char message[260]; + std::memset(message, 0, sizeof(message)); + this->data.ClearAll(); + + int type; + int cellX = 0; + int cellY = 0; + for (int index = 1; index < 9999; ++index) { + const char* name = nullptr; + const char* title = nullptr; + if (!script->Call("queryNavi_MapInfo", "d>ssddd", index, &name, &title, &type, &cellX, &cellY)) { + std::sprintf(message, "Map 루아 읽기 실패 %d", index); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!name) { + break; + } + this->data.AddDestination(new CNaviInfo(static_cast(this->data.destinations.size()), name, title, cellX, cellY, type)); + } + + for (int index = 1; index < 99999; ++index) { + int objectType = 100; + const char* title = nullptr; + const char* name = nullptr; + const char* mapName = nullptr; + int objectX = 0; + int objectY = 0; + int objectIndex = 0; + int id; + if (!script->Call("queryNavi_NpcInfo", "d>sdddssdd", index, &mapName, &id, &objectType, &objectIndex, &name, &title, &objectX, &objectY)) { + std::sprintf(message, "Npc 루아 읽기 실패 %d", index); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (info) { + CNavi_Object* npc = new CNavi_Object(objectType, objectIndex, name, title, objectX, objectY, info); + npc->SetId(id); + info->AddNpc(npc); + } + } + + for (int index = 1; index < 99999; ++index) { + int objectType = 100; + const char* title = nullptr; + const char* name = nullptr; + const char* mapName = nullptr; + int objectX = 0; + int objectY = 0; + int objectIndex = 0; + int id; + if (!script->Call("queryNavi_MobInfo", "d>sdddssdd", index, &mapName, &id, &objectType, &objectIndex, &name, &title, &objectX, &objectY)) { + std::sprintf(message, "몬스터 루아 읽기 실패 %d", index); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (info) { + CNavi_Object* mob = new CNavi_Object(objectType, objectIndex, name, title, objectX, objectY, info); + mob->SetId(id); + info->AddMob(mob); + } + } + + for (int index = 1; index < 99999; ++index) { + int objectType = 100; + const char* linkedMap = nullptr; + const char* title = nullptr; + const char* name = nullptr; + const char* mapName = nullptr; + int linkedX = 0; + int linkedY = 0; + int objectX = 0; + int objectY = 0; + int objectIndex = 0; + int id; + if (!script->Call( + "queryNavi_LinkInfo", "d>sdddssddsdd", index, &mapName, &id, &objectType, &objectIndex, &name, &title, &objectX, &objectY, &linkedMap, &linkedX, + &linkedY + )) { + std::sprintf(message, "Link 루아 읽기 실패 %d", index); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + CNaviInfo* linked = this->FindObject(linkedMap); + if (info && linked) { + CNavi_Link* link = new CNavi_Link(objectType, objectIndex, name, title, objectX, objectY, info, linked, linkedX, linkedY); + link->SetId(id); + info->AddLink(link); + } + } + + int pick[11] = {}; + for (int index = 1; index < 9999; ++index) { + const char* mapName = nullptr; + int pickX = 0; + int pickY = 0; + if (!script->Call( + "queryNavi_PickNpc", "d>sddddddddddd", index, &mapName, &pickX, &pickY, &pick[0], &pick[1], &pick[2], &pick[3], &pick[4], &pick[5], &pick[6], + &pick[7], &pick[8] + )) { + StringFormat(message, sizeof(message), static_cast(-1), "Failed to read Link lua %d", index); + MessageBoxA(hWnd, message, "Error queryNavi_PickNpc ", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (info) { + CNavi_Object* npc = info->FindNpcAt(pickX, pickY); + if (npc) { + npc->unknown_0058 = pick[0]; + npc->unknown_005C = pick[1]; + npc->unknown_0060 = pick[2]; + npc->unknown_0064 = pick[3]; + npc->unknown_0068 = pick[4]; + npc->unknown_006C = pick[5]; + npc->unknown_0070 = pick[6]; + npc->unknown_0074 = pick[7]; + npc->unknown_0078 = pick[8]; + } + } + } + + for (int map = 1; map < 999999; map += 3) { + const char* mapName = nullptr; + int count = 0; + if (!script->Call("queryNavi_Distance_Map", "d>sd", map, &mapName, &count)) { + std::sprintf(message, "워프 길 정보 읽기 실패 %d", map); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (!info) { + continue; + } + for (int entry = 1; entry < count + 1; ++entry) { + int linkId = -1; + if (!script->Call("queryNavi_Distance_Link", "dd>d", map, entry, &linkId)) { + continue; + } + CNavi_Link* link = info->FindLink(linkId, true); + if (!link) { + continue; + } + for (int pass = 1;; ++pass) { + const char* kind = nullptr; + int targetId = -1; + int cost = 0; + if (!script->Call("queryNavi_Distance_Pass", "ddd>sdd", map, entry, pass, &kind, &targetId, &cost)) { + continue; + } + if (std::strcmp("NULL", kind) == 0) { + break; + } + if (std::strcmp(kind, "P") == 0) { + CNavi_Link* target = info->FindLink(targetId, true); + if (target) { + link->AddLink(NaviLink{target, cost}); + } + } else if (std::strcmp(kind, "E") == 0) { + CNavi_Link* target = link->GetLinkedInfo()->FindLink(targetId, true); + if (target) { + link->AddLinkedLink(NaviLink{target, cost}); + } + } + } + } + } + + for (int map = 1; map < 999999; map += 3) { + const char* mapName = nullptr; + int count = 0; + if (!script->Call("queryNavi_NpcDistance_Map", "d>sd", map, &mapName, &count)) { + std::sprintf(message, "Npc 워프 길 정보 읽기 실패 %d", map); + MessageBoxA(hWnd, message, "Error", 0); + break; + } + if (!mapName) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (!info) { + continue; + } + for (int entry = 1; entry < count + 1; ++entry) { + int npcId = -1; + if (!script->Call("queryNavi_NpcDistance_Link", "dd>d", map, entry, &npcId)) { + continue; + } + CNavi_Object* npc = info->FindNpc(npcId, true); + if (!npc) { + continue; + } + for (int pass = 1;; ++pass) { + const char* targetMap = nullptr; + int targetId = -1; + int cost = 0; + if (!script->Call("queryNavi_NpcDistance_Pass", "ddd>sdd", map, entry, pass, &targetMap, &targetId, &cost)) { + continue; + } + if (targetId == 0 && cost == 0) { + break; + } + CNaviInfo* targetInfo = this->FindObject(targetMap); + CNavi_Link* target = targetInfo ? targetInfo->FindLink(targetId, true) : this->data.FindLink(targetId, true); + if (target) { + npc->AddLink(NaviLink{target, cost}); + } + } + } + } + + for (int index = 1; index < 200; ++index) { + const char* name = nullptr; + const char* mapName = nullptr; + int id = 0; + int objectIndex = 0; + int linkedX = 0; + int linkedY = 0; + if (!script->Call("queryNavi_Scroll", "d>sddsdd", index, &name, &id, &objectIndex, &mapName, &linkedX, &linkedY)) { + char text[260]; + std::memset(text, 0, sizeof(text)); + std::sprintf(text, "Scroll 정보 읽기 실패 %d", index); + MessageBoxA(hWnd, text, "Error", 0); + break; + } + if (std::strcmp("NULL", name) == 0 && std::strcmp("NULL", mapName) == 0) { + break; + } + CNaviInfo* info = this->FindObject(mapName); + if (!info) { + continue; + } + CNavi_Link* link = new CNavi_Link(400, objectIndex, name, nullptr, 0, 0, nullptr, info, linkedX, linkedY); + link->SetId(id); + this->data.AddObject(link); + link->ClearLinkedLinks(); + for (int pass = 1;; ++pass) { + int targetId = -1; + int cost = 0; + if (!script->Call("queryNavi_Scroll_Pass", "dd>dd", index, pass, &targetId, &cost)) { + continue; + } + if (targetId == 0 && cost == 0) { + break; + } + CNavi_Link* target = info->FindLink(targetId, true); + if (target) { + link->AddLinkedLink(NaviLink{target, cost}); + } + } + } + + this->unknown_1244 = this->FindObject("prontera"); + this->data.ResetLinkDepths(); + return true; +} + // OFFSET: 0x00DE0A50 // FUNCTION: fn_23466 std::uint32_t CSession::GetServerTime() { @@ -124,6 +525,94 @@ bool CSession::AddShopName(std::string name, int shopId) { return false; } +// OFFSET: 0x00E00910 +// FUNCTION: fn_23644 +void CSession::LoadNavigationScripts() { + const char* npcDistance; + const char* scroll; + const char* pickNpc; + + if (g_serviceMode == 0) { + if (!this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_f_krpri", true, false)) { + return; + } + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Map_krpri", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Npc_krpri", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Mob_krpri", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Link_krpri", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_LinkDistance_krpri", true, false); + npcDistance = "Lua Files\\Navigation\\Navi_NpcDistance_krpri"; + scroll = "Lua Files\\Navigation\\Navi_Scroll_krpri"; + pickNpc = "Lua Files\\Navigation\\navi_picknpc_krpri"; + } else if (g_serviceMode == 1) { + if (!this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_f_krSak", true, false)) { + return; + } + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Map_krSak", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Npc_krSak", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Mob_krSak", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Link_krSak", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_LinkDistance_krSak", true, false); + npcDistance = "Lua Files\\Navigation\\Navi_NpcDistance_krSak"; + scroll = "Lua Files\\Navigation\\Navi_Scroll_krSak"; + pickNpc = "Lua Files\\Navigation\\navi_picknpc_krSak"; + } else { + if (!this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_f_krLoc", true, false)) { + return; + } + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Map_krLoc", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Npc_krLoc", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Mob_krLoc", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_Link_krLoc", true, false); + this->m_hotkeyScript->Load("Lua Files\\Navigation\\Navi_LinkDistance_krLoc", true, false); + npcDistance = "Lua Files\\Navigation\\Navi_npcDistance_krLoc"; + scroll = "Lua Files\\Navigation\\Navi_Scroll_krLoc"; + pickNpc = "Lua Files\\Navigation\\navi_picknpc_krLoc"; + } + + this->m_hotkeyScript->Load(npcDistance, true, false); + this->m_hotkeyScript->Load(scroll, true, false); + this->m_hotkeyScript->Load(pickNpc, true, false); + g_navigationManager.LoadScript(this->m_hotkeyScript); +} + +// OFFSET: 0x00E00B30 +// FUNCTION: fn_23645 +void CSession::LoadRobeAlpha() { + for (int index = 1; index < 1000; ++index) { + int robeId = 0; + int from = 0; + int to = 0; + int period = 0; + LuaScript* script = this->m_hotkeyScript; + + const std::uint8_t signatureSource[] = {0x15, 0x45, 0xC9, 0x0F, 0x21, 0x81, 0x73}; + thread_local EncryptedName signature(signatureSource); + const std::uint8_t functionSource[] = {0x36, 0x32, 0xDC, 0x11, 0x9E, 0x27, 0x6B, 0xB4, 0x29, 0x34, 0xC9, 0x02, 0x95, + 0x36, 0x77, 0xA1, 0x2E, 0x33, 0xDC, 0x0E, 0x8E, 0x3D, 0x7F, 0xBA, 0x47}; + thread_local EncryptedName function(functionSource); + + if (!script->Call(function.Text(), signature.Text(), index, &robeId, &from, &to, &period)) { + char message[260]; + std::memset(message, 0, sizeof(message)); + const std::uint8_t formatSource[] = {0xAA, 0x72, 0x76, 0xA1, 0x8C, 0x37, 0x93, 0x0A, 0xB5, 0x74, 0x63, 0xB2, 0x87, 0x26, + 0x8F, 0x1F, 0xB2, 0x73, 0x76, 0xBE, 0x9C, 0x2D, 0x87, 0x04, 0xFB, 0x28, 0x3C, 0xF3, + 0xD0, 0x27, 0xC1, 0xAB, 0x0B, 0xB6, 0xF1, 0xF3, 0x48, 0x84, 0x27, 0xBB, 0xDB}; + thread_local EncryptedName format(formatSource); + std::sprintf(message, format.Text(), index); + const std::uint8_t titleSource[] = {0xC8, 0x0D, 0x8B, 0xC0, 0xA5, 0x91}; + thread_local EncryptedName title(titleSource); + MessageBoxA(hWnd, message, title.Text(), 0); + return; + } + + if (!robeId) { + return; + } + this->m_robeAlpha.insert({robeId, RobeAlpha{from, to, period}}); + } +} + // OFFSET: 0x00E010B0 // FUNCTION: fn_23646 int CSession::SetUnknown8134(int value) { diff --git a/Source/Contents/Configuration/ServiceConfiguration.h b/Source/Contents/Configuration/ServiceConfiguration.h index 1f6cf4d..a786e29 100644 --- a/Source/Contents/Configuration/ServiceConfiguration.h +++ b/Source/Contents/Configuration/ServiceConfiguration.h @@ -3,5 +3,6 @@ extern signed char g_language; extern int g_serviceType; +extern int g_serviceMode; #endif diff --git a/Source/Contents/NavigationManager.h b/Source/Contents/NavigationManager.h index 111511e..e356344 100644 --- a/Source/Contents/NavigationManager.h +++ b/Source/Contents/NavigationManager.h @@ -16,6 +16,7 @@ class CNavi_Object; class CSprRes; class CTexture; class GroundGeometry; +class LuaScript; struct NaviCell { /* 0000 */ int x; @@ -78,6 +79,8 @@ public: /* 0074 */ int unknown_0074; /* 0078 */ int unknown_0078; + CNavi_Object(); + CNavi_Object(int type, int index, const char* name, const char* title, int cellX, int cellY, CNaviInfo* info); virtual ~CNavi_Object(); virtual int GetId() const; virtual int GetType() const; @@ -119,6 +122,7 @@ public: std::vector::iterator LinkedEnd(); void AddLinkedLink(const NaviLink& link); void ClearLinkedLinks(); + CNavi_Link(int type, int index, const char* name, const char* title, int cellX, int cellY, CNaviInfo* info, CNaviInfo* linkedInfo, int unknown80, int unknown84); ~CNavi_Link() override; int GetId() const override; @@ -153,6 +157,7 @@ struct NaviObjectRecord { class CNaviInfo { public: + CNaviInfo(int index, const char* name, const char* title, int cellX, int cellY, int type); ~CNaviInfo(); bool HasName(const char* name) const; @@ -217,6 +222,8 @@ public: NaviCell* GetCell(NaviCell* out); void Clear(); void ClearAll(); + bool AddDestination(CNaviInfo* info); + bool AddObject(CNavi_Link* link); CNavi_Link* FindLink(unsigned int key, bool byId); int FindRoute(std::vector* route, bool direct, bool allowGates, bool includeObjects, bool allowWarps, int side); void ResetLinkDepths(); @@ -253,6 +260,7 @@ public: std::string DestinationTitle(); float FitToSquare(int* offsetX, int* offsetY, int width, int height, float size) const; void LoadSettings(); + bool LoadScript(LuaScript* script); bool BuildRoute(int startX, int startY, int destX, int destY, bool collectCells); bool SavedTargetText(char* out, int size); int RequestRoute(int cellX, int cellY);