Merge pull request #85 from rtw1x1/main

fix: Mark refresh and BGM failure
This commit is contained in:
rtw1x1
2026-01-21 18:34:09 +00:00
committed by GitHub
10 changed files with 118 additions and 34 deletions

View File

@@ -48,29 +48,30 @@ bool CPackManager::GetFileWithPool(std::string_view path, TPackFile& result, CBu
thread_local std::string buf; thread_local std::string buf;
NormalizePath(path, buf); NormalizePath(path, buf);
// First try to load from pack
if (m_load_from_pack) { if (m_load_from_pack) {
auto it = m_entries.find(buf); auto it = m_entries.find(buf);
if (it != m_entries.end()) { if (it != m_entries.end()) {
return it->second.first->GetFileWithPool(it->second.second, result, pPool); 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) { // Fallback to disk (for files not in packs, like bgm folder)
result = pPool->Acquire(size); std::ifstream ifs(buf, std::ios::binary);
result.resize(size); if (ifs.is_open()) {
} else { ifs.seekg(0, std::ios::end);
result.resize(size); size_t size = ifs.tellg();
} ifs.seekg(0, std::ios::beg);
if (ifs.read((char*)result.data(), size)) { if (pPool) {
return true; 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; thread_local std::string buf;
NormalizePath(path, buf); NormalizePath(path, buf);
// First check in pack entries
if (m_load_from_pack) { if (m_load_from_pack) {
auto it = m_entries.find(buf); auto it = m_entries.find(buf);
return it != m_entries.end(); if (it != m_entries.end()) {
} return true;
else { }
return std::filesystem::exists(buf);
} }
// 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 void CPackManager::NormalizePath(std::string_view in, std::string& out) const

View File

@@ -1,7 +1,9 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "GuildMarkDownloader.h" #include "GuildMarkDownloader.h"
#include "PythonCharacterManager.h" #include "PythonCharacterManager.h"
#include "PythonTextTail.h"
#include "Packet.h" #include "Packet.h"
#include "PackLib/PackManager.h"
// MARK_BUG_FIX // MARK_BUG_FIX
struct SMarkIndex struct SMarkIndex
@@ -89,6 +91,7 @@ void CGuildMarkDownloader::__Initialize()
m_dwRandomKey=0; m_dwRandomKey=0;
m_dwTodo=TODO_RECV_NONE; m_dwTodo=TODO_RECV_NONE;
m_kVec_dwGuildID.clear(); m_kVec_dwGuildID.clear();
m_setUpdatedImageIndices.clear();
} }
bool CGuildMarkDownloader::__StateProcess() bool CGuildMarkDownloader::__StateProcess()
@@ -113,7 +116,29 @@ void CGuildMarkDownloader::__OfflineState_Set()
void CGuildMarkDownloader::__CompleteState_Set() void CGuildMarkDownloader::__CompleteState_Set()
{ {
m_eState = STATE_COMPLETE; 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<DWORD>::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<CGraphicImage*>(pResource)->Reload();
}
}
}
CPackManager::instance().SetPackLoadMode();
m_setUpdatedImageIndices.clear();
// Refresh all mark instances to use the updated textures
CPythonTextTail::Instance().RefreshAllGuildMark();
} }
void CGuildMarkDownloader::__LoginState_Set() void CGuildMarkDownloader::__LoginState_Set()
@@ -335,7 +360,9 @@ bool CGuildMarkDownloader::__SendMarkCRCList()
TPacketCGMarkCRCList kPacketMarkCRCList; TPacketCGMarkCRCList kPacketMarkCRCList;
if (!CGuildMarkManager::Instance().GetBlockCRCList(m_currentRequestingImageIndex, kPacketMarkCRCList.crclist)) if (!CGuildMarkManager::Instance().GetBlockCRCList(m_currentRequestingImageIndex, kPacketMarkCRCList.crclist))
{
__CompleteState_Set(); __CompleteState_Set();
}
else else
{ {
kPacketMarkCRCList.header = HEADER_CG_MARK_CRCLIST; kPacketMarkCRCList.header = HEADER_CG_MARK_CRCLIST;
@@ -387,18 +414,8 @@ bool CGuildMarkDownloader::__LoginState_RecvMarkBlock()
// 마크 이미지 저장 // 마크 이미지 저장
CGuildMarkManager::Instance().SaveMarkImage(kPacket.imgIdx); CGuildMarkManager::Instance().SaveMarkImage(kPacket.imgIdx);
// 리소스 리로딩 (재접속을 안해도 본인것은 잘 보이게 함) // Track updated image index for deferred reload
std::string imagePath; m_setUpdatedImageIndices.insert(kPacket.imgIdx);
if (CGuildMarkManager::Instance().GetMarkImageFilename(kPacket.imgIdx, imagePath))
{
CResource * pResource = CResourceManager::Instance().GetResourcePointer(imagePath.c_str());
if (pResource->IsType(CGraphicImage::Type()))
{
CGraphicImage* pkGrpImg=static_cast<CGraphicImage*>(pResource);
pkGrpImg->Reload();
}
}
} }
// 더 요청할 것이 있으면 요청하고 아니면 이미지를 저장하고 종료 // 더 요청할 것이 있으면 요청하고 아니면 이미지를 저장하고 종료

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <set>
#include "EterLib/NetStream.h" #include "EterLib/NetStream.h"
#include "MarkManager.h" #include "MarkManager.h"
@@ -76,4 +78,6 @@ class CGuildMarkDownloader : public CNetworkStream, public CSingleton<CGuildMark
DWORD m_dwBlockIndex; DWORD m_dwBlockIndex;
DWORD m_dwBlockDataSize; DWORD m_dwBlockDataSize;
DWORD m_dwBlockDataPos; DWORD m_dwBlockDataPos;
std::set<DWORD> m_setUpdatedImageIndices;
}; };

