MRMJ-1: Messenger & Skills fixes

This commit is contained in:
Mind Rapist
2025-12-14 05:17:16 +02:00
parent da619922cb
commit 0f79d890ba
53 changed files with 1387 additions and 231 deletions

View File

@@ -12,6 +12,11 @@
#include "char_manager.h"
#include "questmanager.h"
#ifdef FIX_MESSENGER_ACTION_SYNC
static char __account[CHARACTER_NAME_MAX_LEN * 2 + 1];
static char __companion[CHARACTER_NAME_MAX_LEN * 2 + 1];
#endif
MessengerManager::MessengerManager()
{
}
@@ -43,6 +48,13 @@ void MessengerManager::Login(MessengerManager::keyA account)
if (m_set_loginAccount.find(account) != m_set_loginAccount.end())
return;
#ifdef FIX_MESSENGER_ACTION_SYNC
DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size());
if (account.compare(__account))
return;
#endif
DBManager::instance().FuncQuery(std::bind(&MessengerManager::LoadList, this, std::placeholders::_1),
"SELECT account, companion FROM messenger_list%s WHERE account='%s'", get_table_postfix(), account.c_str());
@@ -110,13 +122,131 @@ void MessengerManager::Logout(MessengerManager::keyA account)
m_Relation.erase(account);
//m_map_stMobile.erase(account);
#ifdef FIX_MESSENGER_ACTION_SYNC
// remove any pending requests from/to this account so they don't get stuck
EraseRequestsForAccount(account);
#endif
}
#ifdef CROSS_CHANNEL_FRIEND_REQUEST
void MessengerManager::RegisterRequestToAdd(const char* name, const char* targetName)
{
uint32_t dw1 = GetCRC32(name, strlen(name));
uint32_t dw2 = GetCRC32(targetName, strlen(targetName));
char buf[64]{ 0, };
snprintf(buf, sizeof(buf), "%u:%u", dw1, dw2);
buf[63] = '\0';
uint32_t dwComplex = GetCRC32(buf, strlen(buf));
#ifdef FIX_MESSENGER_ACTION_SYNC
// Check if this requester already sent the same request
if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end())
{
// Send P2P response back to requester's core
TPacketGGMessengerResponse p2pResp{};
p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE;
strlcpy(p2pResp.szRequester, name, sizeof(p2pResp.szRequester));
strlcpy(p2pResp.szTarget, targetName, sizeof(p2pResp.szTarget));
p2pResp.bResponseType = 0; // already_sent
P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse));
return;
}
// Clear any old incoming requests for this target before adding new one
EraseIncomingRequestsForTarget(targetName);
RegisterRequestComplex(dw1, dw2, dwComplex);
#else
m_set_requestToAdd.insert(dwComplex);
#endif
}
// stage 1: starts on the core where "ch" resides. Validate ch and move to stage 2
void MessengerManager::P2PRequestToAdd_Stage1(LPCHARACTER ch, const char* targetName)
{
LPCHARACTER pkTarget = CHARACTER_MANAGER::Instance().FindPC(targetName);
uint32_t dw1 = GetCRC32(ch->GetName(), strlen(ch->GetName()));
uint32_t dw2 = GetCRC32(targetName, strlen(targetName));
char buf[64]{ 0, };
snprintf(buf, sizeof(buf), "%u:%u", dw2, dw1);
buf[63] = '\0';
uint32_t dwComplex = GetCRC32(buf, strlen(buf));
// Check if target already sent a request to requester (reverse)
if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] %s has already sent you a friend request."), targetName);
return;
}
if (!pkTarget)
{
if (!ch || !ch->IsPC())
return;
if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 친구 추가를 받을 수 없는 상태입니다."));
return;
}
TPacketGGMessengerRequest p2pp{};
p2pp.header = HEADER_GG_MESSENGER_REQUEST_ADD;
strlcpy(p2pp.account, ch->GetName(), CHARACTER_NAME_MAX_LEN + 1);
strlcpy(p2pp.target, targetName, CHARACTER_NAME_MAX_LEN + 1);
P2P_MANAGER::Instance().Send(&p2pp, sizeof(TPacketGGMessengerRequest));
}
else // if we have both, just continue normally
RequestToAdd(ch, pkTarget);
}
// stage 2: ends up on the core where the target resides
void MessengerManager::P2PRequestToAdd_Stage2(const char* characterName, LPCHARACTER target)
{
LPCHARACTER ch = CHARACTER_MANAGER::Instance().FindPC(characterName);
if (!target || !target->IsPC())
return;
if (quest::CQuestManager::instance().GetPCForce(target->GetPlayerID())->IsRunning())
{
// Send response back to requester's core
TPacketGGMessengerResponse p2pResp{};
p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE;
strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester));
strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget));
p2pResp.bResponseType = 2; // quest_running
P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse));
return;
}
if (target->IsBlockMode(BLOCK_MESSENGER_INVITE))
{
// Send response back to requester's core
TPacketGGMessengerResponse p2pResp{};
p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE;
strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester));
strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget));
p2pResp.bResponseType = 3; // blocking_requests
P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse));
return;
}
MessengerManager::Instance().RegisterRequestToAdd(characterName, target->GetName());
target->ChatPacket(CHAT_TYPE_COMMAND, "messenger_auth %s", characterName);
}
#endif
void MessengerManager::RequestToAdd(LPCHARACTER ch, LPCHARACTER target)
{
if (!ch->IsPC() || !target->IsPC())
return;
if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 친구 추가를 받을 수 없는 상태입니다."));
@@ -133,7 +263,43 @@ void MessengerManager::RequestToAdd(LPCHARACTER ch, LPCHARACTER target)
snprintf(buf, sizeof(buf), "%u:%u", dw1, dw2);
DWORD dwComplex = GetCRC32(buf, strlen(buf));
#ifdef FIX_MESSENGER_ACTION_SYNC
std::string requester = ch->GetName();
std::string companion = target->GetName();
char buf2[64];
snprintf(buf2, sizeof(buf2), "%u:%u", dw2, dw1);
DWORD dwComplexRev = GetCRC32(buf2, strlen(buf2));
// In-memory quick check (fast, works if lists are loaded)
if (IsInList(requester, companion) || IsInList(companion, requester))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You are already friends with %s."), companion.c_str());
return;
}
// Check if this requester already sent the same request
if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You already sent a friend request to %s."), companion.c_str());
return;
}
// Check if target already sent a request to requester (reverse)
if (m_set_requestToAdd.find(dwComplexRev) != m_set_requestToAdd.end())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] %s has already sent you a friend request."), companion.c_str());
return;
}
// Clear any old incoming requests for this target before adding new one
EraseIncomingRequestsForTarget(target->GetName());
// register complex indexed mappings so we can erase them on disconnect
RegisterRequestComplex(dw1, dw2, dwComplex);
#else
m_set_requestToAdd.insert(dwComplex);
#endif
target->ChatPacket(CHAT_TYPE_COMMAND, "messenger_auth %s", ch->GetName());
}
@@ -177,7 +343,22 @@ bool MessengerManager::AuthToAdd(MessengerManager::keyA account, MessengerManage
return false;
}
#ifndef FIX_MESSENGER_ACTION_SYNC
m_set_requestToAdd.erase(dwComplex);
#else
RemoveComplex(dwComplex);
// In-memory quick check (fast, works if lists are loaded)
if (IsInList(account, companion) || IsInList(companion, account))
{
LPCHARACTER acc_ch = CHARACTER_MANAGER::instance().FindPC(account.c_str());
if (acc_ch)
acc_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You are already friends with %s."), companion.c_str());
return false;
}
#endif
if (!bDeny)
{
@@ -188,7 +369,122 @@ bool MessengerManager::AuthToAdd(MessengerManager::keyA account, MessengerManage
return true;
}
#ifdef FIX_MESSENGER_ACTION_SYNC
void MessengerManager::RegisterRequestComplex(DWORD dw1, DWORD dw2, DWORD dwComplex)
{
// avoid duplicates
if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end())
return;
m_set_requestToAdd.insert(dwComplex);
m_map_requestComplex[dwComplex] = std::make_pair(dw1, dw2);
m_map_requestsFrom[dw1].insert(dwComplex);
m_map_requestsTo[dw2].insert(dwComplex);
}
void MessengerManager::RemoveComplex(DWORD dwComplex)
{
auto it = m_map_requestComplex.find(dwComplex);
if (it == m_map_requestComplex.end())
{
m_set_requestToAdd.erase(dwComplex);
return;
}
DWORD dw1 = it->second.first;
DWORD dw2 = it->second.second;
// erase complex mapping
m_map_requestComplex.erase(it);
// remove from requester index
auto itFrom = m_map_requestsFrom.find(dw1);
if (itFrom != m_map_requestsFrom.end())
{
itFrom->second.erase(dwComplex);
if (itFrom->second.empty())
m_map_requestsFrom.erase(itFrom);
}
// remove from target index
auto itTo = m_map_requestsTo.find(dw2);
if (itTo != m_map_requestsTo.end())
{
itTo->second.erase(dwComplex);
if (itTo->second.empty())
m_map_requestsTo.erase(itTo);
}
// remove from master set
m_set_requestToAdd.erase(dwComplex);
}
void MessengerManager::EraseRequestsForAccount(keyA account)
{
DWORD dw = GetCRC32(account.c_str(), account.length());
std::vector<DWORD> toRemove;
auto itFrom = m_map_requestsFrom.find(dw);
if (itFrom != m_map_requestsFrom.end())
{
for (DWORD c : itFrom->second)
toRemove.push_back(c);
}
auto itTo = m_map_requestsTo.find(dw);
if (itTo != m_map_requestsTo.end())
{
for (DWORD c : itTo->second)
toRemove.push_back(c);
}
if (toRemove.empty())
return;
// uniqueify to avoid double removals
std::sort(toRemove.begin(), toRemove.end());
toRemove.erase(std::unique(toRemove.begin(), toRemove.end()), toRemove.end());
for (DWORD c : toRemove)
RemoveComplex(c);
}
void MessengerManager::EraseIncomingRequestsForTarget(const char* targetName)
{
DWORD dwTarget = GetCRC32(targetName, strlen(targetName));
std::vector<DWORD> toRemove;
// Find all requests where this person is the target (incoming requests)
auto itTo = m_map_requestsTo.find(dwTarget);
if (itTo != m_map_requestsTo.end())
{
for (DWORD c : itTo->second)
toRemove.push_back(c);
}
if (toRemove.empty())
return;
// Remove all found requests
for (DWORD c : toRemove)
RemoveComplex(c);
}
void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerManager::keyA companion, bool isRequester)
#else
void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerManager::keyA companion)
#endif
{
m_Relation[account].insert(companion);
m_InverseRelation[companion].insert(account);
@@ -196,14 +492,22 @@ void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerMana
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str());
LPDESC d = ch ? ch->GetDesc() : NULL;
#ifdef FIX_MESSENGER_ACTION_SYNC
if (d && isRequester)
#else
if (d)
#endif
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> %s 님을 친구로 추가하였습니다."), companion.c_str());
}
LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(companion.c_str());
#ifdef CROSS_CHANNEL_FRIEND_REQUEST
if (tch || P2P_MANAGER::Instance().Find(companion.c_str()))
#else
if (tch)
#endif
SendLogin(account, companion);
else
SendLogout(account, companion);
@@ -217,7 +521,16 @@ void MessengerManager::AddToList(MessengerManager::keyA account, MessengerManage
if (m_Relation[account].find(companion) != m_Relation[account].end())
return;
#ifdef FIX_MESSENGER_ACTION_SYNC
DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size());
DBManager::instance().EscapeString(__companion, sizeof(__companion), companion.c_str(), companion.size());
if (account.compare(__account) || companion.compare(__companion))
return;
#endif
sys_log(0, "Messenger Add %s %s", account.c_str(), companion.c_str());
DBManager::instance().Query("INSERT INTO messenger_list%s VALUES ('%s', '%s')",
get_table_postfix(), account.c_str(), companion.c_str());
@@ -231,16 +544,46 @@ void MessengerManager::AddToList(MessengerManager::keyA account, MessengerManage
P2P_MANAGER::instance().Send(&p2ppck, sizeof(TPacketGGMessenger));
}
#ifdef FIX_MESSENGER_ACTION_SYNC
void MessengerManager::__RemoveFromList(MessengerManager::keyA account, MessengerManager::keyA companion, bool isRequester)
#else
void MessengerManager::__RemoveFromList(MessengerManager::keyA account, MessengerManager::keyA companion)
#endif
{
m_Relation[account].erase(companion);
m_InverseRelation[companion].erase(account);
#ifdef FIX_MESSENGER_ACTION_SYNC
m_Relation[companion].erase(account);
m_InverseRelation[account].erase(companion);
#endif
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str());
LPDESC d = ch ? ch->GetDesc() : NULL;
#ifdef FIX_MESSENGER_ACTION_SYNC
if (d && isRequester)
#else
if (d)
#endif
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> %s 님을 메신저에서 삭제하였습니다."), companion.c_str());
#ifdef FIX_MESSENGER_ACTION_SYNC
LPCHARACTER tch = CHARACTER_MANAGER::Instance().FindPC(companion.c_str());
if (tch && tch->GetDesc())
{
TPacketGCMessenger p;
p.header = HEADER_GC_MESSENGER;
p.subheader = MESSENGER_SUBHEADER_GC_REMOVE_FRIEND;
p.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + account.size();
BYTE bLen = account.size();
tch->GetDesc()->BufferedPacket(&p, sizeof(p));
tch->GetDesc()->BufferedPacket(&bLen, sizeof(BYTE));
tch->GetDesc()->Packet(account.c_str(), account.size());
}
#endif
}
bool MessengerManager::IsInList(MessengerManager::keyA account, MessengerManager::keyA companion) // Fix
@@ -265,8 +608,17 @@ void MessengerManager::RemoveFromList(MessengerManager::keyA account, MessengerM
if (!IsInList(account, companion)) // Fix
return;
#ifdef FIX_MESSENGER_ACTION_SYNC
DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size());
DBManager::instance().EscapeString(__companion, sizeof(__companion), companion.c_str(), companion.size());
if (account.compare(__account) || companion.compare(__companion))
return;
#else
char companionEscaped[CHARACTER_NAME_MAX_LEN * 2 + 1];
DBManager::instance().EscapeString(companionEscaped, sizeof(companionEscaped), companion.c_str(), companion.length());
DBManager::instance().EscapeString(companionEscaped, sizeof(companionEscaped), companion.c_str(), companion.length());
#endif
sys_log(1, "Messenger Remove %s %s", account.c_str(), companion.c_str());
@@ -274,8 +626,13 @@ void MessengerManager::RemoveFromList(MessengerManager::keyA account, MessengerM
// get_table_postfix(), account.c_str(), companion.c_str());
// Fix
#ifdef FIX_MESSENGER_ACTION_SYNC
DBManager::instance().Query("DELETE FROM messenger_list%s WHERE (account='%s' AND companion = '%s') OR (account = '%s' AND companion = '%s')",
get_table_postfix(), account.c_str(), companion.c_str(), companion.c_str(), account.c_str());
#else
DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' AND companion = '%s'",
get_table_postfix(), account.c_str(), companionEscaped);
get_table_postfix(), account.c_str(), companion.c_str());
#endif
__RemoveFromList(account, companion);
@@ -291,6 +648,13 @@ void MessengerManager::RemoveAllList(keyA account)
{
std::set<keyT> company(m_Relation[account]);
#ifdef FIX_MESSENGER_ACTION_SYNC
DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size());
if (account.compare(__account))
return;
#endif
/* SQL Data 삭제 */
DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'",
get_table_postfix(), account.c_str(), account.c_str());
@@ -301,6 +665,9 @@ void MessengerManager::RemoveAllList(keyA account)
iter++ )
{
this->RemoveFromList(account, *iter);
#ifdef FIX_MESSENGER_ACTION_SYNC
this->RemoveFromList(*iter, account);
#endif
}
/* 복사한 데이타 삭제 */
@@ -314,7 +681,6 @@ void MessengerManager::RemoveAllList(keyA account)
company.clear();
}
void MessengerManager::SendList(MessengerManager::keyA account)
{
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str());