PDA

View Full Version : MQWarp/MQZone/MQGate Detector (Code Name: The VZTZ Hammer!)


TheLieka
03-28-2008, 05:20 PM
May god have mercy on my soul for trying to diff this. I apologize that a lot of it will be redundant checks, but we've had to tweak it quite a bit to get it to the point where it is now. We only have false alarms when we hit a massive lag spike (which happens on occasion), but the only way around that would be to allow massive distance updates all the time - which defeats the purpose.

I know this won't fit into one post, and probably won't even fit into 3 or 4, but I'll do my best to get it all in.

Ok, *gulp* here goes.

Anti-MQ /Warp, Anti-MQ /Gate, Anti-MQ /zone, Anti-MQ /ghost code from the Vallon Zek/Tallon Zek Server:

In addition to myself, contributions to this code came from Rancar and Null.

.\common\ruletypes.h

After:

RULE_BOOL ( Zone, EnableShadowrest, 0 ) // enables or disables the shadowrest zone feature for player corpses. Default is turned off.

Add:

RULE_INT ( Zone, MQWarpExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQZoneExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQGateExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQGhostExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
RULE_BOOL ( Zone, EnableMQWarpDetector, False ) //Lieka: Enable the MQWarp Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQZoneDetector, False ) //Lieka: Enable the MQZone Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQGateDetector, False ) //Lieka: Enable the MQGate Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQGhostDetector, False ) //Lieka: Enable the MQGhost Detector. Set to False to disable this feature.
RULE_REAL ( Zone, MQWarpDetectorDistance, 30 ) //Lieka: Distance a player must travel between client to server location updates before a warp is registered. 30 allows for beyond GM speed without lag.
RULE_REAL ( Zone, MQWarpLagThreshold, 140 ) //Lieka: Distance beyond the Zone:MQWarpDetectorDistance that a player must travel within the MQWarpThresholdTimer amount of time before tripping the MQWarp detector. Set to 0 to disable this feature.
RULE_REAL ( Zone, MQWarpThresholdTimer, 90000 ) //Lieka: Amount of time before the warp_threshold resets to the Zone:MQWarpLagThreshold value. Default: 90000 (900 seconds/15 minutes). Set to -1 to disable this feature.
RULE_INT ( Zone, MQWarpDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQ Detector. This spell will be actually cast, don't pick a resistible spell. Default: 757 (Resurrection Effects)
RULE_INT ( Zone, MQGateDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
RULE_INT ( Zone, MQZoneDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
RULE_INT ( Zone, MQGhostDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQGhostDetector. This spell will be actually cast, don't pick a resistable spell. Default: 757 (Resurrection Effects)



.\common\database.h

After:
bool SetHackerFlag(const char* accountname, const char* charactername, const char* hacked);

Add:

bool SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);

.\common\database.cpp

After:

bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked) values('%s','%s','%s')", accountname, charactername, hacked), errbuf, 0,&affected_rows)) {
cerr << "Error in SetHackerFlag query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);

if (affected_rows == 0)
{
return false;
}

return true;
}

Add:

bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka: Utilize the "hacker" table, but also give zone information.
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {
cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);

if (affected_rows == 0)
{
return false;
}

return true;
}

.\zone\client.h

After:

typedef enum {
ZoneToSafeCoords, // Always send ZonePlayerToBind_Struct to client: Succor/Evac
GMSummon, // Always send ZonePlayerToBind_Struct to client: Only a GM Summon
ZoneToBindPoint, // Always send ZonePlayerToBind_Struct to client: Death Only
ZoneSolicited, // Always send ZonePlayerToBind_Struct to client: Portal, Translocate, Evac spells that have a x y z coord in the spell data
ZoneUnsolicited,
GateToBindPoint, // Always send RequestClientZoneChange_Struct to client: Gate spell or Translocate To Bind Point spell
SummonPC, // In-zone GMMove() always: Call of the Hero spell or some other type of in zone only summons
EvacToSafeCoords
} ZoneMode;

Add:

typedef enum {
MQWarp,
MQZone,
MQGate,
MQGhost
} CheatTypes;

After:

void AI_Init();
void AI_Start(int32 iMoveDelay = 0);
void AI_Stop();
void Trader_ShowItems();
void Trader_EndTrader();
void Trader_StartTrader();
int8 WithCustomer();
bool CheckCheat();

Add:

void CheatDetected(CheatTypes Cheat);
bool WarpDetection(bool CTimer, float Distance);



.\zone\client.cpp

Change (Insert Red Lines):

bool Client::CheckCheat(){

float dx=cheat_x-x_pos;
float dy=cheat_y-y_pos;
float result=sqrtf((dx*dx)+(dy*dy));
return result>(RuleR(Zone, MQWarpDetectorDistance)); //Lieka: Integrated into Rules System; default value is 30, this allows for beyond GM speed without lag.

TheLieka
03-28-2008, 05:24 PM
.\zone\client_packet.cpp

After:

void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app) {
SendAATable();
}

Add:

bool Client::WarpDetection(bool CTimer, float distance)
{
float last_distance;
if (threshold_timer.GetRemainingTime() < 1 && ((RuleR(Zone, MQWarpThresholdTimer)) != -1)) { //Null: If the timer is done, reset threshold, then reset timer //Lieka: Integrated into Rules System.
warp_threshold = (RuleR(Zone, MQWarpLagThreshold)); //Lieka: Integrated warp_threshold value into Rules System. Original Value was 140.
threshold_timer.Start((RuleR(Zone, MQWarpThresholdTimer)), false); //Lieka: Integrated timer duration value into the Rules System. Original Value was 90000 (90 seconds).
}
if ((CTimer))
return false;
else
{
//Null Edit: made warp detector fire only when the sum of all the warps in a period of time are greater than a threshold
//this makes the warp detector more lax on small warps, but still drops the hammer on the big ones.
if (distance>140.0f) {
last_distance = (distance-140.0f);
warp_threshold -= last_distance;
last_warp_distance = last_distance;
}
return (warp_threshold < 0); //Null: If the threshold is met, hit them with the hammer
}
}

void Client::CheatDetected(CheatTypes CheatType)
{ //[Paddy] ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.
switch (CheatType)
{
case MQWarp://Some zones have serious issues, turning off warp flags for these zones.
if(!((zone->GetZoneID()==2)/*qeynos2*/ || (zone->GetZoneID()==9)/*freportw*/|| (zone->GetZoneID()==10)/*freporte*/ || (zone->GetZoneID()==34)/*nro*/ || (zone->GetZoneID()==24)/*erudin*/ || (zone->GetZoneID()==75)/*Paineel*/ || (zone->GetZoneID()==62)/*Felwitheb*/) && (RuleB(Zone, EnableMQWarpDetector) && ((status < RuleI(Zone, MQWarpExemptStatus) || (RuleI(Zone, MQWarpExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQWarp detector (This may be depricated now, but these zones were problems in the past)
{
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name,this->name, "/MQWarp", zone->GetShortName());
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
SpellFinished((RuleI(Zone, MQWarpDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
worldserver.SendEmoteMessage(0,0,0,13,"<MQWarp Detector>. %s was just caught warping in %s. Come get your free kill!",this->GetName(),zone->GetLongName());
warp_threshold = 1; //Null: bringing the detector back up to one to avoid chain detections.
}
break;
case MQZone:
if(!( (zone->GetZoneID()==31)/*sola*/ || (zone->GetZoneID()==32)/*solb*/ || (zone->GetZoneID()==25)/*nek*/ || (zone->GetZoneID()==27)/*lava*/ ) && (RuleB(Zone, EnableMQZoneDetector))&& ((status < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQZone detector (This may be depricated now, but were problems in the past)
{
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name,this->name, "/MQZone", zone->GetShortName());
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
AddBuff(this,(RuleI(Zone, MQZoneDetectionSpell)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
worldserver.SendEmoteMessage(0,0,0,13,"<MQZone Detector>. %s as just caught using Macroquest to /Zone to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQZone detector has caught a cheater.
}
break;
case MQGate:
if (RuleB(Zone, EnableMQGateDetector)&& ((status < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name,this->name, "/MQGate", zone->GetShortName());
this->SetZone(this->GetZoneID()); //Lieka: Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
AddBuff(this,(RuleI(Zone, MQGateDetectionSpell)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
worldserver.SendEmoteMessage(0,0,0,13,"<MQGate Detector>. %s was just caught using Macroquest to /Gate to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
}
break;
case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified
if (RuleB(Zone, EnableMQGhostDetector) && ((status < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name,this->name, "/MQGhost", zone->GetShortName());
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
SpellFinished((RuleI(Zone, MQGhostDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
worldserver.SendEmoteMessage(0,0,0,13,"<MQGhost Detector>. %s was just caught using Macroquest to /Ghost to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
}
break;
}
}

Change (Insert Red Lines):

dist = sqrt(dist);
/*[Paddy] Cutting out the Z-Axis check. Not necessary and prevents long falls from triggering */
//tmp = z_pos - ppu->z_pos;
//dist += tmp*tmp;

/* Begin Cheat Detection*/
if ((this->cheat_timer.GetRemainingTime())>1 && (this->cheat_timer.Enabled())) //Lieka: Check to see if the cheat (exemption) timer is active - this is for debugging
{
//Spell timer is currently active
//worldserver.SendEmoteMessage(0,0,0,13,"Timer is Active. %d True: %s",this->cheat_timer.GetRemainingTime(), (this->cheat_timer.GetRemainingTime()>1)? "true" : "false"); //Leika Edit: Enable this to get debug messages.
}
else //Timer has elapsed or hasn't started, let's do a Warp Check
{
if ((WarpDetection(false, dist)) && (((admin <= RuleI(Zone, MQWarpExemptStatus)) || (RuleI(Zone, MQWarpExemptStatus) == -1))) //Exempt from warp detection if admin level is > Rule:Zone:MQWarpExemptStatus
{
printf("Warping Detected by %S Acct: %s Distance: %f.", GetName(), AccountName(), GetLWDistance());
CheatDetected(MQWarp); //Lieka: Execute MQWarp function on offending player
}
}
//Lieka End Edit


Change (Insert Red Lines):

void Client::Handle_OP_GMSummon(const EQApplicationPacket *app)
{
if (app->size != sizeof(GMSummon_Struct)) {
cout << "Wrong size on OP_GMSummon. Got: " << app->size << ", Expected: " << sizeof(GMSummon_Struct) << endl;
return;
}
this->cheat_timer.Start(5000, false); //Lieka: Exempt in-zone GM Summons from triggering MQWarp detector
OPGMSummon(app);
return;
}

After:

x_pos = m_pp.x;
y_pos = m_pp.y;
z_pos = m_pp.z;
heading = m_pp.heading;
race = m_pp.race;
base_race = m_pp.race;
gender = m_pp.gender;
base_gender = m_pp.gender;
deity = m_pp.deity;//FYI: DEITY_AGNOSTIC = 396; still valid?
haircolor = m_pp.haircolor;
beardcolor = m_pp.beardcolor;
eyecolor1 = m_pp.eyecolor1;
eyecolor2 = m_pp.eyecolor2;
hairstyle = m_pp.hairstyle;
luclinface = m_pp.face;
// vesuvias - appearence fix
beard = m_pp.beard;

Add:

this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when logging in after LD - basically gives a grace period for large position changes.

After:

case SE_InvisVsUndead:
{
invisible_undead = true;
break;
}
case SE_InvisVsAnimals:
{
invisible_animals = true;
break;
}
}
}
}

Add:

this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when arriving in a new zone.

TheLieka
03-28-2008, 05:27 PM
.\zone\client_process.cpp

Change (Insert Red Lines):

if (ra->action == 1) {
this->cheat_timer.Start(3500, false); //[Paddy] Allow getting rezzed without triggering
cout << "Player " << this->name << " got a " << (int16)spells[ra->spellid].base[0] << "% Rezz" << endl;
this->BuffFadeAll();
SetMana(0);
SetHP(GetMaxHP()/5);
EQApplicationPacket* outapp = app->Copy();
outapp->SetOpcode(OP_RezzComplete);

Change (Insert Red Lines):

void Client::OPGMSummon(const EQApplicationPacket *app)
{
GMSummon_Struct* gms = (GMSummon_Struct*) app->pBuffer;
Mob* st = entity_list.GetMob(gms->charname);

if(st && st->IsCorpse())
{
st->CastToCorpse()->Summon(this, false);
}
else
{
if(admin < 80)
{
return;
}
if(st)
{
this->cheat_timer.Start(3500, false);//[Paddy] Allow PC's to be summoned without triggering Warp Detection
Message(0, "Local: Summoning %s to %i, %i, %i", gms->charname, gms->x, gms->y, gms->z);
if (st->IsClient() && (st->CastToClient()->GetAnon() != 1 || this->Admin() >= st->CastToClient()->Admin()))
st->CastToClient()->MovePC((float)gms->x, (float)gms->y, (float)gms->z, this->GetHeading(), 2, true);
else
st->GMMove(this->GetX(), this->GetY(), this->GetZ(),this->GetHeading());
}
else
{
int8 tmp = gms->charname[strlen(gms->charname)-1];
if (!worldserver.Connected())
{
Message(0, "Error: World server disconnected");
}
else if (tmp < '0' || tmp > '9') // dont send to world if it's not a player's name
{
ServerPacket* pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct));
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer;
strcpy(szp->adminname, this->GetName());
szp->adminrank = this->Admin();
strcpy(szp->name, gms->charname);
strcpy(szp->zone, zone->GetShortName());
szp->x_pos = (float)gms->x;
szp->y_pos = (float)gms->y;
szp->z_pos = (float)gms->z;
szp->ignorerestrictions = 2;
worldserver.SendPacket(pack);
safe_delete(pack);
}
else {
//all options have been exhausted
//summon our target...
this->cheat_timer.Start(3500, false); //Lieka: Don't want to trip the MQWarp detector here either.
if(GetTarget() && GetTarget()->IsCorpse()){
GetTarget()->CastToCorpse()->Summon(this, false);
}
}
}
}
}

.\zone\command.cpp

Change (Insert Red Lines):

else if (t->IsClient())
{
if(c->Admin() < 150)
{
c->Message(0, "You may not summon a player.");
return;
}
t->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Zone-to-Zone GM Summons from triggering the MQZone and MQWarp detectors.
c->Message(0, "Summoning player %s to %1.1f, %1.1f, %1.1f", t->GetName(), c->GetX(), c->GetY(), c->GetZ());
t->CastToClient()->MovePC(zone->GetZoneID(), c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(), 2, GMSummon);
}
}

Change (Insert Red Lines):

if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4)){
//zone to specific coords
c->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Not sure why we put this here... should be an admin if you are zoning to special coordinates by this point.
c->MovePC(zoneid, atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), 0.0f, 0);
}
else {
//zone to safe coords
c->cheat_timer.Start(3500,false); //Lieka: Should only hit this spot if your status is high enough to #zone, but prevent it from triggering the detector anyway.
c->MovePC(zoneid, 0.0f, 0.0f, 0.0f, 0.0f, 0, ZoneToSafeCoords);
}
}

.\zone.mob.h

After:

inline int16 GetRace() const { return race; }
inline int8 GetGender() const { return gender; }
inline int8 GetTexture() const { return texture; }
inline int8 GetHelmTexture() const { return helmtexture; }
inline int8 GetClass() const { return class_; }
inline uint8 GetLevel() const { return level; }
inline const char* GetName() const { return name; }

Add:

float GetLWDistance() { return last_warp_distance; } //Null: these are used to return the values to #showstats
float GetWarpThreshold() { return warp_threshold; } //this one too

Change (Insert Red Lines):

bool fix_pathing;
Timer cheat_timer; //Lieka: Timer used to check for movement exemptions/client-based, unsolicited zone exemptions
Timer threshold_timer; //Null: threshold timer
float warp_threshold; //Null: threshold for warp detector
float last_warp_distance; //Null: last distance logged as a warp, used for logs and #showstats
inline float GetCWPX() const { return(cur_wp_x); }
inline float GetCWPY() const { return(cur_wp_y); }
inline float GetCWPZ() const { return(cur_wp_z); }



.\zone\mob.cpp

Change (Insert Red Lines):

attack_timer(2000),
attack_dw_timer(2000),
ranged_timer(2000),
tic_timer(6000),
mana_timer(2000),
spellend_timer(0),
cheat_timer(0), //Lieka: Timer for MQ Detector exemptions
stunned_timer(0),
bardsong_timer(6000),
threshold_timer(0), //Lieka: Timer to allow exemptions MQWarp related to lag
#ifdef FLEE_HP_RATIO
flee_timer(FLEE_CHECK_TIMER),
#endif
bindwound_timer(10000)
// mezzed_timer(0)
{
targeted = false;
logpos = false;
tar_ndx=0;
tar_vector=0;
tar_vx=0;
tar_vy=0;
tar_vz=0;
tarx=0;
tary=0;
tarz=0;
AI_Init();
SetMoving(false);
moved=false;
warp_threshold = 140; //Null: set the threshold on creation of mob instance
last_warp_distance = 0; //Null: set this one to zero also just because.
_egnode = NULL;
adverrorinfo = 0;
name[0]=0;
clean_name[0]=0;
lastname[0]=0;


Change (Insert Red Lines):

logging_enabled = false;
isgrouped = false;
_appearance = eaStanding;
pRunAnimSpeed = 0;
// guildeqid = GUILD_NONE;

spellend_timer.Disable();
cheat_timer.Disable();
bardsong_timer.Disable();
bardsong = 0;
bardsong_target_id = 0;
casting_spell_id = 0;
target = 0;

Change (Insert Red Lines):

void Mob::ShowStats(Client* client) {
client->Message(0, "Name: %s %s", GetName(), lastname);
client->Message(0, " Level: %i MaxHP: %i CurHP: %i AC: %i Class: %i", GetLevel(), GetMaxHP(), GetHP(), GetAC(), GetClass());
client->Message(0, " MaxMana: %i CurMana: %i ATK: %i Size: %1.1f", GetMaxMana(), GetMana(), GetATK(), GetSize());
client->Message(0, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA());
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR());
client->Message(0, " Race: %i BaseRace: %i Texture: %i HelmTexture: %i Gender: %i BaseGender: %i", GetRace(), GetBaseRace(), GetTexture(), GetHelmTexture(), GetGender(), GetBaseGender());
client->Message(0, " Last Warp Distance: %f Threshold Remaining: %f", GetLWDistance(), GetWarpThreshold()); //Null: added this to check players last warp distance for debuging.
if (client->Admin() >= 100) {
client->Message(0, " EntityID: %i PetID: %i OwnerID: %i AIControlled: %i", this->GetID(), this->GetPetID(), this->GetOwnerID(), this->IsAIControlled());
if (this->IsClient()) {
client->Message(0, " CharID: %i PetID: %i", this->CastToClient()->CharacterID(), this->GetPetID());
client->Message(0, " Endurance: %i, Max Endurance %i",client->GetEndurance(), client->GetMaxEndurance());
}

Change (Insert Red Lines):

if (target->IsClient()) {
target->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Mob Summons from tripping hack detector.
target->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);
}
else
GetHateTop()->GMMove(x_pos, y_pos, z_pos, target->GetHeading());
return true;
}
return false;
}

TheLieka
03-28-2008, 05:30 PM
.\zone\spdat.h

After:

int GetMinLevel(int16 spell_id);
int CalcBuffDuration_formula(int level, int formula, int duration);
sint32 CalculatePoisonCounters(int16 spell_id);
sint32 CalculateDiseaseCounters(int16 spell_id);
sint32 CalculateCurseCounters(int16 spell_id);
bool IsDiscipline(int16 spell_id);
bool IsResurrectionEffects(int16 spell_id);
bool IsRuneSpell(int16 spell_id);
bool IsMagicRuneSpell(int16 spell_id);

Add:

bool IsShadowStepSpell(int16 spell_id);
bool IsSuccorSpell(int16 spell_id);
bool IsTeleportSpell(int16 spell_id);
bool IsGateSpell(int16 spell_id);

.\zone\spdat.cpp

After:

bool IsRuneSpell(int16 spell_id) {
bool Result = false;

if(IsValidSpell(spell_id)) {
for(int i = 0; i < EFFECT_COUNT; i++) {
if(spells[spell_id].effectid[i] == SE_Rune) {
Result = true;
break;
}
}
}

return Result;
}

Add:

bool IsShadowStepSpell(int16 spell_id) {
if (IsEffectInSpell(spell_id, SE_ShadowStep)){
return true;
}
else {
return false;
}
}
bool IsSuccorSpell(int16 spell_id) {
if (IsEffectInSpell(spell_id, SE_Succor)){
return true;
}
else {
return false;
}
}
bool IsTeleportSpell(int16 spell_id) {
if (IsEffectInSpell(spell_id, SE_Teleport)){
return true;
}
else {
return false;
}
}
bool IsGateSpell(int16 spell_id) {
if (IsEffectInSpell(spell_id, SE_Gate)){
return true;
}
else {
return false;
}
}


.\zone\spell_effects.cpp

Change (Insert Red Lines):

case SE_SummonPC:
{
if(IsClient()){
CastToClient()->cheat_timer.Start(3500, false); //Lieka: Exempt spells the "SummonPC" effect from triggering the MQWarp detector.
CastToClient()->MovePC(zone->GetZoneID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);
Message(15, "You have been summoned!");
} else {
caster->Message(13, "This spell can only be cast on players.");
}
break;
}

.\zone\spells.cpp

Change (Insert Red Lines):

if(bard_song_mode)
{
if(IsClient())
{
this->CastToClient()->CheckSongSkillIncrease(spell_id);
//Lieka start Edit: Fixing Warp Detector triggered for Bard Songs
if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
(IsTeleportSpell(spell_id)) ||
(IsSuccorSpell(spell_id)) ||
(IsShadowStepSpell(spell_id)) ||
(IsGateSpell(spell_id)))
{
this->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the bard song effects
}
//Lieka end edit.
}
// go again in 6 seconds
//this is handled with bardsong_timer
// DoCastSpell(casting_spell_id, casting_spell_targetid, casting_spell_slot, 6000, casting_spell_mana);

mlog(SPELLS__CASTING, "Bard song %d should be started", spell_id);
}
else

After:

else
{
if(IsClient())
{
Client *c = CastToClient();
SendSpellBarEnable(spell_id);

// this causes the delayed refresh of the spell bar gems
c->MemorizeSpell(slot, spell_id, memSpellSpellbar);

// this tells the client that casting may happen again
SetMana(GetMana());

// skills
if(slot < MAX_PP_MEMSPELL)
{
c->CheckIncreaseSkill(spells[spell_id].skill);

// increased chance of gaining channel skill if you regained concentration
c->CheckIncreaseSkill(CHANNELING, regain_conc ? 5 : 0);

c->CheckSpecializeIncrease(spell_id);
}

Add:

if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
(IsTeleportSpell(spell_id)) ||
(IsSuccorSpell(spell_id)) ||
(IsShadowStepSpell(spell_id)) ||
(IsGateSpell(spell_id)))
{
c->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects
}

After:

if // Bind Sight line of spells
(
spell_id == 500 || // bind sight
spell_id == 407 // cast sight
)
{
action->target = GetID();
}
else
{
action->target = spelltar->GetID();
}

action->level = caster_level; // caster level, for animation only
action->type = 231; // 231 means a spell
action->spell = spell_id;
action->sequence = (int32) (GetHeading() * 2); // just some random number
action->instrument_mod = GetInstrumentMod(spell_id);
action->buff_unknown = 0;

Add:

//Lieka start Edit: Fixing Warp Detector triggered by spells cast on the player.
if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
(IsTeleportSpell(spell_id)) ||
(IsSuccorSpell(spell_id)) ||
(IsShadowStepSpell(spell_id)) ||
(IsGateSpell(spell_id)))
{
spelltar->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects
}
//Lieka end edit.

.\zone\zone.h

Change:

ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f);

To:

ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f, Client* client = NULL);


.\zone\zone.cpp

Change:

ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance) {

To:

ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance, Client* client) {

Change (Insert Red Lines):

if(closest_dist>(200.0f*200.0f) && closest_dist<max_distance2)
{
client->CheatDetected(MQZone); //[Paddy] Someone is trying to use /zone
LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
LogFile->write(EQEMuLog::Status, "<Real Zone Points>. %f x %f y %fz ",x,y,z);
//worldserver.SendEmoteMessage(0,0,0,13,"<Real Zone Points>. %f x %f y %fz ",x,y,z);
closest_zp = NULL; //Lieka: Prevent the zone request from happening.
}
if(closest_dist > max_distance2)
closest_zp = NULL;

if(!closest_zp)
closest_zp = GetClosestZonePointWithoutZone(x,y,z);

return closest_zp;
}

TheLieka
03-28-2008, 05:32 PM
.\zone\zoning.cpp

After:

case ZoneToSafeCoords:
//going to safe coords, but client dosent know where?
//assume it is this zone for now.

Add:

cheat_timer.Start(35000,false); //Lieka: Allow Zone/Evac to Safe Coords without triggering MQWarp detector.

After:

case GMSummon:

Add:

cheat_timer.Start(35000,false); //Lieka: Allow Inter-Zone GM Summons without triggering MQZone detectors.


After:

case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going.

Add:

cheat_timer.Start(3500,false); //Lieka: Allow Server Forced Zoning without triggering MQZone detector.

After:

case ZoneUnsolicited: //client came up with this on its own.
zone_point = zone->GetClosestZonePointWithoutZone(GetX(), GetY(), GetZ(), ZONEPOINT_NOZONE_RANGE);
if(zone_point) {
//we found a zone point, which is a reasonable distance away
//assume that is the one were going with.

Add:

cheat_timer.Start(3500,false); //Lieka: Allow Zone normal zoning without triggering MQZone detector.

After:

} else {
//unable to find a zone point... is there anything else
//that can be a valid un-zolicited zone request?

Add:

this->CheatDetected(MQZone); //Lieka: Bring down the hammer, they are trying to zone without meeting any of the above criteria.

After:

if(zone_mode == ZoneUnsolicited) {
zone_point = zone->GetClosestZonePoint(GetX(), GetY(), GetZ(), target_zone_id, ZONEPOINT_ZONE_RANGE);
//if we didnt get a zone point, or its to a different zone,
//then we assume this is invalid.
if(!zone_point || zone_point->target_zone_id != target_zone_id) {
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);

Add:

if ((this->cheat_timer.GetRemainingTime())<1 || (!this->cheat_timer.Enabled())){ //Lieka: Disable MQGate Detector if timer is active.
this->CheatDetected(MQGate);
}

Change (Insert Red Lines):

//for now, there are no other cases...

//could not find a valid reason for them to be zoning, stop it.
[color=red] this->CheatDetected(MQZone); //Lieka: Bring down the hammer, we don't let hackers off that easily...
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%s'. Not near a zone point.", GetName(), target_zone_name);
SendZoneCancel(zc);
return;


Change (Insert Red Lines):

//enforce min status and level
if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) {
this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate level or status requirements (i.e. zoning into FearPlane at level 30, etc)
myerror = ZONE_ERROR_NOEXPERIENCE;
}

if(!ignorerestrictions && flag_needed[0] != '\0') {
//the flag needed string is not empty, meaning a flag is required.
if(Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) {
this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate flag.
Message(13, "You must have the flag %s to enter this zone.");
myerror = ZONE_ERROR_NOEXPERIENCE;
}
}

After:

void Client::SendZoneCancel(ZoneChange_Struct *zc) {
//effectively zone them right back to where they were
//unless we find a better way to stop the zoning process.
EQApplicationPacket *outapp;

Add:

cheat_timer.Start(3500,false); //Lieka: Disable MQ Warp & MQ Gate Detector when zoning fails. (not high enough level, etc)

After:

void Client::SendZoneError(ZoneChange_Struct *zc, sint8 err) {
LogFile->write(EQEMuLog::Error, "Zone %i is not available because target wasn't found or character insufficent level", zc->zoneID);

Add:

cheat_timer.Start(3500,false);//Lieka: Disable /Warp & /Gate Detector when zoning fails. (not high enough level, etc)

Change (insert red lines):


switch(zm) {
case EvacToSafeCoords:
this->cheat_timer.Start(2500,false);// Null: added a timers to this location because sometimes the ones in the other locations of code were not doing the job
case ZoneToSafeCoords:
this->cheat_timer.Start(2500,false);
x = zone->safe_x();
y = zone->safe_y();
z = zone->safe_z();
heading = heading;
break;
case GMSummon:
this->cheat_timer.Start(2500,false);
zonesummon_x = x_pos = x;
zonesummon_y = y_pos = y;
zonesummon_z = z_pos = z;
heading = heading;

zonesummon_id = zoneID;
zonesummon_ignorerestrictions = 1;
break;
case ZoneSolicited:
this->cheat_timer.Start(2500,false);
zonesummon_x = x;
zonesummon_y = y;
zonesummon_z = z;
heading = heading;

zonesummon_id = zoneID;
zonesummon_ignorerestrictions = ignorerestrictions;
break;
case GateToBindPoint:
this->cheat_timer.Start(2500,false);
x = x_pos = m_pp.binds[0].x;
y = y_pos = m_pp.binds[0].y;
z = z_pos = m_pp.binds[0].z;
heading = m_pp.binds[0].heading;
break;
case ZoneToBindPoint:
this->cheat_timer.Start(2500,false);
x = x_pos = m_pp.binds[0].x;
y = y_pos = m_pp.binds[0].y;
z = z_pos = m_pp.binds[0].z;
heading = m_pp.binds[0].heading;

zonesummon_ignorerestrictions = 1;
LogFile->write(EQEMuLog::Debug, "Player %s has died and will be zoned to bind point in zone: %s at LOC x=%f, y=%f, z=%f, heading=%f", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading);
break;
case SummonPC:
this->cheat_timer.Start(2500,false);
zonesummon_x = x_pos = x;
zonesummon_y = y_pos = y;
zonesummon_z = z_pos = z;
heading = heading;
break;
default:
LogFile->write(EQEMuLog::Error, "Client::ZonePC() received a reguest to perform an unsupported client zone operation.");
ReadyToZone = false;
break;
}

TheLieka
03-28-2008, 05:36 PM
REQUIRED SQL:

ALTER TABLE `hackers`
ADD COLUMN `zone` TEXT AFTER `hacked`;
ADD COLUMN `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `zone`;

insert into rule_values values (0, Zone:EnableMQWarpDetector, False);
insert into rule_values values (0, Zone:EnableMQZoneDetector, False);
insert into rule_values values (0, Zone:EnableMQGateDetector, False);
insert into rule_values values (0, Zone:EnableMQGhostDetector, False);

insert into rule_values values (0, Zone:MQWarpExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);
insert into rule_values values (0, Zone:MQZoneExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);

insert into rule_values values (0, Zone:MQWarpDetectorDistance, 30);
insert into rule_values values (0, Zone:MQWarpLagThreshold, 140);
insert into rule_values values (0, Zone:MQWarpThresholdTimer, 90000);

insert into rule_values values (0, Zone:MQWarpDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQGateDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQZoneDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQGhostDetectionSpellID, 757);

There are 15 new rules created as a result of this addition. Here is a breakdown of each:

Zone:EnableMQWarpDetector //Lieka: Enable the MQWarp Detector. Set to False to disable this feature.
Zone:EnableMQZoneDetector //Lieka: Enable the MQZone Detector. Set to False to disable this feature.
Zone:EnableMQGateDetector //Lieka: Enable the MQGate Detector. Set to False to disable this feature.
Zone:EnableMQGhostDetector //Lieka: Enable the MQGhost Detector. Set to False to disable this feature.

Zone:MQWarpExemptStatus //Lieka: Required account status to exempt the MQWarpDetector. Set to -1 to disable this feature.
Zone:MQZoneExemptStatus //Lieka: Required account status to exempt the MQWarpDetector. Set to -1 to disable this feature.
Zone:MQGateExemptStatus //Lieka: Required account status to exempt the MQWarpDetector. Set to -1 to disable this feature.
Zone:MQGhostExemptStatus //Lieka: Required account status to exempt the MQWarpDetector. Set to -1 to disable this feature.

Zone:MQWarpDetectorDistance //Lieka: Distance a player must travel between client to server location updates before a warp is registered. 30 allows for beyond GM speed without lag.
Zone:MQWarpLagThreshold //Lieka: Distance beyond the Zone:MQWarpDetectorDistance that a player must travel within the MQWarpThresholdTimer amount of time before tripping the MQWarp detector. Set to 0 to disable this feature.
Zone:MQWarpThresholdTimer //Lieka: Amount of time before the warp_threshold resets to the Zone:MQWarpLagThreshold value. Default: 90000 (900 seconds
Zone:MQWarpDetectionSpellID //Lieka: Which spell ID will be cast on players that incur the hammer of the MQ Detector. This spell will be actually cast don't pick a resistible spell. Default: 757 (Resurrection Effects)
Zone:MQZoneDetectionSpellID //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
Zone:MQGateDetectionSpellID //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
Zone:MQGhostDetectionSpellID //Lieka: Which spell ID will be cast on players that incur the hammer of the MQGhostDetector. This spell will be actually cast don't pick a resistible spell. Default: 757 (Resurrection Effects)

TheLieka
03-28-2008, 05:38 PM
Updating your Zone_Points table for MQZoneDetector.

When an unsolicited zone request comes through (i.e. the client is requesting a zone change), the MQZoneDetector works with the source to determine if the player is within an acceptable distance of a zoneline. These zonelines must be set in your Zone_Points table in order for this feature to work correctly. The majority of the Zone_Points only specify the destination zone points, but have 0, 0, 0 for the source zone points. If it is a zone line (like literally a line), then you put 999999 for the appropriate value. Below is my list, list:

I do not have a complete Zone_Points table, but I do have Old World, FearPlane, HatePlane, and AirPlane updated in my table.

SQL Step 1: Wipe your old world zone lines (I'm assuming that we're all based off of PEQ originally (mine is based from Angelox, but originally still it was PEQ)).

This is a list of zone_points IDs that I have written insert statements for.

delete from zone_points where id = 1 || id = 3 || id = 7 || id = 10 || id = 11 || id = 14 || id = 17 || id = 18 || id = 19 || id = 20 || id = 21 || id = 23 || id = 24 || id = 25 || id = 27 || id = 31 || id = 38 || id = 40 || id = 41 || id = 45 || id = 47 || id = 49 || id = 51 || id = 52 || id = 53 || id = 67 || id = 68 || id = 69 || id = 71 || id = 75 || id = 77 || id = 94 || id = 97 || id = 99 || id = 101 || id = 108 || id = 121 || id = 126 || id = 148 || id = 181 || id = 182 || id = 186 || id = 187 || id = 197 || id = 214 || id = 336 || id = 337 || id = 338 || id = 339 || id = 340 || id = 341 || id = 342 || id = 343 || id = 345 || id = 370 || id = 371 || id = 372 || id = 373 || id = 374 || id = 375 || id = 376 || id = 377 || id = 378 || id = 379 || id = 380 || id = 381 || id = 382 || id = 383 || id = 384 || id = 385 || id = 386 || id = 387 || id = 388 || id = 389 || id = 390 || id = 391 || id = 392 || id = 393 || id = 394 || id = 395 || id = 396 || id = 397 || id = 398 || id = 399 || id = 400 || id = 401 || id = 402 || id = 413 || id = 414 || id = 415 || id = 416 || id = 417 || id = 418 || id = 419 || id = 420 || id = 440 || id = 472 || id = 473 || id = 474 || id = 475 || id = 476 || id = 477 || id = 478 || id = 479 || id = 480 || id = 481 || id = 482 || id = 483 || id = 484 || id = 485 || id = 486 || id = 487 || id = 488 || id = 489 || id = 490 || id = 491 || id = 492 || id = 493 || id = 537 || id = 538 || id = 549 || id = 550 || id = 551 || id = 552 || id = 557 || id = 558 || id = 559 || id = 575 || id = 590 || id = 591 || id = 592 || id = 594 || id = 640 || id = 641 || id = 642 || id = 643 || id = 644 || id = 647 || id = 648 || id = 649 || id = 657 || id = 658 || id = 659 || id = 660 || id = 663 || id = 664 || id = 665 || id = 666 || id = 675 || id = 676 || id = 677 || id = 685 || id = 686 || id = 687 || id = 688 || id = 689 || id = 690 || id = 691 || id = 692 || id = 693 || id = 700 || id = 701 || id = 703 || id = 704 || id = 725 || id = 726 || id = 738 || id = 739 || id = 740 || id = 741 || id = 742 || id = 743 || id = 752 || id = 769 || id = 770 || id = 771 || id = 772 || id = 773 || id = 774 || id = 775 || id = 799 || id = 800 || id = 801 || id = 802 || id = 803 || id = 804 || id = 806 || id = 807 || id = 808 || id = 851 || id = 852 || id = 853 || id = 854 || id = 855 || id = 857 || id = 858 || id = 860 || id = 861 || id = 862 || id = 888 || id = 889 || id = 905 || id = 910 || id = 911 || id = 912 || id = 914 || id = 915 || id = 916 || id = 917 || id = 918 || id = 920 || id = 921 || id = 970 || id = 971 || id = 977 || id = 978 || id = 1142 || id = 1145 || id = 1146 || id = 1147 || id = 1148 || id = 1149 || id = 1150 || id = 1151 || id = 1152 || id = 1153 || id = 1154 || id = 1155 || id = 1158 || id = 1159 || id = 1160 || id = 1161 || id = 1162 || id = 1174 || id = 1218 || id = 1268 || id = 1269 || id = 1270 || id = 1271 || id = 1272 || id = 1273 || id = 1274 || id = 1275 || id = 1276 || id = 1277 || id = 1278 || id = 1314 || id = 1315 || id = 1327 || id = 1328 || id = 1329 || id = 1333 || id = 1750 || id = 1751;

SQL Step 2: Batch the updated zonefiles back in.

insert into zone_points values (1, 'qeynos',1,464,-442,1.5,0,-151,-5,1.5,999,0,2);
insert into zone_points values (3, 'qeynos',2,586,-80,1.5,0,-26,356,1.5,999,0,2);
insert into zone_points values (7, 'qeynos2',9,1395,999999,999999,0,-304.6,999999,999999,999,0,4);
insert into zone_points values (10, 'feerrott',5,-2380,2601,26,0,-766,1034.5,107.2,0,0,72);
insert into zone_points values (11, 'feerrott',77,870.59,-160.11,-6.37,0,-901.31,444.21,-152.87,999,0,202);
insert into zone_points values (14, 'commons',0,0,0,0,0,0,0,-32,128,0,152);
insert into zone_points values (17, 'qey2hh1',2,999999,-15998,0,0,999999,3194,4,999,0,13);
insert into zone_points values (18, 'northkarana',1,999999,3275,-1.4,0,999999,-15844,0,999,0,12);
insert into zone_points values (19, 'northkarana',2,999999,-3100,999999,0,999999,1143.7,999999,999,0,15);
insert into zone_points values (20, 'eastkarana',1,999999,1143.7,999999,0,999999,-3100,999999,999,0,13);
insert into zone_points values (21, 'northkarana',3,-4508.36,999999,-31.27,0,2700,895,-30.03,128,0,14);
insert into zone_points values (23, 'eastkarana',2,3602,-2074,11.22,0,-1187,-443,32,999,0,16);
insert into zone_points values (24, 'beholder',1,-1184.86,-452.33,37.5,0,3371,-2284,51,999,0,15);
insert into zone_points values (25, 'eastkarana',3,-3088,-8339,693,0,835,109,3.13,999,0,5);
insert into zone_points values (27, 'southkarana',2,-3143,931,-9,0,-79.3,-7.9,4,999,0,18);
insert into zone_points values (31, 'beholder',2,907,-1846,4.75,0,-116.69,-23.31,4,999,0,11);
insert into zone_points values (38, 'highkeep',1,56.81,96.21,3.13,0,63.33,-106.07,3.13,999,0,5);
insert into zone_points values (40, 'commons',1,900,4180,-48,0,1464.44,-1088.05,-48,999,0,20);
insert into zone_points values (41, 'kithicor',3,1464,-1089,-48,0,904.3,4216,-48.97,999,0,21);
insert into zone_points values (45, 'commons',2,999999,-1621,999999,0,999999,5045,999999,999,0,22);
insert into zone_points values (47, 'commons',3,-1146,597,-39,0,-75.27,35.22,3.13,999,0,36);
insert into zone_points values (49, 'ecommons',2,999999,5050,999999,0,10.3,-1475,-51,65,0,21);
insert into zone_points values (51, 'ecommons',3,999999,-1600,999999,0,-28,775,-24,191,0,9);
insert into zone_points values (52, 'nektulos',1,2250.9,-1110.4,1.8,0,12,158,31,999,0,40);
insert into zone_points values (53, 'ecommons',4,1552,649,-17,0,-2698,-653,999999,999,0,25);
insert into zone_points values (67, 'nektulos',2,41,156,32,0,1529,614,-18,999,0,22);
insert into zone_points values (68, 'nektulos',5,-2702.2,-660.4,-18,0,1529,614,-18,999,0,22);
insert into zone_points values (69, 'nektulos',3,3107,289,-17,0,-2091,-205,-14,0,0,27);
insert into zone_points values (71, 'gukbottom',7,0,0,0,0,1630,359,-88,999,0,65);
insert into zone_points values (75, 'lavastorm',2,1349,330,3,0,268.8,7.5,3,0,0,80);
insert into zone_points values (77, 'guktop',7,0,0,0,0,1667,-136,-98,360,0,66);
insert into zone_points values (94, 'feerrott',1,-1132,-3124.12,-9.22,0,-1132.7,1888.8,-9,226.9,0,46);
insert into zone_points values (97, 'feerrott',2,364.44,3415.17,3.13,0,1007.7,-2864.3,17,59.1,0,50);
insert into zone_points values (99, 'feerrott',4,1667,808,60,0,-385.27,-96.32,3.5,2.5,0,49);
insert into zone_points values (101, 'feerrott',3,-1451.82,-111.83,51,0,70.4,-65.1,3.1,64,0,48);
insert into zone_points values (108, 'southkarana',4,2900,999999,-31,0,-4472,1206,-30.03,0,0,13);
insert into zone_points values (121, 'erudsxing',1,0,0,3,0,115,325,23.75,360,0,24);
insert into zone_points values (126, 'felwithea',1,-1943,-2595,25,0,6,255,3,0,0,54);
insert into zone_points values (148, 'akanon',1000,54,-76,2,0,-2062,528,-110,999,0,56);
insert into zone_points values (181, 'erudnint',1,0,0,0,0,712,806,22,999,0,23);
insert into zone_points values (182, 'erudnint',2,711.4,793,5.8,63.6,-770,-182,54,0,0,24);
insert into zone_points values (186, 'butcher',4,1355,3239,11.75,0,410.05,-9171.42,10,999,0,69);
insert into zone_points values (187, 'oasis',3,0,0,3,0,0,0,3,0,0,93);
insert into zone_points values (197, 'highkeep',2,-91.98,91.48,3.13,0,-88.57,-107.04,3.13,999,0,5);
insert into zone_points values (214, 'qeynos',5,276,-552,-52,0,339,-175,-67,999,0,45);
insert into zone_points values (336, 'felwithea',2,350,-720,-10,0,244,-834,-10,0,0,62);
insert into zone_points values (337, 'felwithea',3,43,210,3,0,-1931,-2632,21,0,128,54);
insert into zone_points values (338, 'gfaydark',1,-1934,-2597,23,0,40,200,4,999,0,61);
insert into zone_points values (339, 'gfaydark',2,-2612,-1112,3.13,0,2175,-1202,3.13,999,0,57);
insert into zone_points values (340, 'gfaydark',3,-1641,2665,3.13,0,-1320,-3082,3.13,999,0,68);
insert into zone_points values (341, 'gfaydark',4,2600,-55,19,0,-660,162,4,999,0,58);
insert into zone_points values (342, 'gfaydark',177,-182,-744,-1.3,0,838,882,-157,999,0,202);
insert into zone_points values (343, 'gfaydark',178,-2245,-1820,0.4,0,812,97,-157,999,0,202);
insert into zone_points values (345, 'crushbone',1,-632,163,3.13,0,2608,-55,18.5,999,0,54);
insert into zone_points values (370, 'felwitheb',1,244,-834,-10,0,344,-720,-10,0,0,61);
insert into zone_points values (371, 'felwitheb',2,0,0,0,0,524,-497,-2,0,0,62);
insert into zone_points values (372, 'felwitheb',3,0,0,0,0,583,-602,-5,0,0,62);
insert into zone_points values (373, 'felwitheb',4,0,0,0,0,484,-717,-4,0,0,62);
insert into zone_points values (374, 'felwitheb',5,0,0,0,0,301,-587,-10,0,0,62);
insert into zone_points values (375, 'felwitheb',6,0,0,0,0,301,-587,-10,0,0,62);
insert into zone_points values (376, 'felwitheb',7,0,0,0,0,301,-587,-10,0,0,62);

TheLieka
03-28-2008, 05:45 PM
SQL Part 2: Continued

insert into zone_points values (377, 'freporte',9,100,-64,-24,0,-84,-926,-28,999,0,9);
insert into zone_points values (378, 'freporte',10,448,-360,-28,0,-418,-622,-28,999,0,9);
insert into zone_points values (379, 'freporte',11,-1306,999999,-52.21,0,4131,332,-24.28,999,0,34);
insert into zone_points values (380, 'freporte',53,-155,344,-94,0,-740,-1632,-94,999,0,9);
insert into zone_points values (381, 'freportw',5,149,-716,-11,0,12,-656,-55,999,0,9);
insert into zone_points values (382, 'freportw',6,96,-652,-39,0,147,-682,-13,999,0,9);
insert into zone_points values (383, 'freportw',7,270,-699,-25,0,-376,-83,999999,999,0,8);
insert into zone_points values (384, 'freportw',8,225,-126,-10,0,-415,491,999999,999,0,8);
insert into zone_points values (385, 'freportw',9,-84,-926,-28,0,100,-64,-24,999,0,10);
insert into zone_points values (386, 'freportw',10,-418,-622,-28,0,448,-360,-28,999,0,10);
insert into zone_points values (387, 'freportw',12,999999,775,-24,0,999999,-1592,-54,999,0,22);
insert into zone_points values (388, 'freportw',51,1585,-272,2,0,372,722,-8,999,0,8);
insert into zone_points values (389, 'freportw',52,719,-586,-20,0,-2,-441,-18,999,0,8);
insert into zone_points values (390, 'freportw',53,-740,-1632,-94,0,-155,344,-94,999,0,10);
insert into zone_points values (391, 'freportw',177,0,0,0,0,-406,-234,-157,258,0,202);
insert into zone_points values (392, 'freportn',7,-379,-83,-25,0,267,-700,999999,0,0,9);
insert into zone_points values (393, 'freportn',8,-415,491,-11,0,227,-124,999999,0,0,9);
insert into zone_points values (394, 'freportn',51,372,722,-11,0,1590,-275,4,0,0,9);
insert into zone_points values (395, 'freportn',52,-6,-436,-20,0,730,-581,-18,0,0,9);
insert into zone_points values (396, 'grobb',1,-133,50,3.13,0,-2827,-665.3,-30,127.5,0,46);
insert into zone_points values (397, 'halas',1,-692.79,-77.88,3.13,0,3684,380,5,999,0,30);
insert into zone_points values (398, 'kaladima',1,-64.45,42.17,3.13,0,3131,-179,3.13,999,0,68);
insert into zone_points values (399, 'kaladima',2,419.97,333.59,-18.15,0,416,340,-22,999,0,67);
insert into zone_points values (400, 'kaladima',3,390,-264,3.13,0,354,-224,4,999,0,67);
insert into zone_points values (401, 'kaladimb',1,416,340,-22,0,419.97,333.59,-18.15,999,0,60);
insert into zone_points values (402, 'kaladimb',2,354,-224,4,0,390,-264,4,999,0,60);
insert into zone_points values (413, 'neriaka',1,0,0,0,0,-242,999999,999999,999,0,41);
insert into zone_points values (414, 'neriaka',2,86,-354,-11,0,999999,-367,999999,999,0,41);
insert into zone_points values (415, 'neriaka',3,29,155,30,0,2252,-1105,1,999,0,25);
insert into zone_points values (416, 'neriakb',1,0,0,0,0,-247,999999,999999,999,0,40);
insert into zone_points values (417, 'neriakb',2,86,-401,-11,0,999999,-361,999999,999,0,40);
insert into zone_points values (418, 'neriakb',3,200,-852,-39,0,206,999999,999999,999,0,42);
insert into zone_points values (419, 'neriakc',1,205,-852,-39,0,200,999999,999999,999,0,41);
insert into zone_points values (420, 'neriakc',2,0,0,0,0,-876,1146,-1,252,0,57);
insert into zone_points values (440, 'oggok',1,-396,-90,4,0,1609,901.4,58,126,0,47);
insert into zone_points values (472, 'qeynos',3,0,0,0,0,230,-64,-80,129,0,45);
insert into zone_points values (473, 'qeynos',4,177,-477,-16,0,307,-184,-38,250,0,45);
insert into zone_points values (474, 'qeynos',22,-185,149,-64,0,-175,147,-77,999,0,45);
insert into zone_points values (475, 'qeynos',33,-151,-596,-25,0,217,-301,-38,999,0,45);
insert into zone_points values (476, 'qeynos2',1,0,0,0,0,-168,-714,-10,999,0,2);
insert into zone_points values (477, 'qeynos2',2,0,0,0,0,-30,-153,9,250,0,2);
insert into zone_points values (478, 'qeynos2',4,0,0,0,0,-175,141,-80,384,0,45);
insert into zone_points values (479, 'qeynos2',5,175,90,-39,0,637,105,-38,999,0,45);
insert into zone_points values (480, 'qeynos2',6,194,348,-27,0,889,217,-50,999,0,45);
insert into zone_points values (481, 'qeynos2',14,0,0,0,0,893,756,-82,0,0,2);
insert into zone_points values (482, 'qeynos2',77,0,0,0,0,147,-289,-157,383,0,202);
insert into zone_points values (483, 'qeynos2',99,308,-161,4,0,1057,-49,-43,999,0,45);
insert into zone_points values (484, 'qcat',1,-175,147,-77,0,-189,127,-90,999,0,1);
insert into zone_points values (485, 'qcat',2,217,-301,-38,0,-147,-608,-24,999,0,1);
insert into zone_points values (486, 'qcat',3,307,-184,-38,0,175,-483,-27,999,0,1);
insert into zone_points values (487, 'qcat',4,339,-175,-67,0,273,-553,-62,999,0,1);
insert into zone_points values (488, 'qcat',5,637,105,-40,0,175,90,-38,999,0,2);
insert into zone_points values (489, 'qcat',6,889,217,-50,0,190,340,-30,999,0,2);
insert into zone_points values (490, 'qcat',7,0,0,0,0,1122,-852,-50,275,0,38);
insert into zone_points values (491, 'qcat',99,1051,-49,-58,0,302,-161,-13,999,0,2);
insert into zone_points values (492, 'rivervale',98,-371,-278,4,0,2022,3825,463,999,0,20);
insert into zone_points values (493, 'rivervale',99,0,0,0,0,410,-2552,-4,999,0,33);
insert into zone_points values (537, 'qrg',5,-594.8,211.9,2.8,0,5100.9,196.7,-1,128,0,4);
insert into zone_points values (538, 'qrg',7,47.4,-512.2,42.8,129.6,47.4,-512.2,42.8,0,0,3);
insert into zone_points values (549, 'butcher',1,-1312,-3070,3.75,0,-1650,2673,1,999,0,54);
insert into zone_points values (550, 'butcher',2,3114.75,-186.57,3.75,0,-64,42,4,999,0,60);
insert into zone_points values (551, 'butcher',3,-2929,-344,3.75,0,2856,262,473,999,0,70);
insert into zone_points values (552, 'butcher',77,1752,-502,1,0,829,474,-157,999,0,202);
insert into zone_points values (557, 'cauldron',1,2856,262,472.47,0,-2935,-337,3.13,999,0,68);
insert into zone_points values (558, 'cauldron',2,-1167,-1013,-330,0,100,30,326,999,0,64);
insert into zone_points values (559, 'cauldron',3,-2002.06,-627.76,93.15,0,64,330,3.13,999,0,63);
insert into zone_points values (575, 'ecommons',1,-2462,-105,3.13,0,2604,2903,3.13,999,0,34);
insert into zone_points values (590, 'everfrost',1,3700,370,3,0,-676,-76.46,3.13,999,0,29);
insert into zone_points values (591, 'everfrost',2,-3061,-530,-109,0,95,-340,4,999,0,17);
insert into zone_points values (592, 'everfrost',3,2020,-7048,-60,0,-60,100,4,999,0,73);
insert into zone_points values (594, 'everfrost',77,2884.4,-75,-60,0,846,131,-157,999,0,202);
insert into zone_points values (640, 'innothule',1,2569.11,1140.77,-24.78,0,-3203,1098,-21,192.2,0,35);
insert into zone_points values (641, 'innothule',2,-1131.29,1893.76,-9.22,0,-1102,-3100.5,-9,8,0,47);
insert into zone_points values (642, 'innothule',3,-2763.64,-615.55,-31.44,0,-95.1,-2.3,3.1,9.1,0,52);
insert into zone_points values (643, 'innothule',4,140.98,-827.97,-8.37,0,-36,7.4,3,255.5,0,65);
insert into zone_points values (644, 'innothule',77,-731.99,-30.93,-25.78,0,-812,95,-157,999,0,202);
insert into zone_points values (647, 'kerraridge',1,467.9,-915.7,23,60.3,-512,2653,-34.5,194.8,0,38);
insert into zone_points values (648, 'kithicor',1,644,4890,693,0,-979,91,4,999,0,5);
insert into zone_points values (649, 'kithicor',2,2007,3825,465,0,-369,-282,4,999,0,19);
insert into zone_points values (657, 'lavastorm',1,-937.4,-1063,16,0,-15,856,5,999,0,44);
insert into zone_points values (658, 'lavastorm',25,-2117.83,-194.11,-16.45,0,3107,289,-17,999,0,25);
insert into zone_points values (659, 'lavastorm',31,798,223,129,0,-476.07,-485.77,73.72,999,0,31);
insert into zone_points values (660, 'lavastorm',32,915,483,54,0,-413,-265,-112,999,0,32);
insert into zone_points values (663, 'lfaydark',1,925,-2185,0,0,579,2205,-112,999,0,56);
insert into zone_points values (664, 'lfaydark',2,2179,-1213,0,0,-2624,-1113,1,999,0,54);
insert into zone_points values (665, 'lfaydark',3,-1111,3360,4,0,-347,126,-182,999,0,59);
insert into zone_points values (666, 'lfaydark',9,0,0,0,0,910,-1775,-75,226,0,42);
insert into zone_points values (675, 'misty',1,-834,1432,-7,0,228,152,6,999,0,11);
insert into zone_points values (676, 'misty',2,410,-2588,-7,0,-79,78,5,1470,0,19);
insert into zone_points values (677, 'misty',77,0,0,0,0,830,1227,-157,511,0,202);
insert into zone_points values (685, 'nektulos',77,0,0,0,0,-841,132,-157,257,0,202);
insert into zone_points values (686, 'nro',1,4175,999999,-24.27,0,-1097,999999,-52.22,999,0,10);
insert into zone_points values (687, 'nro',2,-1889,999999,3,0,2501.1,999999,999999,999,0,37);
insert into zone_points values (688, 'nro',3,2626,2908,4,0,-2461,-152,4,999,0,22);
insert into zone_points values (689, 'nro',4,0,0,0,0,5330,390,-15,322,0,110);
insert into zone_points values (690, 'northkarana',0,0,0,0,0,0,0,-32,128,0,152);
insert into zone_points values (691, 'northkarana',6,0,0,0,0,0,0,-25,0,0,152);
insert into zone_points values (692, 'oasis',1,2545,999999,999999,0,-1876,999999,999999,999,0,34);
insert into zone_points values (693, 'oasis',2,-1876,255,5,0,1530,95.6,7,104.9,0,35);
insert into zone_points values (700, 'qeytoqrg',1,-304.6,999999,999999,0,1395,999999,999999,999,0,2);
insert into zone_points values (701, 'qeytoqrg',2,1222,-2468,-1,0,36,45,999999,999,0,12);
insert into zone_points values (703, 'qeytoqrg',3,3436,-1135,3,0,-162.1,16.05,3.8009,999,0,17);
insert into zone_points values (704, 'qeytoqrg',4,5199,69,-3,0,-65.9,136.9,4,241,0,3);
insert into zone_points values (725, 'rathemtn',1,3411,3036,-1.4,0,2518,-2282,4,999,0,51);
insert into zone_points values (726, 'rathemtn',2,416,-3108,3,0,377,3424,2,999,0,47);
insert into zone_points values (738, 'sro',1,1535,196,5,0,-1899,95.6,7,11.2,0,37);
insert into zone_points values (739, 'sro',2,-3207,1137,-23,0,2563,1153,-23,117.1,0,46);
insert into zone_points values (740, 'southkarana',1,-8554,1144,3,0,4374,1151,1,999,0,51);
insert into zone_points values (741, 'steamfont',1,-2056,526,-107,0,54,-77,4,999,0,55);
insert into zone_points values (742, 'steamfont',2,590,2212,-110,0,918,-2177,-4,999,0,57);

TheLieka
03-28-2008, 05:47 PM
SQL Part 2: Concluded

insert into zone_points values (743, 'steamfont',77,0,0,0,0,-401,-76,-157,255,0,202);
insert into zone_points values (752, 'soltemple',1,243,56,2,0,1322.4,280.9,149,128,0,27 );
insert into zone_points values (769, 'tox',0,-1518.6,-919.3,-37.4,0,0,0,-32,128,0,152);
insert into zone_points values (770, 'tox',1,2515.4,222.29,-44.72,0,-1556,-184,-45,999,0,24);
insert into zone_points values (771, 'tox',2,-2627,-431,-41,0,878.4,101.5,3.8,92.5,0,75);
insert into zone_points values (772, 'tox',3,-512,2653,-34.5,62,467.9,-915.7,24,60.3,0,74);
insert into zone_points values (773, 'tox',4,0,0,0,0,266,203,-38,0,0,45);
insert into zone_points values (774, 'tox',77,2326,-580,-45,0,662,36,-157,256,0,202);
insert into zone_points values (775, 'tox',177,-2339,284,-47,0,-840,1227,-157,257,0,202);
insert into zone_points values (799, 'qey2hh1',1,0,0,0,0,1238,-2449,-2,999,0,4);
insert into zone_points values (800, 'arena',1,-57.43,-844.61,12.02,0,2346.56,2676.59,97,999,0,51);
insert into zone_points values (801, 'befallen',1,-75.27,35.22,3.75,0,-1150,596,-38,999,0,21);
insert into zone_points values (802, 'blackburrow',1,-158.97,38.92,3.75,0,3431,-1155,3.75,999,0,4);
insert into zone_points values (803, 'blackburrow',2,94.53,-345.21,3.75,0,-3058,-530,-109,999,0,30);
insert into zone_points values (804, 'blackburrow',7,163.07,148.64,-155.19,0,270,2730,-2,999,0,181);
insert into zone_points values (806, 'lakerathe',1,2513,-2280,5,0,3411,3036,-2,999,0,50);
insert into zone_points values (807, 'lakerathe',2,2347.52,2704.3,95,0,-59,-841,9,999,0,77);
insert into zone_points values (808, 'lakerathe',3,4376.63,1155.48,3.13,0,-8563,1156,4,999,0,14);
insert into zone_points values (851, 'guktop',1,1632,353,-87,0,1667,-136,-98,0,0,66);
insert into zone_points values (852, 'guktop',2,1535,-71,-98,0,1498,-13,-94,0,0,66);
insert into zone_points values (853, 'guktop',4,1134,608,-81,0,1127,650,-85,999,0,66);
insert into zone_points values (854, 'guktop',5,1196,-192,-78,0,1196,-212,-78,0,0,66);
insert into zone_points values (855, 'guktop',6,-63.68,41.72,3.13,0,172.2,-811.6,-7,65.1,0,46);
insert into zone_points values (857, 'gukbottom',1,1667,-136,-98,0,1630,359,-88,0,0,65);
insert into zone_points values (858, 'gukbottom',2,1498,-13,-94,0,1527,-59,-94,0,0,65);
insert into zone_points values (860, 'gukbottom',4,1127,650.56,-88,0,1134,608,-81,999,0,65);
insert into zone_points values (861, 'gukbottom',5,1196,-212,-81,0,1196,-192,-78,0,0,65);
insert into zone_points values (862, 'gukbottom',3,0,0,0,0,170,-818,-9,0,0,46);
insert into zone_points values (888, 'mistmoore',1,-350,123,-178,0,-1115,3359,4,999,0,57);
insert into zone_points values (889, 'najena',1,-19,869,4,0,-936,-1058,13,999,0,27);
insert into zone_points values (905, 'permafrost',1,0,0,0,0,2022,-7073,-55,999,0,30);
insert into zone_points values (910, 'soldunga',1,-443,-525,70,0,783.95,227.54,127.36,999,0,27);
insert into zone_points values (911, 'soldunga',2,-303,-507,25,0,-273,-506,25,999,0,32);
insert into zone_points values (912, 'soldunga',3,-1080,-541,-0.9,0,-1081,-518,-0.9,999,0,32);
insert into zone_points values (914, 'soldunga',5,-361,-384,13,0,-364,-413,11,999,0,32);
insert into zone_points values (915, 'soldunga',6,-705,-450,-12,128,-706,-434,-29,52,0,32);
insert into zone_points values (916, 'soldunga',7,-286,-506,25,0,-278,999999,999999,999,0,32);
insert into zone_points values (917, 'soldunga',8,-165,-551,26,0,-166,-582,17,999,0,32);
insert into zone_points values (918, 'soldunga',9,-986,-566,2,0,-977,-475,-28,128,0,32);
insert into zone_points values (920, 'soldunga',11,0,0,0,0,-371,999999,999999,999,0,32);
insert into zone_points values (921, 'soldunga',12,-872,-391,11,0,-907,-381,10,128,0,31);
insert into zone_points values (970, 'paw',1,0,0,0,0,-3143,931,-11,999,0,14);
insert into zone_points values (971, 'unrest',1,81,335,3,0,-2032,-626,91,999,0,70);
insert into zone_points values (977, 'qeynos2',7,-151,-5,1.5,0,464,-442,1.5,999,0,1);
insert into zone_points values (978, 'qeynos2',8,-26,356,1.5,0,586,-80,1.5,999,0,1);
insert into zone_points values (1142, 'kedge',1,0,0,0,0,-1182,-1009,-334,999,0,70);
insert into zone_points values (1145, 'highpass',1,844.8,105.4,4.1,0,-3097,-8338,690,999,0,15);
insert into zone_points values (1146, 'highpass',2,-981,92,431,0,557,4892,691,999,0,20);
insert into zone_points values (1147, 'soldungb',1,-413,-265,-112,0,911.18,484.37,57.44,999,0,27);
insert into zone_points values (1148, 'soldungb',2,-281,-506,25,0,-295,-505,26,144,0,31);
insert into zone_points values (1149, 'soldungb',3,-1084,-536,0,0,-1084,-538,0,999,0,31);
insert into zone_points values (1150, 'soldungb',4,0,0,0,0,999999,-454,999999,999,0,31);
insert into zone_points values (1151, 'soldungb',5,-365,-400,11,0,-372,-381,13,122,0,31);
insert into zone_points values (1152, 'soldungb',6,-361,-400,11,0,999999,-398,999999,999,0,31);
insert into zone_points values (1153, 'soldungb',7,-281,-506,25,0,-176,-537,29,157,0,31);
insert into zone_points values (1154, 'soldungb',8,0,0,0,0,999999,-570,21,999,0,31);
insert into zone_points values (1155, 'soldungb',9,-996,-489,-24,0,-972,-504,-22,128,0,31);
insert into zone_points values (1158, 'runnyeye',1,0,0,0,0,903,-1844,4,999,0,16);
insert into zone_points values (1159, 'runnyeye',2,248,141,4,0,-830,1431,-9,999,0,33);
insert into zone_points values (1160, 'erudnext',1,-1398.23,-256.76,-40.28,128,-1410.7,-184.5,38,999,0,24);
insert into zone_points values (1161, 'erudnext',2,-1408.01,-308.03,40.7,0,-1410.7,-310.3,-42,128,0,24);
insert into zone_points values (1162, 'erudnext',3,-1556,-184,-45,999,2550,296,-48,999,0,38);
insert into zone_points values (1174, 'cazicthule',1,70.4,-65.1,3.1,64,-1464,-107,52,5,0,47);
insert into zone_points values (1218, 'fearplane',1,844,482,142,0,-2288,2605,1,999,0,47);
insert into zone_points values (1268, 'paineel',1,891,105,4,0,-2607,-429,-42,40,0,38);
insert into zone_points values (1269, 'paineel',2,0,0,0,0,669.6,300,-69.4,148.6,0,39);
insert into zone_points values (1270, 'paineel',3,735,-884,-33,0,746,-900,-34,192,0,101);
insert into zone_points values (1271, 'paineel',4,601.3,-940.8,-94.2,0,800,200,0,0,0,75);
insert into zone_points values (1272, 'paineel',5,0,0,0,0,725,999999,999999,999,0,75);
insert into zone_points values (1273, 'paineel',10,910.9,523.3,-118.2,0,959,557.3,-79,64,0,75);
insert into zone_points values (1274, 'paineel',11,959,557.3,-79,192,906,525,-121,128,0,75);
insert into zone_points values (1275, 'paineel',12,881.6,755.9,-77.2,124.9,1068.7,658.2,-36.2,128,0,75);
insert into zone_points values (1276, 'paineel',13,1085.8,657.7,-35.3,128,464,217,41,0,0,75);
insert into zone_points values (1277, 'paineel',14,1068.7,658.2,-35.2,0,886,755,-77,0,0,75);
insert into zone_points values (1278, 'paineel',15,476,217,43.7,0,1091,658,-41,0,0,75);
insert into zone_points values (1314, 'warrens',2,-92.4,1142,-107.2,59.8,712,-876,-33,107,0,75);
insert into zone_points values (1315, 'warrens',3,750,-887,-33,0,712,-876,-33,107,0,75);
insert into zone_points values (1327, 'erudnext',4,-645,-193.6,77.7,65,712,807,22,192,0,23);
insert into zone_points values (1328, 'highpass',3,-91.5,-112.6,4.1,0,-16,88,4.1,192.2,0,6);
insert into zone_points values (1329, 'highpass',4,62.8,-112.6,4.1,0,-16,88,4.1,192.2,0,6);
insert into zone_points values (1333, 'soldungb',12,-705,-450,-12,0,-681,-463,-20,34,0,31);
insert into zone_points values (1750, 'erudnext',5,-645.1,-271.1,-70.7,192.4,-394.1,-6.6,41.8,0,0,24);
insert into zone_points values (1751, 'erudnext',6,-344.1,-10,39.8,0,-770,-183,54.7,0,0,24);

Holy shit - ok, I wonder if anyone else will actually make it through all that. ;) Nonetheless, that's the pride and joy of VZ/TZ - enjoy it and keep those hackers at bay. :)

Thanks,
Dax

TheLieka
03-28-2008, 06:22 PM
dammit, I missed AirPlane:

delete from zone_points where id = 1163 || id = 1164 || id = 1165 || id = 1166 || id = 1167 || id = 1168 || id = 1169 || id = 1170 || id = 1171 || id = 1172 || id = 1173;

insert into zone_points values (1163, 'airplane', 1, 0, 0, 0, 0, -387, 415, 132, 0, 0, 37);
insert into zone_points values (1164, 'airplane', 3, 0, 0, 0, 0, 516, 1108, -8, 999, 0, 71);
insert into zone_points values (1165, 'airplane', 4, 0, 0, 0, 0, -103, -434, -359, 999, 0, 71);
insert into zone_points values (1166, 'airplane', 5, 0, 0, 0, 0, 564, 320, -55, 0, 0, 71);
insert into zone_points values (1167, 'airplane', 6, 0, 0, 0, 0, 1185, -781, 130, 999, 0, 71);
insert into zone_points values (1168, 'airplane', 7, 0, 0, 0, 0, -884, 1089, 412, 999, 0, 71);
insert into zone_points values (1169, 'airplane', 8, 0, 0, 0, 0, -750, 306, 772, 999, 0, 71);
insert into zone_points values (1170, 'airplane', 9, 0, 0, 0, 0, -984, -471, 1013, 999, 0, 71);
insert into zone_points values (1171, 'airplane', 10, 0, 0, 0, 0, -262, -1294, 1221, 999, 0, 71);
insert into zone_points values (1172, 'airplane', 11, 999999, 999999, -2000, 999, -41.52, -1552.49, -70.81, 999, 0, 10);
insert into zone_points values (1173, 'airplane', 12, 0, 0, 0, 0, 1463, 574, -765, 250, 0, 71);

Dax

moydock
03-28-2008, 07:42 PM
Holy. Shit. Much appreciation Dax. I'll post results, may take me a few days :).

Aramid
03-29-2008, 12:45 AM
REQUIRED SQL:

insert into rule_values values (0, Zone:MQWarpExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);
insert into rule_values values (0, Zone:MQZoneExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);



You have a duplicate Zone:MQGateExemptStatus rule in your sql. Should the last one have been :


insert into rule_values values (0, Zone:MQGhostExemptStatus, 50); ?

mattmeck
03-29-2008, 04:44 AM
I just have to say..


Thank you for sharing, this is big and will help the community.

cavedude
03-29-2008, 05:09 AM
This is wonderful, and I can't wait to try it out! However...

Could you post a diff against working code? Linux isn't liking client_packet.cpp at all and I want to rule out copy/paste errors on my part. (Though, there are a couple of typos as well, for example):

AddBuff(this,(RuleI(Zone, MQZoneDetectionSpell)),30);

under Client::CheatDetected

needs to be:

AddBuff(this,(RuleI(Zone, MQZoneDetectionSpellID)),30);

Also, "False" in ruletypes.h needs to be "false", for Linux anyway.

Thanks for sharing this, it certainly is brilliantly written besides the minor typos here and there.

TheLieka
03-29-2008, 06:56 AM
Sorry for the typos with the rules system (I put it together for the submission). I'll see if I can get you a diff, but we've deviated quite a bit from the standard build, so it will take me a bit. I'll see if I can get one together.

Dax

cavedude
03-29-2008, 07:01 AM
I understand completely, getting a clean diff from TGC wouldn't be easy either so I sympathize.

TheLieka
03-29-2008, 09:39 AM
Ok, sorry for the false start. Yeah there were a few typos, etc with the previous code, I went through it again, and got a diff from it and 0.7.0-1102

Index: common/database.cpp

================================================== =================

--- common/database.cpp (revision 110)

+++ common/database.cpp (working copy)

@@ -1458,6 +1458,24 @@

return true;
}

+bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka: Utilize the "hacker" table, but also give zone information.

+ char errbuf[MYSQL_ERRMSG_SIZE];

+ char *query = 0;

+ int32 affected_rows = 0;

+ if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {

+ cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;

+ return false;

+ }

+ safe_delete_array(query);

+

+ if (affected_rows == 0)

+ {

+ return false;

+ }

+

+ return true;

+}
+
int8 Database::GetRaceSkill(int8 skillid, int8 in_race)
{
int16 race_cap = 0;
Index: common/database.h

================================================== =================

--- common/database.h (revision 110)

+++ common/database.h (working copy)

@@ -118,6 +118,7 @@

bool MoveCharacterToZone(int32 iCharID, const char* iZonename);
bool UpdateName(const char* oldname, const char* newname);
bool SetHackerFlag(const char* accountname, const char* charactername, const char* hacked);
+ bool SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
bool AddToNameFilter(const char* name);
bool ReserveName(int32 account_id, char* name);
bool CreateCharacter(uint32 account_id, char* name, int16 gender, int16 race, int16 class_, int8 str, int8 sta, int8 cha, int8 dex, int8 int_, int8 agi, int8 wis, int8 face);
Index: common/ruletypes.h

================================================== =================

--- common/ruletypes.h (revision 110)

+++ common/ruletypes.h (working copy)

@@ -65,6 +65,21 @@

RULE_INT ( Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT ( Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
RULE_BOOL ( Zone, EnableShadowrest, 0 ) // enables or disables the shadowrest zone feature for player corpses. Default is turned off.
+RULE_INT ( Zone, MQWarpExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.

+RULE_INT ( Zone, MQZoneExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.

+RULE_INT ( Zone, MQGateExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.

+RULE_INT ( Zone, MQGhostExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.

+RULE_BOOL ( Zone, EnableMQWarpDetector, false ) //Lieka: Enable the MQWarp Detector. Set to False to disable this feature.

+RULE_BOOL ( Zone, EnableMQZoneDetector, false ) //Lieka: Enable the MQZone Detector. Set to False to disable this feature.

+RULE_BOOL ( Zone, EnableMQGateDetector, false ) //Lieka: Enable the MQGate Detector. Set to False to disable this feature.

+RULE_BOOL ( Zone, EnableMQGhostDetector, false ) //Lieka: Enable the MQGhost Detector. Set to False to disable this feature.

+RULE_REAL ( Zone, MQWarpDetectorDistance, 30 ) //Lieka: Distance a player must travel between client to server location updates before a warp is registered. 30 allows for beyond GM speed without lag.

+RULE_REAL ( Zone, MQWarpLagThreshold, 140 ) //Lieka: Distance beyond the Zone:MQWarpDetectorDistance that a player must travel within the MQWarpThresholdTimer amount of time before tripping the MQWarp detector. Set to 0 to disable this feature.

+RULE_REAL ( Zone, MQWarpThresholdTimer, 90000 ) //Lieka: Amount of time before the warp_threshold resets to the Zone:MQWarpLagThreshold value. Default: 90000 (900 seconds/15 minutes). Set to -1 to disable this feature.

+RULE_INT ( Zone, MQWarpDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQ Detector. This spell will be actually cast, don't pick a resistible spell. Default: 757 (Resurrection Effects)

+RULE_INT ( Zone, MQGateDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)

+RULE_INT ( Zone, MQZoneDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)

+RULE_INT ( Zone, MQGhostDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQGhostDetector. This spell will be actually cast, don't pick a resistable spell. Default: 757 (Resurrection Effects)
RULE_CATEGORY_END()

RULE_CATEGORY( Map )


Index: zone/client.cpp

================================================== =================

--- zone/client.cpp (revision 110)

+++ zone/client.cpp (working copy)

@@ -2304,7 +2304,7 @@

float dx=cheat_x-x_pos;
float dy=cheat_y-y_pos;
float result=sqrtf((dx*dx)+(dy*dy));
- return result>70;
+ return result>(RuleR(Zone, MQWarpDetectorDistance)); //Lieka: Integrated into Rules System; default value is 30, this allows for beyond GM speed without lag.
}

void Client::SetHideMe(bool flag)
Index: zone/client.h

================================================== =================

--- zone/client.h (revision 110)

+++ zone/client.h (working copy)

@@ -152,6 +152,13 @@

EvacToSafeCoords
} ZoneMode;

+typedef enum {

+ MQWarp,

+ MQZone,

+ MQGate,

+ MQGhost

+} CheatTypes;
+
class ClientFactory {
public:
Client *MakeClient(EQStream* ieqs);
@@ -175,6 +182,8 @@

void Trader_StartTrader();
int8 WithCustomer();
bool CheckCheat();
+ void CheatDetected(CheatTypes Cheat);

+ bool WarpDetection(bool CTimer, float Distance);
virtual bool IsClient() const { return true; }
virtual void DBAWComplete(int8 workpt_b1, DBAsyncWork* dbaw);
bool FinishConnState2(DBAsyncWork* dbaw);

Index: zone/client_process.cpp

================================================== =================

--- zone/client_process.cpp (revision 110)

+++ zone/client_process.cpp (working copy)

@@ -921,6 +921,7 @@

return;
const Resurrect_Struct* ra = (const Resurrect_Struct*) app->pBuffer;
if (ra->action == 1) {
+ this->cheat_timer.Start(3500, false); //[Paddy] Allow getting rezzed without triggering

cout << "Player " << this->name << " got a " << (int16)spells[ra->spellid].base[0] << "% Rezz" << endl;
this->BuffFadeAll();
SetMana(0);
@@ -1481,6 +1482,7 @@

}
if(st)
{
+ this->cheat_timer.Start(3500, false);//[Paddy] Allow PC's to be summoned without triggering Warp Detection

Message(0, "Local: Summoning %s to %i, %i, %i", gms->charname, gms->x, gms->y, gms->z);
if (st->IsClient() && (st->CastToClient()->GetAnon() != 1 || this->Admin() >= st->CastToClient()->Admin()))
st->CastToClient()->MovePC((float)gms->x, (float)gms->y, (float)gms->z, this->GetHeading(), 2, true);
@@ -1512,6 +1514,7 @@

else {
//all options have been exhausted
//summon our target...
+ this->cheat_timer.Start(3500, false); //Lieka: Don't want to trip the MQWarp detector here either.

if(GetTarget() && GetTarget()->IsCorpse()){
GetTarget()->CastToCorpse()->Summon(this, false);
}


Index: zone/command.cpp

================================================== =================

--- zone/command.cpp (revision 110)

+++ zone/command.cpp (working copy)

@@ -1364,6 +1364,7 @@

c->Message(0, "You may not summon a player.");
return;
}
+ t->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Zone-to-Zone GM Summons from triggering the MQZone and MQWarp detectors.

c->Message(0, "Summoning player %s to %1.1f, %1.1f, %1.1f", t->GetName(), c->GetX(), c->GetY(), c->GetZ());
t->CastToClient()->MovePC(zone->GetZoneID(), c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(), 2, GMSummon);
}
@@ -1409,9 +1410,11 @@

}
}

- if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4))
+ if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4)) {
//zone to specific coords
+ c->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Not sure why we put this here... should be an admin if you are zoning to special coordinates by this point.

c->MovePC(zoneid, atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), 0.0f, 0);
+ }
else
//zone to safe coords
c->MovePC(zoneid, 0.0f, 0.0f, 0.0f, 0.0f, 0, ZoneToSafeCoords);

TheLieka
03-29-2008, 09:42 AM
Index: zone/mob.h

================================================== =================

--- zone/mob.h (revision 110)

+++ zone/mob.h (working copy)

@@ -455,7 +455,8 @@

inline Mob* GetTarget() const { return target; }
virtual void SetTarget(Mob* mob);
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
-
+ float GetLWDistance() { return last_warp_distance; } //Null: these are used to return the values to #showstats

+ float GetWarpThreshold() { return warp_threshold; } //this one too
bool IsLoggingEnabled() const { return(logging_enabled); }
void EnableLogging() { logging_enabled = true; }
void DisableLogging() { logging_enabled = false; }
@@ -783,6 +784,10 @@


//temporary:
bool fix_pathing;
+ Timer cheat_timer; //Lieka: Timer used to check for movement exemptions/client-based, unsolicited zone exemptions

+ Timer threshold_timer; //Null: threshold timer

+ float warp_threshold; //Null: threshold for warp detector

+ float last_warp_distance; //Null: last distance logged as a warp, used for logs and #showstats
inline float GetCWPX() const { return(cur_wp_x); }
inline float GetCWPY() const { return(cur_wp_y); }
inline float GetCWPZ() const { return(cur_wp_z); }





Index: zone/zoning.cpp

================================================== =================

--- zone/zoning.cpp (revision 110)

+++ zone/zoning.cpp (working copy)

@@ -55,6 +55,7 @@

case ZoneToSafeCoords:
//going to safe coords, but client dosent know where?
//assume it is this zone for now.
+ cheat_timer.Start(35000,false); //Lieka: Allow Zone/Evac to Safe Coords without triggering MQWarp detector.
target_zone_id = zone->GetZoneID();
break;
case GMSummon:
@@ -74,10 +75,13 @@

if(zone_point) {
//we found a zone point, which is a reasonable distance away
//assume that is the one were going with.
+ cheat_timer.Start(3500,false); //Lieka: Allow Zone normal zoning without triggering MQZone detector.
target_zone_id = zone_point->target_zone_id;
} else {
//unable to find a zone point... is there anything else
//that can be a valid un-zolicited zone request?
+
+ this->CheatDetected(MQZone); //Lieka: Bring down the hammer, they are trying to zone without meeting any of the above criteria.

Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
@@ -105,6 +109,11 @@

if(!zone_point || zone_point->target_zone_id != target_zone_id) {
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id);
+
+ if ((this->cheat_timer.GetRemainingTime())<1 || (!this->cheat_timer.Enabled())){ //Lieka: Disable MQGate Detector if timer is active.

+ this->CheatDetected(MQGate);

+ }
+
SendZoneCancel(zc);
return;
}
@@ -168,6 +177,7 @@

ignorerestrictions = 1; //can always get to our bind point? seems exploitable
break;
case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going.
+ cheat_timer.Start(3500,false); //Lieka: Allow Server Forced Zoning without triggering MQZone detector.
//recycle zonesummon variables
dest_x = zonesummon_x;
dest_y = zonesummon_y;
@@ -204,6 +214,7 @@

//for now, there are no other cases...

//could not find a valid reason for them to be zoning, stop it.
+ this->CheatDetected(MQZone); //Lieka: Bring down the hammer, we don't let hackers off that easily...
Message(13, "Invalid unsolicited zone request.");
LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%s'. Not near a zone point.", GetName(), target_zone_name);
SendZoneCancel(zc);
@@ -218,12 +229,15 @@

//not sure when we would use ZONE_ERROR_NOTREADY

//enforce min status and level
- if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel))
+ if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) {
+ this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate level or status requirements (i.e. zoning into FearPlane at level 30, etc)

myerror = ZONE_ERROR_NOEXPERIENCE;
+ }

if(!ignorerestrictions && flag_needed[0] != '\0') {
//the flag needed string is not empty, meaning a flag is required.
if(Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) {
+ this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate flag.

Message(13, "You must have the flag %s to enter this zone.");
myerror = ZONE_ERROR_NOEXPERIENCE;
}
@@ -265,6 +279,7 @@

//effectively zone them right back to where they were
//unless we find a better way to stop the zoning process.
EQApplicationPacket *outapp;
+ cheat_timer.Start(3500,false); //Lieka: Disable MQ Warp & MQ Gate Detector when zoning fails. (not high enough level, etc)
outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct));
ZoneChange_Struct *zc2 = (ZoneChange_Struct*)outapp->pBuffer;
strcpy(zc2->char_name, zc->char_name);
@@ -279,6 +294,7 @@


void Client::SendZoneError(ZoneChange_Struct *zc, sint8 err) {
LogFile->write(EQEMuLog::Error, "Zone %i is not available because target wasn't found or character insufficent level", zc->zoneID);
+ cheat_timer.Start(3500,false);//Lieka: Disable /Warp & /Gate Detector when zoning fails. (not high enough level, etc)

EQApplicationPacket *outapp;
outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct));
@@ -424,57 +440,64 @@

database.GetZoneLongName(pShortZoneName, &pZoneName);
iZoneNameLength = strlen(pZoneName);

- switch(zm) {
- case EvacToSafeCoords:
- case ZoneToSafeCoords:
- x = zone->safe_x();
- y = zone->safe_y();
- z = zone->safe_z();
- heading = heading;
- break;
- case GMSummon:
- zonesummon_x = x_pos = x;
- zonesummon_y = y_pos = y;
- zonesummon_z = z_pos = z;
- heading = heading;
-
- zonesummon_id = zoneID;
- zonesummon_ignorerestrictions = 1;
- break;
- case ZoneSolicited:
- zonesummon_x = x;
- zonesummon_y = y;
- zonesummon_z = z;
- heading = heading;
-
- zonesummon_id = zoneID;
- zonesummon_ignorerestrictions = ignorerestrictions;
- break;
- case GateToBindPoint:
- x = x_pos = m_pp.binds[0].x;
- y = y_pos = m_pp.binds[0].y;
- z = z_pos = m_pp.binds[0].z;
- heading = m_pp.binds[0].heading;
- break;
- case ZoneToBindPoint:
- x = x_pos = m_pp.binds[0].x;
- y = y_pos = m_pp.binds[0].y;
- z = z_pos = m_pp.binds[0].z;
- heading = m_pp.binds[0].heading;
-
- zonesummon_ignorerestrictions = 1;
- LogFile->write(EQEMuLog::Debug, "Player %s has died and will be zoned to bind point in zone: %s at LOC x=%f, y=%f, z=%f, heading=%f", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading);
- break;
- case SummonPC:
- zonesummon_x = x_pos = x;
- zonesummon_y = y_pos = y;
- zonesummon_z = z_pos = z;
- heading = heading;
- break;
- default:
- LogFile->write(EQEMuLog::Error, "Client::ZonePC() received a reguest to perform an unsupported client zone operation.");
- ReadyToZone = false;
- break;
+ switch(zm) {

+ case EvacToSafeCoords:

+ this->cheat_timer.Start(2500,false);// Null: added a timers to this location because sometimes the ones in the other locations of code were not doing the job

+ case ZoneToSafeCoords:

+ this->cheat_timer.Start(2500,false);

+ x = zone->safe_x();

+ y = zone->safe_y();

+ z = zone->safe_z();

+ heading = heading;

+ break;

+ case GMSummon:

+ this->cheat_timer.Start(2500,false);

+ zonesummon_x = x_pos = x;

+ zonesummon_y = y_pos = y;

+ zonesummon_z = z_pos = z;

+ heading = heading;

+

+ zonesummon_id = zoneID;

+ zonesummon_ignorerestrictions = 1;

+ break;

+ case ZoneSolicited:

+ this->cheat_timer.Start(2500,false);

+ zonesummon_x = x;

+ zonesummon_y = y;

+ zonesummon_z = z;

+ heading = heading;

+

+ zonesummon_id = zoneID;

+ zonesummon_ignorerestrictions = ignorerestrictions;

+ break;

+ case GateToBindPoint:

+ this->cheat_timer.Start(2500,false);

+ x = x_pos = m_pp.binds[0].x;

+ y = y_pos = m_pp.binds[0].y;

+ z = z_pos = m_pp.binds[0].z;

+ heading = m_pp.binds[0].heading;

+ break;

+ case ZoneToBindPoint:

+ this->cheat_timer.Start(2500,false);

+ x = x_pos = m_pp.binds[0].x;

+ y = y_pos = m_pp.binds[0].y;

+ z = z_pos = m_pp.binds[0].z;

+ heading = m_pp.binds[0].heading;

+

+ zonesummon_ignorerestrictions = 1;

+ LogFile->write(EQEMuLog::Debug, "Player %s has died and will be zoned to bind point in zone: %s at LOC x=%f, y=%f, z=%f, heading=%f", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading);

+ break;

+ case SummonPC:

+ this->cheat_timer.Start(2500,false);

+ zonesummon_x = x_pos = x;

+ zonesummon_y = y_pos = y;

+ zonesummon_z = z_pos = z;

+ heading = heading;

+ break;

+ default:

+ LogFile->write(EQEMuLog::Error, "Client::ZonePC() received a reguest to perform an unsupported client zone operation.");

+ ReadyToZone = false;

+ break;

}

if(ReadyToZone) {

TheLieka
03-29-2008, 09:43 AM
Index: zone/client_packet.cpp

================================================== =================

--- zone/client_packet.cpp (revision 110)

+++ zone/client_packet.cpp (working copy)

@@ -771,6 +771,82 @@

void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app) {
SendAATable();
}
+bool Client::WarpDetection(bool CTimer, float distance)

+{

+ float last_distance;

+ if (threshold_timer.GetRemainingTime() < 1 && ((RuleR(Zone, MQWarpThresholdTimer)) != -1)) { //Null: If the timer is done, reset threshold, then reset timer //Lieka: Integrated into Rules System.

+ warp_threshold = (RuleR(Zone, MQWarpLagThreshold)); //Lieka: Integrated warp_threshold value into Rules System. Original Value was 140.

+ threshold_timer.Start((RuleR(Zone, MQWarpThresholdTimer)), false); //Lieka: Integrated timer duration value into the Rules System. Original Value was 90000 (90 seconds).

+ }

+ if ((CTimer))

+ return false;

+ else

+ {

+ //Null Edit: made warp detector fire only when the sum of all the warps in a period of time are greater than a threshold

+ //this makes the warp detector more lax on small warps, but still drops the hammer on the big ones.

+ if (distance>140.0f) {

+ last_distance = (distance-140.0f);

+ warp_threshold -= last_distance;

+ last_warp_distance = last_distance;

+ }

+ return (warp_threshold < 0); //Null: If the threshold is met, hit them with the hammer

+ }

+}

+

+void Client::CheatDetected(CheatTypes CheatType)

+{ //[Paddy] ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.

+ switch (CheatType)

+ {

+ case MQWarp://Some zones have serious issues, turning off warp flags for these zones.

+ if(!((zone->GetZoneID()==2)/*qeynos2*/ || (zone->GetZoneID()==9)/*freportw*/|| (zone->GetZoneID()==10)/*freporte*/ || (zone->GetZoneID()==34)/*nro*/ || (zone->GetZoneID()==24)/*erudin*/ || (zone->GetZoneID()==75)/*Paineel*/ || (zone->GetZoneID()==62)/*Felwitheb*/) && (RuleB(Zone, EnableMQWarpDetector) && ((this->Admin() < RuleI(Zone, MQWarpExemptStatus) || (RuleI(Zone, MQWarpExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQWarp detector (This may be depricated now, but these zones were problems in the past)

+ {

+ Message(13, "Your account has been reported for hacking.");

+ database.SetMQDetectionFlag(this->account_name,this->name, "/MQWarp", zone->GetShortName());

+ SetMana(0); //Lieka: Remove all mana from player.

+ SetHP(5); //Lieka: Set player's hitpoints to 5.

+ BuffFadeAll(); //Lieka: Wipe all of player's buffs.

+ SpellFinished((RuleI(Zone, MQWarpDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).

+ worldserver.SendEmoteMessage(0,0,0,13,"<MQWarp Detector>. %s was just caught warping in %s. Come get your free kill!",this->GetName(),zone->GetLongName());

+ warp_threshold = 1; //Null: bringing the detector back up to one to avoid chain detections.

+ }

+ break;

+ case MQZone:

+ if(!( (zone->GetZoneID()==31)/*sola*/ || (zone->GetZoneID()==32)/*solb*/ || (zone->GetZoneID()==25)/*nek*/ || (zone->GetZoneID()==27)/*lava*/ ) && (RuleB(Zone, EnableMQZoneDetector))&& ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1))) //Lieka: Exempt these zones from the MQZone detector (This may be depricated now, but were problems in the past)

+ {

+ Message(13, "Your account has been reported for hacking.");

+ database.SetMQDetectionFlag(this->account_name,this->name, "/MQZone", zone->GetShortName());

+ SetMana(0); //Lieka: Remove all mana from player.

+ SetHP(5); //Lieka: Set player's hitpoints to 5.

+ BuffFadeAll(); //Lieka: Wipe all of player's buffs.

+ AddBuff(this,(RuleI(Zone, MQZoneDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).

+ worldserver.SendEmoteMessage(0,0,0,13,"<MQZone Detector>. %s as just caught using Macroquest to /Zone to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQZone detector has caught a cheater.

+ }

+ break;

+ case MQGate:

+ if (RuleB(Zone, EnableMQGateDetector)&& ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {

+ Message(13, "Your account has been reported for hacking.");

+ database.SetMQDetectionFlag(this->account_name,this->name, "/MQGate", zone->GetShortName());

+ this->SetZone(this->GetZoneID()); //Lieka: Prevent the player from zoning, place him back in the zone where he tried to originally /gate.

+ SetMana(0); //Lieka: Remove all mana from player.

+ SetHP(5); //Lieka: Set player's hitpoints to 5.

+ BuffFadeAll(); //Lieka: Wipe all of player's buffs.

+ AddBuff(this,(RuleI(Zone, MQGateDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).

+ worldserver.SendEmoteMessage(0,0,0,13,"<MQGate Detector>. %s was just caught using Macroquest to /Gate to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.

+ }

+ break;

+ case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified

+ if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {

+ Message(13, "Your account has been reported for hacking.");

+ database.SetMQDetectionFlag(this->account_name,this->name, "/MQGhost", zone->GetShortName());

+ SetMana(0); //Lieka: Remove all mana from player.

+ SetHP(5); //Lieka: Set player's hitpoints to 5.

+ BuffFadeAll(); //Lieka: Wipe all of player's buffs.

+ SpellFinished((RuleI(Zone, MQGhostDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).

+ worldserver.SendEmoteMessage(0,0,0,13,"<MQGhost Detector>. %s was just caught using Macroquest to /Ghost to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.

+ }

+ break;

+ }

+}

void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
{
@@ -796,9 +872,28 @@

dist += tmp*tmp;
tmp = y_pos - ppu->y_pos;
dist += tmp*tmp;
- tmp = z_pos - ppu->z_pos;
- dist += tmp*tmp;
- if(dist > 50.0f*50.0f) {
+
+ dist = sqrt(dist);

+ /*[Paddy] Cutting out the Z-Axis check. Not necessary and prevents long falls from triggering */

+ //tmp = z_pos - ppu->z_pos;

+ //dist += tmp*tmp;

+

+ /* Begin Cheat Detection*/

+ if ((this->cheat_timer.GetRemainingTime())>1 && (this->cheat_timer.Enabled())) //Lieka: Check to see if the cheat (exemption) timer is active - this is for debugging

+ {

+ //Spell timer is currently active

+ //worldserver.SendEmoteMessage(0,0,0,13,"Timer is Active. %d True: %s",this->cheat_timer.GetRemainingTime(), (this->cheat_timer.GetRemainingTime()>1)? "true" : "false"); //Leika Edit: Enable this to get debug messages.

+ }

+ else //Timer has elapsed or hasn't started, let's do a Warp Check

+ {

+ if ((WarpDetection(false, dist)) && ((admin <= RuleI(Zone, MQWarpExemptStatus)) || (RuleI(Zone, MQWarpExemptStatus) == -1))) //Exempt from warp detection if admin level is > Rule:Zone:MQWarpExemptStatus

+ {

+ printf("Warping Detected by %S Acct: %s Distance: %f.", GetName(), AccountName(), GetLWDistance());

+ CheatDetected(MQWarp); //Lieka: Execute MQWarp function on offending player

+ }

+ }

+ //Lieka End Edit
+ if(dist > 50.0f*50.0f) {
printf("%s: Large position change: %f units\n", GetName(), sqrtf(dist));
printf("Coords: (%.4f, %.4f, %.4f) -> (%.4f, %.4f, %.4f)\n",
x_pos, y_pos, z_pos, ppu->x_pos, ppu->y_pos, ppu->z_pos);
@@ -813,13 +908,13 @@

// this checking of heading/x_pos is cheap, and the result is
// subtle, but you'll notice your sense heading improve as you
// travel around
- if(
- ( (heading != ppu->heading) && !((int)heading % 3) ) || // turning
- ( (x_pos != ppu->x_pos) && !((int)x_pos % 6) ) // moving
- )
- {
- CheckIncreaseSkill(SENSE_HEADING, -20);
- }
+ if(

+ ( (heading != ppu->heading) && !((int)heading % 3) ) || // turning

+ ( (x_pos != ppu->x_pos) && !((int)x_pos % 6) ) // moving

+ )

+ {

+ CheckIncreaseSkill(SENSE_HEADING, -20);

+ }


if(proximity_timer.Check()) {
entity_list.ProcessMove(this, ppu->x_pos, ppu->y_pos, ppu->z_pos);
@@ -3154,6 +3249,7 @@

cout << "Wrong size on OP_GMSummon. Got: " << app->size << ", Expected: " << sizeof(GMSummon_Struct) << endl;
return;
}
+ this->cheat_timer.Start(5000, false); //Lieka: Exempt in-zone GM Summons from triggering MQWarp detector

OPGMSummon(app);
return;
}
@@ -6016,6 +6112,7 @@

// vesuvias - appearence fix
beard = m_pp.beard;

+ this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when logging in after LD - basically gives a grace period for large position changes.


//if we zone in with invalid Z, fix it.
@@ -6648,6 +6745,8 @@

}
}
}
+
+ this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when arriving in a new zone.

client_data_loaded = true;
int x;

TheLieka
03-29-2008, 09:44 AM
Index: zone/spell_effects.cpp

================================================== =================

--- zone/spell_effects.cpp (revision 110)

+++ zone/spell_effects.cpp (working copy)

@@ -1682,11 +1682,13 @@


case SE_SummonPC:
{
- if(IsClient())
- CastToClient()->MovePC(zone->GetZoneID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);
- else
- caster->Message(13, "This spell can only be cast on players.");
-
+ if(IsClient()){

+ CastToClient()->cheat_timer.Start(3500, false); //Lieka: Exempt spells the "SummonPC" effect from triggering the MQWarp detector.

+ CastToClient()->MovePC(zone->GetZoneID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);

+ Message(15, "You have been summoned!");

+ } else {

+ caster->Message(13, "This spell can only be cast on players.");

+ }
break;
}

Index: zone/spells.cpp

================================================== =================

--- zone/spells.cpp (revision 110)

+++ zone/spells.cpp (working copy)

@@ -942,6 +942,16 @@

if(IsClient())
{
this->CastToClient()->CheckSongSkillIncrease(spell_id);
+ //Lieka start Edit: Fixing Warp Detector triggered for Bard Songs

+ if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.

+ (IsTeleportSpell(spell_id)) ||

+ (IsSuccorSpell(spell_id)) ||

+ (IsShadowStepSpell(spell_id)) ||

+ (IsGateSpell(spell_id)))

+ {

+ this->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the bard song effects

+ }

+ //Lieka end edit.
}
// go again in 6 seconds
//this is handled with bardsong_timer
@@ -972,8 +982,15 @@


c->CheckSpecializeIncrease(spell_id);
}
+ if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.

+ (IsTeleportSpell(spell_id)) ||

+ (IsSuccorSpell(spell_id)) ||

+ (IsShadowStepSpell(spell_id)) ||

+ (IsGateSpell(spell_id)))

+ {

+ c->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects

+ }

-
}

// there should be no casting going on now
@@ -2242,6 +2259,17 @@

action->instrument_mod = GetInstrumentMod(spell_id);
action->buff_unknown = 0;

+ //Lieka start Edit: Fixing Warp Detector triggered by spells cast on the player.

+ if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.

+ (IsTeleportSpell(spell_id)) ||

+ (IsSuccorSpell(spell_id)) ||

+ (IsShadowStepSpell(spell_id)) ||

+ (IsGateSpell(spell_id)))

+ {

+ spelltar->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects

+ }

+ //Lieka end edit.
+
if(spelltar->IsClient()) // send to target
spelltar->CastToClient()->QueuePacket(action_packet);
if(IsClient()) // send to caster


Index: zone/zone.cpp

================================================== =================

--- zone/zone.cpp (revision 110)

+++ zone/zone.cpp (working copy)

@@ -1185,7 +1185,7 @@

}
}

-ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance) {
+ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance, Client* client) {
LinkedListIterator<ZonePoint*> iterator(zone_point_list);
ZonePoint* closest_zp = 0;
float closest_dist = FLT_MAX;
@@ -1214,8 +1214,14 @@

}

if(closest_dist>(200.0f*200.0f) && closest_dist<max_distance2)
- LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
-
+ {

+ client->CheatDetected(MQZone); //[Paddy] Someone is trying to use /zone

+ LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);

+ LogFile->write(EQEMuLog::Status, "<Real Zone Points>. %f x %f y %fz ",x,y,z);

+ //worldserver.SendEmoteMessage(0,0,0,13,"<Real Zone Points>. %f x %f y %fz ",x,y,z);

+ closest_zp = NULL; //Lieka: Prevent the zone request from happening.

+ }
+
if(closest_dist > max_distance2)
closest_zp = NULL;

Index: zone/zone.h

================================================== =================

--- zone/zone.h (revision 110)

+++ zone/zone.h (working copy)

@@ -108,7 +108,7 @@


int32 CountSpawn2();
ZonePoint* GetClosestZonePoint(float x, float y, float z, const char* to_name, float max_distance = 40000.0f);
- ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f);
+ ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f, Client* client = NULL);
ZonePoint* GetClosestZonePointWithoutZone(float x, float y, float z, float max_distance = 40000.0f);
SpawnGroupList spawn_group_list;



Index: zone/mob.cpp

================================================== =================

--- zone/mob.cpp (revision 110)

+++ zone/mob.cpp (working copy)

@@ -100,8 +100,10 @@

tic_timer(6000),
mana_timer(2000),
spellend_timer(0),
+ cheat_timer(0), //Lieka: Timer for MQ Detector exemptions
stunned_timer(0),
bardsong_timer(6000),
+ threshold_timer(0), //Lieka: Timer to allow exemptions MQWarp related to lag

#ifdef FLEE_HP_RATIO
flee_timer(FLEE_CHECK_TIMER),
#endif
@@ -121,7 +123,8 @@

AI_Init();
SetMoving(false);
moved=false;
-
+ warp_threshold = 140; //Null: set the threshold on creation of mob instance

+ last_warp_distance = 0; //Null: set this one to zero also just because.

_egnode = NULL;
adverrorinfo = 0;
name[0]=0;
@@ -231,7 +234,7 @@

// guildeqid = GUILD_NONE;

spellend_timer.Disable();
-
+ cheat_timer.Disable();
bardsong_timer.Disable();
bardsong = 0;
bardsong_target_id = 0;
@@ -874,6 +877,7 @@

client->Message(0, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA());
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR());
client->Message(0, " Race: %i BaseRace: %i Texture: %i HelmTexture: %i Gender: %i BaseGender: %i", GetRace(), GetBaseRace(), GetTexture(), GetHelmTexture(), GetGender(), GetBaseGender());
+ client->Message(0, " Last Warp Distance: %f Threshold Remaining: %f", GetLWDistance(), GetWarpThreshold()); //Null: added this to check players last warp distance for debuging.

if (client->Admin() >= 100) {
client->Message(0, " EntityID: %i PetID: %i OwnerID: %i AIControlled: %i", this->GetID(), this->GetPetID(), this->GetOwnerID(), this->IsAIControlled());
if (this->IsClient()) {
@@ -1842,6 +1846,10 @@

// RangerDown - GMMove doesn't seem to be working well with players, so use MovePC for them, GMMove for NPC's
if (target->IsClient())
target->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);
+ if (target->IsClient()) {

+ target->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Mob Summons from tripping hack detector.

+ target->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);

+ }
else
GetHateTop()->GMMove(x_pos, y_pos, z_pos, target->GetHeading());
return true;
}

Index: zone/spdat.cpp

================================================== =================

--- zone/spdat.cpp (revision 110)

+++ zone/spdat.cpp (working copy)

@@ -637,6 +637,39 @@

return Result;
}

+bool IsShadowStepSpell(int16 spell_id) {

+ if (IsEffectInSpell(spell_id, SE_ShadowStep)){

+ return true;

+ }

+ else {

+ return false;

+ }

+}

+bool IsSuccorSpell(int16 spell_id) {

+ if (IsEffectInSpell(spell_id, SE_Succor)){

+ return true;

+ }

+ else {

+ return false;

+ }

+}

+bool IsTeleportSpell(int16 spell_id) {

+ if (IsEffectInSpell(spell_id, SE_Teleport)){

+ return true;

+ }

+ else {

+ return false;

+ }

+}

+bool IsGateSpell(int16 spell_id) {

+ if (IsEffectInSpell(spell_id, SE_Gate)){

+ return true;

+ }

+ else {

+ return false;

+ }

+}
+
bool IsMagicRuneSpell(int16 spell_id) {
bool Result = false;


Index: zone/spdat.h

================================================== =================

--- zone/spdat.h (revision 110)

+++ zone/spdat.h (working copy)

@@ -531,6 +531,10 @@

bool IsResurrectionEffects(int16 spell_id);
bool IsRuneSpell(int16 spell_id);
bool IsMagicRuneSpell(int16 spell_id);
+bool IsShadowStepSpell(int16 spell_id);

+bool IsSuccorSpell(int16 spell_id);

+bool IsTeleportSpell(int16 spell_id);

+bool IsGateSpell(int16 spell_id);
bool IsManaTapSpell(int16 spell_id);
bool IsAllianceSpellLine(int16 spell_id);
bool IsDeathSaveSpell(int16 spell_id);

TheLieka
03-29-2008, 09:48 AM
Updated the SQL to address a couple of issues too.

ALTER TABLE `hackers`
ADD COLUMN `zone` TEXT AFTER `hacked`;
ADD COLUMN `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `zone`;

insert into rule_values values (0, Zone:EnableMQWarpDetector, false);
insert into rule_values values (0, Zone:EnableMQZoneDetector, false);
insert into rule_values values (0, Zone:EnableMQGateDetector, false);
insert into rule_values values (0, Zone:EnableMQGhostDetector, false);

insert into rule_values values (0, Zone:MQWarpExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);
insert into rule_values values (0, Zone:MQZoneExemptStatus, 50);
insert into rule_values values (0, Zone:MQGhostExemptStatus, 50);

insert into rule_values values (0, Zone:MQWarpDetectorDistance, 30);
insert into rule_values values (0, Zone:MQWarpLagThreshold, 140);
insert into rule_values values (0, Zone:MQWarpThresholdTimer, 90000);

insert into rule_values values (0, Zone:MQWarpDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQGateDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQZoneDetectionSpellID, 757);
insert into rule_values values (0, Zone:MQGhostDetectionSpellID, 757);

Hopefully it should be good now. Let me know if you have any questions or concerns.

Dax

cavedude
03-29-2008, 11:42 AM
Compiled perfectly! I'm going to play around now, thank you!

TheLieka
03-29-2008, 12:16 PM
:) Glad to hear it - there might be some issues from tying it into the rules system (I'm hoping not, but it was not tested nearly as thoroughly with the rules setup as it was prior to it), but other than that, it should be pretty much as it reads. Let me know if you have any questions or concerns.

Thanks,
Dax

Semedaien
03-29-2008, 12:42 PM
Awsome man, thank you for the wonderful contribution to the emu community!

KLS
03-29-2008, 02:51 PM
Yeah, thank you much. This is very much needed, I'm gonna let it sit on PEQ for a bit and see what CD thinks about it before moving it to official source. If there's a situation where false positives happen a lot I'd just like to resolve it before it gets put in is all.

So_1337
03-31-2008, 01:54 AM
Absolutely brilliant! Always such quality from you :)

Angelox
04-02-2008, 06:51 AM
I moved part of this to another forum (Development:: Development) as "MQWarp/MQZone/MQGate Detector Discussion".
This forum is intended for submissions only, so I tried to split up the thread as best I could - use the new thread for discussion.

TheLieka
04-14-2008, 10:15 AM
Yes, we merged back with the eqemu source and use Wildcard's updates to the zoning stuff (getting all the bugs worked out of it made for an interesting week on our server ;)).

Here are the source snippets involved in pulling the zonepoints, then checking them against a zone request.

Here's the code that pulls and checks the zone points:


SQL query that pulls the zone points into the code:
from .\zone\zone.cpp
bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list,const char* zonename)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
zone_point_list->Clear();
zone->numzonepoints = 0;
MakeAnyLenString(&query, "SELECT x,y,z,target_x,target_y,target_z,target_zone_id,he ading,target_heading,number FROM zone_points WHERE zone='%s' order by number", zonename);
if (RunQuery(query, strlen(query), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)))
{
ZonePoint* zp = new ZonePoint;
zp->x = atof(row[0]);
zp->y = atof(row[1]);
zp->z = atof(row[2]);
zp->target_x = atof(row[3]);
zp->target_y = atof(row[4]);
zp->target_z = atof(row[5]);
zp->target_zone_id = atoi(row[6]);
zp->heading=atof(row[7]);
zp->target_heading=atof(row[8]);
zp->number=atoi(row[9]);
zone_point_list->Insert(zp);
zone->numzonepoints++;
}
mysql_free_result(result);
}
else
{
cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return true;
}

Here is the function that checks for the closest zone points.

ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance, Client* client) {
LinkedListIterator<ZonePoint*> iterator(zone_point_list);
ZonePoint* closest_zp = 0;
float closest_dist = FLT_MAX;
float max_distance2 = max_distance*max_distance;
iterator.Reset();
while(iterator.MoreElements())
{
ZonePoint* zp = iterator.GetData();
if (zp->target_zone_id == to)
{
float delta_x = zp->x - x;
float delta_y = zp->y - y;
if(zp->x == 999999 || zp->x == -999999)
delta_x = 0;
if(zp->y == 999999 || zp->y == -999999)
delta_y = 0;

float dist = delta_x*delta_x+delta_y*delta_y;///*+(zp->z-z)*(zp->z-z)*/;
if (dist < closest_dist)
{
closest_zp = zp;
closest_dist = dist;
}
}
iterator.Advance();
}

if(closest_dist>(200.0f*200.0f) && closest_dist<max_distance2)
{
client->CheatDetected(MQZone); //[Paddy] Someone is trying to use /zone
LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
LogFile->write(EQEMuLog::Status, "<Real Zone Points>. %f x %f y %fz ",x,y,z);
//worldserver.SendEmoteMessage(0,0,0,13,"<Real Zone Points>. %f x %f y %fz ",x,y,z);
closest_zp = NULL; //Lieka: Prevent the zone request from happening.
}

In the `zone_points` table, your current entries are fine - they're just incomplete. If you select * from zone_points where y = 0 && x = 0 && z = 0; then you will see the entries that need to be updated (pretty much all of them). I've already posted the list for old world zones, but kunark+ need to still be updated.

Basically, when there's an unsolicited zone request from the client (i.e. the client requests a zone change):

The function "ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance, Client* client)" compares the x, y (not target_x and target_y) in the records that match the target_zone_id within your zone_points table against the client's current x, y. If the (zonepoint->x - client->x) * (zonepoint->y - client->y) > 4000 (200*200), then it assumes that the zone request is the result of a hack (which it most likely is). So, if you have 0, 0 for a value in your x, y in the zone_points table, then unless the client is attempting to use that zone_point from close to that x, y in the zone, it will detect a /MQZone attempt. If the zone that the client is using is a zone wall (like East Commons -> West Freeport), you'll put 999999 for the x or y (whichever is appropriate), and it will exempt it that (x or y) from the check (because it's too damn hard to draw a line in the database).

Once you update these records in your zone_points table, you can #reloadzps from within that zone (the source zone, not the target zone), and retest them.

I hope that helps,
Dax

TheLieka
04-16-2008, 03:51 AM
Ax - the submission thread for this is locked, could you move this code over for me?

I don't have a ton of time to document this, but it's well documented in the code. Long story short -
Warp detection is now done by velocity rather than just distance. The time measurement is taken between Player Position Update packets being received. The velocity is taken by taking the distance / time since last PPU. If the detector trips, it moves the player back to his previous PPU location. Added the following rules:
For Disabling MQDetector Penalties (Punishment for the player)
For Disabling SQL Logging (haven't replaced it with text logging, but if it's a performance concern you can now disable it in the rules)
For Disabling MQDetector Broadcast
For Setting the Speed Limit (speed measured by units / second - this rule specifies the number of units a player is allowed to travel per second. From testing: 3-4 is level 50 SoW, 7 - 10 is GM Speed
Added 4 new items to #showstats:
Last PPU Time: Indicates how long it was since the last PPU for the player (in hundredths of a second)
Longest PPU Time: Records the longest time between PPUs for the player (in hundredths of a second)
Current Movement Speed: Indicates the current movement speed of the player
Highest Movement Speed: Indicates the highest movement speed of the player

That's pretty much it - the rest is the same as my original submission, but I think these updates should be what the code needed.

Let me know what you think. :)

Thanks,
Dax

This Diff was taken against 0.7.0-1102
diff c:/EQEmu_0.7.0_1102_source/zone/client.h c:/VZ-TZ-Diff/zone/client.h
151a152
> WarpDetected, // Lieka: Return client to pre-warp location
154a156,162
> typedef enum {
> MQWarp,
> MQZone,
> MQGate,
> MQGhost
> } CheatTypes;
>
177a186,187
> void CheatDetected(CheatTypes Cheat);
> bool WarpDetection(bool CTimer, float Distance, int32 last_ppu_timer);
diff c:/EQEmu_0.7.0_1102_source/zone/client_packet.cpp c:/VZ-TZ-Diff/zone/client_packet.cpp
773a774,860
> bool Client::WarpDetection(bool CTimer, float distance, int32 last_ppu_timer) //Lieka: Completely reworked this function. Rather than basing warp detection on large movement diffs, we now base it on the player's speed (update distance / update time)
> {
> if (CTimer)
> return false;
> else
> {
> movement_speed = distance / (last_ppu_timer/100);
> if (movement_speed > highest_movement_speed) {
> highest_movement_speed = movement_speed;
> }
> return (movement_speed > RuleR(Zone, MQWarpSpeedLimit)); //Lieka: If the player breaks the speed limit, bring down the hammer.
> }
> }
>
> void Client::CheatDetected(CheatTypes CheatType)
> { //[Paddy] ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.
> switch (CheatType)
> {
> case MQWarp://Some zones have serious issues, turning off warp flags for these zones.
> if(!((zone->GetZoneID()==2)/*qeynos2*/ || (zone->GetZoneID()==9)/*freportw*/|| (zone->GetZoneID()==10)/*freporte*/ || (zone->GetZoneID()==34)/*nro*/ || (zone->GetZoneID()==24)/*erudin*/ || (zone->GetZoneID()==75)/*Paineel*/ || (zone->GetZoneID()==62)/*Felwitheb*/) && (RuleB(Zone, EnableMQWarpDetector) && ((this->Admin() < RuleI(Zone, MQWarpExemptStatus) || (RuleI(Zone, MQWarpExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQWarp detector (This may be depricated now, but these zones were problems in the past)
> {
> if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
> Message(13, "Your account has been reported for hacking.");
> database.SetMQDetectionFlag(this->account_name, this->name, "/MQWarp", zone->GetShortName());
> }
> if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
> SetMana(0); //Lieka: Remove all mana from player.
> SetHP(5); //Lieka: Set player's hitpoints to 5.
> BuffFadeAll(); //Lieka: Wipe all of player's buffs.
> SpellFinished((RuleI(Zone, MQWarpDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
> }
> if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
> worldserver.SendEmoteMessage(0,0,0,13,"<MQWarp Detector>. %s was just caught warping in %s. Come get your free kill!",this->GetName(),zone->GetLongName());
> }
> break;
> case MQZone:
> if(!( (zone->GetZoneID()==31)/*sola*/ || (zone->GetZoneID()==32)/*solb*/ || (zone->GetZoneID()==25)/*nek*/ || (zone->GetZoneID()==27)/*lava*/ ) && (RuleB(Zone, EnableMQZoneDetector))&& ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1))) //Lieka: Exempt these zones from the MQZone detector (This may be depricated now, but were problems in the past)
> {
> if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
> Message(13, "Your account has been reported for hacking.");
> database.SetMQDetectionFlag(this->account_name, this->name, "/MQZone", zone->GetShortName());
> }
> if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
> SetMana(0); //Lieka: Remove all mana from player.
> SetHP(5); //Lieka: Set player's hitpoints to 5.
> BuffFadeAll(); //Lieka: Wipe all of player's buffs.
> AddBuff(this,(RuleI(Zone, MQZoneDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
> }
> if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
> worldserver.SendEmoteMessage(0,0,0,13,"<MQZone Detector>. %s as just caught using Macroquest to /Zone to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQZone detector has caught a cheater.
> }
> break;
> case MQGate:
> if (RuleB(Zone, EnableMQGateDetector)&& ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
> if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
> Message(13, "Your account has been reported for hacking.");
> database.SetMQDetectionFlag(this->account_name, this->name, "/MQGate", zone->GetShortName());
> }
> this->SetZone(this->GetZoneID()); //Lieka: Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
> if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
> SetMana(0); //Lieka: Remove all mana from player.
> SetHP(5); //Lieka: Set player's hitpoints to 5.
> BuffFadeAll(); //Lieka: Wipe all of player's buffs.
> AddBuff(this,(RuleI(Zone, MQGateDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
> }
> if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
> worldserver.SendEmoteMessage(0,0,0,13,"<MQGate Detector>. %s was just caught using Macroquest to /Gate to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
> }
> break;
> case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified
> if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
> if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
> Message(13, "Your account has been reported for hacking.");
> database.SetMQDetectionFlag(this->account_name, this->name, "/MQGhost", zone->GetShortName());
> }
> if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
> SetMana(0); //Lieka: Remove all mana from player.
> SetHP(5); //Lieka: Set player's hitpoints to 5.
> BuffFadeAll(); //Lieka: Wipe all of player's buffs.
> SpellFinished((RuleI(Zone, MQGhostDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
> }
> if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
> worldserver.SendEmoteMessage(0,0,0,13,"<MQGhost Detector>. %s was just caught using Macroquest to /Ghost to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
> }
> break;
> }
> }
791,792c878,888
<
<
---
> //Lieka: Track duration between Player Position Updates to determine lag (for warp detection).
> if (ppu_timer.Enabled()) {
> last_ppu_timer = 40000 - ppu_timer.GetRemainingTime();
> if(last_ppu_timer > longest_ppu_timer) {
> longest_ppu_timer = last_ppu_timer;
> }
> } else {
> last_ppu_timer = 1;
> }
> ppu_timer.Start(40000, true);
>
799,801c895,918
< tmp = z_pos - ppu->z_pos;
< dist += tmp*tmp;
< if(dist > 50.0f*50.0f) {
---
>
> dist = sqrt(dist);
> /*[Paddy] Cutting out the Z-Axis check. Not necessary and prevents long falls from triggering */
> //tmp = z_pos - ppu->z_pos;
> //dist += tmp*tmp;
>
> /* Begin Cheat Detection*/
> if (((this->cheat_timer.GetRemainingTime())>1 && (this->cheat_timer.Enabled())) || longest_ppu_timer < 2) //Lieka: Check to see if the cheat (exemption) timer is active - this is for debugging
> {
> //Spell timer is currently active
> //worldserver.SendEmoteMessage(0,0,0,13,"Timer is Active. %d True: %s",this->cheat_timer.GetRemainingTime(), (this->cheat_timer.GetRemainingTime()>1)? "true" : "false"); //Leika Edit: Enable this to get debug messages.
> }
> else //Timer has elapsed or hasn't started, let's do a Warp Check
> {
> if ((WarpDetection(false, dist, last_ppu_timer)) && ((RuleB(Zone,EnableMQGateDetector) && (admin <= RuleI(Zone, MQWarpExemptStatus)) || (RuleI(Zone, MQWarpExemptStatus) == -1)))) //Exempt from warp detection if admin level is > Rule:Zone:MQWarpExemptStatus
> {
> printf("Warping Detected by %s Distance: %f.", GetName(), dist);
> this->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, heading, 2, WarpDetected); //Lieka Edit: Move player back to pre-warp location
> CheatDetected(MQWarp); //Lieka: Execute MQWarp function on offending player
> return;
> }
> }
> //Lieka End Edit
> if(dist > 50.0f*50.0f) {
816,822c933,939
< if(
< ( (heading != ppu->heading) && !((int)heading % 3) ) || // turning
< ( (x_pos != ppu->x_pos) && !((int)x_pos % 6) ) // moving
< )
< {
< CheckIncreaseSkill(SENSE_HEADING, -20);
< }
---
> if(
> ( (heading != ppu->heading) && !((int)heading % 3) ) || // turning
> ( (x_pos != ppu->x_pos) && !((int)x_pos % 6) ) // moving
> )
> {
> CheckIncreaseSkill(SENSE_HEADING, -20);
> }
3156a3274
> this->cheat_timer.Start(5000, false); //Lieka: Exempt in-zone GM Summons from triggering MQWarp detector
6018a6137
> this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when logging in after LD - basically gives a grace period for large position changes.
6650a6770,6771
>
> this->cheat_timer.Start(2500,false); //Lieka: Prevent tripping the MQWarp detector when arriving in a new zone.
diff c:/EQEmu_0.7.0_1102_source/zone/client_process.cpp c:/VZ-TZ-Diff/zone/client_process.cpp
923a924
> this->cheat_timer.Start(3500, false); //[Paddy] Allow getting rezzed without triggering
1483a1485
> this->cheat_timer.Start(3500, false);//[Paddy] Allow PC's to be summoned without triggering Warp Detection
1514a1517
> this->cheat_timer.Start(3500, false); //Lieka: Don't want to trip the MQWarp detector here either.
diff c:/EQEmu_0.7.0_1102_source/zone/command.cpp c:/VZ-TZ-Diff/zone/command.cpp
1366a1367
> t->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Zone-to-Zone GM Summons from triggering the MQZone and MQWarp detectors.
1412c1413
< if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4))
---
> if (sep->IsNumber(2) || sep->IsNumber(3) || sep->IsNumber(4)) {
1413a1415
> c->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Not sure why we put this here... should be an admin if you are zoning to special coordinates by this point.
1414a1417
> }
diff c:/EQEmu_0.7.0_1102_source/zone/mob.cpp c:/VZ-TZ-Diff/zone/mob.cpp
102a103
> cheat_timer(0), //Lieka: Timer for MQ Detector exemptions
104a106
> ppu_timer(0), //Lieka: Timer to track time between Player Update Packets (to detect lag) for MQWarp detection
124c126,129
<
---
> longest_ppu_timer = 0; //Lieka: reset longest player packet update timer record on creation of mob instance
> last_ppu_timer = 0; //Lieka: reset last player packet update timer record on creation of mob instance
> movement_speed = 0; //Lieka: reset player movement speed record on creation of mob instance
> highest_movement_speed = 0; //Lieka: reset highest recorded player movement speed on creation of mob instance
234c239
<
---
> cheat_timer.Disable();
876a882,883
> client->Message(0, " Last Player Position Update Timer: %i Longest Player Position Update Timer: %i", GetLastPPUTimer(), GetLongestPPUTimer()); //Lieka: added this to monitor player lag for MQWarp detection.
> client->Message(0, " Current Movement Speed: %i Highest Movement Speed: %i", GetMovementSpeed(), GetHighestMovementSpeed()); //Lieka: added this to monitor player's movement speed (based on last PPU update / PPU time.
1844a1852,1855
> if (target->IsClient()) {
> target->CastToClient()->cheat_timer.Start(3500,false); //Lieka: Prevent Mob Summons from tripping hack detector.
> target->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, target->GetHeading(), 0, SummonPC);
> }
diff c:/EQEmu_0.7.0_1102_source/zone/mob.h c:/VZ-TZ-Diff/zone/mob.h
458c458,461
<
---
> int32 GetLastPPUTimer() { return last_ppu_timer; } //Lieka: Used in #showstats mainly for debugging and monitoring players
> int32 GetLongestPPUTimer() { return longest_ppu_timer; } //Lieka: Used in #showstats mainly for debugging and monitoring players
> int32 GetMovementSpeed() { return movement_speed; } //Lieka: Used in #showstats mainly for debugging and monitoring players
> int32 GetHighestMovementSpeed() { return highest_movement_speed; } //Lieka: Used in #showstats mainly for debugging and monitorint players
785a789,794
> Timer cheat_timer; //Lieka: Timer used to check for movement exemptions/client-based, unsolicited zone exemptions
> Timer ppu_timer; //Lieka: Timer used to track amount of time between Player Position Updates.
> int32 last_ppu_timer; //Lieka: Indicates last amount of time between the player's PPUs.
> int32 longest_ppu_timer; //Lieka: indicates longest time that the player gone without a PPU (while in the current zone).
> float movement_speed; //Lieka: Calculated movement speed in units / second.
> float highest_movement_speed; //Lieka: Highest movement speed reached.
diff c:/EQEmu_0.7.0_1102_source/zone/spdat.cpp c:/VZ-TZ-Diff/zone/spdat.cpp
639a640,672
> bool IsShadowStepSpell(int16 spell_id) {
> if (IsEffectInSpell(spell_id, SE_ShadowStep)){
> return true;
> }
> else {
> return false;
> }
> }
> bool IsSuccorSpell(int16 spell_id) {
> if (IsEffectInSpell(spell_id, SE_Succor)){
> return true;
> }
> else {
> return false;
> }
> }
> bool IsTeleportSpell(int16 spell_id) {
> if (IsEffectInSpell(spell_id, SE_Teleport)){
> return true;
> }
> else {
> return false;
> }
> }
> bool IsGateSpell(int16 spell_id) {
> if (IsEffectInSpell(spell_id, SE_Gate)){
> return true;
> }
> else {
> return false;
> }
> }
>
diff c:/EQEmu_0.7.0_1102_source/zone/spdat.h c:/VZ-TZ-Diff/zone/spdat.h
533a534,537
> bool IsShadowStepSpell(int16 spell_id);
> bool IsSuccorSpell(int16 spell_id);
> bool IsTeleportSpell(int16 spell_id);
> bool IsGateSpell(int16 spell_id);
diff c:/EQEmu_0.7.0_1102_source/zone/spell_effects.cpp c:/VZ-TZ-Diff/zone/spell_effects.cpp
1685,1689c1685,1690
< if(IsClient())
< CastToClient()->MovePC(zone->GetZoneID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);
< else
< caster->Message(13, "This spell can only be cast on players.");
<
---
> if(IsClient()){
> CastToClient()->cheat_timer.Start(3500, false); //Lieka: Exempt spells the "SummonPC" effect from triggering the MQWarp detector.
> CastToClient()->MovePC(zone->GetZoneID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC);
> } else {
> caster->Message(13, "This spell can only be cast on players.");
> }
diff c:/EQEmu_0.7.0_1102_source/zone/spells.cpp c:/VZ-TZ-Diff/zone/spells.cpp
944a945,954
> //Lieka start Edit: Fixing Warp Detector triggered for Bard Songs
> if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
> (IsTeleportSpell(spell_id)) ||
> (IsSuccorSpell(spell_id)) ||
> (IsShadowStepSpell(spell_id)) ||
> (IsGateSpell(spell_id)))
> {
> this->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the bard song effects
> }
> //Lieka end edit.
975c985,992
<
---
> if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
> (IsTeleportSpell(spell_id)) ||
> (IsSuccorSpell(spell_id)) ||
> (IsShadowStepSpell(spell_id)) ||
> (IsGateSpell(spell_id)))
> {
> c->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects
> }
2243a2261,2271
>
> //Lieka start Edit: Fixing Warp Detector triggered by spells cast on the player.
> if ((IsGateSpell(spell_id)) ||//Lieka Edit Begin: Checking effects within the spell, rather than hardcoding Spell IDs.
> (IsTeleportSpell(spell_id)) ||
> (IsSuccorSpell(spell_id)) ||
> (IsShadowStepSpell(spell_id)) ||
> (IsGateSpell(spell_id)))
> {
> spelltar->cheat_timer.Start(2000,false); //Lieka: Exempt above effects from setting off MQWarp detector due to intrazone movement generated from the spell effects
> }
> //Lieka end edit.
diff c:/EQEmu_0.7.0_1102_source/zone/zone.cpp c:/VZ-TZ-Diff/zone/zone.cpp
1188c1188
< ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance) {
---
> ZonePoint* Zone::GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance, Client* client) {
1217,1218c1217,1224
< LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
<
---
> {
> client->CheatDetected(MQZone); //[Paddy] Someone is trying to use /zone
> LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
> LogFile->write(EQEMuLog::Status, "<Real Zone Points>. %f x %f y %fz ",x,y,z);
> //worldserver.SendEmoteMessage(0,0,0,13,"<Real Zone Points>. %f x %f y %fz ",x,y,z);
> closest_zp = NULL; //Lieka: Prevent the zone request from happening.
> }
>
diff c:/EQEmu_0.7.0_1102_source/zone/zone.h c:/VZ-TZ-Diff/zone/zone.h
111c111
< ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f);
---
> ZonePoint* GetClosestZonePoint(float x, float y, float z, int32 to, float max_distance = 40000.0f, Client* client = NULL);
diff c:/EQEmu_0.7.0_1102_source/zone/zoning.cpp c:/VZ-TZ-Diff/zone/zoning.cpp
57a58
> cheat_timer.Start(35000,false); //Lieka: Allow Zone/Evac to Safe Coords without triggering MQWarp detector.
76a78
> cheat_timer.Start(3500,false); //Lieka: Allow Zone normal zoning without triggering MQZone detector.
80a83,84
>
> this->CheatDetected(MQZone); //Lieka: Bring down the hammer, they are trying to zone without meeting any of the above criteria.
107a112,116
>
> if ((this->cheat_timer.GetRemainingTime())<1 || (!this->cheat_timer.Enabled())){ //Lieka: Disable MQGate Detector if timer is active.
> this->CheatDetected(MQGate);
> }
>
170a180
> cheat_timer.Start(3500,false); //Lieka: Allow Server Forced Zoning without triggering MQZone detector.
206a217
> this->CheatDetected(MQZone); //Lieka: Bring down the hammer, we don't let hackers off that easily...
221c232,233
< if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel))
---
> if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) {
> this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate level or status requirements (i.e. zoning into FearPlane at level 30, etc)
222a235
> }
226a240
> this->cheat_timer.Start(3500,false); //Lieka: Don't set off warp detector for when a player is moved to the safe-spot for trying to access a zone without the appropriate flag.
267a282
> cheat_timer.Start(3500,false); //Lieka: Disable MQ Warp & MQ Gate Detector when zoning fails. (not high enough level, etc)
281a297
> cheat_timer.Start(3500,false);//Lieka: Disable /Warp & /Gate Detector when zoning fails. (not high enough level, etc)
410a427,430
> case WarpDetected:
> Message(15, "Returning to pre-warp location.");
> ZonePC(zoneID, x, y, z, heading, ignorerestrictions, zm);
> break;
427,477c447,511
< switch(zm) {
< case EvacToSafeCoords:
< case ZoneToSafeCoords:
< x = zone->safe_x();
< y = zone->safe_y();
< z = zone->safe_z();
< heading = heading;
< break;
< case GMSummon:
< zonesummon_x = x_pos = x;
< zonesummon_y = y_pos = y;
< zonesummon_z = z_pos = z;
< heading = heading;
<
< zonesummon_id = zoneID;
< zonesummon_ignorerestrictions = 1;
< break;
< case ZoneSolicited:
< zonesummon_x = x;
< zonesummon_y = y;
< zonesummon_z = z;
< heading = heading;
<
< zonesummon_id = zoneID;
< zonesummon_ignorerestrictions = ignorerestrictions;
< break;
< case GateToBindPoint:
< x = x_pos = m_pp.binds[0].x;
< y = y_pos = m_pp.binds[0].y;
< z = z_pos = m_pp.binds[0].z;
< heading = m_pp.binds[0].heading;
< break;
< case ZoneToBindPoint:
< x = x_pos = m_pp.binds[0].x;
< y = y_pos = m_pp.binds[0].y;
< z = z_pos = m_pp.binds[0].z;
< heading = m_pp.binds[0].heading;
<
< zonesummon_ignorerestrictions = 1;
< LogFile->write(EQEMuLog::Debug, "Player %s has died and will be zoned to bind point in zone: %s at LOC x=%f, y=%f, z=%f, heading=%f", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading);
< break;
< case SummonPC:
< zonesummon_x = x_pos = x;
< zonesummon_y = y_pos = y;
< zonesummon_z = z_pos = z;
< heading = heading;
< break;
< default:
< LogFile->write(EQEMuLog::Error, "Client::ZonePC() received a reguest to perform an unsupported client zone operation.");
< ReadyToZone = false;
< break;
---
> switch(zm) {
> case EvacToSafeCoords:
> this->cheat_timer.Start(2500,false);// Null: added a timers to this location because sometimes the ones in the other locations of code were not doing the job
> case ZoneToSafeCoords:
> this->cheat_timer.Start(2500,false);
> x = zone->safe_x();
> y = zone->safe_y();
> z = zone->safe_z();
> heading = heading;
> break;
> case GMSummon:
> this->cheat_timer.Start(2500,false);
> zonesummon_x = x_pos = x;
> zonesummon_y = y_pos = y;
> zonesummon_z = z_pos = z;
> heading = heading;
>
> zonesummon_id = zoneID;
> zonesummon_ignorerestrictions = 1;
> break;
> case ZoneSolicited:
> this->cheat_timer.Start(2500,false);
> zonesummon_x = x;
> zonesummon_y = y;
> zonesummon_z = z;
> heading = heading;
>
> zonesummon_id = zoneID;
> zonesummon_ignorerestrictions = ignorerestrictions;
> break;
> case GateToBindPoint:
> this->cheat_timer.Start(2500,false);
> x = x_pos = m_pp.binds[0].x;
> y = y_pos = m_pp.binds[0].y;
> z = z_pos = m_pp.binds[0].z;
> heading = m_pp.binds[0].heading;
> break;
> case ZoneToBindPoint:
> this->cheat_timer.Start(2500,false);
> x = x_pos = m_pp.binds[0].x;
> y = y_pos = m_pp.binds[0].y;
> z = z_pos = m_pp.binds[0].z;
> heading = m_pp.binds[0].heading;
>
> zonesummon_ignorerestrictions = 1;
> LogFile->write(EQEMuLog::Debug, "Player %s has died and will be zoned to bind point in zone: %s at LOC x=%f, y=%f, z=%f, heading=%f", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading);
> break;
> case SummonPC:
> this->cheat_timer.Start(2500,false);
> zonesummon_x = x_pos = x;
> zonesummon_y = y_pos = y;
> zonesummon_z = z_pos = z;
> heading = heading;
> break;
> case WarpDetected:
> this->cheat_timer.Disable();
> zonesummon_x = x_pos = x;
> zonesummon_y = y_pos = y;
> zonesummon_z = z_pos = z;
> heading = heading;
> break;
> default:
> LogFile->write(EQEMuLog::Error, "Client::ZonePC() received a reguest to perform an unsupported client zone operation.");
> ReadyToZone = false;
> break;
diff c:/EQEmu_0.7.0_1102_source/common/database.h c:/VZ-TZ-Diff/common/database.h
120a121
> bool SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
diff c:/EQEmu_0.7.0_1102_source/common/ruletypes.h c:/VZ-TZ-Diff/common/ruletypes.h
67a68,84
> RULE_INT ( Zone, MQWarpExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
> RULE_INT ( Zone, MQZoneExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
> RULE_INT ( Zone, MQGateExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
> RULE_INT ( Zone, MQGhostExemptStatus, 50 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
> RULE_BOOL ( Zone, EnableMQWarpDetector, false ) //Lieka: Enable the MQWarp Detector. Set to False to disable this feature.
> RULE_BOOL ( Zone, EnableMQZoneDetector, false ) //Lieka: Enable the MQZone Detector. Set to False to disable this feature.
> RULE_BOOL ( Zone, EnableMQGateDetector, false ) //Lieka: Enable the MQGate Detector. Set to False to disable this feature.
> RULE_BOOL ( Zone, EnableMQGhostDetector, false ) //Lieka: Enable the MQGhost Detector. Set to False to disable this feature.
> RULE_REAL ( Zone, MQWarpSpeedLimit, 30 ) //Lieka: Units / second that a player is allowed to travel before a warp is registered. At level 50 SoW = 4, GM Speed = 7 Default value: 10
> RULE_INT ( Zone, MQWarpDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQ Detector. This spell will be actually cast, don't pick a resistible spell. Default: 757 (Resurrection Effects)
> RULE_INT ( Zone, MQGateDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
> RULE_INT ( Zone, MQZoneDetectionSpellID, 757 ) //Lieka: Which spell ID debuff will be cast on players that incur the hammer of the MQGateDetector. This spell will be added as a debuff while zoning. Default: 757 (Resurrection Effects)
> RULE_INT ( Zone, MQGhostDetectionSpellID, 757 ) //Lieka: Which spell ID will be cast on players that incur the hammer of the MQGhostDetector. This spell will be actually cast, don't pick a resistable spell. Default: 757 (Resurrection Effects)
> RULE_BOOL ( Zone, MQDetectorDisablePenalties, false ) //Lieka: Disable penalties (including spell IDs in other MQ rules above when a player triggers a detector. Default value: false
> RULE_BOOL ( Zone, MQDetectorDisableBroadcast, false ) //Lieka: Disable the broadcast message when the use of MQ is detected. Default Value: false
> RULE_BOOL ( Zone, MQDetectorDisableSQLLogging, false ) //Lieka: Disable logging of MQDetector events into SQL. Default Value: false
>
diff c:/EQEmu_0.7.0_1102_source/common/database.cpp c:/VZ-TZ-Diff/common/database.cpp
1460a1461,1478
> bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka: Utilize the "hacker" table, but also give zone information.
> char errbuf[MYSQL_ERRMSG_SIZE];
> char *query = 0;
> int32 affected_rows = 0;
> if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {
> cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;
> return false;
> }
> safe_delete_array(query);
>
> if (affected_rows == 0)
> {
> return false;
> }
>
> return true;
> }
>

SQL Rules
insert into rule_values values (0, 'Zone:MQWarpExemptStatus', 50);
insert into rule_values values (0, 'Zone:MQZoneExemptStatus', 50);
insert into rule_values values (0, 'Zone:MQGateExemptStatus', 50);
insert into rule_values values (0, 'Zone:MQGhostExemptStatus', 50);
insert into rule_values values (0, 'Zone:EnableMQWarpDetector', 'false');
insert into rule_values values (0, 'Zone:EnableMQZoneDetector', 'false');
insert into rule_values values (0, 'Zone:EnableMQGateDetector', 'false');
insert into rule_values values (0, 'Zone:EnableMQGhostDetector', 'false');
insert into rule_values values (0, 'Zone:MQWarpSpeedLimit', 30);
insert into rule_values values (0, 'Zone:MQWarpDetectionSpellID', 757);
insert into rule_values values (0, 'Zone:MQGateDetectionSpellID', 757);
insert into rule_values values (0, 'Zone:MQZoneDetectionSpellID', 757);
insert into rule_values values (0, 'Zone:MQGhostDetectionSpellID', 757);
insert into rule_values values (0, 'Zone:MQDetectorDisablePenalties', 'false');
insert into rule_values values (0, 'Zone:MQDetectorDisableBroadcast', 'false');
insert into rule_values values (0, 'Zone:MQDetectorDisableSQLLogging', 'false');

Doodman
05-02-2008, 12:35 AM
Just a couple of comments on the code.

Firstly, excellent work. I love to see fixes for cheats and MQ type hacks.

One thing tho. might not even be yours, but they it was in yours posts:
bool Client::CheckCheat(){

float dx=cheat_x-x_pos;
float dy=cheat_y-y_pos;
float result=sqrtf((dx*dx)+(dy*dy));
return result>(RuleR(Zone, MQWarpDetectorDistance)); //Lieka: Integrated into Rules System; default value is 30, this allows for beyond GM speed without lag.

Consider pre-squaring "RuleR(Zone, MQWarpDetectorDistance)" and eliminate the sqrtf(). sqrt() is very expensive. Most times you don't need raw distance, you just need to compare the two. i.e.
Expensive: if (sqrtf((dx*dx)+(dy*dy)) > 30)
Cheaper: if (((dx*dx)+(dy*dy)) > 900)

Yet they accomplish the same result.

Just some tips, otherwise looks good.

TheLieka
05-03-2008, 01:41 AM
I'll make that change, we've also been doing some more testing with it (I've been really bogged down at work for the past month-ish), and found a few other places to refine the warp detection. I'll post those changes as soon as we get them completely ironed out.

Dax

Wiz
05-03-2008, 03:29 PM
Other things MQ does that I'm not seeing on this:

1) Let's you use a banker anywhere in the game.
2) Activate a door from anywhere in the zone (so if you have a teleport clicky zonepoint you can use it from anywhere for instance).
3) Equip things you can't use.
4) Loot corpses from anywhere in zone.
5) Bogus appearance packets (not just spawn packets) to change anyone's race / appearance etc. Not as trivial as it sounds, change a guy in a dungeon to size 50 and he's stuck.
6) Fake all sorts of things in the CastSpell packet - cast spells they don't have memorized, cast spells they have memorized as clicky spells (to prevent mana usage), cast clicky spells with a different slot (to prevent charges being used) and so on.

If there's already sanity checks in place for these, nevermind me, just wanted to bring it up.

Also remember that no warp detection will ever be perfect and can always be replicated by lag, so we've found that it's a bad idea to auto punish someone for warping - needs a human eye to determine if its authentic warping or just lag. Moving the person back to where they came from and freezing them for a few seconds might be a better idea than deathtouch.

John Adams
05-30-2008, 04:28 PM
This is exactly the kind of stuff that makes me all stiff in the britches for EQEmu again. I love this code, this effort, and the team work to iron out the iffy's.

I do not see this in the changelog yet. Is this still being evaluated for the base code? Can't wait.

KLS
05-30-2008, 05:00 PM
Yeah, once I find a crash that I *somehow* introduced while testing this I'll submit it. It's being somewhat elusive and I dun wanna submit code that has a known crash.

trevius
05-31-2008, 05:06 AM
I have added his diff from the 1102 code 2 times, but into 1108 and can't seem to get it to fully function, even though some of it does. I can't wait for this to get added into the main source! That and a few other additions will be nice.

Also, if you are doing a new update soon, KLS, I see that you don't have my fixmob post stickied. And, I think you guys sticky everything that is planned to go in at some point. The fixmob command change isn't huge, but without the changes I made, the command is only about half useful. With the changes it is fully functional and works flawlessly. They are very simple changes. I can always add them in manually before compiling, but it seems like something useful to have in the release source.

trevius
06-01-2008, 05:09 PM
Ax - the submission thread for this is locked, could you move this code over for me?

I don't have a ton of time to document this, but it's well documented in the code. Long story short -
Warp detection is now done by velocity rather than just distance. The time measurement is taken between Player Position Update packets being received. The velocity is taken by taking the distance / time since last PPU. If the detector trips, it moves the player back to his previous PPU location. Added the following rules:
For Disabling MQDetector Penalties (Punishment for the player)
For Disabling SQL Logging (haven't replaced it with text logging, but if it's a performance concern you can now disable it in the rules)
For Disabling MQDetector Broadcast
For Setting the Speed Limit (speed measured by units / second - this rule specifies the number of units a player is allowed to travel per second. From testing: 3-4 is level 50 SoW, 7 - 10 is GM Speed
Added 4 new items to #showstats:
Last PPU Time: Indicates how long it was since the last PPU for the player (in hundredths of a second)
Longest PPU Time: Records the longest time between PPUs for the player (in hundredths of a second)
Current Movement Speed: Indicates the current movement speed of the player
Highest Movement Speed: Indicates the highest movement speed of the player

That's pretty much it - the rest is the same as my original submission, but I think these updates should be what the code needed.

Let me know what you think. :)

Thanks,
Dax

This Diff was taken against 0.7.0-1102

...Removed code for size of quote



So, from looking at the source, it looks like the new eqemu binary code 1110 added in the detection from TZ/VZ, but it wasn't the most recent version of the detection which is noted in this quote. I updated to the latest 1110 code and so far it seems to be working very well. It has already detected some cheaters that I have confirmed are in fact cheaters. So far it looks great. I haven't seen any of the broadcasts and haven't heard any reports of players being punished by the tool, which are both fine with me. As far as I can tell, the only thing this does right now is log the MQ usage in the hackers table. Again, that is perfectly fine with me.

The reason I wanted to post here was to see if the latest updates on this code were under consideration for being added to the source. The last diff from TheLieka shows more features and probably better ways to detect warping and also catch more false positives. I could never get that diff to work properly with 1108. If TZ/VZ ever updates to 1110, I would love to see a diff from that with their latest anti-MQ code. I think it should be considerably less to change from 1102, since it now includes the MQ detection.

Also, I wanted to note that if anyone updates to the 1110, they will also want to add the rules listed below (and NOT the latest ones posted by TheLieka):

insert into rule_values values (0, Zone:EnableMQWarpDetector, true);
insert into rule_values values (0, Zone:EnableMQZoneDetector, true);
insert into rule_values values (0, Zone:EnableMQGateDetector, true);
insert into rule_values values (0, Zone:EnableMQGhostDetector, true);

insert into rule_values values (0, Zone:MQWarpExemptStatus, 50);
insert into rule_values values (0, Zone:MQGateExemptStatus, 50);
insert into rule_values values (0, Zone:MQZoneExemptStatus, 50);
insert into rule_values values (0, Zone:MQGhostExemptStatus, 50);

insert into rule_values values (0, Zone:MQWarpDetectorDistance, 30);
insert into rule_values values (0, Zone:MQWarpLagThreshold, 140);
insert into rule_values values (0, Zone:MQWarpThresholdTimer, 90000);

I didn't read through any of the actual source to see what all was added and what wasn't, I just read through the ruletypes.h to see what had rules added. Here is the source:

RULE_CATEGORY( Zone )
RULE_INT ( Zone, NPCGlobalPositionUpdateInterval, 60000 ) //ms between intervals of sending a position update to the entire zone.
RULE_INT ( Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT ( Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
RULE_BOOL ( Zone, EnableShadowrest, 0 ) // enables or disables the shadowrest zone feature for player corpses. Default is turned off.
RULE_INT ( Zone, MQWarpExemptStatus, -1 ) //Lieka: Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQZoneExemptStatus, -1 ) //Lieka: Required status level to exempt the MQZoneDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQGateExemptStatus, -1 ) //Lieka: Required status level to exempt the MQGateDetector. Set to -1 to disable this feature.
RULE_INT ( Zone, MQGhostExemptStatus, -1 ) //Lieka: Required status level to exempt the MGhostDetector. Set to -1 to disable this feature.
RULE_BOOL ( Zone, EnableMQWarpDetector, true ) //Lieka: Enable the MQWarp Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQZoneDetector, true ) //Lieka: Enable the MQZone Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQGateDetector, true ) //Lieka: Enable the MQGate Detector. Set to False to disable this feature.
RULE_BOOL ( Zone, EnableMQGhostDetector, true ) //Lieka: Enable the MQGhost Detector. Set to False to disable this feature.
RULE_REAL ( Zone, MQWarpDetectorDistance, 4900 ) //Lieka: Distance a player must travel between client to server location updates before a warp is registered. 30 allows for beyond GM speed without lag.
RULE_REAL ( Zone, MQWarpLagThreshold, 140 ) //Lieka: Distance beyond the Zone:MQWarpDetectorDistance that a player must travel within the MQWarpThresholdTimer amount of time before tripping the MQWarp detector. Set to 0 to disable this feature.
RULE_REAL ( Zone, MQWarpThresholdTimer, 90000 ) //Lieka: Amount of time before the warp_threshold resets to the Zone:MQWarpLagThreshold value. Default: 90000 (900 seconds/15 minutes). Set to -1 to disable this feature.
RULE_CATEGORY_END()

Huge thanks for TheLieka and the TZ/VZ team for writing this code, and to KLS and anyone who helped get it added into the source. Like I said, so far it is great. I was just curious if the latest code from TheLieka has been tried and/or is under consideration for being added to the source.

Also, someone might want to stick the rules table updates into the log file along with the hacker table one that is already there.

KLS
06-01-2008, 05:26 PM
I didn't add that since I didn't see it I can look at that stuff too.

trevius
06-01-2008, 06:05 PM
I didn't add that since I didn't see it I can look at that stuff too.

Ya, when I first started adding in the source, I added all of the original stuff he posted and it all went in very well and compiled perfectly. I think it was easier since it had the "Before" and "After" notes showing exactly where the modified code should be added into the source. It took me a couple of hours to get it in, and then I scrolled down and saw the latest update and realized I had to recheck everything I had already added in! I figured that was the case with the updates to the source in the 1110 as well.

I basically had to run diffs and modify a bunch of stuff to my already modified code and was able to get it to compile in 1108, but it didn't seem to function at all other than the zone loop issue with the zone_points problem stated previously.

Finally, I started from scratch again with unmodified 1108 source and I pulled up a diff from 1102 to 1108 showing line numbers. I then used textpad to pull up 1108 so I could modify it and turned on Line Numbers there as well. Then, for each line in the diff, I looked at the 1102 source for each line mentioned and then lined that up with the 1108 code in my diff. Then, I added all of the lines 1 by 1 to my 1108 that I had opened in textpad. It was a quite involved processes lol. But, I thought I had it all in where it should be. I tried to compile and got some errors which appeared to be related to where I was adding the code to. The first time I compiled it errored on one of the first few lines and I just moved it down 1 to where it looked like it should go, but NOT the same line number mentioned in the diff and it got past that part the next time I compiled. But, the second compile failed later and I fixed it again by moving the line down 1 in the source. So, maybe I just didn't understand how the diff posted was supposed to work. I read it as the line number mentioned is where the code change was supposed to be added to the source, but maybe it is the line after it? I don't know. Either way, once I got the compile to work, it still did nothing other than cause the zone loops from the zone_points issue.

So far, the 1110 source is functioning perfectly as far as I can tell. But, it seems like the latest update from TheLieka might make it even better, which would be quite amazing. Plus, the rules it includes in the latest update look really great. I am sure the additional options for this system would come in quite handy. I am sure you guys updating the source should have much better luck than me lol. I just follow directions, but you should be able to actually understand where things are supposed to go or not. This is some very important and useful code and I am very excited to finally free up my time watching for cheating (which I waste countless hours doing) to finally allow this feature to do it for me!

Thanks again for all of the hard work you guys do. I am more than willing to put any new code updates through a good stress test on my server. My server gets quite a good load of players on it, so they should be good for testing for issues with anything released.

TheLieka
06-03-2008, 01:23 PM
I only have a moment, so I apologize for not being able to address these things in great depth.

We had issues with zoning into certain zones setting off the warp detector with the last iteration of changes that I posted. Unfortunately, I had to fall into a possibly permenant hiatus status shortly after that, so I never had a chance to chase down the root of that problem.

Other than that, the code was working very well for us, but with limited dev resources (as every ServerOp has experienced) and conflicting goals - we had to stop working on it for the time being. We ended up reverting back to a previous version of the warp detector (the older version only judges warps based on movement distance, rather than the newer version which judges warps based on movement velocity).

The older versions are quite inadequate for accounting for lag - which the new version does very well. I do not think it would take much time for someone to go through and finalize the code for the new version, but unforunately, I simply do not have the time to do it right now.

I would love to see the few remaining glitches in this code resolved and committed to the official source - I think it would be a great asset to any ServerOp with the intention of running a legit server.

Dax

trevius
06-03-2008, 05:56 PM
Ya, I am sure we all know very well how easy it is to get sidetracked and get pulled into working on other problems instead of just focusing on one project :P Seems like I am working on something different every day lol.

The current anti-MQ detection in the 1110 code works very well and seems to catch every case of actual warping. The only negative part to it atm is that it also catches some false positives. It seems like CotH and maybe some other legit character moving features are not accounted for in the current committed version. I know you put checks in for pretty much all of them in the newest anti-MQ detection release.

Maybe if we could just get all of the false positive checks that are in the latest one added to the current committed version, that would finalize the detection to be quite complete for now anyway. Of course, it would also be great to have it run the checks against velocity instead of distance to help remove even more false positives.

I will try to do a diff of your newest anti-MQ code against the one that is currently in the committed code and post it here. Then, maybe we can all work towards pulling out the important changes and see if we can get the new stuff working. I am no coder, but I am fairly good at adjusting things as long as I have examples to work with and can grasp what it is trying to do.

I think it would be great to have some of the other rules working as well, but that isn't quite as important.

I want to make it clear that I LOVE the current MQ detection that is in the 1110 release! This will save me countless hours of time from investigating cheating and already in just a couple of days has stopped almost every incident of MQ abuse on my server! So, THANKS! I currently have the MQZone rule turned off so that I don't have to worry about zone_points and I think that helps a lot at least until I can find time to add them all in.

Even if nothing is changed in the code from here on out, I think it is a vital tool for the community and probably the best thing we have gotten in quite a while. That isn't to say that all of the other changes recently aren't great, but just that the MQ detection is simply amazing!

trevius
06-04-2008, 01:35 AM
Here is the best diff I can get for changing from the old code to the new code. I think I have everything here, but there could definitely be a mistake or 2. I think it should at least be a place to start. I had to add in vague line numbers because I don't have the exact lines where they should be in the 1110 code.

Index: zone/client.h
@@ Somewhere near Line 155 @@
WarpDetected, // Lieka: Return client to pre-warp location

@@ Somewhere near Line 190 @@
< bool WarpDetection(bool CTimer, float Distance);
bool WarpDetection(bool CTimer, float Distance, int32 last_ppu_timer);

Index: zone/client_packet.cpp
@@ Somewhere near Line 771 @@
< bool Client::WarpDetection(bool CTimer, float distance)
< {
< float last_distance;
< if (threshold_timer.GetRemainingTime() < 1 && ((RuleR(Zone, MQWarpThresholdTimer)) != -1)) { //Null: If the timer is done, reset threshold, then reset timer //Lieka: Integrated into Rules System.
< warp_threshold = (RuleR(Zone, MQWarpLagThreshold)); //Lieka: Integrated warp_threshold value into Rules System. Original Value was 140.
< threshold_timer.Start((RuleR(Zone, MQWarpThresholdTimer)), false); //Lieka: Integrated timer duration value into the Rules System. Original Value was 90000 (90 seconds).
< }
< if ((CTimer))
< return false;
< else
< {
< //Null Edit: made warp detector fire only when the sum of all the warps in a period of time are greater than a threshold
< //this makes the warp detector more lax on small warps, but still drops the hammer on the big ones.
< if (distance>140.0f) {
< last_distance = (distance-140.0f);
< warp_threshold -= last_distance;
< last_warp_distance = last_distance;
< }
< return (warp_threshold < 0); //Null: If the threshold is met, hit them with the hammer
< }
< }
< void Client::CheatDetected(CheatTypes CheatType)
< { //[Paddy] ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.
< switch (CheatType)
< {
< case MQWarp://Some zones have serious issues, turning off warp flags for these zones.
< if(!((zone->GetZoneID()==2)/*qeynos2*/ || (zone->GetZoneID()==9)/*freportw*/|| (zone->GetZoneID()==10)/*freporte*/ || (zone->GetZoneID()==34)/*nro*/ || (zone->GetZoneID()==24)/*erudin*/ || (zone->GetZoneID()==75)/*Paineel*/ || (zone->GetZoneID()==62)/*Felwitheb*/) && (RuleB(Zone, EnableMQWarpDetector) && ((this->Admin() < RuleI(Zone, MQWarpExemptStatus) || (RuleI(Zone, MQWarpExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQWarp detector (This may be depricated now, but these zones were problems in the past)
< {
< Message(13, "Your account has been reported for hacking.");
< database.SetMQDetectionFlag(this->account_name,this->name, "/MQWarp", zone->GetShortName());
< SetMana(0); //Lieka: Remove all mana from player.
< SetHP(5); //Lieka: Set player's hitpoints to 5.
< BuffFadeAll(); //Lieka: Wipe all of player's buffs.
< SpellFinished((RuleI(Zone, MQWarpDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
< worldserver.SendEmoteMessage(0,0,0,13,"<MQWarp Detector>. %s was just caught warping in %s. Come get your free kill!",this->GetName(),zone->GetLongName());
< warp_threshold = 1; //Null: bringing the detector back up to one to avoid chain detections.
< }
< break;
< case MQZone:
< if(!( (zone->GetZoneID()==31)/*sola*/ || (zone->GetZoneID()==32)/*solb*/ || (zone->GetZoneID()==25)/*nek*/ || (zone->GetZoneID()==27)/*lava*/ ) && (RuleB(Zone, EnableMQZoneDetector))&& ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1))) //Lieka: Exempt these zones from the MQZone detector (This may be depricated now, but were problems in the past)
< {
< Message(13, "Your account has been reported for hacking.");
< database.SetMQDetectionFlag(this->account_name,this->name, "/MQZone", zone->GetShortName());
< SetMana(0); //Lieka: Remove all mana from player.
< SetHP(5); //Lieka: Set player's hitpoints to 5.
< BuffFadeAll(); //Lieka: Wipe all of player's buffs.
< AddBuff(this,(RuleI(Zone, MQZoneDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
< worldserver.SendEmoteMessage(0,0,0,13,"<MQZone Detector>. %s as just caught using Macroquest to /Zone to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQZone detector has caught a cheater.
< }
< break;
< case MQGate:
< if (RuleB(Zone, EnableMQGateDetector)&& ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
< Message(13, "Your account has been reported for hacking.");
< database.SetMQDetectionFlag(this->account_name,this->name, "/MQGate", zone->GetShortName());
< this->SetZone(this->GetZoneID()); //Lieka: Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
< SetMana(0); //Lieka: Remove all mana from player.
< SetHP(5); //Lieka: Set player's hitpoints to 5.
< BuffFadeAll(); //Lieka: Wipe all of player's buffs.
< AddBuff(this,(RuleI(Zone, MQGateDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
< worldserver.SendEmoteMessage(0,0,0,13,"<MQGate Detector>. %s was just caught using Macroquest to /Gate to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
< }
< break;
< case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified
< if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
< Message(13, "Your account has been reported for hacking.");
< database.SetMQDetectionFlag(this->account_name,this->name, "/MQGhost", zone->GetShortName());
< SetMana(0); //Lieka: Remove all mana from player.
< SetHP(5); //Lieka: Set player's hitpoints to 5.
< BuffFadeAll(); //Lieka: Wipe all of player's buffs.
< SpellFinished((RuleI(Zone, MQGhostDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
< worldserver.SendEmoteMessage(0,0,0,13,"<MQGhost Detector>. %s was just caught using Macroquest to /Ghost to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
< }
< break;
< }
< }

bool Client::WarpDetection(bool CTimer, float distance, int32 last_ppu_timer) //Lieka: Completely reworked this function. Rather than basing warp detection on large movement diffs, we now base it on the player's speed (update distance / update time)
{
if (CTimer)
return false;
else
{
movement_speed = distance / (last_ppu_timer/100);
if (movement_speed > highest_movement_speed) {
highest_movement_speed = movement_speed;
}
return (movement_speed > RuleR(Zone, MQWarpSpeedLimit)); //Lieka: If the player breaks the speed limit, bring down the hammer.
}
}

void Client::CheatDetected(CheatTypes CheatType)
{ //[Paddy] ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request.
switch (CheatType)
{
case MQWarp://Some zones have serious issues, turning off warp flags for these zones.
if(!((zone->GetZoneID()==2)/*qeynos2*/ || (zone->GetZoneID()==9)/*freportw*/|| (zone->GetZoneID()==10)/*freporte*/ || (zone->GetZoneID()==34)/*nro*/ || (zone->GetZoneID()==24)/*erudin*/ || (zone->GetZoneID()==75)/*Paineel*/ || (zone->GetZoneID()==62)/*Felwitheb*/) && (RuleB(Zone, EnableMQWarpDetector) && ((this->Admin() < RuleI(Zone, MQWarpExemptStatus) || (RuleI(Zone, MQWarpExemptStatus)) == -1)))) //Lieka: Exempt these zones from the MQWarp detector (This may be depricated now, but these zones were problems in the past)
{
if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name, this->name, "/MQWarp", zone->GetShortName());
}
if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
SpellFinished((RuleI(Zone, MQWarpDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
}
if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
worldserver.SendEmoteMessage(0,0,0,13,"<MQWarp Detector>. %s was just caught warping in %s. Come get your free kill!",this->GetName(),zone->GetLongName());
}
break;
case MQZone:
if(!( (zone->GetZoneID()==31)/*sola*/ || (zone->GetZoneID()==32)/*solb*/ || (zone->GetZoneID()==25)/*nek*/ || (zone->GetZoneID()==27)/*lava*/ ) && (RuleB(Zone, EnableMQZoneDetector))&& ((this->Admin() < RuleI(Zone, MQZoneExemptStatus) || (RuleI(Zone, MQZoneExemptStatus)) == -1))) //Lieka: Exempt these zones from the MQZone detector (This may be depricated now, but were problems in the past)
{
if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name, this->name, "/MQZone", zone->GetShortName());
}
if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
AddBuff(this,(RuleI(Zone, MQZoneDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
}
if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
worldserver.SendEmoteMessage(0,0,0,13,"<MQZone Detector>. %s as just caught using Macroquest to /Zone to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQZone detector has caught a cheater.
}
break;
case MQGate:
if (RuleB(Zone, EnableMQGateDetector)&& ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name, this->name, "/MQGate", zone->GetShortName());
}
this->SetZone(this->GetZoneID()); //Lieka: Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
AddBuff(this,(RuleI(Zone, MQGateDetectionSpellID)),30); //Lieka: Integrated into Rules System. Add (de)buff on player for 30 ticks. Default: 757 (Resurrection Effects).
}
if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
worldserver.SendEmoteMessage(0,0,0,13,"<MQGate Detector>. %s was just caught using Macroquest to /Gate to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
}
break;
case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified
if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
if (!RuleB(Zone, MQDetectorDisableSQLLogging)){
Message(13, "Your account has been reported for hacking.");
database.SetMQDetectionFlag(this->account_name, this->name, "/MQGhost", zone->GetShortName());
}
if(!RuleB(Zone, MQDetectorDisablePenalties)){ //Lieka: Toggle Negative effects based on rule value
SetMana(0); //Lieka: Remove all mana from player.
SetHP(5); //Lieka: Set player's hitpoints to 5.
BuffFadeAll(); //Lieka: Wipe all of player's buffs.
SpellFinished((RuleI(Zone, MQGhostDetectionSpellID)), this); //Lieka: Integrated into Rules System. Spell to cast on players Default: 757 (Resurrection Effects).
}
if(!RuleB(Zone, MQDetectorDisableBroadcast)) //Lieka: Toggle broadcast based on rule value
worldserver.SendEmoteMessage(0,0,0,13,"<MQGhost Detector>. %s was just caught using Macroquest to /Ghost to %s. Come get your free kill!",this->GetName(),zone->GetLongName()); //Lieka: Broadcast to the server that the MQGate Detector has caught a cheater.
}
break;
}
}

@@ Somewhere near Line 890 @@

//Lieka: Track duration between Player Position Updates to determine lag (for warp detection).
if (ppu_timer.Enabled()) {
last_ppu_timer = 40000 - ppu_timer.GetRemainingTime();
if(last_ppu_timer > longest_ppu_timer) {
longest_ppu_timer = last_ppu_timer;
}
} else {
last_ppu_timer = 1;
}
ppu_timer.Start(40000, true);

@@ Somewhere near Line 910 @@
< if ((this->cheat_timer.GetRemainingTime())>1 && (this->cheat_timer.Enabled())) //Lieka: Check to see if the cheat (exemption) timer is active - this is for debugging
< {
< //Spell timer is currently active
< //worldserver.SendEmoteMessage(0,0,0,13,"Timer is Active. %d True: %s",this->cheat_timer.GetRemainingTime(), (this->cheat_timer.GetRemainingTime()>1)? "true" : "false"); //Leika Edit: Enable this to get debug messages.
< }
< else //Timer has elapsed or hasn't started, let's do a Warp Check
< {
< if ((WarpDetection(false, dist)) && ((admin <= RuleI(Zone, MQWarpExemptStatus)) || (RuleI(Zone, MQWarpExemptStatus) == -1))) //Exempt from warp detection if admin level is > Rule:Zone:MQWarpExemptStatus
< {
< printf("Warping Detected by %S Acct: %s Distance: %f.", GetName(), AccountName(), GetLWDistance());
< CheatDetected(MQWarp); //Lieka: Execute MQWarp function on offending player
< }

if (((this->cheat_timer.GetRemainingTime())>1 && (this->cheat_timer.Enabled())) || longest_ppu_timer < 2) //Lieka: Check to see if the cheat (exemption) timer is active - this is for debugging
{
//Spell timer is currently active
//worldserver.SendEmoteMessage(0,0,0,13,"Timer is Active. %d True: %s",this->cheat_timer.GetRemainingTime(), (this->cheat_timer.GetRemainingTime()>1)? "true" : "false"); //Leika Edit: Enable this to get debug messages.
}
else //Timer has elapsed or hasn't started, let's do a Warp Check
{
if ((WarpDetection(false, dist, last_ppu_timer)) && ((RuleB(Zone,EnableMQGateDetector) && (admin <= RuleI(Zone, MQWarpExemptStatus)) || (RuleI(Zone, MQWarpExemptStatus) == -1)))) //Exempt from warp detection if admin level is > Rule:Zone:MQWarpExemptStatus
{
printf("Warping Detected by %s Distance: %f.", GetName(), dist);
this->CastToClient()->MovePC(zone->GetZoneID(), x_pos, y_pos, z_pos, heading, 2, WarpDetected); //Lieka Edit: Move player back to pre-warp location
CheatDetected(MQWarp); //Lieka: Execute MQWarp function on offending player
return;
}

Index: zone/mob.cpp
@@ Somewhere near Line 100 @@
< threshold_timer(0), //Lieka: Timer to allow exemptions MQWarp related to lag

@@ Somewhere near Line 105 @@
ppu_timer(0), //Lieka: Timer to track time between Player Update Packets (to detect lag) for MQWarp detection

@@ Somewhere near Line 125 @@
< warp_threshold = 140; //Null: set the threshold on creation of mob instance
< last_warp_distance = 0; //Null: set this one to zero also just because.

longest_ppu_timer = 0; //Lieka: reset longest player packet update timer record on creation of mob instance
last_ppu_timer = 0; //Lieka: reset last player packet update timer record on creation of mob instance
movement_speed = 0; //Lieka: reset player movement speed record on creation of mob instance
highest_movement_speed = 0; //Lieka: reset highest recorded player movement speed on creation of mob instance

@@ Somewhere near Line 875 @@
< client->Message(0, " Last Warp Distance: %f Threshold Remaining: %f", GetLWDistance(), GetWarpThreshold()); //Null: added this to check players last warp distance for debuging.

client->Message(0, " Last Player Position Update Timer: %i Longest Player Position Update Timer: %i", GetLastPPUTimer(), GetLongestPPUTimer()); //Lieka: added this to monitor player lag for MQWarp detection.
client->Message(0, " Current Movement Speed: %i Highest Movement Speed: %i", GetMovementSpeed(), GetHighestMovementSpeed()); //Lieka: added this to monitor player's movement speed (based on last PPU update / PPU time.








Index: zone/mob.h
@@ Somewhere near Line 455 @@
< float GetLWDistance() { return last_warp_distance; } //Null: these are used to return the values to #showstats
< float GetWarpThreshold() { return warp_threshold; } //this one too

int32 GetLastPPUTimer() { return last_ppu_timer; } //Lieka: Used in #showstats mainly for debugging and monitoring players
int32 GetLongestPPUTimer() { return longest_ppu_timer; } //Lieka: Used in #showstats mainly for debugging and monitoring players
int32 GetMovementSpeed() { return movement_speed; } //Lieka: Used in #showstats mainly for debugging and monitoring players
int32 GetHighestMovementSpeed() { return highest_movement_speed; } //Lieka: Used in #showstats mainly for debugging and monitorint players


@@ Somewhere near Line 785 @@
< Timer threshold_timer; //Null: threshold timer
< float warp_threshold; //Null: threshold for warp detector
< float last_warp_distance; //Null: last distance logged as a warp, used for logs and #showstats

Timer ppu_timer; //Lieka: Timer used to track amount of time between Player Position Updates.
int32 last_ppu_timer; //Lieka: Indicates last amount of time between the player's PPUs.
int32 longest_ppu_timer; //Lieka: indicates longest time that the player gone without a PPU (while in the current zone).
float movement_speed; //Lieka: Calculated movement speed in units / second.
float highest_movement_speed; //Lieka: Highest movement speed reached.

Index: zone/spell_effects.cpp
@@ Somewhere near Line 1680 @@
Message(15, "You have been summoned!");

Index: zone/zoning.cpp
@@ Somewhere near Line 430 @@
case WarpDetected:
Message(15, "Returning to pre-warp location.");
ZonePC(zoneID, x, y, z, heading, ignorerestrictions, zm);
break;

@@ Somewhere near Line 450 @@
case WarpDetected:
this->cheat_timer.Disable();
zonesummon_x = x_pos = x;
zonesummon_y = y_pos = y;
zonesummon_z = z_pos = z;
heading = heading;
break;


Index: common/ruletypes.h
@@ Somewhere near Line 75 @@
< RULE_REAL ( Zone, MQWarpDetectorDistance, 30 ) //Lieka: Distance a player must travel between client to server location updates before a warp is registered. 30 allows for beyond GM speed without lag.
< RULE_REAL ( Zone, MQWarpLagThreshold, 140 ) //Lieka: Distance beyond the Zone:MQWarpDetectorDistance that a player must travel within the MQWarpThresholdTimer amount of time before tripping the MQWarp detector. Set to 0 to disable this feature.
< RULE_REAL ( Zone, MQWarpThresholdTimer, 90000 ) //Lieka: Amount of time before the warp_threshold resets to the Zone:MQWarpLagThreshold value. Default: 90000 (900 seconds/15 minutes). Set to -1 to disable this feature.

RULE_REAL ( Zone, MQWarpSpeedLimit, 30 ) //Lieka: Units / second that a player is allowed to travel before a warp is registered. At level 50 SoW = 4, GM Speed = 7 Default value: 10
RULE_BOOL ( Zone, MQDetectorDisablePenalties, false ) //Lieka: Disable penalties (including spell IDs in other MQ rules above when a player triggers a detector. Default value: false
RULE_BOOL ( Zone, MQDetectorDisableBroadcast, false ) //Lieka: Disable the broadcast message when the use of MQ is detected. Default Value: false
RULE_BOOL ( Zone, MQDetectorDisableSQLLogging, false ) //Lieka: Disable logging of MQDetector events into SQL. Default Value: false



Index: zone/client.cpp
@@ Somewhere near Line 2300 @@
< return result>(RuleR(Zone, MQWarpDetectorDistance)); //Lieka: Integrated into Rules System; default value is 30, this allows for beyond GM speed without lag.

spider661
06-28-2008, 02:04 PM
case MQGhost: //Lieka: Not currently implemented, but the framework is in place - just needs detection scenarios identified

is this working now or no and if not has anyone found a way around it? i have seen a problem with it on my server as of late and would be nice to get told about it when im not online.

even if its just a simple check is pc close to a npc and what is the npc faction if its hostile there cheating i would be happy with that most the custom zones i use i just set all the npcs to the default hostile faction that npc loot editor sets it to. faction is 14329

KingMort
06-30-2008, 03:13 PM
On behalf of Raid Addicts, I want to thank you for this fix. I am sure it will help a ton to stop cheaters on my server.. And I am sure it will also help my stress level. :)

Your a God send thanks, and keep up the good work !


King Mortenson
www.raidaddicts.org

KingMort
07-10-2008, 08:28 PM
Seems that I am having zone looping issues in certain zones. Any Ideas why?

trevius
07-10-2008, 09:50 PM
Your zone_points table isn't fully updated. Personally, I disabled the mqzone detection on my server so that I don't have to mess with it until either I or someone else gets all of the zone points added in and updated. The rest of it works fine. To disable mqzone detection, look at the rules posted for it.

KingMort
07-12-2008, 04:04 PM
Yeah it is disabled but still in some zones people are going into loops, zoning in and out over and over or something... Only started happening after the code went in..

TheLieka
07-12-2008, 07:58 PM
Never heard of this one. Is it only certain zones? If so, what zones?

Dax

cavedude
07-12-2008, 08:00 PM
I had this looping problem with original code on the forums, however TGC has never had this issue with the altered version KLS put into the official code base. It was the incorrect zone_points in the DB causing it of course (putting in valid coords for both x,y,z, and target_x,y,z corrects this), and I believe KLS removed the zone check in the core code.

Angelox
07-12-2008, 10:00 PM
I had this looping problem with original code on the forums, however TGC has never had this issue with the altered version KLS put into the official code base. It was the incorrect zone_points in the DB causing it of course (putting in valid coords for both x,y,z, and target_x,y,z corrects this), and I believe KLS removed the zone check in the core code.

What? I hope not! I've been all week fixing the zones - TheLieka already said what the problem was and what to do (disable in rule_values). This just needs to get all the zone_points fixed and in place; just a little work and I'll have it done in a while. I was planning on posting the fixes(when ready), but if it' out of the source, then it's pointless.

KLS
07-12-2008, 10:11 PM
In the official source I still have the check but I took out the forced zone cancel which was what was causing the loop. The detection remained in place.

I'll be up for adding it back in if we can get the zone points completely updated.

KingMort
07-12-2008, 10:12 PM
Hehe sorry if I caused a stir , perhaps someone could help me out.. Is our code out of date? Our good friend Ndnet is my prime coder atm so maybe you could help us fix this. Seems there are many zones where this is happening.. Players are getting frustrated.

Angelox
07-12-2008, 10:39 PM
In the official source I still have the check but I took out the forced zone cancel which was what was causing the loop. The detection remained in place.

I'll be up for adding it back in if we can get the zone points completely updated.

Did you quote it out or removed it? I need it to 'loop' so I can test after fixed (make sure it quit looping) - I don't want to post anything that's not tested.
What I'm doing is a slow process - already I thought i was testing for loops, so I guess I need to start over again.

Angelox
07-13-2008, 08:37 AM
Hehe sorry if I caused a stir , perhaps someone could help me out.. Is our code out of date? Our good friend Ndnet is my prime coder atm so maybe you could help us fix this. Seems there are many zones where this is happening.. Players are getting frustrated.

What version EqEmu are you running?

KLS
07-13-2008, 08:52 AM
Basically there's a block of code in zone.cpp that looks kinda like:

if(closest_dist>(40000.0f) && closest_dist<max_distance2)
{
if(client)
client->CheatDetected(MQZone); //[Paddy] Someone is trying to use /zone
LogFile->write(EQEMuLog::Status, "WARNING: Closest zone point for zone id %d is %f, you might need to update your zone_points table if you dont arrive at the right spot.",to,closest_dist);
LogFile->write(EQEMuLog::Status, "<Real Zone Points>. %f x %f y %fz ",x,y,z);
}

if you add the line:
closest_zp = NULL;

Right before the closing bracket it will attempt to cancel the zone request. I took it out so it just logs the invalid zone since if it cancels a zone at a zone point it will dump the player right back there and they'll attempt to zone again; thus an endless loop. Ideally it should probably send a cancel zone request and send you to the safe point in the zone like with other cancel zone requests, wouldn't fix a bad zone table but players wouldn't loop endlessly.

Angelox
07-13-2008, 10:41 AM
Thanks - Hopefully, when this is all done, The only players getting looped will be the cheaters.
I'm also making sure the player lands in a proper position after zone (for example, not facing the zone he just came from).

For anyone who has time to help;
If any one is doing this or wants to help, please post here. I started with Kunark (maybe you can work another expansion).
It's a simple process , once you understand what you are doing (I hope I understood!).

I use 'MySql Query Browser'
Here's an example;
The line SELECT zone,y,x,z,heading,target_y,target_x,target_z,targ et_heading,target_zone_id FROM zone_points where zone ='firiona' and target_zone_id ='85'or zone= 'lakeofillomen'and target_zone_id ='84';
will produce this (open in a new window , I can't post HTML here I guess);
http://www.nahunta.org/~angelox/zonetest.html
what you see is the 'fixed' version of zone_points between FV and IllOmen. before fix, both sets of x, y, z were set to '0'.
Since I isolated the two occasions of zoning between mentioned zones , it's now much easier to change the right coords, and you can see which settings you need, for example;
x,y,z is where you should be in firiona and is the same as target_x, target_y, target_z in lakeofillomen, because that's where you were sent from. Same deal for lakeofillomens zone_points.
After the first query, you can re use the same one, just change 'zone' and 'target_zone_id' for the new query (Keep everything windowed, so you can switch from client to MySql Browser).

Since Kunark has so many zones, I went to EqAtlas (http://www.eqatlas.com/atlas.html), and printed the Zone Connection Map for Kunark, I then wrote in the zone number by each zone name there for reference. Now that I have a chart of all the zones with the connecting zonelines, I can find what I need for the query. Once that zone line is done, I go over the line with a red pen ( so I know it's done).
MySql Query Browser has 'on the fly' edit feature, so you can change the coords you are looking at.
#reloadzps doesn't always work right - so, if you think you got it right, and it still doesn't work, then you need to log out and restart the server.

I just thought I'd post in case anyone wants to help, we can get it done faster, if not I'll get it done, just will take a while.

trevius
07-13-2008, 05:59 PM
Is there any way to add an IP Address column to the Hackers Table and have it log the IP that is being used to cheat from? This would be useful for the players who try to lie their way out of it. I am all about giving a second chance if I think one is warranted, but I hate being lied to.

As long as someone confesses and promises not to do it again, I am ok with that. But, if they lie about it and make up a story about someone else doing it on their account, I would prefer to just ban them outright if I can prove that they are lying.

Angelox
07-13-2008, 06:41 PM
This should exempt any zones that are not ready;
UPDATE zone_points set x='999999',y='999999', z='999999' where x='0' and y='0' and z='0';
Since the query looks for only the ones that have x,y, and z with 0's, it will only fill in the ones that are not fixed. So far, it looks to be working.
For anyone just tuning in to this thread , Leika has already posted pre-Kunark fixes in the first part of this thread.

Angelox
07-13-2008, 06:52 PM
Also (my edit time ran out);
I did notice some zones still will act funny, "closest_zp = NULL;" or not, until I did the 999999 fill with the query.
Here's more that I noticed; if you do a #goto in GM mode, when you zone, that's where you will land when you get to the other zone (same coords you #goto'd before) - I just spent hours in Howling Stones figuring this out. HS has one entry point, two exits, and both exits far away from zin and each other. So, although you may think you are exempt from the restriction in GM mode, don't believe it: Some things will not work right unless you play/test under normal conditions.

So_1337
08-01-2008, 11:26 PM
I see that this is no longer stickied, but is work continuing on this? The detection is in, but there doesn't appear to be any form of punishment implemented that I can tell as of 1119.

Just checking in. The detection performs beautifully, thanks to everyone who has put work into this. It is sorely needed.

LordAdakos
11-24-2011, 12:50 AM
Thread necroing, sorry -- Wondering if there was a way to implement punishment via perl script, or debuff ?