Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature---send a message on connect (remind rules, announce event, give Discord url, etc) #392

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
df23b2d
Create welcome.py
ElGuillermo Dec 1, 2023
6c0c99a
Update hooks.py
ElGuillermo Dec 1, 2023
8d0fe6a
Update hooks.py
ElGuillermo Dec 1, 2023
d0727c3
Update hooks.py
ElGuillermo Dec 1, 2023
e6e39e9
Update hooks.py
ElGuillermo Dec 1, 2023
b500a19
Update hooks.py
ElGuillermo Dec 2, 2023
80464f2
Update and rename welcome.py to message_on_connect.py
ElGuillermo Dec 2, 2023
80f7177
Update hooks.py
ElGuillermo Dec 2, 2023
bfb1db9
Update hooks.py
ElGuillermo Dec 2, 2023
1089c9d
Update message_on_connect.py
ElGuillermo Dec 2, 2023
fd2ef13
Update miscellaneous.js
ElGuillermo Dec 2, 2023
a46653a
Update App.js
ElGuillermo Dec 2, 2023
6d30402
Update message_on_connect.py
ElGuillermo Dec 2, 2023
aa1b591
Update hooks.py
ElGuillermo Dec 2, 2023
03d5a94
Update App.js
ElGuillermo Dec 2, 2023
8ee70fb
Update App.js
ElGuillermo Dec 3, 2023
f96ec2f
Update header.js
ElGuillermo Dec 3, 2023
829e372
Update auto_settings.py
ElGuillermo Dec 3, 2023
3f8ee71
Update auto_settings.py
ElGuillermo Dec 3, 2023
c56681b
Update user_settings.py
ElGuillermo Dec 3, 2023
8ab72a9
Update user_settings.py
ElGuillermo Dec 3, 2023
5dca702
Update hooks.py
ElGuillermo Dec 3, 2023
7893608
Update hooks.py
ElGuillermo Dec 3, 2023
0c70629
Update hooks.py
ElGuillermo Dec 3, 2023
9cb1134
Update __init__.py
ElGuillermo Dec 3, 2023
fc908c2
Update __init__.py
ElGuillermo Dec 3, 2023
5d285aa
Update user_settings.py
ElGuillermo Dec 3, 2023
dcb08f8
Update hooks.py
ElGuillermo Dec 3, 2023
a6b11ed
Update urls.py
ElGuillermo Dec 3, 2023
3739534
Update miscellaneous.js
ElGuillermo Dec 3, 2023
8cdc9fe
Update App.js
ElGuillermo Dec 6, 2023
847c217
Update hooks.py
ElGuillermo Dec 6, 2023
6396f37
Update user_settings.py
ElGuillermo Dec 7, 2023
000b836
Update hooks.py
ElGuillermo Dec 7, 2023
7b8e655
Merge branch 'master' into Feature---Send-a-message-to-remind-the-rul…
cemathey Dec 8, 2023
8a6b519
Add permissions
cemathey Dec 8, 2023
86e4a28
Merge branch 'master' into Feature---Send-a-message-to-remind-the-rul…
cemathey Sep 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions rcon/api_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from rcon.user_config.gtx_server_name import GtxServerNameChangeUserConfig
from rcon.user_config.log_line_webhooks import LogLineWebhookUserConfig
from rcon.user_config.log_stream import LogStreamUserConfig
from rcon.user_config.message_on_connect import MessageOnConnectUserConfig
from rcon.user_config.name_kicks import NameKickUserConfig
from rcon.user_config.rcon_connection_settings import RconConnectionSettingsUserConfig
from rcon.user_config.rcon_server_settings import RconServerSettingsUserConfig
Expand Down Expand Up @@ -81,20 +82,23 @@
def parameter_aliases(alias_to_param: Dict[str, str]):
"""Specify parameter aliases of a function. This might be useful to preserve backwards
compatibility or to handle parameters named after a Python reserved keyword.
Takes a mapping of aliases to their parameter name."""

def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for alias, param in alias_to_param.items():
if alias in kwargs:
kwargs[param] = kwargs.pop(alias)
return func(*args, **kwargs)

wrapper._parameter_aliases = alias_to_param
return wrapper

return decorator


