/** * Runs the server. The server will wait for some match info (which specifies the teams and set of * maps to run) and then begin running matches. */ public void run() { int aWins = 0, bWins = 0; while (!matches.isEmpty()) { Match match = matches.peek(); if (!finished.isEmpty()) match.setInitialTeamMemory(finished.getLast().getComputedTeamMemory()); try { debug("running match " + match); match.initialize(); runMatch(match, proxyWriter); finished.add(match); matches.remove(match); if (match.getWinner() == Team.A) aWins++; else if (match.getWinner() == Team.B) bWins++; match.finish(); // Allow best of three scrimmages -- single game scrims should still work fine // TODO:This "win mode" should probably be something from the database if (mode == Mode.TOURNAMENT || mode == Mode.SCRIMMAGE) { if (aWins == 2 || bWins == 2) break; } } catch (Exception e) { ErrorReporter.report(e); error("couldn't run match: "); this.state = State.ERROR; } } proxyWriter.terminate(); }
/** * Runs a match; configures the controller and list of proxies, and starts running the game in a * separate thread. */ private void runMatch(final Match match, final ProxyWriter proxyWriter) throws Exception { if (Mode.HEADLESS.equals(mode) || Mode.SCRIMMAGE.equals(mode) || Mode.TOURNAMENT.equals(mode)) { this.state = State.RUNNING; this.runUntil = Integer.MAX_VALUE; } // Poll for RUNNING, if mode == Mode.LOCAL while (!State.RUNNING.equals(state)) { try { Thread.sleep(250); } catch (InterruptedException e) { } } long startTime = System.currentTimeMillis(); say("-------------------- Match Starting --------------------"); say(match.toString()); // Compute the header and send it to all listeners. MatchHeader header = match.getHeader(); proxyWriter.enqueue(header); ExtensibleMetadata exHeader = match.getHeaderMetadata(); proxyWriter.enqueue(exHeader); this.state = State.RUNNING; int count = 0; final String throttle = options.get("bc.server.throttle"); final int throttleCount = options.getInt("bc.server.throttle-count"); final boolean doYield = "yield".equals(throttle); final boolean doSleep = "sleep".equals(throttle); // If there are more rounds to be run, run them and // and send the round (and optionally stats) bytes to // recipients. while (match.hasMoreRounds()) { // If not paused/stopped: switch (this.state) { case RUNNING: if (match.getRoundNumber() == runUntil) { Thread.sleep(25); break; } final RoundDelta round = match.getRound(); if (round == null) break; if (GameState.BREAKPOINT.equals(match.getGameState())) { this.state = State.PAUSED; proxyWriter.enqueue(new PauseEvent()); } else if (GameState.DONE.equals(match.getGameState())) { this.state = State.FINISHED; } proxyWriter.enqueue(round); if (count++ == throttleCount) { if (doYield) Thread.yield(); else if (doSleep) Thread.sleep(1); count = 0; } break; case PAUSED: Thread.sleep(250); break; } } // Compute footer data. GameStats gameStats = match.getGameStats(); MatchFooter footer = match.getFooter(); proxyWriter.enqueue(gameStats); proxyWriter.enqueue(footer); say(match.getWinnerString()); say("-------------------- Match Finished --------------------"); double timeDiff = (System.currentTimeMillis() - startTime) / 1000.0; debug(String.format("match completed in %.4g seconds", timeDiff)); this.state = State.FINISHED; }