Read nearby 26.3 sign text

This commit is contained in:
Tanner
2026-11-05 23:47:05 +00:00
parent 09035793e2
commit c323ea8373
4 changed files with 179 additions and 2 deletions
+23
View File
@@ -324,6 +324,29 @@ class Commands:
tree = next(self.g.world.find_trees(pos, 50))
reply = str(tree)[1:-1]
## !signs [distance] - prints nearby sign text
if command == 'signs':
distance = float(data) if data else 32
signs = self.g.world.find_signs(
utils.pint(self.g.pos), distance)
if signs:
results = []
for sign in signs:
text = ' | '.join(line for line in sign['lines']
if line.strip())
entry = '{} {}: {}'.format(
sign['side'], sign['position'], text)
results.append(entry)
print('Sign {} {}:'.format(
sign['side'], sign['position']))
for line in sign['lines']:
print(' ' + line)
reply = '; '.join(results)
if len(reply) > 240:
reply = reply[:237] + '...'
else:
reply = 'no signs found within {} blocks'.format(distance)
## !info [query] - replies with info on a coordinate, block, item, or player
if command == 'info':
if not reply:
+27 -2
View File
@@ -4,8 +4,9 @@ from munch import Munch
from minecraft.networking.packets import clientbound, serverbound
from minecraft.networking.modern import (
AddEntityPacket, ContainerOpenPacket, ContainerSetContentPacket,
ContainerSetSlotPacket, SetEntityDataPacket,
AddEntityPacket, BlockEntityDataPacket, ContainerOpenPacket,
ContainerSetContentPacket, ContainerSetSlotPacket, SetEntityDataPacket,
nbt_plain,
PaletteSection,
EntityPositionSyncPacket, MoveEntityPositionPacket,
MoveEntityPositionRotationPacket, MoveEntityRotationPacket,
@@ -218,6 +219,7 @@ class WorldState:
self.min_section = min_y // 16
self.chunks = {}
self.index = {}
self.block_entities = {}
from mosfet.info import blocks
self.indexed_ids = blocks.INDEXED_IDS
self.center = None
@@ -242,6 +244,10 @@ class WorldState:
chunk = ChunkColumn(packet.x, packet.z, packet.sections,
self.min_section)
self.chunks[(packet.x, packet.z)] = chunk
for entity in getattr(packet, 'block_entities', []):
pos = (entity['x'], entity['y'], entity['z'])
self.set_block_entity(
pos, entity['type'], entity.get('data'))
for section_y, section in chunk.sections.items():
palette = section['blocks']
if not self.indexed_ids.intersection(
@@ -275,6 +281,12 @@ class WorldState:
return None
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)] = {
'type': entity_type,
'data': nbt_plain(data),
}
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))
@@ -300,10 +312,16 @@ class WorldState:
}
if not self.index[state_id]:
del self.index[state_id]
self.block_entities = {
pos: entity for pos, entity in self.block_entities.items()
if not (x0 <= pos[0] < x0 + 16 and
z0 <= pos[2] < z0 + 16)
}
def unload_all_chunks(self):
self.chunks.clear()
self.index.clear()
self.block_entities.clear()
def get_loaded_area(self, ignore_empty=False):
if not self.chunks:
@@ -348,6 +366,7 @@ class EntityManager:
for packet_type, handler in (
(AddEntityPacket, self.handle_add_entity),
(SetEntityDataPacket, self.handle_entity_data),
(BlockEntityDataPacket, self.handle_block_entity_data),
(RemoveEntitiesPacket, self.handle_remove_entities),
(MoveEntityPositionPacket, self.handle_move),
(MoveEntityPositionRotationPacket, self.handle_move),
@@ -379,6 +398,12 @@ class EntityManager:
type=packet.entity_type_id, yaw=packet.yaw,
pitch=packet.pitch)
def handle_block_entity_data(self, packet):
location = packet.location
self.g.chunks.set_block_entity(
(location.x, location.y, location.z),
packet.block_entity_type, packet.data)
def handle_entity_data(self, packet):
obj = self.g.objects.get(packet.entity_id)
if obj is None or not packet.item_stacks:
+58
View File
@@ -1,4 +1,5 @@
import collections
import json
import re
import time
import random
@@ -18,6 +19,63 @@ class World:
def block_at(self, x, y, z):
return self.g.chunks.get_block_at(x, y, z)
@staticmethod
def _sign_component_text(value):
if value is None:
return ''
if isinstance(value, str):
stripped = value.strip()
if stripped.startswith(('{', '[')):
try:
parsed = json.loads(stripped)
except ValueError:
return value
if parsed != value:
return World._sign_component_text(parsed)
return value
if isinstance(value, (list, tuple)):
return ''.join(World._sign_component_text(part) for part in value)
if isinstance(value, dict):
text = value.get('text', '')
if not text and value.get('translate'):
text = value['translate']
if isinstance(text, (dict, list)):
text = World._sign_component_text(text)
return (str(text) +
World._sign_component_text(value.get('with', [])) +
World._sign_component_text(value.get('extra', [])))
return str(value)
def find_signs(self, center, distance=16):
"""Return nearby loaded signs as position/side/four-lines records."""
result = []
for position, entity in self.g.chunks.block_entities.items():
if utils.phyp(center, position) > distance:
continue
data = entity.get('data') or {}
for side in ('front', 'back'):
text_data = data.get(side + '_text')
if not isinstance(text_data, dict):
continue
messages = text_data.get('messages', [])
lines = tuple(self._sign_component_text(line)
for line in messages[:4])
lines += ('',) * (4 - len(lines))
if any(line.strip() for line in lines):
result.append({
'position': position, 'side': side, 'lines': lines,
})
if not any(key in data for key in ('front_text', 'back_text')):
old_lines = tuple(self._sign_component_text(data.get(
'Text{}'.format(index), '')) for index in range(1, 5))
if any(line.strip() for line in old_lines):
result.append({
'position': position, 'side': 'front',
'lines': old_lines,
})
result.sort(key=lambda sign: utils.phyp(center, sign['position']))
return result
def check_air_column(self, pos, distance):
for i in range(distance):
check = utils.padd(pos, (0, i, 0))