diff --git a/src/PackLib/PackManager.cpp b/src/PackLib/PackManager.cpp index bb2b6a8..b8ecf29 100644 --- a/src/PackLib/PackManager.cpp +++ b/src/PackLib/PackManager.cpp @@ -48,29 +48,30 @@ bool CPackManager::GetFileWithPool(std::string_view path, TPackFile& result, CBu thread_local std::string buf; NormalizePath(path, buf); + // First try to load from pack if (m_load_from_pack) { auto it = m_entries.find(buf); if (it != m_entries.end()) { return it->second.first->GetFileWithPool(it->second.second, result, pPool); } } - else { - std::ifstream ifs(buf, std::ios::binary); - if (ifs.is_open()) { - ifs.seekg(0, std::ios::end); - size_t size = ifs.tellg(); - ifs.seekg(0, std::ios::beg); - if (pPool) { - result = pPool->Acquire(size); - result.resize(size); - } else { - result.resize(size); - } + // Fallback to disk (for files not in packs, like bgm folder) + std::ifstream ifs(buf, std::ios::binary); + if (ifs.is_open()) { + ifs.seekg(0, std::ios::end); + size_t size = ifs.tellg(); + ifs.seekg(0, std::ios::beg); - if (ifs.read((char*)result.data(), size)) { - return true; - } + if (pPool) { + result = pPool->Acquire(size); + result.resize(size); + } else { + result.resize(size); + } + + if (ifs.read((char*)result.data(), size)) { + return true; } } @@ -82,13 +83,16 @@ bool CPackManager::IsExist(std::string_view path) const thread_local std::string buf; NormalizePath(path, buf); + // First check in pack entries if (m_load_from_pack) { auto it = m_entries.find(buf); - return it != m_entries.end(); - } - else { - return std::filesystem::exists(buf); + if (it != m_entries.end()) { + return true; + } } + + // Fallback to disk (for files not in packs, like bgm folder) + return std::filesystem::exists(buf); } void CPackManager::NormalizePath(std::string_view in, std::string& out) const diff --git a/src/UserInterface/GuildMarkDownloader.cpp b/src/UserInterface/GuildMarkDownloader.cpp index c3d4138..c7e236d 100644 --- a/src/UserInterface/GuildMarkDownloader.cpp +++ b/src/UserInterface/GuildMarkDownloader.cpp @@ -1,7 +1,9 @@ #include "StdAfx.h" #include "GuildMarkDownloader.h" #include "PythonCharacterManager.h" +#include "PythonTextTail.h" #include "Packet.h" +#include "PackLib/PackManager.h" // MARK_BUG_FIX struct SMarkIndex @@ -89,6 +91,7 @@ void CGuildMarkDownloader::__Initialize() m_dwRandomKey=0; m_dwTodo=TODO_RECV_NONE; m_kVec_dwGuildID.clear(); + m_setUpdatedImageIndices.clear(); } bool CGuildMarkDownloader::__StateProcess() @@ -113,7 +116,29 @@ void CGuildMarkDownloader::__OfflineState_Set() void CGuildMarkDownloader::__CompleteState_Set() { m_eState = STATE_COMPLETE; - CPythonCharacterManager::instance().RefreshAllGuildMark(); + + // Reload all updated mark images before refreshing guild marks + // Must use file load mode since mark images are stored on disk, not in pack + CPackManager::instance().SetFileLoadMode(); + + for (std::set::iterator it = m_setUpdatedImageIndices.begin(); it != m_setUpdatedImageIndices.end(); ++it) + { + std::string imagePath; + if (CGuildMarkManager::Instance().GetMarkImageFilename(*it, imagePath)) + { + CResource* pResource = CResourceManager::Instance().GetResourcePointer(imagePath.c_str()); + if (pResource && pResource->IsType(CGraphicImage::Type())) + { + static_cast(pResource)->Reload(); + } + } + } + + CPackManager::instance().SetPackLoadMode(); + m_setUpdatedImageIndices.clear(); + + // Refresh all mark instances to use the updated textures + CPythonTextTail::Instance().RefreshAllGuildMark(); } void CGuildMarkDownloader::__LoginState_Set() @@ -335,7 +360,9 @@ bool CGuildMarkDownloader::__SendMarkCRCList() TPacketCGMarkCRCList kPacketMarkCRCList; if (!CGuildMarkManager::Instance().GetBlockCRCList(m_currentRequestingImageIndex, kPacketMarkCRCList.crclist)) + { __CompleteState_Set(); + } else { kPacketMarkCRCList.header = HEADER_CG_MARK_CRCLIST; @@ -387,18 +414,8 @@ bool CGuildMarkDownloader::__LoginState_RecvMarkBlock() // 마크 이미지 저장 CGuildMarkManager::Instance().SaveMarkImage(kPacket.imgIdx); - // 리소스 리로딩 (재접속을 안해도 본인것은 잘 보이게 함) - std::string imagePath; - - if (CGuildMarkManager::Instance().GetMarkImageFilename(kPacket.imgIdx, imagePath)) - { - CResource * pResource = CResourceManager::Instance().GetResourcePointer(imagePath.c_str()); - if (pResource->IsType(CGraphicImage::Type())) - { - CGraphicImage* pkGrpImg=static_cast(pResource); - pkGrpImg->Reload(); - } - } + // Track updated image index for deferred reload + m_setUpdatedImageIndices.insert(kPacket.imgIdx); } // 더 요청할 것이 있으면 요청하고 아니면 이미지를 저장하고 종료 diff --git a/src/UserInterface/GuildMarkDownloader.h b/src/UserInterface/GuildMarkDownloader.h index 4873edd..8bd6e5d 100644 --- a/src/UserInterface/GuildMarkDownloader.h +++ b/src/UserInterface/GuildMarkDownloader.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "EterLib/NetStream.h" #include "MarkManager.h" @@ -76,4 +78,6 @@ class CGuildMarkDownloader : public CNetworkStream, public CSingleton m_setUpdatedImageIndices; }; diff --git a/src/UserInterface/Packet.h b/src/UserInterface/Packet.h index 53bf1a9..f4109b4 100644 --- a/src/UserInterface/Packet.h +++ b/src/UserInterface/Packet.h @@ -240,6 +240,7 @@ enum HEADER_GC_MARK_BLOCK = 100, HEADER_GC_MARK_DIFF_DATA = 101, HEADER_GC_MARK_IDXLIST = 102, + HEADER_GC_MARK_UPDATE = 103, //HEADER_GC_SLOW_TIMER = 105, HEADER_GC_TIME = 106, @@ -412,6 +413,13 @@ typedef struct packet_mark_block // 뒤에 64 x 48 x 픽셀크기(4바이트) = 12288만큼 데이터 붙음 } TPacketGCMarkBlock; +typedef struct packet_mark_update +{ + uint8_t header; + uint32_t guildID; + uint16_t imgIdx; +} TPacketGCMarkUpdate; + typedef struct command_symbol_upload { uint8_t header; diff --git a/src/UserInterface/PythonNetworkStream.cpp b/src/UserInterface/PythonNetworkStream.cpp index a2eb607..32b44d7 100644 --- a/src/UserInterface/PythonNetworkStream.cpp +++ b/src/UserInterface/PythonNetworkStream.cpp @@ -121,6 +121,7 @@ class CMainPacketHeaderMap : public CNetworkPacketHeaderMap Set(HEADER_GC_MESSENGER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMessenger), DYNAMIC_SIZE_PACKET)); Set(HEADER_GC_GUILD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCGuild), DYNAMIC_SIZE_PACKET)); + Set(HEADER_GC_MARK_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMarkUpdate), STATIC_SIZE_PACKET)); Set(HEADER_GC_PARTY_INVITE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyInvite), STATIC_SIZE_PACKET)); Set(HEADER_GC_PARTY_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyAdd), STATIC_SIZE_PACKET)); diff --git a/src/UserInterface/PythonNetworkStream.h b/src/UserInterface/PythonNetworkStream.h index 6fc01f7..1e4132f 100644 --- a/src/UserInterface/PythonNetworkStream.h +++ b/src/UserInterface/PythonNetworkStream.h @@ -494,6 +494,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton> RecvMarkUpdate: guildID=%u, imgIdx=%u\n", packet.guildID, packet.imgIdx); + + // Rate limit mark downloads to prevent connection spam from multiple simultaneous guild uploads + // Allow at most one download request per 1 second from server-pushed updates + DWORD dwCurrentTime = ELTimer_GetMSec(); + if (dwCurrentTime < gs_dwMarkUpdateRequestTime) + return true; + + gs_dwMarkUpdateRequestTime = dwCurrentTime + 1000; // 1 second cooldown + + CGuildMarkDownloader& rkGuildMarkDownloader = CGuildMarkDownloader::Instance(); + rkGuildMarkDownloader.Connect(m_kMarkAuth.m_kNetAddr, m_kMarkAuth.m_dwHandle, m_kMarkAuth.m_dwRandomKey); + + return true; +} + // Guild ////////////////////////////////////////////////////////////////////////// diff --git a/src/UserInterface/PythonTextTail.cpp b/src/UserInterface/PythonTextTail.cpp index 8c1db1d..54a7f1b 100644 --- a/src/UserInterface/PythonTextTail.cpp +++ b/src/UserInterface/PythonTextTail.cpp @@ -9,6 +9,7 @@ #include "PythonGuild.h" #include "Locale.h" #include "MarkManager.h" +#include "PackLib/PackManager.h" #include // EPlaceDir and TextTailBiDi() template are defined in utf8.h @@ -916,6 +917,24 @@ void CPythonTextTail::DetachLevel(DWORD dwVID) } +void CPythonTextTail::RefreshAllGuildMark() +{ + CPackManager::instance().SetFileLoadMode(); + + for (TTextTailMap::iterator itor = m_CharacterTextTailMap.begin(); itor != m_CharacterTextTailMap.end(); ++itor) + { + TTextTail* pTextTail = itor->second; + + if (!pTextTail->pMarkInstance) + continue; + + // Re-load the mark instance to get the updated texture + pTextTail->pMarkInstance->Load(); + } + + CPackManager::instance().SetPackLoadMode(); +} + void CPythonTextTail::Initialize() { // DEFAULT_FONT @@ -926,7 +945,7 @@ void CPythonTextTail::Initialize() { TraceError("CPythonTextTail::Initialize - CANNOT_FIND_DEFAULT_FONT"); return; - } + } ms_pFont = pkDefaultFont; // END_OF_DEFAULT_FONT diff --git a/src/UserInterface/PythonTextTail.h b/src/UserInterface/PythonTextTail.h index e5850fa..63d3cac 100644 --- a/src/UserInterface/PythonTextTail.h +++ b/src/UserInterface/PythonTextTail.h @@ -74,6 +74,7 @@ class CPythonTextTail : public CSingleton void SetItemTextTailOwner(DWORD dwVID, const char * c_szName); void DeleteCharacterTextTail(DWORD VirtualID); void DeleteItemTextTail(DWORD VirtualID); + void RefreshAllGuildMark(); int Pick(int ixMouse, int iyMouse); void SelectItemName(DWORD dwVirtualID); diff --git a/src/UserInterface/UserInterface.cpp b/src/UserInterface/UserInterface.cpp index 9670490..63b0199 100644 --- a/src/UserInterface/UserInterface.cpp +++ b/src/UserInterface/UserInterface.cpp @@ -162,7 +162,7 @@ bool PackInitialize(const char * c_pszFolder) "sound", "sound_m", "sound2", - "bgm", + // "bgm", // BGM files are loaded directly from disk, not from pack "locale", "uiscript", "ETC",