Compare commits

...

2 Commits

7 changed files with 169 additions and 134 deletions

27
bot.py
View File

@ -20,7 +20,7 @@ from minecraft.networking.connection import Connection
from minecraft.networking.packets import Packet, clientbound, serverbound from minecraft.networking.packets import Packet, clientbound, serverbound
from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException
from protocol.packets import BlockChangePacket from protocol.packets import TimeUpdatePacket, SetSlotPacket
from bunch import Bunch from bunch import Bunch
from panda3d.core import LPoint3f, LVector3f from panda3d.core import LPoint3f, LVector3f
@ -185,18 +185,27 @@ def bot(global_state):
g.chunks.register(g.connection) g.chunks.register(g.connection)
h1 = packet_wrapper(packet_handlers.handle_join_game) def x(p):
g.connection.register_packet_listener(h1, clientbound.play.JoinGamePacket) print(p)
h2 = packet_wrapper(packet_handlers.handle_position_and_look) h = packet_wrapper(packet_handlers.handle_block_change)
g.connection.register_packet_listener(h2, clientbound.play.PlayerPositionAndLookPacket) g.connection.register_packet_listener(h, clientbound.play.BlockChangePacket)
h3 = packet_wrapper(packet_handlers.handle_block_change) h = packet_wrapper(packet_handlers.handle_join_game)
g.connection.register_packet_listener(h3, BlockChangePacket) g.connection.register_packet_listener(h, clientbound.play.JoinGamePacket)
h = packet_wrapper(packet_handlers.handle_position_and_look)
g.connection.register_packet_listener(h, clientbound.play.PlayerPositionAndLookPacket)
g.chat = ChatManager(g) g.chat = ChatManager(g)
h4 = packet_wrapper(packet_handlers.handle_chat) h = packet_wrapper(packet_handlers.handle_chat)
g.chat.set_handler(h4) g.chat.set_handler(h)
h = packet_wrapper(packet_handlers.handle_time_update)
g.connection.register_packet_listener(h, TimeUpdatePacket)
h = packet_wrapper(packet_handlers.handle_set_slot)
g.connection.register_packet_listener(h, SetSlotPacket)
try: try:
while not g.pos: while not g.pos:

View File

@ -18,6 +18,7 @@ g.local_state = False
g.connection = False g.connection = False
g.mcdata = False g.mcdata = False
g.pos = False g.pos = False
g.inv = {}
@app.route('/') @app.route('/')
def hello_world(): def hello_world():
@ -54,6 +55,7 @@ def main():
print('Locking...') print('Locking...')
while g.running: while g.running:
time.sleep(1) time.sleep(1)
importlib.reload(bot)
except KeyboardInterrupt: except KeyboardInterrupt:
observer.stop() observer.stop()
observer.join() observer.join()

View File

@ -8,8 +8,13 @@ def get_packets(old_get_packets):
# add any custom packets here # add any custom packets here
mc_packets.add(packets.ChunkDataPacket) mc_packets.add(packets.ChunkDataPacket)
mc_packets.add(packets.BlockChangePacket) mc_packets.add(packets.AcknowledgePlayerDiggingPacket)
mc_packets.add(packets.MultiBlockChangePacket) mc_packets.add(packets.BlockBreakAnimationPacket)
mc_packets.add(packets.SetSlotPacket)
mc_packets.add(packets.TimeUpdatePacket)
mc_packets.add(packets.PlayerDiggingPacket)
mc_packets.add(packets.PickItemPacket)
mc_packets.add(packets.HeldItemChangePacket)
return mc_packets return mc_packets
return lambda x: wrapper(old_get_packets, x) return lambda x: wrapper(old_get_packets, x)

View File

@ -97,3 +97,15 @@ def handle_chat(message, g):
if reply: if reply:
print(reply) print(reply)
g.chat.send(reply) g.chat.send(reply)
def handle_time_update(packet, g):
l = g.local_state
l.time = packet.time_of_day % 24000
def handle_set_slot(packet, g):
print(packet)
if packet.window_id == 0:
g.inv[packet.slot] = packet.slot_data

View File

