From c3cd3f848384c982b925fd234a615525e2139f85 Mon Sep 17 00:00:00 2001 From: Simone Romano <19979417+SunTrustDev@users.noreply.github.com> Date: Wed, 4 Mar 2026 20:12:40 +0100 Subject: [PATCH] Fix default guild mark, color and format --- src/game/MarkImage.cpp | 27 ++++++++++++--- src/game/MarkImage.h | 2 ++ src/game/MarkManager.cpp | 75 +++++++++++++++++++++++++++++++++++++++- src/game/MarkManager.h | 2 ++ src/game/guild.cpp | 12 ++++++- 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/src/game/MarkImage.cpp b/src/game/MarkImage.cpp index ce983a2..bb4cfc6 100644 --- a/src/game/MarkImage.cpp +++ b/src/game/MarkImage.cpp @@ -40,11 +40,9 @@ void CGuildMarkImage::Create() memset(m_apxImage, 0, sizeof(m_apxImage)); } -bool CGuildMarkImage::Save(const char* c_szFileName) +bool CGuildMarkImage::Save(const char* c_szFileName) { - if (stbi_write_tga(c_szFileName, WIDTH, HEIGHT, 4, m_apxImage) == 0) - return false; - return true; + return stbi_write_tga(c_szFileName, WIDTH, HEIGHT, 4, m_apxImage) != 0; } bool CGuildMarkImage::Build(const char * c_szFileName) @@ -59,7 +57,26 @@ bool CGuildMarkImage::Build(const char * c_szFileName) return true; } -bool CGuildMarkImage::Load(const char * c_szFileName) +bool LoadSingleMarkFromFile(const char* path, Pixel* outBuf) +{ + int w, h, channels; + unsigned char* data = stbi_load(path, &w, &h, &channels, 4); + if (!data) + return false; + + if (w != SGuildMark::WIDTH || h != SGuildMark::HEIGHT) + { + sys_err("LoadSingleMarkFromFile: '%s' is %dx%d, expected %dx%d", path, w, h, SGuildMark::WIDTH, SGuildMark::HEIGHT); + stbi_image_free(data); + return false; + } + + memcpy(outBuf, data, SGuildMark::SIZE * sizeof(Pixel)); + stbi_image_free(data); + return true; +} + +bool CGuildMarkImage::Load(const char * c_szFileName) { int w, h, channels; unsigned char* data = stbi_load(c_szFileName, &w, &h, &channels, 4); diff --git a/src/game/MarkImage.h b/src/game/MarkImage.h index 57f1172..00b6353 100644 --- a/src/game/MarkImage.h +++ b/src/game/MarkImage.h @@ -105,4 +105,6 @@ class CGuildMarkImage Pixel m_apxImage[WIDTH * HEIGHT]; }; +bool LoadSingleMarkFromFile(const char* path, Pixel* outBuf); + #endif diff --git a/src/game/MarkManager.cpp b/src/game/MarkManager.cpp index 79c5161..f6691f3 100644 --- a/src/game/MarkManager.cpp +++ b/src/game/MarkManager.cpp @@ -70,6 +70,41 @@ bool CGuildMarkManager::LoadMarkIndex() LoadMarkImages(); + // Re-apply default mark to any empty slots (handles deleted/rebuilt atlas on restart) + Pixel defaultPixels[SGuildMark::SIZE]; + if (__LoadDefaultMark(defaultPixels)) + { + std::set setModifiedImages; + + for (std::map::iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it) + { + DWORD mID = it->second; + DWORD imgIdx = mID / CGuildMarkImage::MARK_TOTAL_COUNT; + DWORD posMark = mID % CGuildMarkImage::MARK_TOTAL_COUNT; + + CGuildMarkImage* pkImage = __GetImage(imgIdx); + if (!pkImage) + continue; + + DWORD colMark = posMark % CGuildMarkImage::MARK_COL_COUNT; + DWORD rowMark = posMark / CGuildMarkImage::MARK_COL_COUNT; + + SGuildMark kMark; + pkImage->GetData(colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT, + SGuildMark::WIDTH, SGuildMark::HEIGHT, kMark.m_apxBuf); + + if (kMark.IsEmpty()) + { + sys_log(0, "LoadMarkIndex: guild %u slot %u empty, re-applying default mark", it->first, mID); + pkImage->SaveMark(posMark, (BYTE*)defaultPixels); + setModifiedImages.insert(imgIdx); + } + } + + for (std::set::iterator it = setModifiedImages.begin(); it != setModifiedImages.end(); ++it) + SaveMarkImage(*it); + } + fclose(fp); return true; } @@ -165,7 +200,10 @@ DWORD CGuildMarkManager::GetMarkID(DWORD guildID) std::map::iterator it = m_mapGID_MarkID.find(guildID); if (it == m_mapGID_MarkID.end()) + { + sys_log(0, "Server GetMarkID: guildID=%u NOT FOUND (map size=%zu)", guildID, m_mapGID_MarkID.size()); return INVALID_MARK_ID; + } return it->second; } @@ -203,8 +241,10 @@ void CGuildMarkManager::CopyMarkIdx(char * pcBuf) const { WORD * pwBuf = (WORD *) pcBuf; + sys_log(0, "CopyMarkIdx: sending %zu entries", m_mapGID_MarkID.size()); for (std::map::const_iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it) { + sys_log(0, "CopyMarkIdx: guildID=%u -> markID=%u", it->first, it->second); *(pwBuf++) = it->first; // guild id *(pwBuf++) = it->second; // mark id } @@ -242,7 +282,28 @@ DWORD CGuildMarkManager::SaveMark(DWORD guildID, BYTE * pbMarkImage) return idMark; } -// SERVER - Allocate a mark slot with default (empty) image for a new guild +bool CGuildMarkManager::__LoadDefaultMark(Pixel* outBuf) +{ + static const char* candidates[] = { + "mark/default_mark.tga", + "mark/default_mark.png", + "mark/default_mark.jpg", + }; + + for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); ++i) + { + if (LoadSingleMarkFromFile(candidates[i], outBuf)) + { + sys_log(0, "AllocMark: loaded default mark from '%s'", candidates[i]); + return true; + } + } + + sys_log(0, "AllocMark: no default mark found (tried .tga/.png/.jpg); new guild slot will be transparent"); + return false; +} + +// SERVER - Allocate a mark slot for a new guild and fill it with the default mark. DWORD CGuildMarkManager::AllocMark(DWORD guildID) { // Check if guild already has a mark @@ -261,6 +322,18 @@ DWORD CGuildMarkManager::AllocMark(DWORD guildID) sys_log(0, "AllocMark: allocated mark id %u for guild %u", idMark, guildID); + DWORD imgIdx = idMark / CGuildMarkImage::MARK_TOTAL_COUNT; + CGuildMarkImage* pkImage = __GetImage(imgIdx); + if (pkImage) + { + Pixel defaultPixels[SGuildMark::SIZE]; + if (__LoadDefaultMark(defaultPixels)) + { + pkImage->SaveMark(idMark % CGuildMarkImage::MARK_TOTAL_COUNT, (BYTE*)defaultPixels); + SaveMarkImage(imgIdx); + } + } + // Save the index so the mark slot is persisted SaveMarkIndex(); diff --git a/src/game/MarkManager.h b/src/game/MarkManager.h index f8879e9..b3c5e73 100644 --- a/src/game/MarkManager.h +++ b/src/game/MarkManager.h @@ -65,6 +65,8 @@ class CGuildMarkManager : public singleton CGuildMarkImage * __GetImage(DWORD imgIdx); CGuildMarkImage * __GetImagePtr(DWORD idMark); + bool __LoadDefaultMark(Pixel* outBuf); + std::map m_mapIdx_Image; // index = image index std::map m_mapGID_MarkID; // index = guild id diff --git a/src/game/guild.cpp b/src/game/guild.cpp index f17946b..b8c7a4d 100644 --- a/src/game/guild.cpp +++ b/src/game/guild.cpp @@ -17,6 +17,7 @@ #include "log.h" #include "questmanager.h" #include "MarkManager.h" +#include "MarkImage.h" SGuildMember::SGuildMember(LPCHARACTER ch, BYTE grade, DWORD offer_exp) : pid(ch->GetPlayerID()), grade(grade), is_general(0), job(ch->GetJob()), level(ch->GetLevel()), offer_exp(offer_exp), name(ch->GetName()) @@ -116,7 +117,16 @@ CGuild::CGuild(TGuildCreateParameter & cp) RequestAddMember(cp.master, GUILD_LEADER_GRADE); // Allocate a mark slot for the new guild - CGuildMarkManager::instance().AllocMark(GetID()); + DWORD markID = CGuildMarkManager::instance().AllocMark(GetID()); + sys_log(0, "Guild created: guildID=%u allocated markID=%u", GetID(), markID); + + if (markID != CGuildMarkManager::INVALID_MARK_ID) + { + WORD imgIdx = static_cast(markID / CGuildMarkImage::MARK_TOTAL_COUNT); + extern void BroadcastGuildMarkUpdate(DWORD dwGuildID, WORD wImgIdx); + BroadcastGuildMarkUpdate(GetID(), imgIdx); + sys_log(0, "Broadcast mark update for new guild %u imgIdx %u", GetID(), imgIdx); + } } void CGuild::Initialize()