EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Server Code Submissions (https://www.eqemulator.org/forums/forumdisplay.php?f=669)
-   -   MQWarp/MQZone/MQGate Detector (Code Name: The VZTZ Hammer!) (https://www.eqemulator.org/forums/showthread.php?t=24761)

TheLieka 03-28-2008 05:20 PM

MQWarp/MQZone/MQGate Detector (Code Name: The VZTZ Hammer!)
 
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:

Code:

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

Code:

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:
Code:

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

Code:

bool        SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
.\common\database.cpp

After:

Code:

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:

Code:

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:

Code:

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:

Code:

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

After:

Code:

        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:

Code:

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



.\zone\client.cpp

Change (Insert Red Lines):

Code:

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:

Code:

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

Add:

Code:

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):

Code:

        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):

Code:

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:

Code:

        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:

Code:

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:

Code:

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

Add:

Code:

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):

Code:

        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):

Code:

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):

Code:

        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):

Code:

        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:

Code:

        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:

Code:

        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):

Code:

        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):

Code:

                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):

Code:

        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):

Code:

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):

Code:

                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:

Code:

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:

Code:

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

.\zone\spdat.cpp

After:

Code:

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:

Code:

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):

Code:

                        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):

Code:

        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:

Code:

        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:

Code:

                        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:

Code:

        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:

Code:

                //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:

Code:

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

Code:

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

.\zone\zone.cpp

Change:

Code:

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

Code:

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

Code:

        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:

Code:

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

Add:

Code:

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

Code:

                case GMSummon:
Add:

Code:

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

After:

Code:

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

Code:

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

Code:

                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:

Code:

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

Code:

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

Add:

Code:

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

Code:

                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:

Code:

                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):

Code:

[color=red]                //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);
                return;


Change (Insert Red Lines):

Code:

        //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:

Code:

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:

Code:

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

Code:

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:

Code:

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


Code:

        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:

Code:

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

Code:

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.

Code:

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.

Code:

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
Code:


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

Code:

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:

Code:

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;
Code:

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

Quote:

Originally Posted by TheLieka (Post 145527)
REQUIRED SQL:
Code:


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 :

Code:


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):

Code:

AddBuff(this,(RuleI(Zone, MQZoneDetectionSpell)),30);
under Client::CheatDetected

needs to be:

Code:

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

Code:

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

Code:

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

Code:

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

Code:

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.

Code:

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

Code:

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
Code:

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,heading,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.

Code:

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
Code:

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
Code:

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
Code:

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:
Quote:

Code:

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

Quote:

Originally Posted by TheLieka (Post 147116)
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):

Code:

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:

Code:

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

Quote:

Originally Posted by KLS (Post 149780)
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!


All times are GMT -4. The time now is 12:17 PM.

Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.