From 930f4f3868182f65cf312680bea7feaff67b51ce Mon Sep 17 00:00:00 2001 From: Tanner Date: Sat, 7 Nov 2026 23:21:41 +0000 Subject: [PATCH] Clear stale sign data when signs break --- mosfet/protocol/managers.py | 15 ++++++++++++- mosfet/world.py | 11 ++++++++++ tests/test_signs.py | 42 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/mosfet/protocol/managers.py b/mosfet/protocol/managers.py index d01c40e..94c9c8f 100644 --- a/mosfet/protocol/managers.py +++ b/mosfet/protocol/managers.py @@ -283,11 +283,21 @@ class WorldState: return chunk.get_block_at(floor(x), floor(y), floor(z)) def set_block_entity(self, position, entity_type, data): - self.block_entities[tuple(position)] = { + position = tuple(position) + if data is None: + self.block_entities.pop(position, None) + return + self.block_entities[position] = { 'type': entity_type, 'data': nbt_plain(data), } + @staticmethod + def _is_sign_state(block_state_id): + from mosfet.info import blocks + name = blocks.BLOCKS.get(block_state_id) + return name is not None and name.endswith('_sign') + def set_block_at(self, x, y, z, block_state_id): x, y, z = floor(x), floor(y), floor(z) chunk = self.get_chunk(floor(x / 16), floor(z / 16)) @@ -297,6 +307,9 @@ class WorldState: pos = (x, y, z) if previous in self.indexed_ids: self.index.get(previous, set()).discard(pos) + if (self._is_sign_state(previous) and + not self._is_sign_state(block_state_id)): + self.block_entities.pop(pos, None) if block_state_id in self.indexed_ids: self.index.setdefault(block_state_id, set()).add(pos) return True diff --git a/mosfet/world.py b/mosfet/world.py index 1a1fe6d..cff4bfa 100644 --- a/mosfet/world.py +++ b/mosfet/world.py @@ -25,6 +25,11 @@ class World: def block_at(self, x, y, z): return self.g.chunks.get_block_at(x, y, z) + @staticmethod + def _is_sign_state(state_id): + name = blocks.BLOCKS.get(state_id) + return name is not None and name.endswith('_sign') + @staticmethod def _sign_component_text(value): if value is None: @@ -58,6 +63,12 @@ class World: for position, entity in self.g.chunks.block_entities.items(): if utils.phyp(center, position) > distance: continue + get_block_at = getattr(self.g.chunks, 'get_block_at', None) + if callable(get_block_at): + state_id = get_block_at(*position) + if (state_id is not None and + not self._is_sign_state(state_id)): + continue data = entity.get('data') or {} for side in ('front', 'back'): text_data = data.get(side + '_text') diff --git a/tests/test_signs.py b/tests/test_signs.py index 39d1605..e3a2baa 100644 --- a/tests/test_signs.py +++ b/tests/test_signs.py @@ -3,6 +3,7 @@ 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 @@ -45,6 +46,47 @@ class SignReadingTests(unittest.TestCase): 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': [