Consolidate bot runtime on Minecraft 26.3
This commit is contained in:
+133
-27
@@ -6,6 +6,8 @@ import os
|
||||
import sys
|
||||
import time
|
||||
import importlib
|
||||
import threading
|
||||
import traceback
|
||||
from math import floor, ceil
|
||||
from copy import copy
|
||||
|
||||
@@ -68,26 +70,51 @@ def tick(global_state):
|
||||
required_distance = getattr(g, 'physics_render_distance',
|
||||
g.info.render_distance)
|
||||
if not g.chunks.check_loaded(required_distance):
|
||||
if g.get('movement_status') != 'waiting_for_chunks':
|
||||
print('[movement] status=waiting_for_chunks near {}'.format(
|
||||
utils.pint(p)), flush=True)
|
||||
g.movement_status = 'waiting_for_chunks'
|
||||
if not g.chunks.loading:
|
||||
print('Loading chunks', end='', flush=True)
|
||||
g.chunks.loading = time.time()
|
||||
if getattr(g, 'protocol_version', 0) == 777:
|
||||
from minecraft.networking.modern import PlayerPositionRotation
|
||||
packet = PlayerPositionRotation(
|
||||
x=p.x, y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True)
|
||||
else:
|
||||
packet = serverbound.play.PositionAndLookPacket(
|
||||
x=p.x, feet_y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True)
|
||||
now = time.time()
|
||||
if now - g.get('chunk_wait_report_at', 0) >= 5:
|
||||
center = g.chunks.center
|
||||
if center is None:
|
||||
missing = 'cache center not received'
|
||||
else:
|
||||
cx, cz = center
|
||||
missing = [
|
||||
(x, z)
|
||||
for x in range(cx - required_distance,
|
||||
cx + required_distance + 1)
|
||||
for z in range(cz - required_distance,
|
||||
cz + required_distance + 1)
|
||||
if (x, z) not in g.chunks.chunks
|
||||
]
|
||||
print('\n[movement] chunk wait: pos={}, center={}, '
|
||||
'radius={}, loaded={}, missing={}'.format(
|
||||
utils.pint(p), center, g.chunks.radius,
|
||||
len(g.chunks.chunks), missing), flush=True)
|
||||
g.chunk_wait_report_at = now
|
||||
from minecraft.networking.modern import (
|
||||
ClientTickEnd, PlayerPositionRotation,
|
||||
)
|
||||
packet = PlayerPositionRotation(
|
||||
x=p.x, y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True)
|
||||
g.connection.write_packet(packet, force=True)
|
||||
if getattr(g, 'protocol_version', 0) == 777:
|
||||
from minecraft.networking.modern import ClientTickEnd
|
||||
g.connection.write_packet(ClientTickEnd(), force=True)
|
||||
g.connection.write_packet(ClientTickEnd(), force=True)
|
||||
return
|
||||
else:
|
||||
if g.chunks.loading:
|
||||
print()
|
||||
print('Chunks loaded in', round(time.time() - g.chunks.loading, 2), 's')
|
||||
g.chunks.loading = False
|
||||
g.chunk_wait_report_at = 0
|
||||
status = 'following_path' if g.path else 'running_job'
|
||||
if g.get('movement_status') != status:
|
||||
print('[movement] status={}'.format(status), flush=True)
|
||||
g.movement_status = status
|
||||
|
||||
########## object physics ##########
|
||||
# note: it's possible the chunk data is out of date when this runs
|
||||
@@ -208,23 +235,15 @@ def tick(global_state):
|
||||
target_pitch_d = 0 - g.pitch
|
||||
g.pitch += utils.cap(target_pitch_d, 10)
|
||||
|
||||
if getattr(g, 'protocol_version', 0) == 777:
|
||||
from minecraft.networking.modern import PlayerPositionRotation
|
||||
packet = PlayerPositionRotation(
|
||||
x=p.x, y=p.y, z=p.z, pitch=g.pitch, yaw=g.yaw,
|
||||
on_ground=(not in_air))
|
||||
else:
|
||||
packet = serverbound.play.PositionAndLookPacket(
|
||||
x=p.x, feet_y=p.y, z=p.z, pitch=g.pitch, yaw=g.yaw,
|
||||
on_ground=(not in_air))
|
||||
if getattr(g, 'protocol_version', 0) == 777:
|
||||
from minecraft.networking.modern import ClientTickEnd
|
||||
# Keep the client-tick boundary after its movement packet on the wire;
|
||||
# force=True on only the latter could overtake the queued position.
|
||||
g.connection.write_packet(packet, force=True)
|
||||
g.connection.write_packet(ClientTickEnd(), force=True)
|
||||
else:
|
||||
g.connection.write_packet(packet)
|
||||
from minecraft.networking.modern import (
|
||||
ClientTickEnd, PlayerPositionRotation,
|
||||
)
|
||||
packet = PlayerPositionRotation(
|
||||
x=p.x, y=p.y, z=p.z, pitch=g.pitch, yaw=g.yaw,
|
||||
on_ground=(not in_air))
|
||||
# Keep the client-tick boundary after its movement packet on the wire.
|
||||
g.connection.write_packet(packet, force=True)
|
||||
g.connection.write_packet(ClientTickEnd(), force=True)
|
||||
|
||||
if g.job:
|
||||
g.job.tick()
|
||||
@@ -352,3 +371,90 @@ def bot(global_state):
|
||||
g.connection.early_outgoing_packet_listeners = []
|
||||
|
||||
print('Bot module loaded.')
|
||||
|
||||
|
||||
def start_automation(global_state):
|
||||
"""Start migrated path-following and crop automation only."""
|
||||
g = global_state
|
||||
g.protocol_version = 777
|
||||
g.time = 0.0
|
||||
g.path = []
|
||||
g.look_at = None
|
||||
g.y_v = 0.0
|
||||
g.y_a = 0.0
|
||||
g.crawling = False
|
||||
g.afk_timeout = 0.0
|
||||
g.objects = g.get('objects') or {}
|
||||
g.players = g.get('players') or {}
|
||||
g.breaking = None
|
||||
g.break_time = 0.0
|
||||
g.correction_count = g.get('correction_count', 0)
|
||||
g.yaw = float(g.get('yaw', 0.0) or 0.0)
|
||||
g.pitch = float(g.get('pitch', 0.0) or 0.0)
|
||||
g.chunks.loading = False
|
||||
# Local navigation only needs nearby chunks; waiting for the entire view
|
||||
# radius can stall on servers that stream chunks gradually.
|
||||
g.physics_render_distance = 2
|
||||
g.movement_paused = False
|
||||
g.movement_status = 'idle'
|
||||
g.movement_error = None
|
||||
# Keep the port constrained to crop harvesting; other legacy jobs and
|
||||
# general inventory/window mutations are not exposed through this adapter.
|
||||
from mosfet.game import Game
|
||||
from mosfet.job import JobStates
|
||||
g.game = Game(g)
|
||||
g.job = JobStates(g)
|
||||
|
||||
def run():
|
||||
from mosfet import bot, utils
|
||||
loaded_since = None
|
||||
initial_world_ready = False
|
||||
|
||||
def set_status(status):
|
||||
if g.movement_status != status:
|
||||
print('[movement] status={}'.format(status), flush=True)
|
||||
g.movement_status = status
|
||||
|
||||
while (g.get('running', True) and g.get('connection') and
|
||||
g.connection.connected):
|
||||
started = time.monotonic()
|
||||
now = time.monotonic()
|
||||
if not initial_world_ready:
|
||||
if g.chunks.check_loaded(g.physics_render_distance):
|
||||
if loaded_since is None:
|
||||
loaded_since = now
|
||||
elif now - loaded_since >= 0.5:
|
||||
initial_world_ready = True
|
||||
else:
|
||||
loaded_since = None
|
||||
# Wait once for the initial position/chunk batch. After that,
|
||||
# bot.tick() keeps requesting chunks at cache boundaries instead
|
||||
# of gating itself forever on a momentary missing column.
|
||||
movement_ready = initial_world_ready
|
||||
job_active = (g.job is not None and g.job.state != g.job.idle)
|
||||
has_work = bool(g.path) or job_active or bool(g.breaking)
|
||||
if g.get('movement_paused'):
|
||||
set_status('paused')
|
||||
elif has_work and not movement_ready:
|
||||
set_status('waiting_for_chunks')
|
||||
elif has_work and movement_ready:
|
||||
try:
|
||||
bot.tick(g)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
g.movement_error = traceback.format_exc()
|
||||
g.path = []
|
||||
g.movement_status = 'error'
|
||||
print('[movement] stopped after navigation error',
|
||||
flush=True)
|
||||
return
|
||||
elif not has_work and not g.get('movement_paused'):
|
||||
set_status('idle')
|
||||
delay = max(0.0, utils.TICK - (time.monotonic() - started))
|
||||
time.sleep(delay)
|
||||
|
||||
worker = threading.Thread(target=run, name='mosfet-movement',
|
||||
daemon=True)
|
||||
g.movement_thread = worker
|
||||
worker.start()
|
||||
return worker
|
||||
|
||||
Reference in New Issue
Block a user