Compare commits
6 Commits
caa3fbb2a4
...
1d8d473e26
Author | SHA1 | Date | |
---|---|---|---|
1d8d473e26 | |||
cf8677ee65 | |||
d0bfed75dd | |||
4b97aaf739 | |||
743d002167 | |||
1fe35c77fc |
24
bot.py
24
bot.py
|
@ -55,10 +55,18 @@ def tick(global_state):
|
||||||
target = None
|
target = None
|
||||||
|
|
||||||
# make sure current chunks are loaded for physics
|
# make sure current chunks are loaded for physics
|
||||||
if not g.chunks.check_loaded(p, 9):
|
if not g.chunks.check_loaded(p, 288):
|
||||||
|
if not g.chunks.loading:
|
||||||
|
print('Loading chunks', end='', flush=True)
|
||||||
|
g.chunks.loading = True
|
||||||
packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True)
|
packet = serverbound.play.PositionAndLookPacket(x=p.x, feet_y=p.y, z=p.z, pitch=0, yaw=0, on_ground=True)
|
||||||
g.connection.write_packet(packet, force=True)
|
g.connection.write_packet(packet, force=True)
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
if g.chunks.loading:
|
||||||
|
print()
|
||||||
|
print('Chunks loaded.')
|
||||||
|
g.chunks.loading = False
|
||||||
|
|
||||||
g.chunks.unload_chunks(p)
|
g.chunks.unload_chunks(p)
|
||||||
|
|
||||||
|
@ -205,7 +213,7 @@ def init(global_state):
|
||||||
g.item_lock = False
|
g.item_lock = False
|
||||||
g.command_lock = False
|
g.command_lock = False
|
||||||
|
|
||||||
g.window = None
|
g.trades = []
|
||||||
|
|
||||||
g.job = jobs.JobStates(g)
|
g.job = jobs.JobStates(g)
|
||||||
g.chopped_tree = False
|
g.chopped_tree = False
|
||||||
|
@ -246,11 +254,8 @@ def bot(global_state):
|
||||||
time.sleep(utils.TICK)
|
time.sleep(utils.TICK)
|
||||||
print('Player loaded.')
|
print('Player loaded.')
|
||||||
|
|
||||||
while not g.chunks.check_loaded(g.pos, 529):
|
|
||||||
time.sleep(utils.TICK)
|
|
||||||
print('Chunks loaded.')
|
|
||||||
|
|
||||||
init(g)
|
init(g)
|
||||||
|
g.game.close_window()
|
||||||
print('Initialized.')
|
print('Initialized.')
|
||||||
|
|
||||||
while g.running:
|
while g.running:
|
||||||
|
@ -269,10 +274,3 @@ def bot(global_state):
|
||||||
g.connection.early_outgoing_packet_listeners = []
|
g.connection.early_outgoing_packet_listeners = []
|
||||||
|
|
||||||
print('Bot module loaded.')
|
print('Bot module loaded.')
|
||||||
|
|
||||||
print(mcdata.mcd.blockCollisionShapes['blocks']['brewing_stand'])
|
|
||||||
print(mcdata.mcd.blockCollisionShapes['shapes']['107'])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
58
game.py
58
game.py
|
@ -309,6 +309,40 @@ class MCWorld:
|
||||||
result.append(mob)
|
result.append(mob)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def find_villagers(self, center, distance):
|
||||||
|
# finds villagers within distance
|
||||||
|
result = []
|
||||||
|
for eid, mob in copy(self.g.mobs).items():
|
||||||
|
type_name = mobs.MOB_NAMES[mob.type]
|
||||||
|
if type_name != 'villager' : continue
|
||||||
|
pos = utils.pint((mob.x, mob.y, mob.z))
|
||||||
|
if utils.phyp(center, pos) > distance:
|
||||||
|
continue
|
||||||
|
result.append(mob)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def find_villager_openings(self, villager):
|
||||||
|
# returns coords in a cardinal direction where we can stand by a villager
|
||||||
|
maze_solver = path.Pathfinder(self.g.chunks)
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for distance in range(3):
|
||||||
|
for direction in path.CHECK_DIRECTIONS:
|
||||||
|
offset = utils.pmul(direction, distance+1)
|
||||||
|
|
||||||
|
if not maze_solver.check_traverse(villager, offset):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check for line of sight
|
||||||
|
for check in range(distance+1):
|
||||||
|
offset2 = utils.pmul(direction, check+1)
|
||||||
|
offset2 = utils.padd(offset2, path.BLOCK_ABOVE)
|
||||||
|
check = utils.padd(villager, offset2)
|
||||||
|
if self.block_at(*check) not in blocks.NON_SOLID_IDS:
|
||||||
|
break
|
||||||
|
else: # for
|
||||||
|
result.append(utils.padd(villager, offset))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
|
@ -642,7 +676,12 @@ class Game:
|
||||||
self.g.job.state = self.g.job.loiter
|
self.g.job.state = self.g.job.loiter
|
||||||
reply = 'ok'
|
reply = 'ok'
|
||||||
|
|
||||||
|
if command == 'trade':
|
||||||
|
self.g.job.state = self.g.job.trade
|
||||||
|
reply = 'ok'
|
||||||
|
|
||||||
if command == 'stop':
|
if command == 'stop':
|
||||||
|
self.close_window()
|
||||||
bot.init(self.g)
|
bot.init(self.g)
|
||||||
reply = 'ok'
|
reply = 'ok'
|
||||||
|
|
||||||
|
@ -759,7 +798,7 @@ class Game:
|
||||||
try:
|
try:
|
||||||
item = self.g.window.contents[slot]
|
item = self.g.window.contents[slot]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
item = Slot(present=False, item_id=None, item_count=None, nbt=None)
|
item = Slot(present=False)
|
||||||
print(item)
|
print(item)
|
||||||
self.click_window(slot, button, mode, item)
|
self.click_window(slot, button, mode, item)
|
||||||
else:
|
else:
|
||||||
|
@ -773,7 +812,8 @@ class Game:
|
||||||
|
|
||||||
if command == 'test':
|
if command == 'test':
|
||||||
reply = 'ok'
|
reply = 'ok'
|
||||||
self.select_next_item()
|
r = self.g.world.find_villager_openings((615, 78, 493))
|
||||||
|
print(r)
|
||||||
|
|
||||||
################# Authorized commands ##########################
|
################# Authorized commands ##########################
|
||||||
if authed:
|
if authed:
|
||||||
|
@ -893,7 +933,9 @@ class Game:
|
||||||
def select_item(self, items):
|
def select_item(self, items):
|
||||||
# select the first match from items of inv
|
# select the first match from items of inv
|
||||||
# uses smallest stack of that match
|
# uses smallest stack of that match
|
||||||
|
# and optionally the most damaged item
|
||||||
inv_items = list(self.g.inv.items())
|
inv_items = list(self.g.inv.items())
|
||||||
|
inv_items.sort(key=lambda x: (x[1].nbt or {}).get('Damage', 0), reverse=True)
|
||||||
inv_items.sort(key=lambda x: x[1].item_count or 0)
|
inv_items.sort(key=lambda x: x[1].item_count or 0)
|
||||||
for slot, item in inv_items:
|
for slot, item in inv_items:
|
||||||
if item.item_id in items:
|
if item.item_id in items:
|
||||||
|
@ -922,7 +964,9 @@ class Game:
|
||||||
def select_next_item(self):
|
def select_next_item(self):
|
||||||
# select the next item slot that has an item
|
# select the next item slot that has an item
|
||||||
for slot, item in self.g.inv.items():
|
for slot, item in self.g.inv.items():
|
||||||
|
if slot < 9: continue # skip armour slots
|
||||||
if item.present:
|
if item.present:
|
||||||
|
print('slot:', slot, 'item:', item)
|
||||||
self.g.game.choose_slot(slot)
|
self.g.game.choose_slot(slot)
|
||||||
self.g.holding = item.item_id
|
self.g.holding = item.item_id
|
||||||
return True
|
return True
|
||||||
|
@ -961,10 +1005,11 @@ class Game:
|
||||||
w.count += 1
|
w.count += 1
|
||||||
|
|
||||||
def close_window(self):
|
def close_window(self):
|
||||||
packet = CloseWindowPacket()
|
if self.g.window:
|
||||||
packet.window_id = self.g.window.data.window_id
|
packet = CloseWindowPacket()
|
||||||
self.g.connection.write_packet(packet)
|
packet.window_id = self.g.window.data.window_id
|
||||||
self.g.window = None
|
self.g.connection.write_packet(packet)
|
||||||
|
self.g.window = None
|
||||||
|
|
||||||
def handle_window_confirmation(self, packet):
|
def handle_window_confirmation(self, packet):
|
||||||
print(packet)
|
print(packet)
|
||||||
|
@ -1139,6 +1184,7 @@ class Game:
|
||||||
|
|
||||||
def handle_trade_list(self, packet):
|
def handle_trade_list(self, packet):
|
||||||
print(packet)
|
print(packet)
|
||||||
|
self.g.trades = packet.trades
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
if self.g.breaking:
|
if self.g.breaking:
|
||||||
|
|
170
jobs.py
170
jobs.py
|
@ -303,7 +303,7 @@ class GatherWartStates:
|
||||||
def select_wart(self):
|
def select_wart(self):
|
||||||
p = utils.pint(self.g.pos)
|
p = utils.pint(self.g.pos)
|
||||||
|
|
||||||
if self.g.game.select_item(items.NETHERWART_ID):
|
if self.g.game.select_item([items.NETHERWART_ID]):
|
||||||
self.state = self.wait_select
|
self.state = self.wait_select
|
||||||
self.wait_time = 0.5
|
self.wait_time = 0.5
|
||||||
else:
|
else:
|
||||||
|
@ -403,6 +403,7 @@ class GatherWoodStates:
|
||||||
print('Unable to get to tree', self.tree)
|
print('Unable to get to tree', self.tree)
|
||||||
if self.tree not in self.good_trees:
|
if self.tree not in self.good_trees:
|
||||||
self.bad_trees.append(self.tree)
|
self.bad_trees.append(self.tree)
|
||||||
|
print('Added to bad trees list')
|
||||||
self.state = self.cleanup
|
self.state = self.cleanup
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -507,7 +508,6 @@ class GatherWoodStates:
|
||||||
# never gets ran, placeholder
|
# never gets ran, placeholder
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, global_state):
|
def __init__(self, global_state):
|
||||||
self.g = global_state
|
self.g = global_state
|
||||||
self.state = self.idle
|
self.state = self.idle
|
||||||
|
@ -893,7 +893,6 @@ class CacheItemsStates:
|
||||||
self.g.look_at = self.area
|
self.g.look_at = self.area
|
||||||
self.state = self.open_chest
|
self.state = self.open_chest
|
||||||
|
|
||||||
|
|
||||||
def select_chest(self):
|
def select_chest(self):
|
||||||
if self.g.game.select_item([items.CHEST_ID]):
|
if self.g.game.select_item([items.CHEST_ID]):
|
||||||
self.state = self.find_cache_spot
|
self.state = self.find_cache_spot
|
||||||
|
@ -1288,19 +1287,23 @@ class ClearLeavesStates:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
if self.g.chopped_tree:
|
if not self.g.chopped_tree:
|
||||||
sapling_type = self.g.chopped_tree + '_sapling'
|
print('Didnt chop tree, clearing leaves')
|
||||||
sapling_item = items.get_id(sapling_type)
|
self.state = self.cleanup
|
||||||
num_saplings = self.g.game.count_items([sapling_item])
|
return
|
||||||
print('Have', num_saplings, sapling_type, 'in inventory')
|
|
||||||
|
|
||||||
if num_saplings > 8:
|
sapling_type = self.g.chopped_tree + '_sapling'
|
||||||
print('Aborting clearing leaves')
|
sapling_item = items.get_id(sapling_type)
|
||||||
self.state = self.cleanup
|
num_saplings = self.g.game.count_items([sapling_item])
|
||||||
return
|
print('Have', num_saplings, sapling_type, 'in inventory')
|
||||||
|
|
||||||
self.state = self.select_log
|
if num_saplings > 8:
|
||||||
print('Clearing leaves...')
|
print('Have enough saplings, aborting clearing leaves')
|
||||||
|
self.state = self.cleanup
|
||||||
|
return
|
||||||
|
|
||||||
|
self.state = self.select_log
|
||||||
|
print('Clearing leaves...')
|
||||||
|
|
||||||
def select_log(self):
|
def select_log(self):
|
||||||
# select a log to avoid using tools
|
# select a log to avoid using tools
|
||||||
|
@ -1558,6 +1561,10 @@ class FillBlocksStates:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.last_block = check
|
self.last_block = check
|
||||||
|
else: # for
|
||||||
|
self.state = self.cleanup
|
||||||
|
print('Aborting, no air left')
|
||||||
|
return
|
||||||
|
|
||||||
def select_item(self):
|
def select_item(self):
|
||||||
f = self.g.filling
|
f = self.g.filling
|
||||||
|
@ -1765,6 +1772,114 @@ class EatFoodStates:
|
||||||
self.state()
|
self.state()
|
||||||
|
|
||||||
|
|
||||||
|
class SellToVillagerStates:
|
||||||
|
def idle(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
self.state = self.find_villager
|
||||||
|
|
||||||
|
def find_villager(self):
|
||||||
|
print('Finding new villager...')
|
||||||
|
w = self.g.world
|
||||||
|
p = utils.pint(self.g.pos)
|
||||||
|
|
||||||
|
for villager in w.find_villagers(p, 100):
|
||||||
|
print('Found villager:', villager)
|
||||||
|
if villager not in self.bad_villagers:
|
||||||
|
break
|
||||||
|
else: # for
|
||||||
|
print('No good villagers left, aborting.')
|
||||||
|
self.state = self.cleanup
|
||||||
|
return
|
||||||
|
|
||||||
|
self.villager = villager
|
||||||
|
self.villager_pos = utils.pint((villager.x, villager.y, villager.z))
|
||||||
|
self.state = self.find_openings
|
||||||
|
|
||||||
|
def find_openings(self):
|
||||||
|
w = self.g.world
|
||||||
|
self.openings = w.find_villager_openings(self.villager_pos)
|
||||||
|
self.state = self.choose_opening
|
||||||
|
|
||||||
|
def choose_opening(self):
|
||||||
|
w = self.g.world
|
||||||
|
p = utils.pint(self.g.pos)
|
||||||
|
|
||||||
|
print('openings:', self.openings)
|
||||||
|
|
||||||
|
if not len(self.openings):
|
||||||
|
print('Unable to get to villager:', self.villager)
|
||||||
|
if self.villager not in self.good_villagers:
|
||||||
|
self.bad_villagers.append(self.villager)
|
||||||
|
print('Added to bad villager list')
|
||||||
|
self.state = self.cleanup
|
||||||
|
return
|
||||||
|
|
||||||
|
navpath = w.path_to_place(p, self.openings[0])
|
||||||
|
|
||||||
|
if navpath:
|
||||||
|
self.g.path = navpath
|
||||||
|
self.state = self.going_to_villager
|
||||||
|
else:
|
||||||
|
self.openings.pop(0)
|
||||||
|
|
||||||
|
def going_to_villager(self):
|
||||||
|
if utils.pint(self.g.pos) == self.openings[0]:
|
||||||
|
print('Arrived at villager')
|
||||||
|
self.g.look_at = self.villager_pos
|
||||||
|
self.wait_time = 0.5
|
||||||
|
self.state = self.wait_to_interact
|
||||||
|
|
||||||
|
def wait_to_interact(self):
|
||||||
|
if self.wait_time > 0:
|
||||||
|
self.wait_time -= utils.TICK
|
||||||
|
else:
|
||||||
|
self.state = self.interact_villager
|
||||||
|
|
||||||
|
def interact_villager(self):
|
||||||
|
print('Interacting with villager')
|
||||||
|
self.g.game.interact(self.villager.entity_id)
|
||||||
|
self.g.game.animate()
|
||||||
|
self.state = self.select_trade
|
||||||
|
|
||||||
|
def select_trade(self):
|
||||||
|
if not self.g.window or not self.g.trades:
|
||||||
|
return
|
||||||
|
|
||||||
|
print('Got trades window')
|
||||||
|
self.state = self.freeze
|
||||||
|
|
||||||
|
def freeze(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def wait(self):
|
||||||
|
if self.wait_time > 0:
|
||||||
|
self.wait_time -= utils.TICK
|
||||||
|
else:
|
||||||
|
self.state = self.cleanup
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
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.villager = None
|
||||||
|
self.villager_pos = None
|
||||||
|
self.bad_villagers = []
|
||||||
|
self.good_villagers = []
|
||||||
|
self.openings = []
|
||||||
|
self.wait_time = 0
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.state()
|
||||||
|
|
||||||
|
|
||||||
class JobStates:
|
class JobStates:
|
||||||
def idle(self):
|
def idle(self):
|
||||||
|
@ -1786,6 +1901,7 @@ class JobStates:
|
||||||
self.gather_wart_states = GatherWartStates(self.g)
|
self.gather_wart_states = GatherWartStates(self.g)
|
||||||
self.gather_crop_states = GatherCropStates(self.g)
|
self.gather_crop_states = GatherCropStates(self.g)
|
||||||
self.eat_food_states = EatFoodStates(self.g)
|
self.eat_food_states = EatFoodStates(self.g)
|
||||||
|
self.sell_to_villager = SellToVillagerStates(self.g)
|
||||||
|
|
||||||
def run_machines(self, machines):
|
def run_machines(self, machines):
|
||||||
for m in machines:
|
for m in machines:
|
||||||
|
@ -1897,12 +2013,13 @@ class JobStates:
|
||||||
self.sleep_with_bed_states.silent = True
|
self.sleep_with_bed_states.silent = True
|
||||||
|
|
||||||
f = self.g.filling
|
f = self.g.filling
|
||||||
name = blocks.BLOCKS[f.block]
|
if f:
|
||||||
item = items.ITEMS['minecraft:'+name]['protocol_id']
|
name = blocks.BLOCKS[f.block]
|
||||||
|
item = items.ITEMS['minecraft:'+name]['protocol_id']
|
||||||
|
|
||||||
self.grab_supplies_states.supplies = {
|
self.grab_supplies_states.supplies = {
|
||||||
tuple([item]): 0,
|
tuple([item]): 0,
|
||||||
}
|
}
|
||||||
return machines
|
return machines
|
||||||
|
|
||||||
def loiter(self):
|
def loiter(self):
|
||||||
|
@ -1914,6 +2031,21 @@ class JobStates:
|
||||||
self.sleep_with_bed_states.silent = True
|
self.sleep_with_bed_states.silent = True
|
||||||
return machines
|
return machines
|
||||||
|
|
||||||
|
def trade(self):
|
||||||
|
machines = [
|
||||||
|
#self.grab_supplies_states,
|
||||||
|
self.sell_to_villager,
|
||||||
|
#self.sleep_with_bed_states,
|
||||||
|
#self.eat_food_states,
|
||||||
|
#self.cache_items_states,
|
||||||
|
]
|
||||||
|
self.sleep_with_bed_states.silent = True
|
||||||
|
self.cache_items_states.silent = True
|
||||||
|
self.grab_supplies_states.supplies = {
|
||||||
|
tuple(items.AXE_IDS): 9,
|
||||||
|
}
|
||||||
|
return machines
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.init_machines()
|
self.init_machines()
|
||||||
self.state = self.idle
|
self.state = self.idle
|
||||||
|
|
|
@ -44,6 +44,7 @@ class ChunksManager:
|
||||||
self.chunks = {}
|
self.chunks = {}
|
||||||
self.biomes = {}
|
self.biomes = {}
|
||||||
self.index = {}
|
self.index = {}
|
||||||
|
self.loading = False
|
||||||
|
|
||||||
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)
|
||||||
|
@ -74,6 +75,8 @@ class ChunksManager:
|
||||||
self.index[item_id].append(coords)
|
self.index[item_id].append(coords)
|
||||||
|
|
||||||
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
|
||||||
|
if self.loading:
|
||||||
|
print('.', end='', flush=True)
|
||||||
|
|
||||||
def register(self, connection):
|
def register(self, connection):
|
||||||
connection.register_packet_listener(self.handle_block, clientbound.play.BlockChangePacket)
|
connection.register_packet_listener(self.handle_block, clientbound.play.BlockChangePacket)
|
||||||
|
|
|
@ -103,7 +103,7 @@ class Nbt(Type):
|
||||||
|
|
||||||
|
|
||||||
class Slot(Type):
|
class Slot(Type):
|
||||||
def __init__(self, present, item_id, item_count, nbt):
|
def __init__(self, present, item_id=None, item_count=None, nbt=None):
|
||||||
self.present = present
|
self.present = present
|
||||||
self.item_id = item_id
|
self.item_id = item_id
|
||||||
self.item_count = item_count
|
self.item_count = item_count
|
||||||
|
@ -112,8 +112,11 @@ class Slot(Type):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.__dict__)
|
return str(self.__dict__)
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Slot(present={}, item_id={}, item_count={}, nbt={}'.format(
|
if self.present:
|
||||||
self.present, self.item_id, self.item_count, self.nbt)
|
return 'Slot(present={}, item_id={}, item_count={}, nbt={}'.format(
|
||||||
|
self.present, self.item_id, self.item_count, self.nbt)
|
||||||
|
else:
|
||||||
|
return 'Slot(present={})'.format(self.present)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def read(file_object):
|
def read(file_object):
|
||||||
|
@ -131,9 +134,10 @@ class Slot(Type):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def send(value, socket):
|
def send(value, socket):
|
||||||
Boolean.send(value.present, socket)
|
Boolean.send(value.present, socket)
|
||||||
VarInt.send(value.item_id, socket)
|
if value.present:
|
||||||
Byte.send(value.item_count, socket)
|
VarInt.send(value.item_id, socket)
|
||||||
Byte.send(0x00, socket)
|
Byte.send(value.item_count, socket)
|
||||||
|
Byte.send(0x00, socket)
|
||||||
|
|
||||||
|
|
||||||
class Entry(Type):
|
class Entry(Type):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user