Factorio: Added ability to chat from within the game. (#1068)
* Factorio: Added ability to chat from within the game. This also allows using commands such as !hint from within the game. * Factorio: Only prepend player names to chat in multiplayer. * Factorio: Mirror chat sent from the FactorioClient UI to the Factorio server. * Factorio: Remove local coordinates from outgoing chat. * Factorio: Added setting to disable bridging chat out. Added client command to toggle this setting at run-time. * Factorio: Added in-game command to toggle chat bridging setting at run-time. * . * Factorio: Document toggle for chat bridging feature. * (Removed superfluous type annotations.) * (Removed hard to read regex.) * Docs/Factorio: Fix display of multiline code snippets.
This commit is contained in:
parent
924f484be0
commit
cfff12d8d7
|
@ -8,6 +8,7 @@ import re
|
|||
import subprocess
|
||||
import time
|
||||
import random
|
||||
import typing
|
||||
|
||||
import ModuleUpdate
|
||||
ModuleUpdate.update()
|
||||
|
@ -51,6 +52,9 @@ class FactorioCommandProcessor(ClientCommandProcessor):
|
|||
"""Toggle filtering of item sends that get displayed in-game to only those that involve you."""
|
||||
self.ctx.toggle_filter_item_sends()
|
||||
|
||||
def _cmd_toggle_chat(self):
|
||||
"""Toggle sending of chat messages from players on the Factorio server to Archipelago."""
|
||||
self.ctx.toggle_bridge_chat_out()
|
||||
|
||||
class FactorioContext(CommonContext):
|
||||
command_processor = FactorioCommandProcessor
|
||||
|
@ -71,6 +75,8 @@ class FactorioContext(CommonContext):
|
|||
self.energy_link_increment = 0
|
||||
self.last_deplete = 0
|
||||
self.filter_item_sends: bool = False
|
||||
self.multiplayer: bool = False # whether multiple different players have connected
|
||||
self.bridge_chat_out: bool = True
|
||||
|
||||
async def server_auth(self, password_requested: bool = False):
|
||||
if password_requested and not self.password:
|
||||
|
@ -87,13 +93,15 @@ class FactorioContext(CommonContext):
|
|||
def on_print(self, args: dict):
|
||||
super(FactorioContext, self).on_print(args)
|
||||
if self.rcon_client:
|
||||
self.print_to_game(args['text'])
|
||||
if not args['text'].startswith(self.player_names[self.slot] + ":"):
|
||||
self.print_to_game(args['text'])
|
||||
|
||||
def on_print_json(self, args: dict):
|
||||
if self.rcon_client:
|
||||
if not self.filter_item_sends or not self.is_uninteresting_item_send(args):
|
||||
text = self.factorio_json_text_parser(copy.deepcopy(args["data"]))
|
||||
self.print_to_game(text)
|
||||
if not text.startswith(self.player_names[self.slot] + ":"):
|
||||
self.print_to_game(text)
|
||||
super(FactorioContext, self).on_print_json(args)
|
||||
|
||||
@property
|
||||
|
@ -130,6 +138,27 @@ class FactorioContext(CommonContext):
|
|||
f"{Utils.format_SI_prefix(args['value'])}J remaining.")
|
||||
self.rcon_client.send_command(f"/ap-energylink {gained}")
|
||||
|
||||
def on_user_say(self, text: str) -> typing.Optional[str]:
|
||||
# Mirror chat sent from the UI to the Factorio server.
|
||||
self.print_to_game(f"{self.player_names[self.slot]}: {text}")
|
||||
return text
|
||||
|
||||
async def chat_from_factorio(self, user: str, message: str) -> None:
|
||||
if not self.bridge_chat_out:
|
||||
return
|
||||
|
||||
# Pass through commands
|
||||
if message.startswith("!"):
|
||||
await self.send_msgs([{"cmd": "Say", "text": message}])
|
||||
return
|
||||
|
||||
# Omit messages that contain local coordinates
|
||||
if "[gps=" in message:
|
||||
return
|
||||
|
||||
prefix = f"({user}) " if self.multiplayer else ""
|
||||
await self.send_msgs([{"cmd": "Say", "text": f"{prefix}{message}"}])
|
||||
|
||||
def toggle_filter_item_sends(self) -> None:
|
||||
self.filter_item_sends = not self.filter_item_sends
|
||||
if self.filter_item_sends:
|
||||
|
@ -139,6 +168,15 @@ class FactorioContext(CommonContext):
|
|||
logger.info(announcement)
|
||||
self.print_to_game(announcement)
|
||||
|
||||
def toggle_bridge_chat_out(self) -> None:
|
||||
self.bridge_chat_out = not self.bridge_chat_out
|
||||
if self.bridge_chat_out:
|
||||
announcement = "Chat is now bridged to Archipelago."
|
||||
else:
|
||||
announcement = "Chat is no longer bridged to Archipelago."
|
||||
logger.info(announcement)
|
||||
self.print_to_game(announcement)
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
|
@ -178,6 +216,7 @@ async def game_watcher(ctx: FactorioContext):
|
|||
research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
|
||||
victory = data["victory"]
|
||||
await ctx.update_death_link(data["death_link"])
|
||||
ctx.multiplayer = data.get("multiplayer", False)
|
||||
|
||||
if not ctx.finished_game and victory:
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
|
@ -281,8 +320,14 @@ async def factorio_server_watcher(ctx: FactorioContext):
|
|||
elif re.match(r"^[0-9.]+ Script @[^ ]+\.lua:\d+: Player command toggle-ap-send-filter", msg):
|
||||
factorio_server_logger.debug(msg)
|
||||
ctx.toggle_filter_item_sends()
|
||||
elif re.match(r"^[0-9.]+ Script @[^ ]+\.lua:\d+: Player command toggle-ap-chat$", msg):
|
||||
factorio_server_logger.debug(msg)
|
||||
ctx.toggle_bridge_chat_out()
|
||||
else:
|
||||
factorio_server_logger.info(msg)
|
||||
match = re.match(r"^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d \[CHAT\] ([^:]+): (.*)$", msg)
|
||||
if match:
|
||||
await ctx.chat_from_factorio(match.group(1), match.group(2))
|
||||
if ctx.rcon_client:
|
||||
commands = {}
|
||||
while ctx.send_index < len(ctx.items_received):
|
||||
|
@ -383,6 +428,7 @@ async def factorio_spinup_server(ctx: FactorioContext) -> bool:
|
|||
async def main(args):
|
||||
ctx = FactorioContext(args.connect, args.password)
|
||||
ctx.filter_item_sends = initial_filter_item_sends
|
||||
ctx.bridge_chat_out = initial_bridge_chat_out
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||
|
||||
if gui_enabled:
|
||||
|
@ -438,6 +484,9 @@ if __name__ == '__main__':
|
|||
if not isinstance(options["factorio_options"]["filter_item_sends"], bool):
|
||||
logging.warning(f"Warning: Option filter_item_sends should be a bool.")
|
||||
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)):
|
||||
raise FileNotFoundError(f"Path {os.path.dirname(executable)} does not exist or could not be accessed.")
|
||||
|
|
1
Utils.py
1
Utils.py
|
@ -232,6 +232,7 @@ def get_default_options() -> OptionsType:
|
|||
"factorio_options": {
|
||||
"executable": os.path.join("factorio", "bin", "x64", "factorio"),
|
||||
"filter_item_sends": False,
|
||||
"bridge_chat_out": True,
|
||||
},
|
||||
"sni_options": {
|
||||
"sni": "SNI",
|
||||
|
|
|
@ -101,6 +101,8 @@ factorio_options:
|
|||
# server_settings: "factorio\\data\\server-settings.json"
|
||||
# Whether to filter item send messages displayed in-game to only those that involve you.
|
||||
filter_item_sends: false
|
||||
# Whether to send chat messages from players on the Factorio server to Archipelago.
|
||||
bridge_chat_out: true
|
||||
minecraft_options:
|
||||
forge_directory: "Minecraft Forge server"
|
||||
max_heap_size: "2G"
|
||||
|
|
|
@ -157,6 +157,7 @@ function on_player_created(event)
|
|||
{%- if silo == 2 %}
|
||||
check_spawn_silo(game.players[event.player_index].force)
|
||||
{%- endif %}
|
||||
dumpInfo(player.force)
|
||||
end
|
||||
script.on_event(defines.events.on_player_created, on_player_created)
|
||||
|
||||
|
@ -491,6 +492,7 @@ commands.add_command("ap-sync", "Used by the Archipelago client to get progress
|
|||
["death_link"] = DEATH_LINK,
|
||||
["energy"] = chain_lookup(forcedata, "energy"),
|
||||
["energy_bridges"] = chain_lookup(forcedata, "energy_bridges"),
|
||||
["multiplayer"] = #game.players > 1,
|
||||
}
|
||||
|
||||
for tech_name, tech in pairs(force.technologies) do
|
||||
|
@ -600,5 +602,9 @@ commands.add_command("toggle-ap-send-filter", "Toggle filtering of item sends th
|
|||
log("Player command toggle-ap-send-filter") -- notifies client
|
||||
end)
|
||||
|
||||
commands.add_command("toggle-ap-chat", "Toggle sending of chat messages from players on the Factorio server to Archipelago.", function(call)
|
||||
log("Player command toggle-ap-chat") -- notifies client
|
||||
end)
|
||||
|
||||
-- data
|
||||
progressive_technologies = {{ dict_to_lua(progressive_technology_table) }}
|
||||
|
|
|
@ -132,6 +132,8 @@ This allows you to host your own Factorio game.
|
|||
|
||||
For additional client features, issue the `/help` command in the Archipelago Client. Once connected to the AP server,
|
||||
you can also issue the `!help` command to learn about additional commands like `!hint`.
|
||||
For more information about the commands you can use, see the [Commands Guide](/tutorial/Archipelago/commands/en) and
|
||||
[Other Settings](#other-settings).
|
||||
|
||||
## Allowing Other People to Join Your Game
|
||||
|
||||
|
@ -148,10 +150,20 @@ you can also issue the `!help` command to learn about additional commands like `
|
|||
- Type `/toggle-ap-send-filter` in-game
|
||||
- Type `/toggle_send_filter` in the Archipelago Client
|
||||
- In your `host.yaml` set
|
||||
```
|
||||
factorio_options:
|
||||
filter_item_sends: true
|
||||
```
|
||||
```
|
||||
factorio_options:
|
||||
filter_item_sends: true
|
||||
```
|
||||
- By default, in-game chat is bridged to Archipelago. If you prefer to be able to speak privately, you can disable this
|
||||
feature by doing one of the following:
|
||||
- Type `/toggle-ap-chat` in-game
|
||||
- Type `/toggle_chat` in the Archipelago Client
|
||||
- In your `host.yaml` set
|
||||
```
|
||||
factorio_options:
|
||||
bridge_chat_out: false
|
||||
```
|
||||
Note that this will also disable `!` commands from within the game, and that it will not affect incoming chat.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
@ -159,13 +171,6 @@ In case any problems should occur, the Archipelago Client will create a file `Fa
|
|||
contents of this file may help you troubleshoot an issue on your own and is vital for requesting help from other people
|
||||
in Archipelago.
|
||||
|
||||
## Commands in game
|
||||
|
||||
Once you have connected to the server successfully using the Archipelago Factorio Client you should see a message
|
||||
stating you can get help using Archipelago commands by typing `!help`. Commands cannot currently be sent from within
|
||||
the Factorio session, but you can send them from the Archipelago Factorio Client. For more information about the commands
|
||||
you can use see the [commands guide](/tutorial/Archipelago/commands/en).
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- Alternate Tutorial by
|
||||
|
|
Loading…
Reference in New Issue