ThiSpawn

Untitled

Dec 28th, 2016
616
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.60 KB | None | 0 0
  1. # Everything here is reverse from the .exe version 5.16.0
  2. # Clean versions of functions are proposed where the assembly was not optimized
  3. # (of course it's ASM translated in C++ then translated in Python)
  4. # by ThiSpawn on 25/12/2016, fuck christmas
  5.  
  6. from math import exp, log, pi, atan2, sqrt, sin, cos
  7. from copy import copy
  8.  
  9.  
  10. def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
  11.     return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
  12.  
  13.  
  14. class Vector3(object):
  15.     def __init__(self, x=0.0, y=0.0, z=0.0):
  16.         self.x = x
  17.         self.y = y
  18.         self.z = z
  19.  
  20.     def __iadd__(self, other):
  21.         self.x += other.x
  22.         self.y += other.y
  23.         self.z += other.z
  24.         return self
  25.  
  26.     def __add__(self, other):
  27.         return Vector3(
  28.             self.x + other.x,
  29.             self.y + other.y,
  30.             self.z + other.z)
  31.  
  32.     def __isub__(self, other):
  33.         self.x -= other.x
  34.         self.y -= other.y
  35.         self.z -= other.z
  36.         return self
  37.  
  38.     def __sub__(self, other):
  39.         return Vector3(
  40.             self.x - other.x,
  41.             self.y - other.y,
  42.             self.z - other.z)
  43.  
  44.     def __imul__(self, other):
  45.         if isinstance(other, Vector3):
  46.             self.x *= other.x
  47.             self.y *= other.y
  48.             self.z *= other.z
  49.         else:
  50.             self.x *= other
  51.             self.y *= other
  52.             self.z *= other
  53.         return self
  54.  
  55.     def __mul__(self, other):
  56.         if isinstance(other, Vector3):
  57.             return Vector3(
  58.                 self.x * other.x,
  59.                 self.y * other.y,
  60.                 self.z * other.z)
  61.         return Vector3(
  62.             self.x * other,
  63.             self.y * other,
  64.             self.z * other)
  65.  
  66.     def __idiv__(self, other):
  67.         if isinstance(other, Vector3):
  68.             self.x /= other.x
  69.             self.y /= other.y
  70.             self.z /= other.z
  71.         else:
  72.             self.x /= other
  73.             self.y /= other
  74.             self.z /= other
  75.         return self
  76.  
  77.     def __div__(self, other):
  78.         if isinstance(other, Vector3):
  79.             return Vector3(
  80.                 self.x / other.x,
  81.                 self.y / other.y,
  82.                 self.z / other.z)
  83.         return Vector3(
  84.             self.x / other,
  85.             self.y / other,
  86.             self.z / other)
  87.  
  88.     def __str__(self):
  89.         return '({:f}, {:f}, {:f})'.format(self.x, self.y, self.z)
  90.  
  91.     def dot(self, other):
  92.         isinstance(other, Vector3)
  93.         return self.x * other.x + self.y * other.y + self.z * other.z
  94.  
  95.     def sqnorm(self):
  96.         return self.dot(self)
  97.  
  98.     def len(self):
  99.         return sqrt(self.sqnorm())
  100.  
  101.     def normalize(self):
  102.         n = self.len()
  103.         self.x /= n
  104.         self.y /= n
  105.         self.z /= n
  106.  
  107.     def normalized(self):
  108.         return self / self.len()
  109.  
  110.     def update(self, other):
  111.         isinstance(other, Vector3)
  112.         self.x = other.x
  113.         self.y = other.y
  114.         self.z = other.z
  115.  
  116.  
  117. BALLISTIC_FLATTENING = 1.0
  118. BALLISTIC_SCALE = 60.0
  119.  
  120.  
  121. def flatten_traj_height(h):
  122.     if BALLISTIC_FLATTENING != 0.0 and h > 0:
  123.         h = log(BALLISTIC_FLATTENING * h + 1.0) / BALLISTIC_FLATTENING
  124.     return h
  125.  
  126.  
  127. def unflatten_traj_height(h):
  128.     if BALLISTIC_FLATTENING != 0.0 and h > 0:
  129.         h = (exp(BALLISTIC_FLATTENING * h) - 1.0) / BALLISTIC_FLATTENING
  130.     return h
  131.  
  132.  
  133. def set_ballistic_flattening(f):
  134.     global BALLISTIC_FLATTENING
  135.     BALLISTIC_FLATTENING = f
  136.  
  137.  
  138. def set_ballistic_scale(f):
  139.     global BALLISTIC_SCALE
  140.     BALLISTIC_SCALE = f
  141.  
  142.  
  143. def d_to_area(d):
  144.     return 0.25 * d * d * pi
  145.  
  146.  
  147. def unflatten_pos_and_vel_original(pos, vel_dir):
  148.     assert isinstance(pos, Vector3)
  149.     assert isinstance(vel_dir, Vector3)
  150.     y = unflatten_traj_height(pos.y)
  151.  
  152.     new_pos = pos + vel_dir * 0.001
  153.     new_pos.y = unflatten_traj_height(new_pos.y)
  154.  
  155.     pos.y = y
  156.  
  157.     angle_z2x = atan2(vel_dir.x, vel_dir.z)
  158.     dz = new_pos.z - pos.z
  159.     dx = new_pos.x - pos.x
  160.     pitch_angle = -atan2(new_pos.y - pos.y, sqrt(dz * dz + dx * dx))
  161.  
  162.     vel_dir.x = sin(angle_z2x) * cos(pitch_angle)
  163.     vel_dir.y = sin(-pitch_angle)
  164.     vel_dir.z = cos(angle_z2x) * cos(pitch_angle)
  165.  
  166.     return pos, vel_dir
  167.  
  168.  
  169. # the calculus seemed dumb, and it was.
  170. def unflatten_pos_and_vel(pos, vel_dir):
  171.     assert isinstance(pos, Vector3)
  172.     assert isinstance(vel_dir, Vector3)
  173.  
  174.     vel_dir *= 0.001  # small delta to approximate non linear warp of the tangent
  175.     y0 = unflatten_traj_height(pos.y)
  176.     y1 = unflatten_traj_height(pos.y + vel_dir.y)
  177.  
  178.     pos.y = y0
  179.     vel_dir.y = y1 - y0
  180.     vel_dir.normalize()
  181.  
  182.     return pos, vel_dir
  183.  
  184. if 0:
  185.     __a = unflatten_pos_and_vel_original(Vector3(20.0, 3.0, 10.0), Vector3(10.0, 5.0, 5.0))
  186.     __b = unflatten_pos_and_vel(Vector3(20.0, 3.0, 10.0), Vector3(10.0, 5.0, 5.0))
  187.     assert isclose(__a[0].x, __b[0].x)
  188.     assert isclose(__a[0].y, __b[0].y)
  189.     assert isclose(__a[0].z, __b[0].z)
  190.     assert isclose(__a[1].x, __b[1].x)
  191.     assert isclose(__a[1].y, __b[1].y)
  192.     assert isclose(__a[1].z, __b[1].z)
  193.  
  194.  
  195. # Lesta values, yes.. G is not as precise as the rest :P
  196. G = 9.8
  197. G_VEC = Vector3(0, -G, 0)
  198. GAS_CST_R = 8.31447  # N.m / (mol.K)
  199. AIR_MOLAR_MASS = 0.0289644  # kg / mol
  200. SEALEVEL_TEMPERATURE = 288.15  # K
  201. STATIC_PRESSURE_LVL0 = 101325.0  # Pa
  202. TEMPERATURE_LAPSE_RATE_LVL0 = -0.0065  # K / m
  203. PRESSURE_CST_H0 = G * AIR_MOLAR_MASS / (GAS_CST_R * TEMPERATURE_LAPSE_RATE_LVL0)
  204.  
  205.  
  206. TEMPERATURE_LAPSE_RATE_LVL0_NEG = 0.0065  # K / m
  207. PRESSURE_CST_H0_NEG = -PRESSURE_CST_H0
  208.  
  209.  
  210. def altitude_temperature(y):
  211.     return SEALEVEL_TEMPERATURE + y * TEMPERATURE_LAPSE_RATE_LVL0
  212.  
  213.  
  214. def altitude_pressure_original(y):
  215.     return STATIC_PRESSURE_LVL0 * pow(
  216.         1 - y * TEMPERATURE_LAPSE_RATE_LVL0_NEG / SEALEVEL_TEMPERATURE,
  217.         PRESSURE_CST_H0_NEG)
  218.  
  219.  
  220. def altitude_pressure(y):
  221.     return STATIC_PRESSURE_LVL0 * pow(
  222.         SEALEVEL_TEMPERATURE / altitude_temperature(y),
  223.         PRESSURE_CST_H0)
  224.  
  225. assert isclose(altitude_pressure_original(260), altitude_pressure(260))
  226.  
  227.  
  228. def altitude_pressure_n_temperature(y):
  229.     temperature = altitude_temperature(y)
  230.     return STATIC_PRESSURE_LVL0 * pow(
  231.         SEALEVEL_TEMPERATURE / temperature,
  232.         PRESSURE_CST_H0), temperature
  233.  
  234.  
  235. class TrajPoint(object):
  236.     def __init__(self, pos, v, time):
  237.         self.pos = pos
  238.         self.v = v
  239.         self.time = time
  240.  
  241.  
  242. class BulletSim(object):
  243.     def __init__(self, mass, d, air_drag_coeff, velocity0, s_pos, s_dir):
  244.         self.mass = mass
  245.         self.d = d
  246.         self.airDragCoeff = air_drag_coeff
  247.         self.v0 = velocity0
  248.         self.pos = s_pos
  249.         self.vel_vec = s_dir.normalized() * velocity0
  250.         self.A = 0.25 * d * d * pi
  251.         self.time = 0.0
  252.         self.steps = 0
  253.  
  254.     def step_original(self):
  255.         dy = self.pos.y * 0.48749998 * 0.0013333333
  256.         dt = max(min(dy * exp(dy), 0.8125), 0.1001)
  257.         vel_vec = self.vel_vec
  258.  
  259.         p, temperature = altitude_pressure_n_temperature(self.pos.y)
  260.         air_density = AIR_MOLAR_MASS * p / (GAS_CST_R * temperature)
  261.         drag = self.A * 0.5 * self.airDragCoeff * air_density * vel_vec.sqnorm()
  262.  
  263.         pitch = atan2(vel_vec.y, sqrt(vel_vec.z * vel_vec.z + vel_vec.x * vel_vec.x))
  264.         yaw = atan2(vel_vec.z, vel_vec.x)
  265.  
  266.         a_drag = -drag / self.mass
  267.         a_horizontal = cos(pitch) * a_drag
  268.         a_vertical = sin(pitch) * a_drag - G
  269.  
  270.         a = Vector3(
  271.             cos(yaw) * a_horizontal,
  272.             a_vertical,
  273.             sin(yaw) * a_horizontal)
  274.  
  275.         self.pos += vel_vec * dt
  276.         self.vel_vec += a * dt
  277.         self.steps += 1
  278.  
  279.     def step(self):
  280.         dy = self.pos.y * 0.00064999
  281.         dt = max(min(dy * exp(dy), 0.8125), 0.1001)
  282.         vel_vec = self.vel_vec
  283.  
  284.         p, temperature = altitude_pressure_n_temperature(self.pos.y)
  285.         air_density = AIR_MOLAR_MASS * p / (GAS_CST_R * temperature)
  286.         drag = self.A * 0.5 * self.airDragCoeff * air_density * vel_vec.sqnorm()
  287.  
  288.         a = (vel_vec.normalized() * (-drag / self.mass) + G_VEC)
  289.  
  290.         self.pos += vel_vec * dt
  291.         self.vel_vec += a * dt
  292.         self.steps += 1
  293.  
  294. if 0:
  295.     _bullet0 = BulletSim(3.0, 0.04, 0.35, 300.0, Vector3(20.0, 3.0, 10.0), Vector3(10.0, 5.0, 5.0))
  296.     _bullet0.step_original()
  297.     _bullet1 = BulletSim(3.0, 0.04, 0.35, 300.0, Vector3(20.0, 3.0, 10.0), Vector3(10.0, 5.0, 5.0))
  298.     _bullet1.step()
  299.     assert isclose(_bullet0.vel_vec.x, _bullet1.vel_vec.x)
  300.     assert isclose(_bullet0.vel_vec.y, _bullet1.vel_vec.y)
  301.     assert isclose(_bullet0.vel_vec.z, _bullet1.vel_vec.z)
  302.  
  303.  
  304. # flatten_output is not part of Lesta's code, it's added for comparison with real trajectory
  305. # Lesta's bug: if the input shoot_pos is not already flattened, their code doesn't flatten the first trajectory point.
  306. def build_trajectory(mass, d, air_drag_coeff, velocity, shoot_pos, shoot_dir,
  307.                      draft, ret_stride, flat_input, t0, trajectory, flatten_output=False):
  308.     s_pos = copy(shoot_pos)
  309.     s_dir = copy(shoot_dir)
  310.  
  311.     # added (not original)
  312.     flat_s_pos = copy(shoot_pos)
  313.     if flat_input:
  314.         unflatten_pos_and_vel(s_pos, s_dir)
  315.     else:
  316.         flat_s_pos.y = flatten_traj_height(flat_s_pos.y)
  317.  
  318.     initial_len = len(trajectory)
  319.     trajectory.append(TrajPoint(flat_s_pos if flatten_output else s_pos, velocity, t0))
  320.  
  321.     bullet = BulletSim(mass, d, air_drag_coeff, velocity, s_pos * BALLISTIC_SCALE, s_dir)
  322.  
  323.     if bullet.pos.y >= 0.0:
  324.         cur_i = initial_len
  325.         inv_ballistic_scale = 1.0 / BALLISTIC_SCALE
  326.         while cur_i < 1024:
  327.             cur_i += 1
  328.             bullet.step()
  329.             bullet_world_pos = copy(bullet.pos) * inv_ballistic_scale
  330.             if flatten_output:
  331.                 bullet_world_pos.y = flatten_traj_height(bullet_world_pos.y)
  332.             trajectory.append(TrajPoint(
  333.                 bullet_world_pos,
  334.                 bullet.vel_vec.len(),
  335.                 t0 + bullet.time))
  336.             if bullet_world_pos.y <= 0.0:
  337.                 break
  338.         else:
  339.             raise OverflowError(
  340.                 "Oversize of vs array (1024): Arguments: mass:{:f}, d:{:f}, airDragCoeff:{:f}, v:{:f}, pos:{!s}, "
  341.                 "dir:{!s}, draft:{!s}\n".format(mass, d, air_drag_coeff, velocity, shoot_pos, shoot_dir, draft))
  342.  
  343.     # possible exploit here : assumed underwater with already 2 points and going down..
  344.     p0, p1 = trajectory[-2:]
  345.     pos0, pos1 = p0.pos, p1.pos
  346.     v37 = 1.0 - pos1.y / (pos1.y - pos0.y)
  347.     if v37 >= 0.00000011920929:  # lastlast bullet was overwater
  348.         p1.pos = pos0 + (pos1 - pos0) * v37
  349.         p1.time = p0.time + (p1.time - p0.time) * v37
  350.     elif trajectory:
  351.         trajectory.pop()
  352.  
  353.     if ret_stride > 1:
  354.         # fixed (official code is wrong: cur_i = 0)
  355.         cur_i = initial_len
  356.         end = len(trajectory)
  357.         if initial_len < end:
  358.             i = initial_len
  359.             while i < end:
  360.                 trajectory[cur_i] = trajectory[i]
  361.                 i += ret_stride
  362.                 cur_i += 1
  363.         # official code is weird:
  364.         # if trajectory[-1].v != trajectory[cur_i - 1].v:
  365.         if cur_i != end:
  366.             trajectory[cur_i] = trajectory[-1]
  367.             del trajectory[cur_i + 1:]
  368.             # new size was wrong if cur_i inited with 0:
  369.             # new_size = initial_len + cur_i;
  370.  
  371.     return 1
  372.  
  373. if 1:
  374.     import matplotlib.pyplot as plt
  375.     set_ballistic_scale(60.0)
  376.     for i in range(1, 15):
  377.         traj = []
  378.         build_trajectory(3.0, 0.04, 0.35, 300.0, Vector3(0.0, 0.2, 0.0), Vector3(1.0, 0.1*i, 0), 0, 1, False, 0, traj)
  379.         xs, ys = zip(*((p.pos.x, p.pos.y) for p in traj))
  380.         plt.plot(xs, ys, 'r-')
  381.         flattened_ys = list(flatten_traj_height(y) for y in ys)
  382.         plt.plot(xs, flattened_ys, 'b-')
  383.         plt.xlabel('dist (m/ballistic_scale)')
  384.         plt.ylabel('height (m/ballistic_scale)')
  385.         plt.grid(True)
  386.         plt.axis('equal')
  387.         print "final_velocity : ", traj[-1].v
  388.     plt.show()
  389.  
  390. WATER_DENSITY = 1000.0
  391.  
  392.  
  393. def get_dist_underwater(unknown0, unknown1, d, mass, water_drag):
  394.     # drag_coeff = (d_to_area(d) * a5 * 102.0 * G) / (2.0 * a4)
  395.     drag_coeff = (d_to_area(d) * 0.5 * water_drag * WATER_DENSITY) / mass
  396.     return log(unknown0 * unknown1 * drag_coeff + 1.0) / drag_coeff
  397.  
  398.  
  399. def get_velo_underwater(t, velocity0, d, mass, water_drag):
  400.     drag_coeff = (d_to_area(d) * 0.5 * water_drag * WATER_DENSITY) / mass
  401.     return velocity0 * exp(-t * drag_coeff)
  402.  
  403.  
  404. def get_time_underwater(unknown0, unknown1, d, mass, water_drag):
  405.     drag_coeff = (d_to_area(d) * 0.5 * water_drag * WATER_DENSITY) / mass
  406.     return (exp(unknown0 * drag_coeff) - 1.0) / (unknown1 * drag_coeff)
Add Comment
Please, Sign In to add comment