Files
minecraft-bot/tests/test_cache_items.py
T

317 lines
10 KiB
Python

import io
import unittest
from contextlib import redirect_stdout
from munch import Munch
from minecraft.networking.types import BlockFace
from mosfet.info import items
from mosfet.jobs.cache_items import CacheItemsStates
class CacheItemsTests(unittest.TestCase):
def test_chest_search_log_distinguishes_labeled_and_trapped_counts(self):
class FakeWorld:
@staticmethod
def find_labeled_chests(*_args):
return [{} for _ in range(11)]
@staticmethod
def find_blocks_indexed(*_args):
return []
state = CacheItemsStates(Munch(
world=FakeWorld(), pos=(0, 64, 0)))
output = io.StringIO()
with redirect_stdout(output):
state.find_trapped_chests()
self.assertIn(
'Found 11 labeled chests; found 0 trapped chests: []',
output.getvalue())
def test_wanted_single_stack_is_not_considered_transferable(self):
wanted_id = items.WHEAT_SEEDS_ID
old_wanted = items.WANTED_ITEMS
items.WANTED_ITEMS = set(old_wanted) | {wanted_id}
try:
state = CacheItemsStates(Munch(inv={
9: Munch(present=True, item_id=wanted_id, item_count=56),
}))
self.assertFalse(state._has_transferable_item({wanted_id}))
state.g.inv[10] = Munch(
present=True, item_id=wanted_id, item_count=12)
self.assertTrue(state._has_transferable_item({wanted_id}))
finally:
items.WANTED_ITEMS = old_wanted
def test_post_sleep_halves_threshold_only_with_compatible_nearby_chest(self):
bed = (0, 64, 0)
chest_position = (5, 64, 0)
item_id = items.get_id('stone')
class FakeGame:
@staticmethod
def count_inventory_slots():
return 14
class NearbyWorld:
@staticmethod
def find_labeled_chests(_center, _distance):
return [{
'position': chest_position,
'positions': (chest_position,),
'item_ids': {item_id},
}]
g = Munch(
game=FakeGame(), world=NearbyWorld(),
minimum_cache_slots=27, post_sleep_cache_bed=bed,
inv={9: Munch(present=True, item_id=item_id, item_count=64)})
state = CacheItemsStates(g)
state.init()
self.assertIs(state.state.__func__, state.find_trapped_chests.__func__)
self.assertNotIn('post_sleep_cache_bed', g)
def test_post_sleep_threshold_rounds_27_up_to_14(self):
bed = (0, 64, 0)
item_id = items.get_id('stone')
class FakeGame:
@staticmethod
def count_inventory_slots():
return 13
class NearbyWorld:
@staticmethod
def find_labeled_chests(_center, _distance):
return [{
'position': (5, 64, 0),
'positions': ((5, 64, 0),),
'item_ids': {item_id},
}]
g = Munch(
game=FakeGame(), world=NearbyWorld(), minimum_cache_slots=27,
post_sleep_cache_bed=bed,
inv={9: Munch(present=True, item_id=item_id, item_count=64)})
state = CacheItemsStates(g)
state.init()
self.assertIs(state.state.__func__, state.cleanup.__func__)
def test_post_sleep_does_not_lower_threshold_without_compatible_nearby_chest(self):
class FakeGame:
@staticmethod
def count_inventory_slots():
return 14
class EmptyWorld:
@staticmethod
def find_labeled_chests(_center, _distance):
return []
g = Munch(
game=FakeGame(), world=EmptyWorld(), minimum_cache_slots=27,
post_sleep_cache_bed=(0, 64, 0), inv={})
state = CacheItemsStates(g)
state.init()
self.assertIs(state.state.__func__, state.cleanup.__func__)
self.assertNotIn('post_sleep_cache_bed', g)
def test_post_sleep_ignores_compatible_chest_beyond_16_blocks(self):
item_id = items.get_id('stone')
class FakeGame:
@staticmethod
def count_inventory_slots():
return 14
class FarWorld:
@staticmethod
def find_labeled_chests(_center, _distance):
position = (17, 64, 0)
return [{
'position': position,
'positions': (position,),
'item_ids': {item_id},
}]
state = CacheItemsStates(Munch(
game=FakeGame(), world=FarWorld(), minimum_cache_slots=27,
post_sleep_cache_bed=(0, 64, 0),
inv={9: Munch(present=True, item_id=item_id, item_count=64)}))
state.init()
self.assertIs(state.state.__func__, state.cleanup.__func__)
def test_manual_cache_threshold_override_is_consumed_once(self):
class FakeGame:
@staticmethod
def count_inventory_slots():
return 5
state = CacheItemsStates(Munch(
game=FakeGame(), minimum_cache_slots=27))
state.minimum = 0
state.init()
self.assertIs(state.state.__func__, state.find_trapped_chests.__func__)
self.assertNotIn('minimum', state.__dict__)
state.init()
self.assertIs(state.state.__func__, state.cleanup.__func__)
def test_successful_labeled_transfer_skips_placing_another_cache_chest(self):
item_id = items.get_id('stone')
stack = Munch(present=True, item_id=item_id, item_count=16)
window = Munch(container_slots=27, contents={
**dict.fromkeys(range(27)), 27: stack,
})
clicks = []
class FakeGame:
@staticmethod
def count_window_slots():
return 0
@staticmethod
def click_window(*args):
clicks.append(args)
class FakeWorld:
@staticmethod
def find_blocks_indexed(*_args):
return []
@staticmethod
def find_labeled_chests(*_args):
return []
g = Munch(
game=FakeGame(), world=FakeWorld(), pos=(0, 64, 0),
inv={}, window=window, item_lock=False)
state = CacheItemsStates(g)
state.is_labeled_container = True
state.container_item_ids = {item_id}
state.move_items()
self.assertEqual(len(clicks), 1)
self.assertFalse(state.transferred_to_labeled_chest)
window.contents[27] = Munch(present=False, item_id=0, item_count=0)
g.item_lock = False
state.pending_transfer['confirm_after'] = 0
state.move_items()
self.assertTrue(state.transferred_to_labeled_chest)
state.labeled_chests = []
state.trapped_chests = []
state.choose_trapped_chest()
self.assertIs(state.state.__func__, state.cleanup.__func__)
def test_mutually_reachable_opening_is_skipped_after_path_failure(self):
start = (0, 64, 0)
first = (4, 64, 0)
nearby = (4, 64, 1)
item_id = items.get_id('stone')
calls = []
class FakeWorld:
@staticmethod
def find_cache_openings(area, _center):
position = first if area == (10, 64, 0) else nearby
return [{'position': position}]
def path_to_place(self, origin, target):
origin, target = tuple(origin), tuple(target)
calls.append((origin, target))
if origin == start and target == first:
return None
if (origin, target) in ((nearby, first), (first, nearby)):
return [origin, target]
return None
state = CacheItemsStates(Munch(
world=FakeWorld(), pos=start,
inv={9: Munch(present=True, item_id=item_id)}))
state.labeled_chests = [
{'position': (10, 64, 0), 'positions': ((10, 64, 0),),
'item_ids': {item_id}, 'labels': {'Stone'}},
{'position': (11, 64, 0), 'positions': ((11, 64, 0),),
'item_ids': {item_id}, 'labels': {'Stone'}},
]
state.trapped_chests = []
state.choose_trapped_chest()
self.assertEqual(calls, [
(start, first), (nearby, first), (first, nearby),
])
self.assertIn(first, state.bad_openings)
self.assertIn(nearby, state.bad_openings)
def test_one_way_reachability_does_not_blacklist_opening(self):
bad = (1, 64, 0)
candidate = (2, 64, 0)
class FakeWorld:
@staticmethod
def path_to_place(start, target):
return [start, target] if tuple(start) == candidate else None
state = CacheItemsStates(Munch())
state.bad_openings = {bad}
self.assertFalse(state._opening_in_bad_region(FakeWorld(), candidate))
self.assertNotIn(candidate, state.bad_openings)
def test_cache_travel_looks_along_path_then_turns_to_chest(self):
opening = (5, 64, 8)
chest_look = (4.9, 64.1, 7.8)
state = CacheItemsStates(Munch(
pos=(2.5, 64, 2.5), look_at=(1, 64, 1)))
state.opening = opening
state.open_interaction = {'look_at': chest_look}
state.going_to_trapped_chest()
self.assertIsNone(state.g.look_at)
state.g.pos = opening
state.going_to_trapped_chest()
self.assertEqual(state.g.look_at, chest_look)
self.assertIs(state.state.__func__, state.turn_to_trapped_chest.__func__)
state.g.pos = (2.5, 64, 2.5)
state.g.look_at = (1, 64, 1)
state.going_to_area()
self.assertIsNone(state.g.look_at)
def test_cache_chest_placement_sneaks_to_avoid_opening_support_container(self):
calls = []
class FakeGame:
@staticmethod
def place_block(*args, **kwargs):
calls.append((args, kwargs))
state = CacheItemsStates(Munch(game=FakeGame()))
state.area = (3, 65, 7)
state.place_chest()
self.assertEqual(calls, [(
((3, 64, 7), BlockFace.TOP), {'sneaking': True},
)])
self.assertIs(state.state.__func__, state.open_chest.__func__)
if __name__ == '__main__':
unittest.main()