From 25ce916b437a1470fc949913b868abab17129532 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Fri, 25 Sep 2020 00:03:22 -0600 Subject: [PATCH] Add a job to find enchanted golden apples --- blocks.py | 9 +++++ bot.py | 4 +- game.py | 33 ++++++++++++++-- items.py | 2 + jobs.py | 93 ++++++++++++++++++++++++++++++++++++++++++++ main.py | 2 + protocol/managers.py | 20 +++++++++- protocol/packets.py | 2 +- protocol/types.py | 8 ++-- utils.py | 1 - 10 files changed, 163 insertions(+), 11 deletions(-) diff --git a/blocks.py b/blocks.py index 6eaa4ba..1937048 100644 --- a/blocks.py +++ b/blocks.py @@ -214,6 +214,10 @@ LEAVES = [ 'dark_oak_leaves', ] +CHESTS = [ + 'chest', +] + INDEXED = [ 'chest', ] @@ -239,6 +243,11 @@ for block_name in LEAVES: for state in JSON_BLOCKS['minecraft:' + block_name]['states']: LEAF_IDS.add(state['id']) +CHEST_IDS = set() +for block_name in CHESTS: + for state in JSON_BLOCKS['minecraft:' + block_name]['states']: + CHEST_IDS.add(state['id']) + INDEXED_IDS = set() for block_name in INDEXED: for state in JSON_BLOCKS['minecraft:' + block_name]['states']: diff --git a/bot.py b/bot.py index 25ebf88..a92ec90 100644 --- a/bot.py +++ b/bot.py @@ -156,6 +156,7 @@ def init(global_state): g.dumping = None g.item_lock = False + g.command_lock = False g.window = None @@ -193,8 +194,7 @@ def bot(global_state): time.sleep(utils.TICK) print('Player loaded.') - x, y, z = utils.pint(g.pos) - while (floor(x/16), floor(y/16), floor(z/16)) not in g.chunks.chunks: + while not g.chunks.check_loaded(g.pos): time.sleep(utils.TICK) print('Chunks loaded.') diff --git a/game.py b/game.py index 581c351..d8c35ba 100644 --- a/game.py +++ b/game.py @@ -249,6 +249,11 @@ class Game: source, text = message reply = None + if source == 'SYSTEM': + print('unlocking command...') + self.g.command_lock = False + return + match = re.match(r'<(\w+)> (.*)', text) if match: sender, text = match.groups() @@ -267,6 +272,7 @@ class Game: data = text.split(' ', 1)[1] else: command = text + data = None if command == 'ping': reply = 'pong' @@ -370,6 +376,12 @@ class Game: if command == 'loaded': reply = str(self.g.chunks.get_loaded_area()) + if command == 'gapple': + self.g.job.state = self.g.job.find_gapple + if data: + self.g.job.find_gapple_states.count = int(data) + reply = 'ok' + if reply: print(reply) self.g.chat.send(reply) @@ -513,13 +525,28 @@ class Game: self.g.connection.write_packet(packet2) def handle_spawn_object(self, packet): + return if packet.type_id != 37: return print(packet) def handle_entity_metadata(self, packet): - return - if packet.metadata and packet.metadata[0].index != 7: return - print(packet) + if not packet.metadata: + return + + if not self.g.job: + return + + current_chest = self.g.job.find_gapple_states.current_chest + if not current_chest: + return + + for entry in packet.metadata: + if entry.type != 6: + continue + + if entry.value.item_id in items.GAPPLE_ID: + self.g.chat.send('gapple found: ' + str(current_chest)[1:-1]) + def handle_spawn_living(self, packet): return diff --git a/items.py b/items.py index c02a818..db56616 100644 --- a/items.py +++ b/items.py @@ -32,4 +32,6 @@ for item_name, item in ITEMS.items(): CHEST_ID = set([ITEMS['minecraft:chest']['protocol_id']]) +GAPPLE_ID = set([ITEMS['minecraft:enchanted_golden_apple']['protocol_id']]) + USEFUL_ITEMS = BED_IDS | CHEST_ID diff --git a/jobs.py b/jobs.py index 1d68e9d..dff40d3 100644 --- a/jobs.py +++ b/jobs.py @@ -7,6 +7,8 @@ from panda3d.core import LPoint3f from minecraft.networking.types import BlockFace +from protocol.managers import ChunkNotLoadedException + import utils importlib.reload(utils) import path @@ -19,6 +21,85 @@ import data importlib.reload(data) +class FindGappleStates: + def idle(self): + return None + + def init(self): + self.state = self.go_spectator + + def go_spectator(self): + print('Going spectator...') + self.g.chat.send('/gamemode spectator') + + self.state = self.tp_to_coord + + def tp_to_coord(self): + step = utils.spiral(self.count) + step_scaled = utils.pmul(step, 192) + self.coord = utils.padd(self.origin, step_scaled) + self.coord = utils.padd(self.coord, (0, 50, 0)) + + print('count:', self.count, 'teleporting to:', self.coord) + self.g.chat.send('/tp {} {} {}'.format(*self.coord)) + + self.state = self.wait_for_load + + def wait_for_load(self): + if self.g.chunks.check_loaded(self.g.pos): + print('chunks have been loaded') + self.state = self.pick_chest + + def pick_chest(self): + chest_list = [] + for chest_id in blocks.CHEST_IDS: + chest_list.extend(self.g.chunks.index.get(chest_id, [])) + + for chest in chest_list: + if chest in self.checked_chests: continue + + self.current_chest = chest + self.state = self.break_chest + break + else: # for + print('exhausted chest list') + self.state = self.cleanup + + def break_chest(self): + print('Breaking chest', self.current_chest) + self.g.command_lock = True + self.g.chat.send('/setblock {} {} {} air destroy'.format(*self.current_chest)) + self.checked_chests.append(self.current_chest) + + self.state = self.wait_for_items + + def wait_for_items(self): + if not self.g.command_lock: + print('done waiting for items') + self.state = self.pick_chest + + def cleanup(self): + self.count += 1 + self.state = self.done + + def done(self): + # never gets ran, placeholder + return None + + def __init__(self, global_state): + self.g = global_state + self.state = self.idle + + self.origin = utils.pint(self.g.pos) + self.count = 0 + self.coord = None + self.current_chest = None + self.checked_chests = [] + + def run(self): + self.state() + + class LumberjackStates: def bair(self, p): return self.g.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS @@ -515,6 +596,16 @@ class JobStates: def idle(self): return None + def find_gapple(self): + s1 = self.find_gapple_states + + if s1.state == s1.idle: + s1.state = s1.init + elif s1.state == s1.done: + s1.state = s1.init + + s1.run() + def gather_sand(self): s1 = self.gather_sand_states s2 = self.sleep_with_bed_states @@ -570,6 +661,7 @@ class JobStates: self.gather_sand_states = GatherSandStates(self.g) self.sleep_with_bed_states = SleepWithBedStates(self.g) self.cache_items_states = CacheItemsStates(self.g) + self.find_gapple_states = FindGappleStates(self.g) self.state = self.idle def __init__(self, global_state): @@ -581,6 +673,7 @@ class JobStates: self.gather_sand_states = GatherSandStates(self.g) self.sleep_with_bed_states = SleepWithBedStates(self.g) self.cache_items_states = CacheItemsStates(self.g) + self.find_gapple_states = FindGappleStates(self.g) def tick(self): self.state() diff --git a/main.py b/main.py index 07a7df5..ecb8bfb 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,8 @@ g.connection = False g.mcdata = False g.pos = False g.inv = {} +g.window = None +g.job = None @app.route('/') def hello_world(): diff --git a/protocol/managers.py b/protocol/managers.py index 0224326..4cc4d1e 100644 --- a/protocol/managers.py +++ b/protocol/managers.py @@ -5,6 +5,8 @@ import json from minecraft.networking.packets import clientbound, serverbound from protocol import packets +import utils + class DataManager: def __init__(self, directory): self.blocks = {} @@ -80,7 +82,8 @@ class ChunksManager: def get_chunk(self, x, y, z): index = (x, y, z) if not index in self.chunks: - raise ChunkNotLoadedException(index) + return None + #raise ChunkNotLoadedException(index) return self.chunks[index] def get_loaded_area(self, ignore_empty=False): @@ -101,12 +104,27 @@ class ChunksManager: def get_block_at(self, x, y, z): c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) + if not c: return None return c.get_block_at(x%16, y%16, z%16) def set_block_at(self, x, y, z, block): c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) + if not c: return None c.set_block_at(x%16, y%16, z%16, block) + def check_loaded(self, position): + #for i in range(441): # TODO: base off render_distance? + x, y, z = utils.pint(position) + player_chunk = (x//16, 1, z//16) + for i in range(121): # TODO: base off render_distance? + offset = utils.spiral(i) + check = utils.padd(player_chunk, offset) + + if check not in self.chunks: + return False + + return True + class ChunkNotLoadedException(Exception): def __str__(self): diff --git a/protocol/packets.py b/protocol/packets.py index 5175c33..986e5e1 100644 --- a/protocol/packets.py +++ b/protocol/packets.py @@ -312,7 +312,7 @@ class EntityMetadataPacket(Packet): self.entity_id = VarInt.read(file_object) self.metadata = [] for _ in range(99): - entry = Entry.read(file_object) + entry = Entry.read(file_object, self.context) if not entry: break self.metadata.append(entry) diff --git a/protocol/types.py b/protocol/types.py index b66b813..ea1744a 100644 --- a/protocol/types.py +++ b/protocol/types.py @@ -133,7 +133,7 @@ class Slot(Type): Boolean.send(value.present, socket) VarInt.send(value.item_id, socket) Byte.send(value.item_count, socket) - TrailingByteArray.send(value.nbt, socket) + Byte.send(0x00, socket) class Entry(Type): @@ -157,16 +157,18 @@ class Entry(Type): def __str__(self): return str(self.__dict__) def __repr__(self): - return 'Entry(index={}, type={}, value={}'.format( + return 'Entry(index={}, type={}, value={})'.format( self.index, self.type, self.value) @staticmethod - def read(file_object): + def read(file_object, context): index = UnsignedByte.read(file_object) if index == 0xff: return None type = VarInt.read(file_object) try: value = Entry.types[type].read(file_object) + except TypeError: + value = Entry.types[type].read_with_context(file_object, context) except KeyError: return None return Entry(index, type, value) diff --git a/utils.py b/utils.py index 166de3f..a5fec16 100644 --- a/utils.py +++ b/utils.py @@ -90,4 +90,3 @@ def break_time(block_id, held_item=0, in_water=False, on_ground=True, enchantmen if not on_ground: time *= 5.0 return time -