Add job for filling in a volume of blocks

This commit is contained in:
Tanner Collin 2020-12-05 10:56:56 +00:00
parent b8952db742
commit e0c5c3a6b9
8 changed files with 294 additions and 7 deletions

View File

@ -19,6 +19,7 @@ for name, data in JSON_BLOCKS.items():
BREAK_DISTANCE = 6 BREAK_DISTANCE = 6
AIR = 0 AIR = 0
STONE = 1
SAND = 66 SAND = 66
SINGLE_SNOW = 3921 SINGLE_SNOW = 3921
SOUL_TORCH = 4008 SOUL_TORCH = 4008

2
bot.py
View File

@ -205,6 +205,8 @@ def init(global_state):
g.queue_afk = False g.queue_afk = False
g.filling = False
def bot(global_state): def bot(global_state):
g = global_state g = global_state

52
game.py
View File

@ -20,7 +20,7 @@ from protocol.packets import (
ClickWindowPacket, CloseWindowPacket, ServerWindowConfirmationPacket, ClickWindowPacket, CloseWindowPacket, ServerWindowConfirmationPacket,
ClientWindowConfirmationPacket, EntityMetadataPacket, ClientWindowConfirmationPacket, EntityMetadataPacket,
SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket, SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
EntityActionPacket, EntityActionPacket, SpawnPlayerPacket,
) )
from protocol.types import Slot from protocol.types import Slot
@ -319,6 +319,7 @@ class Game:
register(self.handle_entity_position, clientbound.play.EntityPositionDeltaPacket) register(self.handle_entity_position, clientbound.play.EntityPositionDeltaPacket)
register(self.handle_entity_position_rotation, EntityPositionRotationPacket) register(self.handle_entity_position_rotation, EntityPositionRotationPacket)
register(self.handle_destroy_entities, DestroyEntitiesPacket) register(self.handle_destroy_entities, DestroyEntitiesPacket)
register(self.handle_spawn_player, SpawnPlayerPacket)
#register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket) #register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
#register(self.handle_packet, Packet, early=True) #register(self.handle_packet, Packet, early=True)
@ -356,6 +357,8 @@ class Game:
import traceback import traceback
print(traceback.format_exc()) print(traceback.format_exc())
#print(packet)
def handle_position_and_look(self, packet): def handle_position_and_look(self, packet):
print(packet) print(packet)
p = LPoint3f(x=packet.x, y=packet.y, z=packet.z) p = LPoint3f(x=packet.x, y=packet.y, z=packet.z)
@ -612,6 +615,33 @@ class Game:
data = data.replace('^', '.') data = data.replace('^', '.')
reply = str(eval(data)) reply = str(eval(data))
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]
except BaseException as e: except BaseException as e:
import traceback import traceback
print(traceback.format_exc()) print(traceback.format_exc())
@ -794,6 +824,18 @@ class Game:
packet2.accepted = packet.accepted packet2.accepted = packet.accepted
self.g.connection.write_packet(packet2) self.g.connection.write_packet(packet2)
def handle_spawn_player(self, packet):
print(packet)
self.g.players[packet.entity_id] = Munch(
entity_id=packet.entity_id,
player_uuid=packet.player_uuid,
x=packet.x,
y=packet.y,
z=packet.z,
yaw=packet.yaw,
pitch=packet.pitch,
)
def handle_spawn_object(self, packet): def handle_spawn_object(self, packet):
#return #return
if packet.type_id != 37: return if packet.type_id != 37: return
@ -809,9 +851,6 @@ class Game:
) )
def check_gapple(self, packet): def check_gapple(self, packet):
if not self.g.job:
return
current_gapple_chest = self.g.job.find_gapple_states.current_chest current_gapple_chest = self.g.job.find_gapple_states.current_chest
if current_gapple_chest: if current_gapple_chest:
for entry in packet.metadata: for entry in packet.metadata:
@ -826,6 +865,7 @@ class Game:
if not packet.metadata: if not packet.metadata:
return return
if self.g.job and self.g.job.state == self.g.job.find_gapple_states:
self.check_gapple(packet) self.check_gapple(packet)
obj = self.g.objects.get(packet.entity_id, None) obj = self.g.objects.get(packet.entity_id, None)
@ -836,6 +876,10 @@ class Game:
obj.item_id = entry.value.item_id obj.item_id = entry.value.item_id
obj.item_count = entry.value.item_count obj.item_count = entry.value.item_count
player = self.g.players.get(packet.entity_id, None)
if player:
return
def handle_spawn_living(self, packet): def handle_spawn_living(self, packet):
self.g.mobs[packet.entity_id] = Munch( self.g.mobs[packet.entity_id] = Munch(
entity_id=packet.entity_id, entity_id=packet.entity_id,

212
jobs.py
View File

@ -2,6 +2,7 @@ import re
import time import time
import importlib import importlib
import random import random
from itertools import count
from math import hypot from math import hypot
from panda3d.core import LPoint3f from panda3d.core import LPoint3f
@ -1107,6 +1108,209 @@ class CheckThreatsStates:
self.state() self.state()
class FillBlocksStates:
def idle(self):
return None
def init(self):
f = self.g.filling
if not f:
self.state = self.cleanup
print('Aborting, nothing to fill')
return
if self.last_block:
self.state = self.select_block
else:
self.state = self.find_last_block
def find_last_block(self):
w = self.g.world
f = self.g.filling
print('Finding last block')
b1, b2 = utils.pboundingbox(f.coord1, f.coord2)
y_start = f.coord1[1]
y_end = f.coord2[1]
distance = utils.phyp(f.coord1, f.coord2)
self.next_block = f.coord1
for offset in utils.search_3d(distance):
check = utils.padd(f.coord1, offset)
# ensure block is within fill area
if check[0] < b1[0] or check[0] > b2[0]:
continue
if check[2] < b1[2] or check[2] > b2[2]:
continue
if w.block_at(*check) == blocks.AIR:
self.state = self.select_block
return
self.last_block = check
def select_block(self):
f = self.g.filling
name = blocks.BLOCKS[f.block]
item = items.ITEMS['minecraft:'+name]['protocol_id']
if self.g.game.select_item([item]):
#self.g.look_at = utils.padd(self.area, path.BLOCK_BELOW)
self.state = self.find_next_block
else:
print('No blocks, aborting')
self.state = self.cleanup
def find_next_block(self):
w = self.g.world
f = self.g.filling
print('Finding next block, last:', self.last_block)
b1, b2 = utils.pboundingbox(f.coord1, f.coord2)
box = utils.psub(b2, b1)
xz_distance = hypot(box[0]+1, box[2]+1)
y_start = f.coord1[1]
y_end = f.coord2[1]
print('distance', xz_distance)
for y in range(y_start, y_end+1):
for i in count():
offset = utils.spiral(i)
check = utils.padd(self.last_block, offset)
check = (check[0], y, check[2])
print('layer', y)
print('offset', offset)
print('hypot', hypot(offset[0], offset[2]))
if hypot(offset[0], offset[2]) > xz_distance:
break
# ensure block is within fill area
if check[0] < b1[0] or check[0] > b2[0]:
continue
if check[2] < b1[2] or check[2] > b2[2]:
continue
if w.block_at(*check) == blocks.AIR:
print('Found next block:', check)
self.next_block = check
self.state = self.check_block_distance
return
# if there's nothing left to fill
self.g.filling = None
self.state = self.cleanup
def check_block_distance(self):
w = self.g.world
p = utils.pint(self.g.pos)
head = utils.padd(p, path.BLOCK_ABOVE)
if utils.phyp(head, self.next_block) < 4:
self.state = self.fill_block
else:
self.state = self.nav_to_block
def nav_to_block(self):
w = self.g.world
p = utils.pint(self.g.pos)
c = self.g.chunks
tmp = c.get_block_at(*self.next_block)
c.set_block_at(*self.next_block, blocks.STONE)
pos = utils.padd(self.next_block, path.BLOCK_ABOVE)
navpath = w.path_to_place(p, pos)
c.set_block_at(*self.next_block, tmp)
if navpath:
self.g.path = navpath[:-1]
self.state = self.going_to_block
else:
print('Cant get to that block')
self.state = self.cleanup
#self.bad_sand.append(self.sand)
#self.state = self.find_new_sand
def going_to_block(self):
if not len(self.g.path):
self.state = self.fill_block
def fill_block(self):
print('Filling block', self.next_block)
self.g.game.place_block(self.next_block, BlockFace.TOP)
self.g.look_at = self.next_block
self.wait_time = 0.25
self.state = self.wait_for_block
def wait_for_block(self):
if self.wait_time > 0:
self.wait_time -= utils.TICK
else:
self.state = self.check_block
def check_block(self):
w = self.g.world
if w.block_at(*self.next_block) != blocks.AIR:
self.last_block = self.next_block
else:
print('Block didnt appear')
self.state = self.check_obstruction
def check_obstruction(self):
p = utils.pint(self.g.pos)
print('last', self.last_block)
print('p', p)
if self.last_block[1] >= p[1]:
print('Obstructed, going to last block')
self.state = self.nav_to_last_block
else:
self.state = self.cleanup
def nav_to_last_block(self):
w = self.g.world
p = utils.pint(self.g.pos)
c = self.g.chunks
pos = utils.padd(self.last_block, path.BLOCK_ABOVE)
navpath = w.path_to_place(p, pos)
if navpath:
self.g.path = navpath
self.state = self.going_to_last_block
else:
print('Cant get to that block')
self.state = self.cleanup
def going_to_last_block(self):
if not len(self.g.path):
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.wait_time = 0
self.last_block = None
self.next_block = None
def run(self):
self.state()
class JobStates: class JobStates:
def idle(self): def idle(self):
return [] return []
@ -1121,6 +1325,7 @@ class JobStates:
self.clear_leaves_states = ClearLeavesStates(self.g) self.clear_leaves_states = ClearLeavesStates(self.g)
self.grab_sapling_states = GrabSaplingStates(self.g) self.grab_sapling_states = GrabSaplingStates(self.g)
self.grab_sand_states = GrabSandStates(self.g) self.grab_sand_states = GrabSandStates(self.g)
self.fill_blocks_states = FillBlocksStates(self.g)
self.check_threats_states = CheckThreatsStates(self.g) self.check_threats_states = CheckThreatsStates(self.g)
def run_machines(self, machines): def run_machines(self, machines):
@ -1190,6 +1395,13 @@ class JobStates:
self.cache_items_states.silent = True self.cache_items_states.silent = True
return machines return machines
def fill_blocks(self):
machines = [
self.fill_blocks_states,
self.sleep_with_bed_states,
]
return machines
def stop(self): def stop(self):
self.init_machines() self.init_machines()
self.state = self.idle self.state = self.idle

View File

@ -21,6 +21,7 @@ g.pos = False
g.inv = {} g.inv = {}
g.objects = {} g.objects = {}
g.mobs = {} g.mobs = {}
g.players = {}
g.window = None g.window = None
g.job = None g.job = None
g.correction_count = 0 g.correction_count = 0

View File

@ -23,7 +23,8 @@ def get_packets(old_get_packets):
mc_packets.add(packets.SpawnLivingEntityPacket) mc_packets.add(packets.SpawnLivingEntityPacket)
mc_packets.add(packets.EntityPositionRotationPacket) mc_packets.add(packets.EntityPositionRotationPacket)
mc_packets.add(packets.DestroyEntitiesPacket) mc_packets.add(packets.DestroyEntitiesPacket)
mc_packets.add(packets.EntityActionPacket) #mc_packets.add(packets.EntityActionPacket)
mc_packets.add(packets.SpawnPlayerPacket)
return mc_packets return mc_packets
return lambda x: wrapper(old_get_packets, x) return lambda x: wrapper(old_get_packets, x)

View File

@ -5,7 +5,7 @@ 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, String, UUID, Angle, Double, Short, UnsignedLong, Byte, BlockFace, String, UUID, Angle, Double,
Float, Float, Direction, PositionAndLook
) )
from protocol.types import Nbt, Slot, Entry from protocol.types import Nbt, Slot, Entry
@ -374,3 +374,19 @@ class EntityActionPacket(Packet):
{'action_id': VarInt}, {'action_id': VarInt},
{'jump_boost': VarInt}, {'jump_boost': VarInt},
] ]
class SpawnPlayerPacket(Packet):
# https://wiki.vg/Protocol#Spawn_Player
id = 0x04
packet_name = 'spawn player'
definition = [
{'entity_id': VarInt},
{'player_uuid': UUID},
{'x': Double},
{'y': Double},
{'z': Double},
{'yaw': Angle},
{'pitch': Angle},
]

View File

@ -33,6 +33,16 @@ def phyp_king(p1, p2):
def pint(p): def pint(p):
return (floor(p[0]), floor(p[1]), floor(p[2])) return (floor(p[0]), floor(p[1]), floor(p[2]))
def pboundingbox(p1, p2):
b1 = (min(p1[0], p2[0]), min(p1[1], p2[1]), min(p1[2], p2[2]))
b2 = (max(p1[0], p2[0]), max(p1[1], p2[1]), max(p1[2], p2[2]))
return b1, b2
def pvolume(p1, p2):
b1, b2 = pboundingbox(p1, p2)
box = psub(b2, b1)
return (box[0]+1) * (box[1]+1) * (box[2]+1)
def cap(x, amount): def cap(x, amount):
sign = 1 if x >= 0 else -1 sign = 1 if x >= 0 else -1
return sign * min(abs(x), amount) return sign * min(abs(x), amount)