Example #1
0
def main(args: argparse.Namespace):
    loadfile: Path
    if os.path.isabs(args.loadfile):
        loadfile = Path(args.loadfile)
    else:
        # Take paths relative to 'data/saves/'
        loadfile = common.savefile(args.loadfile)

    physics_engine = physics.PhysicsEngine(common.load_savefile(loadfile))
    initial_state = physics_engine.get_state()

    gui = flight_gui.FlightGui(initial_state,
                               title=name,
                               running_as_mirror=False)
    atexit.register(gui.shutdown)

    if args.flamegraph:
        common.start_flamegraphing()
    if args.profile:
        common.start_profiling()

    while True:
        state = physics_engine.get_state()

        # If we have any commands, process them so the simthread has as
        # much time as possible to restart before next update.
        physics_engine.handle_requests(gui.pop_commands())

        gui.draw(state)
        gui.rate(common.FRAMERATE)
Example #2
0
def lead_server_loop(args):
    """Main, 'while True'-style loop for a lead server. Blocking.
    See help text for command line arguments for what a lead server is."""

    # Before you make changes to the lead server architecture, consider that
    # the GRPC server runs in a separate thread than this thread!
    state_server = network.StateServer()

    log.info(f'Loading save at {args.data_location.path}')
    physics_engine = physics.PEngine(
        common.load_savefile(Path(args.data_location.path)))

    if not args.no_gui:
        global cleanup_function
        global ungraceful_shutdown
        gui = flight_gui.FlightGui(physics_engine.get_state(),
                                   no_intro=args.no_intro)
        cleanup_function = gui.shutdown
        ungraceful_shutdown = gui.ungraceful_shutdown

    server = grpc.server(concurrent.futures.ThreadPoolExecutor(max_workers=4))
    grpc_stubs.add_StateServerServicer_to_server(state_server, server)
    server.add_insecure_port(f'[::]:{args.serve_on_port}')
    server.start()  # This doesn't block!
    # Need a context manager from now on, to make sure the server always stops.
    with common.GrpcServerContext(server):
        log.info(f'Server running on port {args.serve_on_port}. Ctrl-C exits.')

        if args.profile:
            common.start_profiling()
        while True:
            user_commands = []
            state = physics_engine.get_state()
            state_server.notify_state_change(copy.deepcopy(state._proto_state))

            if not args.no_gui:
                user_commands += gui.pop_commands()
            user_commands += state_server.pop_commands()

            # If we have any commands, process them so the simthread has as
            # much time as possible to regenerate solutions before next update
            for command in user_commands:
                if command.ident == network.Request.NOOP:
                    continue
                log.info(f'Got command: {command}')
                physics_engine.handle_request(command)

            if not args.no_gui:
                gui.draw(state)
                gui.rate(common.FRAMERATE)
            else:
                time.sleep(1 / common.FRAMERATE)
Example #3
0
def mirroring_loop(args):
    """Main, 'while True'-style loop for a mirroring client. Blocking.
    See help text for CLI arguments for the difference between mirroring and
    serving."""
    currently_mirroring = True

    log.info('Connecting to CnC server...')
    with network.StateClient(args.data_location.hostname,
                             args.data_location.port) as mirror_state:
        log.info(f'Querying lead server {args.data_location.geturl()}')
        state = mirror_state()
        physics_engine = physics.PEngine(state)

        if not args.no_gui:
            log.info('Initializing graphics (thanks sean)...')
            gui = flight_gui.FlightGui(state)
            global cleanup_function
            cleanup_function = gui.shutdown

        while True:
            try:
                if currently_mirroring:
                    state = mirror_state()
                    physics_engine.set_state(state)
                else:
                    state = physics_engine.get_state()

                if not args.no_gui:
                    gui.draw(state)
                    gui.rate(common.FRAMERATE)
                    if gui.closed:
                        break
                else:
                    time.sleep(1 / common.FRAMERATE)
            except KeyboardInterrupt:
                # TODO: hacky solution to turn off mirroring right now is a ^C
                if currently_mirroring:
                    currently_mirroring = False
                else:
                    raise
Example #4
0
def main(args: argparse.Namespace):
    log.info(f'Connecting to physics server {args.physics_server}.')
    time_of_next_network_update = 0.0
    lead_server_connection = network.StateClient(Request.HAB_FLIGHT,
                                                 args.physics_server)
    state = lead_server_connection.get_state()
    physics_engine = physics.PhysicsEngine(state)

    gui = flight_gui.FlightGui(state, title=name, running_as_mirror=False)
    atexit.register(gui.shutdown)

    while True:
        gui.draw(state)

        user_commands = gui.pop_commands()
        current_time = time.monotonic()

        # If there are user commands or we've gone a while since our last
        # contact with the physics server, request an update.
        if user_commands or current_time > time_of_next_network_update:
            # Our state is stale, get the latest update
            # TODO: what if this fails? Do anything smarter than an exception?
            state = lead_server_connection.get_state(user_commands)
            physics_engine.set_state(state)
            if len(user_commands) == 0:
                time_of_next_network_update = (
                    current_time + common.TIME_BETWEEN_NETWORK_UPDATES)
            else:
                # If we sent a user command, still ask for an update soon so
                # the user input can be reflected in hab flight's GUI as soon
                # as possible.
                # Magic number alert! The constant we add should be enough that
                # the physics server has had enough time to simulate the effect
                # of our input, but we should minimize the constant to minimize
                # input lag.
                time_of_next_network_update = current_time + 0.15
        else:
            state = physics_engine.get_state()

        gui.rate(common.FRAMERATE)
Example #5
0
def main(args: argparse.Namespace):
    time_of_last_network_update = 0.0
    networking = True  # Whether data is requested over the network

    log.info(f'Connecting to physics server {args.physics_server}.')
    lead_server_connection = network.StateClient(Request.MC_FLIGHT,
                                                 args.physics_server)
    state = lead_server_connection.get_state()
    physics_engine = physics.PhysicsEngine(state)

    gui = flight_gui.FlightGui(state, title=name, running_as_mirror=True)
    atexit.register(gui.shutdown)

    while True:
        old_networking = networking
        networking = gui.requesting_read_from_physics_server()
        if old_networking != networking:
            log.info(('STARTED' if networking else 'STOPPED') +
                     ' networking with the physics server at ' +
                     args.physics_server)

        if (networking and time.monotonic() - time_of_last_network_update >
                common.TIME_BETWEEN_NETWORK_UPDATES):
            # Our state is stale, get the latest update
            # TODO: what if this fails? Set networking to False?
            state = lead_server_connection.get_state()
            physics_engine.set_state(state)
            time_of_last_network_update = time.monotonic()
        else:
            state = physics_engine.get_state()

        gui.draw(state)
        if not networking:
            # When we're not networking, allow user input.
            physics_engine.handle_requests(gui.pop_commands())
        gui.rate(common.FRAMERATE)