oakes / play-clj

A Clojure game library
The Unlicense
939 stars 73 forks source link

lein play-clj template crashes on exit #86

Closed Raffinate closed 8 years ago

Raffinate commented 9 years ago

I've entered "$ lein new play-clj my-app" Then I've changed directory to "./my-app/desktop" and run "$ lein repl" "my-app.core.desktop-launcher=> (-main)" Default "Hello World!" window appeared. After I press close button, repl crashes. I can copy/paste a trace that got to my terminal emulator. Is this default behavior and I need to add something in the template code?

oakes commented 9 years ago

Yeah that is known behavior. I think it has to do with the fact that there are multiple threads running and the REPL thread is destroyed when the window is closed.

hackergrrl commented 9 years ago

Is there a clean way to terminate the program from within the game? It looks like "easy" solutions like (System/exit 1) don't work either.

oakes commented 9 years ago

@noffle Try (app! :exit)

hackergrrl commented 9 years ago

Hey Zach. I gave that a shot, but I'm still seeing the repl crash:

clojure-gdx-hello.core.desktop-launcher=> (-main)
nil
clojure-gdx-hello.core.desktop-launcher=> Exception in thread "Thread-3" clojure.lang.ExceptionInfo: Subprocess failed {:exit-code 255}
    at clojure.core$ex_info.invoke(core.clj:4403)
    at leiningen.core.eval$fn__6725.invoke(eval.clj:236)
    at clojure.lang.MultiFn.invoke(MultiFn.java:231)
    at leiningen.core.eval$eval_in_project.invoke(eval.clj:337)
    at leiningen.repl$server$fn__10717.invoke(repl.clj:241)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:624)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at clojure.core$apply.invoke(core.clj:628)
    at clojure.core$bound_fn_STAR_$fn__4140.doInvoke(core.clj:1884)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.lang.Thread.run(Thread.java:745)

SocketException The transport's socket appears to have lost its connection to the nREPL server
    clojure.tools.nrepl.transport/bencode/fn--7491/fn--7492 (transport.clj:95)
    clojure.tools.nrepl.transport/bencode/fn--7491 (transport.clj:95)
    clojure.tools.nrepl.transport/fn-transport/fn--7463 (transport.clj:42)
    clojure.core/binding-conveyor-fn/fn--4145 (core.clj:1910)
    java.util.concurrent.FutureTask.run (FutureTask.java:262)
    java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145)
    java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:615)
    java.lang.Thread.run (Thread.java:745)
Bye for now!
oakes commented 9 years ago

Oh, I didn't realize you were trying to keep the REPL alive. I have not found a way to do that. Is there a reason you want to? There is a way to restart the game if you want to start with fresh state.

rqndom commented 7 years ago

This is a old question but I am currently facing the same problem.

I have found the issue to be caused by lwjgl backend: by default its mainloop thread calls System.exit(-1) on close, which terminates the mainloop but also others threads including the repl one.

(for more details see method LwjglApplication.mainLoop() in https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglApplication.java)

This behaviour can be changed by passing a custom configuration object to the application, disabling the System.exit call by setting forceExit attribute to false.

I have attached next the patch that works on my environment (patch on desktop-launcher.clj file). As I'm new to clojure I may not write good code, so feel free to refactor it if needed. :)

--- desktop-launcher.clj    2016-11-09 09:12:04.283550194 +0100
+++ desktop-launcher-patch.clj  2016-11-09 09:09:08.000000000 +0100
@@ -1,10 +1,16 @@
 (ns {{desktop-namespace}}
   (:require [{{namespace}} :refer :all])
-  (:import [com.badlogic.gdx.backends.lwjgl LwjglApplication]
+  (:import [com.badlogic.gdx.backends.lwjgl LwjglApplication LwjglApplicationConfiguration]
            [org.lwjgl.input Keyboard])
   (:gen-class))

 (defn -main
   []
-  (LwjglApplication. {{game-name}} "{{app-name}}" 800 600)
+  (let [config (LwjglApplicationConfiguration.)]
+    (set! (.-title config) "{{app-name}}")
+    (set! (.-width config) 800)
+    (set! (.-height config) 600)
+    (set! (.-vSyncEnabled config) true)
+    (set! (.-forceExit config) false)
+    (LwjglApplication. {{game-name}} config))
   (Keyboard/enableRepeatEvents true))