allow Factorio Client to recognize if it's trying to connect to the wrong multiworld.

This commit is contained in:
Fabian Dill 2021-05-16 00:21:00 +02:00
parent 8e27ad3547
commit 3e1941a561
8 changed files with 56 additions and 45 deletions

View File

@ -44,6 +44,7 @@ class MultiWorld():
self.shops = [] self.shops = []
self.itempool = [] self.itempool = []
self.seed = None self.seed = None
self.seed_name: str = "Unavailable"
self.precollected_items = [] self.precollected_items = []
self.state = CollectionState(self) self.state = CollectionState(self)
self._cached_entrances = None self._cached_entrances = None

View File

@ -112,6 +112,7 @@ class CommonContext():
self.team = None self.team = None
self.slot = None self.slot = None
self.auth = None self.auth = None
self.seed_name = None
self.locations_checked: typing.Set[int] = set() self.locations_checked: typing.Set[int] = set()
self.locations_scouted: typing.Set[int] = set() self.locations_scouted: typing.Set[int] = set()
@ -278,6 +279,9 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
logger.exception(f"Could not get command from {args}") logger.exception(f"Could not get command from {args}")
raise raise
if cmd == 'RoomInfo': if cmd == 'RoomInfo':
if ctx.seed_name and ctx.seed_name != args["seed_name"]:
logger.info("The server is running a different multiworld than your client is. (invalid seed_name)")
else:
logger.info('--------------------------------') logger.info('--------------------------------')
logger.info('Room Information:') logger.info('Room Information:')
logger.info('--------------------------------') logger.info('--------------------------------')

View File

@ -107,6 +107,7 @@ async def game_watcher(ctx: FactorioContext, bridge_file: str):
research_data = {int(tech_name.split("-")[1]) for tech_name in research_data} research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
victory = data["victory"] victory = data["victory"]
ctx.auth = data["slot_name"] ctx.auth = data["slot_name"]
ctx.seed_name = data["seed_name"]
if not ctx.finished_game and victory: if not ctx.finished_game and victory:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}]) await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])

10
Main.py
View File

@ -67,6 +67,7 @@ def main(args, seed=None):
world.secure() world.secure()
else: else:
world.random.seed(world.seed) world.random.seed(world.seed)
world.seed_name = str(args.outputname if args.outputname else world.seed)
world.shuffle = args.shuffle.copy() world.shuffle = args.shuffle.copy()
world.logic = args.logic.copy() world.logic = args.logic.copy()
@ -314,7 +315,7 @@ def main(args, seed=None):
balance_multiworld_progression(world) balance_multiworld_progression(world)
logger.info('Generating output files.') logger.info('Generating output files.')
outfilebase = 'AP_%s' % (args.outputname if args.outputname else world.seed) outfilebase = 'AP_' + world.seed_name
rom_names = [] rom_names = []
def _gen_rom(team: int, player: int): def _gen_rom(team: int, player: int):
@ -422,8 +423,7 @@ def main(args, seed=None):
for player in world.alttp_player_ids: for player in world.alttp_player_ids:
rom_futures.append(pool.submit(_gen_rom, team, player)) rom_futures.append(pool.submit(_gen_rom, team, player))
for player in world.factorio_player_ids: for player in world.factorio_player_ids:
mod_futures.append(pool.submit(generate_mod, world, player, mod_futures.append(pool.submit(generate_mod, world, player))
str(args.outputname if args.outputname else world.seed)))
def get_entrance_to_region(region: Region): def get_entrance_to_region(region: Region):
for entrance in region.entrances: for entrance in region.entrances:
@ -559,7 +559,7 @@ def main(args, seed=None):
"version": tuple(_version_tuple), "version": tuple(_version_tuple),
"tags": ["AP"], "tags": ["AP"],
"minimum_versions": minimum_versions, "minimum_versions": minimum_versions,
"seed_name": str(args.outputname if args.outputname else world.seed) "seed_name": world.seed_name
}), 9) }), 9)
with open(output_path('%s.archipelago' % outfilebase), 'wb') as f: with open(output_path('%s.archipelago' % outfilebase), 'wb') as f:
@ -578,7 +578,7 @@ def main(args, seed=None):
multidata_task.result() # retrieve exception if one exists multidata_task.result() # retrieve exception if one exists
pool.shutdown() # wait for all queued tasks to complete pool.shutdown() # wait for all queued tasks to complete
for player in world.minecraft_player_ids: # Doing this after shutdown prevents the .apmc from being generated if there's an error for player in world.minecraft_player_ids: # Doing this after shutdown prevents the .apmc from being generated if there's an error
generate_mc_data(world, player, str(args.outputname if args.outputname else world.seed)) generate_mc_data(world, player)
if not args.skip_playthrough: if not args.skip_playthrough:
logger.info('Calculating playthrough.') logger.info('Calculating playthrough.')
create_playthrough(world) create_playthrough(world)

View File

