@Override
    public final void run() {
        isRunning = true;

        try {
            initialize();
        } catch (Exception | NoClassDefFoundError | UnsatisfiedLinkError ex) {
            LogUtil.logError("Failed to start ClassiCube!", ex);
            JOptionPane.showMessageDialog(null, ex.toString(), "Failed to start ClassiCube",
                    JOptionPane.ERROR_MESSAGE);
            isRunning = false;
            return;
        }

        long fpsUpdateTimer = System.currentTimeMillis();
        int fps = 0;
        try {
            // Main loop!
            while (isRunning) {
                if (isWaiting) {
                    Thread.sleep(100L);
                } else {
                    onFrame();

                    fps++;
                    while (System.currentTimeMillis() >= fpsUpdateTimer + 1000L) {
                        debug = fps + " fps, " + Chunk.chunkUpdates + " chunk updates";
                        Chunk.chunkUpdates = 0;
                        fpsUpdateTimer += 1000L;
                        fps = 0;
                    }
                }
            }
        } catch (StopGameException ex) {
        } catch (Exception ex) {
            LogUtil.logError("Fatal error in main loop (run)", ex);
        } finally {
            shutdown();
        }
    }