Move command processing to separate file
This commit is contained in:
		@@ -24,6 +24,7 @@ from mosfet.protocol.managers import DataManager, ChunksManager, ChatManager, Ch
 | 
			
		||||
 | 
			
		||||
from munch import Munch
 | 
			
		||||
 | 
			
		||||
from mosfet import commands
 | 
			
		||||
from mosfet import game
 | 
			
		||||
from mosfet import job
 | 
			
		||||
from mosfet import path
 | 
			
		||||
@@ -38,6 +39,7 @@ from mosfet.info import mobs
 | 
			
		||||
 | 
			
		||||
for module in [
 | 
			
		||||
    blocks,
 | 
			
		||||
    commands,
 | 
			
		||||
    game,
 | 
			
		||||
    items,
 | 
			
		||||
    job,
 | 
			
		||||
@@ -267,6 +269,7 @@ def bot(global_state):
 | 
			
		||||
 | 
			
		||||
    g.game = game.Game(g)
 | 
			
		||||
    g.world = world.World(g)
 | 
			
		||||
    g.commands = commands.Commands(g)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        while not g.pos:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										524
									
								
								mosfet/commands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										524
									
								
								mosfet/commands.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,524 @@
 | 
			
		||||
import re
 | 
			
		||||
import time
 | 
			
		||||
import random
 | 
			
		||||
from math import hypot
 | 
			
		||||
from itertools import count
 | 
			
		||||
from munch import Munch
 | 
			
		||||
 | 
			
		||||
from mosfet.protocol.types import Slot
 | 
			
		||||
 | 
			
		||||
from mosfet import print_help
 | 
			
		||||
from mosfet import utils
 | 
			
		||||
from mosfet import path
 | 
			
		||||
from mosfet import bot
 | 
			
		||||
from mosfet.info import blocks
 | 
			
		||||
from mosfet.info import items
 | 
			
		||||
from mosfet.info import mobs
 | 
			
		||||
 | 
			
		||||
class Commands:
 | 
			
		||||
    def __init__(self, global_state):
 | 
			
		||||
        self.g = global_state
 | 
			
		||||
 | 
			
		||||
        self.g.chat.set_handler(self.handle_chat)
 | 
			
		||||
 | 
			
		||||
    def handle_chat(self, message):
 | 
			
		||||
        source, text = message
 | 
			
		||||
        reply = None
 | 
			
		||||
        private = False
 | 
			
		||||
        for_me = False
 | 
			
		||||
        authed = False
 | 
			
		||||
 | 
			
		||||
        if source == 'SYSTEM':
 | 
			
		||||
            self.g.command_lock = False
 | 
			
		||||
 | 
			
		||||
        if text == 'You are now AFK.':
 | 
			
		||||
            self.g.afk = True
 | 
			
		||||
        elif text == 'You are no longer AFK.':
 | 
			
		||||
            self.g.afk = False
 | 
			
		||||
 | 
			
		||||
        match1 = re.match(r'<?(\w+)> (.*)', text)
 | 
			
		||||
        match2 = re.match(r'\[(\w+) -> me] (.*)', text)
 | 
			
		||||
        if match1:
 | 
			
		||||
            sender, text = match1.groups()
 | 
			
		||||
        elif match2:
 | 
			
		||||
            sender, text = match2.groups()
 | 
			
		||||
            private = True
 | 
			
		||||
        else:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if sender == 'tanner6':
 | 
			
		||||
            authed = True
 | 
			
		||||
 | 
			
		||||
        if text.startswith('zzz'):
 | 
			
		||||
            text = '!zzz'
 | 
			
		||||
 | 
			
		||||
        bot_num = self.g.name[-1]
 | 
			
		||||
 | 
			
		||||
        if text.startswith(bot_num):
 | 
			
		||||
            text = text[1:]
 | 
			
		||||
            for_me = True
 | 
			
		||||
        elif text.startswith('! '):
 | 
			
		||||
            text = text[2:]
 | 
			
		||||
        elif text.startswith('!'):
 | 
			
		||||
            text = text[1:]
 | 
			
		||||
        else:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if ' ' in text:
 | 
			
		||||
            command = text.split(' ', 1)[0]
 | 
			
		||||
            data = text.split(' ', 1)[1]
 | 
			
		||||
        else:
 | 
			
		||||
            command = text
 | 
			
		||||
            data = None
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
 | 
			
		||||
            ## ### Public Commands
 | 
			
		||||
            ## These can be ran by anyone, all bots will reply.
 | 
			
		||||
 | 
			
		||||
            ## !help - prints this whole help message to console
 | 
			
		||||
            ## !help [command] - replies in-game explaining command
 | 
			
		||||
            if command == 'help':
 | 
			
		||||
                if data:
 | 
			
		||||
                    for line in print_help.HELP_LINES:
 | 
			
		||||
                        if line[1:].startswith(data) or line[1:].startswith(data[1:]):
 | 
			
		||||
                            reply = 'command ' + line
 | 
			
		||||
                            break
 | 
			
		||||
                    else:  # for
 | 
			
		||||
                        reply = 'command not found'
 | 
			
		||||
                else:
 | 
			
		||||
                    print()
 | 
			
		||||
                    print()
 | 
			
		||||
                    for line in print_help.HELP_LINES:
 | 
			
		||||
                        print(line)
 | 
			
		||||
                    reply = 'check console'
 | 
			
		||||
 | 
			
		||||
            ## !ping - replies with "pong"
 | 
			
		||||
            if command == 'ping':
 | 
			
		||||
                reply = 'pong'
 | 
			
		||||
 | 
			
		||||
            ## !echo [data] - replies with "data"
 | 
			
		||||
            if command == 'echo' and data:
 | 
			
		||||
                reply = data
 | 
			
		||||
 | 
			
		||||
            ## !pos - replies with position and dimension
 | 
			
		||||
            if command == 'pos':
 | 
			
		||||
                reply = str(utils.pint(self.g.pos))[1:-1] + ', ' + self.g.dimension
 | 
			
		||||
 | 
			
		||||
            ## !afk - goes AFK with /afk
 | 
			
		||||
            if command == 'afk':
 | 
			
		||||
                if not self.g.afk:
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
 | 
			
		||||
            ## !unafk - goes not AFK with /afk
 | 
			
		||||
            if command == 'unafk':
 | 
			
		||||
                if self.g.afk:
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
 | 
			
		||||
            ## !error - raises an error
 | 
			
		||||
            if command == 'error':
 | 
			
		||||
                reply = 'ok'
 | 
			
		||||
                raise
 | 
			
		||||
 | 
			
		||||
            ## !inv - prints current inventory
 | 
			
		||||
            if command == 'inv':
 | 
			
		||||
                inv_list = []
 | 
			
		||||
                for i in self.g.inv.values():
 | 
			
		||||
                    if i.present:
 | 
			
		||||
                        inv_list.append('{}:{} x {}'.format(items.ITEM_NAMES[i.item_id], str(i.item_id), i.item_count))
 | 
			
		||||
                inv_list.sort()
 | 
			
		||||
                result = '\n'.join(inv_list)
 | 
			
		||||
                print(result or 'Empty')
 | 
			
		||||
 | 
			
		||||
            ## !time - replies with Minecraft world time
 | 
			
		||||
            if command == 'time':
 | 
			
		||||
                reply = str(self.g.time)
 | 
			
		||||
 | 
			
		||||
            ## !count [id] - counts the number of items with that id
 | 
			
		||||
            if command == 'count' and data:
 | 
			
		||||
                item = int(data)
 | 
			
		||||
                reply = str(self.g.game.count_items([item]))
 | 
			
		||||
 | 
			
		||||
            ## !loaded - replies with the current loaded area
 | 
			
		||||
            if command == 'loaded':
 | 
			
		||||
                reply = str(self.g.chunks.get_loaded_area())
 | 
			
		||||
 | 
			
		||||
            ## !players - prints the current players
 | 
			
		||||
            ## !players clear - clears the current player list
 | 
			
		||||
            if command == 'players':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.players = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    for k, v in self.g.players.items():
 | 
			
		||||
                        print(str(k) + ':', v, self.g.player_names[v.player_uuid])
 | 
			
		||||
 | 
			
		||||
            ## !objects - prints the current items on ground
 | 
			
		||||
            ## !objects clear - clears the current object list
 | 
			
		||||
            if command == 'objects':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.objects = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    for k, v in self.g.objects.items():
 | 
			
		||||
                        if data and v.item_id != int(data): continue
 | 
			
		||||
                        print(str(k) + ':', v, items.ITEM_NAMES[v.item_id])
 | 
			
		||||
 | 
			
		||||
            ## !mobs - prints the current mobs
 | 
			
		||||
            ## !mobs clear - clears the current mob list
 | 
			
		||||
            if command == 'mobs':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.mobs = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    all_mobs = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                    for k, v in all_mobs:
 | 
			
		||||
                        if data and v.type != int(data): continue
 | 
			
		||||
                        print(str(k) + ':', v, mobs.MOB_NAMES[v.type])
 | 
			
		||||
                    reply = str(len(all_mobs)) + ' mobs'
 | 
			
		||||
 | 
			
		||||
            ## !monsters - prints the current monsters
 | 
			
		||||
            if command == 'monsters':
 | 
			
		||||
                monsters = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                count = 0
 | 
			
		||||
                for k, v in monsters:
 | 
			
		||||
                    if v.type not in mobs.EVIL_IDS: continue
 | 
			
		||||
                    if data and v.type != int(data): continue
 | 
			
		||||
                    count += 1
 | 
			
		||||
                    print(str(k) + ':', v, mobs.MOB_NAMES[v.type])
 | 
			
		||||
                reply = str(count) + ' monsters'
 | 
			
		||||
 | 
			
		||||
            ## !villagers - prints the current villagers
 | 
			
		||||
            if command == 'villagers':
 | 
			
		||||
                all_mobs = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                count = 0
 | 
			
		||||
                for k, v in all_mobs:
 | 
			
		||||
                    type_name = mobs.MOB_NAMES[v.type]
 | 
			
		||||
                    if type_name != 'villager' : continue
 | 
			
		||||
                    count += 1
 | 
			
		||||
                    print(str(k) + ':', v, type_name)
 | 
			
		||||
                reply = str(count) + ' villagers'
 | 
			
		||||
 | 
			
		||||
            ## !threats - prints the dangerous monsters within 20 blocks
 | 
			
		||||
            ## !threats [num] - prints the dangerous monsters within num blocks
 | 
			
		||||
            if command == 'threats':
 | 
			
		||||
                distance = int(data) if data else 20
 | 
			
		||||
                p = utils.pint(self.g.pos)
 | 
			
		||||
                threats = self.g.world.find_threats(p, distance)
 | 
			
		||||
 | 
			
		||||
                for t in threats:
 | 
			
		||||
                    print(str(t.entity_id) + ':', t, mobs.MOB_NAMES[t.type])
 | 
			
		||||
                reply = str(len(threats)) + ' threats'
 | 
			
		||||
 | 
			
		||||
            if command == 'spiral' and data:
 | 
			
		||||
                for i in range(int(data)):
 | 
			
		||||
                    print(utils.spiral(i))
 | 
			
		||||
 | 
			
		||||
            if command == 'sand_slice':
 | 
			
		||||
                result = self.g.world.find_sand_slice(utils.pint(self.g.pos), 50)
 | 
			
		||||
                reply = str(result)
 | 
			
		||||
 | 
			
		||||
            ## "zzz" or !zzz - bot does /afk to let others sleep
 | 
			
		||||
            if command == 'zzz':
 | 
			
		||||
                if not self.g.afk and self.g.dimension == 'overworld':
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
                    self.g.afk_timeout = 5.0
 | 
			
		||||
 | 
			
		||||
            ## !tree - replies with the closest tree
 | 
			
		||||
            if command == 'tree':
 | 
			
		||||
                pos = utils.pint(self.g.pos)
 | 
			
		||||
                tree = next(self.g.world.find_trees(pos, 50))
 | 
			
		||||
                reply = str(tree)[1:-1]
 | 
			
		||||
 | 
			
		||||
            ## !block x y z - replies what block is at (x, y, z)
 | 
			
		||||
            if command == 'block':
 | 
			
		||||
                try:
 | 
			
		||||
                    data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                    x1, y1, z1 = [int(x) for x in data.split()]
 | 
			
		||||
                except (AttributeError, ValueError):
 | 
			
		||||
                    reply = 'usage: !block x1 y1 z1'
 | 
			
		||||
 | 
			
		||||
                if not reply:
 | 
			
		||||
                    coord = (x1, y1, z1)
 | 
			
		||||
                    block = self.g.world.block_at(*coord)
 | 
			
		||||
 | 
			
		||||
                if not reply and block is None:
 | 
			
		||||
                    reply = 'first coord out of range'
 | 
			
		||||
 | 
			
		||||
                if not reply:
 | 
			
		||||
                    reply = blocks.BLOCKS[block] + ':' + str(block)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            ################# Specific commands ##########################
 | 
			
		||||
 | 
			
		||||
            ## ### Bot-specific Commands
 | 
			
		||||
            ## These will only run for the bot they are addressed to.
 | 
			
		||||
 | 
			
		||||
            if for_me:
 | 
			
		||||
 | 
			
		||||
                ## 1respawn - respawns the bot if it's dead
 | 
			
		||||
                if command == 'respawn':
 | 
			
		||||
                    self.g.game.respawn()
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1gather wood - gathers wood from the world
 | 
			
		||||
                ## 1gather sand - gathers sand from the world
 | 
			
		||||
                if command == 'gather' and data:
 | 
			
		||||
                    if data == 'wood':
 | 
			
		||||
                        self.g.job.state = self.g.job.gather_wood
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'sand':
 | 
			
		||||
                        self.g.job.state = self.g.job.gather_sand
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                    if reply:
 | 
			
		||||
                        for i in self.g.inv.values():
 | 
			
		||||
                            print(i.item_id)
 | 
			
		||||
                            if i.item_id in items.BED_IDS:
 | 
			
		||||
                                break
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply += ', I need a bed'
 | 
			
		||||
 | 
			
		||||
                ## 1farm wood - farms wood from a certain area
 | 
			
		||||
                ## 1farm sand - farms sand from a certain area
 | 
			
		||||
                ## 1farm wart - farms netherwart from a certain area
 | 
			
		||||
                ## 1farm crop - farms mature crops from a certain area
 | 
			
		||||
                if command == 'farm' and data:
 | 
			
		||||
                    if data == 'wood':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_wood
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'sand':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_sand
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'wart':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_wart
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data.startswith('crop'):
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_crop
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                    if reply and self.g.dimension == 'overworld':
 | 
			
		||||
                        for i in self.g.inv.values():
 | 
			
		||||
                            if i.item_id in items.BED_IDS:
 | 
			
		||||
                                break
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply += ', I need a bed'
 | 
			
		||||
 | 
			
		||||
                ## 1loiter - stands still but eats, sleeps, and flees
 | 
			
		||||
                if command == 'loiter':
 | 
			
		||||
                    self.g.job.state = self.g.job.loiter
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1trade - sells items to villagers to get emeralds
 | 
			
		||||
                if command == 'trade':
 | 
			
		||||
                    self.g.job.state = self.g.job.trade
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1stop - stops the current job and resets bot
 | 
			
		||||
                if command == 'stop':
 | 
			
		||||
                    self.g.game.close_window()
 | 
			
		||||
                    bot.init(self.g)
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1drop - drops the current stack its holding
 | 
			
		||||
                if command == 'drop':
 | 
			
		||||
                    self.g.game.drop_stack()
 | 
			
		||||
 | 
			
		||||
                ## 1select [id] - moves item with id into main hand
 | 
			
		||||
                if command == 'select' and data:
 | 
			
		||||
                    item = int(data)
 | 
			
		||||
                    if self.g.game.select_item([item]):
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'not found'
 | 
			
		||||
 | 
			
		||||
                ## 1dump [id] - drops all items matching id
 | 
			
		||||
                if command == 'dump' and data:
 | 
			
		||||
                    item = int(data)
 | 
			
		||||
                    if self.g.game.count_items([item]):
 | 
			
		||||
                        self.g.dumping = item
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'not found'
 | 
			
		||||
 | 
			
		||||
                ## 1drain - drops all items in inventory
 | 
			
		||||
                if command == 'drain':
 | 
			
		||||
                    self.g.draining = True
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                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 command == 'cache':
 | 
			
		||||
                    self.g.job.state = self.g.job.cache_items
 | 
			
		||||
                    self.g.job.cache_items_states.minimum = 0
 | 
			
		||||
                    self.g.job.cache_items_states.silent = True
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                ## 1fill [x] [y] [z] [x] [y] [z] - fills the cuboid with the block at the first coordinate
 | 
			
		||||
                if command == 'fill':
 | 
			
		||||
                    try:
 | 
			
		||||
                        data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                        x1, y1, z1, x2, y2, z2 = [int(x) for x in data.split()]
 | 
			
		||||
                    except (AttributeError, ValueError):
 | 
			
		||||
                        reply = 'usage: !fill x1 y1 z1 x2 y2 z2'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        coord1 = (x1, y1, z1)
 | 
			
		||||
                        coord2 = (x2, y2, z2)
 | 
			
		||||
                        block = self.g.world.block_at(*coord1)
 | 
			
		||||
 | 
			
		||||
                    if not reply and y1 > y2:
 | 
			
		||||
                        reply = 'can only fill upwards'
 | 
			
		||||
 | 
			
		||||
                    if not reply and block is None:
 | 
			
		||||
                        reply = 'first coord out of range'
 | 
			
		||||
 | 
			
		||||
                    if not reply and block == 0:
 | 
			
		||||
                        reply = 'can\'t fill with air'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        self.g.filling = Munch(coord1=coord1, coord2=coord2, block=block)
 | 
			
		||||
                        self.g.job.state = self.g.job.fill_blocks
 | 
			
		||||
                        reply = 'filling ' + str(utils.pvolume(coord1, coord2)) + ' with ' + blocks.BLOCKS[block]
 | 
			
		||||
 | 
			
		||||
                ## 1here - bot comes to your location
 | 
			
		||||
                if command == 'here':
 | 
			
		||||
                    try:
 | 
			
		||||
                        sender_uuid = self.g.player_names[sender]
 | 
			
		||||
                    except KeyError:
 | 
			
		||||
                        reply = 'can\'t find your uuid'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        for p in self.g.players.values():
 | 
			
		||||
                            if p.player_uuid == sender_uuid:
 | 
			
		||||
                                player = p
 | 
			
		||||
                                break
 | 
			
		||||
                        else: # for
 | 
			
		||||
                            reply = 'can\'t find you'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        pos = utils.pint(self.g.pos)
 | 
			
		||||
                        goal = utils.pint((p.x, p.y, p.z))
 | 
			
		||||
                        start = time.time()
 | 
			
		||||
                        navpath = self.g.world.path_to_place(pos, goal)
 | 
			
		||||
 | 
			
		||||
                        if navpath:
 | 
			
		||||
                            self.g.path = navpath
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            print(len(navpath))
 | 
			
		||||
                            print(navpath)
 | 
			
		||||
                            print(round(time.time() - start, 3), 'seconds')
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            self.g.look_at = None
 | 
			
		||||
                            reply = 'ok'
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply = 'no path'
 | 
			
		||||
 | 
			
		||||
                ## 1goto [x] [y] [z] - sends the bot to coordinate (x, y, z)
 | 
			
		||||
                if command == 'goto':
 | 
			
		||||
                    try:    
 | 
			
		||||
                        data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                        x2, y2, z2 = [int(x) for x in data.split()]
 | 
			
		||||
                    except (AttributeError, ValueError):
 | 
			
		||||
                        reply = 'usage: !goto x y z'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        pos = utils.pint(self.g.pos)
 | 
			
		||||
                        goal = utils.pint((x2, y2, z2))
 | 
			
		||||
                        start = time.time()
 | 
			
		||||
                        navpath = self.g.world.path_to_place(pos, goal)
 | 
			
		||||
 | 
			
		||||
                        if navpath:
 | 
			
		||||
                            self.g.path = navpath
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            print(len(navpath))
 | 
			
		||||
                            print(navpath)
 | 
			
		||||
                            print(round(time.time() - start, 3), 'seconds')
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            self.g.look_at = None
 | 
			
		||||
                            reply = 'ok'
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply = 'no path'
 | 
			
		||||
 | 
			
		||||
                if command == 'break':
 | 
			
		||||
                    self.g.game.break_block(blocks.TEST_BLOCK)
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                if command == 'open':
 | 
			
		||||
                    self.g.game.open_container(blocks.TEST_BLOCK)
 | 
			
		||||
 | 
			
		||||
                ## 1close - closes the current Minecraft window
 | 
			
		||||
                if command == 'close':
 | 
			
		||||
                    if self.g.window:
 | 
			
		||||
                        self.g.game.close_window()
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'nothing open'
 | 
			
		||||
 | 
			
		||||
                ## 1click [slot] [button] [mode] - clicks the current window
 | 
			
		||||
                if command == 'click' and data:
 | 
			
		||||
                    if self.g.window:
 | 
			
		||||
                        slot, button, mode = [int(x) for x in data.split(' ')]
 | 
			
		||||
                        try:
 | 
			
		||||
                            item = self.g.window.contents[slot]
 | 
			
		||||
                        except KeyError:
 | 
			
		||||
                            item = Slot(present=False)
 | 
			
		||||
                        print(item)
 | 
			
		||||
                        self.g.game.click_window(slot, button, mode, item)
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'nothing open'
 | 
			
		||||
 | 
			
		||||
                ## 1use - use the item it's currently holding
 | 
			
		||||
                if command == 'use':
 | 
			
		||||
                    self.g.game.use_item(0)
 | 
			
		||||
 | 
			
		||||
                ## 1interact [entity id] - interacts with that entity
 | 
			
		||||
                if command == 'interact' and data:
 | 
			
		||||
                    self.g.game.interact(int(data))
 | 
			
		||||
 | 
			
		||||
                if command == 'test':
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                    r = self.g.world.find_villager_openings((615, 78, 493))
 | 
			
		||||
                    print(r)
 | 
			
		||||
 | 
			
		||||
            ################# Authorized commands ##########################
 | 
			
		||||
 | 
			
		||||
            ## ### Authorized Commands
 | 
			
		||||
            ## These dangerous commands can only be ran by the bot owner.
 | 
			
		||||
 | 
			
		||||
            if authed:
 | 
			
		||||
 | 
			
		||||
                ## 1print [expression] - replies with Python eval(expression)
 | 
			
		||||
                if command == 'print':
 | 
			
		||||
                    data = data.replace('`', '.')
 | 
			
		||||
                    reply = str(eval(data))
 | 
			
		||||
 | 
			
		||||
                ## 1exit - exits the program
 | 
			
		||||
                if command == 'exit':
 | 
			
		||||
                    import os
 | 
			
		||||
                    os._exit(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        except BaseException as e:
 | 
			
		||||
            import traceback
 | 
			
		||||
            print(traceback.format_exc())
 | 
			
		||||
            reply = 'Error: {} - {}\n'.format(e.__class__.__name__, e)
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        if reply:
 | 
			
		||||
            print(reply)
 | 
			
		||||
            if private and not reply.startswith('/'):
 | 
			
		||||
                self.g.chat.send('/m ' + sender + ' ' + reply)
 | 
			
		||||
            else:
 | 
			
		||||
                self.g.chat.send(reply)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										513
									
								
								mosfet/game.py
									
									
									
									
									
								
							
							
						
						
									
										513
									
								
								mosfet/game.py
									
									
									
									
									
								
							@@ -1,6 +1,5 @@
 | 
			
		||||
import re
 | 
			
		||||
import time
 | 
			
		||||
import importlib
 | 
			
		||||
import random
 | 
			
		||||
from math import hypot
 | 
			
		||||
from itertools import count
 | 
			
		||||
@@ -22,7 +21,6 @@ from mosfet.protocol.packets import (
 | 
			
		||||
 | 
			
		||||
from mosfet.protocol.types import Slot
 | 
			
		||||
 | 
			
		||||
from mosfet import print_help
 | 
			
		||||
from mosfet import utils
 | 
			
		||||
from mosfet import path
 | 
			
		||||
from mosfet import bot
 | 
			
		||||
@@ -64,8 +62,6 @@ class Game:
 | 
			
		||||
 | 
			
		||||
        #register(self.handle_packet, Packet, early=True)
 | 
			
		||||
 | 
			
		||||
        self.g.chat.set_handler(self.handle_chat)
 | 
			
		||||
 | 
			
		||||
    def handle_login_success(self, packet):
 | 
			
		||||
        print(packet)
 | 
			
		||||
        self.g.name = packet.Username
 | 
			
		||||
@@ -126,510 +122,6 @@ class Game:
 | 
			
		||||
            if new_path:
 | 
			
		||||
                self.g.path = new_path
 | 
			
		||||
 | 
			
		||||
    def handle_chat(self, message):
 | 
			
		||||
        source, text = message
 | 
			
		||||
        reply = None
 | 
			
		||||
        private = False
 | 
			
		||||
        for_me = False
 | 
			
		||||
        authed = False
 | 
			
		||||
 | 
			
		||||
        if source == 'SYSTEM':
 | 
			
		||||
            self.g.command_lock = False
 | 
			
		||||
 | 
			
		||||
        if text == 'You are now AFK.':
 | 
			
		||||
            self.g.afk = True
 | 
			
		||||
        elif text == 'You are no longer AFK.':
 | 
			
		||||
            self.g.afk = False
 | 
			
		||||
 | 
			
		||||
        match1 = re.match(r'<?(\w+)> (.*)', text)
 | 
			
		||||
        match2 = re.match(r'\[(\w+) -> me] (.*)', text)
 | 
			
		||||
        if match1:
 | 
			
		||||
            sender, text = match1.groups()
 | 
			
		||||
        elif match2:
 | 
			
		||||
            sender, text = match2.groups()
 | 
			
		||||
            private = True
 | 
			
		||||
        else:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if sender == 'tanner6':
 | 
			
		||||
            authed = True
 | 
			
		||||
 | 
			
		||||
        if text.startswith('zzz'):
 | 
			
		||||
            text = '!zzz'
 | 
			
		||||
 | 
			
		||||
        bot_num = self.g.name[-1]
 | 
			
		||||
 | 
			
		||||
        if text.startswith(bot_num):
 | 
			
		||||
            text = text[1:]
 | 
			
		||||
            for_me = True
 | 
			
		||||
        elif text.startswith('! '):
 | 
			
		||||
            text = text[2:]
 | 
			
		||||
        elif text.startswith('!'):
 | 
			
		||||
            text = text[1:]
 | 
			
		||||
        else:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if ' ' in text:
 | 
			
		||||
            command = text.split(' ', 1)[0]
 | 
			
		||||
            data = text.split(' ', 1)[1]
 | 
			
		||||
        else:
 | 
			
		||||
            command = text
 | 
			
		||||
            data = None
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
 | 
			
		||||
            ## ### Public Commands
 | 
			
		||||
            ## These can be ran by anyone, all bots will reply.
 | 
			
		||||
 | 
			
		||||
            ## !help - prints this whole help message to console
 | 
			
		||||
            ## !help [command] - replies in-game explaining command
 | 
			
		||||
            if command == 'help':
 | 
			
		||||
                if data:
 | 
			
		||||
                    for line in print_help.HELP_LINES:
 | 
			
		||||
                        if line[1:].startswith(data) or line[1:].startswith(data[1:]):
 | 
			
		||||
                            reply = 'command ' + line
 | 
			
		||||
                            break
 | 
			
		||||
                    else:  # for
 | 
			
		||||
                        reply = 'command not found'
 | 
			
		||||
                else:
 | 
			
		||||
                    print()
 | 
			
		||||
                    print()
 | 
			
		||||
                    for line in print_help.HELP_LINES:
 | 
			
		||||
                        print(line)
 | 
			
		||||
                    reply = 'check console'
 | 
			
		||||
 | 
			
		||||
            ## !ping - replies with "pong"
 | 
			
		||||
            if command == 'ping':
 | 
			
		||||
                reply = 'pong'
 | 
			
		||||
 | 
			
		||||
            ## !echo [data] - replies with "data"
 | 
			
		||||
            if command == 'echo' and data:
 | 
			
		||||
                reply = data
 | 
			
		||||
 | 
			
		||||
            ## !pos - replies with position and dimension
 | 
			
		||||
            if command == 'pos':
 | 
			
		||||
                reply = str(utils.pint(self.g.pos))[1:-1] + ', ' + self.g.dimension
 | 
			
		||||
 | 
			
		||||
            ## !afk - goes AFK with /afk
 | 
			
		||||
            if command == 'afk':
 | 
			
		||||
                if not self.g.afk:
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
 | 
			
		||||
            ## !unafk - goes not AFK with /afk
 | 
			
		||||
            if command == 'unafk':
 | 
			
		||||
                if self.g.afk:
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
 | 
			
		||||
            ## !error - raises an error
 | 
			
		||||
            if command == 'error':
 | 
			
		||||
                reply = 'ok'
 | 
			
		||||
                raise
 | 
			
		||||
 | 
			
		||||
            ## !inv - prints current inventory
 | 
			
		||||
            if command == 'inv':
 | 
			
		||||
                inv_list = []
 | 
			
		||||
                for i in self.g.inv.values():
 | 
			
		||||
                    if i.present:
 | 
			
		||||
                        inv_list.append('{}:{} x {}'.format(items.ITEM_NAMES[i.item_id], str(i.item_id), i.item_count))
 | 
			
		||||
                inv_list.sort()
 | 
			
		||||
                result = '\n'.join(inv_list)
 | 
			
		||||
                print(result or 'Empty')
 | 
			
		||||
 | 
			
		||||
            ## !time - replies with Minecraft world time
 | 
			
		||||
            if command == 'time':
 | 
			
		||||
                reply = str(self.g.time)
 | 
			
		||||
 | 
			
		||||
            ## !count [id] - counts the number of items with that id
 | 
			
		||||
            if command == 'count' and data:
 | 
			
		||||
                item = int(data)
 | 
			
		||||
                reply = str(self.count_items([item]))
 | 
			
		||||
 | 
			
		||||
            ## !loaded - replies with the current loaded area
 | 
			
		||||
            if command == 'loaded':
 | 
			
		||||
                reply = str(self.g.chunks.get_loaded_area())
 | 
			
		||||
 | 
			
		||||
            ## !players - prints the current players
 | 
			
		||||
            ## !players clear - clears the current player list
 | 
			
		||||
            if command == 'players':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.players = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    for k, v in self.g.players.items():
 | 
			
		||||
                        print(str(k) + ':', v, self.g.player_names[v.player_uuid])
 | 
			
		||||
 | 
			
		||||
            ## !objects - prints the current items on ground
 | 
			
		||||
            ## !objects clear - clears the current object list
 | 
			
		||||
            if command == 'objects':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.objects = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    for k, v in self.g.objects.items():
 | 
			
		||||
                        if data and v.item_id != int(data): continue
 | 
			
		||||
                        print(str(k) + ':', v, items.ITEM_NAMES[v.item_id])
 | 
			
		||||
 | 
			
		||||
            ## !mobs - prints the current mobs
 | 
			
		||||
            ## !mobs clear - clears the current mob list
 | 
			
		||||
            if command == 'mobs':
 | 
			
		||||
                if data == 'clear':
 | 
			
		||||
                    self.g.mobs = {}
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                else:
 | 
			
		||||
                    all_mobs = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                    for k, v in all_mobs:
 | 
			
		||||
                        if data and v.type != int(data): continue
 | 
			
		||||
                        print(str(k) + ':', v, mobs.MOB_NAMES[v.type])
 | 
			
		||||
                    reply = str(len(all_mobs)) + ' mobs'
 | 
			
		||||
 | 
			
		||||
            ## !monsters - prints the current monsters
 | 
			
		||||
            if command == 'monsters':
 | 
			
		||||
                monsters = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                count = 0
 | 
			
		||||
                for k, v in monsters:
 | 
			
		||||
                    if v.type not in mobs.EVIL_IDS: continue
 | 
			
		||||
                    if data and v.type != int(data): continue
 | 
			
		||||
                    count += 1
 | 
			
		||||
                    print(str(k) + ':', v, mobs.MOB_NAMES[v.type])
 | 
			
		||||
                reply = str(count) + ' monsters'
 | 
			
		||||
 | 
			
		||||
            ## !villagers - prints the current villagers
 | 
			
		||||
            if command == 'villagers':
 | 
			
		||||
                all_mobs = sorted(list(self.g.mobs.items()), key=lambda x: x[1].type)
 | 
			
		||||
                count = 0
 | 
			
		||||
                for k, v in all_mobs:
 | 
			
		||||
                    type_name = mobs.MOB_NAMES[v.type]
 | 
			
		||||
                    if type_name != 'villager' : continue
 | 
			
		||||
                    count += 1
 | 
			
		||||
                    print(str(k) + ':', v, type_name)
 | 
			
		||||
                reply = str(count) + ' villagers'
 | 
			
		||||
 | 
			
		||||
            ## !threats - prints the dangerous monsters within 20 blocks
 | 
			
		||||
            ## !threats [num] - prints the dangerous monsters within num blocks
 | 
			
		||||
            if command == 'threats':
 | 
			
		||||
                distance = int(data) if data else 20
 | 
			
		||||
                p = utils.pint(self.g.pos)
 | 
			
		||||
                threats = self.g.world.find_threats(p, distance)
 | 
			
		||||
 | 
			
		||||
                for t in threats:
 | 
			
		||||
                    print(str(t.entity_id) + ':', t, mobs.MOB_NAMES[t.type])
 | 
			
		||||
                reply = str(len(threats)) + ' threats'
 | 
			
		||||
 | 
			
		||||
            if command == 'spiral' and data:
 | 
			
		||||
                for i in range(int(data)):
 | 
			
		||||
                    print(utils.spiral(i))
 | 
			
		||||
 | 
			
		||||
            if command == 'sand_slice':
 | 
			
		||||
                result = self.g.world.find_sand_slice(utils.pint(self.g.pos), 50)
 | 
			
		||||
                reply = str(result)
 | 
			
		||||
 | 
			
		||||
            ## "zzz" or !zzz - bot does /afk to let others sleep
 | 
			
		||||
            if command == 'zzz':
 | 
			
		||||
                if not self.g.afk and self.g.dimension == 'overworld':
 | 
			
		||||
                    reply = '/afk'
 | 
			
		||||
                    self.g.afk_timeout = 5.0
 | 
			
		||||
 | 
			
		||||
            ## !tree - replies with the closest tree
 | 
			
		||||
            if command == 'tree':
 | 
			
		||||
                pos = utils.pint(self.g.pos)
 | 
			
		||||
                tree = next(self.g.world.find_trees(pos, 50))
 | 
			
		||||
                reply = str(tree)[1:-1]
 | 
			
		||||
 | 
			
		||||
            ## !block x y z - replies what block is at (x, y, z)
 | 
			
		||||
            if command == 'block':
 | 
			
		||||
                try:
 | 
			
		||||
                    data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                    x1, y1, z1 = [int(x) for x in data.split()]
 | 
			
		||||
                except (AttributeError, ValueError):
 | 
			
		||||
                    reply = 'usage: !block x1 y1 z1'
 | 
			
		||||
 | 
			
		||||
                if not reply:
 | 
			
		||||
                    coord = (x1, y1, z1)
 | 
			
		||||
                    block = self.g.world.block_at(*coord)
 | 
			
		||||
 | 
			
		||||
                if not reply and block is None:
 | 
			
		||||
                    reply = 'first coord out of range'
 | 
			
		||||
 | 
			
		||||
                if not reply:
 | 
			
		||||
                    reply = blocks.BLOCKS[block] + ':' + str(block)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            ################# Specific commands ##########################
 | 
			
		||||
 | 
			
		||||
            ## ### Bot-specific Commands
 | 
			
		||||
            ## These will only run for the bot they are addressed to.
 | 
			
		||||
 | 
			
		||||
            if for_me:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
                ## 1respawn - respawns the bot if it's dead
 | 
			
		||||
                if command == 'respawn':
 | 
			
		||||
                    packet = serverbound.play.ClientStatusPacket()
 | 
			
		||||
                    packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
 | 
			
		||||
                    self.g.connection.write_packet(packet)
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1gather wood - gathers wood from the world
 | 
			
		||||
                ## 1gather sand - gathers sand from the world
 | 
			
		||||
                if command == 'gather' and data:
 | 
			
		||||
                    if data == 'wood':
 | 
			
		||||
                        self.g.job.state = self.g.job.gather_wood
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'sand':
 | 
			
		||||
                        self.g.job.state = self.g.job.gather_sand
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                    if reply:
 | 
			
		||||
                        for i in self.g.inv.values():
 | 
			
		||||
                            print(i.item_id)
 | 
			
		||||
                            if i.item_id in items.BED_IDS:
 | 
			
		||||
                                break
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply += ', I need a bed'
 | 
			
		||||
 | 
			
		||||
                ## 1farm wood - farms wood from a certain area
 | 
			
		||||
                ## 1farm sand - farms sand from a certain area
 | 
			
		||||
                ## 1farm wart - farms netherwart from a certain area
 | 
			
		||||
                ## 1farm crop - farms mature crops from a certain area
 | 
			
		||||
                if command == 'farm' and data:
 | 
			
		||||
                    if data == 'wood':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_wood
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'sand':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_sand
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data == 'wart':
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_wart
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    elif data.startswith('crop'):
 | 
			
		||||
                        self.g.job.state = self.g.job.farm_crop
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                    if reply and self.g.dimension == 'overworld':
 | 
			
		||||
                        for i in self.g.inv.values():
 | 
			
		||||
                            if i.item_id in items.BED_IDS:
 | 
			
		||||
                                break
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply += ', I need a bed'
 | 
			
		||||
 | 
			
		||||
                ## 1loiter - stands still but eats, sleeps, and flees
 | 
			
		||||
                if command == 'loiter':
 | 
			
		||||
                    self.g.job.state = self.g.job.loiter
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1trade - sells items to villagers to get emeralds
 | 
			
		||||
                if command == 'trade':
 | 
			
		||||
                    self.g.job.state = self.g.job.trade
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1stop - stops the current job and resets bot
 | 
			
		||||
                if command == 'stop':
 | 
			
		||||
                    self.close_window()
 | 
			
		||||
                    bot.init(self.g)
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                ## 1drop - drops the current stack its holding
 | 
			
		||||
                if command == 'drop':
 | 
			
		||||
                    self.drop_stack()
 | 
			
		||||
 | 
			
		||||
                ## 1select [id] - moves item with id into main hand
 | 
			
		||||
                if command == 'select' and data:
 | 
			
		||||
                    item = int(data)
 | 
			
		||||
                    if self.select_item([item]):
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'not found'
 | 
			
		||||
 | 
			
		||||
                ## 1dump [id] - drops all items matching id
 | 
			
		||||
                if command == 'dump' and data:
 | 
			
		||||
                    item = int(data)
 | 
			
		||||
                    if self.count_items([item]):
 | 
			
		||||
                        self.g.dumping = item
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'not found'
 | 
			
		||||
 | 
			
		||||
                ## 1drain - drops all items in inventory
 | 
			
		||||
                if command == 'drain':
 | 
			
		||||
                    self.g.draining = True
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                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 command == 'cache':
 | 
			
		||||
                    self.g.job.state = self.g.job.cache_items
 | 
			
		||||
                    self.g.job.cache_items_states.minimum = 0
 | 
			
		||||
                    self.g.job.cache_items_states.silent = True
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                ## 1fill [x] [y] [z] [x] [y] [z] - fills the cuboid with the block at the first coordinate
 | 
			
		||||
                if command == 'fill':
 | 
			
		||||
                    try:
 | 
			
		||||
                        data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                        x1, y1, z1, x2, y2, z2 = [int(x) for x in data.split()]
 | 
			
		||||
                    except (AttributeError, ValueError):
 | 
			
		||||
                        reply = 'usage: !fill x1 y1 z1 x2 y2 z2'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        coord1 = (x1, y1, z1)
 | 
			
		||||
                        coord2 = (x2, y2, z2)
 | 
			
		||||
                        block = self.g.world.block_at(*coord1)
 | 
			
		||||
 | 
			
		||||
                    if not reply and y1 > y2:
 | 
			
		||||
                        reply = 'can only fill upwards'
 | 
			
		||||
 | 
			
		||||
                    if not reply and block is None:
 | 
			
		||||
                        reply = 'first coord out of range'
 | 
			
		||||
 | 
			
		||||
                    if not reply and block == 0:
 | 
			
		||||
                        reply = 'can\'t fill with air'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        self.g.filling = Munch(coord1=coord1, coord2=coord2, block=block)
 | 
			
		||||
                        self.g.job.state = self.g.job.fill_blocks
 | 
			
		||||
                        reply = 'filling ' + str(utils.pvolume(coord1, coord2)) + ' with ' + blocks.BLOCKS[block]
 | 
			
		||||
 | 
			
		||||
                ## 1here - bot comes to your location
 | 
			
		||||
                if command == 'here':
 | 
			
		||||
                    try:
 | 
			
		||||
                        sender_uuid = self.g.player_names[sender]
 | 
			
		||||
                    except KeyError:
 | 
			
		||||
                        reply = 'can\'t find your uuid'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        for p in self.g.players.values():
 | 
			
		||||
                            if p.player_uuid == sender_uuid:
 | 
			
		||||
                                player = p
 | 
			
		||||
                                break
 | 
			
		||||
                        else: # for
 | 
			
		||||
                            reply = 'can\'t find you'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        pos = utils.pint(self.g.pos)
 | 
			
		||||
                        goal = utils.pint((p.x, p.y, p.z))
 | 
			
		||||
                        start = time.time()
 | 
			
		||||
                        navpath = self.g.world.path_to_place(pos, goal)
 | 
			
		||||
 | 
			
		||||
                        if navpath:
 | 
			
		||||
                            self.g.path = navpath
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            print(len(navpath))
 | 
			
		||||
                            print(navpath)
 | 
			
		||||
                            print(round(time.time() - start, 3), 'seconds')
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            self.g.look_at = None
 | 
			
		||||
                            reply = 'ok'
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply = 'no path'
 | 
			
		||||
 | 
			
		||||
                ## 1goto [x] [y] [z] - sends the bot to coordinate (x, y, z)
 | 
			
		||||
                if command == 'goto':
 | 
			
		||||
                    try:    
 | 
			
		||||
                        data = data.replace('(', ' ').replace(')', ' ').replace(',', ' ')
 | 
			
		||||
                        x2, y2, z2 = [int(x) for x in data.split()]
 | 
			
		||||
                    except (AttributeError, ValueError):
 | 
			
		||||
                        reply = 'usage: !goto x y z'
 | 
			
		||||
 | 
			
		||||
                    if not reply:
 | 
			
		||||
                        pos = utils.pint(self.g.pos)
 | 
			
		||||
                        goal = utils.pint((x2, y2, z2))
 | 
			
		||||
                        start = time.time()
 | 
			
		||||
                        navpath = self.g.world.path_to_place(pos, goal)
 | 
			
		||||
 | 
			
		||||
                        if navpath:
 | 
			
		||||
                            self.g.path = navpath
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            print(len(navpath))
 | 
			
		||||
                            print(navpath)
 | 
			
		||||
                            print(round(time.time() - start, 3), 'seconds')
 | 
			
		||||
                            if self.g.job:
 | 
			
		||||
                                self.g.job.stop()
 | 
			
		||||
                            self.g.look_at = None
 | 
			
		||||
                            reply = 'ok'
 | 
			
		||||
                        else:
 | 
			
		||||
                            reply = 'no path'
 | 
			
		||||
 | 
			
		||||
                if command == 'break':
 | 
			
		||||
                    self.break_block(blocks.TEST_BLOCK)
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
 | 
			
		||||
                if command == 'open':
 | 
			
		||||
                    self.open_container(blocks.TEST_BLOCK)
 | 
			
		||||
 | 
			
		||||
                ## 1close - closes the current Minecraft window
 | 
			
		||||
                if command == 'close':
 | 
			
		||||
                    if self.g.window:
 | 
			
		||||
                        self.close_window()
 | 
			
		||||
                        reply = 'ok'
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'nothing open'
 | 
			
		||||
 | 
			
		||||
                ## 1click [slot] [button] [mode] - clicks the current window
 | 
			
		||||
                if command == 'click' and data:
 | 
			
		||||
                    if self.g.window:
 | 
			
		||||
                        slot, button, mode = [int(x) for x in data.split(' ')]
 | 
			
		||||
                        try:
 | 
			
		||||
                            item = self.g.window.contents[slot]
 | 
			
		||||
                        except KeyError:
 | 
			
		||||
                            item = Slot(present=False)
 | 
			
		||||
                        print(item)
 | 
			
		||||
                        self.click_window(slot, button, mode, item)
 | 
			
		||||
                    else:
 | 
			
		||||
                        reply = 'nothing open'
 | 
			
		||||
 | 
			
		||||
                ## 1use - use the item it's currently holding
 | 
			
		||||
                if command == 'use':
 | 
			
		||||
                    self.use_item(0)
 | 
			
		||||
 | 
			
		||||
                ## 1interact [entity id] - interacts with that entity
 | 
			
		||||
                if command == 'interact' and data:
 | 
			
		||||
                    self.interact(int(data))
 | 
			
		||||
 | 
			
		||||
                if command == 'test':
 | 
			
		||||
                    reply = 'ok'
 | 
			
		||||
                    r = self.g.world.find_villager_openings((615, 78, 493))
 | 
			
		||||
                    print(r)
 | 
			
		||||
 | 
			
		||||
            ################# Authorized commands ##########################
 | 
			
		||||
 | 
			
		||||
            ## ### Authorized Commands
 | 
			
		||||
            ## These dangerous commands can only be ran by the bot owner.
 | 
			
		||||
 | 
			
		||||
            if authed:
 | 
			
		||||
 | 
			
		||||
                ## 1print [expression] - replies with Python eval(expression)
 | 
			
		||||
                if command == 'print':
 | 
			
		||||
                    data = data.replace('`', '.')
 | 
			
		||||
                    reply = str(eval(data))
 | 
			
		||||
 | 
			
		||||
                ## 1exit - exits the program
 | 
			
		||||
                if command == 'exit':
 | 
			
		||||
                    import os
 | 
			
		||||
                    os._exit(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        except BaseException as e:
 | 
			
		||||
            import traceback
 | 
			
		||||
            print(traceback.format_exc())
 | 
			
		||||
            reply = 'Error: {} - {}\n'.format(e.__class__.__name__, e)
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        if reply:
 | 
			
		||||
            print(reply)
 | 
			
		||||
            if private and not reply.startswith('/'):
 | 
			
		||||
                self.g.chat.send('/m ' + sender + ' ' + reply)
 | 
			
		||||
            else:
 | 
			
		||||
                self.g.chat.send(reply)
 | 
			
		||||
 | 
			
		||||
    def handle_time_update(self, packet):
 | 
			
		||||
        self.g.time = packet.time_of_day % 24000
 | 
			
		||||
 | 
			
		||||
@@ -683,6 +175,11 @@ class Game:
 | 
			
		||||
        #print(packet)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def respawn(self):
 | 
			
		||||
        packet = serverbound.play.ClientStatusPacket()
 | 
			
		||||
        packet.action_id = serverbound.play.ClientStatusPacket.RESPAWN
 | 
			
		||||
        self.g.connection.write_packet(packet)
 | 
			
		||||
 | 
			
		||||
    def animate(self):
 | 
			
		||||
        packet = serverbound.play.AnimationPacket()
 | 
			
		||||
        packet.hand = packet.HAND_MAIN
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
HELP_LINES = []
 | 
			
		||||
 | 
			
		||||
with open('mosfet/game.py', 'r') as f:
 | 
			
		||||
with open('mosfet/commands.py', 'r') as f:
 | 
			
		||||
    for line in f.readlines():
 | 
			
		||||
        if line.strip().startswith('## '):
 | 
			
		||||
            HELP_LINES.append(line.strip()[3:])
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user