Validate interaction NPCs for refine and cube
Some checks failed
build / Linux asan (push) Has been cancelled
build / Linux release (push) Has been cancelled
build / FreeBSD build (push) Has been cancelled

This commit is contained in:
server
2026-04-16 12:43:34 +02:00
parent f79d5134c4
commit bdfdef8411
4 changed files with 183 additions and 14 deletions

View File

@@ -1878,6 +1878,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
// by mhh
LPITEM* GetCubeItem() { return m_pointsInstant.pCubeItems; }
bool IsCubeOpen () const { return (m_pointsInstant.pCubeNpc?true:false); }
LPCHARACTER GetCubeNpc() const { return m_pointsInstant.pCubeNpc; }
void SetCubeNpc(LPCHARACTER npc) { m_pointsInstant.pCubeNpc = npc; }
bool CanDoCube() const;

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "char.h"
#include "utils.h"
#include "item.h"
#include "desc.h"
#include "DragonSoul.h"
@@ -150,5 +151,41 @@ bool CHARACTER::DragonSoul_RefineWindow_Close()
bool CHARACTER::DragonSoul_RefineWindow_CanRefine()
{
return NULL != m_pointsInstant.m_pDragonSoulRefineWindowOpener;
}
if (NULL == m_pointsInstant.m_pDragonSoulRefineWindowOpener)
return false;
LPENTITY pOpener = m_pointsInstant.m_pDragonSoulRefineWindowOpener;
if (!pOpener->IsType(ENTITY_CHARACTER))
{
RecordAntiCheatViolation("DRAGON_SOUL_REFINE", 6, "state=invalid_opener", true);
m_pointsInstant.m_pDragonSoulRefineWindowOpener = NULL;
return false;
}
LPCHARACTER npc = (LPCHARACTER)pOpener;
if (!npc->IsNPC() || npc == this || npc->GetMapIndex() != GetMapIndex())
{
char szDetail[160];
snprintf(szDetail,
sizeof(szDetail),
"npc=%u map=%ld npc_map=%ld",
npc->GetVID(),
static_cast<long>(GetMapIndex()),
static_cast<long>(npc->GetMapIndex()));
RecordAntiCheatViolation("DRAGON_SOUL_REFINE", 8, szDetail, true);
m_pointsInstant.m_pDragonSoulRefineWindowOpener = NULL;
return false;
}
const int iDistance = DISTANCE_APPROX(GetX() - npc->GetX(), GetY() - npc->GetY());
if (iDistance > 2000)
{
char szDetail[160];
snprintf(szDetail, sizeof(szDetail), "npc=%u distance=%d max=%d", npc->GetVID(), iDistance, 2000);
RecordAntiCheatViolation("DRAGON_SOUL_REFINE", iDistance > 2800 ? 12 : 4, szDetail, iDistance > 2800);
m_pointsInstant.m_pDragonSoulRefineWindowOpener = NULL;
return false;
}
return true;
}

View File

@@ -43,6 +43,57 @@
#include "buff_on_attributes.h"
#include "belt_inventory_helper.h"
namespace
{
constexpr int kRefineNpcMaxDistance = 2000;
bool ValidateStoredRefineNpc(LPCHARACTER ch, DWORD dwRefineNpcVID, const char* action)
{
if (!ch)
return false;
if (0 == dwRefineNpcVID)
{
char szDetail[128];
snprintf(szDetail, sizeof(szDetail), "action=%s state=missing", action ? action : "-");
ch->RecordAntiCheatViolation("REFINE_NPC", 8, szDetail, true);
return false;
}
LPCHARACTER npc = CHARACTER_MANAGER::instance().Find(dwRefineNpcVID);
if (!npc || npc == ch || !npc->IsNPC() || npc->GetMapIndex() != ch->GetMapIndex())
{
char szDetail[160];
snprintf(szDetail,
sizeof(szDetail),
"action=%s npc=%u map=%ld npc_map=%ld",
action ? action : "-",
dwRefineNpcVID,
static_cast<long>(ch->GetMapIndex()),
static_cast<long>(npc ? npc->GetMapIndex() : 0));
ch->RecordAntiCheatViolation("REFINE_NPC", 8, szDetail, true);
return false;
}
const int iDistance = DISTANCE_APPROX(ch->GetX() - npc->GetX(), ch->GetY() - npc->GetY());
if (iDistance > kRefineNpcMaxDistance)
{
char szDetail[160];
snprintf(szDetail,
sizeof(szDetail),
"action=%s npc=%u distance=%d max=%d",
action ? action : "-",
dwRefineNpcVID,
iDistance,
kRefineNpcMaxDistance);
ch->RecordAntiCheatViolation("REFINE_NPC", iDistance > kRefineNpcMaxDistance + 800 ? 12 : 4, szDetail, iDistance > kRefineNpcMaxDistance + 800);
return false;
}
return true;
}
}
const int ITEM_BROKEN_METIN_VNUM = 28960;
// CHANGE_ITEM_ATTRIBUTES
@@ -814,6 +865,12 @@ bool CHARACTER::DoRefine(LPITEM item, bool bMoneyOnly, int iType)
ClearRefineMode();
return false;
}
if (!ValidateStoredRefineNpc(this, m_dwRefineNPCVID, bMoneyOnly ? "money_only" : "normal"))
{
ClearRefineMode();
return false;
}
//개량 시간제한 : upgrade_refine_scroll.quest 에서 개량후 5분이내에 일반 개량을
//진행할수 없음
@@ -993,6 +1050,12 @@ bool CHARACTER::DoRefineWithScroll(LPITEM item, int iType)
return false;
}
if (!ValidateStoredRefineNpc(this, m_dwRefineNPCVID, "scroll"))
{
ClearRefineMode();
return false;
}
ClearRefineMode();
//개량 시간제한 : upgrade_refine_scroll.quest 에서 개량후 5분이내에 일반 개량을

