forked from metin-server/m2dev-client-src
Merge pull request #84 from rtw1x1/main
ML: Item / Mob / NPC client sided
This commit is contained in:
@@ -298,6 +298,8 @@ enum
|
||||
HEADER_GC_DRAGON_SOUL_REFINE = 209,
|
||||
HEADER_GC_RESPOND_CHANNELSTATUS = 210,
|
||||
|
||||
HEADER_GC_ITEM_GET = 211,
|
||||
|
||||
HEADER_GC_KEY_AGREEMENT_COMPLETED = 0xfa, // _IMPROVED_PACKET_ENCRYPTION_
|
||||
HEADER_GC_KEY_AGREEMENT = 0xfb, // _IMPROVED_PACKET_ENCRYPTION_
|
||||
HEADER_GC_HANDSHAKE_OK = 0xfc, // 252
|
||||
@@ -1630,6 +1632,15 @@ typedef struct packet_set_item
|
||||
TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_SLOT_MAX_NUM];
|
||||
} TPacketGCItemSet;
|
||||
|
||||
typedef struct packet_item_get
|
||||
{
|
||||
uint8_t header;
|
||||
uint32_t dwItemVnum;
|
||||
uint8_t bCount;
|
||||
uint8_t bArg; // 0: normal, 1: from party member
|
||||
char szFromName[CHARACTER_NAME_MAX_LEN + 1];
|
||||
} TPacketGCItemGet;
|
||||
|
||||
typedef struct packet_use_item
|
||||
{
|
||||
uint8_t header;
|
||||
@@ -2281,6 +2292,7 @@ typedef struct SPacketGCNPCPosition
|
||||
struct TNPCPosition
|
||||
{
|
||||
uint8_t bType;
|
||||
uint32_t dwVnum;
|
||||
char name[CHARACTER_NAME_MAX_LEN+1];
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
@@ -71,6 +71,7 @@ class CMainPacketHeaderMap : public CNetworkPacketHeaderMap
|
||||
|
||||
Set(HEADER_GC_ITEM_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemDel), STATIC_SIZE_PACKET));
|
||||
Set(HEADER_GC_ITEM_SET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemSet), STATIC_SIZE_PACKET));
|
||||
Set(HEADER_GC_ITEM_GET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemGet), STATIC_SIZE_PACKET));
|
||||
|
||||
Set(HEADER_GC_ITEM_USE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemUse), STATIC_SIZE_PACKET));
|
||||
Set(HEADER_GC_ITEM_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemUpdate), STATIC_SIZE_PACKET));
|
||||
|
||||
@@ -447,6 +447,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
|
||||
|
||||
bool RecvItemDelPacket(); // Alarm to python
|
||||
bool RecvItemSetPacket(); // Alarm to python
|
||||
bool RecvItemGetPacket(); // Alarm to python
|
||||
bool RecvItemUsePacket(); // Alarm to python
|
||||
bool RecvItemUpdatePacket(); // Alarm to python
|
||||
bool RecvItemGroundAddPacket();
|
||||
@@ -604,6 +605,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
|
||||
void __RecvCharacterUpdatePacket(SNetworkUpdateActorData * pkNetUpdateActorData);
|
||||
|
||||
void __FilterInsult(char* szLine, UINT uLineLen);
|
||||
void __LocalizeItemLinks(char* buf, size_t bufSize);
|
||||
|
||||
void __SetGuildID(DWORD id);
|
||||
|
||||
|
||||
@@ -320,6 +320,10 @@ void CPythonNetworkStream::GamePhase()
|
||||
ret = RecvItemSetPacket();
|
||||
break;
|
||||
|
||||
case HEADER_GC_ITEM_GET:
|
||||
ret = RecvItemGetPacket();
|
||||
break;
|
||||
|
||||
case HEADER_GC_ITEM_USE:
|
||||
ret = RecvItemUsePacket();
|
||||
break;
|
||||
@@ -1293,6 +1297,111 @@ void CPythonNetworkStream::__ConvertEmpireText(DWORD dwEmpireID, char* szText)
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonNetworkStream::__LocalizeItemLinks(char* buf, size_t bufSize)
|
||||
{
|
||||
// Replace item names in hyperlinks with client-side localized names
|
||||
// Format: |Hitem:VNUM:flags:socket0:socket1:socket2...|h[ItemName]|h
|
||||
|
||||
// Early exit: skip processing if no item links exist
|
||||
if (!strstr(buf, "|Hitem:"))
|
||||
return;
|
||||
|
||||
char* pSearch = buf;
|
||||
char result[2048];
|
||||
char* pResult = result;
|
||||
char* pResultEnd = result + sizeof(result) - 1;
|
||||
|
||||
while (*pSearch && pResult < pResultEnd)
|
||||
{
|
||||
// Look for |Hitem:
|
||||
if (strncmp(pSearch, "|Hitem:", 7) == 0)
|
||||
{
|
||||
char* pLinkStart = pSearch;
|
||||
pSearch += 7;
|
||||
|
||||
// Extract vnum (first hex value after "item:")
|
||||
DWORD dwVnum = 0;
|
||||
while (*pSearch && *pSearch != ':' && *pSearch != '|')
|
||||
{
|
||||
if (*pSearch >= '0' && *pSearch <= '9')
|
||||
dwVnum = dwVnum * 16 + (*pSearch - '0');
|
||||
else if (*pSearch >= 'a' && *pSearch <= 'f')
|
||||
dwVnum = dwVnum * 16 + (*pSearch - 'a' + 10);
|
||||
else if (*pSearch >= 'A' && *pSearch <= 'F')
|
||||
dwVnum = dwVnum * 16 + (*pSearch - 'A' + 10);
|
||||
pSearch++;
|
||||
}
|
||||
|
||||
// Find |h[ which marks the start of the item name
|
||||
char* pNameStart = strstr(pSearch, "|h[");
|
||||
if (pNameStart)
|
||||
{
|
||||
pNameStart += 3; // Skip "|h["
|
||||
|
||||
// Find ]|h which marks the end of the item name
|
||||
char* pNameEnd = strstr(pNameStart, "]|h");
|
||||
if (pNameEnd)
|
||||
{
|
||||
// Get the client-side item name
|
||||
CItemData* pItemData;
|
||||
const char* szLocalName = NULL;
|
||||
if (CItemManager::Instance().GetItemDataPointer(dwVnum, &pItemData))
|
||||
szLocalName = pItemData->GetName();
|
||||
|
||||
// Copy everything from link start to |h[
|
||||
size_t copyLen = pNameStart - pLinkStart;
|
||||
if (pResult + copyLen < pResultEnd)
|
||||
{
|
||||
memcpy(pResult, pLinkStart, copyLen);
|
||||
pResult += copyLen;
|
||||
}
|
||||
|
||||
// Insert the localized name (or original if not found)
|
||||
const char* szName = szLocalName ? szLocalName : pNameStart;
|
||||
size_t nameLen = szLocalName ? strlen(szLocalName) : (pNameEnd - pNameStart);
|
||||
if (pResult + nameLen < pResultEnd)
|
||||
{
|
||||
if (szLocalName)
|
||||
{
|
||||
memcpy(pResult, szLocalName, nameLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pResult, pNameStart, nameLen);
|
||||
}
|
||||
pResult += nameLen;
|
||||
}
|
||||
|
||||
// Copy ]|h
|
||||
if (pResult + 3 < pResultEnd)
|
||||
{
|
||||
memcpy(pResult, "]|h", 3);
|
||||
pResult += 3;
|
||||
}
|
||||
|
||||
pSearch = pNameEnd + 3; // Skip past ]|h
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't parse properly, just copy the character and continue
|
||||
if (pResult < pResultEnd)
|
||||
*pResult++ = *pLinkStart;
|
||||
pSearch = pLinkStart + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pResult < pResultEnd)
|
||||
*pResult++ = *pSearch;
|
||||
pSearch++;
|
||||
}
|
||||
}
|
||||
*pResult = '\0';
|
||||
|
||||
strncpy(buf, result, bufSize - 1);
|
||||
buf[bufSize - 1] = '\0';
|
||||
}
|
||||
|
||||
bool CPythonNetworkStream::RecvChatPacket()
|
||||
{
|
||||
TPacketGCChat kChat;
|
||||
@@ -1309,6 +1418,9 @@ bool CPythonNetworkStream::RecvChatPacket()
|
||||
|
||||
buf[uChatSize]='\0';
|
||||
|
||||
// Localize item names in hyperlinks for multi-language support
|
||||
__LocalizeItemLinks(buf, sizeof(buf));
|
||||
|
||||
if (kChat.type >= CHAT_TYPE_MAX_NUM)
|
||||
return true;
|
||||
|
||||
@@ -4173,7 +4285,15 @@ bool CPythonNetworkStream::RecvNPCList()
|
||||
if (!Recv(sizeof(TNPCPosition), &NPCPosition))
|
||||
return false;
|
||||
|
||||
CPythonMiniMap::Instance().RegisterAtlasMark(NPCPosition.bType, NPCPosition.name, NPCPosition.x, NPCPosition.y);
|
||||
const char* c_szName = nullptr;
|
||||
if (CPythonNonPlayer::Instance().GetName(NPCPosition.dwVnum, &c_szName))
|
||||
{
|
||||
CPythonMiniMap::Instance().RegisterAtlasMark(NPCPosition.bType, c_szName, NPCPosition.x, NPCPosition.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPythonMiniMap::Instance().RegisterAtlasMark(NPCPosition.bType, NPCPosition.name, NPCPosition.x, NPCPosition.y);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -158,7 +158,18 @@ bool CPythonNetworkStream::RecvCharacterAdditionalInfo()
|
||||
|
||||
if(kNetActorData.m_dwVID == chrInfoPacket.dwVID)
|
||||
{
|
||||
kNetActorData.m_stName = chrInfoPacket.name;
|
||||
if (kNetActorData.m_bType == CActorInstance::TYPE_NPC)
|
||||
{
|
||||
const char* c_szName;
|
||||
if (CPythonNonPlayer::Instance().GetName(kNetActorData.m_dwRace, &c_szName))
|
||||
kNetActorData.m_stName = c_szName;
|
||||
else
|
||||
kNetActorData.m_stName = chrInfoPacket.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNetActorData.m_stName = chrInfoPacket.name;
|
||||
}
|
||||
kNetActorData.m_dwGuildID = chrInfoPacket.dwGuildID;
|
||||
kNetActorData.m_dwLevel = chrInfoPacket.dwLevel;
|
||||
kNetActorData.m_sAlignment=chrInfoPacket.sAlignment;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "PythonCharacterManager.h"
|
||||
|
||||
#include "AbstractPlayer.h"
|
||||
#include "GameLib/ItemManager.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SafeBox
|
||||
@@ -254,6 +255,40 @@ bool CPythonNetworkStream::RecvItemSetPacket()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonNetworkStream::RecvItemGetPacket()
|
||||
{
|
||||
TPacketGCItemGet packet;
|
||||
if (!Recv(sizeof(TPacketGCItemGet), &packet))
|
||||
return false;
|
||||
|
||||
CItemData* pItemData;
|
||||
if (!CItemManager::Instance().GetItemDataPointer(packet.dwItemVnum, &pItemData))
|
||||
{
|
||||
TraceError("CPythonNetworkStream::RecvItemGetPacket - Unknown item vnum %u", packet.dwItemVnum);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packet.bArg == 0)
|
||||
{
|
||||
// Normal pickup
|
||||
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_ItemGet",
|
||||
Py_BuildValue("(si)", pItemData->GetName(), packet.bCount));
|
||||
}
|
||||
else if (packet.bArg == 1)
|
||||
{
|
||||
// Received from party member
|
||||
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_ItemGetFromParty",
|
||||
Py_BuildValue("(ssi)", pItemData->GetName(), packet.szFromName, packet.bCount));
|
||||
}
|
||||
else if (packet.bArg == 2)
|
||||
{
|
||||
// Delivered to party member
|
||||
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_ItemDeliverToParty",
|
||||
Py_BuildValue("(ssi)", pItemData->GetName(), packet.szFromName, packet.bCount));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonNetworkStream::RecvItemUsePacket()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user