[Feature request] Prevent vote spamming
Some few individuals like to distract all players on a server or want to bully specific players. One way they do this is vote spamming.
Kicking these players has only limited impact on their behavior. They may reconnect (also with a different nickname) and restart their voting campaign.
Idea for solution
Block votes of nicknames known less than five minutes or which have been kicked or banned less than five minutes ago. For that, track some kind of reputation.
Implementation
- Define a
avg_vote_wait_time
time span (e.g. 5 minutes). -
future_time_span_multiplier() :=
5/3 - sqrt(random_float_from_0_to_1())
. -
new_vote_permission_on() :=
current_timestamp() + avg_vote_wait_time * future_time_span_multiplier()
. - Create a persistent table of two columns
nickname
andvote_permission_on
. - When a nickname joins and there is no entry for the nickname in the table,
insert an entry with
new_vote_permission_on()
asvote_permission_on
. - When a nickname is kicked or banned, remove all its entries from the table.
- Block a nickname’s vote if and only if
there is a entry for the nickname in the table
with
vote_permission_on
being after now. -
Optionally, for housekeeping and privacy:
- Define a
expiry_time_span
(e.g. 1 month). - Extend the table by a column
expiry_on
. -
new_expiry_on() :=
current_timestamp + expiry_time_span * future_time_span_multiplier()
. - When a nickname joins, do instead of the above:
- If there is no entry for the nickname in the table,
insert an entry with
new_vote_permission_on()
asvote_permission_on
, andnew_expiry_on()
asexpiry_on
. - Else update the nickname’s
expiry_on
tonew_expiry_on()
.
- If there is no entry for the nickname in the table,
insert an entry with
- On certain events (after a match was finished as well as on every day and server stop and start) run a cleanup job.
- During the cleanup job, each entry in the table is checked:
- If its
expiry_on
is not after now, delete the entry. - Else:
- If the nickname is connected, set its
expiry_on
tonew_expiry_on()
. - If (Not else if) its
vote_permission_on
is not after now, setvote_permission_on
to some constant date long ago.
- If the nickname is connected, set its
- If its
- Define a
-
Optional: The check for the vote permission could also
dynamically depend on the rejected vote frequency
to prevent blocking when there is no need to:
- Increase
avg_vote_wait_time
to e.g. 10min. -
max_vote_wait_time := 5/3 * avg_vote_wait_time
(see above). - Define a
rejected_vote_penalty_half_life
as maybeavg_vote_wait_time * ln(2)
. -
rejected_vote_penalty_changed_on := current_timestamp()
. -
rejected_vote_penalty := 0
. -
get_rejected_vote_penalty() :=
rejected_vote_penalty * 0.5 ^
((current_timestamp() - rejected_vote_penalty_changed_on)
/ rejected_vote_penalty_half_life)
. - When a (not blocked) vote is rejected:
-
rejected_vote_penalty :=
get_rejected_vote_penalty() + avg_vote_wait_time
-
rejected_vote_penalty_changed_on := current_timestamp()
.
-
- Instead of the above, block a nickname’s vote if and only if
there is a entry for the nickname in the table with
vote_permission_on + get_rejected_vote_penalty() - max_vote_wait_time
being after now. - In the same manner check the
vote_permission_on
during the cleanup job.
- Increase