| 
									
										
										
										
											2021-07-22 01:08:44 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2021-07-12 13:54:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Minecraft Randomizer
Squash merge, original Commits:
* Minecraft locations, items, and generation without logic
* added id lookup for minecraft
* typing import fix in minecraft/Items.py
* fix 2
* implementing Minecraft options and hard/postgame advancement exclusion
* first logic pass (75/80)
* logic pass 2 and proper completion conditions
* added insane difficulty pool, modified method of excluding item pools for easier extension
* bump network_data_package version
* minecraft testing framework
* switch Ancient Debris to Netherite Scrap to avoid advancement triggering on receiving that item
* Testing now functions, split tests up by advancement pane, added some story tests
* Newer testing framework: every advancement gets its own function, for ease of testing
* fixed logic for The End... Again...
* changed option names to "include_hard_advancements" etc.
* village/pillager-related advancements now require can_adventure: weapon + food
* a few minecraft tests
* rename "Flint & Steel" to "Flint and Steel" for parity with in-game name
* additional MC tests
* more tests, mostly nether-related tests
* more tests, removed anvil path for Two Birds One Arrow
* include Minecraft slot data, and a world seed for each Minecraft player slot
* Added new items: ender pearls, lapis, porkchops
* All remaining Minecraft tests
* formatting of Minecraft tests and logic for better readability
* require Wither kill for Monsters Hunted
* properly removed 8 Emeralds item from item pool
* enchanting required for wither; fishing rod required for water breathing; water breathing required for elder guardian kill
* Added 12 new advancements (ported from old achievement system)
* renamed "On a Rail" for consistency with modern advancements
* tests for the new advancements
* moved slot_data generation for minecraft into worlds/minecraft/__init__.py, added logic_version to slot_data
* output minecraft options in the spoiler log
* modified advancement goal values for new advancements
* make non-native Minecraft items appear as Shovel in ALttP, and unknown-game items as Power Stars
* fixed glowstone block logic for Not Quite Nine Lives
* setup for shuffling MC structures: building ER world and shuffling regions/entrances
* ensured Nether Fortresses can't be placed in the End
* finished logic for structure randomization
* fixed nonnative items always showing up as Hammers in ALttP shops
* output minecraft structure info in the spoiler
* generate .apmc file for communication with MC client
* fixed structure rando always using the same seed
* move stuff to worlds/minecraft/Regions.py
* make output apmc file have consistent name with other files
* added minecraft bottle macro; fixed tests imports
* generalizing MC region generation
* restructured structure shuffling in preparation for structure plando
* only output structure rando info in spoiler if they are shuffled
* Force structure rando to always be off, for the stable release
* added Minecraft options to player settings
* formally added combat_difficulty as an option
* Added Ender Dragon into playthrough, cleaned up goal map
* Added new difficulties: Easy, Normal, Hard combat
* moved .apmc generation time to prevent outputs on failed generation
* updated tests for new combat logic
* Fixed bug causing generation to fail; removed Nether Fortress event since it should no longer be needed with the fix
* moved all MC-specific functions into gen_minecraft
* renamed "logic_version" to "client_version"
* bug fixes
properly flagged event locations/items with id None
moved generation back to Main.py to fix mysterious generation failures
* moved link_minecraft_regions into minecraft init, left create_regions in Main for caching
* added seed_name, player_name, client_version to apmc file
* reenabled structure shuffle
* added entrance tests for minecraft
Co-authored-by: achuang <alexander.w.chuang@gmail.com>
											
										 
											2021-05-08 07:38:57 -04:00
										 |  |  | from .Items import MinecraftItem, item_table, item_frequencies | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | from .Locations import MinecraftAdvancement, advancement_table, exclusion_table, events_table | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  | from .Regions import mc_regions, link_minecraft_structures, default_connections | 
					
						
							| 
									
										
											  
											
												Minecraft Randomizer
