Files
minecraft-bot/mosfet/jobs/sleep_with_bed.py
T
2026-11-04 19:20:15 +00:00

310 lines
9.5 KiB
Python

import re
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 SleepWithBedStates:
def idle(self):
return None
def init(self):
self.my_bed = False
self.area = None
self.opening = None
self.beds = []
current_time = self.g.get('time')
if current_time is None or current_time < 12000:
print('Aborting sleep, not night')
self.state = self.cleanup
return
if self.g.get('dimension') != 'overworld':
print('Aborting sleep, not in overworld')
self.state = self.cleanup
return
self.state = self.find_beds
def find_beds(self):
print('Finding beds...')
w = self.g.world
p = utils.pint(self.g.pos)
result = ([] if self.force_new_bed else
w.find_blocks_indexed(p, blocks.BED_IDS, 80))
if self.force_new_bed:
print('Skipping existing beds; placing a new bed as requested')
self.beds = []
for bed in result:
if bed in self.bad_beds:
continue
if w.check_bed_occupied(bed):
continue
self.beds.append(bed)
print('Found:', self.beds)
self.state = self.choose_bed
def choose_bed(self):
print('Choosing a bed...')
w = self.g.world
p = utils.pint(self.g.pos)
while self.beds:
bed = self.beds.pop(0)
print('Chose:', bed)
navpath = w.path_to_place_faked(p, bed)
print('navpath:', navpath)
if navpath is None:
self.bad_beds.append(bed)
print('Cant get to bed, blacklisting')
continue
self.area = bed
self.opening = navpath[-2] if len(navpath) > 1 else p
self.g.path = navpath[:-1]
self.g.look_at = self.area
self.state = self.going_to_bed
return
print('No reachable beds; trying to place one')
self.state = self.select_bed
def going_to_bed(self):
if utils.pint(self.g.pos) == self.opening:
print('At existing bed')
self.my_bed = False
self.g.look_at = self.area
self.wait_time = 0.5
self.state = self.turn_to_bed
def turn_to_bed(self):
self.g.look_at = self.area
self.wait_time -= utils.TICK
if self.wait_time <= 0:
self.state = self.use_bed
def select_bed(self):
if self.g.game.select_item(items.BED_IDS):
self.state = self.find_bed_spot
else:
print('No bed, aborting.')
self.state = self.cleanup
def find_bed_spot(self):
print('Finding a bed spot...')
w = self.g.world
p = utils.pint(self.g.pos)
for area in w.find_bed_areas(p, 100):
print('Found area:', area)
if area not in self.bad_areas:
break
else: # for
print('Unable to find area')
self.state = self.cleanup
return
self.area = area
openings = w.find_bed_openings(self.area)
for o in openings:
toward_player = (o[0] - self.area[0], 0,
o[2] - self.area[2])
# The bed head points away from the player when placing from this
# opening, so require that footprint and its support to be clear.
head = (self.area[0] - toward_player[0], self.area[1],
self.area[2] - toward_player[2])
if (w.block_at(*head) != blocks.AIR or
w.block_at(*utils.padd(head, path.BLOCK_ABOVE)) != blocks.AIR):
continue
head_support = w.block_at(*utils.padd(head, path.BLOCK_BELOW))
if (head_support is None or
head_support in blocks.NON_SOLID_IDS or
head_support in blocks.AVOID_IDS):
continue
navpath = w.path_to_place(p, o)
self.opening = o
if navpath is not None:
break
else: # for
print('Unable to get to bed area', self.area)
self.bad_areas.append(self.area)
self.state = self.cleanup
return
self.g.path = navpath
self.g.look_at = self.area
self.state = self.going_to_area
def going_to_area(self):
if utils.pint(self.g.pos) == self.opening:
print('At bed area')
self.g.look_at = self.area
self.wait_time = 0.5
self.state = self.turn_to_bed_area
def turn_to_bed_area(self):
self.g.look_at = self.area
self.wait_time -= utils.TICK
if self.wait_time <= 0:
self.state = self.place_bed
def place_bed(self):
support = utils.padd(self.area, path.BLOCK_BELOW)
print('Placing bed at', self.area, 'on', support)
self.g.game.place_block(
support, BlockFace.TOP,
hand=self.g.get('holding_hand', 0))
self.my_bed = True
self.wait_time = 0.5
self.state = self.wait_use
def wait_use(self):
if self.wait_time > 0:
self.wait_time -= utils.TICK
return
if self.g.world.block_at(*self.area) not in blocks.BED_IDS:
print('Bed placement was not confirmed at', self.area)
self.bad_areas.append(self.area)
self.my_bed = False
self.state = self.cleanup
return
self.state = self.use_bed
def use_bed(self):
w = self.g.world
current_time = self.g.get('time')
if current_time is None or current_time < 12550:
return
if w.block_at(*self.area) not in blocks.BED_IDS:
print('Bed disappeared before use:', self.area)
self.my_bed = False
self.state = self.cleanup
return
if w.check_bed_occupied(self.area):
print('Bed occupied, aborting.')
self.state = self.cleanup
return
print('Using bed')
self.g.game.place_block(self.area, BlockFace.TOP)
self.sleep_deadline = time.monotonic() + 5.0
self.sleep_confirmed = False
if not self.silent:
self.g.chat.send('zzz')
self.state = self.sleep_bed
def sleep_bed(self):
w = self.g.world
p = utils.pint(self.g.pos)
current_time = self.g.get('time')
threats = w.find_threats(p, 10)
if w.check_bed_occupied(self.area):
self.sleep_confirmed = True
if threats:
print('Waking up due to threats:')
print(threats)
if self.sleep_confirmed:
self.g.game.leave_bed()
self.state = self.cleanup
elif current_time is not None and current_time < 100:
print('Woke up time')
self.state = self.break_bed
elif self.g.get('correction_count', 0) and self.sleep_confirmed:
print('Woke up by movement')
self.state = self.break_bed
elif (not self.sleep_confirmed and
time.monotonic() >= self.sleep_deadline):
print('Bed use was not confirmed')
self.state = self.cleanup
def break_bed(self):
if self.my_bed:
if self.g.game.break_block(self.area):
self.state = self.collect_bed
else:
print('Could not break the placed bed at', self.area)
self.my_bed = False
self.state = self.cleanup
else:
self.state = self.cleanup
def collect_bed(self):
if not self.g.breaking:
self.g.path = [utils.padd(self.area, utils.spiral(n))
for n in range(9)]
self.wait_time = 2
self.collect_deadline = time.monotonic() + 8
self.state = self.wait
def wait(self):
# Finish the short pickup sweep, but don't let it block forever.
if (self.g.path and
time.monotonic() < self.collect_deadline):
return
if self.wait_time > 0:
self.wait_time -= utils.TICK
else:
self.state = self.cleanup
def cleanup(self):
if (self.my_bed and self.area and
self.g.world.block_at(*self.area) in blocks.BED_IDS):
self.state = self.break_bed
return
self.g.look_at = None
self.g.path = []
self.my_bed = False
self.force_new_bed = False
self.state = self.done
if (self.g.get('job') and
getattr(self.g.job.state, '__name__', None) == 'sleep'):
self.g.job.state = self.g.job.idle
def done(self):
# never gets ran, placeholder
return None
def __init__(self, global_state):
self.g = global_state
self.state = self.idle
self.silent = False
self.my_bed = False
self.beds = []
self.bad_beds = []
self.area = None
self.opening = None
self.bad_areas = []
self.wait_time = 0
self.force_new_bed = False
self.sleep_confirmed = False
self.sleep_deadline = 0
def run(self):
self.state()