private void tick() {
    if (level != null) {
      if (level.player1Score >= Level.TARGET_SCORE) {
        addMenu(new WinMenu(GAME_WIDTH, GAME_HEIGHT, 1));
        level = null;
        return;
      }
      if (level.player2Score >= Level.TARGET_SCORE) {
        addMenu(new WinMenu(GAME_WIDTH, GAME_HEIGHT, 2));
        level = null;
        return;
      }
      if (keys.escape.wasPressed()) {
        clearMenus();
        addMenu(new TitleMenu(GAME_WIDTH, GAME_HEIGHT));
        level = null;
        return;
      }
    }
    if (packetLink != null) {
      packetLink.tick();
    }

    mouseButtons.setPosition(getMousePosition());
    if (!menuStack.isEmpty()) {
      menuStack.peek().tick(mouseButtons);
    }
    if (mouseMoved) {
      mouseMoved = false;
      mouseHideTime = 0;
      if (mouseHidden) {
        mouseHidden = false;
      }
    }
    if (mouseHideTime < 60) {
      mouseHideTime++;
      if (mouseHideTime == 60) {
        mouseHidden = true;
      }
    }
    mouseButtons.tick();

    if (level != null) {
      if (synchronizer.preTurn()) {
        synchronizer.postTurn();
        for (int index = 0; index < keys.getAll().size(); index++) {
          Keys.Key key = keys.getAll().get(index);
          boolean nextState = key.nextState;
          if (key.isDown != nextState) {
            synchronizer.addCommand(new ChangeKeyCommand(index, nextState));
          }
        }
        if (keys.save.isDown) {
          level.save();
        }
        keys.tick();
        for (Keys skeys : synchedKeys) {
          skeys.tick();
        }

        // if mouse is in use, update player orientation before level
        // tick
        if (!mouseHidden) {

          // update player mouse, in world pixels relative to player
          player.setAimByMouse(
              ((mouseButtons.getX() / SCALE) - (screen.w / 2)),
              (((mouseButtons.getY() / SCALE) + 24) - (screen.h / 2)));
        } else {
          player.setAimByKeyboard();
        }

        level.tick();
      }
    }

    if (createServerState == 1) {
      createServerState = 2;

      synchronizer = new TurnSynchronizer(MojamComponent.this, packetLink, localId, 2);

      clearMenus();
      createLevel(TitleMenu.level);

      synchronizer.setStarted(true);
      packetLink.sendPacket(new StartGamePacket(TurnSynchronizer.synchedSeed, TitleMenu.level));
      packetLink.setPacketListener(MojamComponent.this);
    }
  }
  public void run() {
    long lastTime = System.nanoTime();
    double unprocessed = 0;
    int frames = 0;
    long lastTimer1 = System.currentTimeMillis();

    try {
      init();
    } catch (Exception e) {
      e.printStackTrace();
      return;
    }

    // if (!isMultiplayer) {
    // createLevel();
    // }

    int toTick = 0;

    long lastRenderTime = System.nanoTime();
    int min = 999999999;
    int max = 0;

    while (running) {
      if (!this.hasFocus()) {
        keys.release();
      }

      double nsPerTick = 1000000000.0 / framerate;
      boolean shouldRender = false;
      while (unprocessed >= 1) {
        toTick++;
        unprocessed -= 1;
      }

      int tickCount = toTick;
      if (toTick > 0 && toTick < 3) {
        tickCount = 1;
      }
      if (toTick > 20) {
        toTick = 20;
      }

      for (int i = 0; i < tickCount; i++) {
        toTick--;
        // long before = System.nanoTime();
        tick();
        // long after = System.nanoTime();
        // System.out.println("Tick time took " + (after - before) *
        // 100.0 / nsPerTick + "% of the max time");
        shouldRender = true;
      }
      // shouldRender = true;

      BufferStrategy bs = getBufferStrategy();
      if (bs == null) {
        createBufferStrategy(3);
        continue;
      }
      if (shouldRender) {
        frames++;
        Graphics g = bs.getDrawGraphics();

        Random lastRandom = TurnSynchronizer.synchedRandom;
        TurnSynchronizer.synchedRandom = null;

        render(g);

        TurnSynchronizer.synchedRandom = lastRandom;

        long renderTime = System.nanoTime();
        int timePassed = (int) (renderTime - lastRenderTime);
        if (timePassed < min) {
          min = timePassed;
        }
        if (timePassed > max) {
          max = timePassed;
        }
        lastRenderTime = renderTime;
      }

      long now = System.nanoTime();
      unprocessed += (now - lastTime) / nsPerTick;
      lastTime = now;

      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      if (shouldRender) {
        if (bs != null) {
          bs.show();
        }
      }

      if (System.currentTimeMillis() - lastTimer1 > 1000) {
        lastTimer1 += 1000;
        fps = frames;
        frames = 0;
      }
    }
  }