-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Pitch40 update #6007
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pitch40 update #6007
Conversation
Added more options for Pitch40. Changed default settings for Pitch40, increasing the average speed (25.5768 → 28.8312). Even higher average speeds could be achieved with the same pitch lock settings(~30), but using a greater(~100) height difference. Values were generated using simulated annealing (python). Tested in both singleplayer and on a server (with Grim AntiCheat).
|
interesting! could you share the simulation code used to generate the values? |
|
python generator (ChatGPT + Heppe's python code + My Brain) import math
import random
# =========================
# Vector & Physics (YOURS)
# =========================
class Vec3:
def __init__(self, x=0, y=0, z=0):
self.x = x
self.y = y
self.z = z
def add(self, x, y, z):
return Vec3(self.x + x, self.y + y, self.z + z)
def horizontalDistance(self):
return math.sqrt(self.x * self.x + self.z * self.z)
def length(self):
return math.sqrt(self.x * self.x + self.z * self.z + self.y * self.y)
def multiply(self, x, y, z):
return Vec3(self.x * x, self.y * y, self.z * z)
def copy(self):
return Vec3(self.x, self.y, self.z)
def lookAngle(xRot, yRot):
f = xRot * math.pi / 180.0
f1 = -yRot * math.pi / 180.0
f2 = math.cos(f1)
f3 = math.sin(f1)
f4 = math.cos(f)
f5 = math.sin(f)
return Vec3((f3 * f4), (-f5), (f2 * f4))
def elytraPointer(
ticks,
xRot=0,
yRot=-90,
deltaMovement=Vec3(),
deltaXRot=0,
height=float('inf'),
startingPosition=Vec3(),
delta2_rot=None
):
position = startingPosition
for _ in range(ticks):
vec3 = deltaMovement
vec31 = lookAngle(xRot, yRot)
f = xRot * math.pi / 180.0
d0 = 0.08
d1 = math.cos(f)
d3 = vec3.horizontalDistance()
d5 = math.cos(f) ** 2
vec3 = deltaMovement.add(0.0, d0 * (-1.0 + d5 * 0.75), 0.0)
if d1 != 0:
if vec3.y < 0.0:
d6 = vec3.y * -0.1 * d5
vec3 = vec3.add(
vec31.x * d6 / d1,
d6,
vec31.z * d6 / d1
)
if f < 0.0:
d10 = d3 * (-math.sin(f)) * 0.04
vec3 = vec3.add(
-vec31.x * d10 / d1,
d10 * 3.2,
-vec31.z * d10 / d1
)
vec3 = vec3.add(
(vec31.x / d1 * d3 - vec3.x) * 0.1,
0.0,
(vec31.z / d1 * d3 - vec3.z) * 0.1
)
deltaMovement = vec3.multiply(0.99, 0.98, 0.99)
position = position.add(deltaMovement.x, deltaMovement.y, deltaMovement.z)
if height + position.y <= 0:
return position, deltaMovement
return position, deltaMovement
# =========================
# Infinite Flight Controller
# =========================
class InfinitePitchController:
def __init__(
self,
height_delta,
pitch_up_speed,
pitch_down_speed,
down_angle,
up_angle
):
self.height_delta = height_delta
self.pitch_up_speed = pitch_up_speed
self.pitch_down_speed = pitch_down_speed
self.down_angle = down_angle
self.up_angle = up_angle
self.pitch = down_angle
self.pitching_down = True
self.base_height = 0
def rand(self, base, jitter):
return base #+ random.uniform(-jitter, jitter)
def tick(self, y):
lower = self.base_height
upper = self.base_height + self.height_delta
if self.pitching_down and y <= lower:
self.pitching_down = False
elif not self.pitching_down and y >= upper:
self.pitching_down = True
if not self.pitching_down:
self.pitch -= self.rand(self.pitch_up_speed, 3.0)
if self.pitch < self.up_angle:
self.pitch = self.up_angle
#self.ticks = 0
self.pitching_down = True
else:
if self.pitch < self.down_angle:
#self.ticks += 1
#coef = 1 + min(1, self.ticks / 50)
self.pitch += self.rand(self.pitch_down_speed * 1, 0.125)
return self.pitch
# =========================
# Simulation
# =========================
def simulate_flight(controller, ticks=10_000):
pos = Vec3(0, controller.height_delta, 0)
vel = Vec3(0, 0, 0)
for _ in range(ticks):
pitch = controller.tick(pos.y)
pos, vel = elytraPointer(
ticks=1,
xRot=pitch,
yRot=-90,
deltaMovement=vel,
startingPosition=pos
)
if pos.y <= -10:
return False, pos.x
return True, pos.x
def fitness(ctrl):
alive, dist = simulate_flight(ctrl)
return dist if alive else -1e9
# =========================
# Simulated Annealing
# =========================
def clamp(v, lo, hi):
return max(lo, min(hi, v))
def simulated_annealing(
steps=2000,
T_start=1000.0,
T_end=1.0
):
'''
height_delta=80.0,
pitch_up_speed=7.04,
pitch_down_speed=1.10,
down_angle=38.95,
up_angle=-63.01
'''
current = InfinitePitchController(
# Put some values and code will try to find a better option
height_delta=40,
pitch_up_speed=5.45,
pitch_down_speed=0.90,
down_angle=37.72,
up_angle=-54.77
# 15199.6
)
current_score = fitness(current)
best = current
best_score = current_score
for step in range(steps):
T = T_start * ((T_end / T_start) ** (step / steps))
candidate = InfinitePitchController(
height_delta=clamp(
current.height_delta + random.uniform(-2, 2),
40, 100
),
pitch_up_speed=clamp(
current.pitch_up_speed + random.uniform(-1, 1),
0.1, 30
),
pitch_down_speed=clamp(
current.pitch_down_speed + random.uniform(-0.1, 0.1),
0.1, 10.0
),
down_angle=clamp(
current.down_angle + random.uniform(-0.5, 0.5),
20, 60
),
up_angle=clamp(
current.up_angle + random.uniform(-1, 1),
-70, -30
)
)
score = fitness(candidate)
delta = score - current_score
if delta > 0 or random.random() < math.exp(delta / T):
current = candidate
current_score = score
if score > best_score:
best = candidate
best_score = score
print(f"[NEW BEST] {best_score:.1f}")
return best, best_score
# =========================
# Run
# =========================
if __name__ == "__main__":
best, score = simulated_annealing()
print("\n=== OPTIMAL PARAMETERS (SA) ===")
print(f"Height delta : {best.height_delta:.2f}")
print(f"Pitch up speed : {best.pitch_up_speed:.2f}")
print(f"Pitch down speed : {best.pitch_down_speed:.2f}")
print(f"Down angle : {best.down_angle:.2f}")
print(f"Up angle : {best.up_angle:.2f}")
print(f"Distance (10k ticks): {score:.1f}")
|
|
visual.py import math
import random
import matplotlib.pyplot as plt
# =========================
# Vector & Physics
# =========================
class Vec3:
def __init__(self, x=0, y=0, z=0):
self.x = x
self.y = y
self.z = z
def add(self, x, y, z):
return Vec3(self.x + x, self.y + y, self.z + z)
def horizontalDistance(self):
return math.sqrt(self.x * self.x + self.z * self.z)
def multiply(self, x, y, z):
return Vec3(self.x * x, self.y * y, self.z * z)
def lookAngle(xRot, yRot):
f = xRot * math.pi / 180.0
f1 = -yRot * math.pi / 180.0
return Vec3(
math.sin(f1) * math.cos(f),
-math.sin(f),
math.cos(f1) * math.cos(f)
)
def elytraPointer(ticks, xRot, yRot, deltaMovement, startingPosition):
pos = startingPosition
vel = deltaMovement
for _ in range(ticks):
look = lookAngle(xRot, yRot)
f = xRot * math.pi / 180.0
d0 = 0.08
d1 = math.cos(f)
d3 = vel.horizontalDistance()
d5 = math.cos(f) ** 2
vel = vel.add(0, d0 * (-1 + d5 * 0.75), 0)
if d1 != 0:
if vel.y < 0:
d6 = vel.y * -0.1 * d5
vel = vel.add(look.x * d6 / d1, d6, look.z * d6 / d1)
if f < 0:
d10 = d3 * (-math.sin(f)) * 0.04
vel = vel.add(
-look.x * d10 / d1,
d10 * 3.2,
-look.z * d10 / d1
)
vel = vel.add(
(look.x / d1 * d3 - vel.x) * 0.1,
0,
(look.z / d1 * d3 - vel.z) * 0.1
)
vel = vel.multiply(0.99, 0.98, 0.99)
pos = pos.add(vel.x, vel.y, vel.z)
if pos.y <= 0:
break
return pos, vel
# =========================
# BASIC CONTROLLER
# =========================
class BasicController:
def __init__(self):
'''
#Fork
self.height_delta = 40
self.pitch_up_speed = 5.45
self.pitch_down_speed = 0.90
self.down_angle = 37.72
self.up_angle = -54.77
'''
'''
#Legacy
self.height_delta = 60
self.pitch_up_speed = 4
self.pitch_down_speed = 4
self.down_angle = 40
self.up_angle = -40
'''
#Modern
self.height_delta = 40
self.pitch_up_speed = 15
self.pitch_down_speed = 0.5
self.down_angle = 32
self.up_angle = -49
self.pitch = self.down_angle
self.pitching_down = True
self.base_height = 0
def tick(self, y):
lower = self.base_height
upper = self.base_height + self.height_delta
if self.pitching_down and y <= lower:
self.pitching_down = False
elif not self.pitching_down and y >= upper:
self.pitching_down = True
if not self.pitching_down:
self.pitch -= self.pitch_up_speed
if self.pitch < self.up_angle:
self.pitch = self.up_angle
self.pitching_down = True
else:
if self.pitch < self.down_angle:
self.pitch += self.pitch_down_speed
return self.pitch
# =========================
# DATA COLLECTION
# =========================
def collect_data(ticks=30000):
ctrl = BasicController()
pos = Vec3(0, ctrl.height_delta, 0)
vel = Vec3(0, 0, 0)
prev_pitch = ctrl.pitch
data = []
for _ in range(ticks):
pitch = ctrl.tick(pos.y)
xSpeed = vel.horizontalDistance()
ySpeed = vel.y
data.append((
pos.y,
xSpeed,
ySpeed,
prev_pitch,
pitch
))
pos, vel = elytraPointer(
ticks=1,
xRot=pitch,
yRot=-90,
deltaMovement=vel,
startingPosition=pos
)
prev_pitch = pitch
if pos.y <= -10:
break
return data
# =========================
# VISUALIZATION
# =========================
def visualize(data):
h = [d[0] for d in data]
xs = [d[1] for d in data]
ys = [d[2] for d in data]
p = [d[4] for d in data]
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.scatter(h, p, s=2)
plt.xlabel("Height")
plt.ylabel("xRot")
plt.subplot(2, 2, 2)
plt.scatter(xs, p, s=2)
plt.xlabel("xSpeed")
plt.ylabel("xRot")
plt.subplot(2, 2, 3)
plt.scatter(ys, p, s=2)
plt.xlabel("ySpeed")
plt.ylabel("xRot")
plt.subplot(2, 2, 4)
plt.scatter(xs, ys, c=p, s=2)
plt.xlabel("xSpeed")
plt.ylabel("ySpeed")
plt.colorbar(label="xRot")
plt.tight_layout()
plt.show()
# =========================
# RUN
# =========================
if __name__ == "__main__":
data = collect_data()
visualize(data) |
|
It could be possible to decrease angle not linearly (in order to get even faster), but I have no idea what kind of function to use. Maybe someone can find a better approach, although changing constants might be accepted as a pull request with a higher probability rather than some rewrites |




Added more options for Pitch40.
Changed default settings for Pitch40, increasing the average speed (25.5768 → 28.8312).
Even higher average speeds could be achieved with the same pitch lock settings(~30), but using a greater(~100) height difference.
Values were generated using simulated annealing (python). Tested in both singleplayer and on a server (with Grim AntiCheat).
Type of change
Description
Added more options for Pitch40.
Changed default settings for Pitch40, increasing the average speed (25.5768 → 28.8312).
Even higher average speeds could be achieved with the same pitch lock settings(~30), but using a greater(~100) height difference.
Values were generated using simulated annealing (python). Tested in both singleplayer and on a server (with Grim AntiCheat).
Related issues
How Has This Been Tested?
Singleplayer and multiplayer.
Checklist: