Reimplement !drain command
This commit is contained in:
+77
-1
@@ -5,7 +5,7 @@ from itertools import count
|
||||
from munch import Munch
|
||||
|
||||
from minecraft.networking.packets import Packet, clientbound, serverbound
|
||||
from minecraft.networking.types import BlockFace
|
||||
from minecraft.networking.types import BlockFace, Byte, Short, VarInt
|
||||
from minecraft.networking.modern import (
|
||||
ClientTickEnd, ContainerClickSwapPacket, PlayerActionPacket,
|
||||
SetCarriedItemPacket, UseItemOnBlockPacket,
|
||||
@@ -33,6 +33,21 @@ from mosfet.info import items
|
||||
from mosfet.info import mcdata
|
||||
from mosfet.info import mobs
|
||||
|
||||
class ContainerClickDropPacket(Packet):
|
||||
"""Drop the full stack in one player-inventory slot (protocol 777)."""
|
||||
id = 0x12
|
||||
packet_name = 'container click drop'
|
||||
|
||||
def write_fields(self, packet_buffer):
|
||||
VarInt.send(self.container_id, packet_buffer)
|
||||
VarInt.send(self.state_id, packet_buffer)
|
||||
Short.send(self.slot, packet_buffer)
|
||||
Byte.send(1, packet_buffer) # drop the whole stack
|
||||
VarInt.send(4, packet_buffer) # ContainerInput.THROW
|
||||
VarInt.send(0, packet_buffer) # no changed-slot predictions
|
||||
VarInt.send(0, packet_buffer) # empty carried item stack
|
||||
|
||||
|
||||
class LegacyGame:
|
||||
def __init__(self, global_state):
|
||||
self.g = global_state
|
||||
@@ -644,7 +659,68 @@ class Game(LegacyGame):
|
||||
self.break_deadline = time.monotonic() + max(0.05, hardness_time)
|
||||
return True
|
||||
|
||||
def start_drain(self):
|
||||
slots = [slot for slot, item in sorted(self.g.inv.items())
|
||||
if 9 <= slot <= 45 and getattr(item, 'present', False)]
|
||||
self.g.drain_slots = slots
|
||||
self.g.drain_waiting = None
|
||||
self.g.drain_dropped = 0
|
||||
self.g.drain_total = len(slots)
|
||||
self.g.drain_error = None
|
||||
self.g.draining = bool(slots)
|
||||
return len(slots)
|
||||
|
||||
def _tick_drain(self):
|
||||
waiting = self.g.get('drain_waiting')
|
||||
if waiting:
|
||||
slot = waiting['slot']
|
||||
state_id = self.g.inventory_state_ids.get(0, 0)
|
||||
if state_id != waiting['state_id']:
|
||||
item = self.g.inv.get(slot)
|
||||
if not item or not getattr(item, 'present', False):
|
||||
self.g.drain_dropped += 1
|
||||
print('[drain] dropped stack from slot {}; {}/{} complete'.format(
|
||||
slot, self.g.drain_dropped, self.g.drain_total), flush=True)
|
||||
self.g.drain_waiting = None
|
||||
else:
|
||||
self.g.drain_error = 'server did not clear inventory slot {}'.format(slot)
|
||||
self.g.draining = False
|
||||
self.g.drain_waiting = None
|
||||
print('[drain] stopped: ' + self.g.drain_error, flush=True)
|
||||
return
|
||||
elif time.monotonic() - waiting['sent_at'] > 3.0:
|
||||
self.g.drain_error = 'timed out waiting for inventory update on slot {}'.format(slot)
|
||||
self.g.draining = False
|
||||
self.g.drain_waiting = None
|
||||
print('[drain] stopped: ' + self.g.drain_error, flush=True)
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
while self.g.drain_slots:
|
||||
slot = self.g.drain_slots.pop(0)
|
||||
item = self.g.inv.get(slot)
|
||||
if not item or not getattr(item, 'present', False):
|
||||
continue
|
||||
state_id = self.g.inventory_state_ids.get(0, 0)
|
||||
packet = ContainerClickDropPacket(
|
||||
container_id=0, state_id=state_id, slot=slot)
|
||||
self.g.connection.write_packet(packet, force=True)
|
||||
self.g.connection.write_packet(ClientTickEnd(), force=True)
|
||||
self.g.drain_waiting = {
|
||||
'slot': slot, 'state_id': state_id,
|
||||
'item_count': item.item_count, 'sent_at': time.monotonic(),
|
||||
}
|
||||
return
|
||||
|
||||
self.g.draining = False
|
||||
self.g.drain_waiting = None
|
||||
print('[drain] complete: dropped {} stacks'.format(
|
||||
self.g.drain_dropped), flush=True)
|
||||
|
||||
def tick(self):
|
||||
if self.g.get('draining'):
|
||||
self._tick_drain()
|
||||
if not self.g.get('breaking') or self.break_deadline is None:
|
||||
return
|
||||
if time.monotonic() < self.break_deadline:
|
||||
|
||||
Reference in New Issue
Block a user