Overhaul Timeline to log tweaks to specific ticks, rebuilding if needed
This commit is contained in:
parent
0cab97f0a6
commit
8903601a1a
5 changed files with 91 additions and 58 deletions
|
|
@ -1,7 +1,7 @@
|
|||
(local Vat (require :vat))
|
||||
(local {: basic-sandbox : det} (require :vat.env))
|
||||
(local {: snapshot : inject} (require :vat.snapshot))
|
||||
(local {: Timeline : tick-trial} (require :vat.timeline))
|
||||
(local Timeline (require :vat.timeline))
|
||||
(local multimethod (require :vat.lib.multimethod))
|
||||
(local {: gen-random-env} (require :vat.lib.random))
|
||||
(local {: on-love-key-event : love-input : make-love-draw-env} (require :vat.lib.love))
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
(let [vat (get-game-vat)
|
||||
end-tick (vat:last-tick)
|
||||
start-tick (math.max 1 (- end-tick tick-count))]
|
||||
(Timeline.new (tick-trial vat) start-tick)))
|
||||
(Timeline.new vat start-tick)))
|
||||
|
||||
(fn restart []
|
||||
(game-vat:eval "((. (require :game) :restart))"))
|
||||
|
|
|
|||
45
test/vat.fnl
45
test/vat.fnl
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(local Vat (require :vat))
|
||||
(local {: basic-sandbox} (require :vat.env))
|
||||
(local {: Timeline : tick-trial} (require :vat.timeline))
|
||||
(local Timeline (require :vat.timeline))
|
||||
|
||||
(fn test-binary-search []
|
||||
(t.= [true 1] [(binary-search [1 2 3 4 5] 1)])
|
||||
|
|
@ -100,24 +100,31 @@
|
|||
(local vat (Vat.new :tracked {:ticks-per-snap 3}))
|
||||
(vat:inject {:tick (fn [] (set _G.counter (+ _G.counter 1))) :counter 1})
|
||||
(for [_ 1 30] (vat:tick))
|
||||
(local t1 (Timeline.new (tick-trial vat) 10 20))
|
||||
(t.= 11 (length t1.snapshots))
|
||||
(t.= 10 (. t1.snapshots 1 :vat :env :counter))
|
||||
(t.= 15 (. t1.snapshots 6 :vat :env :counter))
|
||||
(t.= 20 (. t1.snapshots 11 :vat :env :counter))
|
||||
(local t2 (Timeline.new (tick-trial vat #($1:inject {:tick (fn [] (set _G.counter (+ _G.counter 10)))})) 20 25))
|
||||
(t.= 6 (length t2.snapshots))
|
||||
(t.= 20 (. t2.snapshots 1 :vat :env :counter))
|
||||
(t.= 70 (. t2.snapshots 6 :vat :env :counter))
|
||||
(t2:move-start 15)
|
||||
(t.= 11 (length t2.snapshots))
|
||||
(t.= 15 (. t2.snapshots 1 :vat :env :counter))
|
||||
(t.= 65 (. t2.snapshots 6 :vat :env :counter))
|
||||
(t.= 115 (. t2.snapshots 11 :vat :env :counter))
|
||||
(t2:move-start 20)
|
||||
(t.= 6 (length t2.snapshots))
|
||||
(t.= 20 (. t2.snapshots 1 :vat :env :counter))
|
||||
(t.= 70 (. t2.snapshots 6 :vat :env :counter)))
|
||||
(local tl (Timeline.new vat 10 20))
|
||||
(t.= 11 (length tl.snapshots))
|
||||
(t.= 10 (. tl.snapshots 1 :vat :env :counter))
|
||||
(t.= 15 (. tl.snapshots 6 :vat :env :counter))
|
||||
(t.= 20 (. tl.snapshots 11 :vat :env :counter))
|
||||
(: (. tl.snapshots 6 :vat) :inject {:tick (fn [] (set _G.counter (+ _G.counter 10)))})
|
||||
(t.is (. tl.tweaks 15))
|
||||
(t.= 11 (length tl.snapshots))
|
||||
(t.= 10 (. tl.snapshots 1 :vat :env :counter))
|
||||
(t.= 15 (. tl.snapshots 6 :vat :env :counter))
|
||||
(t.= 65 (. tl.snapshots 11 :vat :env :counter))
|
||||
(tl:move-end 25)
|
||||
(t.= 16 (length tl.snapshots))
|
||||
(t.= 115 (. tl.snapshots 16 :vat :env :counter))
|
||||
(tl:move-start 15)
|
||||
(t.= 11 (length tl.snapshots))
|
||||
(t.= 15 (. tl.snapshots 1 :vat :env :counter))
|
||||
(t.= 65 (. tl.snapshots 6 :vat :env :counter))
|
||||
(t.= 115 (. tl.snapshots 11 :vat :env :counter))
|
||||
(tl:move 20 30)
|
||||
(t.= 15 tl.start-tick)
|
||||
(t.= 16 (length tl.snapshots))
|
||||
(t.= 15 (. tl.snapshots 1 :vat :env :counter))
|
||||
(t.= 65 (. tl.snapshots 6 :vat :env :counter))
|
||||
(t.= 165 (. tl.snapshots 16 :vat :env :counter)))
|
||||
|
||||
{: test-binary-search
|
||||
: test-fork
|
||||
|
|
|
|||
|
|
@ -109,11 +109,11 @@
|
|||
last-snapshot (. snapshots (length snapshots))]
|
||||
(+ last-snapshot.tick self.history.tick-count)))
|
||||
:vat-at-tick
|
||||
(fn [self tick]
|
||||
(fn [self tick ?opts]
|
||||
(let [snapshots self.history.snapshots
|
||||
(found isnap) (binary-search snapshots tick #(if (< $1.tick $2) -1 (> $1.tick $2) 1 0))
|
||||
snapshot (. snapshots (if found isnap (- isnap 1)))
|
||||
vat (snapshot.vat:new)]
|
||||
vat (snapshot.vat:new ?opts)]
|
||||
(if found vat
|
||||
(let [first-step (+ (vat:stepcount) 1)]
|
||||
(vat:playback-ticks-from self first-step (- tick snapshot.tick))
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
(local {: history-component : LogPtr : step-lim} (require :vat.history))
|
||||
(local {: profile : time : debug-component} (require :vat.debug))
|
||||
(local fennel (require :lib.fennel))
|
||||
(local {: show} (require :inspector.debug))
|
||||
; (local {: show} (require :inspector.debug))
|
||||
|
||||
; a vat is a sandboxed Lua code environment where we intend the following properties to hold:
|
||||
; 1. all regular functions are deterministic (calling a function with the same arguments always causes the same effect and returns the same value)
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
(let [state-vat (self.module-vat:new)
|
||||
allowedGlobals (if ?envForGlobals (icollect [k _ (pairs ?envForGlobals)] k) nil)
|
||||
luacode (fennel.compile-string (.. "(require " (fennel.view modulename) ")") {:env state-vat.env :requireAsInclude true : allowedGlobals})]
|
||||
(when (= state-vat.env.package.preload nil) (show :dead-include))
|
||||
; (when (= state-vat.env.package.preload nil) (show :dead-include))
|
||||
(state-vat:eval-lua luacode)
|
||||
(collect [k v (pairs state-vat.env)] (when (or (= k :package) (not (. self.module-vat.env k))) (values k v)))))
|
||||
:include (fn [self modulename] (self:inject (self:export-state-from-module modulename self.env)))
|
||||
|
|
|
|||
|
|
@ -1,41 +1,51 @@
|
|||
(fn tick-trial [parent-vat ?f]
|
||||
(fn [start-tick]
|
||||
(let [vat (parent-vat:vat-at-tick start-tick)
|
||||
steplim-pre-tweak (vat:nextstep)
|
||||
_ (when ?f (?f vat))
|
||||
steplim-post-tweak (vat:nextstep)
|
||||
step-delta (- steplim-post-tweak steplim-pre-tweak)]
|
||||
{: vat
|
||||
:next (fn [self]
|
||||
(let [vat (self.vat:new)]
|
||||
(vat:playback-ticks-from parent-vat (- (self.vat:nextstep) step-delta))
|
||||
(when (> (vat:nextstep) (self.vat:nextstep))
|
||||
{: vat :next self.next})))})))
|
||||
|
||||
(local Timeline {})
|
||||
(set Timeline.__index Timeline)
|
||||
|
||||
(fn Timeline.new [trial start-tick ?end-tick]
|
||||
(let [self (setmetatable {: trial} Timeline)]
|
||||
(set Timeline.components
|
||||
{:tweaks
|
||||
{:after [:log :history]
|
||||
:new (fn [self opts] {:on-tweak opts.on-tweak :start-step (self:nextstep)})
|
||||
:clone (fn [self vat opts]
|
||||
(set self.tweaks.start-step vat.tweaks.start-step)
|
||||
(when (= self.tweaks.on-tweak nil) (set self.tweaks.on-tweak vat.tweaks.on-tweak)))
|
||||
:hooks {:on-tweak (fn [self ...] (when self.tweaks.on-tweak (self.tweaks.on-tweak self)) ...)
|
||||
:set-on-tweak (fn [self on-tweak] (set self.tweaks.on-tweak on-tweak))
|
||||
:reset-tweaks (fn [self] (set self.tweaks.start-step (self:nextstep)))
|
||||
:apply-tweaks-to (fn [self vat]
|
||||
(let [count (- (self:nextstep) self.tweaks.start-step)]
|
||||
(when (> count 0)
|
||||
(vat:playback-from self self.tweaks.start-step count))))}
|
||||
:overrides {:tick (fn [tick] (fn [self] (self:on-tweak (tick self))))
|
||||
:inject (fn [inject] (fn [self state] (self:on-tweak (inject self state))))
|
||||
:eval-func (fn [eval] (fn [self func ...] (self:on-tweak (eval self func ...))))}}})
|
||||
|
||||
; todo: probably would be nice for snapshot list to be generated on demand so we can batch changes
|
||||
; todo: timeline cloning
|
||||
(fn Timeline.new [vat start-tick ?end-tick]
|
||||
(let [self (setmetatable {: vat :tweaks []} Timeline)]
|
||||
(self:rebuild start-tick ?end-tick)
|
||||
self))
|
||||
|
||||
(fn Timeline.validate-start-tick [self start-tick]
|
||||
(if (and self.earliest-tweak (< self.earliest-tweak start-tick)) self.earliest-tweak start-tick))
|
||||
|
||||
(fn Timeline.rebuild [self start-tick ?end-tick]
|
||||
(set self.snapshots [])
|
||||
(set self.start-tick start-tick)
|
||||
(self:insert-snapshot 1 (self.trial start-tick) start-tick)
|
||||
(self:insert-snapshots 1 (if ?end-tick (- ?end-tick start-tick) nil))
|
||||
(set self.start-tick (self:validate-start-tick start-tick))
|
||||
(let [vat (self.vat:vat-at-tick self.start-tick)]
|
||||
(self:insert-snapshot 1 vat (vat:nextstep) self.start-tick))
|
||||
(self:build-snapshots 1 (if ?end-tick (- ?end-tick self.start-tick) nil))
|
||||
(set self.end-tick (. self.snapshots (length self.snapshots) :tick)))
|
||||
|
||||
(fn Timeline.move [self new-start-tick ?new-end-tick]
|
||||
(assert (or (= ?new-end-tick nil) (<= new-start-tick ?new-end-tick)))
|
||||
|
||||
(if (not= new-start-tick self.start-tick)
|
||||
(if (not= (self:validate-start-tick new-start-tick) self.start-tick)
|
||||
(self:rebuild new-start-tick ?new-end-tick)
|
||||
(= ?new-end-tick nil)
|
||||
(self:insert-snapshots (length self.snapshots) nil)
|
||||
(self:build-snapshots (length self.snapshots) nil)
|
||||
(> ?new-end-tick self.end-tick)
|
||||
(self:insert-snapshots (length self.snapshots) (- ?new-end-tick self.end-tick))
|
||||
(self:build-snapshots (length self.snapshots) (- ?new-end-tick self.end-tick))
|
||||
(< ?new-end-tick self.end-tick)
|
||||
(for [i 1 (- self.end-tick ?new-end-tick)]
|
||||
(table.remove self.snapshots)))
|
||||
|
|
@ -48,17 +58,33 @@
|
|||
(fn Timeline.move-start [self new-start-tick]
|
||||
(self:move new-start-tick self.end-tick))
|
||||
|
||||
(fn Timeline.insert-snapshot [self isnap snap tick]
|
||||
(set snap.tick tick)
|
||||
(table.insert self.snapshots isnap snap))
|
||||
(fn Timeline.on-tweak [self tick vat]
|
||||
(tset self.tweaks tick vat)
|
||||
(when (or (= self.earliest-tweak nil) (< tick self.earliest-tweak))
|
||||
(set self.earliest-tweak tick))
|
||||
(let [end-tick self.end-tick]
|
||||
; rebuild snapshots
|
||||
(self:move self.start-tick tick)
|
||||
(self:move self.start-tick end-tick)))
|
||||
|
||||
(fn Timeline.insert-snapshots [self isnap-prev count]
|
||||
(fn Timeline.insert-snapshot [self isnap vat src-steplim tick]
|
||||
(vat:install-components self.components)
|
||||
(vat:reset-tweaks)
|
||||
(vat:set-on-tweak nil)
|
||||
(let [tweak (. self.tweaks tick)]
|
||||
(when tweak (tweak:apply-tweaks-to vat)))
|
||||
(vat:set-on-tweak #(self:on-tweak tick $1))
|
||||
(table.insert self.snapshots isnap {: vat : tick : src-steplim}))
|
||||
|
||||
(fn Timeline.build-snapshots [self isnap-prev count]
|
||||
(when (or (= count nil) (> count 0))
|
||||
(let [prev-snap (. self.snapshots isnap-prev)
|
||||
snap (prev-snap:next)
|
||||
isnap (+ isnap-prev 1)]
|
||||
(when snap
|
||||
(self:insert-snapshot isnap snap (+ prev-snap.tick 1))
|
||||
(self:insert-snapshots isnap (when count (- count 1)))))))
|
||||
(let [prev-snap (. self.snapshots isnap-prev)]
|
||||
(when (< prev-snap.src-steplim (self.vat:nextstep))
|
||||
(let [vat (prev-snap.vat:new)
|
||||
_ (vat:playback-ticks-from self.vat prev-snap.src-steplim 1)
|
||||
isnap (+ isnap-prev 1)
|
||||
stepcount (- (vat:nextstep) (prev-snap.vat:nextstep))]
|
||||
(self:insert-snapshot isnap vat (+ prev-snap.src-steplim stepcount) (+ prev-snap.tick 1))
|
||||
(self:build-snapshots isnap (when count (- count 1))))))))
|
||||
|
||||
{: Timeline : tick-trial}
|
||||
Timeline
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue