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',
|
||||
]
|
||||
|
||||
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 = [
|
||||
'chest',
|
||||
'trapped_chest',
|
||||
'emerald_block',
|
||||
'barrel',
|
||||
]
|
||||
] + BEDS
|
||||
|
||||
|
||||
NON_SOLID_IDS = set([SINGLE_SNOW])
|
||||
|
@ -310,16 +329,23 @@ for block_name in ['beetroots']:
|
|||
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||
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()
|
||||
for block_name in SAPLINGS:
|
||||
for state in JSON_BLOCKS['minecraft:' + block_name]['states']:
|
||||
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_POTATO_ID = max(POTATO_IDS)
|
||||
MATURE_CARROT_ID = max(CARROT_IDS)
|
||||
|
|
24
bot.py
24
bot.py
|
@ -24,7 +24,7 @@ from minecraft.networking.packets import Packet, clientbound, serverbound
|
|||
from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException
|
||||
|
||||
from munch import Munch
|
||||
from panda3d.core import LPoint3f, LVector3f
|
||||
from vector import Point3D, Vector3D
|
||||
|
||||
import game
|
||||
importlib.reload(game)
|
||||
|
@ -41,9 +41,9 @@ importlib.reload(mcdata)
|
|||
|
||||
last_tick = time.time()
|
||||
|
||||
PITCH_ANGLE_DIR = LVector3f(x=0, y=1, z=0)
|
||||
YAW_ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
||||
YAW_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))
|
||||
YAW_LOOK_AHEAD = 4
|
||||
|
||||
|
||||
|
@ -105,7 +105,7 @@ def tick(global_state):
|
|||
########## player physics ##########
|
||||
|
||||
if g.path and len(g.path):
|
||||
target = LPoint3f(g.path[0])
|
||||
target = Point3D(g.path[0])
|
||||
target.x += 0.5
|
||||
target.z += 0.5
|
||||
|
||||
|
@ -142,9 +142,11 @@ def tick(global_state):
|
|||
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_above = g.chunks.get_block_at(floor(p.x), ceil(p.y+1), floor(p.z))
|
||||
in_void = p.y < 0
|
||||
in_air = block_below in blocks.NON_SOLID_IDS or in_void
|
||||
in_water = block_below in blocks.WATER_IDS
|
||||
g.crawling = block_above not in blocks.NON_SOLID_IDS
|
||||
|
||||
if in_air:
|
||||
g.y_a = -36.0
|
||||
|
@ -156,11 +158,11 @@ def tick(global_state):
|
|||
g.y_a = 0
|
||||
|
||||
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:
|
||||
look_at = LPoint3f(g.path[YAW_LOOK_AHEAD])
|
||||
look_at = Point3D(g.path[YAW_LOOK_AHEAD])
|
||||
elif g.path and len(g.path):
|
||||
look_at = LPoint3f(g.path[-1])
|
||||
look_at = Point3D(g.path[-1])
|
||||
else:
|
||||
look_at = None
|
||||
|
||||
|
@ -175,9 +177,10 @@ def tick(global_state):
|
|||
target_pitch_d = target_pitch - g.pitch
|
||||
g.pitch += utils.cap(target_pitch_d, 10)
|
||||
|
||||
# remove vertical component for yaw calculation
|
||||
look_at_d.y = 0
|
||||
# remove vertical component for yaw calculation
|
||||
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_d = target_yaw - g.yaw
|
||||
target_yaw_d = (target_yaw_d + 180) % 360 - 180
|
||||
|
@ -204,6 +207,7 @@ def init(global_state):
|
|||
g.y_a = 0
|
||||
g.yaw = 360
|
||||
g.pitch = 0
|
||||
g.crawling = False
|
||||
|
||||
g.breaking = None
|
||||
g.break_time = 0
|
||||
|
|
38
game.py
38
game.py
|
@ -8,7 +8,7 @@ from itertools import count
|
|||
from munch import Munch
|
||||
from copy import copy
|
||||
|
||||
from panda3d.core import LPoint3f
|
||||
from vector import Point3D
|
||||
|
||||
from minecraft.networking.packets import Packet, clientbound, serverbound
|
||||
from minecraft.networking.types import BlockFace
|
||||
|
@ -21,7 +21,7 @@ from protocol.packets import (
|
|||
ClientWindowConfirmationPacket, EntityMetadataPacket,
|
||||
SpawnLivingEntityPacket, EntityPositionRotationPacket, DestroyEntitiesPacket,
|
||||
EntityActionPacket, EntityTeleport, InteractEntityPacket, TradeListPacket,
|
||||
SelectTradePacket,
|
||||
SelectTradePacket, DisconnectPacket,
|
||||
)
|
||||
|
||||
from protocol.types import Slot
|
||||
|
@ -117,10 +117,8 @@ class MCWorld:
|
|||
log_count += 1
|
||||
|
||||
for offset in path.CHECK_DIRECTIONS:
|
||||
if self.block_at(*utils.padd(log, offset)) not in blocks.LEAF_IDS:
|
||||
break
|
||||
else: # for:
|
||||
good_leaves = True
|
||||
if self.block_at(*utils.padd(log, offset)) in blocks.LEAF_IDS:
|
||||
good_leaves = True
|
||||
|
||||
# make sure it's a good tree
|
||||
if not good_leaves or log_count < 3:
|
||||
|
@ -132,7 +130,7 @@ class MCWorld:
|
|||
|
||||
def find_tree_openings(self, 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 = []
|
||||
|
||||
# TODO: make sure only non-solid and leaves between
|
||||
|
@ -146,7 +144,7 @@ class MCWorld:
|
|||
return result
|
||||
|
||||
def path_to_place(self, start, place):
|
||||
maze_solver = path.Pathfinder(self.g.chunks)
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
|
||||
try:
|
||||
s = maze_solver.astar(start, place)
|
||||
|
@ -155,8 +153,8 @@ class MCWorld:
|
|||
return None
|
||||
|
||||
def find_bed_areas(self, center, distance):
|
||||
bed_clearance = 25 # 5x5 area
|
||||
clear_distance = 3
|
||||
bed_clearance = 9 # 5x5 area
|
||||
clear_distance = 2
|
||||
|
||||
for a in self.find_blocks_3d(center, [0], distance, 50):
|
||||
# check for air around the area
|
||||
|
@ -324,7 +322,7 @@ class MCWorld:
|
|||
|
||||
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)
|
||||
maze_solver = path.Pathfinder(self.g)
|
||||
result = []
|
||||
|
||||
for distance in range(3):
|
||||
|
@ -374,6 +372,7 @@ class Game:
|
|||
register(self.handle_update_health, clientbound.play.UpdateHealthPacket)
|
||||
#register(self.handle_entity_velocity, clientbound.play.EntityVelocityPacket)
|
||||
register(self.handle_trade_list, TradeListPacket)
|
||||
register(self.handle_disconnect, DisconnectPacket)
|
||||
|
||||
#register(self.handle_packet, Packet, early=True)
|
||||
|
||||
|
@ -393,11 +392,11 @@ class Game:
|
|||
def handle_block_change(self, packet):
|
||||
if packet.block_state_id == blocks.SOUL_TORCH:
|
||||
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)
|
||||
|
||||
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:
|
||||
solution = list(solution)
|
||||
self.g.path = solution
|
||||
|
@ -420,7 +419,7 @@ class Game:
|
|||
|
||||
def handle_position_and_look(self, 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
|
||||
|
||||
confirm_packet = serverbound.play.TeleportConfirmPacket()
|
||||
|
@ -851,6 +850,11 @@ class Game:
|
|||
data = data.replace('^', '.')
|
||||
reply = str(eval(data))
|
||||
|
||||
if command == 'exit':
|
||||
import os
|
||||
os._exit(0)
|
||||
|
||||
|
||||
|
||||
except BaseException as e:
|
||||
import traceback
|
||||
|
@ -1230,6 +1234,12 @@ class Game:
|
|||
packet.selected_slot = num
|
||||
self.g.connection.write_packet(packet)
|
||||
|
||||
def handle_disconnect(self, packet):
|
||||
print(packet)
|
||||
print('Client disconnected!')
|
||||
import os
|
||||
os._exit(1)
|
||||
|
||||
def tick(self):
|
||||
if self.g.breaking:
|
||||
self.animate()
|
||||
|
|
57
jobs.py
57
jobs.py
|
@ -732,7 +732,51 @@ class SleepWithBedStates:
|
|||
self.state = self.cleanup
|
||||
return
|
||||
|
||||
self.state = self.select_bed
|
||||
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
|
||||
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):
|
||||
if self.g.game.select_item(items.BED_IDS):
|
||||
|
@ -778,6 +822,7 @@ class SleepWithBedStates:
|
|||
|
||||
def place_bed(self):
|
||||
self.g.game.place_block(self.area, BlockFace.TOP)
|
||||
self.my_bed = True
|
||||
self.state = self.use_bed
|
||||
|
||||
def use_bed(self):
|
||||
|
@ -803,8 +848,12 @@ class SleepWithBedStates:
|
|||
self.state = self.break_bed
|
||||
|
||||
def break_bed(self):
|
||||
self.g.game.break_block(self.area)
|
||||
self.state = self.collect_bed
|
||||
if self.my_bed:
|
||||
self.g.game.break_block(self.area)
|
||||
self.state = self.collect_bed
|
||||
else:
|
||||
self.state = self.cleanup
|
||||
|
||||
|
||||
def collect_bed(self):
|
||||
if not self.g.breaking:
|
||||
|
@ -833,6 +882,8 @@ class SleepWithBedStates:
|
|||
|
||||
self.silent = False
|
||||
|
||||
self.my_bed = False
|
||||
self.beds = []
|
||||
self.area = None
|
||||
self.opening = None
|
||||
self.bad_areas = []
|
||||
|
|
|
@ -19,6 +19,7 @@ def get_packets(old_get_packets):
|
|||
mc_packets.add(packets.DestroyEntitiesPacket)
|
||||
mc_packets.add(packets.EntityTeleport)
|
||||
mc_packets.add(packets.TradeListPacket)
|
||||
mc_packets.add(packets.DisconnectPacket)
|
||||
|
||||
|
||||
return mc_packets
|
||||
|
|
69
path.py
69
path.py
|
@ -121,8 +121,9 @@ HALF_PARKOUR = {
|
|||
BLOCK_CACHE_SIZE = 2**14
|
||||
|
||||
class Pathfinder(AStar):
|
||||
def __init__(self, chunks):
|
||||
self.chunks = chunks
|
||||
def __init__(self, g):
|
||||
self.g = g
|
||||
self.chunks = g.chunks
|
||||
self.start_time = time.time()
|
||||
|
||||
@functools.lru_cache(maxsize=BLOCK_CACHE_SIZE)
|
||||
|
@ -133,6 +134,23 @@ class Pathfinder(AStar):
|
|||
def bavoid(self, p):
|
||||
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):
|
||||
dest = utils.padd(node, offset)
|
||||
|
||||
|
@ -254,27 +272,32 @@ class Pathfinder(AStar):
|
|||
def neighbors(self, node):
|
||||
results = []
|
||||
|
||||
for offset in TRAVERSE:
|
||||
if self.check_traverse(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DIAGONAL:
|
||||
if self.check_diagonal(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in ASCEND:
|
||||
if self.check_ascend(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND:
|
||||
if self.check_descend(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND2:
|
||||
if self.check_descend2(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND3:
|
||||
if self.check_descend3(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in PARKOUR:
|
||||
if self.check_parkour(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
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:
|
||||
if self.check_traverse(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DIAGONAL:
|
||||
if self.check_diagonal(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in ASCEND:
|
||||
if self.check_ascend(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND:
|
||||
if self.check_descend(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND2:
|
||||
if self.check_descend2(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in DESCEND3:
|
||||
if self.check_descend3(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
for offset in PARKOUR:
|
||||
if self.check_parkour(node, offset):
|
||||
results.append(utils.padd(node, offset))
|
||||
|
||||
if not results:
|
||||
if time.time() - self.start_time > 2.0:
|
||||
|
|
|
@ -447,3 +447,14 @@ class SelectTradePacket(Packet):
|
|||
definition = [
|
||||
{'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