Add job for filling in a volume of blocks
This commit is contained in:
parent
b8952db742
commit
e0c5c3a6b9
|
@ -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
2
bot.py
|
@ -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
52
game.py
|
@ -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
212
jobs.py
|
@ -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
|
||||||
|
|
1
main.py
1
main.py
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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},
|
||||||
|
]
|
||||||
|
|
10
utils.py
10
utils.py
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user