Harden fishing and mining action validation
This commit is contained in:
@@ -140,6 +140,12 @@ void CHARACTER::Initialize()
|
||||
LastDropTime = 0;
|
||||
m_dwPickupWindowStart = 0;
|
||||
m_iPickupWindowCount = 0;
|
||||
m_dwFishingWindowStart = 0;
|
||||
m_iFishingWindowCount = 0;
|
||||
m_lFishingStartX = 0;
|
||||
m_lFishingStartY = 0;
|
||||
m_dwMiningWindowStart = 0;
|
||||
m_iMiningWindowCount = 0;
|
||||
|
||||
m_iLastPMPulse = 0;
|
||||
m_iPMCounter = 0;
|
||||
@@ -4064,6 +4070,17 @@ void CHARACTER::ItemGetPacket(DWORD dwItemVnum, BYTE bCount, const char* szName,
|
||||
d->Packet(&pack, sizeof(pack));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr DWORD kActionWindowMs = 1000;
|
||||
constexpr int kFishingRateWarnThreshold = 8;
|
||||
constexpr int kFishingRateBlockThreshold = 18;
|
||||
constexpr int kFishingTakeMaxMoveDistance = 1200;
|
||||
constexpr int kMiningRateWarnThreshold = 6;
|
||||
constexpr int kMiningRateBlockThreshold = 15;
|
||||
constexpr int kMiningStartMaxDistance = 1000;
|
||||
}
|
||||
|
||||
// MINING
|
||||
void CHARACTER::mining_take()
|
||||
{
|
||||
@@ -4082,18 +4099,72 @@ void CHARACTER::mining_cancel()
|
||||
|
||||
void CHARACTER::mining(LPCHARACTER chLoad)
|
||||
{
|
||||
const DWORD dwNow = get_dword_time();
|
||||
if (0 == m_dwMiningWindowStart || dwNow - m_dwMiningWindowStart >= kActionWindowMs)
|
||||
{
|
||||
m_dwMiningWindowStart = dwNow;
|
||||
m_iMiningWindowCount = 0;
|
||||
}
|
||||
|
||||
++m_iMiningWindowCount;
|
||||
if (m_iMiningWindowCount > kMiningRateWarnThreshold)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "window=1s count=%d target=%u", m_iMiningWindowCount, chLoad ? chLoad->GetVID() : 0);
|
||||
RecordAntiCheatViolation("MINING_RATE", MIN(8, 1 + (m_iMiningWindowCount - kMiningRateWarnThreshold) / 2), szDetail, m_iMiningWindowCount > kMiningRateBlockThreshold);
|
||||
|
||||
if (m_iMiningWindowCount > kMiningRateBlockThreshold)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pkMiningEvent)
|
||||
{
|
||||
mining_cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDead() || !CanMove() || !CanHandleItem())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"dead=%d can_move=%d can_item=%d target=%u",
|
||||
IsDead() ? 1 : 0,
|
||||
CanMove() ? 1 : 0,
|
||||
CanHandleItem() ? 1 : 0,
|
||||
chLoad ? chLoad->GetVID() : 0);
|
||||
RecordAntiCheatViolation("MINING_CONTEXT", 4, szDetail);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chLoad)
|
||||
return;
|
||||
|
||||
if (mining::GetRawOreFromLoad(chLoad->GetRaceNum()) == 0)
|
||||
return;
|
||||
|
||||
if (chLoad == this || chLoad->GetMapIndex() != GetMapIndex())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"target=%u map=%ld target_map=%ld",
|
||||
chLoad->GetVID(),
|
||||
static_cast<long>(GetMapIndex()),
|
||||
static_cast<long>(chLoad->GetMapIndex()));
|
||||
RecordAntiCheatViolation("MINING_TARGET", 10, szDetail, true);
|
||||
return;
|
||||
}
|
||||
|
||||
const int iDistance = DISTANCE_APPROX(GetX() - chLoad->GetX(), GetY() - chLoad->GetY());
|
||||
if (iDistance > kMiningStartMaxDistance)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "target=%u distance=%d max=%d", chLoad->GetVID(), iDistance, kMiningStartMaxDistance);
|
||||
RecordAntiCheatViolation("MINING_TARGET", iDistance > kMiningStartMaxDistance + 800 ? 12 : 4, szDetail, iDistance > kMiningStartMaxDistance + 800);
|
||||
return;
|
||||
}
|
||||
|
||||
LPITEM pick = GetWear(WEAR_WEAPON);
|
||||
|
||||
if (!pick || pick->GetType() != ITEM_PICK)
|
||||
@@ -4120,12 +4191,43 @@ void CHARACTER::mining(LPCHARACTER chLoad)
|
||||
|
||||
void CHARACTER::fishing()
|
||||
{
|
||||
const DWORD dwNow = get_dword_time();
|
||||
if (0 == m_dwFishingWindowStart || dwNow - m_dwFishingWindowStart >= kActionWindowMs)
|
||||
{
|
||||
m_dwFishingWindowStart = dwNow;
|
||||
m_iFishingWindowCount = 0;
|
||||
}
|
||||
|
||||
++m_iFishingWindowCount;
|
||||
if (m_iFishingWindowCount > kFishingRateWarnThreshold)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "window=1s count=%d active=%d", m_iFishingWindowCount, m_pkFishingEvent ? 1 : 0);
|
||||
RecordAntiCheatViolation("FISHING_RATE", MIN(8, 1 + (m_iFishingWindowCount - kFishingRateWarnThreshold) / 2), szDetail, m_iFishingWindowCount > kFishingRateBlockThreshold);
|
||||
|
||||
if (m_iFishingWindowCount > kFishingRateBlockThreshold)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pkFishingEvent)
|
||||
{
|
||||
fishing_take();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDead() || !CanMove() || !CanHandleItem())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"dead=%d can_move=%d can_item=%d",
|
||||
IsDead() ? 1 : 0,
|
||||
CanMove() ? 1 : 0,
|
||||
CanHandleItem() ? 1 : 0);
|
||||
RecordAntiCheatViolation("FISHING_CONTEXT", 4, szDetail);
|
||||
return;
|
||||
}
|
||||
|
||||
// 못감 속성에서 낚시를 시도한다?
|
||||
{
|
||||
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
|
||||
@@ -4161,11 +4263,36 @@ void CHARACTER::fishing()
|
||||
float fx, fy;
|
||||
GetDeltaByDegree(GetRotation(), 400.0f, &fx, &fy);
|
||||
|
||||
m_lFishingStartX = GetX();
|
||||
m_lFishingStartY = GetY();
|
||||
m_pkFishingEvent = fishing::CreateFishingEvent(this);
|
||||
}
|
||||
|
||||
void CHARACTER::fishing_take()
|
||||
{
|
||||
if (!CanMove() || !CanHandleItem())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"can_move=%d can_item=%d",
|
||||
CanMove() ? 1 : 0,
|
||||
CanHandleItem() ? 1 : 0);
|
||||
RecordAntiCheatViolation("FISHING_CONTEXT", 4, szDetail);
|
||||
event_cancel(&m_pkFishingEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
const int iMovedDistance = DISTANCE_APPROX(GetX() - m_lFishingStartX, GetY() - m_lFishingStartY);
|
||||
if (iMovedDistance > kFishingTakeMaxMoveDistance)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "distance=%d max=%d", iMovedDistance, kFishingTakeMaxMoveDistance);
|
||||
RecordAntiCheatViolation("FISHING_CONTEXT", iMovedDistance > kFishingTakeMaxMoveDistance + 800 ? 10 : 4, szDetail, iMovedDistance > kFishingTakeMaxMoveDistance + 800);
|
||||
event_cancel(&m_pkFishingEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
LPITEM rod = GetWear(WEAR_WEAPON);
|
||||
if (rod && rod->GetType() == ITEM_ROD)
|
||||
{
|
||||
|
||||
@@ -2051,6 +2051,12 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
||||
int CountDrops;
|
||||
DWORD m_dwPickupWindowStart;
|
||||
int m_iPickupWindowCount;
|
||||
DWORD m_dwFishingWindowStart;
|
||||
int m_iFishingWindowCount;
|
||||
long m_lFishingStartX;
|
||||
long m_lFishingStartY;
|
||||
DWORD m_dwMiningWindowStart;
|
||||
int m_iMiningWindowCount;
|
||||
void ClearPMCounter(void) { m_iPMCounter = 0; }
|
||||
void IncreasePMCounter(void) { m_iPMCounter++; }
|
||||
void SetLastPMPulse(void);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "db.h"
|
||||
#include "log.h"
|
||||
#include "skill.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace mining
|
||||
{
|
||||
@@ -16,6 +17,7 @@ namespace mining
|
||||
MAX_ORE = 18,
|
||||
MAX_FRACTION_COUNT = 9,
|
||||
ORE_COUNT_FOR_REFINE = 100,
|
||||
MINING_COMPLETE_MAX_DISTANCE = 1200,
|
||||
};
|
||||
|
||||
struct SInfo
|
||||
@@ -366,6 +368,42 @@ namespace mining
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (load->GetMapIndex() != ch->GetMapIndex())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"target=%u map=%ld target_map=%ld",
|
||||
load->GetVID(),
|
||||
static_cast<long>(ch->GetMapIndex()),
|
||||
static_cast<long>(load->GetMapIndex()));
|
||||
ch->RecordAntiCheatViolation("MINING_CONTEXT", 8, szDetail, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ch->CanMove() || !ch->CanHandleItem())
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"can_move=%d can_item=%d target=%u",
|
||||
ch->CanMove() ? 1 : 0,
|
||||
ch->CanHandleItem() ? 1 : 0,
|
||||
load->GetVID());
|
||||
ch->RecordAntiCheatViolation("MINING_CONTEXT", 4, szDetail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int iDistance = DISTANCE_APPROX(ch->GetX() - load->GetX(), ch->GetY() - load->GetY());
|
||||
if (iDistance > MINING_COMPLETE_MAX_DISTANCE)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "target=%u distance=%d max=%d", load->GetVID(), iDistance, MINING_COMPLETE_MAX_DISTANCE);
|
||||
ch->RecordAntiCheatViolation("MINING_DISTANCE", iDistance > MINING_COMPLETE_MAX_DISTANCE + 800 ? 12 : 4, szDetail, iDistance > MINING_COMPLETE_MAX_DISTANCE + 800);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("너무 멀리 떨어져 있어 채광을 완료할 수 없습니다."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iPct = GetOrePct(ch);
|
||||
|
||||
if (number(1, 100) <= iPct)
|
||||
@@ -445,4 +483,3 @@ namespace mining
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user