Squash merge, original Commits:
* Minecraft locations, items, and generation without logic
* added id lookup for minecraft
* typing import fix in minecraft/Items.py
* fix 2
* implementing Minecraft options and hard/postgame advancement exclusion
* first logic pass (75/80)
* logic pass 2 and proper completion conditions
* added insane difficulty pool, modified method of excluding item pools for easier extension
* bump network_data_package version
* minecraft testing framework
* switch Ancient Debris to Netherite Scrap to avoid advancement triggering on receiving that item
* Testing now functions, split tests up by advancement pane, added some story tests
* Newer testing framework: every advancement gets its own function, for ease of testing
* fixed logic for The End... Again...
* changed option names to "include_hard_advancements" etc.
* village/pillager-related advancements now require can_adventure: weapon + food
* a few minecraft tests
* rename "Flint & Steel" to "Flint and Steel" for parity with in-game name
* additional MC tests
* more tests, mostly nether-related tests
* more tests, removed anvil path for Two Birds One Arrow
* include Minecraft slot data, and a world seed for each Minecraft player slot
* Added new items: ender pearls, lapis, porkchops
* All remaining Minecraft tests
* formatting of Minecraft tests and logic for better readability
* require Wither kill for Monsters Hunted
* properly removed 8 Emeralds item from item pool
* enchanting required for wither; fishing rod required for water breathing; water breathing required for elder guardian kill
* Added 12 new advancements (ported from old achievement system)
* renamed "On a Rail" for consistency with modern advancements
* tests for the new advancements
* moved slot_data generation for minecraft into worlds/minecraft/__init__.py, added logic_version to slot_data
* output minecraft options in the spoiler log
* modified advancement goal values for new advancements
* make non-native Minecraft items appear as Shovel in ALttP, and unknown-game items as Power Stars
* fixed glowstone block logic for Not Quite Nine Lives
* setup for shuffling MC structures: building ER world and shuffling regions/entrances
* ensured Nether Fortresses can't be placed in the End
* finished logic for structure randomization
* fixed nonnative items always showing up as Hammers in ALttP shops
* output minecraft structure info in the spoiler
* generate .apmc file for communication with MC client
* fixed structure rando always using the same seed
* move stuff to worlds/minecraft/Regions.py
* make output apmc file have consistent name with other files
* added minecraft bottle macro; fixed tests imports
* generalizing MC region generation
* restructured structure shuffling in preparation for structure plando
* only output structure rando info in spoiler if they are shuffled
* Force structure rando to always be off, for the stable release
* added Minecraft options to player settings
* formally added combat_difficulty as an option
* Added Ender Dragon into playthrough, cleaned up goal map
* Added new difficulties: Easy, Normal, Hard combat
* moved .apmc generation time to prevent outputs on failed generation
* updated tests for new combat logic
* Fixed bug causing generation to fail; removed Nether Fortress event since it should no longer be needed with the fix
* moved all MC-specific functions into gen_minecraft
* renamed "logic_version" to "client_version"
* bug fixes
properly flagged event locations/items with id None
moved generation back to Main.py to fix mysterious generation failures
* moved link_minecraft_regions into minecraft init, left create_regions in Main for caching
* added seed_name, player_name, client_version to apmc file
* reenabled structure shuffle
* added entrance tests for minecraft
Co-authored-by: achuang <alexander.w.chuang@gmail.com>
											
										 
											2021-05-08 07:38:57 -04:00
										 |  |  | from .Rules import set_rules | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  | from worlds.generic.Rules import exclusion_rules | 
					
						
							| 
									
										
											  
											
												Minecraft Randomizer
