import unittest from unittest.mock import patch from munch import Munch from mosfet.commands import Commands from mosfet.info import blocks from mosfet.protocol.managers import EntityManager, WorldState from mosfet.world import World class SignReadingTests(unittest.TestCase): def test_world_decodes_front_and_back_sign_components(self): chunks = Munch(block_entities={ (2, 64, 3): { 'type': 7, 'data': { 'front_text': {'messages': [ '{"text":"Hello","extra":[{"text":" world"}]}', '{"text":"line two"}', '', ''], }, 'back_text': {'messages': [ '{"text":"back"}', '', '', ''], }, }, }, }) signs = World(Munch(chunks=chunks)).find_signs((0, 64, 0), 10) self.assertEqual(signs, [ {'position': (2, 64, 3), 'side': 'front', 'lines': ('Hello world', 'line two', '', '')}, {'position': (2, 64, 3), 'side': 'back', 'lines': ('back', '', '', '')}, ]) def test_block_entity_update_is_cached_for_sign_search(self): chunks = WorldState() manager = object.__new__(EntityManager) manager.g = Munch(chunks=chunks) manager.handle_block_entity_data(Munch( location=Munch(x=4, y=65, z=-2), block_entity_type=7, data={'front_text': {'messages': ['{"text":"Farm"}', '', '', '']}}, )) signs = World(Munch(chunks=chunks)).find_signs((4, 65, -2), 1) self.assertEqual(signs[0]['lines'], ('Farm', '', '', '')) def test_broken_sign_block_update_removes_cached_sign_entity(self): position = (4, 65, -2) sign_state = blocks.MCD_BLOCKS['oak_wall_sign']['minStateId'] class FakeColumn: def __init__(self): self.states = {} def get_block_at(self, x, y, z): return self.states.get((x, y, z), blocks.AIR) def set_block_at(self, x, y, z, state_id): previous = self.get_block_at(x, y, z) self.states[(x, y, z)] = state_id return previous chunks = WorldState() chunks.chunks[(0, -1)] = FakeColumn() chunks.set_block_at(*position, sign_state) chunks.set_block_entity(position, 7, { 'front_text': {'messages': ['mosfet1 stay', 'within 8 square', '', '']}, }) world = World(Munch(chunks=chunks)) self.assertEqual(len(world.find_signs(position, 1)), 1) chunks.set_block_at(*position, blocks.AIR) self.assertNotIn(position, chunks.block_entities) self.assertEqual(world.find_signs(position, 1), []) def test_sign_search_ignores_stale_block_entity_for_non_sign_block(self): position = (4, 65, -2) chunks = Munch( block_entities={position: {'data': {'front_text': { 'messages': ['mosfet1 stay', 'within 8 square', '', ''], }}}}, get_block_at=lambda *_position: blocks.AIR, ) self.assertEqual(World(Munch(chunks=chunks)).find_signs(position, 1), []) def test_group_and_individual_sign_addresses(self): group_world = World(Munch(chunks=Munch(block_entities={ (0, 64, 0): {'data': {'front_text': {'messages': [ 'mosfet', 'stay within25', 'square', '', ]}}}, }), pos=(0, 64, 0))) for bot_name in ('mosfet1', 'mosfet2', 'mosfet3'): self.assertEqual([p['shape'] for p in group_world.sign_policies(bot_name)], ['square']) self.assertEqual(group_world.sign_policies('mosfet4'), []) individual_world = World(Munch(chunks=Munch(block_entities={ (1, 64, 0): {'data': {'front_text': {'messages': [ 'mosfet2', 'stay within 10 circle', '', '', ]}}}, }), pos=(1, 64, 0))) self.assertEqual([p['shape'] for p in individual_world.sign_policies('mosfet2')], ['circle']) self.assertEqual(individual_world.sign_policies('mosfet1'), []) def test_nearest_sign_policy_overrides_farther_matching_sign(self): chunks = Munch(block_entities={ (-138, 71, -268): {'data': {'front_text': {'messages': [ 'mosfet1', 'stay within 25 square', '', '', ]}}}, (-158, 71, -248): {'data': {'front_text': {'messages': [ 'mosfet1', 'stay within 6 squares', '', '', ]}}}, }) world = World(Munch(chunks=chunks, pos=(-158, 71, -248))) self.assertEqual(world.sign_policies('mosfet1'), [{ 'position': (-158, 71, -248), 'distance': 6, 'shape': 'square', 'side': 'front', }]) def test_work_paths_obey_sign_boundary_but_cache_paths_do_not(self): sign_data = {'front_text': {'messages': [ 'mosfet1', 'stay within 25 square', '', '', ]}} chunks = Munch(block_entities={(0, 64, 0): {'data': sign_data}}) work_machine = object() cache_machine = object() job = Munch(active_machine=work_machine, cache_items_states=cache_machine) world = World(Munch(chunks=chunks, job=job, name='mosfet1', pos=(0, 64, 0))) class FixedPathfinder: @staticmethod def astar(_start, _place): return [(0, 64, 0), (20, 64, 0), (30, 64, 0)] with patch('mosfet.world.path.Pathfinder', return_value=FixedPathfinder()): self.assertIsNone(world.path_to_place((0, 64, 0), (30, 64, 0))) job.active_machine = cache_machine self.assertEqual(world.path_to_place( (0, 64, 0), (30, 64, 0)), [(0, 64, 0), (20, 64, 0), (30, 64, 0)]) policy = {'position': (0, 64, 0), 'distance': 25, 'shape': 'square'} self.assertTrue(World._path_allowed_by_sign( [(30, 64, 0), (27, 64, 0), (24, 64, 0)], policy)) self.assertFalse(World._path_allowed_by_sign( [(30, 64, 0), (32, 64, 0), (24, 64, 0)], policy)) six_square = {'position': (-158, 71, -248), 'distance': 6, 'shape': 'square'} six_circle = dict(six_square, shape='circle') crop = (-162, 68, -247) self.assertEqual(World._sign_policy_distance(crop, six_square), 4) self.assertAlmostEqual(World._sign_policy_distance(crop, six_circle), (17 ** 0.5)) four_square = {'position': (0, 64, 0), 'distance': 4, 'shape': 'square'} self.assertEqual(World._sign_policy_distance((4, 70, 4), four_square), 4) self.assertTrue(World._inside_sign_policy((4, 70, 4), four_square)) self.assertFalse(World._inside_sign_policy((5, 64, 4), four_square)) same_xz_far_y = (-158, -20, -248) self.assertEqual( World._sign_policy_distance(same_xz_far_y, six_square), 0) def test_signs_command_replies_with_nearby_text(self): class FakeChat: def __init__(self): self.sent = [] def set_handler(self, handler): self.handler = handler def send(self, message): self.sent.append(message) chat = FakeChat() world = Munch(find_signs=lambda _position, _distance: [{ 'position': (1, 64, 2), 'side': 'front', 'lines': ('Hello', 'world', '', ''), }]) commands = Commands(Munch( name='mosfet1', chat=chat, world=world, pos=(0.5, 64.0, 0.5))) commands.handle_chat(('CHAT', 'tester', 'tester: !signs')) self.assertEqual(chat.sent, ['front (1, 64, 2): Hello | world']) if __name__ == '__main__': unittest.main()