diff --git a/BaseClasses.py b/BaseClasses.py index 2be9a982..446eea5b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -85,7 +85,7 @@ class MultiWorld(): game: Dict[int, str] random: random.Random - per_slot_randoms: Dict[int, random.Random] + per_slot_randoms: Utils.DeprecateDict[int, random.Random] """Deprecated. Please use `self.random` instead.""" class AttributeProxy(): @@ -217,7 +217,8 @@ class MultiWorld(): set_player_attr('game', "A Link to the Past") set_player_attr('completion_condition', lambda state: True) self.worlds = {} - self.per_slot_randoms = {} + self.per_slot_randoms = Utils.DeprecateDict("Using per_slot_randoms is now deprecated. Please use the " + "world's random object instead (usually self.random)") self.plando_options = PlandoOptions.none def get_all_ids(self) -> Tuple[int, ...]: @@ -251,14 +252,13 @@ class MultiWorld(): return {group_id for group_id, group in self.groups.items() if player in group["players"]} def set_seed(self, seed: Optional[int] = None, secure: bool = False, name: Optional[str] = None): + assert not self.worlds, "seed needs to be initialized before Worlds" self.seed = get_seed(seed) if secure: self.secure() else: self.random.seed(self.seed) self.seed_name = name if name else str(self.seed) - self.per_slot_randoms = {player: random.Random(self.random.getrandbits(64)) for player in - range(1, self.players + 1)} def set_options(self, args: Namespace) -> None: # TODO - remove this section once all worlds use options dataclasses @@ -275,7 +275,6 @@ class MultiWorld(): for player in self.player_ids: world_type = AutoWorld.AutoWorldRegister.world_types[self.game[player]] self.worlds[player] = world_type(self, player) - self.worlds[player].random = self.per_slot_randoms[player] options_dataclass: typing.Type[Options.PerGameCommonOptions] = world_type.options_dataclass self.worlds[player].options = options_dataclass(**{option_key: getattr(args, option_key)[player] for option_key in options_dataclass.type_hints}) diff --git a/test/general/__init__.py b/test/general/__init__.py index 5e0f22f4..2819628d 100644 --- a/test/general/__init__.py +++ b/test/general/__init__.py @@ -1,5 +1,5 @@ from argparse import Namespace -from typing import Type, Tuple +from typing import Optional, Tuple, Type from BaseClasses import MultiWorld, CollectionState from worlds.AutoWorld import call_all, World @@ -7,18 +7,21 @@ from worlds.AutoWorld import call_all, World gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "generate_basic", "pre_fill") -def setup_solo_multiworld(world_type: Type[World], steps: Tuple[str, ...] = gen_steps) -> MultiWorld: +def setup_solo_multiworld( + world_type: Type[World], steps: Tuple[str, ...] = gen_steps, seed: Optional[int] = None +) -> MultiWorld: """ Creates a multiworld with a single player of `world_type`, sets default options, and calls provided gen steps. :param world_type: Type of the world to generate a multiworld for :param steps: The gen steps that should be called on the generated multiworld before returning. Default calls steps through pre_fill + :param seed: The seed to be used when creating this multiworld """ multiworld = MultiWorld(1) multiworld.game[1] = world_type.game multiworld.player_name = {1: "Tester"} - multiworld.set_seed() + multiworld.set_seed(seed) multiworld.state = CollectionState(multiworld) args = Namespace() for name, option in world_type.options_dataclass.type_hints.items(): diff --git a/test/general/test_fill.py b/test/general/test_fill.py index 48941777..70e9e822 100644 --- a/test/general/test_fill.py +++ b/test/general/test_fill.py @@ -13,6 +13,7 @@ from worlds.generic.Rules import CollectionRule, add_item_rule, locality_rules, def generate_multiworld(players: int = 1) -> MultiWorld: multiworld = MultiWorld(players) + multiworld.set_seed(0) multiworld.player_name = {} multiworld.state = CollectionState(multiworld) for i in range(players): @@ -32,8 +33,6 @@ def generate_multiworld(players: int = 1) -> MultiWorld: world.options = world.options_dataclass(**{option_key: getattr(multiworld, option_key)[player_id] for option_key in world.options_dataclass.type_hints}) - multiworld.set_seed(0) - return multiworld diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index 93e4a5c3..4d9b31d1 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -3,6 +3,7 @@ from __future__ import annotations import hashlib import logging import pathlib +import random import re import sys import time @@ -299,6 +300,8 @@ class World(metaclass=AutoWorldRegister): assert multiworld is not None self.multiworld = multiworld self.player = player + self.random = random.Random(multiworld.random.getrandbits(64)) + multiworld.per_slot_randoms[player] = self.random def __getattr__(self, item: str) -> Any: if item == "settings": diff --git a/worlds/dlcquest/test/__init__.py b/worlds/dlcquest/test/__init__.py index e998bd8a..8a39b43a 100644 --- a/worlds/dlcquest/test/__init__.py +++ b/worlds/dlcquest/test/__init__.py @@ -37,8 +37,7 @@ def setup_dlc_quest_solo_multiworld(test_options=None, seed=None, _cache: Dict[F if frozen_options in _cache: return _cache[frozen_options] - multiworld = setup_base_solo_multiworld(DLCqworld, ()) - multiworld.set_seed(seed) + multiworld = setup_base_solo_multiworld(DLCqworld, (), seed=seed) # print(f"Seed: {multiworld.seed}") # Uncomment to print the seed for every test args = Namespace() for name, option in DLCqworld.options_dataclass.type_hints.items(): diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ba037f7a..948fb83b 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -124,8 +124,7 @@ def setup_solo_multiworld(test_options=None, seed=None, if frozen_options in _cache: return _cache[frozen_options] - multiworld = setup_base_solo_multiworld(StardewValleyWorld, ()) - multiworld.set_seed(seed) + multiworld = setup_base_solo_multiworld(StardewValleyWorld, (), seed=seed) # print(f"Seed: {multiworld.seed}") # Uncomment to print the seed for every test args = Namespace() for name, option in StardewValleyWorld.options_dataclass.type_hints.items():