From 09035793e29b611d95c7331b5a2c5437b2bdc40f Mon Sep 17 00:00:00 2001 From: Tanner Date: Thu, 5 Nov 2026 23:37:10 +0000 Subject: [PATCH] Batch crop farming and stop on unreachable barrels --- mosfet/job.py | 1 + mosfet/jobs/gather_crop.py | 12 +++++++++++- mosfet/jobs/grab_supplies.py | 8 ++------ tests/test_crop_batch.py | 35 +++++++++++++++++++++++++++++++++++ tests/test_grab_supplies.py | 14 ++++++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 tests/test_crop_batch.py diff --git a/mosfet/job.py b/mosfet/job.py index e9085a1..b6676cd 100644 --- a/mosfet/job.py +++ b/mosfet/job.py @@ -355,4 +355,5 @@ class JobStates(LegacyJobStates): self.check_threats_states.safety = None self.check_threats_states.external_safety = False self.gather_crop_states.active_section_anchor = None + self.gather_crop_states.completed_crops = 0 self.state = self.idle diff --git a/mosfet/jobs/gather_crop.py b/mosfet/jobs/gather_crop.py index 3f7d220..3b3bc2c 100644 --- a/mosfet/jobs/gather_crop.py +++ b/mosfet/jobs/gather_crop.py @@ -17,6 +17,8 @@ from mosfet.info import mcdata from mosfet.info import mobs class GatherCropStates: + CROPS_PER_BATCH = 16 + def idle(self): return None @@ -216,7 +218,14 @@ class GatherCropStates: blocks.BLOCKS.get(current_state) == crop_name and current_state != self.type_id) if replanted: - self.state = self.cleanup + self.completed_crops += 1 + if self.completed_crops >= self.CROPS_PER_BATCH: + print('Completed {} crop harvests; running maintenance'.format( + self.completed_crops)) + self.completed_crops = 0 + self.state = self.cleanup + else: + self.state = self.find_new_crop elif time.time() > getattr(self, 'place_deadline', 0): print('Crop did not replant; blacklisting', self.crop) self.bad_crops.append(self.crop) @@ -242,6 +251,7 @@ class GatherCropStates: self.active_section_anchor = None self.retry_after = 0.0 self.bad_crops = [] + self.completed_crops = 0 def run(self): self.state() diff --git a/mosfet/jobs/grab_supplies.py b/mosfet/jobs/grab_supplies.py index b73fc88..b3facdd 100644 --- a/mosfet/jobs/grab_supplies.py +++ b/mosfet/jobs/grab_supplies.py @@ -242,13 +242,9 @@ class GrabSuppliesStates: self.checked_supplies = [] return else: - print('No path, blacklisting barrel') - time.sleep(0.1) + print('Barrel is unreachable; ending supply task') self.bad_barrels.append(self.barrel) - if len(self.bad_barrels) > 3: - self.state = self.cleanup - else: - self.state = self.choose_barrel + self.state = self.cleanup def going_to_barrel(self): if utils.pint(self.g.pos) == self.opening: diff --git a/tests/test_crop_batch.py b/tests/test_crop_batch.py new file mode 100644 index 0000000..96f3b5e --- /dev/null +++ b/tests/test_crop_batch.py @@ -0,0 +1,35 @@ +import unittest +from munch import Munch + +from mosfet.info import blocks +from mosfet.jobs.gather_crop import GatherCropStates + + +class CropBatchTests(unittest.TestCase): + def test_gather_crop_finishes_after_sixteen_successful_replants(self): + unripe_wheat = blocks.MCD_BLOCKS['wheat']['minStateId'] + mature_wheat = blocks.MATURE_WHEAT_ID + self.assertNotEqual(unripe_wheat, mature_wheat) + + class FakeWorld: + @staticmethod + def block_at(*_position): + return unripe_wheat + + state = GatherCropStates(Munch(world=FakeWorld())) + state.crop = (1, 64, 1) + state.type_id = mature_wheat + + for completed in range(1, state.CROPS_PER_BATCH): + state.wait_place() + self.assertEqual(state.completed_crops, completed) + self.assertIs(state.state.__func__, state.find_new_crop.__func__) + state.state = state.wait_place + + state.wait_place() + self.assertEqual(state.completed_crops, 0) + self.assertIs(state.state.__func__, state.cleanup.__func__) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_grab_supplies.py b/tests/test_grab_supplies.py index c21710d..3f27350 100644 --- a/tests/test_grab_supplies.py +++ b/tests/test_grab_supplies.py @@ -44,6 +44,20 @@ class GroundSupplyTests(unittest.TestCase): self.assertEqual(state.target_items, (items.CHEST_ID,)) self.assertIs(state.state.__func__, state.find_ground_items.__func__) + def test_unreachable_barrel_ends_supply_task_without_trying_more(self): + class FakeWorld: + @staticmethod + def path_to_place_faked(_start, _barrel): + return None + + state = GrabSuppliesStates(Munch( + pos=(0.5, 64.0, 0.5), world=FakeWorld(), chunks=Munch())) + state.barrel = (10, 64, 10) + state.path_to_barrel() + + self.assertIs(state.state.__func__, state.cleanup.__func__) + self.assertEqual(state.bad_barrels, [(10, 64, 10)]) + def test_job_walks_to_and_picks_up_dropped_supply_before_barrels(self): axe_id = next(iter(items.AXE_IDS)) dropped_axe = Munch(