From fec30be7ddfbe0285a6b3e676ccc474db0c65abf Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Tue, 30 Mar 2021 19:24:52 -0400 Subject: [PATCH] fix broken hot reload pattern, handle exceptions in game updates --- editor/imstate.fnl | 2 ++ editor/repl.fnl | 27 ++++++++++++++++++++------- editor/replview.fnl | 2 +- game/entities/bomb.fnl | 9 +++++---- game/entities/bomberman.fnl | 6 +++--- game/mode.fnl | 24 ++++++++++++++++++++++-- game/tiles.fnl | 6 +++--- lib/util.fnl | 12 +++++++++++- todo.txt | 5 ----- 9 files changed, 67 insertions(+), 26 deletions(-) diff --git a/editor/imstate.fnl b/editor/imstate.fnl index 2c15b9f..be539d5 100644 --- a/editor/imstate.fnl +++ b/editor/imstate.fnl @@ -160,6 +160,8 @@ ; handle key events (when (focus view tag x y w h {:i 1 :iAnchor 1 :blink (love.timer.getTime)}) (local f view.imstate.focus) + (when (> f.i (+ (length text) 1)) (set f.i (+ (length text) 1))) + (when (> f.iAnchor (+ (length text) 1)) (set f.iAnchor (+ (length text) 1))) (when view.imstate.text (set textNew (replace-selection view textNew view.imstate.text))) (each [_ key (ipairs (or view.imstate.keys []))] diff --git a/editor/repl.fnl b/editor/repl.fnl index 5dd9203..bc97046 100644 --- a/editor/repl.fnl +++ b/editor/repl.fnl @@ -3,11 +3,24 @@ (local style (require :core.style)) (local lume (require :lib.lume)) -(local repl {}) +(local repl (util.hot-table ...)) +(fn repl.text-height [text ?font] + (let [font (or ?font style.font) + (_ newlines) (text:gsub "\n" "\n")] + (* (font:get_height) (+ newlines 1)))) + +(fn repl.inspect-table [tbl view x y-start w] + (var y y-start) + (var h 0) + (each [k v (pairs tbl)] + (let [kstr (fv k) + wk 1] + nil)) + ) (fn repl.inspect [v view x y w] (renderer.draw_text style.font (fv v) x y style.text) - (style.font:get_height)) + (repl.text-height (fv v))) (fn repl.inspector [{: vals} view x y] (var h 0) @@ -20,7 +33,7 @@ (listener:append line))) (fn repl.run [{: listeners}] - (local inspector (util.fn repl :inspector)) + (local inspector #(repl.inspector $...)) (fennel.repl {:readChunk coroutine.yield :onValues #(repl.notify listeners {:draw inspector :vals $1}) :onError (fn [errType err luaSource] (repl.notify listeners {:draw inspector :vals [err]})) @@ -39,11 +52,11 @@ (fn repl.new [] (local result {:listeners [] - :listen (util.fn repl :listen) - :unlisten (util.fn repl :unlisten) - :submit (util.fn repl :submit) + :listen #(repl.listen $...) + :unlisten #(repl.unlisten $...) + :submit #(repl.submit $...) :coro (coroutine.create repl.run)}) (coroutine.resume result.coro result) result) -repl +repl.hot diff --git a/editor/replview.fnl b/editor/replview.fnl index 5aff52f..81cf65f 100644 --- a/editor/replview.fnl +++ b/editor/replview.fnl @@ -33,7 +33,7 @@ (local cmd (or ?cmd self.cmd)) (when (= ?cmd nil) (set self.cmd "")) - (self:append {:draw (util.fn ReplView :draw-cmd) : cmd}) + (self:append {:draw #(self.draw-cmd $...) : cmd}) (self.conn:submit cmd)) (fn ReplView.draw [self] diff --git a/game/entities/bomb.fnl b/game/entities/bomb.fnl index 8961c92..9bdaec0 100644 --- a/game/entities/bomb.fnl +++ b/game/entities/bomb.fnl @@ -1,7 +1,8 @@ (local util (require :lib.util)) (local dim (require :game.dim)) -(local Bomb {}) +(local Bomb (util.hot-table ...)) + (fn draw-ticking [bomb x y] (love.graphics.setColor 0.4 0.4 0.4) (love.graphics.circle :fill x y (/ dim.tilesize 2)) @@ -39,9 +40,9 @@ :exploding (rules.clear-bomb bomb)))) (fn Bomb.new [] - {:state :ticking :timer 3 :solid true :draw (util.fn Bomb :draw) :update (util.fn Bomb :update)}) + {:state :ticking :timer 3 :solid true :draw #(Bomb.draw $...) :update #(Bomb.update $...)}) (fn Bomb.new-explosion [] - {:state :exploding :timer 0.5 :deadly true :draw (util.fn Bomb :draw) :update (util.fn Bomb :update)}) + {:state :exploding :timer 0.5 :deadly true :draw #(Bomb.draw $...) :update #(Bomb.update $...)}) -Bomb +Bomb.hot diff --git a/game/entities/bomberman.fnl b/game/entities/bomberman.fnl index 52b8f58..b0ca496 100644 --- a/game/entities/bomberman.fnl +++ b/game/entities/bomberman.fnl @@ -4,7 +4,7 @@ (local {: edge : vec*} (util.require :game.helpers)) (local map (require :game.tilemap)) -(local bomberman {}) +(local bomberman (util.hot-table ...)) (set bomberman.keymap {:up :w :down :s :left :a :right :d :bomb :x}) (fn bomberman.draw [entity] @@ -30,6 +30,6 @@ (rules.place-bomb (map.world-to-tile entity.pos)))) (fn bomberman.new [pos] - {: pos :vel [0 0] :draw (util.fn bomberman :draw) :update (util.fn bomberman :update)}) + {: pos :vel [0 0] :draw #(bomberman.draw $...) :update #(bomberman.update $...)}) -bomberman +bomberman.hot diff --git a/game/mode.fnl b/game/mode.fnl index cbd76b2..3987409 100644 --- a/game/mode.fnl +++ b/game/mode.fnl @@ -2,15 +2,35 @@ (local map (require :game.tilemap)) (local rules (require :game.rules)) -(fn update [dt] +(fn game-update [dt] (map.update-entitymap state.bombs dt rules) (each [_ entity (ipairs state.entities)] (entity:update dt rules))) -(fn draw [] +(fn exception-update [dt] + (when (love.keyboard.isDown :f2) + (set state.update-exception nil))) + +(fn update [dt] + (if state.update-exception + (exception-update dt) + (xpcall #(game-update dt) (fn [msg] + (set state.update-exception (.. msg "\n" (debug.traceback))))))) + +(fn game-draw [] (map.draw-tilemaps 0 0 [state.bombs state.map]) (each [_ entity (ipairs state.entities)] (entity:draw))) +(fn exception-draw [] + (love.graphics.setColor 1 0 0 1) + (love.graphics.setNewFont 14) + (love.graphics.printf (.. "Press F2 when resolved\n" state.update-exception) 20 20 (- (love.graphics.getWidth) 40))) + +(fn draw [] + (if state.update-exception + (exception-draw) + (game-draw))) + {: update : draw} diff --git a/game/tiles.fnl b/game/tiles.fnl index a4e5a5b..3893ddc 100644 --- a/game/tiles.fnl +++ b/game/tiles.fnl @@ -1,7 +1,7 @@ (local dim (require :game.dim)) (local util (require :lib.util)) -(local tileset {}) +(local tileset (util.hot-table ...)) (fn rect [x y color] (love.graphics.setColor (table.unpack color)) (love.graphics.rectangle :fill @@ -35,7 +35,7 @@ :breakable true} {:name :dot :edible true} - ] (util.fn tileset :bombertile-draw))) + ] #(tileset.bombertile-draw $...))) -tileset +tileset.hot diff --git a/lib/util.fnl b/lib/util.fnl index 2676d3e..4750016 100644 --- a/lib/util.fnl +++ b/lib/util.fnl @@ -53,6 +53,16 @@ (fn swappable-require [modname] (swappable (require modname))) +(fn hot-table [modname] + (local tbl {}) + (fn find-table [] + (let [loaded-pkg (. package.loaded modname)] + (if (= (type loaded-pkg) :table) loaded-pkg) tbl)) + (setmetatable {:hot tbl} { + :__index (fn [_ key] (. (find-table) key)) + :__newindex (fn [_ key val] (tset (find-table) key val)) + })) + (fn readjson [filename] (local f (io.open filename :r)) (local text (f:read "*a")) @@ -91,6 +101,6 @@ {: int8-to-bytes : int16-to-bytes : int24-to-bytes : bytes-to-uint8 : bytes-to-uint16 : bytes-to-uint24 : splice : lo : hi - : reload : hotswap : swappable :require swappable-require :fn mk-swappable-fn + : reload : hotswap : swappable :require swappable-require : hot-table : readjson : writejson : waitfor : in-coro : multival} diff --git a/todo.txt b/todo.txt index b777f82..3d4fd56 100644 --- a/todo.txt +++ b/todo.txt @@ -1,11 +1,6 @@ TODO: -* all usages of util.fn are wrong!! you can't use the table as locally defined as it will disappear!!! aargh * tile editor (geometric shapes for now?) -DEBUG TOOLS: -#1 problem: update failing crashes the editor -- store exception and stop running game; patch and restart - Repl-y thing: appends objects to a list (inspectable?)