diff --git a/.gitignore b/.gitignore index 791f7b1bb7..5da42dc1e0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *_Spoiler.txt *.bmbp *.apbp +*.apcivvi *.apl2ac *.apm3 *.apmc diff --git a/worlds/civ_6/Civ6Client.py b/worlds/civ_6/Civ6Client.py index 973a794a4f..f1053a989b 100644 --- a/worlds/civ_6/Civ6Client.py +++ b/worlds/civ_6/Civ6Client.py @@ -1,7 +1,9 @@ import asyncio import logging +import os import traceback from typing import Dict, List +import zipfile from CommonClient import ClientCommandProcessor, CommonContext, get_base_parser, logger, server_loop, gui_enabled from .Data import get_progressive_districts_data @@ -68,11 +70,12 @@ class CivVIContext(CommonContext): item.name: item.code for item in generate_item_table().values()} connection_state = ConnectionState.DISCONNECTED - def __init__(self, server_address, password): + def __init__(self, server_address, password, apcivvi_file=None): super().__init__(server_address, password) self.game_interface = CivVIInterface(logger) location_by_era = generate_era_location_table() self.item_table = generate_item_table() + self.apcivvi_file = apcivvi_file # Get tables formatted in a way that is easier to use here for era, locations in location_by_era.items(): @@ -151,7 +154,6 @@ async def tuner_sync_task(ctx: CivVIContext): else: try: if ctx.processing_multiple_items == True: - logger.debug("Waiting for items to finish processing") await asyncio.sleep(3) else: state = await ctx.game_interface.is_in_game() @@ -203,7 +205,6 @@ async def handle_receive_items(ctx: CivVIContext, last_received_index_override: try: last_received_index = last_received_index_override or await ctx.game_interface.get_last_received_index() if len(ctx.items_received) - last_received_index > 1: - logger.debug("Multiple items received") ctx.processing_multiple_items = True progressive_districts: List[CivVIItemData] = [] @@ -244,8 +245,6 @@ async def handle_receive_items(ctx: CivVIContext, last_received_index_override: elif item.item_type == CivVICheckType.ERA: progressive_eras.append(item) - if ctx.processing_multiple_items: - logger.debug("DONE") ctx.processing_multiple_items = False finally: # If something errors out, then unblock item processing @@ -253,7 +252,6 @@ async def handle_receive_items(ctx: CivVIContext, last_received_index_override: async def handle_check_goal_complete(ctx: CivVIContext): - # logger.debug("Sending Goal Complete") result = await ctx.game_interface.check_victory() if result: logger.info("Sending Victory to server!") @@ -285,7 +283,22 @@ def main(connect=None, password=None, name=None): Utils.init_logging("Civilization VI Client") async def _main(connect, password, name): - ctx = CivVIContext(connect, password) + parser = get_base_parser() + parser.add_argument('apcivvi_file', default="", type=str, nargs='?', help="Path to apcivvi file") + args = parser.parse_args() + ctx = CivVIContext(connect, password, args.apcivvi_file) + + if args.apcivvi_file: + parent_dir = os.path.dirname(args.apcivvi_file) + target_name = os.path.basename(args.apcivvi_file).replace(".apcivvi", "-MOD-FILES") + target_path = os.path.join(parent_dir, target_name) + if not os.path.exists(target_path): + os.makedirs(target_path, exist_ok=True) + logger.info("Extracting mod files to %s", target_path) + with zipfile.ZipFile(args.apcivvi_file, 'r') as zip_ref: + for member in zip_ref.namelist(): + zip_ref.extract(member, target_path) + ctx.auth = name ctx.server_task = asyncio.create_task( server_loop(ctx), name="ServerLoop") @@ -314,6 +327,7 @@ def main(connect=None, password=None, name=None): def debug_main(): parser = get_base_parser() + parser.add_argument('apcivvi_file', default="", type=str, nargs='?', help="Path to apcivvi file") parser.add_argument('--name', default=None, help="Slot Name to connect as.") parser.add_argument('--debug', default=None, diff --git a/worlds/civ_6/Container.py b/worlds/civ_6/Container.py index 5d324eea5c..93db3647e1 100644 --- a/worlds/civ_6/Container.py +++ b/worlds/civ_6/Container.py @@ -36,7 +36,7 @@ class CivVIContainer(APContainer): player=None, player_name: str = "", server: str = ""): self.patch_data = patch_data self.file_path = base_path - container_path = os.path.join(output_directory, base_path + ".zip") + container_path = os.path.join(output_directory, base_path + ".apcivvi") super().__init__(container_path, player, player_name, server) def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None: diff --git a/worlds/civ_6/TunerClient.py b/worlds/civ_6/TunerClient.py index 8a6d3497af..7478e02e8b 100644 --- a/worlds/civ_6/TunerClient.py +++ b/worlds/civ_6/TunerClient.py @@ -55,7 +55,6 @@ class TunerClient: async def send_command(self, command_string: str, size: int = 64): """Send a raw commannd""" - self.logger.debug("Sending Command: " + command_string) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setblocking(False) @@ -83,8 +82,6 @@ class TunerClient: received_data = await self.async_recv(sock) response = decode_mixed_string(received_data) - self.logger.debug('Received:') - self.logger.debug(response) return self.__parse_response(response) except socket.timeout: @@ -97,9 +94,9 @@ class TunerClient: "The remote computer refused the network connection", ] if any(error in str(e) for error in connection_errors): - raise TunerConnectionException(e) + raise TunerConnectionException(e) else: - raise TunerErrorException(e) + raise TunerErrorException(e) finally: sock.close() diff --git a/worlds/civ_6/__init__.py b/worlds/civ_6/__init__.py index 45af2cdc2e..b8d61247a8 100644 --- a/worlds/civ_6/__init__.py +++ b/worlds/civ_6/__init__.py @@ -1,7 +1,7 @@ import math import os import random -from typing import Dict +from typing import Dict, Optional import typing from .Data import get_boosts_data @@ -19,7 +19,7 @@ from worlds.AutoWorld import World, WebWorld from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components, launch_subprocess -def run_client(): +def run_client(url: Optional[str] = None): print("Running Civ6 Client") from .Civ6Client import main # lazy import launch_subprocess(main, name="Civ6Client") @@ -183,7 +183,7 @@ class CivVIWorld(World): def generate_output(self, output_directory: str): mod_name = f"AP-{self.multiworld.get_file_safe_player_name(self.player)}" mod_dir = os.path.join( - output_directory, mod_name + "_" + Utils.__version__) + output_directory, mod_name + "_" + self.multiworld.seed_name) mod_files = { f"NewItems.xml": generate_new_items(self), f"InitOptions.lua": generate_setup_file(self), diff --git a/worlds/civ_6/docs/setup_en.md b/worlds/civ_6/docs/setup_en.md index cd419fc66f..7dc44150f9 100644 --- a/worlds/civ_6/docs/setup_en.md +++ b/worlds/civ_6/docs/setup_en.md @@ -1,49 +1,51 @@ -# Setup Guide for Civilization VI Archipelago - -This guide is meant to help you get up and running with Civlization VI in your Archipelago run. Note that this requires you to have both Rise & Fall as well as Gathering Storm installed. This will not work unless both of those DLCs are enabled. - -## Requirements - -The following are required in order to play Civ VI in Archipelago - -- Windows OS (Firaxis does not support the necessary tooling for Mac, Linux is yet to bet verified) - -- Installed [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) v0.4.5 or higher.\ - **Make sure to install the Generator if you intend to generate multiworlds.** - -- The latest version of the [Civ VI AP Mod](https://github.com/hesto2/civilization_archipelago_mod). - -- Tuner setting enabled so the archipelago client can communicate with the game - -## Enabling the tuner -Depending on how you installed Civ 6 you will have to navigate to one of the following: -- `YOUR_USER/Documents/My Games/Sid Meier's Civilization VI/AppOptions.txt` -- `YOUR_USER/AppData/Local/Firaxis Games/Sid Meier's Civilization VI/AppOptions.txt` - -Once you have located your `AppOptions.txt`, do a search for `Enable FireTuner`. Set `EnableTuner` to `1` instead of `0`. __NOTE__: While this is active, achievments will be disabled. - -## Mod Installation - -1. Download and unzip the latest release of the mod from [github](https://github.com/hesto2/civilization_archipelago_mod/releases). - -2. Copy the folder containing the mod files to your Civ VI mods folder. On Windows, this is usually located at `C:\Users\YOUR_USER\Documents\My Games\Sid Meier's Civilization VI\Mods` - -3. After the Archipelago host generates a game, you should be given another zip file titled `AP-{playername}....zip`. Unzip this and copy all of its contents into your mod folder. - -4. Your finished mod folder should look something like this: -- Civ VI Mods Directory - - civilization_archipelago_mod - - NewItems.xml - - InitOptions.lua - - Archipelago.modinfo - - All the other mod files, etc. - -## Configuring your game - -When configuring your game, make sure to start the game in the Ancient Era and leave all settings related to starting technologies and civics as the defaults. Other than that, configure difficulty, AI, etc. as you normally would. - -## Troubleshooting - -- If you are getting an error: `The remote computer refused the network connection`, or something else related to the client (or tuner) not being able to connect, it likely indicates the tuner is not actually enabled. One simple way to verify that it is enabled is, after completing the setup steps, to go Main Menu -> Options -> Look for an option named "Tuner" and verify it is set to "Enabled" - +# Setup Guide for Civilization VI Archipelago + +This guide is meant to help you get up and running with Civlization VI in your Archipelago run. Note that this requires you to have both Rise & Fall as well as Gathering Storm installed. This will not work unless both of those DLCs are enabled. + +## Requirements + +The following are required in order to play Civ VI in Archipelago + +- Windows OS (Firaxis does not support the necessary tooling for Mac, Linux is yet to bet verified) + +- Installed [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) v0.4.5 or higher.\ + **Make sure to install the Generator if you intend to generate multiworlds.** + +- The latest version of the [Civ VI AP Mod](https://github.com/hesto2/civilization_archipelago_mod). + +- Tuner setting enabled so the archipelago client can communicate with the game + +## Enabling the tuner +Depending on how you installed Civ 6 you will have to navigate to one of the following: +- `YOUR_USER/Documents/My Games/Sid Meier's Civilization VI/AppOptions.txt` +- `YOUR_USER/AppData/Local/Firaxis Games/Sid Meier's Civilization VI/AppOptions.txt` + +Once you have located your `AppOptions.txt`, do a search for `Enable FireTuner`. Set `EnableTuner` to `1` instead of `0`. __NOTE__: While this is active, achievments will be disabled. + +## Mod Installation + +1. Download and unzip the latest release of the mod from [github](https://github.com/hesto2/civilization_archipelago_mod/releases). + +2. Copy the folder containing the mod files to your Civ VI mods folder. On Windows, this is usually located at `C:\Users\YOUR_USER\Documents\My Games\Sid Meier's Civilization VI\Mods` + +3. After the Archipelago host generates a game, you should be given a `.apcivvi` file. Associate the file with the Archipelago Launcher and double click it. + +4. Copy the contents of the new folder it generates (it will have the same name as the `.apcivvi` file) into your Civilization VI Archipelago Mod folder. + +5. Your finished mod folder should look something like this: +- Civ VI Mods Directory + - civilization_archipelago_mod + - NewItems.xml + - InitOptions.lua + - Archipelago.modinfo + - All the other mod files, etc. + +## Configuring your game + +When configuring your game, make sure to start the game in the Ancient Era and leave all settings related to starting technologies and civics as the defaults. Other than that, configure difficulty, AI, etc. as you normally would. + +## Troubleshooting + +- If you are getting an error: `The remote computer refused the network connection`, or something else related to the client (or tuner) not being able to connect, it likely indicates the tuner is not actually enabled. One simple way to verify that it is enabled is, after completing the setup steps, to go Main Menu -> Options -> Look for an option named "Tuner" and verify it is set to "Enabled" + - If your game gets in a state where someone has sent you items or you have sent locations but these are not correctly replicated to the multiworld, you can run `/resync` from the Civ 6 client. This may take up to a minute depending on how many items there are. \ No newline at end of file