Release 0.9.0
This commit is contained in:
101
bot/modules/game_environment/__init__.py
Normal file
101
bot/modules/game_environment/__init__.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from bot.module import Module
|
||||
from bot import loaded_modules_dict
|
||||
from time import time
|
||||
|
||||
|
||||
class Environment(Module):
|
||||
templates = object
|
||||
|
||||
def __init__(self):
|
||||
setattr(self, "default_options", {
|
||||
"module_name": self.get_module_identifier()[7:],
|
||||
"dom_element_root": [],
|
||||
"dom_element_select_root": ["id"],
|
||||
"run_observer_interval": 3
|
||||
})
|
||||
|
||||
setattr(self, "required_modules", [
|
||||
"module_dom",
|
||||
"module_dom_management",
|
||||
"module_telnet",
|
||||
"module_webserver"
|
||||
])
|
||||
|
||||
self.next_cycle = 0
|
||||
Module.__init__(self)
|
||||
|
||||
@staticmethod
|
||||
def get_module_identifier():
|
||||
return "module_game_environment"
|
||||
|
||||
def on_socket_connect(self, steamid):
|
||||
Module.on_socket_connect(self, steamid)
|
||||
|
||||
def on_socket_disconnect(self, steamid):
|
||||
Module.on_socket_disconnect(self, steamid)
|
||||
|
||||
# region Standard module stuff
|
||||
def setup(self, options=dict):
|
||||
Module.setup(self, options)
|
||||
self.dom_element_root = self.options.get(
|
||||
"dom_element_root", self.default_options.get("dom_element_root", None)
|
||||
)
|
||||
self.dom_element_select_root = self.options.get(
|
||||
"dom_element_select_root", self.default_options.get("dom_element_select_root", None)
|
||||
)
|
||||
self.run_observer_interval = self.options.get(
|
||||
"run_observer_interval", self.default_options.get("run_observer_interval", None)
|
||||
)
|
||||
|
||||
# endregion
|
||||
def get_last_recorded_gametime_dict(self):
|
||||
active_dataset = self.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
return None
|
||||
|
||||
return (
|
||||
self.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("last_recorded_gametime", {})
|
||||
)
|
||||
|
||||
def get_last_recorded_gametime_string(self):
|
||||
last_recorded_gametime_dict = self.get_last_recorded_gametime_dict()
|
||||
if last_recorded_gametime_dict is None:
|
||||
return "Day {day}, {hour}:{minute}".format(
|
||||
day="n/a",
|
||||
hour="n/a",
|
||||
minute="n/a"
|
||||
)
|
||||
|
||||
return "Day {day}, {hour}:{minute}".format(
|
||||
day=last_recorded_gametime_dict.get("day", "n/a"),
|
||||
hour=last_recorded_gametime_dict.get("hour", "n/a"),
|
||||
minute=last_recorded_gametime_dict.get("minute", "n/a")
|
||||
)
|
||||
|
||||
def run(self):
|
||||
while not self.stopped.wait(self.next_cycle):
|
||||
profile_start = time()
|
||||
|
||||
self.trigger_action_hook(self, event_data=["getgameprefs", {
|
||||
"disable_after_success": True
|
||||
}])
|
||||
|
||||
# requires getgameprefs to be successful
|
||||
self.trigger_action_hook(self, event_data=["getgamestats", {
|
||||
"disable_after_success": True
|
||||
}])
|
||||
|
||||
self.trigger_action_hook(self, event_data=["gettime", {}])
|
||||
|
||||
self.trigger_action_hook(self, event_data=["getentities", {}])
|
||||
|
||||
self.execute_telnet_triggers()
|
||||
|
||||
self.last_execution_time = time() - profile_start
|
||||
self.next_cycle = self.run_observer_interval - self.last_execution_time
|
||||
|
||||
|
||||
loaded_modules_dict[Environment().get_module_identifier()] = Environment()
|
||||
49
bot/modules/game_environment/actions/cancel_shutdown.py
Normal file
49
bot/modules/game_environment/actions/cancel_shutdown.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
from time import time
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
module.dom.data.upsert({
|
||||
"module_game_environment": {
|
||||
active_dataset: {
|
||||
"cancel_shutdown": True,
|
||||
"shutdown_in_seconds": None,
|
||||
"force_shutdown": False
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event_data = ['say_to_all', {
|
||||
'message': (
|
||||
'a [FF6666]scheduled shutdown[-] has been cancelled.'
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
""" stop the timer """
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
pass
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "Set the (active) shutdown procedure to be cancelled",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
52
bot/modules/game_environment/actions/force_shutdown.py
Normal file
52
bot/modules/game_environment/actions/force_shutdown.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
from time import time
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
module.dom.data.upsert({
|
||||
"module_game_environment": {
|
||||
active_dataset: {
|
||||
"cancel_shutdown": False,
|
||||
"shutdown_in_seconds": None,
|
||||
"force_shutdown": True
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event_data = ['say_to_all', {
|
||||
'message': (
|
||||
'[FF6666]FORCED SHUTDOWN INITIATED[-]'
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
""" stop the timer """
|
||||
|
||||
event_data = ['shutdown', {}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
pass
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "Set the (active) shutdown procedure to be force-completed!",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
136
bot/modules/game_environment/actions/getentities.py
Normal file
136
bot/modules/game_environment/actions/getentities.py
Normal file
@@ -0,0 +1,136 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_NORMAL
|
||||
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 main_function(module, event_data, dispatchers_steamid=None):
|
||||
timeout = TELNET_TIMEOUT_NORMAL
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue("listents"):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
poll_is_finished = False
|
||||
# Modern format - matches both empty and populated entity lists
|
||||
regex = (
|
||||
r"Executing\scommand\s\'listents\'\sby\sTelnet\sfrom\s(?P<called_by>.*?)\r?\n"
|
||||
r"(?P<raw_entity_data>[\s\S]*?)"
|
||||
r"Total\sof\s(?P<entity_count>\d{1,3})\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
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
raw_entity_data = match.group("raw_entity_data").lstrip()
|
||||
if len(raw_entity_data) >= 1:
|
||||
regex = (
|
||||
r"\d{1,2}. id=(?P<id>\d+), \["
|
||||
r"type=(?P<type>.+), "
|
||||
r"name=(?P<name>.*), "
|
||||
r"id=(\d+)"
|
||||
r"\], "
|
||||
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"lifetime=(?P<lifetime>.+), "
|
||||
r"remote=(?P<remote>.+), "
|
||||
r"dead=(?P<dead>.+), "
|
||||
r"health=(?P<health>\d+)"
|
||||
r"\r\n"
|
||||
)
|
||||
entities_to_update_dict = {}
|
||||
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
return
|
||||
|
||||
for m in re.finditer(regex, raw_entity_data):
|
||||
last_seen_gametime_string = module.game_environment.get_last_recorded_gametime_string()
|
||||
entity_dict = {
|
||||
"id": m.group("id"),
|
||||
"owner": m.group("id"),
|
||||
"identifier": m.group("id"),
|
||||
"type": str(m.group("type")),
|
||||
"name": str(m.group("name")),
|
||||
"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"))),
|
||||
},
|
||||
"lifetime": str(m.group("lifetime")),
|
||||
"remote": bool(m.group("remote")),
|
||||
"dead": bool(m.group("dead")),
|
||||
"health": int(m.group("health")),
|
||||
"dataset": active_dataset,
|
||||
"last_seen_gametime": last_seen_gametime_string
|
||||
}
|
||||
entities_to_update_dict[m.group("id")] = entity_dict
|
||||
|
||||
if len(entities_to_update_dict) >= 1:
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"elements": {
|
||||
active_dataset: entities_to_update_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
stuff_to_delete = []
|
||||
for path, dom_element_key, dom_element in module.dom.get_dom_element_by_query(
|
||||
target_module=module.get_module_identifier(),
|
||||
query="id"
|
||||
):
|
||||
# Delete entities that are no longer in the update or have health <= 0 (dead)
|
||||
entity_data = entities_to_update_dict.get(dom_element, {})
|
||||
health = entity_data.get("health", 0)
|
||||
if dom_element not in entities_to_update_dict or health <= 0:
|
||||
stuff_to_delete.append([module.get_module_identifier(), "elements"] + path)
|
||||
|
||||
for dom_element_to_delete in stuff_to_delete:
|
||||
module.dom.data.remove_key_by_path(
|
||||
dom_element_to_delete,
|
||||
dispatchers_steamid=dispatchers_steamid
|
||||
)
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
def skip_it(module, event_data, dispatchers_steamid=None):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "get game entities",
|
||||
"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)
|
||||
108
bot/modules/game_environment/actions/getgameprefs.py
Normal file
108
bot/modules/game_environment/actions/getgameprefs.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_NORMAL
|
||||
from bot.logger import get_logger
|
||||
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]
|
||||
logger = get_logger("game_environment.getgameprefs")
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid=None):
|
||||
timeout = TELNET_TIMEOUT_NORMAL
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue("getgamepref"):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
# Modern format: timestamps ARE present in "Executing command" lines
|
||||
# Format: 2025-11-18T20:21:02 4854.528 INF Executing command 'getgamepref'...
|
||||
regex = (
|
||||
r"(?P<datetime>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})\s(?P<stardate>[-+]?\d*\.\d+|\d+)\s"
|
||||
r"INF Executing\scommand\s\'getgamepref\'\sby\sTelnet\sfrom\s(?P<called_by>.*?)\r?\n"
|
||||
r"(?P<raw_gameprefs>(?:GamePref\..*?\r?\n)+)"
|
||||
)
|
||||
|
||||
match = None
|
||||
match_found = False
|
||||
poll_is_finished = False
|
||||
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, re.MULTILINE):
|
||||
poll_is_finished = True
|
||||
match_found = True
|
||||
|
||||
if match_found:
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid, match)
|
||||
return
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def validate_settings(regex, raw_gameprefs):
|
||||
gameprefs_dict = {}
|
||||
all_required_settings_are_available = False
|
||||
for m in re.finditer(regex, raw_gameprefs, re.MULTILINE):
|
||||
stripped_gameprefs = m.group("gamepref_value").rstrip()
|
||||
if all([
|
||||
len(stripped_gameprefs) >= 1, # we have settings
|
||||
m.group("gamepref_name") == "GameName" # the GameName setting is available!
|
||||
|
||||
]):
|
||||
all_required_settings_are_available = True
|
||||
|
||||
gameprefs_dict[m.group("gamepref_name")] = stripped_gameprefs
|
||||
|
||||
if all_required_settings_are_available:
|
||||
return gameprefs_dict
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
regex = (
|
||||
r"GamePref\.(?P<gamepref_name>.*)\s\=\s(?P<gamepref_value>.*)\s"
|
||||
)
|
||||
raw_gameprefs = match.group("raw_gameprefs")
|
||||
|
||||
gameprefs_dict = validate_settings(regex, raw_gameprefs)
|
||||
if isinstance(gameprefs_dict, dict):
|
||||
current_game_name = gameprefs_dict.get("GameName", None)
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
current_game_name: {
|
||||
"gameprefs": gameprefs_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
"active_dataset": current_game_name
|
||||
}
|
||||
})
|
||||
|
||||
logger.info("active_dataset_set", dataset=current_game_name)
|
||||
else:
|
||||
logger.error("gameprefs_validation_failed", reason="required_settings_missing")
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "gets a list of all current game-preferences",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
88
bot/modules/game_environment/actions/getgamestats.py
Normal file
88
bot/modules/game_environment/actions/getgamestats.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_NORMAL
|
||||
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 main_function(module, event_data, dispatchers_steamid=None):
|
||||
# we can't save the gamestats without knowing the game-name, as each game can have different stats.
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
timeout = TELNET_TIMEOUT_NORMAL
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue("getgamestat"):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
# Modern format: timestamps ARE present in "Executing command" lines
|
||||
# Format: 2025-11-18T20:21:02 4854.528 INF Executing command 'getgamestat'...
|
||||
regex = (
|
||||
r"(?P<datetime>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})\s(?P<stardate>[-+]?\d*\.\d+|\d+)\s"
|
||||
r"INF Executing\scommand\s\'getgamestat\'\sby\sTelnet\sfrom\s(?P<called_by>.*?)\r?\n"
|
||||
r"(?P<raw_gamestats>(?:GameStat\..*?\r?\n)+)"
|
||||
)
|
||||
|
||||
match = None
|
||||
match_found = False
|
||||
poll_is_finished = False
|
||||
while not poll_is_finished and (time() < timeout_start + timeout):
|
||||
sleep(0.25) # give the telnet a little time to respond so we have a chance to get the data at first try
|
||||
match = False
|
||||
for match in re.finditer(regex, module.telnet.telnet_buffer, re.MULTILINE):
|
||||
poll_is_finished = True
|
||||
match_found = True
|
||||
|
||||
if match_found:
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid, match)
|
||||
return
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
regex = (
|
||||
r"GameStat\.(?P<gamestat_name>.*)\s\=\s(?P<gamestat_value>.*)\s"
|
||||
)
|
||||
raw_gamestats = match.group("raw_gamestats")
|
||||
gamestats_dict = {}
|
||||
|
||||
for m in re.finditer(regex, raw_gamestats, re.MULTILINE):
|
||||
gamestats_dict[m.group("gamestat_name")] = m.group("gamestat_value").rstrip()
|
||||
|
||||
active_dataset = (
|
||||
module.dom.data
|
||||
.get(module.get_module_identifier())
|
||||
.get("active_dataset", None)
|
||||
)
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
active_dataset: {
|
||||
"gamestats": gamestats_dict
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "gets a list of all current game-stats",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
151
bot/modules/game_environment/actions/gettime.py
Normal file
151
bot/modules/game_environment/actions/gettime.py
Normal file
@@ -0,0 +1,151 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_NORMAL
|
||||
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 get_weekday_string(server_days_passed: int) -> str:
|
||||
days_of_the_week = [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
]
|
||||
|
||||
current_day_index = int(float(server_days_passed) % 7)
|
||||
if 0 <= current_day_index <= 6:
|
||||
return days_of_the_week[current_day_index]
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def is_currently_bloodmoon(module: object, day: int, hour: int = -1) -> bool:
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
next_bloodmoon_date = int(
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("gamestats", {})
|
||||
.get("BloodMoonDay", None)
|
||||
)
|
||||
|
||||
daylight_length = int(
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("gamestats", {})
|
||||
.get("DayLightLength", None)
|
||||
)
|
||||
|
||||
night_length = (24 - daylight_length)
|
||||
morning_length = (night_length - 2)
|
||||
|
||||
if hour >= 0: # we want the exact bloodmoon
|
||||
if next_bloodmoon_date == day and 23 >= hour >= 22:
|
||||
return True
|
||||
if (next_bloodmoon_date + 1) == day and 0 <= hour <= morning_length:
|
||||
return True
|
||||
else: # we only want the day
|
||||
if next_bloodmoon_date == day:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid=None):
|
||||
timeout = TELNET_TIMEOUT_NORMAL
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue("gettime"):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
poll_is_finished = False
|
||||
# Modern format: simple "Day 447, 00:44" response
|
||||
regex = r"Day\s(?P<day>\d{1,5}),\s(?P<hour>\d{1,2}):(?P<minute>\d{1,2})"
|
||||
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
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
active_dataset = (
|
||||
module.dom.data
|
||||
.get(module.get_module_identifier(), {})
|
||||
.get("active_dataset", None)
|
||||
)
|
||||
|
||||
# we can't save the gametime without knowing the game-name, as each game can have different stats.
|
||||
if active_dataset is None:
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
matched_day = int(match.group("day"))
|
||||
matched_hour = match.group("hour")
|
||||
matched_minute = match.group("minute")
|
||||
|
||||
is_bloodmoon = is_currently_bloodmoon(module, matched_day, int(matched_hour))
|
||||
is_bloodday = is_currently_bloodmoon(module, matched_day)
|
||||
|
||||
weekday_string = get_weekday_string(matched_day)
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
active_dataset: {
|
||||
"last_recorded_gametime": {
|
||||
"day": matched_day,
|
||||
"hour": matched_hour,
|
||||
"minute": matched_minute,
|
||||
"weekday": weekday_string,
|
||||
"is_bloodmoon": is_bloodmoon,
|
||||
"is_bloodday": is_bloodday
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
# Update last_recorded_servertime for webserver status widget
|
||||
# Since modern 7D2D servers don't include timestamps in telnet output,
|
||||
# we use system time to track when data was last received
|
||||
from datetime import datetime
|
||||
module.dom.data.upsert({
|
||||
"module_telnet": {
|
||||
"last_recorded_servertime": datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
def skip_it(module, event_data, dispatchers_steamid=None):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "gets the current gettime readout",
|
||||
"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)
|
||||
102
bot/modules/game_environment/actions/manage_entities.py
Normal file
102
bot/modules/game_environment/actions/manage_entities.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot.constants import TELNET_TIMEOUT_EXTENDED
|
||||
from os import path, pardir
|
||||
from time import time, sleep
|
||||
import random
|
||||
import re
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def kill_entity(module, event_data, dispatchers_steamid=None):
|
||||
timeout = TELNET_TIMEOUT_EXTENDED
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
entity_to_be_killed = event_data[1].get("entity_id", None)
|
||||
|
||||
command = "kill {}".format(entity_to_be_killed)
|
||||
if not module.telnet.add_telnet_command_to_queue(command):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
poll_is_finished = False
|
||||
# Modern format - no datetime/stardate prefix
|
||||
regex = (
|
||||
r"Entity\s(?P<zombie_name>.*)\s" + str(entity_to_be_killed) + r"\skilled"
|
||||
)
|
||||
number_of_attempts = 0
|
||||
while not poll_is_finished and (time() < timeout_start + timeout):
|
||||
number_of_attempts += 1
|
||||
telnet_buffer_copy = (module.telnet.telnet_buffer + '.')[:-1]
|
||||
for match in re.finditer(regex, telnet_buffer_copy, re.DOTALL):
|
||||
return match
|
||||
|
||||
sleep(1)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid):
|
||||
action = event_data[1].get("action", None)
|
||||
dataset = event_data[1].get("dataset")
|
||||
entity_id = event_data[1].get("entity_id")
|
||||
entity_name = event_data[1].get("entity_name")
|
||||
|
||||
if action is not None:
|
||||
if action == "kill":
|
||||
match = kill_entity(module, event_data, dispatchers_steamid)
|
||||
if match is not False:
|
||||
if entity_name == "zombieScreamer":
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid, match)
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
action = event_data[1].get("action", None)
|
||||
entity_id = event_data[1].get("entity_id")
|
||||
entity_name = event_data[1].get("entity_name")
|
||||
|
||||
if all([
|
||||
action is not None
|
||||
]):
|
||||
if entity_name == "zombieScreamer":
|
||||
possible_maybes = [
|
||||
"hopefully",
|
||||
"probably dead, yes!",
|
||||
"i think",
|
||||
"i'm almost certain",
|
||||
"yeah. definitely!!"
|
||||
]
|
||||
event_data = ['say_to_all', {
|
||||
'message': '[CCFFCC]Screamer ([FFFFFF]{entity_id}[CCFFCC]) killed[-], [FFFFFF]{maybe}[-]...'.format(
|
||||
entity_id=entity_id,
|
||||
maybe=random.choice(possible_maybes)
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
else:
|
||||
event_data = ['say_to_all', {
|
||||
'message': '[CCFFCC]entity ([FFFFFF]{entity_id}[CCFFCC]) killed[-]'.format(
|
||||
entity_id=entity_id
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "manages entity entries",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": False,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
59
bot/modules/game_environment/actions/say_to_all.py
Normal file
59
bot/modules/game_environment/actions/say_to_all.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from bot import loaded_modules_dict, telnet_prefixes
|
||||
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 main_function(module, event_data, dispatchers_steamid=None):
|
||||
timeout = 5 # [seconds]
|
||||
timeout_start = time()
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
message = event_data[1].get("message", None)
|
||||
|
||||
command = "say \"{}\"".format(message)
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue(command):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
poll_is_finished = False
|
||||
# Modern format: timestamps ARE present in "Executing command" lines
|
||||
regex = (
|
||||
telnet_prefixes["telnet_log"]["timestamp"] +
|
||||
r"Executing\scommand\s\'" + command + r"\'\sby\sTelnet\sfrom\s(?P<called_by>.*)"
|
||||
)
|
||||
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, re.DOTALL):
|
||||
poll_is_finished = True
|
||||
|
||||
if match:
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid, match)
|
||||
return
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
pass
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "sends a message to any player",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
50
bot/modules/game_environment/actions/schedule_shutdown.py
Normal file
50
bot/modules/game_environment/actions/schedule_shutdown.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid):
|
||||
shutdown_in_seconds = int(event_data[1]["shutdown_in_seconds"])
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
module.dom.data.upsert({
|
||||
"module_game_environment": {
|
||||
active_dataset: {
|
||||
"cancel_shutdown": False,
|
||||
"shutdown_in_seconds": shutdown_in_seconds,
|
||||
"force_shutdown": False
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
event_data = ['say_to_all', {
|
||||
'message': (
|
||||
'a [FF6666]scheduled shutdown[-] is about to take place!'
|
||||
'shutdown in {seconds} seconds'.format(
|
||||
seconds=shutdown_in_seconds
|
||||
)
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
pass
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "Sets the schedule for a shutdown",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
70
bot/modules/game_environment/actions/shutdown.py
Normal file
70
bot/modules/game_environment/actions/shutdown.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from bot import loaded_modules_dict
|
||||
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 main_function(module, event_data, dispatchers_steamid):
|
||||
timeout = 10
|
||||
|
||||
if not module.telnet.add_telnet_command_to_queue("shutdown"):
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
poll_is_finished = False
|
||||
# Modern format - no datetime/stardate prefix, just look for "Disconnect"
|
||||
regex = r"Disconnect.*"
|
||||
|
||||
timeout_start = time()
|
||||
while not poll_is_finished and (time() < timeout_start + timeout):
|
||||
sleep(0.5)
|
||||
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
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
module.dom.data.upsert({
|
||||
"module_game_environment": {
|
||||
active_dataset: {
|
||||
"cancel_shutdown": False,
|
||||
"shutdown_in_seconds": None,
|
||||
"force_shutdown": False
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
module.dom.data.upsert({
|
||||
"module_game_environment": {
|
||||
active_dataset: {
|
||||
"cancel_shutdown": False,
|
||||
"shutdown_in_seconds": None,
|
||||
"force_shutdown": False
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "Cleanly shuts down the server",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": True,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
@@ -0,0 +1,46 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid):
|
||||
action = event_data[1].get("action", None)
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
|
||||
if action == "show_options":
|
||||
current_view = "options"
|
||||
current_view_steamid = None
|
||||
elif action == "show_frontend":
|
||||
current_view = "frontend"
|
||||
current_view_steamid = None
|
||||
else:
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
return
|
||||
|
||||
module.set_current_view(dispatchers_steamid, {
|
||||
"current_view": current_view,
|
||||
"current_view_steamid": current_view_steamid
|
||||
})
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
pass
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "manages entity table stuff",
|
||||
"main_function": main_function,
|
||||
"callback_success": callback_success,
|
||||
"callback_fail": callback_fail,
|
||||
"requires_telnet_connection": False,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_action(action_name, action_meta)
|
||||
@@ -0,0 +1,51 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
action_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(module, event_data, dispatchers_steamid=None):
|
||||
event_data[1]["action_identifier"] = action_name
|
||||
next_bloodmoon_date = event_data[1].get("blood_moon_date", None)
|
||||
if next_bloodmoon_date is not None:
|
||||
module.callback_success(callback_success, module, event_data, dispatchers_steamid)
|
||||
|
||||
module.callback_fail(callback_fail, module, event_data, dispatchers_steamid)
|
||||
|
||||
|
||||
def callback_success(module, event_data, dispatchers_steamid, match=None):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
next_bloodmoon_date = event_data[1].get("blood_moon_date", None)
|
||||
|
||||
module.dom.data.upsert({
|
||||
module.get_module_identifier(): {
|
||||
active_dataset: {
|
||||
"gamestats": {
|
||||
"BloodMoonDay": next_bloodmoon_date
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def callback_fail(module, event_data, dispatchers_steamid):
|
||||
pass
|
||||
|
||||
|
||||
def skip_it(module, event_data, dispatchers_steamid=None):
|
||||
pass
|
||||
|
||||
|
||||
action_meta = {
|
||||
"description": "updates bloodmoon date",
|
||||
"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)
|
||||
55
bot/modules/game_environment/commands/when_is_hordenight.py
Normal file
55
bot/modules/game_environment/commands/when_is_hordenight.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot import telnet_prefixes
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
trigger_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(origin_module, module, regex_result):
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
next_bloodmoon_date = (
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("gamestats", {})
|
||||
.get("BloodMoonDay", None)
|
||||
)
|
||||
event_data = ['say_to_all', {
|
||||
'message': 'Next [FFCCCC]hordenight[FFFFFF] will be on day {day}[-]'.format(
|
||||
day=next_bloodmoon_date
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
|
||||
triggers = {
|
||||
"when is hordenight": r"\'(?P<player_name>.*)\'\:\s(?P<command>\/when\sis\shordenight)"
|
||||
}
|
||||
|
||||
trigger_meta = {
|
||||
"description": "tells the player when the next bloodmoon will hit",
|
||||
"main_function": main_function,
|
||||
"triggers": [
|
||||
{
|
||||
"identifier": "when is hordenight (Allocs)",
|
||||
"regex": (
|
||||
telnet_prefixes["telnet_log"]["timestamp"] +
|
||||
telnet_prefixes["Allocs"]["chat"] +
|
||||
triggers["when is hordenight"]
|
||||
),
|
||||
"callback": main_function
|
||||
},
|
||||
{
|
||||
"identifier": "when is hordenight (BCM)",
|
||||
"regex": (
|
||||
telnet_prefixes["telnet_log"]["timestamp"] +
|
||||
telnet_prefixes["BCM"]["chat"] +
|
||||
triggers["when is hordenight"]
|
||||
),
|
||||
"callback": main_function
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_trigger(trigger_name, trigger_meta)
|
||||
@@ -0,0 +1,33 @@
|
||||
{%- from 'jinja2_macros.html' import construct_toggle_link with context -%}
|
||||
{# set this to 'false' for debug purposes, to see the offline state, set it to 'server_is_online' or remove the line
|
||||
for regular use #}
|
||||
{%- set server_is_online = server_is_online -%}
|
||||
{%- set online_status_string = "online" if server_is_online else "offline" -%}
|
||||
|
||||
<div class="{%- if server_is_online == true -%}active{%- else -%}inactive{%- endif -%}">
|
||||
<span>The server is <strong>{{ online_status_string }}</strong>
|
||||
{% if shutdown_in_seconds == none -%}
|
||||
{{ construct_toggle_link(
|
||||
server_is_online,
|
||||
"shutdown", ['widget_event', ['game_environment', ['schedule_shutdown', {
|
||||
"action": "schedule_shutdown",
|
||||
"shutdown_in_seconds": '900'
|
||||
}]]]
|
||||
)}}
|
||||
{%- else -%}
|
||||
{{ construct_toggle_link(
|
||||
server_is_online,
|
||||
"cancel", ['widget_event', ['game_environment', ['cancel_shutdown', {
|
||||
"action": "cancel_shutdown"
|
||||
}]]]
|
||||
)}}
|
||||
{{ shutdown_in_seconds }} seconds to
|
||||
{{ construct_toggle_link(
|
||||
server_is_online,
|
||||
"shutdown", ['widget_event', ['game_environment', ['force_shutdown', {
|
||||
"action": "force_shutdown"
|
||||
}]]]
|
||||
)}}
|
||||
{%- endif -%}
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
{%- from 'jinja2_macros.html' import construct_toggle_link with context -%}
|
||||
{% set current_day = last_recorded_gametime["day"] %}
|
||||
{% set current_hour = last_recorded_gametime["hour"] %}
|
||||
{% set current_minute = last_recorded_gametime["minute"] %}
|
||||
{%
|
||||
set current_weekday =
|
||||
"BloodDay"
|
||||
if last_recorded_gametime["is_bloodday"] == true else
|
||||
last_recorded_gametime["weekday"]
|
||||
%}
|
||||
{% set bloodmoon_modifier = "is_bloodmoon" if last_recorded_gametime["is_bloodmoon"] == true else "regular_gametime" %}
|
||||
{% set bloodday_modifier = "is_bloodday" if last_recorded_gametime["is_bloodday"] == true else "regular_day" %}
|
||||
<div class="{{ bloodmoon_modifier }} {{ bloodday_modifier }}">
|
||||
<span>
|
||||
Day <span class="day">{{ current_day }}/{{ next_bloodmoon_date }}</span>,
|
||||
<span class="time">{{ current_hour }}:{{ current_minute }}</span>
|
||||
({{ current_weekday }})
|
||||
</span>
|
||||
</div>
|
||||
20
bot/modules/game_environment/templates/jinja2_macros.html
Normal file
20
bot/modules/game_environment/templates/jinja2_macros.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{%- macro construct_toggle_link(bool, active_text, deactivate_event, inactive_text, activate_event) -%}
|
||||
{%- set bool = bool|default(false) -%}
|
||||
{%- set active_text = active_text|default(none) -%}
|
||||
{%- set deactivate_event = deactivate_event|default(none) -%}
|
||||
{%- set inactive_text = inactive_text|default(none) -%}
|
||||
{%- set activate_event = activate_event|default(none) -%}
|
||||
{%- if bool == true -%}
|
||||
{%- if deactivate_event != none and activate_event != none -%}
|
||||
<span class="active"><a href="#" onclick="window.socket.emit('{{ deactivate_event[0] }}', {{ deactivate_event[1] }}); return false;">{{ active_text }}</a></span>
|
||||
{%- elif deactivate_event != none and activate_event == none -%}
|
||||
<span class="active"><a href="#" onclick="window.socket.emit('{{ deactivate_event[0] }}', {{ deactivate_event[1] }}); return false;">{{ active_text }}</a></span>
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{%- if deactivate_event != none and activate_event != none -%}
|
||||
<span class="inactive"><a href="#" onclick="window.socket.emit('{{ activate_event[0] }}', {{ activate_event[1] }}); return false;">{{ inactive_text }}</a></span>
|
||||
{%- elif deactivate_event != none and activate_event == none -%}
|
||||
<span class="inactive"><a href="#" onclick="window.socket.emit('{{ deactivate_event[0] }}', {{ deactivate_event[1] }}); return false;">{{ active_text }}</a></span>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
@@ -0,0 +1,9 @@
|
||||
{%- from 'jinja2_macros.html' import construct_toggle_link with context -%}
|
||||
<div>
|
||||
{{ construct_toggle_link(
|
||||
options_view_toggle,
|
||||
"options", ['widget_event', ['game_environment', ['toggle_entities_widget_view', {'steamid': steamid, "action": "show_options"}]]],
|
||||
"back", ['widget_event', ['game_environment', ['toggle_entities_widget_view', {'steamid': steamid, "action": "show_frontend"}]]]
|
||||
)}}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<div id="entity_table_widget_options_toggle" class="pull_out right">
|
||||
{{ control_switch_options_view }}
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<tr>
|
||||
<td colspan="8">
|
||||
<div>
|
||||
{{ action_delete_button }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -0,0 +1,10 @@
|
||||
<tr>
|
||||
<th>*</th>
|
||||
<th onclick="window.sorting(this, entity_table, 1)">actions</th>
|
||||
<th onclick="window.sorting(this, entity_table, 2)">name</th>
|
||||
<th onclick="window.sorting(this, entity_table, 3)">type</th>
|
||||
<th onclick="window.sorting(this, entity_table, 4)">pos</th>
|
||||
<th onclick="window.sorting(this, entity_table, 5)">id</th>
|
||||
<th onclick="window.sorting(this, entity_table, 6)">health</th>
|
||||
<th onclick="window.sorting(this, entity_table, 7)" class="right">gametime</th>
|
||||
</tr>
|
||||
@@ -0,0 +1,25 @@
|
||||
{%- from 'jinja2_macros.html' import construct_toggle_link with context -%}
|
||||
<tr id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}"{%- if css_class %} class="{{ css_class }}"{%- endif -%}>
|
||||
<td>
|
||||
<span id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_control_select_link" class="select_button">{{ control_select_link }}</span>
|
||||
</td>
|
||||
<td class="nobr" id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_actions"> </td>
|
||||
<td id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_name" onclick="$(this).selectText();">{{ entity.name }}</td>
|
||||
<td id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_type" onclick="$(this).selectText();">{{ entity.type }}</td>
|
||||
<td class="position right" onclick="$(this).selectText();">
|
||||
<span id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_pos_x">
|
||||
{{ ((entity | default({})).pos | default({}) ).x | default('0') }}
|
||||
</span>
|
||||
<span id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_pos_y">
|
||||
{{ ((entity | default({})).pos | default({}) ).y | default('0') }}
|
||||
</span>
|
||||
<span id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_pos_z">
|
||||
{{ ((entity | default({})).pos | default({}) ).z | default('0') }}
|
||||
</span>
|
||||
</td>
|
||||
<td id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_id" onclick="$(this).selectText();">{{ entity.id }}</td>
|
||||
<td class="center" id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_health">{{ entity.health }}</td>
|
||||
<td class="nobr right" id="entity_table_row_{{ entity.dataset }}_{{ entity.id }}_last_seen_gametime">
|
||||
{{ entity.last_seen_gametime }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -0,0 +1,29 @@
|
||||
<header>
|
||||
<div>
|
||||
<span>Entities</span>
|
||||
</div>
|
||||
</header>
|
||||
<aside>
|
||||
{{ options_toggle }}
|
||||
</aside>
|
||||
<main>
|
||||
<table class="data_table">
|
||||
<caption>
|
||||
<span>obey</span>
|
||||
</caption>
|
||||
<thead>
|
||||
{{ table_header }}
|
||||
</thead>
|
||||
<tbody id="entity_table">
|
||||
{{ table_rows }}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
{{ table_footer }}
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="dialog">
|
||||
<div id="manage_entities_widget_modal" class="modal-content">
|
||||
<p>this is the text inside the modal</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@@ -0,0 +1,27 @@
|
||||
<header>
|
||||
<div>
|
||||
<span>Entities</span>
|
||||
</div>
|
||||
</header>
|
||||
<aside>
|
||||
{{ options_toggle }}
|
||||
</aside>
|
||||
<main>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">Entity Module Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2"><span>widget-options</span></th>
|
||||
</tr>
|
||||
{% for key, value in widget_options.items() %}
|
||||
<tr>
|
||||
<td><span>{{key}}</span></td><td>{{value}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</main>
|
||||
35
bot/modules/game_environment/triggers/new_bloodmoon.py
Normal file
35
bot/modules/game_environment/triggers/new_bloodmoon.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot import telnet_prefixes
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
trigger_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_function(origin_module, module, regex_result):
|
||||
next_blood_moon = regex_result.group("next_BloodMoon")
|
||||
event_data = ['update_bloodmoon_date', {
|
||||
'blood_moon_date': next_blood_moon,
|
||||
}]
|
||||
module.trigger_action_hook(origin_module, event_data=event_data)
|
||||
|
||||
|
||||
triggers = {
|
||||
"BloodMoon SetDay": r"BloodMoon\sSetDay:\sday\s(?P<next_BloodMoon>\d+)"
|
||||
}
|
||||
|
||||
trigger_meta = {
|
||||
"description": "reacts to updated BloodMoon date in the telnet-stream",
|
||||
"main_function": main_function,
|
||||
"triggers": [
|
||||
{
|
||||
"regex": (
|
||||
telnet_prefixes["telnet_log"]["timestamp"] +
|
||||
triggers["BloodMoon SetDay"]
|
||||
),
|
||||
"callback": main_function
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_trigger(trigger_name, trigger_meta)
|
||||
33
bot/modules/game_environment/triggers/shutdown_handler.py
Normal file
33
bot/modules/game_environment/triggers/shutdown_handler.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from bot import loaded_modules_dict
|
||||
from bot import telnet_prefixes
|
||||
from bot.logger import get_logger
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
trigger_name = path.basename(path.abspath(__file__))[:-3]
|
||||
logger = get_logger("game_environment.shutdown_handler")
|
||||
|
||||
|
||||
def main_function(*args, **kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", {})
|
||||
|
||||
cancel_shutdown = updated_values_dict.get("cancel_shutdown", None)
|
||||
force_shutdown = updated_values_dict.get("force_shutdown", None)
|
||||
|
||||
if cancel_shutdown:
|
||||
logger.info("shutdown_cancelled")
|
||||
if force_shutdown:
|
||||
logger.info("shutdown_forced")
|
||||
|
||||
|
||||
trigger_meta = {
|
||||
"description": "reacts to changes in the shutdown procedure",
|
||||
"main_function": main_function,
|
||||
"handlers": {
|
||||
"module_game_environment/%map_identifier%/cancel_shutdown": main_function,
|
||||
"module_game_environment/%map_identifier%/force_shutdown": main_function
|
||||
}
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_trigger(trigger_name, trigger_meta)
|
||||
@@ -0,0 +1,88 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
widget_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_widget(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get("dispatchers_steamid", None)
|
||||
|
||||
template_frontend = module.templates.get_template('gameserver_status_widget/view_frontend.html')
|
||||
|
||||
server_is_online = module.dom.data.get("module_telnet", {}).get("server_is_online", True)
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
shutdown_in_seconds = (
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("shutdown_in_seconds", None)
|
||||
)
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
server_is_online=server_is_online,
|
||||
shutdown_in_seconds=shutdown_in_seconds
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=[dispatchers_steamid],
|
||||
target_element={
|
||||
"id": "gameserver_status_widget",
|
||||
"type": "div",
|
||||
"selector": "body > header > div > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def update_widget(*args, **kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", None)
|
||||
|
||||
template_frontend = module.templates.get_template('gameserver_status_widget/view_frontend.html')
|
||||
|
||||
server_is_online = module.dom.get_updated_or_default_value(
|
||||
"module_telnet", "server_is_online", updated_values_dict, True
|
||||
)
|
||||
|
||||
shutdown_in_seconds = module.dom.get_updated_or_default_value(
|
||||
"module_game_environment", "shutdown_in_seconds", updated_values_dict, None
|
||||
)
|
||||
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
server_is_online=server_is_online,
|
||||
shutdown_in_seconds=shutdown_in_seconds
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=module.webserver.connected_clients.keys(),
|
||||
target_element={
|
||||
"id": "gameserver_status_widget",
|
||||
"type": "div",
|
||||
"selector": "body > header > div > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
widget_meta = {
|
||||
"description": "shows gameserver status, shut it down. or don't ^^",
|
||||
"main_widget": main_widget,
|
||||
"handlers": {
|
||||
"module_telnet/server_is_online": update_widget,
|
||||
"module_game_environment/%map_identifier%/shutdown_in_seconds": update_widget,
|
||||
"module_game_environment/%map_identifier%/cancel_shutdown": update_widget,
|
||||
"module_game_environment/%map_identifier%/force_shutdown": update_widget
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_widget(widget_name, widget_meta)
|
||||
103
bot/modules/game_environment/widgets/gettime_widget.py
Normal file
103
bot/modules/game_environment/widgets/gettime_widget.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
widget_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def main_widget(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get("dispatchers_steamid", None)
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
template_frontend = module.templates.get_template('gametime_widget/view_frontend.html')
|
||||
gametime = module.game_environment.get_last_recorded_gametime_dict()
|
||||
gametime.update({
|
||||
"is_bloodmoon": "",
|
||||
"is_bloodday": ""
|
||||
})
|
||||
|
||||
next_bloodmoon_date = (
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("gamestats", {})
|
||||
.get("BloodMoonDay", None)
|
||||
)
|
||||
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
last_recorded_gametime=gametime,
|
||||
next_bloodmoon_date=next_bloodmoon_date
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=[dispatchers_steamid],
|
||||
target_element={
|
||||
"id": "gametime_widget",
|
||||
"type": "div",
|
||||
"selector": "body > header > div > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def update_widget(*args, **kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", None)
|
||||
original_values_dict = kwargs.get("original_values_dict", None)
|
||||
|
||||
gametime = updated_values_dict.get("last_recorded_gametime", None)
|
||||
old_gametime = original_values_dict.get("last_recorded_gametime", None)
|
||||
if gametime is None:
|
||||
module.trigger_action_hook(module, event_data=["gettime", {}])
|
||||
return False
|
||||
|
||||
if gametime == old_gametime:
|
||||
pass
|
||||
# return
|
||||
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
next_bloodmoon_date = (
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get(active_dataset, {})
|
||||
.get("gamestats", {})
|
||||
.get("BloodMoonDay", None)
|
||||
)
|
||||
|
||||
template_frontend = module.templates.get_template('gametime_widget/view_frontend.html')
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
last_recorded_gametime=gametime,
|
||||
next_bloodmoon_date=next_bloodmoon_date
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=module.webserver.connected_clients.keys(),
|
||||
target_element={
|
||||
"id": "gametime_widget",
|
||||
"type": "div",
|
||||
"selector": "body > header > div > div"
|
||||
}
|
||||
)
|
||||
return gametime
|
||||
|
||||
|
||||
widget_meta = {
|
||||
"description": "displays the in-game time and day",
|
||||
"main_widget": main_widget,
|
||||
"handlers": {
|
||||
"module_game_environment/%map_identifier%/last_recorded_gametime": update_widget
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_widget(widget_name, widget_meta)
|
||||
@@ -0,0 +1,94 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
from bot.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
widget_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def announce_location_change(*args, **kwargs):
|
||||
"""
|
||||
Handler that announces location edits in the map chat.
|
||||
This demonstrates that the callback_dict system works - multiple modules can
|
||||
subscribe to the same DOM path changes without modifying the locations module.
|
||||
"""
|
||||
module = args[0]
|
||||
method = kwargs.get("method", None)
|
||||
updated_values_dict = kwargs.get("updated_values_dict", {})
|
||||
|
||||
# DEBUG: Log what we received
|
||||
logger.info(
|
||||
"location_change_debug",
|
||||
method=method,
|
||||
updated_values_dict_type=type(updated_values_dict).__name__,
|
||||
updated_values_dict_repr=repr(updated_values_dict)[:200]
|
||||
)
|
||||
|
||||
# Only announce on update, not insert or remove
|
||||
if method != "update":
|
||||
return
|
||||
|
||||
if not isinstance(updated_values_dict, dict):
|
||||
return
|
||||
|
||||
# Get active dataset (map identifier)
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
if active_dataset is None:
|
||||
return
|
||||
|
||||
# updated_values_dict structure at this depth (callback on depth 4):
|
||||
# {location_identifier: {location_data}}
|
||||
# location_data includes "owner" field
|
||||
|
||||
for location_identifier, location_dict in updated_values_dict.items():
|
||||
if not isinstance(location_dict, dict):
|
||||
continue
|
||||
|
||||
# Get owner directly from location_dict
|
||||
owner_steamid = location_dict.get("owner")
|
||||
if owner_steamid is None:
|
||||
logger.warning(
|
||||
"location_owner_missing",
|
||||
location_identifier=location_identifier
|
||||
)
|
||||
continue
|
||||
|
||||
# Get player name from DOM
|
||||
player_name = (
|
||||
module.dom.data
|
||||
.get("module_players", {})
|
||||
.get("elements", {})
|
||||
.get(active_dataset, {})
|
||||
.get(owner_steamid, {})
|
||||
.get("name", "Unknown Player")
|
||||
)
|
||||
|
||||
# Get location name
|
||||
location_name = location_dict.get("name", location_identifier)
|
||||
|
||||
# Send chat message via say_to_all
|
||||
event_data = ['say_to_all', {
|
||||
'message': (
|
||||
'[FFAA00]Location Update:[-] {player} edited location [00FFFF]{location}[-]'
|
||||
.format(
|
||||
player=player_name,
|
||||
location=location_name
|
||||
)
|
||||
)
|
||||
}]
|
||||
module.trigger_action_hook(module, event_data=event_data)
|
||||
|
||||
|
||||
widget_meta = {
|
||||
"description": "Announces location changes in map chat (test for callback_dict system)",
|
||||
"main_widget": None, # No UI widget, just a handler
|
||||
"handlers": {
|
||||
# Subscribe to location changes - any module can do this!
|
||||
"module_locations/elements/%map_identifier%/%owner_steamid%/%element_identifier%": announce_location_change
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_widget(widget_name, widget_meta)
|
||||
406
bot/modules/game_environment/widgets/manage_entities_widget.py
Normal file
406
bot/modules/game_environment/widgets/manage_entities_widget.py
Normal file
@@ -0,0 +1,406 @@
|
||||
from bot import loaded_modules_dict
|
||||
from os import path, pardir
|
||||
|
||||
module_name = path.basename(path.normpath(path.join(path.abspath(__file__), pardir, pardir)))
|
||||
widget_name = path.basename(path.abspath(__file__))[:-3]
|
||||
|
||||
|
||||
def get_entity_table_row_css_class(entity_dict):
|
||||
css_classes = []
|
||||
return " ".join(css_classes)
|
||||
|
||||
|
||||
def select_view(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get('dispatchers_steamid', None)
|
||||
|
||||
current_view = module.get_current_view(dispatchers_steamid)
|
||||
|
||||
if current_view == "options":
|
||||
options_view(module, dispatchers_steamid=dispatchers_steamid)
|
||||
elif current_view == "delete-modal":
|
||||
frontend_view(module, dispatchers_steamid=dispatchers_steamid)
|
||||
delete_modal_view(module, dispatchers_steamid=dispatchers_steamid)
|
||||
else:
|
||||
frontend_view(module, dispatchers_steamid=dispatchers_steamid)
|
||||
|
||||
|
||||
def delete_modal_view(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get('dispatchers_steamid', None)
|
||||
|
||||
all_available_entity_dicts = module.dom.data.get(module.get_module_identifier(), {}).get("elements", {})
|
||||
all_selected_elements_count = 0
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
for map_identifier, entity_dicts in all_available_entity_dicts.items():
|
||||
if active_dataset == map_identifier:
|
||||
for entity_id, entity_dict in entity_dicts.items():
|
||||
entity_is_selected_by = entity_dict.get("selected_by", [])
|
||||
if dispatchers_steamid in entity_is_selected_by:
|
||||
all_selected_elements_count += 1
|
||||
|
||||
modal_confirm_delete = module.dom_management.get_delete_confirm_modal(
|
||||
module,
|
||||
count=all_selected_elements_count,
|
||||
target_module="module_game_environment",
|
||||
dom_element_id="entity_table_modal_action_delete_button",
|
||||
dom_action="delete_selected_dom_elements",
|
||||
dom_element_root=module.dom_element_root,
|
||||
dom_element_select_root=module.dom_element_select_root,
|
||||
confirmed="True"
|
||||
)
|
||||
|
||||
data_to_emit = modal_confirm_delete
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="modal_content",
|
||||
clients=[dispatchers_steamid],
|
||||
target_element={
|
||||
"id": "manage_entities_widget_modal",
|
||||
"type": "div",
|
||||
"selector": "body > main > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def frontend_view(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get('dispatchers_steamid', None)
|
||||
|
||||
template_frontend = module.templates.get_template('manage_entities_widget/view_frontend.html')
|
||||
template_table_rows = module.templates.get_template('manage_entities_widget/table_row.html')
|
||||
template_table_header = module.templates.get_template('manage_entities_widget/table_header.html')
|
||||
template_table_footer = module.templates.get_template('manage_entities_widget/table_footer.html')
|
||||
|
||||
template_options_toggle = module.templates.get_template('manage_entities_widget/control_switch_view.html')
|
||||
template_options_toggle_view = module.templates.get_template('manage_entities_widget/control_switch_options_view.html')
|
||||
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
all_available_entity_dicts = module.dom.data.get(module.get_module_identifier(), {}).get("elements", {})
|
||||
|
||||
table_rows = ""
|
||||
all_selected_elements_count = 0
|
||||
for map_identifier, entity_dicts in all_available_entity_dicts.items():
|
||||
if active_dataset == map_identifier:
|
||||
for entity_id, entity_dict in entity_dicts.items():
|
||||
entity_is_selected_by = entity_dict.get("selected_by", [])
|
||||
|
||||
entity_entry_selected = False
|
||||
if dispatchers_steamid in entity_is_selected_by:
|
||||
entity_entry_selected = True
|
||||
all_selected_elements_count += 1
|
||||
|
||||
control_select_link = module.dom_management.get_selection_dom_element(
|
||||
module,
|
||||
target_module="module_game_environment",
|
||||
dom_element_select_root=["selected_by"],
|
||||
dom_element=entity_dict,
|
||||
dom_element_entry_selected=entity_entry_selected,
|
||||
dom_action_inactive="select_dom_element",
|
||||
dom_action_active="deselect_dom_element"
|
||||
)
|
||||
|
||||
# Sanitize dataset for HTML ID (replace spaces with underscores, lowercase)
|
||||
sanitized_dataset = module.dom_management.sanitize_for_html_id(entity_dict.get("dataset", ""))
|
||||
sanitized_entity_id = str(entity_id)
|
||||
|
||||
# Update entity_dict with sanitized values for template
|
||||
entity_dict_for_template = entity_dict.copy()
|
||||
entity_dict_for_template["dataset"] = sanitized_dataset
|
||||
entity_dict_for_template["dataset_original"] = entity_dict.get("dataset", "")
|
||||
|
||||
table_rows += module.template_render_hook(
|
||||
module,
|
||||
template=template_table_rows,
|
||||
entity=entity_dict_for_template,
|
||||
css_class=get_entity_table_row_css_class(entity_dict),
|
||||
control_select_link=control_select_link
|
||||
)
|
||||
|
||||
current_view = module.get_current_view(dispatchers_steamid)
|
||||
|
||||
options_toggle = module.template_render_hook(
|
||||
module,
|
||||
template=template_options_toggle,
|
||||
control_switch_options_view=module.template_render_hook(
|
||||
module,
|
||||
template=template_options_toggle_view,
|
||||
options_view_toggle=(current_view in ["frontend", "delete-modal"]),
|
||||
steamid=dispatchers_steamid
|
||||
)
|
||||
)
|
||||
|
||||
dom_element_delete_button = module.dom_management.get_delete_button_dom_element(
|
||||
module,
|
||||
count=all_selected_elements_count,
|
||||
target_module="module_game_environment",
|
||||
dom_element_id="entity_table_widget_action_delete_button",
|
||||
dom_action="delete_selected_dom_elements",
|
||||
dom_element_root=module.dom_element_root,
|
||||
dom_element_select_root=module.dom_element_select_root
|
||||
)
|
||||
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
options_toggle=options_toggle,
|
||||
table_header=module.template_render_hook(
|
||||
module,
|
||||
template=template_table_header
|
||||
),
|
||||
table_rows=table_rows,
|
||||
table_footer=module.template_render_hook(
|
||||
module,
|
||||
template=template_table_footer,
|
||||
action_delete_button=dom_element_delete_button
|
||||
)
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=[dispatchers_steamid],
|
||||
method="update",
|
||||
target_element={
|
||||
"id": "manage_entities_widget",
|
||||
"type": "table",
|
||||
"selector": "body > main > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def options_view(*args, **kwargs):
|
||||
module = args[0]
|
||||
dispatchers_steamid = kwargs.get('dispatchers_steamid', None)
|
||||
|
||||
template_frontend = module.templates.get_template('manage_entities_widget/view_options.html')
|
||||
template_options_toggle = module.templates.get_template('manage_entities_widget/control_switch_view.html')
|
||||
template_options_toggle_view = module.templates.get_template('manage_entities_widget/control_switch_options_view.html')
|
||||
|
||||
options_toggle = module.template_render_hook(
|
||||
module,
|
||||
template=template_options_toggle,
|
||||
control_switch_options_view=module.template_render_hook(
|
||||
module,
|
||||
template=template_options_toggle_view,
|
||||
options_view_toggle=False,
|
||||
steamid=dispatchers_steamid
|
||||
)
|
||||
)
|
||||
|
||||
data_to_emit = module.template_render_hook(
|
||||
module,
|
||||
template=template_frontend,
|
||||
options_toggle=options_toggle,
|
||||
widget_options=module.options
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=data_to_emit,
|
||||
data_type="widget_content",
|
||||
clients=[dispatchers_steamid],
|
||||
method="update",
|
||||
target_element={
|
||||
"id": "manage_entities_widget",
|
||||
"type": "table",
|
||||
"selector": "body > main > div"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def table_rows(*args, ** kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", None)
|
||||
method = kwargs.get("method", None)
|
||||
active_dataset = module.dom.data.get("module_game_environment", {}).get("active_dataset", None)
|
||||
|
||||
if method in ["upsert", "edit", "insert"]:
|
||||
for clientid in module.webserver.connected_clients.keys():
|
||||
current_view = module.get_current_view(clientid)
|
||||
if current_view == "frontend":
|
||||
template_table_rows = module.templates.get_template('manage_entities_widget/table_row.html')
|
||||
|
||||
for entity_id, entity_dict in updated_values_dict.items():
|
||||
try:
|
||||
# Sanitize dataset for HTML ID (replace spaces with underscores, lowercase)
|
||||
sanitized_dataset = module.dom_management.sanitize_for_html_id(entity_dict["dataset"])
|
||||
table_row_id = "entity_table_row_{}_{}".format(
|
||||
sanitized_dataset,
|
||||
str(entity_id)
|
||||
)
|
||||
# Update entity_dict with sanitized dataset for template
|
||||
entity_dict = entity_dict.copy()
|
||||
entity_dict["dataset"] = sanitized_dataset
|
||||
entity_dict["dataset_original"] = updated_values_dict[entity_id].get("dataset", "")
|
||||
except KeyError:
|
||||
table_row_id = "manage_entities_widget"
|
||||
|
||||
selected_entity_entries = (
|
||||
module.dom.data
|
||||
.get("module_game_environment", {})
|
||||
.get("elements", {})
|
||||
.get(active_dataset, {})
|
||||
.get(entity_id, {})
|
||||
.get("selected_by", [])
|
||||
)
|
||||
|
||||
entity_entry_selected = False
|
||||
if clientid in selected_entity_entries:
|
||||
entity_entry_selected = True
|
||||
|
||||
control_select_link = module.dom_management.get_selection_dom_element(
|
||||
module,
|
||||
target_module="module_game_environment",
|
||||
dom_element_select_root=["selected_by"],
|
||||
dom_element=entity_dict,
|
||||
dom_element_entry_selected=entity_entry_selected,
|
||||
dom_action_inactive="select_dom_element",
|
||||
dom_action_active="deselect_dom_element"
|
||||
)
|
||||
|
||||
table_row = module.template_render_hook(
|
||||
module,
|
||||
template=template_table_rows,
|
||||
entity=entity_dict,
|
||||
css_class=get_entity_table_row_css_class(entity_dict),
|
||||
control_select_link=control_select_link
|
||||
)
|
||||
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=table_row,
|
||||
data_type="table_row",
|
||||
clients=[clientid],
|
||||
target_element={
|
||||
"id": table_row_id,
|
||||
"type": "tr",
|
||||
"class": get_entity_table_row_css_class(entity_dict),
|
||||
"selector": "body > main > div > div#manage_entities_widget > main > table > tbody"
|
||||
}
|
||||
)
|
||||
elif method == "remove":
|
||||
entity_origin = updated_values_dict[2]
|
||||
entity_id = updated_values_dict[3]
|
||||
# Sanitize dataset for HTML ID (replace spaces with underscores, lowercase)
|
||||
sanitized_origin = module.dom_management.sanitize_for_html_id(entity_origin)
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
data_type="remove_table_row",
|
||||
clients="all",
|
||||
target_element={
|
||||
"id": "entity_table_row_{}_{}".format(
|
||||
sanitized_origin,
|
||||
str(entity_id)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
update_delete_button_status(module, *args, **kwargs)
|
||||
|
||||
|
||||
def update_widget(*args, **kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", None)
|
||||
|
||||
method = kwargs.get("method", None)
|
||||
if method in ["update"]:
|
||||
entity_dict = updated_values_dict
|
||||
player_clients_to_update = list(module.webserver.connected_clients.keys())
|
||||
|
||||
for clientid in player_clients_to_update:
|
||||
try:
|
||||
current_view = module.get_current_view(clientid)
|
||||
# Sanitize dataset for HTML ID (replace spaces with underscores, lowercase)
|
||||
sanitized_dataset = module.dom_management.sanitize_for_html_id(entity_dict.get("dataset", ""))
|
||||
table_row_id = "entity_table_row_{}_{}".format(
|
||||
sanitized_dataset,
|
||||
str(entity_dict.get("id", None))
|
||||
)
|
||||
# Update entity_dict with sanitized dataset
|
||||
original_dataset = entity_dict.get("dataset", "")
|
||||
entity_dict = entity_dict.copy()
|
||||
entity_dict["dataset"] = sanitized_dataset
|
||||
entity_dict["dataset_original"] = original_dataset
|
||||
|
||||
if current_view == "frontend":
|
||||
module.webserver.send_data_to_client_hook(
|
||||
module,
|
||||
payload=entity_dict,
|
||||
data_type="table_row_content",
|
||||
clients="all",
|
||||
method="update",
|
||||
target_element={
|
||||
"id": table_row_id,
|
||||
"parent_id": "manage_entities_widget",
|
||||
"module": "game_environment",
|
||||
"type": "tr",
|
||||
"selector": "body > main > div > div#manage_entities_widget",
|
||||
"class": get_entity_table_row_css_class(entity_dict),
|
||||
}
|
||||
)
|
||||
except AttributeError as error:
|
||||
pass
|
||||
except KeyError as error:
|
||||
pass
|
||||
|
||||
|
||||
def update_selection_status(*args, **kwargs):
|
||||
module = args[0]
|
||||
updated_values_dict = kwargs.get("updated_values_dict", None)
|
||||
|
||||
# Sanitize dataset for HTML ID (replace spaces with underscores, lowercase)
|
||||
sanitized_dataset = module.dom_management.sanitize_for_html_id(updated_values_dict["dataset"])
|
||||
|
||||
module.dom_management.update_selection_status(
|
||||
*args, **kwargs,
|
||||
target_module=module,
|
||||
dom_action_active="deselect_dom_element",
|
||||
dom_action_inactive="select_dom_element",
|
||||
dom_element_id={
|
||||
"id": "entity_table_row_{}_{}_control_select_link".format(
|
||||
sanitized_dataset,
|
||||
updated_values_dict["identifier"]
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
update_delete_button_status(module, *args, **kwargs)
|
||||
|
||||
|
||||
def update_delete_button_status(*args, **kwargs):
|
||||
module = args[0]
|
||||
|
||||
module.dom_management.update_delete_button_status(
|
||||
*args, **kwargs,
|
||||
dom_element_root=module.dom_element_root,
|
||||
dom_element_select_root=module.dom_element_select_root,
|
||||
target_module=module,
|
||||
dom_action="delete_selected_dom_elements",
|
||||
dom_element_id={
|
||||
"id": "entity_table_widget_action_delete_button"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
widget_meta = {
|
||||
"description": "sends and updates a table of all currently known entities",
|
||||
"main_widget": select_view,
|
||||
"handlers": {
|
||||
"module_game_environment/visibility/%steamid%/current_view":
|
||||
select_view,
|
||||
"module_game_environment/elements/%map_identifier%/%id%":
|
||||
table_rows,
|
||||
"module_game_environment/elements/%map_identifier%/%id%/pos":
|
||||
update_widget,
|
||||
"module_game_environment/elements/%map_identifier%/%id%/selected_by":
|
||||
update_selection_status,
|
||||
},
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
loaded_modules_dict["module_" + module_name].register_widget(widget_name, widget_meta)
|
||||
Reference in New Issue
Block a user