Implement 26.3 bed sleeping

This commit is contained in:
Tanner
2026-11-04 19:20:15 +00:00
parent 9fd565c3c9
commit 1ecec547ae
10 changed files with 404 additions and 75 deletions
+121 -41
View File
@@ -21,12 +21,18 @@ class SleepWithBedStates:
return None
def init(self):
if self.g.time < 12000:
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.dimension != 'overworld':
if self.g.get('dimension') != 'overworld':
print('Aborting sleep, not in overworld')
self.state = self.cleanup
return
@@ -38,7 +44,10 @@ class SleepWithBedStates:
w = self.g.world
p = utils.pint(self.g.pos)
result = w.find_blocks_indexed(p, blocks.BED_IDS, 80)
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:
@@ -57,38 +66,39 @@ class SleepWithBedStates:
print('Choosing a bed...')
w = self.g.world
p = utils.pint(self.g.pos)
c = self.g.chunks
if not len(self.beds):
print('No beds')
self.state = self.select_bed
return
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
bed = self.beds[0]
print('Chose:', bed)
navpath = w.path_to_place_faked(p, bed)
print('navpath:', navpath)
if navpath:
self.g.path = navpath[:-1]
self.opening = self.g.path[-1]
self.g.look_at = self.opening
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
else:
self.beds.pop(0)
self.bad_beds.append(bed)
print('Cant get to bed, blacklisting')
time.sleep(0.1)
self.state = self.select_bed
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 = utils.padd(self.area, path.BLOCK_BELOW)
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):
@@ -116,9 +126,24 @@ class SleepWithBedStates:
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: break
if navpath is not None:
break
else: # for
print('Unable to get to bed area', self.area)
self.bad_areas.append(self.area)
@@ -126,35 +151,57 @@ class SleepWithBedStates:
return
self.g.path = navpath
self.g.look_at = self.opening
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 = utils.padd(self.area, path.BLOCK_BELOW)
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):
print('Placing bed')
self.g.game.place_block(self.area, BlockFace.TOP)
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):
# wait to use the bed
if self.wait_time > 0:
self.wait_time -= utils.TICK
else:
self.state = self.use_bed
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 self.g.time < 12550:
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
@@ -162,6 +209,8 @@ class SleepWithBedStates:
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
@@ -169,43 +218,71 @@ class SleepWithBedStates:
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)
self.g.game.leave_bed()
if self.sleep_confirmed:
self.g.game.leave_bed()
self.state = self.cleanup
elif self.g.time < 100:
elif current_time is not None and current_time < 100:
print('Woke up time')
self.state = self.break_bed
elif self.g.correction_count:
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:
self.g.game.break_block(self.area)
self.state = self.collect_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.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):
# wait to pick up bed
# 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
@@ -224,6 +301,9 @@ class SleepWithBedStates:
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()