Implement nrepl support, catch exceptions. Hot code reload is now fully operational.

This commit is contained in:
Jeremy Penner 2013-03-10 03:54:09 -05:00
parent 246213c8a2
commit 339e6f5444
3 changed files with 62 additions and 7 deletions

View file

@ -6,6 +6,7 @@
:jvm-opts ["-Djava.library.path=native"] :jvm-opts ["-Djava.library.path=native"]
:dependencies [[org.clojure/clojure "1.5.0"] :dependencies [[org.clojure/clojure "1.5.0"]
[ns-tracker "0.2.1"] [ns-tracker "0.2.1"]
[org.clojure/tools.nrepl "0.2.2"]
[org.clojars.jyaan/slick "247.1"] [org.clojars.jyaan/slick "247.1"]
[org.clojars.jyaan/slick-native "247.1"] [org.clojars.jyaan/slick-native "247.1"]
[org.clojars.jyaan/slick-lwjgl "247.1"]]) [org.clojars.jyaan/slick-lwjgl "247.1"]])

View file

@ -3,3 +3,9 @@
(defn -main [& args] (defn -main [& args]
(slick/start-game "test-game" :game)) (slick/start-game "test-game" :game))
(defmethod slick/update-game :game [state delta])
(def ^:dynamic g nil)
(def ^:dynamic s nil)
(defmethod slick/eval-with-bindings :game [state game f]
(binding [g game s state] (f)))

View file

@ -1,9 +1,16 @@
(ns hottub.slick (ns hottub.slick
(:import [org.newdawn.slick AppGameContainer]) (:import [org.newdawn.slick AppGameContainer])
(:use ns-tracker.core)) (:use ns-tracker.core)
(:require (clojure.tools.nrepl [server :as server]
[middleware :as middleware])
(clojure.tools.nrepl.middleware interruptible-eval
pr-values
session
load-file)))
(defmulti update-game (fn [state delta] (:state state))) (defmulti update-game (fn [state delta] (:state state)))
(defmulti render-game (fn [state graphics] (:state state))) (defmulti render-game (fn [state graphics] (:state state)))
(defmulti eval-with-bindings (fn [state game f] (:state state)))
(def modified-namespaces (ns-tracker ["src" "test"])) (def modified-namespaces (ns-tracker ["src" "test"]))
@ -16,24 +23,65 @@
:extends org.newdawn.slick.BasicGame) :extends org.newdawn.slick.BasicGame)
(defn game-create [title startstate value] (defn game-create [title startstate value]
[[title] (ref (assoc (or value {}) :state startstate))]) [[title]
(let [evalqueueatom (atom [])
executor (reify java.util.concurrent.Executor
(execute [this f] (swap! evalqueueatom #(conj % f))))
server (server/start-server :handler
(-> server/unknown-op
clojure.tools.nrepl.middleware/wrap-describe
(clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval :executor executor)
clojure.tools.nrepl.middleware.load-file/wrap-load-file
clojure.tools.nrepl.middleware.pr-values/pr-values
clojure.tools.nrepl.middleware.session/add-stdin
clojure.tools.nrepl.middleware.session/session
; ((fn [h] (fn [val] (prn val) (h val))))))]
))]
(prn "nrepl started on port " (:port server) server)
{:state (ref (assoc (or value {}) :state startstate))
:evalqueue evalqueueatom
:server server})])
(defn game-state-ref [this] (:state (.state this)))
(defn game-init [this container]) (defn game-init [this container])
(defn clear-and-get-evalqueue [this]
(let [evalqueueatom (:evalqueue (.state this))]
(loop [evalqueue @evalqueueatom]
(if (compare-and-set! evalqueueatom evalqueue [])
evalqueue
(recur @evalqueueatom)))))
(defn game-update [this container delta] (defn game-update [this container delta]
(doseq [ns-sym (modified-namespaces)] (doseq [ns-sym (modified-namespaces)]
(require ns-sym :reload)) (try
(require ns-sym :reload)
(catch Exception e (prn "Couldn't load" ns-sym (.getMessage e)))))
(doseq [f (clear-and-get-evalqueue this)]
(try
(eval-with-bindings @(game-state-ref this) this f)
(catch Exception e (prn "couldn't eval" f (.getMessage e)))))
(dosync (dosync
(if-let [statenew (update-game @(.state this) delta)] (try
(ref-set (.state this) (assoc @(.state this) :state statenew))))) (if-let [statenew (update-game @(game-state-ref this) delta)]
(ref-set (game-state-ref this) statenew))
(catch Exception e (prn "Couldn't update" (:state @(game-state-ref this)) (.getMessage e))))))
(defn game-render [this container graphics] (defn game-render [this container graphics]
(render-game @(.state this) graphics)) (try
(render-game @(game-state-ref this) graphics)
(catch Exception e (prn "Couldn't render" (:state @(game-state-ref this)) (.getMessage e)))))
(defn game-setstate [this statenew]
(dosync (ref-set (game-state-ref this) statenew)))
(defmethod update-game :default [state delta]) (defmethod update-game :default [state delta])
(defmethod render-game :default [state graphics]) (defmethod render-game :default [state graphics])
(defmethod eval-with-bindings :default [state game f] (f))
(defn start-game [title startstate & [value]] (defn start-game [title startstate & [value]]
(let [game (hottub.slick.Game. title startstate value) (let [game (hottub.slick.Game. title startstate value)
container (AppGameContainer. game 640 480 false)] container (AppGameContainer. game 640 480 false)]
(.start container))) (.start container)
game))