Skip to content

Commit

Permalink
Pawn side of publicizing kick and ban reasons
Browse files Browse the repository at this point in the history
  • Loading branch information
RussellLVP committed Jun 12, 2020
1 parent d0f732b commit f9bd0bf
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 62 deletions.
2 changes: 2 additions & 0 deletions data/irc_messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"join": "<color:2>[%d] <color:3>*** %s has joined the game.",
"login": "<color:2>[%d] <color:3>*** %s has logged in.",
"guest": "<color:2>[%d] <color:3>*** %s has decided to play as %s (guest).",

"quit": "<color:2>[%d] <color:3>*** %s has left the game (%s).",
"quit-reason": "<color:2>[%d] <color:3>*** %s has left the game (%s): %s",

"join-ip-gpci": "<prefix:%><color:5>*** <color:4>%s (Id:%d) IP address:<color:5> %s<color:4>, serial:<color:5> %s",

Expand Down
3 changes: 2 additions & 1 deletion javascript/features/settings/pawn_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import Setting from 'entities/setting.js';

// List of PawnConfig settings with their unique values and settings. Must be synced with Pawn. The
// settings can be in any category, of any type, as long as the identifier is a valid one.
// Next ID: 6
// Next ID: 7
const kSynchronizedSettings = new Map([
[ 'abuse/ignore_sole_passenger_damage', { id: 5 } ],
[ 'abuse/kick_reason_public', { id: 6 } ],
[ 'vehicles/drifting_enabled', { id: 1 } ],
[ 'vehicles/drifting_max_angle', { id: 2 } ],
[ 'vehicles/drifting_min_angle', { id: 3 } ],
Expand Down
1 change: 1 addition & 0 deletions javascript/features/settings/setting_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default [
new Setting('abuse', 'detector_cleo_proaim', Setting.TYPE_BOOLEAN, false, 'Should the CLEO Pro-Aim detector be enabled?'),
new Setting('abuse', 'detector_illegal_vehicle_entry', Setting.TYPE_BOOLEAN, true, 'Should the illegal vehicle entry detector be enabled?'),
new Setting('abuse', 'ignore_sole_passenger_damage', Setting.TYPE_BOOLEAN, true, 'Ignore damage done by sole vehicle passengers?'),
new Setting('abuse', 'kick_reason_public', Setting.TYPE_BOOLEAN, true, 'Whether kick reasons should be shared publicly.'),
new Setting('abuse', 'pawn_based_detectors', Setting.TYPE_BOOLEAN, true, 'Enable the Pawn-based abuse detectors?'),
new Setting('abuse', 'spawn_vehicle_admin_override', Setting.TYPE_BOOLEAN, true, 'Should administrators override vehicle spawning restrictions?'),
new Setting('abuse', 'spawn_vehicle_throttle_time', Setting.TYPE_NUMBER, 180, 'Minimum number of seconds between spawning two vehicles.'),
Expand Down
53 changes: 25 additions & 28 deletions pawn/Driver/Driver.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -279,46 +279,45 @@ public OnPlayerKeyStateChange(playerid, newkeys, oldkeys) {
return 1;
}

// Enable the |left| and or |right| blinkers for |playerid| in |vehicleId|
SetBlinker(playerid, vehicleId, bool:left, bool:right) {
new const blinkerModel = 19294;
// Enable the |left| and/or |right| blinkers for |playerId| who is driving the |vehicleId|.
SetBlinker(playerId, vehicleId, bool: left, bool: right) {
new const kBlinkerModel = 19294;
new const modelId = GetVehicleModel(vehicleId);

if(!VehicleModel(modelId)->isNitroInjectionAvailable()) {
if (!VehicleModel(modelId)->isNitroInjectionAvailable())
return;
}

new Float:sizeX, Float:sizeY, Float:sizeZ;
new Float: sizeX, Float: sizeY, Float: sizeZ;
GetVehicleModelInfo(modelId, VEHICLE_MODEL_INFO_SIZE, sizeX, sizeY, sizeZ);

if (right) {
if (!IsValidDynamicObject(g_blinkerObjects[playerid][0])) {
g_blinkerObjects[playerid][0] = CreateDynamicObject(blinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerid][0], vehicleId, sizeX/2.23, sizeY/2.23,
0.1, 0, 0, 0);

g_blinkerObjects[playerid][1] = CreateDynamicObject(blinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerid][1], vehicleId, sizeX/2.23, -sizeY/2.23,
0.1, 0, 0, 0);
if (!IsValidDynamicObject(g_blinkerObjects[playerId][0])) {
g_blinkerObjects[playerId][0] = CreateDynamicObject(kBlinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerId][0], vehicleId, sizeX / 2.23,
sizeY / 2.23, 0.1, 0, 0, 0);

g_blinkerObjects[playerId][1] = CreateDynamicObject(kBlinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerId][1], vehicleId, sizeX / 2.23,
-sizeY / 2.23, 0.1, 0, 0, 0);
}
} else {
DestroyDynamicBlinkerObject(playerid, 0);
DestroyDynamicBlinkerObject(playerid, 1);
DestroyDynamicBlinkerObject(playerId, 0);
DestroyDynamicBlinkerObject(playerId, 1);
}

if (left) {
if (!IsValidDynamicObject(g_blinkerObjects[playerid][2])) {
g_blinkerObjects[playerid][2] = CreateDynamicObject(blinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerid][2], vehicleId, -sizeX/2.23, sizeY/2.23,
0.1, 0, 0, 0);

g_blinkerObjects[playerid][3] = CreateDynamicObject(blinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerid][3], vehicleId, -sizeX/2.23, -sizeY/2.23,
0.1, 0, 0, 0);
if (!IsValidDynamicObject(g_blinkerObjects[playerId][2])) {
g_blinkerObjects[playerId][2] = CreateDynamicObject(kBlinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerId][2], vehicleId, -sizeX / 2.23,
sizeY / 2.23, 0.1, 0, 0, 0);

g_blinkerObjects[playerId][3] = CreateDynamicObject(kBlinkerModel, 0, 0, 0, 0, 0, 0);
AttachDynamicObjectToVehicle(g_blinkerObjects[playerId][3], vehicleId, -sizeX / 2.23,
-sizeY / 2.23, 0.1, 0, 0, 0);
}
} else {
DestroyDynamicBlinkerObject(playerid, 2);
DestroyDynamicBlinkerObject(playerid, 3);
DestroyDynamicBlinkerObject(playerId, 2);
DestroyDynamicBlinkerObject(playerId, 3);
}
}

