Core: implement first version of ItemLinks

This commit is contained in:
Fabian Dill
2022-02-05 15:49:19 +01:00
parent 6923800081
commit 28201a6c38
10 changed files with 277 additions and 75 deletions

84
Main.py
View File

@@ -1,3 +1,5 @@
import copy
import collections
from itertools import zip_longest, chain
import logging
import os
@@ -7,7 +9,7 @@ import concurrent.futures
import pickle
import tempfile
import zipfile
from typing import Dict, Tuple, Optional
from typing import Dict, Tuple, Optional, Set
from BaseClasses import MultiWorld, CollectionState, Region, RegionType, LocationProgressType
from worlds.alttp.Items import item_name_groups
@@ -18,7 +20,6 @@ from Utils import output_path, get_options, __version__, version_tuple
from worlds.generic.Rules import locality_rules, exclusion_rules
from worlds import AutoWorld
ordered_areas = (
'Light World', 'Dark World', 'Hyrule Castle', 'Agahnims Tower', 'Eastern Palace', 'Desert Palace',
'Tower of Hera', 'Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town', 'Ice Palace',
@@ -136,6 +137,74 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
AutoWorld.call_all(world, "generate_basic")
# temporary home for item links, should be moved out of Main
item_links = {}
for player in world.player_ids:
for item_link in world.item_links[player].value:
if item_link["name"] in item_links:
item_links[item_link["name"]]["players"][player] = item_link["replacement_item"]
item_links[item_link["name"]]["item_pool"] &= set(item_link["item_pool"])
else:
if item_link["name"] in world.player_name.values():
raise Exception(f"Cannot name a ItemLink group the same as a player ({item_link['name']}).")
item_links[item_link["name"]] = {
"players": {player: item_link["replacement_item"]},
"item_pool": set(item_link["item_pool"]),
"game": world.game[player]
}
for item_link in item_links.values():
current_item_name_groups = AutoWorld.AutoWorldRegister.world_types[item_link["game"]].item_name_groups
pool = set()
for item in item_link["item_pool"]:
pool |= current_item_name_groups.get(item, {item})
item_link["item_pool"] = pool
for group_name, item_link in item_links.items():
game = item_link["game"]
group_id, group = world.add_group(group_name, game, set(item_link["players"]))
def find_common_pool(players: Set[int], shared_pool: Set[int]) -> \
Dict[int, Dict[str, int]]:
counters = {player: {name: 0 for name in shared_pool} for player in players}
for item in world.itempool:
if item.player in counters and item.name in shared_pool:
counters[item.player][item.name] += 1
for item in shared_pool:
count = min(counters[player][item] for player in players)
if count:
for player in players:
counters[player][item] = count
else:
for player in players:
del(counters[player][item])
return counters
common_item_count = find_common_pool(group["players"], item_link["item_pool"])
new_itempool = []
for item_name, item_count in next(iter(common_item_count.values())).items():
for _ in range(item_count):
new_itempool.append(group["world"].create_item(item_name))
for item in world.itempool:
if common_item_count.get(item.player, {}).get(item.name, 0):
common_item_count[item.player][item.name] -= 1
else:
new_itempool.append(item)
itemcount = len(world.itempool)
world.itempool = new_itempool
while itemcount > len(world.itempool):
for player in world.get_game_players(game):
if item_link["players"][player]:
world.itempool.append(AutoWorld.call_single(world, "create_item", player,
item_link["players"][player]))
else:
AutoWorld.call_single(world, "create_filler", player)
logger.info("Running Item Plando")
for item in world.itempool:
@@ -253,10 +322,15 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for slot in world.player_ids:
client_versions[slot] = world.worlds[slot].get_required_client_version()
games[slot] = world.game[slot]
slot_info[slot] = NetUtils.NetworkSlot(names[0][slot-1], world.game[slot], world.player_types[slot])
slot_info[slot] = NetUtils.NetworkSlot(names[0][slot - 1], world.game[slot],
world.player_types[slot])
for slot, group in world.groups.items():
games[slot] = world.game[slot]
slot_info[slot] = NetUtils.NetworkSlot(group["name"], world.game[slot], world.player_types[slot],
group_members=sorted(group["players"]))
precollected_items = {player: [item.code for item in world_precollected]
for player, world_precollected in world.precollected_items.items()}
precollected_hints = {player: set() for player in range(1, world.players + 1)}
precollected_hints = {player: set() for player in range(1, world.players + 1 + len(world.groups))}
sending_visible_players = set()
@@ -321,7 +395,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
else:
logger.warning("Location Accessibility requirements not fulfilled.")
# retrieve exceptions via .result() if they occured.
# retrieve exceptions via .result() if they occurred.
multidata_task.result()
for i, future in enumerate(concurrent.futures.as_completed(output_file_futures), start=1):
if i % 10 == 0 or i == len(output_file_futures):