diff --git a/Main.py b/Main.py index c35f5b9d..2b3ec51b 100644 --- a/Main.py +++ b/Main.py @@ -23,8 +23,6 @@ from worlds.alttp.ItemPool import generate_itempool, difficulties, fill_prizes from Utils import output_path, parse_player_names, get_options, __version__, _version_tuple from worlds.hk import gen_hollow from worlds.hk import create_regions as hk_create_regions -from worlds.minecraft import gen_minecraft, fill_minecraft_slot_data, generate_mc_data -from worlds.minecraft.Regions import minecraft_create_regions from worlds.generic.Rules import locality_rules from worlds import Games, lookup_any_item_name_to_id, AutoWorld import Patch @@ -201,9 +199,6 @@ def main(args, seed=None): AutoWorld.call_all(world, "create_regions") - for player in world.minecraft_player_ids: - minecraft_create_regions(world, player) - for player in world.alttp_player_ids: if world.open_pyramid[player] == 'goal': world.open_pyramid[player] = world.goal[player] in {'crystals', 'ganontriforcehunt', @@ -268,9 +263,6 @@ def main(args, seed=None): AutoWorld.call_all(world, "generate_basic") - for player in world.minecraft_player_ids: - gen_minecraft(world, player) - logger.info("Running Item Plando") for item in world.itempool: @@ -526,7 +518,7 @@ def main(args, seed=None): option = getattr(world, option_name)[slot] slots_data[option_name] = int(option.value) for slot in world.minecraft_player_ids: - slot_data[slot] = fill_minecraft_slot_data(world, slot) + slot_data[slot] = AutoWorld.call_single(world, "fill_slot_data", slot) locations_data: Dict[int, Dict[int, Tuple[int, int]]] = {player: {} for player in world.player_ids} for location in world.get_filled_locations(): @@ -578,8 +570,6 @@ def main(args, seed=None): if multidata_task: multidata_task.result() # retrieve exception if one exists 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 - generate_mc_data(world, player) if not args.skip_playthrough: logger.info('Calculating playthrough.') create_playthrough(world) diff --git a/worlds/minecraft/Regions.py b/worlds/minecraft/Regions.py index 2475e038..75469271 100644 --- a/worlds/minecraft/Regions.py +++ b/worlds/minecraft/Regions.py @@ -1,26 +1,10 @@ -from .Locations import MinecraftAdvancement, advancement_table -from BaseClasses import Region, Entrance, Location, MultiWorld, Item - -def minecraft_create_regions(world: MultiWorld, player: int): - - def MCRegion(region_name: str, exits=[]): - ret = Region(region_name, None, region_name, player) - ret.world = world - ret.locations = [ MinecraftAdvancement(player, loc_name, loc_data.id, ret) - for loc_name, loc_data in advancement_table.items() - if loc_data.region == region_name ] - for exit in exits: - ret.exits.append(Entrance(player, exit, ret)) - return ret - - world.regions += [MCRegion(*r) for r in mc_regions] +def link_minecraft_structures(world, player: int): + # Link mandatory connections first for (exit, region) in mandatory_connections: world.get_entrance(exit, player).connect(world.get_region(region, player)) -def link_minecraft_structures(world: MultiWorld, player: int): - # Get all unpaired exits and all regions without entrances (except the Menu) # This function is destructive on these lists. exits = [exit.name for r in world.regions if r.player == player for exit in r.exits if exit.connected_region == None] diff --git a/worlds/minecraft/__init__.py b/worlds/minecraft/__init__.py index f81c2bcf..4e27215f 100644 --- a/worlds/minecraft/__init__.py +++ b/worlds/minecraft/__init__.py @@ -1,81 +1,90 @@ -from random import Random from .Items import MinecraftItem, item_table, item_frequencies -from .Locations import exclusion_table, events_table -from .Regions import link_minecraft_structures +from .Locations import MinecraftAdvancement, advancement_table, exclusion_table, events_table +from .Regions import mc_regions, link_minecraft_structures from .Rules import set_rules -from BaseClasses import MultiWorld +from BaseClasses import Region, Entrance from Options import minecraft_options from ..AutoWorld import World +client_version = (0, 3) class MinecraftWorld(World): game: str = "Minecraft" -client_version = (0, 3) + def _get_mc_data(self): + exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2", + "The End Structure"] + return { + 'world_seed': self.world.slot_seeds[self.player].getrandbits(32), + # consistent and doesn't interfere with other generation + 'seed_name': self.world.seed_name, + 'player_name': self.world.get_player_names(self.player), + 'player_id': self.player, + 'client_version': client_version, + 'structures': {exit: self.world.get_entrance(exit, self.player).connected_region.name for exit in exits} + } -def get_mc_data(world: MultiWorld, player: int): - exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2", - "The End Structure"] - return { - 'world_seed': world.slot_seeds[player].getrandbits(32), - # consistent and doesn't interfere with other generation - 'seed_name': world.seed_name, - 'player_name': world.get_player_names(player), - 'player_id': player, - 'client_version': client_version, - 'structures': {exit: world.get_entrance(exit, player).connected_region.name for exit in exits} - } + def generate_basic(self): + link_minecraft_structures(self.world, self.player) + + pool = [] + for item_name, item_data in item_table.items(): + for count in range(item_frequencies.get(item_name, 1)): + pool.append(MinecraftItem(item_name, item_data.progression, item_data.code, self.player)) + + prefill_pool = {} + prefill_pool.update(events_table) + exclusion_pools = ['hard', 'insane', 'postgame'] + for key in exclusion_pools: + if not getattr(self.world, f"include_{key}_advancements")[self.player]: + prefill_pool.update(exclusion_table[key]) + + for loc_name, item_name in prefill_pool.items(): + item_data = item_table[item_name] + location = self.world.get_location(loc_name, self.player) + item = MinecraftItem(item_name, item_data.progression, item_data.code, self.player) + self.world.push_item(location, item, collect=False) + pool.remove(item) + location.event = item_data.progression + location.locked = True + + self.world.itempool += pool -def generate_mc_data(world: MultiWorld, player: int): - import base64, json - from Utils import output_path - - data = get_mc_data(world, player) - filename = f"AP_{world.seed_name}_P{player}_{world.get_player_names(player)}.apmc" - with open(output_path(filename), 'wb') as f: - f.write(base64.b64encode(bytes(json.dumps(data), 'utf-8'))) + def set_rules(self): + set_rules(self.world, self.player) -def fill_minecraft_slot_data(world: MultiWorld, player: int): - slot_data = get_mc_data(world, player) - for option_name in minecraft_options: - option = getattr(world, option_name)[player] - slot_data[option_name] = int(option.value) - return slot_data + def create_regions(self): + def MCRegion(region_name: str, exits=[]): + ret = Region(region_name, None, region_name, self.player) + ret.world = self.world + ret.locations = [ MinecraftAdvancement(self.player, loc_name, loc_data.id, ret) + for loc_name, loc_data in advancement_table.items() + if loc_data.region == region_name ] + for exit in exits: + ret.exits.append(Entrance(self.player, exit, ret)) + return ret + + self.world.regions += [MCRegion(*r) for r in mc_regions] -# Generates the item pool given the table and frequencies in Items.py. -def minecraft_gen_item_pool(world: MultiWorld, player: int): - pool = [] - for item_name, item_data in item_table.items(): - for count in range(item_frequencies.get(item_name, 1)): - pool.append(MinecraftItem(item_name, item_data.progression, item_data.code, player)) + def generate_output(self): + import base64, json + from Utils import output_path - prefill_pool = {} - prefill_pool.update(events_table) - exclusion_pools = ['hard', 'insane', 'postgame'] - for key in exclusion_pools: - if not getattr(world, f"include_{key}_advancements")[player]: - prefill_pool.update(exclusion_table[key]) - - for loc_name, item_name in prefill_pool.items(): - item_data = item_table[item_name] - location = world.get_location(loc_name, player) - item = MinecraftItem(item_name, item_data.progression, item_data.code, player) - world.push_item(location, item, collect=False) - pool.remove(item) - location.event = item_data.progression - location.locked = True - - world.itempool += pool + data = self._get_mc_data() + filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_names(self.player)}.apmc" + with open(output_path(filename), 'wb') as f: + f.write(base64.b64encode(bytes(json.dumps(data), 'utf-8'))) -# Generate Minecraft world. -def gen_minecraft(world: MultiWorld, player: int): - link_minecraft_structures(world, player) - minecraft_gen_item_pool(world, player) - set_rules(world, player) + def fill_slot_data(self): + slot_data = self._get_mc_data() + for option_name in minecraft_options: + option = getattr(self.world, option_name)[self.player] + slot_data[option_name] = int(option.value) + return slot_data