def time_warp_to_land(conn, vessel, recover=False):
    if vessel.parts.parachutes[
            0].state.name == "active" or vessel.parts.parachutes[
                0].state.name == "semi_deployed":
        pass
    else:
        assert False, f"Parachute state is {vessel.parts.parachutes[0].state.name}"
    space_center = conn.space_center
    space_center.physics_warp_factor = 3

    logger.info("Waiting until landing...")
    surface_altitude = conn.get_call(getattr, vessel.flight(),
                                     'surface_altitude')
    expr = conn.krpc.Expression.less_than(
        conn.krpc.Expression.call(surface_altitude),
        conn.krpc.Expression.constant_double(50))
    event = conn.krpc.add_event(expr)
    with event.condition:
        event.wait()
    space_center.physics_warp_factor = 0

    if recover:
        while not vessel.recoverable:
            time.sleep(1)

        if vessel.recoverable:
            time.sleep(10)
            vessel.recover()

    return True
def crew_list(vessel):
    if vessel.crew_capacity == 0:
        logger.info(f"Craft is unmanned.")
        return []
    else:
        logger.info(
            f"Craft contains {vessel.crew_count} out of {vessel.crew_capacity} crew members"
        )
        return vessel.crew
def wait_for_safe_parachute(conn, vessel):
    logger.info("Waiting until safe to deploy parachute...")
    mean_altitude = conn.get_call(getattr, vessel.flight(), 'mean_altitude')
    expr = conn.krpc.Expression.less_than(
        conn.krpc.Expression.call(mean_altitude),
        conn.krpc.Expression.constant_double(2000))
    event = conn.krpc.add_event(expr)
    with event.condition:
        event.wait()
    return True
def wait_for_fuel_to_run_out(conn, vessel):
    logger.info("Waiting for fuel to run out...")
    fuel_amount = conn.get_call(vessel.resources.amount, 'SolidFuel')
    expr = conn.krpc.Expression.less_than(
        conn.krpc.Expression.call(fuel_amount),
        conn.krpc.Expression.constant_float(0.1))
    event = conn.krpc.add_event(expr)
    with event.condition:
        event.wait()
    return True
def setup_active_vessel(krpc_connect):

    logger.debug("Checking for active for vessel...")
    conn = krpc_connect
    try:
        vessel = conn.space_center.active_vessel
        logger.info(f"Active Vessel Found: {vessel.name}")
        yield vessel
    except Exception as ex:
        logger.error("Could not find active vessel")
        logger.error(f"Reason: {ex}")
        assert False, f"Could not find active vessel - {ex}"

    return krpc_connect
def simple_launch(conn, vessel):
    success = False
    if vessel.situation.name != "pre_launch":
        abort_launch(conn, vessel)
        return False

    vessel.auto_pilot.engage()

    logger.info("Wait 5 seconds to launch...")
    time.sleep(5)
    logger.info("Launching...")

    vessel.control.activate_next_stage()
    vessel.auto_pilot.target_pitch_and_heading(60, 180)

    success = wait_for_fuel_to_run_out(conn, vessel)
    if not success:
        return False

    logger.info("Ditch the empty tank...")
    vessel.control.activate_next_stage()

    vessel.auto_pilot.disengage()

    success = wait_for_safe_parachute(conn, vessel)
    if not success:
        return False

    logger.info("Activating Parachute.")
    vessel.control.activate_next_stage()

    time.sleep(3)
    success = time_warp_to_land(conn, vessel)
    if not success:
        return False

    return True
def log_and_print(message):
    logger.info(message)
    print(message)
def set_autopilot(vessel, pitch=90, heading=90):
    logger.info("Engaging Autopilot")
    vessel.auto_pilot.engage()
    logger.info(f"Set pitch to {pitch} and heading to {heading}")
    vessel.auto_pilot.target_pitch_and_heading(pitch, heading)