import unittest from munch import Munch from mosfet.commands import Commands from mosfet.info import blocks, mobs from mosfet.job import JobStates from mosfet.jobs.check_threats import CheckThreatsStates from mosfet.world import World class FakeChunks: def __init__(self, solid=()): self.solid = set(solid) def get_block_at(self, x, y, z): return blocks.STONE if (x, y, z) in self.solid else blocks.AIR class FakeChat: def __init__(self): self.handler = None self.messages = [] def set_handler(self, handler): self.handler = handler def send(self, message): self.messages.append(message) class TestThreatDetection(unittest.TestCase): def test_find_threats_filters_passive_and_distant_entities(self): zombie = mobs.MOBS['minecraft:zombie']['protocol_id'] villager = mobs.MOBS['minecraft:villager']['protocol_id'] world = World(Munch(mobs={ 1: Munch(entity_id=1, type=zombie, x=3.2, y=64, z=0), 2: Munch(entity_id=2, type=villager, x=2, y=64, z=0), 3: Munch(entity_id=3, type=zombie, x=30, y=64, z=0), })) world.check_air_column = lambda pos, distance: True result = world.find_threats((0, 64, 0), 12) self.assertEqual([threat.entity_id for threat in result], [1]) def test_air_column_excludes_mobs_under_a_solid_roof(self): world = World(Munch(chunks=FakeChunks(solid={(0, 67, 0)}))) self.assertFalse(world.check_air_column((0, 64, 0), 5)) self.assertTrue(world.check_air_column((2, 64, 0), 5)) def test_threat_state_falls_back_to_reachable_clear_area(self): spot = (8, 64, 0) class SafeWorld: def find_blocks_indexed(self, center, block_ids, distance=0): return [] def find_bed_areas(self, center, distance): return [spot] def find_threats(self, center, distance): return [] def path_to_place(self, start, target): return [start, target] g = Munch(world=SafeWorld(), pos=(0, 64, 0), path=[], look_at=None) state = CheckThreatsStates(g) state.state = state.find_safety state.threats = [Munch(entity_id=7)] state.find_safety() self.assertEqual(state.state, state.going_to_safety) self.assertEqual(state.safety, spot) self.assertFalse(state.external_safety) self.assertEqual(g.path[-1], spot) g.pos = spot state.going_to_safety() self.assertEqual(state.state, state.wait) self.assertEqual(state.wait_time, 3) def test_loiter_is_enabled_as_a_job(self): check = object() sleep = Munch(silent=False) eat = object() job = JobStates.__new__(JobStates) job.check_threats_states = check job.sleep_with_bed_states = sleep job.eat_food_states = eat self.assertEqual(JobStates.loiter(job), [check, sleep, eat]) self.assertTrue(sleep.silent) def test_loiter_command_is_no_longer_rejected(self): def loiter(): return [] chat = FakeChat() job = Munch(loiter=loiter, state=None) commands = Commands(Munch(name='mosfet1', chat=chat, job=job)) commands.handle_chat(('CHAT', 'player-uuid', 'tanner: 1loiter')) self.assertIs(job.state, loiter) self.assertEqual(chat.messages, ['ok']) if __name__ == '__main__': unittest.main()