Compare commits
5 Commits
e4b51aa2d6
...
ef68956e63
Author | SHA1 | Date | |
---|---|---|---|
ef68956e63 | |||
0bdae1f775 | |||
2fa3044acb | |||
e642e426b9 | |||
f35c7a4e51 |
38
blocks.py
38
blocks.py
|
@ -237,12 +237,31 @@ SAPLINGS = [
|
||||||
'dark_oak_sapling',
|
'dark_oak_sapling',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
BEDS = [
|
||||||
|
'white_bed',
|
||||||
|
'orange_bed',
|
||||||
|
'magenta_bed',
|
||||||
|
'light_blue_bed',
|
||||||
|
'yellow_bed',
|
||||||
|
'lime_bed',
|
||||||
|
'pink_bed',
|
||||||
|
'gray_bed',
|
||||||
|
'light_gray_bed',
|
||||||
|
'cyan_bed',
|
||||||
|
'purple_bed',
|
||||||
|
'blue_bed',
|
||||||
|
'brown_bed',
|
||||||
|
'green_bed',
|
||||||
|
'red_bed',
|
||||||
|
'black_bed',
|
||||||
|
]
|
||||||
|
|
||||||
INDEXED = [
|
INDEXED = [
|
||||||
'chest',
|
'chest',
|
||||||
'trapped_chest',
|
'trapped_chest',
|
||||||
'emerald_block',
|
'emerald_block',
|
||||||
'barrel',
|
'barrel',
|
||||||
]
|
] + BEDS
|
||||||
|
|
||||||
|
|
||||||
NON_SOLID_IDS = set([SINGLE_SNOW])
|
NON_SOLID_IDS = set([SINGLE_SNOW])
|
||||||
|
@ -310,16 +329,23 @@ for block_name in ['beetroots']:
|
||||||
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||||
BEETROOT_IDS.add(state['id'])
|
BEETROOT_IDS.add(state['id'])
|
||||||
|
|
||||||
INDEXED_IDS = set()
|
|
||||||
for block_name in INDEXED:
|
|
||||||
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
|
||||||
INDEXED_IDS.add(state['id'])
|
|
||||||
|
|
||||||
SAPLING_IDS = set()
|
SAPLING_IDS = set()
|
||||||
for block_name in SAPLINGS:
|
for block_name in SAPLINGS:
|
||||||
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||||
SAPLING_IDS.add(state['id'])
|
SAPLING_IDS.add(state['id'])
|
||||||
|
|
||||||
|
BED_IDS = set()
|
||||||
|
for block_name in BEDS:
|
||||||
|
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||||
|
BED_IDS.add(state['id'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
INDEXED_IDS = set()
|
||||||
|
for block_name in INDEXED:
|
||||||
|
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||||
|
INDEXED_IDS.add(state['id'])
|
||||||
|
|
||||||
MATURE_WHEAT_ID = max(WHEAT_IDS)
|
MATURE_WHEAT_ID = max(WHEAT_IDS)
|
||||||
MATURE_POTATO_ID = max(POTATO_IDS)
|
MATURE_POTATO_ID = max(POTATO_IDS)
|
||||||
MATURE_CARROT_ID = max(CARROT_IDS)
|
MATURE_CARROT_ID = max(CARROT_IDS)
|
||||||
|
|
20
bot.py
20
bot.py
|
@ -24,7 +24,7 @@ from minecraft.networking.packets import Packet, clientbound, serverbound
|
||||||
from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException
|
from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException
|
||||||
|
|
||||||
from munch import Munch
|
from munch import Munch
|
||||||
from panda3d.core import LPoint3f, LVector3f
|
from vector import Point3D, Vector3D
|
||||||
|
|
||||||
import game
|
import game
|
||||||
importlib.reload(game)
|
importlib.reload(game)
|
||||||
|
@ -41,9 +41,9 @@ importlib.reload(mcdata)
|
||||||
|
|
||||||
last_tick = time.time()
|
last_tick = time.time()
|
||||||
|
|
||||||
PITCH_ANGLE_DIR = LVector3f(x=0, y=1, z=0)
|
PITCH_ANGLE_DIR = Vector3D((0, 1, 0))
|
||||||
YAW_ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
YAW_ANGLE_DIR = Vector3D((0, 0, -1))
|
||||||
YAW_ANGLE_REF = LVector3f(x=0, y=1, z=0)
|
YAW_ANGLE_REF = Vector3D((0, 1, 0))
|
||||||
YAW_LOOK_AHEAD = 4
|
YAW_LOOK_AHEAD = 4
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ def tick(global_state):
|
||||||
########## player physics ##########
|
########## player physics ##########
|
||||||
|
|
||||||
if g.path and len(g.path):
|
if g.path and len(g.path):
|
||||||
target = LPoint3f(g.path[0])
|
target = Point3D(g.path[0])
|
||||||
target.x += 0.5
|
target.x += 0.5
|
||||||
target.z += 0.5
|
target.z += 0.5
|
||||||
|
|
||||||
|
@ -142,9 +142,11 @@ def tick(global_state):
|
||||||
g.y_v += g.y_a * utils.TICK
|
g.y_v += g.y_a * utils.TICK
|
||||||
|
|
||||||
block_below = g.chunks.get_block_at(floor(p.x), ceil(p.y-1), floor(p.z))
|
block_below = g.chunks.get_block_at(floor(p.x), ceil(p.y-1), floor(p.z))
|
||||||
|
block_above = g.chunks.get_block_at(floor(p.x), ceil(p.y+1), floor(p.z))
|
||||||
in_void = p.y < 0
|
in_void = p.y < 0
|
||||||
in_air = block_below in blocks.NON_SOLID_IDS or in_void
|
in_air = block_below in blocks.NON_SOLID_IDS or in_void
|
||||||
in_water = block_below in blocks.WATER_IDS
|
in_water = block_below in blocks.WATER_IDS
|
||||||
|
g.crawling = block_above not in blocks.NON_SOLID_IDS
|
||||||
|
|
||||||
if in_air:
|
if in_air:
|
||||||
g.y_a = -36.0
|
g.y_a = -36.0
|
||||||
|
@ -156,11 +158,11 @@ def tick(global_state):
|
||||||
g.y_a = 0
|
g.y_a = 0
|
||||||
|
|
||||||
if g.look_at:
|
if g.look_at:
|
||||||
look_at = LPoint3f(g.look_at)
|
look_at = Point3D(g.look_at)
|
||||||
elif g.path and len(g.path) > YAW_LOOK_AHEAD:
|
elif g.path and len(g.path) > YAW_LOOK_AHEAD:
|
||||||
look_at = LPoint3f(g.path[YAW_LOOK_AHEAD])
|
look_at = Point3D(g.path[YAW_LOOK_AHEAD])
|
||||||
elif g.path and len(g.path):
|
elif g.path and len(g.path):
|
||||||
look_at = LPoint3f(g.path[-1])
|
look_at = Point3D(g.path[-1])
|
||||||
else:
|
else:
|
||||||
look_at = None
|
look_at = None
|
||||||
|
|
||||||
|
@ -178,6 +180,7 @@ def tick(global_state):
|
||||||
# remove vertical component for yaw calculation
|
# remove vertical component for yaw calculation
|
||||||
look_at_d.y = 0
|
look_at_d.y = 0
|
||||||
|
|
||||||
|
if look_at_d.length() > 0.6:
|
||||||
target_yaw = look_at_d.normalized().signedAngleDeg(other=YAW_ANGLE_DIR, ref=YAW_ANGLE_REF)
|
target_yaw = look_at_d.normalized().signedAngleDeg(other=YAW_ANGLE_DIR, ref=YAW_ANGLE_REF)
|
||||||
target_yaw_d = target_yaw - g.yaw
|
target_yaw_d = target_yaw - g.yaw
|
||||||
target_yaw_d = (target_yaw_d + 180) % 360 - 180
|
target_yaw_d = (target_yaw_d + 180) % 360 - 180
|
||||||
|
@ -204,6 +207,7 @@ def init(global_state):
|
||||||
g.y_a = 0
|
g.y_a = 0
|
||||||
g.yaw = 360
|
g.yaw = 360
|
||||||
g.pitch = 0
|
g.pitch = 0
|
||||||
|
g.crawling = False
|
||||||
|
|
||||||
g.breaking = None
|
g.breaking = None
|
||||||
g.break_time = 0
|
g.break_time = 0
|
||||||
|
|
36
game.py
36
game.py
|
@ -8,7 +8,7 @@ from itertools import count
|
||||||
from munch import Munch
|
from munch import Munch
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
from panda3d.core import LPoint3f
|
from vector import Point3D
|
||||||
|
|
||||||
from minecraft.networking.packets import Packet, clientbound, serverbound
|
from minecraft.networking.packets import Packet, clientbound, serverbound
|
||||||
from minecraft.networking.types import BlockFace
|
from minecraft.networking.types import BlockFace
|
||||||
|
@ -21,7 +21,7 @@ from protocol.packets import (
|
||||||
ClientWindowConfirmationPacket, EntityMetadataPacket,
|
ClientWindowConfirmationPacket, EntityMetadataPacket,
|
||||||
SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
|
SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
|
||||||
EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket,
|
EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket,
|
||||||
SelectTradePacket,
|
SelectTradePacket, DisconnectPacket,
|
||||||
)
|
)
|
||||||
|
|
||||||
from protocol.types import Slot
|
from protocol.types import Slot
|
||||||
|
@ -117,9 +117,7 @@ class MCWorld:
|
||||||
log_count += 1
|
log_count += 1
|
||||||
|
|
||||||
for offset in path.CHECK_DIRECTIONS:
|
for offset in path.CHECK_DIRECTIONS:
|
||||||
if self.block_at(*utils.padd(log, offset)) not in blocks.LEAF_IDS:
|
if self.block_at(*utils.padd(log, offset)) in blocks.LEAF_IDS:
|
||||||
break
|
|
||||||
else: # for:
|
|
||||||
good_leaves = True
|
good_leaves = True
|
||||||
|
|
||||||
# make sure it's a good tree
|
# make sure it's a good tree
|
||||||
|
@ -132,7 +130,7 @@ class MCWorld:
|
||||||
|
|
||||||
def find_tree_openings(self, tree):
|
def find_tree_openings(self, tree):
|
||||||
# returns coords in a cardinal direction where we can stand by tree
|
# returns coords in a cardinal direction where we can stand by tree
|
||||||
maze_solver = path.Pathfinder(self.g.chunks)
|
maze_solver = path.Pathfinder(self.g)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
# TODO: make sure only non-solid and leaves between
|
# TODO: make sure only non-solid and leaves between
|
||||||
|
@ -146,7 +144,7 @@ class MCWorld:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def path_to_place(self, start, place):
|
def path_to_place(self, start, place):
|
||||||
maze_solver = path.Pathfinder(self.g.chunks)
|
maze_solver = path.Pathfinder(self.g)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s = maze_solver.astar(start, place)
|
s = maze_solver.astar(start, place)
|
||||||
|
@ -155,8 +153,8 @@ class MCWorld:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def find_bed_areas(self, center, distance):
|
def find_bed_areas(self, center, distance):
|
||||||
bed_clearance = 25 # 5x5 area
|
bed_clearance = 9 # 5x5 area
|
||||||
clear_distance = 3
|
clear_distance = 2
|
||||||
|
|
||||||
for a in self.find_blocks_3d(center, [0], distance, 50):
|
for a in self.find_blocks_3d(center, [0], distance, 50):
|
||||||
# check for air around the area
|
# check for air around the area
|
||||||
|
@ -324,7 +322,7 @@ class MCWorld:
|
||||||
|
|
||||||
def find_villager_openings(self, villager):
|
def find_villager_openings(self, villager):
|
||||||
# returns coords in a cardinal direction where we can stand by a villager
|
# returns coords in a cardinal direction where we can stand by a villager
|
||||||
maze_solver = path.Pathfinder(self.g.chunks)
|
maze_solver = path.Pathfinder(self.g)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for distance in range(3):
|
for distance in range(3):
|
||||||
|
@ -374,6 +372,7 @@ class Game:
|
||||||
register(self.handle_update_health, clientbound.play.UpdateHealthPacket)
|
register(self.handle_update_health, clientbound.play.UpdateHealthPacket)
|
||||||
#register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
|
#register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
|
||||||
register(self.handle_trade_list, TradeListPacket)
|
register(self.handle_trade_list, TradeListPacket)
|
||||||
|
register(self.handle_disconnect, DisconnectPacket)
|
||||||
|
|
||||||
#register(self.handle_packet, Packet, early=True)
|
#register(self.handle_packet, Packet, early=True)
|
||||||
|
|
||||||
|
@ -393,11 +392,11 @@ class Game:
|
||||||
def handle_block_change(self, packet):
|
def handle_block_change(self, packet):
|
||||||
if packet.block_state_id == blocks.SOUL_TORCH:
|
if packet.block_state_id == blocks.SOUL_TORCH:
|
||||||
try:
|
try:
|
||||||
self.g.goal = LPoint3f(x=packet.location[0], y=packet.location[1], z=packet.location[2])
|
self.g.goal = Point3D((packet.location[0], packet.location[1], packet.location[2]))
|
||||||
print('new waypoint:', self.g.goal)
|
print('new waypoint:', self.g.goal)
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
solution = path.Pathfinder(self.g.chunks).astar(utils.pint(self.g.pos), utils.pint(self.g.goal))
|
solution = path.Pathfinder(self.g).astar(utils.pint(self.g.pos), utils.pint(self.g.goal))
|
||||||
if solution:
|
if solution:
|
||||||
solution = list(solution)
|
solution = list(solution)
|
||||||
self.g.path = solution
|
self.g.path = solution
|
||||||
|
@ -420,7 +419,7 @@ class Game:
|
||||||
|
|
||||||
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 = Point3D((packet.x, packet.y, packet.z))
|
||||||
self.g.pos = p
|
self.g.pos = p
|
||||||
|
|
||||||
confirm_packet = serverbound.play.TeleportConfirmPacket()
|
confirm_packet = serverbound.play.TeleportConfirmPacket()
|
||||||
|
@ -851,6 +850,11 @@ class Game:
|
||||||
data = data.replace('^', '.')
|
data = data.replace('^', '.')
|
||||||
reply = str(eval(data))
|
reply = str(eval(data))
|
||||||
|
|
||||||
|
if command == 'exit':
|
||||||
|
import os
|
||||||
|
os._exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -1230,6 +1234,12 @@ class Game:
|
||||||
packet.selected_slot = num
|
packet.selected_slot = num
|
||||||
self.g.connection.write_packet(packet)
|
self.g.connection.write_packet(packet)
|
||||||
|
|
||||||
|
def handle_disconnect(self, packet):
|
||||||
|
print(packet)
|
||||||
|
print('Client disconnected!')
|
||||||
|
import os
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
if self.g.breaking:
|
if self.g.breaking:
|
||||||
self.animate()
|
self.animate()
|
||||||
|
|
51
jobs.py
51
jobs.py
|
@ -732,7 +732,51 @@ class SleepWithBedStates:
|
||||||
self.state = self.cleanup
|
self.state = self.cleanup
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.state = self.find_beds
|
||||||
|
|
||||||
|
def find_beds(self):
|
||||||
|
print('Finding beds...')
|
||||||
|
w = self.g.world
|
||||||
|
p = utils.pint(self.g.pos)
|
||||||
|
|
||||||
|
self.beds = w.find_blocks_indexed(p, blocks.BED_IDS)
|
||||||
|
print('Found:', self.beds)
|
||||||
|
self.state = self.choose_bed
|
||||||
|
|
||||||
|
def choose_bed(self):
|
||||||
|
print('Choosing a bed...')
|
||||||
|
w = self.g.world
|
||||||
|
p = utils.pint(self.g.pos)
|
||||||
|
c = self.g.chunks
|
||||||
|
|
||||||
|
if not len(self.beds):
|
||||||
|
print('No beds')
|
||||||
self.state = self.select_bed
|
self.state = self.select_bed
|
||||||
|
return
|
||||||
|
|
||||||
|
bed = self.beds[0]
|
||||||
|
|
||||||
|
tmp = c.get_block_at(*bed)
|
||||||
|
c.set_block_at(*bed, blocks.AIR)
|
||||||
|
navpath = w.path_to_place(p, bed)
|
||||||
|
c.set_block_at(*bed, tmp)
|
||||||
|
|
||||||
|
print('navpath:', navpath)
|
||||||
|
|
||||||
|
if navpath:
|
||||||
|
self.g.path = navpath[:-1]
|
||||||
|
self.opening = self.g.path[-1]
|
||||||
|
self.area = bed
|
||||||
|
self.state = self.going_to_bed
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.beds.pop(0)
|
||||||
|
|
||||||
|
def going_to_bed(self):
|
||||||
|
if utils.pint(self.g.pos) == self.opening:
|
||||||
|
self.my_bed = False
|
||||||
|
self.g.look_at = self.area
|
||||||
|
self.state = self.use_bed
|
||||||
|
|
||||||
def select_bed(self):
|
def select_bed(self):
|
||||||
if self.g.game.select_item(items.BED_IDS):
|
if self.g.game.select_item(items.BED_IDS):
|
||||||
|
@ -778,6 +822,7 @@ class SleepWithBedStates:
|
||||||
|
|
||||||
def place_bed(self):
|
def place_bed(self):
|
||||||
self.g.game.place_block(self.area, BlockFace.TOP)
|
self.g.game.place_block(self.area, BlockFace.TOP)
|
||||||
|
self.my_bed = True
|
||||||
self.state = self.use_bed
|
self.state = self.use_bed
|
||||||
|
|
||||||
def use_bed(self):
|
def use_bed(self):
|
||||||
|
@ -803,8 +848,12 @@ class SleepWithBedStates:
|
||||||
self.state = self.break_bed
|
self.state = self.break_bed
|
||||||
|
|
||||||
def break_bed(self):
|
def break_bed(self):
|
||||||
|
if self.my_bed:
|
||||||
self.g.game.break_block(self.area)
|
self.g.game.break_block(self.area)
|
||||||
self.state = self.collect_bed
|
self.state = self.collect_bed
|
||||||
|
else:
|
||||||
|
self.state = self.cleanup
|
||||||
|
|
||||||
|
|
||||||
def collect_bed(self):
|
def collect_bed(self):
|
||||||
if not self.g.breaking:
|
if not self.g.breaking:
|
||||||
|
@ -833,6 +882,8 @@ class SleepWithBedStates:
|
||||||
|
|
||||||
self.silent = False
|
self.silent = False
|
||||||
|
|
||||||
|
self.my_bed = False
|
||||||
|
self.beds = []
|
||||||
self.area = None
|
self.area = None
|
||||||
self.opening = None
|
self.opening = None
|
||||||
self.bad_areas = []
|
self.bad_areas = []
|
||||||
|
|
|
@ -19,6 +19,7 @@ def get_packets(old_get_packets):
|
||||||
mc_packets.add(packets.DestroyEntitiesPacket)
|
mc_packets.add(packets.DestroyEntitiesPacket)
|
||||||
mc_packets.add(packets.EntityTeleport)
|
mc_packets.add(packets.EntityTeleport)
|
||||||
mc_packets.add(packets.TradeListPacket)
|
mc_packets.add(packets.TradeListPacket)
|
||||||
|
mc_packets.add(packets.DisconnectPacket)
|
||||||
|
|
||||||
|
|
||||||
return mc_packets
|
return mc_packets
|
||||||
|
|
27
path.py
27
path.py
|
@ -121,8 +121,9 @@ HALF_PARKOUR = {
|
||||||
BLOCK_CACHE_SIZE = 2**14
|
BLOCK_CACHE_SIZE = 2**14
|
||||||
|
|
||||||
class Pathfinder(AStar):
|
class Pathfinder(AStar):
|
||||||
def __init__(self, chunks):
|
def __init__(self, g):
|
||||||
self.chunks = chunks
|
self.g = g
|
||||||
|
self.chunks = g.chunks
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=BLOCK_CACHE_SIZE)
|
@functools.lru_cache(maxsize=BLOCK_CACHE_SIZE)
|
||||||
|
@ -133,6 +134,23 @@ class Pathfinder(AStar):
|
||||||
def bavoid(self, p):
|
def bavoid(self, p):
|
||||||
return self.chunks.get_block_at(*p) in blocks.AVOID_IDS or p[1] < 0
|
return self.chunks.get_block_at(*p) in blocks.AVOID_IDS or p[1] < 0
|
||||||
|
|
||||||
|
def check_traverse_crawling(self, node, offset):
|
||||||
|
dest = utils.padd(node, offset)
|
||||||
|
|
||||||
|
if not self.bair(dest):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.bair(utils.padd(dest, BLOCK_BELOW)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.bavoid(dest):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.bavoid(utils.padd(dest, BLOCK_BELOW)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def check_traverse(self, node, offset):
|
def check_traverse(self, node, offset):
|
||||||
dest = utils.padd(node, offset)
|
dest = utils.padd(node, offset)
|
||||||
|
|
||||||
|
@ -254,6 +272,11 @@ class Pathfinder(AStar):
|
||||||
def neighbors(self, node):
|
def neighbors(self, node):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
if self.g.crawling:
|
||||||
|
for offset in TRAVERSE:
|
||||||
|
if self.check_traverse_crawling(node, offset):
|
||||||
|
results.append(utils.padd(node, offset))
|
||||||
|
else:
|
||||||
for offset in TRAVERSE:
|
for offset in TRAVERSE:
|
||||||
if self.check_traverse(node, offset):
|
if self.check_traverse(node, offset):
|
||||||
results.append(utils.padd(node, offset))
|
results.append(utils.padd(node, offset))
|
||||||
|
|
|
@ -447,3 +447,14 @@ class SelectTradePacket(Packet):
|
||||||
definition = [
|
definition = [
|
||||||
{'selected_slot': VarInt},
|
{'selected_slot': VarInt},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class DisconnectPacket(Packet):
|
||||||
|
# Sent by the server before it disconnects a client
|
||||||
|
# https://wiki.vg/Protocol#Disconnect_.28play.29
|
||||||
|
|
||||||
|
id = 0x19
|
||||||
|
packet_name = 'disconnect'
|
||||||
|
|
||||||
|
definition = [
|
||||||
|
{'reason': String},
|
||||||
|
]
|
||||||
|
|
123
vector.py
Normal file
123
vector.py
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import math
|
||||||
|
|
||||||
|
class Vector3D:
|
||||||
|
def __init__(self, vector):
|
||||||
|
self.x = vector[0]
|
||||||
|
self.y = vector[1]
|
||||||
|
self.z = vector[2]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xz(self):
|
||||||
|
return Vector3D((self.x, 0, self.z))
|
||||||
|
|
||||||
|
def tuple(self):
|
||||||
|
return (self.x, self.y, self.z)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.tuple()[key]
|
||||||
|
|
||||||
|
def length(self):
|
||||||
|
return math.hypot(self.x, self.y, self.z)
|
||||||
|
|
||||||
|
def normalized(self):
|
||||||
|
x = self.x / self.length()
|
||||||
|
y = self.y / self.length()
|
||||||
|
z = self.z / self.length()
|
||||||
|
return Vector3D((x, y, z))
|
||||||
|
|
||||||
|
def dot(self, other):
|
||||||
|
return self.x * other.x + self.y * other.y + self.z * other.z
|
||||||
|
|
||||||
|
def cross(self, other):
|
||||||
|
a1, a2, a3 = self.tuple()
|
||||||
|
b1, b2, b3 = other.tuple()
|
||||||
|
return Vector3D((a2*b3-a3*b2, a3*b1-a1*b3, a1*b2-a2*b1))
|
||||||
|
|
||||||
|
def angleDeg(self, other):
|
||||||
|
ratio = self.dot(other) / (self.length() * other.length())
|
||||||
|
rads = math.acos(ratio)
|
||||||
|
return math.degrees(rads)
|
||||||
|
|
||||||
|
def signedAngleDeg(self, other, ref):
|
||||||
|
angle1 = self.angleDeg(other)
|
||||||
|
cross = self.cross(ref)
|
||||||
|
angle2 = other.angleDeg(cross)
|
||||||
|
if angle2 < 90:
|
||||||
|
return -angle1
|
||||||
|
else:
|
||||||
|
return angle1
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'Vector3D(x={}, y={}, z={})'.format(self.x, self.y, self.z)
|
||||||
|
def __str__(self):
|
||||||
|
return '[{}, {}, {}]'.format(self.x, self.y, self.z)
|
||||||
|
|
||||||
|
class Point3D:
|
||||||
|
def __init__(self, point):
|
||||||
|
self.x = point[0]
|
||||||
|
self.y = point[1]
|
||||||
|
self.z = point[2]
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
#x = other.x - self.x
|
||||||
|
#y = other.y - self.y
|
||||||
|
#z = other.z - self.z
|
||||||
|
x = self.x - other.x
|
||||||
|
y = self.y - other.y
|
||||||
|
z = self.z - other.z
|
||||||
|
return Vector3D((x, y, z))
|
||||||
|
|
||||||
|
def tuple(self):
|
||||||
|
return (self.x, self.y, self.z)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.tuple()[key]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'Point3D(x={}, y={}, z={})'.format(self.x, self.y, self.z)
|
||||||
|
def __str__(self):
|
||||||
|
return '({}, {}, {})'.format(self.x, self.y, self.z)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# test to make sure our Vector module is the same as Panda3D
|
||||||
|
|
||||||
|
from panda3d.core import LPoint3f, LVector3f
|
||||||
|
import random
|
||||||
|
|
||||||
|
pPITCH_ANGLE_DIR = LVector3f(x=0, y=1, z=0)
|
||||||
|
pYAW_ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
||||||
|
pYAW_ANGLE_REF = LVector3f(x=0, y=1, z=0)
|
||||||
|
|
||||||
|
PITCH_ANGLE_DIR = Vector3D((0, 1, 0))
|
||||||
|
YAW_ANGLE_DIR = Vector3D((0, 0, -1))
|
||||||
|
YAW_ANGLE_REF = Vector3D((0, 1, 0))
|
||||||
|
|
||||||
|
for _ in range(1000):
|
||||||
|
r = lambda: random.uniform(-10, 10)
|
||||||
|
a, b, c = r(), r(), r()
|
||||||
|
plook_at_d = LVector3f(x=a, y=b, z=c)
|
||||||
|
look_at_d = Vector3D((a, b, c))
|
||||||
|
|
||||||
|
ptarget_pitch = plook_at_d.normalized().angleDeg(pPITCH_ANGLE_DIR)
|
||||||
|
target_pitch = look_at_d.normalized().angleDeg(PITCH_ANGLE_DIR)
|
||||||
|
|
||||||
|
if round(ptarget_pitch) != round(target_pitch):
|
||||||
|
print('mismatch:', ptarget_pitch, target_pitch)
|
||||||
|
break
|
||||||
|
else: # for
|
||||||
|
print('no mismatches')
|
||||||
|
|
||||||
|
for _ in range(1000):
|
||||||
|
r = lambda: random.uniform(-10, 10)
|
||||||
|
a, b, c = r(), r(), r()
|
||||||
|
plook_at_d = LVector3f(x=a, y=b, z=c)
|
||||||
|
look_at_d = Vector3D((a, b, c))
|
||||||
|
|
||||||
|
ptarget_yaw = plook_at_d.normalized().signedAngleDeg(other=pYAW_ANGLE_DIR, ref=pYAW_ANGLE_REF)
|
||||||
|
target_yaw = look_at_d.normalized().signedAngleDeg(other=YAW_ANGLE_DIR, ref=YAW_ANGLE_REF)
|
||||||
|
|
||||||
|
if round(ptarget_yaw) != round(target_yaw):
|
||||||
|
print('mismatch:', ptarget_yaw, target_yaw)
|
||||||
|
break
|
||||||
|
else: # for
|
||||||
|
print('no mismatches')
|
Loading…
Reference in New Issue
Block a user