Skip to content

Commit b953584

Browse files
committed
Disable the ability to inflict damage for High FPS players
1 parent 0b292b6 commit b953584

File tree

6 files changed

+88
-9
lines changed

6 files changed

+88
-9
lines changed

javascript/features/settings/pawn_config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import { Setting } from 'entities/setting.js';
66

77
// List of PawnConfig settings with their unique values and settings. Must be synced with Pawn. The
88
// settings can be in any category, of any type, as long as the identifier is a valid one.
9-
// Next ID: 15
9+
// Next ID: 18
1010
const kSynchronizedSettings = new Map([
1111
[ 'abuse/disable_out_of_range_damage', { id: 14 } ],
1212
[ 'abuse/fake_car_entry_prevention_enter_ms', { id: 11 } ],
1313
[ 'abuse/fake_car_entry_prevention_exit_ms', { id: 12 } ],
14+
[ 'abuse/highfps_damage_ignored_sec', { id: 15 } ],
15+
[ 'abuse/highfps_damage_sample_sec', { id: 16 } ],
16+
[ 'abuse/highfps_damage_threshold', { id: 17 } ],
1417
[ 'abuse/ignore_sole_passenger_damage', { id: 5 } ],
1518
[ 'abuse/kick_reason_public', { id: 6 } ],
1619
[ 'abuse/kill_attribution_time_sec', { id: 7 } ],

javascript/features/settings/setting_list.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pawn/Driver/Driver.pwn

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ native ReportTrailerUpdate(vehicleid, trailerid);
2828
#define VEHICLE_KEYS_BINDING_BLINKER_LEFT KEY_LOOK_LEFT
2929
#define VEHICLE_KEYS_BINDING_GRAVITY KEY_ANALOG_UP
3030

31+
// Warn the player once every X milliseconds about their damage being disabled due to High FPS.
32+
new const kHighFpsWarningTimeMs = 60 * 1000;
33+
3134
// Polygon that encloses the area of Las Venturas, on the insides of the highway.
3235
new const Float: kLasVenturasAreaPolygon[] = {
3336
1353.59, 832.49,
@@ -57,6 +60,11 @@ new STREAMER_TAG_AREA: g_areaLasVenturas;
5760
// Time (in milliseconds) until when damage issued by a particular player should be disabled.
5861
new g_damageDisabledExpirationTime[MAX_PLAYERS] = { 0, ... };
5962

63+
// Counter for number of subsequent High FPS detections, and time at which the last warning was
64+
// issued to a particular player, to let them know damage was disabled.
65+
new g_highFramerateCounter[MAX_PLAYERS] = { 0, ... };
66+
new g_highFramerateWarningTime[MAX_PLAYERS] = { 0, ... };
67+
6068
// Boolean that indicates whether a particular player is currently in Las Venturas.
6169
new bool: g_inLasVenturas[MAX_PLAYERS] = { false, ... };
6270

@@ -139,6 +147,8 @@ InitializeAreas() {
139147

140148
public OnPlayerConnect(playerid) {
141149
g_aimbotSuspicionCount[playerid] = 0;
150+
g_highFramerateCounter[playerid] = 0;
151+
g_highFramerateWarningTime[playerid] = 0;
142152
g_lastTakenDamageIssuerId[playerid] = -1;
143153
g_lastTakenDamageTime[playerid] = 0;
144154
g_sprayTagStartTime[playerid] = 0;
@@ -182,6 +192,50 @@ public OnPlayerDisconnect(playerid, reason) {
182192
return PlayerEvents(playerid)->onPlayerDisconnect(reason);
183193
}
184194

195+
// Processes framerates of all connected human players and marks them as regular or high FPS. When
196+
// they've been marked as high FPS for a certain number of seconds, their damage might be disabled.
197+
ProcessHighFrameratePlayers() {
198+
new const currentTime = GetTickCount();
199+
200+
for (new playerId = 0; playerId < GetPlayerPoolSize(); ++playerId) {
201+
if (!IsPlayerConnected(playerId) || IsPlayerNPC(playerId))
202+
continue; // skip unconnected players and NPCs
203+
204+
// Reset and bail when the |playerId|'s framerate is within acceptable bounds
205+
if (PlayerManager->framesPerSecond(playerId) < g_abuseHighFramerateDamageThreshold) {
206+
g_highFramerateCounter[playerId] = 0;
207+
continue;
208+
}
209+
210+
if (++g_highFramerateCounter[playerId] < g_abuseHighFramerateDamageSampleSec)
211+
continue; // not enough subsequent samples yet
212+
213+
// (1) Disable the |playerId|'s damage for the configured amount of seconds.
214+
g_damageDisabledExpirationTime[playerId] = max(
215+
g_damageDisabledExpirationTime[playerId],
216+
currentTime + g_abuseHighFramerateDamageIgnoredSec * 1000);
217+
218+
// (2) Share a warning with the |playerId|, but at most once per |kHighFpsWarningTimeMs|.
219+
if (g_highFramerateWarningTime[playerId] == 0 ||
220+
(currentTime - g_highFramerateWarningTime[playerId]) > kHighFpsWarningTimeMs) {
221+
g_highFramerateWarningTime[playerId] = currentTime;
222+
223+
new warningMessage[128];
224+
format(
225+
warningMessage, sizeof(warningMessage),
226+
"* Your ability to inflict damage has been disabled because your FPS topped %d.",
227+
g_abuseHighFramerateDamageThreshold);
228+
229+
SendClientMessage(playerId, Color::Error, warningMessage);
230+
231+
// (3) Log this to the console as well, so that we can inspect how often this happens.
232+
printf("[highfps] %s (Id:%d) has been detected as a High FPS player with an FPS of %d.",
233+
Player(playerId)->nicknameString(), playerId,
234+
PlayerManager->framesPerSecond(playerId));
235+
}
236+
}
237+
}
238+
185239
// Returns whether vehicle keys are available to the |playerid|, based on their current state.
186240
bool: AreVehicleKeysAvailable(playerid) {
187241
return !PlayerSyncedData(playerid)->hasMinigameName() &&
@@ -468,8 +522,9 @@ public OnPlayerStateChange(playerid, newstate, oldstate) {
468522
// to avoid players from abusing vehicle bugs to give them an advantage in a fight.
469523
if ((oldstate == PLAYER_STATE_DRIVER || oldstate == PLAYER_STATE_PASSENGER)
470524
&& g_abuseFakeCarEntryPreventionExitMs > 0) {
471-
g_damageDisabledExpirationTime[playerid] =
472-
GetTickCount() + g_abuseFakeCarEntryPreventionExitMs;
525+
g_damageDisabledExpirationTime[playerid] = max(
526+
g_damageDisabledExpirationTime[playerid],
527+
GetTickCount() + g_abuseFakeCarEntryPreventionExitMs);
473528
}
474529

475530
return LegacyPlayerStateChange(playerid, newstate, oldstate);
@@ -656,8 +711,9 @@ public OnPlayerUpdate(playerid) {
656711
switch (animationIndex) {
657712
case 1043 /* CAR_OPEN_LHS */, 1044 /* CAR_OPEN_RHS */,
658713
1026 /* CAR_GETIN_LHS */, 1027 /* CAR_GETIN_RHS */: {
659-
g_damageDisabledExpirationTime[playerid] =
660-
GetTickCount() + g_abuseFakeCarEntryPreventionEnterMs;
714+
g_damageDisabledExpirationTime[playerid] = max(
715+
g_damageDisabledExpirationTime[playerid],
716+
GetTickCount() + g_abuseFakeCarEntryPreventionEnterMs);
661717
}
662718
}
663719
}

pawn/Driver/PawnConfig.pwn

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
new bool: g_abuseDisableOutOfRangeDamage = true;
1010
new g_abuseFakeCarEntryPreventionEnterMs = 3000;
1111
new g_abuseFakeCarEntryPreventionExitMs = 1750;
12+
new g_abuseHighFramerateDamageIgnoredSec = 10;
13+
new g_abuseHighFramerateDamageSampleSec = 3;
14+
new g_abuseHighFramerateDamageThreshold = 105;
1215
new bool: g_abuseIgnoreSolePassengerDamage = true;
1316
new bool: g_abuseKickReasonsPublic = true;
1417
new g_abuseKillAttributionTimeSec = 10;
@@ -27,11 +30,14 @@ new bool: g_vehicleKeysBlockedInLasVenturas = true;
2730

2831
// These are the unique Ids for each of the properties that can be updated. They must be identical
2932
// between the Pawn and the JavaScript code.
30-
// Next ID: 15
33+
// Next ID: 18
3134
enum PawnConfigProperty {
3235
kAbuseDisableOutOfRangeDamage = 14,
3336
kAbuseFakeCarEntryPreventionEnterMs = 11,
3437
kAbuseFakeCarEntryPreventionExitMs = 12,
38+
kAbuseHighFPSDamageIgnoredSec = 15,
39+
kAbuseHighFPSDamageSampleSec = 16,
40+
kAbuseHighFPSDamageThreshold = 17,
3541
kAbuseIgnoreSolePassengerDamage = 5,
3642
kAbuseKickReasonPublic = 6,
3743
kAbuseKillAttributionTimeSec = 7,
@@ -61,6 +67,15 @@ public OnPawnConfigDataChange(PawnConfigProperty: property, Float: numberValue)
6167
case kAbuseFakeCarEntryPreventionExitMs:
6268
g_abuseFakeCarEntryPreventionExitMs = intValue;
6369

70+
case kAbuseHighFPSDamageIgnoredSec:
71+
g_abuseHighFramerateDamageIgnoredSec = intValue;
72+
73+
case kAbuseHighFPSDamageSampleSec:
74+
g_abuseHighFramerateDamageSampleSec = intValue;
75+
76+
case kAbuseHighFPSDamageThreshold:
77+
g_abuseHighFramerateDamageThreshold = intValue;
78+
6479
case kAbuseIgnoreSolePassengerDamage:
6580
g_abuseIgnoreSolePassengerDamage = !!intValue;
6681

pawn/Interface/TimerController.pwn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class TimerController {
117117

118118
Annotation::ExpandList<SecondTimerPerPlayer>(playerId);
119119
}
120+
121+
ProcessHighFrameratePlayers();
120122
}
121123

122124
/**

pawn/config.pwn

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
* incrementing this version. Significant changes justify a new Major release, use your gut feel.
88
*/
99
class Version {
10-
public const Major = 50;
11-
public const Minor = 8;
10+
public const Major = 51;
11+
public const Minor = 0;
1212
};
1313

1414
// Set this to 1 if you'd like to build Las Venturas Playground in release mode. This affects
1515
// whether config-release.pwn tries to define the prod password salt.
16-
#define BuildGamemodeInReleaseMode 1
16+
#define BuildGamemodeInReleaseMode 0
1717

1818
// Toggling the availability of certain features should be done by changing their values in this
1919
// class. Please follow existing conventions and add features based on their alphabetical order.

0 commit comments

Comments
 (0)