#!/usr/bin/env python # encoding: utf-8 import subprocess, os, time, numpy, sys from signal import SIGKILL # Global list of all/essential running processes processes, necProcesses = [], [] # Command to run the rcssserver. Edit as needed. SERVER_BIN = 'rcssserver' # Command to run the monitor. Edit as needed. MONITOR_BIN = 'soccerwindow2' def getAgentDirCmd(binary_dir, teamname, server_port=6000, coach_port=6002, logDir='log', record=False): """ Returns the team name, command, and directory to run a team. """ cmd = 'start.sh -t %s -p %i -P %i --log-dir %s'%(teamname, server_port, coach_port, logDir) if record: cmd += ' --record' cmd = os.path.join(binary_dir, cmd) return teamname, cmd def launch(cmd, necessary=True, supressOutput=True, name='Unknown'): """Launch a process. Appends to list of processes and (optionally) necProcesses if necessary flag is True. Returns: The launched process. """ kwargs = {} if supressOutput: kwargs = {'stdout':open('/dev/null','w'),'stderr':open('/dev/null','w')} p = subprocess.Popen(cmd.split(' '),shell=False,**kwargs) processes.append(p) if necessary: necProcesses.append([p,name]) return p def main(args, team1='left', team2='right', rng=numpy.random.RandomState()): """Sets up the teams, launches the server and monitor, starts the trainer. """ if args.seed: print '[start.py] Seeding RNG with seed: ', args.seed rng.seed(args.seed) if not os.path.exists(args.logDir): os.makedirs(args.logDir) num_agents = args.offenseAgents + args.defenseAgents binary_dir = os.path.dirname(os.path.realpath(__file__)) server_port = args.port + num_agents coach_port = args.port + num_agents + 1 olcoach_port = args.port + num_agents + 2 serverCommand = os.path.join(binary_dir, SERVER_BIN) serverOptions = ' server::port=%i server::coach_port=%i ' \ 'server::olcoach_port=%i server::coach=1 ' \ 'server::game_logging=%i server::text_logging=%i ' \ 'server::game_log_dir=%s server::text_log_dir=%s '\ 'server::synch_mode=%i ' \ 'server::fullstate_l=%i server::fullstate_r=%i' \ %(server_port, coach_port, olcoach_port, args.logging, args.logging, args.logDir, args.logDir, args.sync, args.fullstate, args.fullstate) team1, team1Cmd = getAgentDirCmd(binary_dir, team1, server_port, coach_port, args.logDir, args.record) team2, team2Cmd = getAgentDirCmd(binary_dir, team2, server_port, coach_port, args.logDir, args.record) try: # Launch the Server server = launch(serverCommand + serverOptions, name='server') time.sleep(0.2) assert server.poll() is None,\ '[start.py] Failed to launch Server with command: \"%s\"' \ %(serverCommand + serverOptions) if not args.headless: monitorCommand = os.path.join(binary_dir, MONITOR_BIN) monitorOptions = ' --connect --port=%i'%(server_port) launch(monitorCommand + monitorOptions, name='monitor') # Launch the Trainer from Trainer import Trainer trainer = Trainer(args=args, rng=rng, server_port=server_port, coach_port=coach_port) trainer.initComm() # Start Team1 launch(team1Cmd,False) trainer.waitOnTeam(True) # wait to make sure of team order # Start Team2 launch(team2Cmd,False) trainer.waitOnTeam(False) # Make sure all players are connected trainer.checkIfAllPlayersConnected() trainer.setTeams() # Run HFO trainer.run(necProcesses) except KeyboardInterrupt: print '[start.py] Exiting for CTRL-C' finally: print '[start.py] Cleaning up server and other processes' for p in processes: try: p.send_signal(SIGKILL) except: pass time.sleep(0.1) def parseArgs(): import argparse p = argparse.ArgumentParser(description='Start Half Field Offense.') p.add_argument('--headless', dest='headless', action='store_true', help='Run without a monitor') p.add_argument('--trials', dest='numTrials', type=int, default=-1, help='Number of trials to run') p.add_argument('--frames', dest='numFrames', type=int, default=-1, help='Number of frames to run for') p.add_argument('--frames-per-trial', dest='maxFramesPerTrial', type=int, default=1000, help='Max number of frames per trial. '\ 'Negative values mean unlimited.') p.add_argument('--offense-agents', dest='offenseAgents', type=int, default=0, help='Number of offensive agents') p.add_argument('--defense-agents', dest='defenseAgents', type=int, default=0, help='Number of defensive agents') p.add_argument('--offense-npcs', dest='offenseNPCs', type=int, default=0, help='Number of offensive uncontrolled players') p.add_argument('--defense-npcs', dest='defenseNPCs', type=int, default=0, help='Number of defensive uncontrolled players') p.add_argument('--no-sync', dest='sync', action='store_false', default=True, help='Run server in non-sync mode') p.add_argument('--port', dest='port', type=int, default=6000, help='Agent server\'s port. rcssserver, coach, and ol_coach'\ ' will be incrementally allocated the following ports.') p.add_argument('--no-logging', dest='logging', action='store_false', default=True, help='Disable rcssserver logging.') p.add_argument('--log-dir', dest='logDir', default='log/', help='Directory to store logs.') p.add_argument('--record', dest='record', action='store_true', help='Record logs of states and actions.') p.add_argument('--agent-on-ball', dest='agent_on_ball', action='store_true', help='Agent starts with the ball.') p.add_argument('--fullstate', dest='fullstate', action='store_true', help='Server provides full-state information to agents.') p.add_argument('--seed', dest='seed', type=int, help='Seed the trainer\'s RNG. Default: time.') args = p.parse_args() assert args.offenseAgents + args.offenseNPCs in xrange(0, 11), \ 'Invalid number of offensive players: (choose from [0,10])' assert args.defenseAgents + args.defenseNPCs in xrange(0, 12), \ 'Invalid number of defensive players: (choose from [0,11])' return args if __name__ == '__main__': main(parseArgs())