Merge pull request #91 from SunTrustDev/bugfix/guild-mark

Fix default guild mark, color and format
This commit is contained in:
d1str4ught
2026-03-09 01:19:32 +01:00
committed by GitHub
5 changed files with 111 additions and 7 deletions

View File

@@ -40,11 +40,9 @@ void CGuildMarkImage::Create()
memset(m_apxImage, 0, sizeof(m_apxImage)); 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 stbi_write_tga(c_szFileName, WIDTH, HEIGHT, 4, m_apxImage) != 0;
return false;
return true;
} }
bool CGuildMarkImage::Build(const char * c_szFileName) bool CGuildMarkImage::Build(const char * c_szFileName)
@@ -59,7 +57,26 @@ bool CGuildMarkImage::Build(const char * c_szFileName)
return true; 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; int w, h, channels;
unsigned char* data = stbi_load(c_szFileName, &w, &h, &channels, 4); unsigned char* data = stbi_load(c_szFileName, &w, &h, &channels, 4);

View File

@@ -105,4 +105,6 @@ class CGuildMarkImage
Pixel m_apxImage[WIDTH * HEIGHT]; Pixel m_apxImage[WIDTH * HEIGHT];
}; };
bool LoadSingleMarkFromFile(const char* path, Pixel* outBuf);
#endif #endif

View File

@@ -70,6 +70,41 @@ bool CGuildMarkManager::LoadMarkIndex()
LoadMarkImages(); LoadMarkImages();
// Re-apply default mark to any empty slots (handles deleted/rebuilt atlas on restart)
Pixel defaultPixels[SGuildMark::SIZE];
if (__LoadDefaultMark(defaultPixels))
{
std::set<DWORD> setModifiedImages;
for (std::map<DWORD, DWORD>::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<DWORD>::iterator it = setModifiedImages.begin(); it != setModifiedImages.end(); ++it)
SaveMarkImage(*it);
}
fclose(fp); fclose(fp);
return true; return true;
} }
@@ -165,7 +200,10 @@ DWORD CGuildMarkManager::GetMarkID(DWORD guildID)
std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.find(guildID); std::map<DWORD, DWORD>::iterator it = m_mapGID_MarkID.find(guildID);
if (it == m_mapGID_MarkID.end()) 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 INVALID_MARK_ID;
}
return it->second; return it->second;
} }
@@ -203,8 +241,10 @@ void CGuildMarkManager::CopyMarkIdx(char * pcBuf) const
{ {
WORD * pwBuf = (WORD *) pcBuf; WORD * pwBuf = (WORD *) pcBuf;
sys_log(0, "CopyMarkIdx: sending %zu entries", m_mapGID_MarkID.size());
for (std::map<DWORD, DWORD>::const_iterator it = m_mapGID_MarkID.begin(); it != m_mapGID_MarkID.end(); ++it) for (std::map<DWORD, DWORD>::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->first; // guild id
*(pwBuf++) = it->second; // mark id *(pwBuf++) = it->second; // mark id
} }
@@ -242,7 +282,28 @@ DWORD CGuildMarkManager::SaveMark(DWORD guildID, BYTE * pbMarkImage)
return idMark; 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) DWORD CGuildMarkManager::AllocMark(DWORD guildID)
{ {
// Check if guild already has a mark // 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); 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 // Save the index so the mark slot is persisted
SaveMarkIndex(); SaveMarkIndex();

View File

@@ -65,6 +65,8 @@ class CGuildMarkManager : public singleton<CGuildMarkManager>
CGuildMarkImage * __GetImage(DWORD imgIdx); CGuildMarkImage * __GetImage(DWORD imgIdx);
CGuildMarkImage * __GetImagePtr(DWORD idMark); CGuildMarkImage * __GetImagePtr(DWORD idMark);
bool __LoadDefaultMark(Pixel* outBuf);
std::map<DWORD, CGuildMarkImage *> m_mapIdx_Image; // index = image index std::map<DWORD, CGuildMarkImage *> m_mapIdx_Image; // index = image index
std::map<DWORD, DWORD> m_mapGID_MarkID; // index = guild id std::map<DWORD, DWORD> m_mapGID_MarkID; // index = guild id

View File

@@ -17,6 +17,7 @@
#include "log.h" #include "log.h"
#include "questmanager.h" #include "questmanager.h"
#include "MarkManager.h" #include "MarkManager.h"
#include "MarkImage.h"
SGuildMember::SGuildMember(LPCHARACTER ch, BYTE grade, DWORD offer_exp) 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()) : 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); RequestAddMember(cp.master, GUILD_LEADER_GRADE);
// Allocate a mark slot for the new guild // 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<WORD>(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() void CGuild::Initialize()