mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Factorio: client cleanup and prevent process bomb (#4882)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,6 @@ import random
|
|||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import typing
|
import typing
|
||||||
@@ -17,15 +16,16 @@ from queue import Queue
|
|||||||
|
|
||||||
import factorio_rcon
|
import factorio_rcon
|
||||||
|
|
||||||
import Utils
|
|
||||||
from CommonClient import ClientCommandProcessor, CommonContext, logger, server_loop, gui_enabled, get_base_parser
|
from CommonClient import ClientCommandProcessor, CommonContext, logger, server_loop, gui_enabled, get_base_parser
|
||||||
from MultiServer import mark_raw
|
from MultiServer import mark_raw
|
||||||
from NetUtils import ClientStatus, NetworkItem, JSONtoTextParser, JSONMessagePart
|
from NetUtils import ClientStatus, NetworkItem, JSONtoTextParser, JSONMessagePart
|
||||||
from Utils import async_start, get_file_safe_name
|
from Utils import async_start, get_file_safe_name, is_windows, Version, format_SI_prefix, get_text_between
|
||||||
|
from .settings import FactorioSettings
|
||||||
|
from settings import get_settings
|
||||||
|
|
||||||
|
|
||||||
def check_stdin() -> None:
|
def check_stdin() -> None:
|
||||||
if Utils.is_windows and sys.stdin:
|
if is_windows and sys.stdin:
|
||||||
print("WARNING: Console input is not routed reliably on Windows, use the GUI instead.")
|
print("WARNING: Console input is not routed reliably on Windows, use the GUI instead.")
|
||||||
|
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class FactorioContext(CommonContext):
|
|||||||
items_handling = 0b111 # full remote
|
items_handling = 0b111 # full remote
|
||||||
|
|
||||||
# updated by spinup server
|
# updated by spinup server
|
||||||
mod_version: Utils.Version = Utils.Version(0, 0, 0)
|
mod_version: Version = Version(0, 0, 0)
|
||||||
|
|
||||||
def __init__(self, server_address, password, filter_item_sends: bool, bridge_chat_out: bool):
|
def __init__(self, server_address, password, filter_item_sends: bool, bridge_chat_out: bool):
|
||||||
super(FactorioContext, self).__init__(server_address, password)
|
super(FactorioContext, self).__init__(server_address, password)
|
||||||
@@ -133,7 +133,7 @@ class FactorioContext(CommonContext):
|
|||||||
elif self.current_energy_link_value is None:
|
elif self.current_energy_link_value is None:
|
||||||
return "Standby"
|
return "Standby"
|
||||||
else:
|
else:
|
||||||
return f"{Utils.format_SI_prefix(self.current_energy_link_value)}J"
|
return f"{format_SI_prefix(self.current_energy_link_value)}J"
|
||||||
|
|
||||||
def on_deathlink(self, data: dict):
|
def on_deathlink(self, data: dict):
|
||||||
if self.rcon_client:
|
if self.rcon_client:
|
||||||
@@ -155,10 +155,10 @@ class FactorioContext(CommonContext):
|
|||||||
if self.energy_link_increment and args.get("last_deplete", -1) == self.last_deplete:
|
if self.energy_link_increment and args.get("last_deplete", -1) == self.last_deplete:
|
||||||
# it's our deplete request
|
# it's our deplete request
|
||||||
gained = int(args["original_value"] - args["value"])
|
gained = int(args["original_value"] - args["value"])
|
||||||
gained_text = Utils.format_SI_prefix(gained) + "J"
|
gained_text = format_SI_prefix(gained) + "J"
|
||||||
if gained:
|
if gained:
|
||||||
logger.debug(f"EnergyLink: Received {gained_text}. "
|
logger.debug(f"EnergyLink: Received {gained_text}. "
|
||||||
f"{Utils.format_SI_prefix(args['value'])}J remaining.")
|
f"{format_SI_prefix(args['value'])}J remaining.")
|
||||||
self.rcon_client.send_command(f"/ap-energylink {gained}")
|
self.rcon_client.send_command(f"/ap-energylink {gained}")
|
||||||
|
|
||||||
def on_user_say(self, text: str) -> typing.Optional[str]:
|
def on_user_say(self, text: str) -> typing.Optional[str]:
|
||||||
@@ -278,7 +278,7 @@ async def game_watcher(ctx: FactorioContext):
|
|||||||
}]))
|
}]))
|
||||||
ctx.rcon_client.send_command(
|
ctx.rcon_client.send_command(
|
||||||
f"/ap-energylink -{value}")
|
f"/ap-energylink -{value}")
|
||||||
logger.debug(f"EnergyLink: Sent {Utils.format_SI_prefix(value)}J")
|
logger.debug(f"EnergyLink: Sent {format_SI_prefix(value)}J")
|
||||||
|
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
@@ -439,9 +439,9 @@ async def factorio_spinup_server(ctx: FactorioContext) -> bool:
|
|||||||
factorio_server_logger.info(msg)
|
factorio_server_logger.info(msg)
|
||||||
if "Loading mod AP-" in msg and msg.endswith("(data.lua)"):
|
if "Loading mod AP-" in msg and msg.endswith("(data.lua)"):
|
||||||
parts = msg.split()
|
parts = msg.split()
|
||||||
ctx.mod_version = Utils.Version(*(int(number) for number in parts[-2].split(".")))
|
ctx.mod_version = Version(*(int(number) for number in parts[-2].split(".")))
|
||||||
elif "Write data path: " in msg:
|
elif "Write data path: " in msg:
|
||||||
ctx.write_data_path = Utils.get_text_between(msg, "Write data path: ", " [")
|
ctx.write_data_path = get_text_between(msg, "Write data path: ", " [")
|
||||||
if "AppData" in ctx.write_data_path:
|
if "AppData" in ctx.write_data_path:
|
||||||
logger.warning("It appears your mods are loaded from Appdata, "
|
logger.warning("It appears your mods are loaded from Appdata, "
|
||||||
"this can lead to problems with multiple Factorio instances. "
|
"this can lead to problems with multiple Factorio instances. "
|
||||||
@@ -521,10 +521,16 @@ rcon_port = args.rcon_port
|
|||||||
rcon_password = args.rcon_password if args.rcon_password else ''.join(
|
rcon_password = args.rcon_password if args.rcon_password else ''.join(
|
||||||
random.choice(string.ascii_letters) for x in range(32))
|
random.choice(string.ascii_letters) for x in range(32))
|
||||||
factorio_server_logger = logging.getLogger("FactorioServer")
|
factorio_server_logger = logging.getLogger("FactorioServer")
|
||||||
options = Utils.get_settings()
|
settings: FactorioSettings = get_settings().factorio_options
|
||||||
executable = options["factorio_options"]["executable"]
|
if os.path.samefile(settings.executable, sys.executable):
|
||||||
|
selected_executable = settings.executable
|
||||||
|
settings.executable = FactorioSettings.executable # reset to default
|
||||||
|
raise Exception(f"FactorioClient was set to run itself {selected_executable}, aborting process bomb.")
|
||||||
|
|
||||||
|
executable = settings.executable
|
||||||
|
|
||||||
server_settings = args.server_settings if args.server_settings \
|
server_settings = args.server_settings if args.server_settings \
|
||||||
else options["factorio_options"].get("server_settings", None)
|
else getattr(settings, "server_settings", None)
|
||||||
server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password)
|
server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password)
|
||||||
|
|
||||||
|
|
||||||
@@ -535,12 +541,8 @@ def launch():
|
|||||||
|
|
||||||
if server_settings:
|
if server_settings:
|
||||||
server_settings = os.path.abspath(server_settings)
|
server_settings = os.path.abspath(server_settings)
|
||||||
if not isinstance(options["factorio_options"]["filter_item_sends"], bool):
|
initial_filter_item_sends = bool(settings.filter_item_sends)
|
||||||
logging.warning(f"Warning: Option filter_item_sends should be a bool.")
|
initial_bridge_chat_out = bool(settings.bridge_chat_out)
|
||||||
initial_filter_item_sends = bool(options["factorio_options"]["filter_item_sends"])
|
|
||||||
if not isinstance(options["factorio_options"]["bridge_chat_out"], bool):
|
|
||||||
logging.warning(f"Warning: Option bridge_chat_out should be a bool.")
|
|
||||||
initial_bridge_chat_out = bool(options["factorio_options"]["bridge_chat_out"])
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.dirname(executable)):
|
if not os.path.exists(os.path.dirname(executable)):
|
||||||
raise FileNotFoundError(f"Path {os.path.dirname(executable)} does not exist or could not be accessed.")
|
raise FileNotFoundError(f"Path {os.path.dirname(executable)} does not exist or could not be accessed.")
|
||||||
|
@@ -5,7 +5,6 @@ import logging
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
import settings
|
|
||||||
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification
|
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification
|
||||||
from worlds.AutoWorld import World, WebWorld
|
from worlds.AutoWorld import World, WebWorld
|
||||||
from worlds.LauncherComponents import Component, components, Type, launch as launch_component
|
from worlds.LauncherComponents import Component, components, Type, launch as launch_component
|
||||||
@@ -20,6 +19,7 @@ from .Technologies import base_tech_table, recipe_sources, base_technology_table
|
|||||||
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table, \
|
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table, \
|
||||||
get_science_pack_pools, Recipe, recipes, technology_table, tech_table, factorio_base_id, useless_technologies, \
|
get_science_pack_pools, Recipe, recipes, technology_table, tech_table, factorio_base_id, useless_technologies, \
|
||||||
fluids, stacking_items, valid_ingredients, progressive_rows
|
fluids, stacking_items, valid_ingredients, progressive_rows
|
||||||
|
from .settings import FactorioSettings
|
||||||
|
|
||||||
|
|
||||||
def launch_client():
|
def launch_client():
|
||||||
@@ -30,29 +30,6 @@ def launch_client():
|
|||||||
components.append(Component("Factorio Client", func=launch_client, component_type=Type.CLIENT))
|
components.append(Component("Factorio Client", func=launch_client, component_type=Type.CLIENT))
|
||||||
|
|
||||||
|
|
||||||
class FactorioSettings(settings.Group):
|
|
||||||
class Executable(settings.UserFilePath):
|
|
||||||
is_exe = True
|
|
||||||
|
|
||||||
class ServerSettings(settings.OptionalUserFilePath):
|
|
||||||
"""
|
|
||||||
by default, no settings are loaded if this file does not exist. \
|
|
||||||
If this file does exist, then it will be used.
|
|
||||||
server_settings: "factorio\\\\data\\\\server-settings.json"
|
|
||||||
"""
|
|
||||||
|
|
||||||
class FilterItemSends(settings.Bool):
|
|
||||||
"""Whether to filter item send messages displayed in-game to only those that involve you."""
|
|
||||||
|
|
||||||
class BridgeChatOut(settings.Bool):
|
|
||||||
"""Whether to send chat messages from players on the Factorio server to Archipelago."""
|
|
||||||
|
|
||||||
executable: Executable = Executable("factorio/bin/x64/factorio")
|
|
||||||
server_settings: typing.Optional[FactorioSettings.ServerSettings] = None
|
|
||||||
filter_item_sends: typing.Union[FilterItemSends, bool] = False
|
|
||||||
bridge_chat_out: typing.Union[BridgeChatOut, bool] = True
|
|
||||||
|
|
||||||
|
|
||||||
class FactorioWeb(WebWorld):
|
class FactorioWeb(WebWorld):
|
||||||
tutorials = [Tutorial(
|
tutorials = [Tutorial(
|
||||||
"Multiworld Setup Guide",
|
"Multiworld Setup Guide",
|
||||||
|
26
worlds/factorio/settings.py
Normal file
26
worlds/factorio/settings.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import typing
|
||||||
|
|
||||||
|
import settings
|
||||||
|
|
||||||
|
|
||||||
|
class FactorioSettings(settings.Group):
|
||||||
|
class Executable(settings.UserFilePath):
|
||||||
|
is_exe = True
|
||||||
|
|
||||||
|
class ServerSettings(settings.OptionalUserFilePath):
|
||||||
|
"""
|
||||||
|
by default, no settings are loaded if this file does not exist. \
|
||||||
|
If this file does exist, then it will be used.
|
||||||
|
server_settings: "factorio\\\\data\\\\server-settings.json"
|
||||||
|
"""
|
||||||
|
|
||||||
|
class FilterItemSends(settings.Bool):
|
||||||
|
"""Whether to filter item send messages displayed in-game to only those that involve you."""
|
||||||
|
|
||||||
|
class BridgeChatOut(settings.Bool):
|
||||||
|
"""Whether to send chat messages from players on the Factorio server to Archipelago."""
|
||||||
|
|
||||||
|
executable: Executable = Executable("factorio/bin/x64/factorio")
|
||||||
|
server_settings: typing.Optional[ServerSettings] = None
|
||||||
|
filter_item_sends: typing.Union[FilterItemSends, bool] = False
|
||||||
|
bridge_chat_out: typing.Union[BridgeChatOut, bool] = True
|
Reference in New Issue
Block a user