Port wood gathering and fix 26.3 swing animation

This commit is contained in:
Tanner
2026-11-05 15:26:55 +00:00
parent 659fa49ea1
commit b71774b9aa
9 changed files with 208 additions and 33 deletions
+3 -2
View File
@@ -66,10 +66,11 @@ class Commands:
command = 'nosquarebrackets'
unsupported = {
'gather', 'trade', 'gapple', 'fill',
'trade', 'gapple', 'fill',
'break', 'open', 'click', 'use', 'interact',
}
if (command in unsupported or
if ((command == 'gather' and data.lower().strip() != 'wood') or
command in unsupported or
(command == 'farm' and not data.lower().startswith('crop'))):
reply = 'not migrated to Minecraft 26.3 yet'
print('Reply:', reply)
+6 -5
View File
@@ -47,11 +47,12 @@ def component_text(value):
return str(value)
def main(global_state=None):
server = os.environ.get('SERVER', '127.0.0.1')
port = int(os.environ.get('PORT', '25565'))
username = os.environ.get('PLAYER_NAME', 'mosfet1')
password = os.environ.get('GAME_PASSWORD', 'mosfetbot')
def main(global_state=None, *, server=None, port=None, username=None,
password=None):
server = server or os.environ.get('SERVER', '127.0.0.1')
port = int(port or os.environ.get('PORT', '25565'))
username = username or os.environ.get('PLAYER_NAME', 'mosfet1')
password = password or os.environ.get('GAME_PASSWORD', 'mosfetbot')
connection = Connection(server, port, username=username,
allowed_versions=['26.3'],
+20 -3
View File
@@ -8,7 +8,8 @@ from minecraft.networking.packets import Packet, clientbound, serverbound
from minecraft.networking.types import BlockFace, Byte, Short, VarInt
from minecraft.networking.modern import (
ClientTickEnd, ContainerClickSwapPacket, PlayerActionPacket,
SetCarriedItemPacket, SetHeldSlotPacket, UseItemOnBlockPacket,
PunchPacket, SetCarriedItemPacket, SetHeldSlotPacket,
UseItemOnBlockPacket,
)
from mosfet.protocol.packets import (
@@ -651,11 +652,14 @@ class LegacyGame:
# Active game facade. The constructor registers no legacy packet listeners;
# migrated actions use the 26.3 packet classes imported above.
class Game(LegacyGame):
ARM_SWING_INTERVAL = 0.1
def __init__(self, global_state):
self.g = global_state
self.sequence = 0
self.break_deadline = None
self.breaking_state = None
self.next_swing_at = 0.0
from mosfet.protocol.packets import SetHealthPacket
# Health is a protocol-777 packet, not the legacy UpdateHealthPacket.
@@ -708,6 +712,10 @@ class Game(LegacyGame):
self.sequence += 1
return self.sequence
def animate(self):
"""Ask the 26.3 server to broadcast a main-hand punch animation."""
self._send_action(PunchPacket())
def break_block(self, location):
location = tuple(int(value) for value in location)
block_id = self.g.chunks.get_block_at(*location)
@@ -720,7 +728,10 @@ class Game(LegacyGame):
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)
now = time.monotonic()
self.break_deadline = now + max(0.05, hardness_time)
self.animate()
self.next_swing_at = now + self.ARM_SWING_INTERVAL
return True
def respawn(self):
@@ -922,7 +933,11 @@ class Game(LegacyGame):
self._tick_drain()
if not self.g.get('breaking') or self.break_deadline is None:
return
if time.monotonic() < self.break_deadline:
now = time.monotonic()
if now < self.break_deadline:
if now >= self.next_swing_at:
self.animate()
self.next_swing_at = now + self.ARM_SWING_INTERVAL
return
packet = PlayerActionPacket(
action=3, location=self.g.breaking, face=1,
@@ -937,6 +952,7 @@ class Game(LegacyGame):
self.g.breaking = None
self.break_deadline = None
self.breaking_state = None
self.next_swing_at = 0.0
def cancel_break(self):
if not self.g.get('breaking'):
@@ -948,6 +964,7 @@ class Game(LegacyGame):
self.g.breaking = None
self.break_deadline = None
self.breaking_state = None
self.next_swing_at = 0.0
def select_item(self, item_ids):
item_ids = set(item_ids)
+1 -1
View File
@@ -79,7 +79,7 @@ SAPLINGS = sorted(name for name in MCD_BLOCKS
BEDS = sorted(name for name in MCD_BLOCKS if name.endswith('_bed'))
INDEXED = ['chest', 'trapped_chest', 'emerald_block', 'barrel'] + BEDS + [
'wheat', 'potatoes', 'carrots', 'beetroots',
]
] + LOGS
LOG_IDS = get_set(LOGS)
LEAF_IDS = get_set(LEAVES)
+3 -1
View File
@@ -265,9 +265,10 @@ class LegacyJobStates:
class JobStates(LegacyJobStates):
"""26.3 facade for crop, inventory, sleeping, and loiter workflows."""
"""26.3 facade for migrated gather-wood and crop workflows."""
def __init__(self, global_state):
self.g = global_state
self.gather_wood_states = gather_wood.GatherWoodStates(global_state)
self.gather_crop_states = gather_crop.GatherCropStates(global_state)
self.cache_items_states = cache_items.CacheItemsStates(global_state)
self.sleep_with_bed_states = sleep_with_bed.SleepWithBedStates(
@@ -311,6 +312,7 @@ class JobStates(LegacyJobStates):
self.g.look_at = None
if self.sleep_with_bed_states.state == self.sleep_with_bed_states.sleep_bed:
self.g.game.leave_bed()
self.gather_wood_states.state = self.gather_wood_states.idle
self.gather_crop_states.state = self.gather_crop_states.idle
self.cache_items_states.state = self.cache_items_states.idle
self.sleep_with_bed_states.state = self.sleep_with_bed_states.idle
+2 -11
View File
@@ -1,20 +1,11 @@
import re
"""Gather naturally generated trees using the active 26.3 world/game APIs."""
import time
import importlib
import random
from itertools import count
from math import floor
from minecraft.networking.types import BlockFace
from mosfet.protocol.managers import ChunkNotLoadedException
from mosfet import utils
from mosfet import path
from mosfet.info import blocks
from mosfet.info import items
from mosfet.info import mcdata
from mosfet.info import mobs
class GatherWoodStates:
def bair(self, p):
+13 -10
View File
@@ -81,9 +81,14 @@ class World:
return result
def find_trees(self, center, distance):
found_trees = []
for log in self.find_blocks_3d(center, blocks.LOG_IDS, distance, 15):
# crawl to the bottom log
found_trees = set()
# 26.3 block-state caches keep an index of tree logs. Searching a
# three-dimensional radius voxel-by-voxel is prohibitively expensive
# and can walk through unloaded space, so use loaded indexed states.
for candidate in self.find_blocks_indexed(
center, blocks.LOG_IDS, distance):
# Crawl to the bottom log of this trunk.
log = candidate
while self.block_at(*utils.padd(log, path.BLOCK_BELOW)) in blocks.LOG_IDS:
log = utils.padd(log, path.BLOCK_BELOW)
base = log
@@ -91,27 +96,25 @@ class World:
if base in found_trees:
continue
# make sure we are on the ground
if self.block_at(*utils.padd(base, path.BLOCK_BELOW)) in blocks.NON_SOLID_IDS:
# Only classify trees when their supporting block is known.
support = self.block_at(*utils.padd(base, path.BLOCK_BELOW))
if support is None or support in blocks.NON_SOLID_IDS:
continue
# crawl to the top log to count and check leaves
# Crawl to the top log to count trunk blocks and check for leaves.
log_count = 1
good_leaves = False
while self.block_at(*utils.padd(log, path.BLOCK_ABOVE)) in blocks.LOG_IDS:
log = utils.padd(log, path.BLOCK_ABOVE)
log_count += 1
for offset in path.CHECK_DIRECTIONS:
if self.block_at(*utils.padd(log, offset)) in blocks.LEAF_IDS:
good_leaves = True
# make sure it's a good tree
if not good_leaves or log_count < 3:
continue
found_trees.append(base)
found_trees.add(base)
yield base
def find_tree_openings(self, tree):