@@ -41,6 +41,12 @@ constexpr auto ALLOWED_ACK_LAG = 2000;
41
41
42
42
enum Spells : uint32
43
43
{
44
+ BLINK = 1953 ,
45
+ BLINK_COOLDOWN_REDUCTION = 23025 , // Reduces Blink cooldown by 2 seconds.
46
+ GLYPH_OF_BLINK = 56365 , // Increases Blink distance by 5 yards.
47
+ SHADOWSTEP = 36554 ,
48
+ FILTHY_TRICKS_RANK_1 = 58414 , // Reduces Shadowstep cooldown by 5 seconds.
49
+ FILTHY_TRICKS_RANK_2 = 58415 , // Reduces Shadowstep cooldown by 10 seconds.
44
50
SHACKLES = 38505 ,
45
51
LFG_SPELL_DUNGEON_DESERTER = 71041 ,
46
52
BG_SPELL_DESERTER = 26013 ,
@@ -93,8 +99,7 @@ void AnticheatMgr::StartHackDetection(Player* player, MovementInfo movementInfo,
93
99
94
100
if (player->IsInFlight () || player->GetTransport () || player->GetVehicle ())
95
101
{
96
- m_Players[key].SetLastMovementInfo (movementInfo);
97
- m_Players[key].SetLastOpcode (opcode);
102
+ m_Players[key].SetLastInformations (movementInfo, opcode, GetPlayerCurrentSpeedRate (player));
98
103
return ;
99
104
}
100
105
@@ -127,8 +132,57 @@ void AnticheatMgr::StartHackDetection(Player* player, MovementInfo movementInfo,
127
132
BGStartExploit (player, movementInfo);
128
133
}
129
134
}
130
- m_Players[key].SetLastMovementInfo (movementInfo);
131
- m_Players[key].SetLastOpcode (opcode);
135
+ m_Players[key].SetLastInformations (movementInfo, opcode, GetPlayerCurrentSpeedRate (player));
136
+ }
137
+
138
+ uint32 AnticheatMgr::GetTeleportSkillCooldownDurationInMS (Player* player) const
139
+ {
140
+ switch (player->getClass ())
141
+ {
142
+ case CLASS_ROGUE:
143
+ if (player->HasAura (FILTHY_TRICKS_RANK_2))
144
+ return 20000u ;
145
+ else if (player->HasAura (FILTHY_TRICKS_RANK_1))
146
+ return 25000u ;
147
+ return 30000u ;
148
+ case CLASS_MAGE:
149
+ if (player->HasAura (BLINK_COOLDOWN_REDUCTION)) // Bonus from Vanilla/Early TBC pvp gear.
150
+ return 13000u ;
151
+ return 15000u ;
152
+ default :
153
+ return 0u ;
154
+ }
155
+ }
156
+
157
+ float AnticheatMgr::GetTeleportSkillDistanceInYards (Player* player) const
158
+ {
159
+ switch (player->getClass ())
160
+ {
161
+ case CLASS_ROGUE: // The rogue's teleport spell is Shadowstep.
162
+ return 25 .0f ; // Synful-Syn: Help needed! At least, 25 yards adjustment is better than nothing!
163
+ // The spell can be casted at a maximum of 25 yards from the middle of the ennemy and teleports the player a short distance behind the target which might be over 25 yards, especially when the target is facing the rogue.
164
+ // Using Shadowstep on Onyxia at as far as I could moved me by 44 yards. Doing it on a blood elf in duel moved me 29 yards.
165
+ case CLASS_MAGE: // The mage's teleport spell is Blink.
166
+ if (player->HasAura (GLYPH_OF_BLINK))
167
+ return 25 .1f ; // Includes a 0.1 miscalculation margin.
168
+ return 20 .1f ; // Includes a 0.1 miscalculation margin.
169
+ default :
170
+ return 0 .0f ;
171
+ }
172
+ }
173
+
174
+ // Get how many yards the player can move in a second.
175
+ float AnticheatMgr::GetPlayerCurrentSpeedRate (Player* player) const
176
+ {
177
+ // we need to know HOW is the player moving
178
+ // TO-DO: Should we check the incoming movement flags?
179
+ if (player->HasUnitMovementFlag (MOVEMENTFLAG_SWIMMING))
180
+ return player->GetSpeed (MOVE_SWIM);
181
+ else if (player->IsFlying ())
182
+ return player->GetSpeed (MOVE_FLIGHT);
183
+ else if (player->HasUnitMovementFlag (MOVEMENTFLAG_WALKING))
184
+ return player->GetSpeed (MOVE_WALK);
185
+ return player->GetSpeed (MOVE_RUN);
132
186
}
133
187
134
188
void AnticheatMgr::SpeedHackDetection (Player* player, MovementInfo movementInfo)
@@ -179,32 +233,20 @@ void AnticheatMgr::SpeedHackDetection(Player* player, MovementInfo movementInfo)
179
233
}
180
234
}
181
235
182
- uint32 distance2D = (uint32) movementInfo.pos .GetExactDist2d (&m_Players[key].GetLastMovementInfo ().pos );
236
+ float distance2D = movementInfo.pos .GetExactDist2d (&m_Players[key].GetLastMovementInfo ().pos );
183
237
184
238
// We don't need to check for a speedhack if the player hasn't moved
185
239
// This is necessary since MovementHandler fires if you rotate the camera in place
186
240
if (!distance2D)
187
241
return ;
188
242
189
- // we need to know HOW is the player moving
190
- // TO-DO: Should we check the incoming movement flags?
191
- UnitMoveType moveType;
192
- if (player->HasUnitMovementFlag (MOVEMENTFLAG_SWIMMING))
193
- moveType = MOVE_SWIM;
194
- else if (player->IsFlying ())
195
- moveType = MOVE_FLIGHT;
196
- else if (player->HasUnitMovementFlag (MOVEMENTFLAG_WALKING))
197
- moveType = MOVE_WALK;
198
- else
199
- moveType = MOVE_RUN;
200
-
201
- // how many yards the player can do in one sec.
202
- // We remove the added speed for jumping because otherwise permanently jumping doubles your allowed speed
203
- uint32 speedRate = (uint32)(player->GetSpeed (moveType));
204
-
205
243
// how long the player took to move to here.
206
244
uint32 timeDiff = getMSTimeDiff (m_Players[key].GetLastMovementInfo ().time , movementInfo.time );
207
245
246
+ float speedRate = GetPlayerCurrentSpeedRate (player);
247
+ if (timeDiff <= ALLOWED_ACK_LAG)
248
+ speedRate = std::max (speedRate, m_Players[key].GetLastSpeedRate ()); // The player might have been moving with a previously faster speed. This should help mitigate a false positive from loosing a speed increase buff.
249
+
208
250
if (int32 (timeDiff) < 0 && sConfigMgr ->GetOption <bool >(" Anticheat.CM.TIMEMANIPULATION" , true ))
209
251
{
210
252
if (sConfigMgr ->GetOption <bool >(" Anticheat.CM.WriteLog" , true ))
@@ -257,19 +299,36 @@ void AnticheatMgr::SpeedHackDetection(Player* player, MovementInfo movementInfo)
257
299
BuildReport (player, COUNTER_MEASURES_REPORT);
258
300
}
259
301
302
+ // Adjust distance from Blink/Shadowstep.
303
+ if (player->HasAura (BLINK) || player->HasAura (SHADOWSTEP))
304
+ {
305
+ // Only adjust the travelled distance if the player previously didn't use a movement spell or didn't move at all since they previously used the movement spell.
306
+ if (!m_Players[key].GetJustUsedMovementSpell () || timeDiff >= GetTeleportSkillCooldownDurationInMS (player))
307
+ {
308
+ m_Players[key].SetJustUsedMovementSpell (true );
309
+ distance2D = std::max (distance2D - GetTeleportSkillDistanceInYards (player), 0 .0f );
310
+ }
311
+ }
312
+ else
313
+ {
314
+ m_Players[key].SetJustUsedMovementSpell (false );
315
+ }
316
+
260
317
// this is the distance doable by the player in 1 sec, using the time done to move to this point.
261
- uint32 clientSpeedRate = distance2D * 1000 / timeDiff;
318
+ float clientSpeedRate = 0 .0f ;
319
+ if (float floatTimeDiff = float (timeDiff))
320
+ clientSpeedRate = distance2D * 1000 .0f / floatTimeDiff;
262
321
263
322
// we create a diff speed in uint32 for further precision checking to avoid legit fall and slide
264
- uint32 diffspeed = clientSpeedRate - speedRate;
323
+ float diffspeed = clientSpeedRate - speedRate;
265
324
266
325
// create a conf to establish a speed limit tolerance over server rate set speed
267
326
// this is done so we can ignore minor violations that are not false positives such as going 1 or 2 over the speed limit
268
- _assignedspeeddiff = sConfigMgr ->GetOption <uint32 >(" Anticheat.SpeedLimitTolerance" , 0 );
327
+ float assignedspeeddiff = sConfigMgr ->GetOption <float >(" Anticheat.SpeedLimitTolerance" , 0 . 0f );
269
328
270
329
// We did the (uint32) cast to accept a margin of tolerance for seasonal spells and buffs such as sugar rush
271
330
// We check the last MovementInfo for the falling flag since falling down a hill and sliding a bit triggered a false positive
272
- if ((diffspeed >= _assignedspeeddiff ) && !m_Players[key].GetLastMovementInfo ().HasMovementFlag (MOVEMENTFLAG_FALLING))
331
+ if ((diffspeed >= assignedspeeddiff ) && !m_Players[key].GetLastMovementInfo ().HasMovementFlag (MOVEMENTFLAG_FALLING))
273
332
{
274
333
if (clientSpeedRate > speedRate * 1 .05f )
275
334
{
0 commit comments