Squash merge, original Commits:
* Minecraft locations, items, and generation without logic
* added id lookup for minecraft
* typing import fix in minecraft/Items.py
* fix 2
* implementing Minecraft options and hard/postgame advancement exclusion
* first logic pass (75/80)
* logic pass 2 and proper completion conditions
* added insane difficulty pool, modified method of excluding item pools for easier extension
* bump network_data_package version
* minecraft testing framework
* switch Ancient Debris to Netherite Scrap to avoid advancement triggering on receiving that item
* Testing now functions, split tests up by advancement pane, added some story tests
* Newer testing framework: every advancement gets its own function, for ease of testing
* fixed logic for The End... Again...
* changed option names to "include_hard_advancements" etc.
* village/pillager-related advancements now require can_adventure: weapon + food
* a few minecraft tests
* rename "Flint & Steel" to "Flint and Steel" for parity with in-game name
* additional MC tests
* more tests, mostly nether-related tests
* more tests, removed anvil path for Two Birds One Arrow
* include Minecraft slot data, and a world seed for each Minecraft player slot
* Added new items: ender pearls, lapis, porkchops
* All remaining Minecraft tests
* formatting of Minecraft tests and logic for better readability
* require Wither kill for Monsters Hunted
* properly removed 8 Emeralds item from item pool
* enchanting required for wither; fishing rod required for water breathing; water breathing required for elder guardian kill
* Added 12 new advancements (ported from old achievement system)
* renamed "On a Rail" for consistency with modern advancements
* tests for the new advancements
* moved slot_data generation for minecraft into worlds/minecraft/__init__.py, added logic_version to slot_data
* output minecraft options in the spoiler log
* modified advancement goal values for new advancements
* make non-native Minecraft items appear as Shovel in ALttP, and unknown-game items as Power Stars
* fixed glowstone block logic for Not Quite Nine Lives
* setup for shuffling MC structures: building ER world and shuffling regions/entrances
* ensured Nether Fortresses can't be placed in the End
* finished logic for structure randomization
* fixed nonnative items always showing up as Hammers in ALttP shops
* output minecraft structure info in the spoiler
* generate .apmc file for communication with MC client
* fixed structure rando always using the same seed
* move stuff to worlds/minecraft/Regions.py
* make output apmc file have consistent name with other files
* added minecraft bottle macro; fixed tests imports
* generalizing MC region generation
* restructured structure shuffling in preparation for structure plando
* only output structure rando info in spoiler if they are shuffled
* Force structure rando to always be off, for the stable release
* added Minecraft options to player settings
* formally added combat_difficulty as an option
* Added Ender Dragon into playthrough, cleaned up goal map
* Added new difficulties: Easy, Normal, Hard combat
* moved .apmc generation time to prevent outputs on failed generation
* updated tests for new combat logic
* Fixed bug causing generation to fail; removed Nether Fortress event since it should no longer be needed with the fix
* moved all MC-specific functions into gen_minecraft
* renamed "logic_version" to "client_version"
* bug fixes
properly flagged event locations/items with id None
moved generation back to Main.py to fix mysterious generation failures
* moved link_minecraft_regions into minecraft init, left create_regions in Main for caching
* added seed_name, player_name, client_version to apmc file
* reenabled structure shuffle
* added entrance tests for minecraft
Co-authored-by: achuang <alexander.w.chuang@gmail.com>
											
										 
											2021-05-08 07:38:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-12 13:54:47 +02:00
										 |  |  | from BaseClasses import Region, Entrance, Item | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | from .Options import minecraft_options | 
					
						
							| 
									
										
										
										
											2021-06-11 14:22:44 +02:00
										 |  |  | from ..AutoWorld import World | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  | client_version = 5 | 
					
						
							| 
									
										
										
										
											2021-06-11 14:22:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class MinecraftWorld(World): | 
					
						
							|  |  |  |     game: str = "Minecraft" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     options = minecraft_options | 
					
						
							| 
									
										
										
										
											2021-07-08 11:07:41 +02:00
										 |  |  |     topology_present = True | 
					
						
							| 
									
										
											  
											
												Minecraft Randomizer