Expand Down Expand Up @@ -461,8 +460,6 @@ public OnUnoccupiedVehicleUpdate(vehicleid, playerid, passenger_seat, Float:new_

g_vehicleLastUnoccupiedSyncMark[vehicleid] = currentTime;

printf("[debug] MarkVehicleMoved(%d)", vehicleid);

// Calls the MarkVehicleMoved() JavaScript native, which will mark the |vehicleid| for respawn.
MarkVehicleMoved(vehicleid);

Expand Down
10 changes: 9 additions & 1 deletion pawn/Driver/PawnConfig.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

// Section: abuse
new bool: g_abuseIgnoreSolePassengerDamage = true;
new bool: g_abuseKickReasonsPublic = true;

// Section: drifting
new bool: g_driftingEnabled = false;
Expand All @@ -16,9 +17,10 @@ new Float: g_driftingMinSpeed = 50.0;

// These are the unique Ids for each of the properties that can be updated. They must be identical
// between the Pawn and the JavaScript code.
// Next ID: 6
// Next ID: 7
enum PawnConfigProperty {
kAbuseIgnoreSolePassengerDamage = 5,
kAbuseKickReasonPublic = 6,
kVehiclesDriftingEnabled = 1,
kVehiclesDriftingMaxAngle = 2,
kVehiclesDriftingMinAngle = 3,
Expand All @@ -36,6 +38,9 @@ public OnPawnConfigDataChange(PawnConfigProperty: property, Float: numberValue)
case kAbuseIgnoreSolePassengerDamage:
g_abuseIgnoreSolePassengerDamage = !!intValue;

case kAbuseKickReasonPublic:
g_abuseKickReasonsPublic = !!intValue;

case kVehiclesDriftingEnabled:
g_driftingEnabled = !!intValue;

Expand All @@ -55,3 +60,6 @@ public OnPawnConfigDataChange(PawnConfigProperty: property, Float: numberValue)
printf("[PawnConfig][warning] Invalid property in update: %d", _: property);
}
}

// Functions to allow legacy parts of the gamemode to access the values. Only when needed.
AreKickReasonsPublic() { return g_abuseKickReasonsPublic ? 1 : 0; }
2 changes: 1 addition & 1 deletion pawn/Elements/Player/Connections/disconnect.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ OnPlayerLVPDisconnect(playerId, reason) {
g_LastSlappedBy[i] = INVALID_PLAYER_ID;
}