View File

@@ -170,6 +170,69 @@ static bool FN_check_valid_npc( WORD vnum )
return false;
}
static void FN_close_cube_session(LPCHARACTER ch)
{
if (!ch)
return;
LPITEM* cube_item = ch->GetCubeItem();
for (int i = 0; i < CUBE_MAX_NUM; ++i)
cube_item[i] = NULL;
ch->SetCubeNpc(NULL);
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube close");
}
static bool FN_validate_cube_npc(LPCHARACTER ch, const char* action)
{
if (!ch || !ch->IsCubeOpen())
return false;
LPCHARACTER npc = ch->GetCubeNpc();
if (NULL == npc)
{
char szDetail[128];
snprintf(szDetail, sizeof(szDetail), "action=%s state=missing", action ? action : "-");
ch->RecordAntiCheatViolation("CUBE_NPC", 6, szDetail, true);
FN_close_cube_session(ch);
return false;
}
if (!npc->IsNPC() || !FN_check_valid_npc(npc->GetRaceNum()) || npc->GetMapIndex() != ch->GetMapIndex())
{
char szDetail[160];
snprintf(szDetail,
sizeof(szDetail),
"action=%s npc=%u map=%ld npc_map=%ld race=%u",
action ? action : "-",
npc->GetVID(),
static_cast<long>(ch->GetMapIndex()),
static_cast<long>(npc->GetMapIndex()),
npc->GetRaceNum());
ch->RecordAntiCheatViolation("CUBE_NPC", 8, szDetail, true);
FN_close_cube_session(ch);
return false;
}
const long distance = DISTANCE_APPROX(ch->GetX() - npc->GetX(), ch->GetY() - npc->GetY());
if (distance >= CUBE_MAX_DISTANCE)
{
char szDetail[160];
snprintf(szDetail,
sizeof(szDetail),
"action=%s npc=%u distance=%ld max=%d",
action ? action : "-",
npc->GetVID(),
distance,
CUBE_MAX_DISTANCE);
ch->RecordAntiCheatViolation("CUBE_NPC", distance >= CUBE_MAX_DISTANCE + 800 ? 12 : 4, szDetail, distance >= CUBE_MAX_DISTANCE + 800);
FN_close_cube_session(ch);
return false;
}
return true;
}
// 큐브데이타가 올바르게 초기화 되었는지 체크한다.
static bool FN_check_cube_data (CUBE_DATA *cube_data)
{
@@ -486,12 +549,10 @@ static bool FN_update_cube_status(LPCHARACTER ch)
if (NULL == ch)
return false;
if (!ch->IsCubeOpen())
if (!FN_validate_cube_npc(ch, "status"))
return false;
LPCHARACTER npc = ch->GetQuestNPC();
if (NULL == npc)
return false;
LPCHARACTER npc = ch->GetCubeNpc();
CUBE_DATA* cube = FN_find_cube(ch->GetCubeItem(), npc->GetRaceNum());
@@ -525,11 +586,10 @@ bool Cube_make (LPCHARACTER ch)
return false;
}
npc = ch->GetQuestNPC();
if (NULL == npc)
{
if (!FN_validate_cube_npc(ch, "make"))
return false;
}
npc = ch->GetCubeNpc();
items = ch->GetCubeItem();
cube_proto = FN_find_cube(items, npc->GetRaceNum());
@@ -613,6 +673,9 @@ void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
if (!FN_validate_cube_npc(ch, "add_item"))
return;
if (inven_index<0 || INVENTORY_MAX_NUM<=inven_index)
return;
if (cube_index<0 || CUBE_MAX_NUM<=cube_index)
@@ -655,6 +718,9 @@ void Cube_delete_item (LPCHARACTER ch, int cube_index)
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
if (!FN_validate_cube_npc(ch, "delete_item"))
return;
if (cube_index<0 || CUBE_MAX_NUM<=cube_index) return;
cube_item = ch->GetCubeItem();
@@ -876,10 +942,11 @@ void Cube_request_result_list(LPCHARACTER ch)
{
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
LPCHARACTER npc = ch->GetQuestNPC();
if (NULL == npc)
if (!FN_validate_cube_npc(ch, "result_list"))
return;
LPCHARACTER npc = ch->GetCubeNpc();
DWORD npcVNUM = npc->GetRaceNum();
size_t resultCount = 0;
@@ -930,10 +997,11 @@ void Cube_request_material_info(LPCHARACTER ch, int requestStartIndex, int reque
{
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
LPCHARACTER npc = ch->GetQuestNPC();
if (NULL == npc)
if (!FN_validate_cube_npc(ch, "material_info"))
return;
LPCHARACTER npc = ch->GetCubeNpc();
DWORD npcVNUM = npc->GetRaceNum();
std::string materialInfoText = "";