Cache after sleep near labeled chests
This commit is contained in:
@@ -3,7 +3,7 @@ import time
|
|||||||
import importlib
|
import importlib
|
||||||
import random
|
import random
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from math import floor
|
from math import ceil, floor
|
||||||
|
|
||||||
from minecraft.networking.types import BlockFace
|
from minecraft.networking.types import BlockFace
|
||||||
|
|
||||||
@@ -19,6 +19,27 @@ class CacheItemsStates:
|
|||||||
def idle(self):
|
def idle(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _has_compatible_labeled_chest_near(self, bed, distance=16):
|
||||||
|
world = self.g.get('world')
|
||||||
|
if world is None:
|
||||||
|
return False
|
||||||
|
keep_slots = self._needed_inventory_slots_to_keep()
|
||||||
|
for chest in world.find_labeled_chests(bed, distance):
|
||||||
|
positions = chest.get('positions') or (chest['position'],)
|
||||||
|
if min(utils.phyp(bed, position) for position in positions) > distance:
|
||||||
|
continue
|
||||||
|
item_ids = chest['item_ids']
|
||||||
|
for slot, item in self.g.inv.items():
|
||||||
|
if (not 9 <= slot <= 44 or not item.present or
|
||||||
|
item.item_id not in item_ids or
|
||||||
|
item.item_id in items.WANTED_ITEMS):
|
||||||
|
continue
|
||||||
|
if (item.item_id in items.NEEDED_ITEMS and
|
||||||
|
slot in keep_slots):
|
||||||
|
continue
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.skip_inventory_slots = set()
|
self.skip_inventory_slots = set()
|
||||||
self.skip_items = []
|
self.skip_items = []
|
||||||
@@ -30,8 +51,15 @@ class CacheItemsStates:
|
|||||||
self.container_item_ids = None
|
self.container_item_ids = None
|
||||||
|
|
||||||
num_stacks = self.g.game.count_inventory_slots()
|
num_stacks = self.g.game.count_inventory_slots()
|
||||||
|
has_override = 'minimum' in self.__dict__
|
||||||
minimum = self.__dict__.pop(
|
minimum = self.__dict__.pop(
|
||||||
'minimum', self.g.get('minimum_cache_slots', 27))
|
'minimum', self.g.get('minimum_cache_slots', 27))
|
||||||
|
post_sleep_bed = self.g.pop('post_sleep_cache_bed', None)
|
||||||
|
if (not has_override and post_sleep_bed is not None and
|
||||||
|
self._has_compatible_labeled_chest_near(post_sleep_bed)):
|
||||||
|
minimum = ceil(minimum / 2)
|
||||||
|
print('Lowering cache threshold after sleep near a compatible chest:',
|
||||||
|
minimum)
|
||||||
print('Inventory amount:', num_stacks)
|
print('Inventory amount:', num_stacks)
|
||||||
if num_stacks == 0:
|
if num_stacks == 0:
|
||||||
self.state = self.cleanup
|
self.state = self.cleanup
|
||||||
|
|||||||
@@ -105,9 +105,10 @@ class GatherCropStates:
|
|||||||
crop, section_size = self._select_crop(candidates, crop_types, p)
|
crop, section_size = self._select_crop(candidates, crop_types, p)
|
||||||
|
|
||||||
if crop is None:
|
if crop is None:
|
||||||
print('No good crops left; retrying after a short wait.')
|
print('No good crops left; running maintenance after {} harvests'.format(
|
||||||
self.retry_after = time.monotonic() + 15.0
|
self.completed_crops))
|
||||||
self.state = self.wait_for_crops
|
self.completed_crops = 0
|
||||||
|
self.state = self.cleanup
|
||||||
return
|
return
|
||||||
|
|
||||||
print('Found crop:', crop,
|
print('Found crop:', crop,
|
||||||
@@ -116,10 +117,6 @@ class GatherCropStates:
|
|||||||
self.type_id = w.block_at(*crop)
|
self.type_id = w.block_at(*crop)
|
||||||
self.state = self.nav_to_crop
|
self.state = self.nav_to_crop
|
||||||
|
|
||||||
def wait_for_crops(self):
|
|
||||||
if time.monotonic() >= self.retry_after:
|
|
||||||
self.state = self.find_new_crop
|
|
||||||
|
|
||||||
def nav_to_crop(self):
|
def nav_to_crop(self):
|
||||||
w = self.g.world
|
w = self.g.world
|
||||||
p = utils.pint(self.g.pos)
|
p = utils.pint(self.g.pos)
|
||||||
@@ -251,7 +248,6 @@ class GatherCropStates:
|
|||||||
self.seed_deadline = None
|
self.seed_deadline = None
|
||||||
self.seed_wait_logged = False
|
self.seed_wait_logged = False
|
||||||
self.active_section_anchor = None
|
self.active_section_anchor = None
|
||||||
self.retry_after = 0.0
|
|
||||||
self.bad_crops = []
|
self.bad_crops = []
|
||||||
self.completed_crops = 0
|
self.completed_crops = 0
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class SleepWithBedStates:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
|
self.sleep_confirmed = False
|
||||||
self.my_bed = False
|
self.my_bed = False
|
||||||
self.area = None
|
self.area = None
|
||||||
self.opening = None
|
self.opening = None
|
||||||
@@ -371,6 +372,8 @@ class SleepWithBedStates:
|
|||||||
return
|
return
|
||||||
self.g.look_at = None
|
self.g.look_at = None
|
||||||
self.g.path = []
|
self.g.path = []
|
||||||
|
if self.sleep_confirmed and self.area is not None:
|
||||||
|
self.g.post_sleep_cache_bed = tuple(self.area)
|
||||||
self.my_bed = False
|
self.my_bed = False
|
||||||
self.force_new_bed = False
|
self.force_new_bed = False
|
||||||
self.state = self.done
|
self.state = self.done
|
||||||
|
|||||||
@@ -46,6 +46,112 @@ class CacheItemsTests(unittest.TestCase):
|
|||||||
finally:
|
finally:
|
||||||
items.WANTED_ITEMS = old_wanted
|
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):
|
def test_manual_cache_threshold_override_is_consumed_once(self):
|
||||||
class FakeGame:
|
class FakeGame:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ class SignWorkTargetTests(unittest.TestCase):
|
|||||||
return crop_state
|
return crop_state
|
||||||
|
|
||||||
state = GatherCropStates(Munch(world=FakeWorld(), pos=(0, 64, 0)))
|
state = GatherCropStates(Munch(world=FakeWorld(), pos=(0, 64, 0)))
|
||||||
|
state.completed_crops = 7
|
||||||
state.find_new_crop()
|
state.find_new_crop()
|
||||||
|
|
||||||
self.assertIs(state.state.__func__, state.wait_for_crops.__func__)
|
self.assertIs(state.state.__func__, state.cleanup.__func__)
|
||||||
|
self.assertEqual(state.completed_crops, 0)
|
||||||
self.assertEqual(state.bad_crops, [])
|
self.assertEqual(state.bad_crops, [])
|
||||||
|
|
||||||
def test_tree_search_skips_out_of_bounds_tree_without_blacklisting_it(self):
|
def test_tree_search_skips_out_of_bounds_tree_without_blacklisting_it(self):
|
||||||
|
|||||||
@@ -52,6 +52,27 @@ class FakeGame:
|
|||||||
|
|
||||||
|
|
||||||
class TestSleepWithBed(unittest.TestCase):
|
class TestSleepWithBed(unittest.TestCase):
|
||||||
|
def test_confirmed_sleep_records_bed_for_following_cache_pass(self):
|
||||||
|
bed = (1, 64, 2)
|
||||||
|
g = Munch(world=FakeWorld(), path=[], look_at=None)
|
||||||
|
state = SleepWithBedStates(g)
|
||||||
|
state.area = bed
|
||||||
|
state.sleep_confirmed = True
|
||||||
|
|
||||||
|
state.cleanup()
|
||||||
|
|
||||||
|
self.assertEqual(g.post_sleep_cache_bed, bed)
|
||||||
|
|
||||||
|
def test_unconfirmed_sleep_does_not_trigger_post_sleep_cache(self):
|
||||||
|
g = Munch(world=FakeWorld(), path=[], look_at=None)
|
||||||
|
state = SleepWithBedStates(g)
|
||||||
|
state.area = (1, 64, 2)
|
||||||
|
state.sleep_confirmed = False
|
||||||
|
|
||||||
|
state.cleanup()
|
||||||
|
|
||||||
|
self.assertNotIn('post_sleep_cache_bed', g)
|
||||||
|
|
||||||
def test_bed_occupancy_only_logs_first_observation_and_changes(self):
|
def test_bed_occupancy_only_logs_first_observation_and_changes(self):
|
||||||
bed_states = [
|
bed_states = [
|
||||||
state for state in blocks.BED_IDS
|
state for state in blocks.BED_IDS
|
||||||
|
|||||||
Reference in New Issue
Block a user