Port inventory components to Minecraft 26.3

This commit is contained in:
Tanner
2026-11-03 23:33:04 +00:00
parent 59c76471f2
commit b6f7ce9948
6 changed files with 137 additions and 26 deletions
+60 -15
View File
@@ -113,30 +113,75 @@ class Commands:
if command == 'inv' or command == 'inventory':
inv_list = []
uniq_item_counts = {}
for i in self.g.inv.values():
if i.present:
inv_list.append((items.ITEM_NAMES[i.item_id], str(i.item_id), i.item_count))
for slot, i in self.g.inv.items():
if not i.present:
continue
base_name = items.ITEM_NAMES.get(i.item_id, str(i.item_id))
components = getattr(i, 'components', {}) or {}
custom_name = components.get('custom_name') or components.get('item_name')
if isinstance(custom_name, dict):
custom_name = custom_name.get('text') or custom_name.get('raw')
display_name = str(custom_name or base_name)
details = []
for key in ('enchantments', 'stored_enchantments'):
for name, level in components.get(key, {}).items():
details.append('{} {}'.format(name, level))
contents = components.get('container')
if contents:
nested_count = sum(bool(getattr(item, 'present', False))
for item in contents)
details.append('{} items inside'.format(nested_count))
written = components.get('written_book_content')
if written:
title = written.get('title', {}).get('raw', '')
details.append('book: {} ({} pages)'.format(
title, len(written.get('pages', []))))
writable = components.get('writable_book_content')
if writable:
details.append('writable book ({} pages)'.format(
len(writable)))
if getattr(i, 'components_unknown', False):
details.append('components partial')
detail_text = ' [{}]'.format(', '.join(details)) if details else ''
inv_list.append((slot, display_name, str(i.item_id),
i.item_count, detail_text))
uniq_item_counts[i.item_id] = (
uniq_item_counts.get(i.item_id, 0) + i.item_count)
if i.item_id not in uniq_item_counts:
uniq_item_counts[i.item_id] = 0
uniq_item_counts[i.item_id] += i.item_count
inv_list.sort()
console_result = '\n'.join(['{}:{} x {}'.format(*x) for x in inv_list])
inv_list.sort(key=lambda entry: (entry[1], entry[2]))
console_result = '\n'.join(
'slot {}: {}:{} x {}{}'.format(*entry)
for entry in inv_list)
if not console_result:
print('Empty')
reply = 'empty'
else:
print(console_result)
if self.g.get('inventory_partial', False):
print('Warning: inventory contains stacks with undecoded components.')
reply_result_1 = ', '.join(['{}:{} x {}'.format(*x) for x in inv_list])
reply_result_2 = ', '.join(['{}:{} x {}'.format(items.ITEM_NAMES[k], str(k), v) for k,v in uniq_item_counts.items()])
reply_result_3 = ', '.join(['{}:{}x{}'.format(items.ITEM_NAMES[k], str(k), v) for k,v in uniq_item_counts.items()])
reply_result_4 = ', '.join(['{}:{}x{}'.format(re.sub(r'[aeiou]', '', items.ITEM_NAMES[k]), str(k), v) for k,v in uniq_item_counts.items()])
reply_result_5 = ' '.join(['{}{}x{}'.format(re.sub(r'[aeiou]', '', items.ITEM_NAMES[k]), str(k), v) for k,v in uniq_item_counts.items()])
reply_result_1 = ', '.join(
'{}:{} x {}{}'.format(*entry[1:]) for entry in inv_list)
reply_result_components = ', '.join(
'{}{}'.format(entry[1], entry[4])
for entry in inv_list if entry[4])
reply_result_2 = ', '.join(
'{}:{} x {}'.format(items.ITEM_NAMES.get(k, str(k)), str(k), v)
for k, v in uniq_item_counts.items())
reply_result_3 = ', '.join(
'{}:{}x{}'.format(items.ITEM_NAMES.get(k, str(k)), str(k), v)
for k, v in uniq_item_counts.items())
reply_result_4 = ', '.join(
'{}:{}x{}'.format(re.sub(r'[aeiou]', '', items.ITEM_NAMES.get(k, str(k))), str(k), v)
for k, v in uniq_item_counts.items())
reply_result_5 = ' '.join(
'{}{}x{}'.format(re.sub(r'[aeiou]', '', items.ITEM_NAMES.get(k, str(k))), str(k), v)
for k, v in uniq_item_counts.items())
for r in [reply_result_1, reply_result_2, reply_result_3, reply_result_4, reply_result_5]:
for r in [reply_result_1, reply_result_components,
reply_result_2, reply_result_3, reply_result_4,
reply_result_5]:
reply = r
if len(reply) < 256:
break
+2
View File
@@ -80,10 +80,12 @@ def main(global_state=None):
from mosfet.commands import Commands
from mosfet.protocol.modern import ModernChatManager
from mosfet.protocol.entities_26_3 import ModernEntityManager
from mosfet.protocol.inventory_26_3 import ModernInventoryManager
from mosfet.automation_26_3 import start as start_modern_movement
global_state.world = World(global_state)
global_state.chat = ModernChatManager(global_state)
global_state.entities = ModernEntityManager(global_state)
global_state.inventory = ModernInventoryManager(global_state)
global_state.commands = Commands(global_state)
start_modern_movement(global_state)
+55
View File
@@ -0,0 +1,55 @@
"""Minimal 26.3 inventory synchronization for legacy read-only commands."""
from mosfet.protocol.types import Slot
from minecraft.networking.modern import (
ContainerSetContentPacket, ContainerSetSlotPacket, SetCursorItemPacket,
)
class ModernInventoryManager:
def __init__(self, global_state):
self.g = global_state
self.g.inv = self.g.get('inv') or {}
self.g.inventory_state_ids = self.g.get('inventory_state_ids') or {}
self.g.inventory_partial = False
self.g.cursor = Slot(present=False)
register = self.g.connection.register_packet_listener
register(self.handle_content, ContainerSetContentPacket)
register(self.handle_slot, ContainerSetSlotPacket)
register(self.handle_cursor, SetCursorItemPacket)
@staticmethod
def to_slot(item):
return Slot(item.present, item.item_id, item.item_count,
components=item.components,
component_ids=item.component_ids,
removed_components=item.removed_components,
components_unknown=item.components_unknown)
def handle_content(self, packet):
slots = {index: self.to_slot(item)
for index, item in enumerate(packet.items)}
self.g.inventory_state_ids[packet.container_id] = packet.state_id
if packet.container_id == 0:
self.g.inv = slots
self.g.inventory_partial = packet.partial
self.g.cursor = self.to_slot(packet.carried_item)
elif self.g.get('window'):
self.g.window.contents = slots
self.g.cursor = self.to_slot(packet.carried_item)
def handle_slot(self, packet):
self.g.inventory_state_ids[packet.container_id] = packet.state_id
item = self.to_slot(packet.item)
if packet.item.components_unknown:
self.g.inventory_partial = True
if packet.container_id == 0:
self.g.inv[packet.slot] = item
elif packet.container_id == -1 and packet.slot == -1:
self.g.cursor = item
elif self.g.get('window'):
self.g.window.contents[packet.slot] = item
def handle_cursor(self, packet):
if packet.item.components_unknown:
self.g.inventory_partial = True
self.g.cursor = self.to_slot(packet.item)
+7 -1
View File
@@ -103,11 +103,17 @@ class Nbt(Type):
class Slot(Type):
def __init__(self, present, item_id=None, item_count=None, nbt=None):
def __init__(self, present, item_id=None, item_count=None, nbt=None,
components=None, component_ids=None,
removed_components=None, components_unknown=False):
self.present = present
self.item_id = item_id
self.item_count = item_count
self.nbt = nbt
self.components = components or {}
self.component_ids = component_ids or []
self.removed_components = removed_components or []
self.components_unknown = components_unknown
def __str__(self):
return str(self.__dict__)