@ -43,7 +43,7 @@ class Client(Endpoint):
version = Version(0, 0, 0) version = Version(0, 0, 0)
tags: typing.List[str] = [] tags: typing.List[str] = []
def __init__(self, socket: websockets.server.WebSocketServerProtocol, ctx: Context): def __init__(self, socket: websockets.WebSocketServerProtocol, ctx: Context):
super().__init__(socket) super().__init__(socket)
self.auth = False self.auth = False
self.name = None self.name = None

View File

@ -10,6 +10,7 @@ require "util"
FREE_SAMPLES = {{ free_samples }} FREE_SAMPLES = {{ free_samples }}
SLOT_NAME = "{{ slot_name }}" SLOT_NAME = "{{ slot_name }}"
SEED_NAME = "{{ seed_name }}"
--SUPPRESS_INVENTORY_EVENTS = false --SUPPRESS_INVENTORY_EVENTS = false
-- Initialize force data, either from it being created or already being part of the game when the mod was added. -- Initialize force data, either from it being created or already being part of the game when the mod was added.
@ -180,7 +181,8 @@ function dumpInfo(force)
local data_collection = { local data_collection = {
["research_done"] = research_done, ["research_done"] = research_done,
["victory"] = chain_lookup(global, "forcedata", force.name, "victory"), ["victory"] = chain_lookup(global, "forcedata", force.name, "victory"),
["slot_name"] = SLOT_NAME ["slot_name"] = SLOT_NAME,
["seed_name"] = SEED_NAME
} }
for tech_name, tech in pairs(force.technologies) do for tech_name, tech in pairs(force.technologies) do

View File

@ -46,7 +46,7 @@ rocket_recipes = {
'{{"copper-cable", 10}, {"iron-plate", 10}, {"wood", 10}}' '{{"copper-cable", 10}, {"iron-plate", 10}, {"wood", 10}}'
} }
def generate_mod(world: MultiWorld, player: int, seedname: str): def generate_mod(world: MultiWorld, player: int):
global template, locale_template, control_template global template, locale_template, control_template
with template_load_lock: with template_load_lock:
if not template: if not template:
@ -59,7 +59,7 @@ def generate_mod(world: MultiWorld, player: int, seedname: str):
locations = [] locations = []
for location in world.get_filled_locations(player): for location in world.get_filled_locations(player):
locations.append((location.name, location.item.name, location.item.player)) locations.append((location.name, location.item.name, location.item.player))
mod_name = f"AP-{seedname}-P{player}-{world.player_names[player][0]}" mod_name = f"AP-{world.seed_name}-P{player}-{world.player_names[player][0]}"
tech_cost = {0: 0.1, tech_cost = {0: 0.1,
1: 0.25, 1: 0.25,
2: 0.5, 2: 0.5,
@ -72,10 +72,12 @@ def generate_mod(world: MultiWorld, player: int, seedname: str):
"tech_cost_scale": tech_cost, "custom_data": world.custom_data[player], "tech_cost_scale": tech_cost, "custom_data": world.custom_data[player],
"tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites[player], "tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites[player],
"rocket_recipe" : rocket_recipes[world.max_science_pack[player].value], "rocket_recipe" : rocket_recipes[world.max_science_pack[player].value],
"slot_name": world.player_names[player][0], "slot_name": world.player_names[player][0], "seed_name": world.seed_name,
"starting_items": world.starting_items[player]} "starting_items": world.starting_items[player]}
for factorio_option in Options.factorio_options: for factorio_option in Options.factorio_options:
template_data[factorio_option] = getattr(world, factorio_option)[player].value template_data[factorio_option] = getattr(world, factorio_option)[player].value
control_code = control_template.render(**template_data) control_code = control_template.render(**template_data)
data_final_fixes_code = template.render(**template_data) data_final_fixes_code = template.render(**template_data)

View File

@ -9,20 +9,21 @@ from Options import minecraft_options
client_version = (0, 3) client_version = (0, 3)
def generate_mc_data(world: MultiWorld, player: int, seedname: str): def generate_mc_data(world: MultiWorld, player: int):
import base64, json import base64, json
from Utils import output_path from Utils import output_path
exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2", "The End Structure"] exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2", "The End Structure"]
data = { data = {
'world_seed': Random(world.rom_seeds[player]).getrandbits(32), # consistent and doesn't interfere with other generation 'world_seed': Random(world.rom_seeds[player]).getrandbits(32), # consistent and doesn't interfere with other generation
'seed_name': seedname, 'seed_name': world.seed_name,
'player_name': world.get_player_names(player), 'player_name': world.get_player_names(player),
'player_id': player,
'client_version': client_version, 'client_version': client_version,
'structures': {exit: world.get_entrance(exit, player).connected_region.name for exit in exits} 'structures': {exit: world.get_entrance(exit, player).connected_region.name for exit in exits}
} }
filename = f"AP_{seedname}_P{player}_{world.get_player_names(player)}.apmc" filename = f"AP_{world.seed_name}_P{player}_{world.get_player_names(player)}.apmc"
with open(output_path(filename), 'wb') as f: with open(output_path(filename), 'wb') as f:
f.write(base64.b64encode(bytes(json.dumps(data), 'utf-8'))) f.write(base64.b64encode(bytes(json.dumps(data), 'utf-8')))