def get_rcon_api(credentials: ServerInfoType | None = None) -> "RconAPI":
"""Return a initialized Rcon connection to the game server
Expand Down Expand Up @@ -578,9 +582,11 @@ def get_online_mods(self) -> list[AdminUserType]:
def get_ingame_mods(self) -> list[AdminUserType]:
return ingame_mods()

@parameter_aliases({
"from": "from_",
})
@parameter_aliases(
{
"from": "from_",
}
)
def get_historical_logs(
self,
player_name: str | None = None,
Expand Down Expand Up @@ -1745,6 +1751,41 @@ def validate_log_stream_config(
reset_to_default=reset_to_default,
)

def get_message_on_connect_config(self):
return MessageOnConnectUserConfig.load_from_db()

def set_message_on_connect_config(
self,
by: str,
config: dict[str, Any] | BaseUserConfig | None = None,
reset_to_default: bool = False,
**kwargs,
) -> bool:
return self._validate_user_config(
command_name=inspect.currentframe().f_code.co_name, # type: ignore
by=by,
model=MessageOnConnectUserConfig,
data=config or kwargs,
dry_run=False,
reset_to_default=reset_to_default,
)

def validate_message_on_connect_config(
self,
by: str,
config: dict[str, Any] | BaseUserConfig | None = None,
reset_to_default: bool = False,
**kwargs,
) -> bool:
return self._validate_user_config(
command_name=inspect.currentframe().f_code.co_name, # type: ignore
by=by,
model=MessageOnConnectUserConfig,
data=config or kwargs,
dry_run=True,
reset_to_default=reset_to_default,
)

def get_date_scoreboard(self, start: int, end: int):
try:
start_date = datetime.fromtimestamp(int(start))
Expand Down
56 changes: 51 additions & 5 deletions rcon/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
is_description_word,
is_help_word,
)
from rcon.user_config.message_on_connect import MessageOnConnectUserConfig
from rcon.user_config.rcon_server_settings import RconServerSettingsUserConfig
from rcon.user_config.real_vip import RealVipUserConfig
from rcon.user_config.vac_game_bans import VacGameBansUserConfig
Expand Down Expand Up @@ -94,7 +95,7 @@ def initialise_vote_map(rcon: Rcon, struct_log):
vote_map.gen_selection()
vote_map.reset_last_reminder_time()
vote_map.apply_results()
except:
except Exception:
logger.exception("Something went wrong in vote map init")


Expand Down Expand Up @@ -221,7 +222,9 @@ def handle_new_match_start(rcon: Rcon, struct_log):
# Check that the log is less than 5min old
if (datetime.utcnow() - log_time).total_seconds() < 5 * 60:
# then we use the current map to be more accurate
if current_map.map.name.lower() == log_map_name.lower().removesuffix(" night"):
if current_map.map.name.lower() == log_map_name.lower().removesuffix(
" night"
):
map_name_to_save = current_map
guessed = False
else:
Expand All @@ -248,7 +251,7 @@ def handle_new_match_start(rcon: Rcon, struct_log):
guessed=guessed,
start_timestamp=int(struct_log["timestamp_ms"] / 1000),
)
except:
except Exception:
raise
finally:
initialise_vote_map(rcon, struct_log)
Expand Down Expand Up @@ -388,7 +391,7 @@ def ban_if_has_vac_bans(rcon: Rcon, player_id: str, name: str):
admin_name="VAC BOT",
)
logger.info(
"Player %s was banned due VAC history, last ban: %s days ago",
"Player '%s' was banned due VAC history, " "last ban: %s days ago",
str(player),
bans.get("DaysSinceLastBan"),
)
Expand Down Expand Up @@ -730,7 +733,7 @@ def _set_real_vips(rcon: Rcon, struct_log):
min_vip_slot = config.minimum_number_vip_slots
vip_count = rcon.get_vips_count()

remaining_vip_slots = max(desired_nb_vips - vip_count, max(min_vip_slot, 0))
remaining_vip_slots = max(desired_nb_vips - vip_count, min_vip_slot, 0)
rcon.set_vip_slots_num(remaining_vip_slots)
logger.info("Real VIP set slots to %s", remaining_vip_slots)

Expand Down Expand Up @@ -771,3 +774,46 @@ def notify_camera(rcon: Rcon, struct_log):

if config.welcome:
temporary_welcome(rcon, struct_log["message"], 60)


def _message_on_connect(rcon: Rcon, struct_log, player_name, player_id):
config = MessageOnConnectUserConfig.load_from_db()
if not config.enabled:
return # Feature is disabled

message_on_connect_txt = config.non_seed_time_text

players_count_request = rcon.get_gamestate()
players_count = (
players_count_request["num_allied_players"]
+ players_count_request["num_axis_players"]
)
if players_count < config.seed_limit:
message_on_connect_txt = config.seed_time_text

def send_message_on_connect():
try:
rcon.message_player(
player_id=player_id,
message=message_on_connect_txt,
by="Message_on_connect",
save_message=False,
)
except Exception as e:
logger.error(
"Could not send MessageOnConnect to player '%s' (%s) : %s",
player_name,
player_id,
e,
)

# The player might not yet have finished connecting in order to send messages.
t = Timer(10, send_message_on_connect)
pendingTimers[player_id].append((RconInvalidNameActionType.warn, t))
t.start()


@on_connected()
@inject_player_ids
def message_on_connect(rcon: Rcon, struct_log, player_name, player_id):
_message_on_connect(rcon, struct_log, player_name, player_id)
1 change: 1 addition & 0 deletions rcon/user_config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
gtx_server_name,
log_line_webhooks,
log_stream,
message_on_connect,
name_kicks,
rcon_connection_settings,
rcon_server_settings,
Expand Down
64 changes: 64 additions & 0 deletions rcon/user_config/message_on_connect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from typing import TypedDict

from pydantic import Field

from rcon.user_config.utils import BaseUserConfig, key_check, set_user_config

SEED_TIME_TEXT = (
"Welcome !\n"
"The server is seeding\n\n"
"[ All time rules ]\n"
"Stay fun, be polite, communicate.\n"
"No teamkill, follow officers orders.\n\n"
"[ + Seed time rules ]\n"
"Do not capture the 4th point\n"
"Do not destroy garries in red zone\n\n"
"Have a good game !"
)
NON_SEED_TIME_TEXT = (
"Welcome !\n\n"
"[ All time rules ]\n"
"Stay fun, be polite, communicate.\n"
"No teamkill, follow officers orders.\n\n"
"Have a good game !"
)


class MessageOnConnectType(TypedDict):
enabled: bool
seed_limit: int
seed_time_text: str
non_seed_time_text: str


class MessageOnConnectUserConfig(BaseUserConfig):
"""
Args:
enabled bool:
Enable message at player's connection
seed_limit int:
The number of players in game to stop the seeding time
seed_time_text str:
A message that will be sent to any entering player in seed time
non_seed_time_text str:
A message that will be sent to any entering player in non-seed time
"""

enabled: bool = Field(default=False, strict=True)
seed_limit: int = Field(ge=0, le=100, default=40)
seed_time_text: str = Field(default=SEED_TIME_TEXT)
non_seed_time_text: str = Field(default=NON_SEED_TIME_TEXT)

@staticmethod
def save_to_db(values: MessageOnConnectType, dry_run=False):
key_check(MessageOnConnectType.__required_keys__, values.keys())

validated_conf = MessageOnConnectUserConfig(
enabled=values.get("enabled"),
seed_limit=values.get("seed_limit"),
seed_time_text=values.get("seed_time_text"),
non_seed_time_text=values.get("non_seed_time_text"),
)

if not dry_run:
set_user_config(MessageOnConnectUserConfig.KEY(), validated_conf.model_dump())
2 changes: 2 additions & 0 deletions rcon/user_config/seed_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from rcon.user_config.gtx_server_name import GtxServerNameChangeUserConfig
from rcon.user_config.log_line_webhooks import LogLineWebhookUserConfig
from rcon.user_config.log_stream import LogStreamUserConfig
from rcon.user_config.message_on_connect import MessageOnConnectUserConfig
from rcon.user_config.name_kicks import NameKickUserConfig
from rcon.user_config.rcon_connection_settings import RconConnectionSettingsUserConfig
from rcon.user_config.rcon_server_settings import RconServerSettingsUserConfig
Expand Down Expand Up @@ -63,6 +64,7 @@ def seed_default_config():
KillsWebhooksUserConfig.seed_db(sess)
LogLineWebhookUserConfig.seed_db(sess)
LogStreamUserConfig.seed_db(sess)
MessageOnConnectUserConfig.seed_db(sess)
NameKickUserConfig.seed_db(sess)
RconConnectionSettingsUserConfig.seed_db(sess)
RconServerSettingsUserConfig.seed_db(sess)
Expand Down
16 changes: 15 additions & 1 deletion rcongui/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
VacGameBans,
TeamKillBanOnConnect,
NameKicks,
MessageOnConnect,
ExpiredVIP,
GTXNameChange,
ChatCommands,
Expand Down Expand Up @@ -432,7 +433,9 @@ function App() {
<LiveSessionScore classes={classes} />
</Route>
<Route
path={process.env.REACT_APP_PUBLIC_BUILD ? "/" : "/livegamescore"}
path={
process.env.REACT_APP_PUBLIC_BUILD ? "/" : "/livegamescore"
}
default={process.env.REACT_APP_PUBLIC_BUILD}
exact
>
Expand Down Expand Up @@ -687,6 +690,17 @@ function App() {
/>
</Grid>
</Route>
<Route path="/settings/message-on-connect">
<Grid container spacing={2}>
<MessageOnConnect
description="Message on connect"
getEndpoint="get_message_on_connect_config"
setEndpoint="set_message_on_connect_config"
validateEndpoint="validate_message_on_connect_config"
describeEndpoint="describe_message_on_connect_config"
/>
</Grid>
</Route>
<Route path="/settings/expired-vip">
<Grid container spacing={2}>
<ExpiredVIP
Expand Down
Loading