Consolidate bot runtime on Minecraft 26.3

This commit is contained in:
Tanner
2026-11-04 03:05:23 +00:00
parent b6f7ce9948
commit f7f58f5d07
15 changed files with 706 additions and 537 deletions
+117 -1
View File
@@ -6,6 +6,10 @@ from munch import Munch
from minecraft.networking.packets import Packet, clientbound, serverbound
from minecraft.networking.types import BlockFace
from minecraft.networking.modern import (
ClientTickEnd, ContainerClickSwapPacket, PlayerActionPacket,
SetCarriedItemPacket, UseItemOnBlockPacket,
)
from mosfet.protocol.packets import (
SetSlotPacket, PlayerDiggingPacket,
@@ -29,7 +33,7 @@ from mosfet.info import items
from mosfet.info import mcdata
from mosfet.info import mobs
class Game:
class LegacyGame:
def __init__(self, global_state):
self.g = global_state
@@ -568,3 +572,115 @@ class Game:
if not self.g.path:
self.g.correction_count = 0
# Active game facade. The constructor registers no legacy packet listeners;
# migrated actions use the 26.3 packet classes imported above.
class Game(LegacyGame):
def __init__(self, global_state):
self.g = global_state
self.sequence = 0
self.break_deadline = None
self.breaking_state = None
def _send_action(self, packet):
self.g.connection.write_packet(packet, force=True)
self.g.connection.write_packet(ClientTickEnd(), force=True)
def _next_sequence(self):
self.sequence += 1
return self.sequence
def break_block(self, location):
location = tuple(int(value) for value in location)
block_id = self.g.chunks.get_block_at(*location)
if block_id is None or block_id == blocks.AIR:
return False
packet = PlayerActionPacket(
action=0, location=location, face=1,
sequence=self._next_sequence())
self._send_action(packet)
self.g.breaking = location
self.breaking_state = block_id
hardness_time = utils.break_time(block_id, self.g.get('holding', 0))
self.break_deadline = time.monotonic() + max(0.05, hardness_time)
return True
def tick(self):
if not self.g.get('breaking') or self.break_deadline is None:
return
if time.monotonic() < self.break_deadline:
return
packet = PlayerActionPacket(
action=3, location=self.g.breaking, face=1,
sequence=self._next_sequence())
self._send_action(packet)
location = self.g.breaking
if self.g.chunks.get_block_at(*location) == self.breaking_state:
# Predict the normal client-side block removal. The server's later
# block update is authoritative and will correct the cache if the
# action was denied or the block changed differently.
self.g.chunks.set_block_at(*location, blocks.AIR)
self.g.breaking = None
self.break_deadline = None
self.breaking_state = None
def cancel_break(self):
if not self.g.get('breaking'):
return
packet = PlayerActionPacket(
action=2, location=self.g.breaking, face=1,
sequence=self._next_sequence())
self._send_action(packet)
self.g.breaking = None
self.break_deadline = None
self.breaking_state = None
def select_item(self, item_ids):
item_ids = set(item_ids)
matches = [(slot, item) for slot, item in self.g.inv.items()
if item.present and item.item_id in item_ids]
if not matches:
return False
# Prefer an already-hotbar stack; otherwise swap the requested stack
# into an empty hotbar slot using the modern container SWAP input.
slot, item = next(
((slot, item) for slot, item in matches if 36 <= slot <= 44),
matches[0])
if 36 <= slot <= 44:
hotbar_slot = slot - 36
elif 9 <= slot <= 35:
empty_hotbar = next(
(candidate - 36 for candidate in range(36, 45)
if candidate not in self.g.inv or
not self.g.inv[candidate].present), None)
hotbar_slot = (empty_hotbar if empty_hotbar is not None else
self.g.get('holding_slot', 0) or 0)
self.g.connection.write_packet(ContainerClickSwapPacket(
container_id=0,
state_id=self.g.inventory_state_ids.get(0, 0),
slot=slot, button=hotbar_slot), force=True)
else:
return False
if self.g.get('holding_slot') != hotbar_slot:
self.g.connection.write_packet(SetCarriedItemPacket(
slot=hotbar_slot), force=True)
self.g.holding_slot = hotbar_slot
self.g.holding = item.item_id
self.g.connection.write_packet(ClientTickEnd(), force=True)
return True
def place_block(self, location, face):
location = tuple(int(value) for value in location)
packet = UseItemOnBlockPacket(
hand=0, location=location, face=int(face),
cursor_x=0.5, cursor_y=0.99 if int(face) == 1 else 0.5,
cursor_z=0.5, inside_block=False, world_border_hit=False,
sequence=self._next_sequence())
self._send_action(packet)
def close_window(self):
# Container open/close packet migration is not part of the crop path.
return None