Implementation Notes: Extended Reload System on martysama 5.8
This document outlines the necessary adaptations and fixes required to successfully implement the "More extended /reload commands" system on the martysama 5.8 p23 CLEAN server source. While the original guide provides the core implementation, it is incomplete for this specific source base, leading to critical linker errors during compilation.
The following changes are mandatory to resolve these errors and ensure the system is fully functional.
1. Missing Function: DBManager::LoadDBString
The extended do_reload command introduces a new sub-command, /reload s, which calls DBManager::instance().LoadDBString(). However, the guide omits the declaration and definition for this function, resulting in a linker error.
Reason for Fix:
The compiler cannot find the definition for LoadDBString because it was never created. We need to add its declaration to the DBManager class header and its implementation to the source file.
Solution:
File: db.h
Add the function declaration inside the DBManager class, under the public: section.
class DBManager : public singleton<DBManager>
{
public:
// ... other public functions ...
void SendLoginPing(const char * c_pszLogin);
// [FIX] Add the declaration for the missing function
void LoadDBString();
void InsertLoginData(CLoginData * pkLD);
// ... rest of the class ...
};
File: db.cpp
Add the function's definition at the end of the file. This implementation reloads the string table from the database and sends each entry as a server notice.
// [FIX] Add the definition for the missing function
void DBManager::LoadDBString()
{
char szQuery[QUERY_MAX_LEN];
snprintf(szQuery, sizeof(szQuery), "SELECT `string` FROM string");
std::unique_ptr<SQLMsg> pMsg(DirectQuery(szQuery));
if (pMsg->Get()->uiNumRows > 0)
{
MYSQL_ROW row;
while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult)))
{
if (row[0])
{
if (strcmp(row[0],""))
{
sys_log(0, "NOTICE: %s", row[0]);
SendNotice(row[0]);
}
}
}
}
}
2. Missing Function: CShop::RemoveGuest
Several calls to GetShop()->RemoveGuest(this) exist within char.cpp (e.g., in CHARACTER::Destroy, CHARACTER::Disconnect). These calls are not directly part of the reload system but are dependencies within the martysama 5.8 source. The compilation fails because this function is not defined in the CShop class.
Reason for Fix:
This is likely a pre-existing issue or an oversight in the source base. To satisfy the linker, we must implement the RemoveGuest function.
Solution:
File: shop.h
Add the function declaration inside the CShop class, under the public: section.
class CShop
{
public:
// ... other public functions ...
virtual bool AddGuest(LPCHARACTER ch,DWORD owner_vid, bool bOtherEmpire);
// [FIX] Add the declaration for the missing function
void RemoveGuest(LPCHARACTER ch);
void RemoveAllGuests();
// ... rest of the class ...
};
File: shop.cpp
Add the function's definition. This implementation properly removes a character from the shop's guest list and notifies the client.
// [FIX] Add the definition for the missing function
void CShop::RemoveGuest(LPCHARACTER ch)
{
if (ch->GetShop() != this)
return;
m_map_guest.erase(ch);
ch->SetShop(NULL);
TPacketGCShop pack;
pack.header = HEADER_GC_SHOP;
pack.subheader = SHOP_SUBHEADER_GC_END;
pack.size = sizeof(TPacketGCShop);
ch->GetDesc()->Packet(&pack, sizeof(pack));
}
// ... rest of the file ...
3. Missing Function Overload: ITEM_MANAGER::ReadDropItemGroup
The guide correctly modifies several item-related functions (ReadEtcDropItemFile, ReadMonsterDropItemGroup, etc.) to accept a boolean isReloading parameter. However, it misses the update for ReadDropItemGroup, which is called during the server boot process. This causes a linker error as the boot sequence (CInputDB::Boot) calls a version of the function that no longer exists.
Reason for Fix:
The original guide failed to provide an updated definition for ReadDropItemGroup. We must add the original, non-reloading version of the function back into the source.
Solution:
File: item_manager_read_tables.cpp
Add the complete, original definition for the function. A good place is before the ReadEtcDropItemFile function.
// [FIX] Add the missing function definition
bool ITEM_MANAGER::ReadDropItemGroup(const char * c_pszFileName)
{
CTextFileLoader loader;
if (!loader.Load(c_pszFileName))
return false;
for (DWORD i = 0; i < loader.GetChildNodeCount(); ++i)
{
std::string stName("");
loader.SetChildNode(i);
loader.GetCurrentNodeName(&stName);
int iVnum = 0;
if (!loader.GetTokenInteger("vnum", &iVnum))
{
sys_err("ReadDropItemGroup : Syntax error %s : no vnum, node %s", c_pszFileName, stName.c_str());
loader.SetParentNode();
return false;
}
CDropItemGroup* pkGroup = M2_NEW CDropItemGroup(iVnum, 0, stName);
TTokenVector * pTok;
for (int k = 1; k < 256; ++k)
{
char buf[4];
snprintf(buf, sizeof(buf), "%d", k);
if (loader.GetTokenVector(buf, &pTok))
{
std::string& name = pTok->at(0);
DWORD dwVnum = 0;
if (!GetVnumByOriginalName(name.c_str(), dwVnum))
{
str_to_number(dwVnum, name.c_str());
if (!ITEM_MANAGER::instance().GetTable(dwVnum))
{
sys_err("ReadDropItemGroup : there is no item %s : node %s", name.c_str(), stName.c_str());
M2_DELETE(pkGroup);
return false;
}
}
int iCount = 0;
str_to_number(iCount, pTok->at(1).c_str());
if (iCount < 1)
{
sys_err("ReadDropItemGroup : there is no count for item %s : node %s", name.c_str(), stName.c_str());
M2_DELETE(pkGroup);
return false;
}
float fPercent = atof(pTok->at(2).c_str());
DWORD dwPct = (DWORD)(10000.0f * fPercent);
sys_log(0," name %s pct %d count %d", name.c_str(), dwPct, iCount);
pkGroup->AddItem(dwVnum, dwPct, iCount);
continue;
}
break;
}
m_map_pkDropItemGroup.insert(std::map<DWORD, CDropItemGroup*>::value_type(iVnum, pkGroup));
loader.SetParentNode();
}
return true;
}
By applying these three fixes, the "More extended /reload commands" system will compile successfully and be fully integrated into the martysama 5.8 source.