Squash merge, original Commits:
* Minecraft locations, items, and generation without logic
* added id lookup for minecraft
* typing import fix in minecraft/Items.py
* fix 2
* implementing Minecraft options and hard/postgame advancement exclusion
* first logic pass (75/80)
* logic pass 2 and proper completion conditions
* added insane difficulty pool, modified method of excluding item pools for easier extension
* bump network_data_package version
* minecraft testing framework
* switch Ancient Debris to Netherite Scrap to avoid advancement triggering on receiving that item
* Testing now functions, split tests up by advancement pane, added some story tests
* Newer testing framework: every advancement gets its own function, for ease of testing
* fixed logic for The End... Again...
* changed option names to "include_hard_advancements" etc.
* village/pillager-related advancements now require can_adventure: weapon + food
* a few minecraft tests
* rename "Flint & Steel" to "Flint and Steel" for parity with in-game name
* additional MC tests
* more tests, mostly nether-related tests
* more tests, removed anvil path for Two Birds One Arrow
* include Minecraft slot data, and a world seed for each Minecraft player slot
* Added new items: ender pearls, lapis, porkchops
* All remaining Minecraft tests
* formatting of Minecraft tests and logic for better readability
* require Wither kill for Monsters Hunted
* properly removed 8 Emeralds item from item pool
* enchanting required for wither; fishing rod required for water breathing; water breathing required for elder guardian kill
* Added 12 new advancements (ported from old achievement system)
* renamed "On a Rail" for consistency with modern advancements
* tests for the new advancements
* moved slot_data generation for minecraft into worlds/minecraft/__init__.py, added logic_version to slot_data
* output minecraft options in the spoiler log
* modified advancement goal values for new advancements
* make non-native Minecraft items appear as Shovel in ALttP, and unknown-game items as Power Stars
* fixed glowstone block logic for Not Quite Nine Lives
* setup for shuffling MC structures: building ER world and shuffling regions/entrances
* ensured Nether Fortresses can't be placed in the End
* finished logic for structure randomization
* fixed nonnative items always showing up as Hammers in ALttP shops
* output minecraft structure info in the spoiler
* generate .apmc file for communication with MC client
* fixed structure rando always using the same seed
* move stuff to worlds/minecraft/Regions.py
* make output apmc file have consistent name with other files
* added minecraft bottle macro; fixed tests imports
* generalizing MC region generation
* restructured structure shuffling in preparation for structure plando
* only output structure rando info in spoiler if they are shuffled
* Force structure rando to always be off, for the stable release
* added Minecraft options to player settings
* formally added combat_difficulty as an option
* Added Ender Dragon into playthrough, cleaned up goal map
* Added new difficulties: Easy, Normal, Hard combat
* moved .apmc generation time to prevent outputs on failed generation
* updated tests for new combat logic
* Fixed bug causing generation to fail; removed Nether Fortress event since it should no longer be needed with the fix
* moved all MC-specific functions into gen_minecraft
* renamed "logic_version" to "client_version"
* bug fixes
properly flagged event locations/items with id None
moved generation back to Main.py to fix mysterious generation failures
* moved link_minecraft_regions into minecraft init, left create_regions in Main for caching
* added seed_name, player_name, client_version to apmc file
* reenabled structure shuffle
* added entrance tests for minecraft
Co-authored-by: achuang <alexander.w.chuang@gmail.com>
											
										 
											2021-05-08 07:38:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-12 18:05:46 +02:00
										 |  |  |     item_name_to_id = {name: data.code for name, data in item_table.items()} | 
					
						
							|  |  |  |     location_name_to_id = {name: data.id for name, data in advancement_table.items()} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  |     data_version = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  |     def _get_mc_data(self): | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  |         exits = [connection[0] for connection in default_connections] | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  |         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, | 
					
						
							| 
									
										
										
										
											2021-07-20 14:16:40 -04:00
										 |  |  |             'structures': {exit: self.world.get_entrance(exit, self.player).connected_region.name for exit in exits}, | 
					
						
							|  |  |  |             'race': self.world.is_race | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def generate_basic(self): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  |         # Generate item pool | 
					
						
							|  |  |  |         itempool = [] | 
					
						
							| 
									
										
										
										
											2021-07-02 16:50:31 -05:00
										 |  |  |         pool_counts = item_frequencies.copy() | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  |         # Replace Rotten Flesh with bee traps | 
					
						
							|  |  |  |         if self.world.bee_traps[self.player]: | 
					
						
							| 
									
										
										
										
											2021-07-02 16:50:31 -05:00
										 |  |  |             pool_counts.update({"Rotten Flesh": 0, "Bee Trap (Minecraft)": 4}) | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  |         # Add structure compasses to the pool, replacing 50 XP | 
					
						
							|  |  |  |         if self.world.structure_compasses[self.player]: | 
					
						
							|  |  |  |             structures = [connection[1] for connection in default_connections] | 
					
						
							|  |  |  |             for struct_name in structures: | 
					
						
							|  |  |  |                 pool_counts[f"Structure Compass ({struct_name})"] = 1 | 
					
						
							|  |  |  |                 pool_counts["50 XP"] -= 1 | 
					
						
							| 
									
										
										
										
											2021-07-12 13:54:47 +02:00
										 |  |  |         for item_name in item_table: | 
					
						
							| 
									
										
										
										
											2021-07-02 16:50:31 -05:00
										 |  |  |             for count in range(pool_counts.get(item_name, 1)): | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  |                 itempool.append(self.create_item(item_name)) | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  |         # Choose locations to automatically exclude based on settings | 
					
						
							|  |  |  |         exclusion_pool = set() | 
					
						
							|  |  |  |         exclusion_types = ['hard', 'insane', 'postgame'] | 
					
						
							|  |  |  |         for key in exclusion_types: | 
					
						
							| 
									
										
										
										
											2021-07-02 20:27:41 -05:00
										 |  |  |             if not getattr(self.world, f"include_{key}_advancements")[self.player]: | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  |                 exclusion_pool.update(exclusion_table[key]) | 
					
						
							|  |  |  |         exclusion_rules(self.world, self.player, exclusion_pool) | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 08:42:55 -05:00
										 |  |  |         # Prefill the Ender Dragon with the completion condition | 
					
						
							|  |  |  |         completion = self.create_item("Victory") | 
					
						
							|  |  |  |         self.world.get_location("Ender Dragon", self.player).place_locked_item(completion) | 
					
						
							|  |  |  |         itempool.remove(completion) | 
					
						
							|  |  |  |         self.world.itempool += itempool | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def set_rules(self): | 
					
						
							|  |  |  |         set_rules(self.world, self.player) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_regions(self): | 
					
						
							|  |  |  |         def MCRegion(region_name: str, exits=[]): | 
					
						
							| 
									
										
										
										
											2021-07-16 12:23:05 +02:00
										 |  |  |             ret = Region(region_name, None, region_name, self.player, self.world) | 
					
						
							|  |  |  |             ret.locations = [MinecraftAdvancement(self.player, loc_name, loc_data.id, ret) | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  |                 for loc_name, loc_data in advancement_table.items()  | 
					
						
							| 
									
										
										
										
											2021-07-16 12:23:05 +02:00
										 |  |  |                 if loc_data.region == region_name] | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  |             for exit in exits:  | 
					
						
							|  |  |  |                 ret.exits.append(Entrance(self.player, exit, ret)) | 
					
						
							|  |  |  |             return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.world.regions += [MCRegion(*r) for r in mc_regions] | 
					
						
							| 
									
										
										
										
											2021-07-14 19:13:25 -05:00
										 |  |  |         link_minecraft_structures(self.world, self.player) | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-21 18:08:15 +02:00
										 |  |  |     def generate_output(self, output_directory: str): | 
					
						
							| 
									
										
										
										
											2021-06-15 18:22:12 -05:00
										 |  |  |         import json | 
					
						
							|  |  |  |         from base64 import b64encode | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         data = self._get_mc_data() | 
					
						
							|  |  |  |         filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_names(self.player)}.apmc" | 
					
						
							| 
									
										
										
										
											2021-07-22 01:08:44 +02:00
										 |  |  |         with open(os.path.join(output_directory, filename), 'wb') as f: | 
					
						
							| 
									
										
										
										
											2021-06-15 18:22:12 -05:00
										 |  |  |             f.write(b64encode(bytes(json.dumps(data), 'utf-8'))) | 
					
						
							| 
									
										
										
										
											2021-06-15 18:15:05 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2021-07-12 13:54:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def create_item(self, name: str) -> Item: | 
					
						
							|  |  |  |         item_data = item_table[name] | 
					
						
							| 
									
										
										
										
											2021-07-15 08:46:07 -05:00
										 |  |  |         item = MinecraftItem(name, item_data.progression, item_data.code, self.player) | 
					
						
							| 
									
										
										
										
											2021-07-23 19:28:16 -04:00
										 |  |  |         nonexcluded_items = ["Sharpness III Book", "Infinity Book", "Looting III Book"] | 
					
						
							|  |  |  |         if name in nonexcluded_items:  # prevent books from going on excluded locations | 
					
						
							| 
									
										
										
										
											2021-07-23 08:55:44 -05:00
										 |  |  |             item.never_exclude = True | 
					
						
							| 
									
										
										
										
											2021-07-15 08:46:07 -05:00
										 |  |  |         return item |