Release 0.9.0
This commit is contained in:
246
bot/modules/players/actions/getplayers.py
Normal file
246
bot/modules/players/actions/getplayers.py
Normal file
@@ -0,0 +1,246 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_SHORT
|
||||
from os import path, pardir
|
||||
from time import sleep, time
|
||||
import re
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def _set_players_offline(players_dict):
|
||||
"""
|
||||
Helper function to mark all players in a dictionary as offline.
|
||||
|
||||
Creates a new dictionary with all players set to is_online=False and
|
||||
is_initialized=False. This is used when telnet commands fail or timeout.
|
||||
|
||||
Args:
|
||||
players_dict: Dictionary of player data keyed by steam_id
|
||||
|
||||
Returns:
|
||||
Dictionary with same players but marked as offline
|
||||
"""
|
||||
modified_players = {}
|
||||
for steam_id, player_data in players_dict.items():
|
||||
# Create a copy of the player dict
|
||||
updated_player = player_data.copy()
|
||||
updated_player["is_online"] = False
|
||||
updated_player["is_initialized"] = False
|
||||
modified_players[steam_id] = updated_player
|
||||
|
||||
return modified_players
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid=None):
|
||||
timeout = TELNET_TIMEOUT_SHORT
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
event_data[1]["fail_reason"] = []
|
||||
|
||||
if module.telnet.add_telnet_command_to_queue("lp"):
|
||||
poll_is_finished = False
|
||||
# Modern format - matches both empty and populated player lists
|
||||
regex = (
|
||||
r"Executing\scommand\s\'lp\'\sby\sTelnet\sfrom\s"
|
||||
r"(?P<called_by>.*?)\r?\n"
|
||||
r"(?P<raw_playerdata>[\s\S]*?)"
|
||||
r"Total\sof\s(?P<player_count>\d{1,2})\sin\sthe\sgame"
|
||||
)
|
||||
|
||||
while not poll_is_finished and (time() < timeout_start + timeout):
|
||||
sleep(0.25)
|
||||
match = False
|
||||
for match in re.finditer(regex, module.telnet.telnet_buffer):
|
||||
poll_is_finished = True
|
||||
|
||||
if match:
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid, match)
|
||||
return
|
||||
|
||||
event_data[1]["fail_reason"].append("timed out waiting for response")
|
||||
else:
|
||||
event_data[1]["fail_reason"].append("action already queued up")
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
""" without a place to store this, why bother """
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
player_count = int(match.group("player_count"))
|
||||
if all([
|
||||
active_dataset is None,
|
||||
player_count <= 0
|
||||
]):
|
||||
return False
|
||||
|
||||
""" get some basic stuff needed later """
|
||||
last_seen_gametime_string = module.game_environment.get_last_recorded_gametime_string()
|
||||
|
||||
""" lets extract all data the game provides!! """
|
||||
# Note: Modern regex doesn't capture datetime, using current time instead
|
||||
from datetime import datetime
|
||||
telnet_datetime = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
|
||||
raw_playerdata = match.group("raw_playerdata").lstrip()
|
||||
# Modern 7D2D format includes pltfmid (platform ID) and crossid (Epic cross-platform ID)
|
||||
# Format: pltfmid=Steam_76561198040658370, crossid=EOS_..., ip=..., ping=...
|
||||
regex = (
|
||||
r"\d{1,2}\. id=(?P<id>\d+), (?P<name>[^,]+), "
|
||||
r"pos=\((?P<pos_x>-?\d+\.\d+), (?P<pos_y>-?\d+\.\d+), (?P<pos_z>-?\d+\.\d+)\), "
|
||||
r"rot=\((?P<rot_x>-?\d+\.\d+), (?P<rot_y>-?\d+\.\d+), (?P<rot_z>-?\d+\.\d+)\), "
|
||||
r"remote=(?P<remote>\w+), "
|
||||
r"health=(?P<health>\d+), "
|
||||
r"deaths=(?P<deaths>\d+), "
|
||||
r"zombies=(?P<zombies>\d+), "
|
||||
r"players=(?P<players>\d+), "
|
||||
r"score=(?P<score>\d+), "
|
||||
r"level=(?P<level>\d+), "
|
||||
r"pltfmid=Steam_(?P<steamid>\d+), crossid=(?P<crossid>[\w_]+), "
|
||||
r"ip=(?P<ip>[^,]+), "
|
||||
r"ping=(?P<ping>\d+)"
|
||||
r"\r\n"
|
||||
)
|
||||
|
||||
all_players_dict = (
|
||||
module.dom.data.get(module.get_module_identifier(), {})
|
||||
.get("elements", {})
|
||||
.get(active_dataset, {})
|
||||
)
|
||||
|
||||
players_to_update_dict = {}
|
||||
for m in re.finditer(regex, raw_playerdata):
|
||||
in_limbo = int(m.group("health")) == 0
|
||||
player_dict = {
|
||||
# data the game provides
|
||||
"id": m.group("id"),
|
||||
"name": str(m.group("name")),
|
||||
"remote": bool(m.group("remote")),
|
||||
"health": int(m.group("health")),
|
||||
"deaths": int(m.group("deaths")),
|
||||
"zombies": int(m.group("zombies")),
|
||||
"players": int(m.group("players")),
|
||||
"score": int(m.group("score")),
|
||||
"level": int(m.group("level")),
|
||||
"steamid": m.group("steamid"),
|
||||
"ip": str(m.group("ip")),
|
||||
"ping": int(float(m.group("ping"))),
|
||||
"pos": {
|
||||
"x": int(float(m.group("pos_x"))),
|
||||
"y": int(float(m.group("pos_y"))),
|
||||
"z": int(float(m.group("pos_z")))
|
||||
},
|
||||
"rot": {
|
||||
"x": int(float(m.group("rot_x"))),
|
||||
"y": int(float(m.group("rot_y"))),
|
||||
"z": int(float(m.group("rot_z")))
|
||||
},
|
||||
# data invented by the bot
|
||||
"dataset": active_dataset,
|
||||
"in_limbo": in_limbo,
|
||||
"is_online": True,
|
||||
"is_initialized": True,
|
||||
"last_updated_servertime": telnet_datetime,
|
||||
"last_seen_gametime": last_seen_gametime_string,
|
||||
"owner": m.group("steamid")
|
||||
}
|
||||
players_to_update_dict[m.group("steamid")] = player_dict
|
||||
|
||||
""" players_to_update_dict now holds all game-data for all online players plus a few generated ones like last seen
|
||||
and is_initialized. Otherwise it's empty """
|
||||
|
||||
# set all players not currently online to offline
|
||||
online_players_list = list(players_to_update_dict.keys())
|
||||
for steamid, existing_player_dict in all_players_dict.items():
|
||||
if existing_player_dict["is_initialized"] is False:
|
||||
continue
|
||||
|
||||
if steamid not in online_players_list and existing_player_dict["is_online"] is True:
|
||||
# Create offline version of player using copy
|
||||
updated_player = existing_player_dict.copy()
|
||||
updated_player["is_online"] = False
|
||||
updated_player["is_initialized"] = False
|
||||
players_to_update_dict[steamid] = updated_player
|
||||
|
||||
if len(players_to_update_dict) >= 1:
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"elements": {
|
||||
active_dataset: players_to_update_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if online_players_list != module.dom.data.get(module.get_module_identifier(), {}).get("online_players"):
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"online_players": online_players_list
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
return
|
||||
|
||||
all_existing_players_dict = (
|
||||
module.dom.data
|
||||
.get(module.get_module_identifier(), {})
|
||||
.get("elements", {})
|
||||
.get(active_dataset, {})
|
||||
)
|
||||
|
||||
# Mark all existing players as offline using helper function
|
||||
all_modified_players_dict = _set_players_offline(all_existing_players_dict)
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"elements": {
|
||||
active_dataset: all_modified_players_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"online_players": []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def skip_it(module, event_data, dispatchers_steamid=None):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
return
|
||||
|
||||
all_existing_players_dict = (
|
||||
module.dom.data
|
||||
.get(module.get_module_identifier(), {})
|
||||
.get("elements", {})
|
||||
.get(active_dataset, {})
|
||||
)
|
||||
|
||||
# Mark all existing players as offline using helper function
|
||||
all_modified_players_dict = _set_players_offline(all_existing_players_dict)
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"elements": {
|
||||
active_dataset: all_modified_players_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "gets a list of all currently logged in players and sets status-flags",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"skip_it": skip_it,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
Reference in New Issue
Block a user