View File

@@ -240,6 +240,7 @@ enum
HEADER_GC_MARK_BLOCK = 100, HEADER_GC_MARK_BLOCK = 100,
HEADER_GC_MARK_DIFF_DATA = 101, HEADER_GC_MARK_DIFF_DATA = 101,
HEADER_GC_MARK_IDXLIST = 102, HEADER_GC_MARK_IDXLIST = 102,
HEADER_GC_MARK_UPDATE = 103,
//HEADER_GC_SLOW_TIMER = 105, //HEADER_GC_SLOW_TIMER = 105,
HEADER_GC_TIME = 106, HEADER_GC_TIME = 106,
@@ -412,6 +413,13 @@ typedef struct packet_mark_block
// 뒤에 64 x 48 x 픽셀크기(4바이트) = 12288만큼 데이터 붙음 // 뒤에 64 x 48 x 픽셀크기(4바이트) = 12288만큼 데이터 붙음
} TPacketGCMarkBlock; } TPacketGCMarkBlock;
typedef struct packet_mark_update
{
uint8_t header;
uint32_t guildID;
uint16_t imgIdx;
} TPacketGCMarkUpdate;
typedef struct command_symbol_upload typedef struct command_symbol_upload
{ {
uint8_t header; uint8_t header;

View File

@@ -121,6 +121,7 @@ class CMainPacketHeaderMap : public CNetworkPacketHeaderMap
Set(HEADER_GC_MESSENGER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMessenger), DYNAMIC_SIZE_PACKET)); 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_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_INVITE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyInvite), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyAdd), STATIC_SIZE_PACKET)); Set(HEADER_GC_PARTY_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyAdd), STATIC_SIZE_PACKET));

View File

@@ -494,6 +494,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
// Guild // Guild
bool RecvGuild(); bool RecvGuild();
bool RecvMarkUpdate();
// Party // Party
bool RecvPartyInvite(); bool RecvPartyInvite();

View File

@@ -1,6 +1,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PythonNetworkStream.h" #include "PythonNetworkStream.h"
#include "Packet.h" #include "Packet.h"
#include "GuildMarkDownloader.h"
#include "PythonGuild.h" #include "PythonGuild.h"
#include "PythonCharacterManager.h" #include "PythonCharacterManager.h"
@@ -440,6 +441,10 @@ void CPythonNetworkStream::GamePhase()
ret = RecvGuild(); ret = RecvGuild();
break; break;
case HEADER_GC_MARK_UPDATE:
ret = RecvMarkUpdate();
break;
case HEADER_GC_PARTY_INVITE: case HEADER_GC_PARTY_INVITE:
ret = RecvPartyInvite(); ret = RecvPartyInvite();
break; break;
@@ -3930,6 +3935,30 @@ bool CPythonNetworkStream::RecvGuild()
return true; return true;
} }
static DWORD gs_dwMarkUpdateRequestTime = 0;
bool CPythonNetworkStream::RecvMarkUpdate()
{
TPacketGCMarkUpdate packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracef(" >> 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 // Guild
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@@ -9,6 +9,7 @@
#include "PythonGuild.h" #include "PythonGuild.h"
#include "Locale.h" #include "Locale.h"
#include "MarkManager.h" #include "MarkManager.h"
#include "PackLib/PackManager.h"
#include <utf8.h> #include <utf8.h>
// EPlaceDir and TextTailBiDi() template are defined in utf8.h // 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() void CPythonTextTail::Initialize()
{ {
// DEFAULT_FONT // DEFAULT_FONT
@@ -926,7 +945,7 @@ void CPythonTextTail::Initialize()
{ {
TraceError("CPythonTextTail::Initialize - CANNOT_FIND_DEFAULT_FONT"); TraceError("CPythonTextTail::Initialize - CANNOT_FIND_DEFAULT_FONT");
return; return;
} }
ms_pFont = pkDefaultFont; ms_pFont = pkDefaultFont;
// END_OF_DEFAULT_FONT // END_OF_DEFAULT_FONT

View File

@@ -74,6 +74,7 @@ class CPythonTextTail : public CSingleton<CPythonTextTail>
void SetItemTextTailOwner(DWORD dwVID, const char * c_szName); void SetItemTextTailOwner(DWORD dwVID, const char * c_szName);
void DeleteCharacterTextTail(DWORD VirtualID); void DeleteCharacterTextTail(DWORD VirtualID);
void DeleteItemTextTail(DWORD VirtualID); void DeleteItemTextTail(DWORD VirtualID);
void RefreshAllGuildMark();
int Pick(int ixMouse, int iyMouse); int Pick(int ixMouse, int iyMouse);
void SelectItemName(DWORD dwVirtualID); void SelectItemName(DWORD dwVirtualID);

View File

@@ -162,7 +162,7 @@ bool PackInitialize(const char * c_pszFolder)
"sound", "sound",
"sound_m", "sound_m",
"sound2", "sound2",
"bgm", // "bgm", // BGM files are loaded directly from disk, not from pack
"locale", "locale",
"uiscript", "uiscript",
"ETC", "ETC",