@ -43,12 +43,13 @@ class ChunksManager:
def handle_block(self, block_packet): def handle_block(self, block_packet):
self.set_block_at(block_packet.location.x, block_packet.location.y, block_packet.location.z, block_packet.block_state_id) self.set_block_at(block_packet.location.x, block_packet.location.y, block_packet.location.z, block_packet.block_state_id)
#self.print_chunk(self.get_chunk(floor(block_packet.location.x/16), floor(block_packet.location.y/16), floor(block_packet.location.z/16)), block_packet.location.y%16)
#print('Block %s at %s'%(blocks_states[block_packet.block_state_id], block_packet.location))
def handle_multiblock(self, multiblock_packet): def handle_multiblock(self, multiblock_packet):
dx = 16 * multiblock_packet.chunk_section_pos.x
dy = 16 * multiblock_packet.chunk_section_pos.y
dz = 16 * multiblock_packet.chunk_section_pos.z
for b in multiblock_packet.records: for b in multiblock_packet.records:
self.handle_block(b) self.set_block_at(dx+b.x, dy+b.y, dz+b.z, b.block_state_id)
def handle_chunk(self, chunk_packet): def handle_chunk(self, chunk_packet):
for i in chunk_packet.chunks: for i in chunk_packet.chunks:
@ -56,8 +57,8 @@ class ChunksManager:
self.biomes[(chunk_packet.x, None, chunk_packet.z)] = chunk_packet.biomes # FIXME self.biomes[(chunk_packet.x, None, chunk_packet.z)] = chunk_packet.biomes # FIXME
def register(self, connection): def register(self, connection):
connection.register_packet_listener(self.handle_block, packets.BlockChangePacket) connection.register_packet_listener(self.handle_block, clientbound.play.BlockChangePacket)
connection.register_packet_listener(self.handle_multiblock, packets.MultiBlockChangePacket) connection.register_packet_listener(self.handle_multiblock, clientbound.play.MultiBlockChangePacket)
connection.register_packet_listener(self.handle_chunk, packets.ChunkDataPacket) connection.register_packet_listener(self.handle_chunk, packets.ChunkDataPacket)
def get_chunk(self, x, y, z): def get_chunk(self, x, y, z):

View File

@ -1,124 +1,13 @@
from math import floor from math import floor
from minecraft.networking.packets import Packet, PacketBuffer from minecraft.networking.packets import Packet, PacketBuffer
from minecraft.networking.types import (
VarInt, Integer, Boolean, UnsignedByte, Long, Short,
multi_attribute_alias, Vector, UnsignedLong
)
from protocol.types import Nbt
from minecraft.networking.packets import Packet
from minecraft.networking.types import ( from minecraft.networking.types import (
VarInt, Integer, UnsignedByte, Position, Vector, MutableRecord, VarInt, Integer, UnsignedByte, Position, Vector, MutableRecord,
attribute_alias, multi_attribute_alias, Long, Boolean, VarLong, attribute_alias, multi_attribute_alias, Long, Boolean, VarLong,
Short, UnsignedLong, Byte, BlockFace,
) )
from protocol.types import Nbt, Slot
class BlockChangePacket(Packet):
id = 0x0B
packet_name = 'block change'
definition = [
{'location': Position},
{'block_state_id': VarInt}]
block_state_id = 0
# For protocols < 347: an accessor for (block_state_id >> 4).
@property
def blockId(self):
return self.block_state_id >> 4
@blockId.setter
def blockId(self, block_id):
self.block_state_id = (self.block_state_id & 0xF) | (block_id << 4)
# For protocols < 347: an accessor for (block_state_id & 0xF).
@property
def blockMeta(self):
return self.block_state_id & 0xF
@blockMeta.setter
def blockMeta(self, meta):
self.block_state_id = (self.block_state_id & ~0xF) | (meta & 0xF)
# This alias is retained for backward compatibility.
blockStateId = attribute_alias('block_state_id')
class MultiBlockChangePacket(Packet):
id = 0x3B
packet_name = 'multi block change'
fields = 'chunk_x', 'chunk_z', 'records'
# Access the 'chunk_x' and 'chunk_z' fields as a tuple.
chunk_pos = multi_attribute_alias(tuple, 'chunk_x', 'chunk_z')
class Record(MutableRecord):
__slots__ = 'x', 'y', 'z', 'block_state_id', 'location'
def __init__(self, **kwds):
self.block_state_id = 0
super(MultiBlockChangePacket.Record, self).__init__(**kwds)
# Access the 'x', 'y', 'z' fields as a Vector of ints.
position = multi_attribute_alias(Vector, 'x', 'y', 'z')
# For protocols < 347: an accessor for (block_state_id >> 4).
@property
def blockId(self):
return self.block_state_id >> 4
@blockId.setter
def blockId(self, block_id):
self.block_state_id = self.block_state_id & 0xF | block_id << 4
# For protocols < 347: an accessor for (block_state_id & 0xF).
@property
def blockMeta(self):
return self.block_state_id & 0xF
@blockMeta.setter
def blockMeta(self, meta):
self.block_state_id = self.block_state_id & ~0xF | meta & 0xF
# This alias is retained for backward compatibility.
blockStateId = attribute_alias('block_state_id')
def read(self, file_object, parent):
data = VarLong.read(file_object)
self.block_state_id = int(data >> 12)
self.x = int(data >> 8 & 0xf)
self.z = int(data >> 4 & 0xf)
self.y = int(data & 0xf)
# Absolute position in world to be compatible with BlockChangePacket
self.location = Vector(self.position.x + parent.chunk_x*16, self.position.y, self.position.z + parent.chunk_z*16)
def write(self, packet_buffer):
raise
UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer)
UnsignedByte.send(self.y, packet_buffer)
VarInt.send(self.block_state_id, packet_buffer)
def read(self, file_object):
coords = Long.read(file_object)
self.chunk_x = int(coords >> 42 & 0x3fffff)
self.chunk_z = int(coords >> 20 & 0x3fffff)
self.chunk_y = int(coords & 0xfffff)
self.unknown = Boolean.read(file_object)
array_size = VarInt.read(file_object)
self.records = []
for i in range(array_size):
record = self.Record()
record.read(file_object, self)
self.records.append(record)
def write_fields(self, packet_buffer):
raise
Integer.send(self.chunk_x, packet_buffer)
Integer.send(self.chunk_z, packet_buffer)
VarInt.send(len(self.records), packet_buffer)
for record in self.records:
record.write(packet_buffer)
class ChunkDataPacket(Packet): class ChunkDataPacket(Packet):
@ -176,9 +65,7 @@ class ChunkDataPacket(Packet):
y = e['y'] y = e['y']
self.chunks[floor(y/16)].entities.append(e) self.chunks[floor(y/16)].entities.append(e)
class Chunk: class Chunk:
position = multi_attribute_alias(Vector, 'x', 'y', 'z') position = multi_attribute_alias(Vector, 'x', 'y', 'z')
def __init__(self, x, y, z, empty=True): def __init__(self, x, y, z, empty=True):
@ -246,3 +133,87 @@ class Chunk:
def origin(self): def origin(self):
return self.position*16 return self.position*16
class AcknowledgePlayerDiggingPacket(Packet):
id = 0x07
packet_name = 'acknowledge player digging'
definition = [
{'location': Position},
{'block': VarInt},
{'status': VarInt},
{'successful': Boolean},
]
class BlockBreakAnimationPacket(Packet):
id = 0x08
packet_name = 'block break animation'
definition = [
{'entity_id': VarInt},
{'location': Position},
{'destroy_stage': Byte},
]
class SetSlotPacket(Packet):
id = 0x15
packet_name = 'set slot'
definition = [
{'window_id': Byte},
{'slot': Short},
{'slot_data': Slot},
]
class TimeUpdatePacket(Packet):
id = 0x4E
packet_name = 'time update'
definition = [
{'world_age': Long},
{'time_of_day': Long},
]
class PlayerDiggingPacket(Packet):
# used when player mines / breaks blocks
# https://wiki.vg/Protocol#Player_Digging
id = 0x1B
packet_name = 'player digging'
definition = [
{'status': VarInt},
{'location': Position},
{'face': VarInt},
]
STARTED = 0
CANCELLED = 1
FINISHED = 2
# PlayerBlockPlacementPacket.Face is an alias for BlockFace.
Face = BlockFace
class PickItemPacket(Packet):
# used when player picks item (middle click)
# https://wiki.vg/Protocol#Pick_Item
id = 0x18
packet_name = 'pick item'
definition = [
{'slot_to_use': VarInt},
]
class HeldItemChangePacket(Packet):
# Sent when the player changes the slot selection
# https://wiki.vg/Protocol#Held_Item_Change_.28serverbound.29
id = 0x25
packet_name = 'held item change'
definition = [
{'slot': Short},
]