if (!BanManager->wasAutomaticallyBanned(playerId) && !Player(playerId)->isNonPlayerCharacter()) {
if (!Player(playerId)->isNonPlayerCharacter()) {
Announcements->announcePlayerDisconnected(
playerId, BanManager->wasUndercoverKicked(playerId) ? 1 /* left */
: reason);
Expand Down
27 changes: 24 additions & 3 deletions pawn/Entities/Players/Player.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by the GPLv2 license, a copy of which can
// be found in the LICENSE file.

#define MAX_KICK_REASON 64

/**
* The Player class will encapsulate various bits of information about the player's current state.
* This is unrelated to their account, statistics or stored data, and thus should be looked at as
Expand Down Expand Up @@ -35,6 +37,11 @@ class Player <playerId (MAX_PLAYERS)> {
// occurs when GetPlayerIp is called OnPlayerDisconnect.
new m_ipAddress[16];

// Data to indicate why a particular player was kicked from the server. Used to create richer,
// more complete messages rather than the catch-all "kicked" reason.
new PlayerKickReason: m_kickReason;
new m_kickTextualReason[MAX_KICK_REASON];

// ---- PRIVATE INLINE CONVENIENCE METHODS -----------------------------------------------------

// Convenience method to enable a flag on the player.
Expand Down Expand Up @@ -84,6 +91,9 @@ class Player <playerId (MAX_PLAYERS)> {
m_levelIsTemporary = false;
m_connectionTime = Time->currentTime();

m_kickReason = UnknownKickReason;
m_kickTextualReason[0] = 0;

this->enableFlag(IsConnectedPlayerFlag);
if (IsPlayerNPC(playerId))
this->enableFlag(IsNonPlayerCharacterFlag);
Expand Down Expand Up @@ -176,7 +186,7 @@ class Player <playerId (MAX_PLAYERS)> {
SendClientMessage(playerId, Color::Information, "available through www.sa-mp.nl/chat");

// Schedule for the player to be kicked from the server.
this->scheduleKick();
this->scheduleKick(BannedKickReason, reason);
}

/**
Expand All @@ -200,7 +210,7 @@ class Player <playerId (MAX_PLAYERS)> {
SendClientMessage(playerId, Color::GangChat, reason);

// Schedule for the player to be kicked from the server.
this->scheduleKick();
this->scheduleKick(KickedKickReason, reason);
}

/**
Expand All @@ -209,7 +219,10 @@ class Player <playerId (MAX_PLAYERS)> {
* the server-sided connection when the Kick() method get called, even if there still are
* other, in-flight undelivered messages.
*/
public scheduleKick() {
public scheduleKick(PlayerKickReason: reason, textualReason[]) {
m_kickReason = reason;
format(m_kickTextualReason, sizeof(m_kickTextualReason), "%s", textualReason);

TogglePlayerControllable(playerId, false);
ShowPlayerDialog(playerId, -1, 0, "", "", "", ""); // close all open dialogs.

Expand Down Expand Up @@ -289,6 +302,14 @@ class Player <playerId (MAX_PLAYERS)> {
return m_ipAddress;
}

public inline PlayerKickReason: kickReason() {
return m_kickReason;
}

public inline kickReasonString() {
return m_kickTextualReason;
}

// ---- SETTERS FOR NORMAL DATA MEMBERS --------------------------------------------------------

/**
Expand Down
2 changes: 1 addition & 1 deletion pawn/Features/Account/AccountCommands.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class AccountCommands {
SendClientMessage(victimId, Color::Information, "Oops.. seems like you're bugged! Please reconnect!");

CSave__OnPlayerDisconnect(victimId);
Player(victimId)->scheduleKick();

Player(victimId)->scheduleKick(ForceReconnectKickReason, "");
return 1;
}

Expand Down
18 changes: 1 addition & 17 deletions pawn/Features/Account/Bans/BanManager.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@ class BanManager {
// The query used for creating a new entry in the logs table.
new m_createEntryQuery;

// Maintain a boolean indicating whether the player was banned automatically.
new bool: m_automaticallyBanned[MAX_PLAYERS];

// Maintain a boolean indicating whether the player was kicked by an undercover administrator.
new bool: m_undercoverKicked[MAX_PLAYERS];

Expand Down Expand Up @@ -147,7 +144,6 @@ class BanManager {
*/
@list(OnPlayerConnect)
public onPlayerConnect(playerId) {
m_automaticallyBanned[playerId] = false;
m_undercoverKicked[playerId] = false;
}

Expand Down Expand Up @@ -258,10 +254,8 @@ class BanManager {
SendClientMessage(playerId, Color::Information, "You may appeal this ban on our forums (http://forum.sa-mp.nl) or on our IRC channel,");
SendClientMessage(playerId, Color::Information, "available at https://sa-mp.nl/chat, or through Discord at https://sa-mp.nl/discord.");

m_automaticallyBanned[playerId] = true;

// The Player class has the functionality required to actually kick this player.
Player(playerId)->scheduleKick();
Player(playerId)->scheduleKick(AutoBannedKickReason, "");
}

/**
Expand Down Expand Up @@ -340,16 +334,6 @@ class BanManager {
this->createDatabaseEntry("ban", administratorId, playerId, reason, banIpAddress, expirationTime);
}

/**
* Returns a boolean indicating whether this player has been automatically banned by the Ban
* Manager. If so, we may not want to display an announcement for their leaving.
*
* @param playerId Id of the player to check this for.
*/
public bool: wasAutomaticallyBanned(playerId) {
return m_automaticallyBanned[playerId];
}

public setUndercoverKicked(playerId, bool: undercover) {
m_undercoverKicked[playerId] = undercover;
}
Expand Down
44 changes: 34 additions & 10 deletions pawn/Features/Gameplay/Communication/Announcements.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,8 @@ class Announcements {
* @param reason The reason why they're disconnecting from the server.
*/
public announcePlayerDisconnected(playerId, reason) {
// Since the player's nickname in the Player class is already emptied before this is executed,
// we grab the name with help of the GetPlayerName native.
new playerName[MAX_PLAYER_NAME+1];
GetPlayerName(playerId, playerName, sizeof(playerName));

new reasonString[16];
new reasonText[128];

switch (reason) {
case 0 /** timed out **/: {
Expand All @@ -143,9 +139,32 @@ class Announcements {
Player(playerId)->nicknameString(), playerId);
}
case 2 /** kicked or banned **/: {
format(reasonString, sizeof(reasonString), "kicked");
format(m_formatBuffer, sizeof(m_formatBuffer), "* %s (Id:%d) has left {A9C4E4}Las Venturas Playground{CCCCCC} (kicked).",
playerName, playerId);
switch (Player(playerId)->kickReason()) {
case KickedKickReason: {
format(reasonString, sizeof(reasonString), "kicked");
format(reasonText, sizeof(reasonText), "%s", Player(playerId)->kickReasonString());
}
case BannedKickReason: {
format(reasonString, sizeof(reasonString), "banned");
format(reasonText, sizeof(reasonText), "%s", Player(playerId)->kickReasonString());
}
case AutoBannedKickReason:
format(reasonString, sizeof(reasonString), "banned");

case ForceReconnectKickReason:
format(reasonString, sizeof(reasonString), "reconnecting");

default:
format(reasonString, sizeof(reasonString), "kicked");
}

if (AreKickReasonsPublic() && reasonText[0]) {
format(m_formatBuffer, sizeof(m_formatBuffer), "* %s (Id:%d) has left {A9C4E4}Las Venturas Playground{CCCCCC} (%s): %s",
Player(playerId)->nicknameString(), playerId, reasonString, reasonText);
} else {
format(m_formatBuffer, sizeof(m_formatBuffer), "* %s (Id:%d) has left {A9C4E4}Las Venturas Playground{CCCCCC} (%s).",
Player(playerId)->nicknameString(), playerId, reasonString);
}
}
default: {
format(reasonString, sizeof(reasonString), "leaving");
Expand All @@ -157,8 +176,13 @@ class Announcements {
this->distributeAnnouncement(ConnectionMessageAnnouncement, Color::ConnectionMessage, m_formatBuffer);

// Announce this player's disconnection to people watching from IRC.
format(m_formatBuffer, sizeof(m_formatBuffer), "%d %s %s", playerId, playerName, reasonString);
EchoMessage("quit", "dsz", m_formatBuffer);
if (AreKickReasonsPublic() && reasonText[0]) {
format(m_formatBuffer, sizeof(m_formatBuffer), "%d %s %s", playerId, Player(playerId)->nicknameString(), reasonString, reasonText);
EchoMessage("quit-reason", "dsz", m_formatBuffer);
} else {
format(m_formatBuffer, sizeof(m_formatBuffer), "%d %s %s", playerId, Player(playerId)->nicknameString(), reasonString);
EchoMessage("quit", "dsz", m_formatBuffer);
}
}

/**
Expand Down
12 changes: 12 additions & 0 deletions pawn/Interface/Enumerations.pwn
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@ enum ColorPickerResultTarget {
PlayerColor,
JavaScriptColor
};

/**
* Reason why a player has left the server, to avoid having "2" (kicked) as a catch-all.
*/
enum PlayerKickReason {
UnknownKickReason,

KickedKickReason,
BannedKickReason,
AutoBannedKickReason,
ForceReconnectKickReason
};

0 comments on commit f9bd0bf

Please sign in to comment.