View File

@ -1,11 +1,12 @@
from __future__ import division from __future__ import division
from minecraft.networking.types.basic import Type, Byte, Short, Integer, Long, Float, Double, ShortPrefixedByteArray
import struct import struct
from minecraft.networking.types.basic import (
Type, Byte, Short, Integer, Long, Float, Double,
ShortPrefixedByteArray, Boolean, VarInt, TrailingByteArray
)
from minecraft.networking.types.utility import Vector from minecraft.networking.types.utility import Vector
from minecraft.networking.types.basic import Type, Byte, Short, Integer, Long, Float, Double, ShortPrefixedByteArray
class IntegerPrefixedByteArray(Type): class IntegerPrefixedByteArray(Type):
@ -19,6 +20,7 @@ class IntegerPrefixedByteArray(Type):
Integer.send(len(value), socket) Integer.send(len(value), socket)
socket.send(value) socket.send(value)
TAG_End = 0 TAG_End = 0
TAG_Byte = 1 TAG_Byte = 1
TAG_Short = 2 TAG_Short = 2
@ -96,3 +98,36 @@ class Nbt(Type):
def send(value, socket): def send(value, socket):
# TODO # TODO
pass pass
class Slot(Type):
def __init__(self, present, item_id, item_count, nbt):
self.present = present
self.item_id = item_id
self.item_count = item_count
self.nbt = nbt
def __str__(self):
return str(self.__dict__)
def __repr__(self):
return 'Slot(present={}, item_id={}, item_count={}, nbt={}'.format(
self.present, self.item_id, self.item_count, self.nbt)
@staticmethod
def read(file_object):
present = Boolean.read(file_object)
item_id = VarInt.read(file_object) if present else None
item_count = Byte.read(file_object) if present else None
nbt = TrailingByteArray.read(file_object) if present else None
return Slot(present, item_id, item_count, nbt)
#a = {}
#a['present'] = Boolean.read(file_object)
#a['item_id'] = VarInt.read(file_object) if a['present'] else None
#a['item_count'] = Byte.read(file_object) if a['present'] else None
#a['nbt'] = TrailingByteArray.read(file_object) if a['present'] else None
#return a
@staticmethod
def send(value, socket):
# TODO
pass