view clojure/com/aurellem/gb_driver.clj @ 76:d7c38ce83421

working on disk-backup for save-states
author Robert McIntyre <rlm@mit.edu>
date Thu, 08 Mar 2012 19:48:54 -0600
parents eb7d4efe0f34
children 9ba461a5c60f
line wrap: on
line source
1 (ns com.aurellem.gb-driver
2 (:import com.aurellem.gb.Gb)
3 (:import java.io.File)
4 (:import (java.nio IntBuffer ByteOrder)))
6 (Gb/loadVBA)
8 (def ^:dynamic *max-history* 1e4)
10 (def ^:dynamic *backup-saves-to-disk* true)
12 (def ^:dynamic *save-history* true)
14 (def ^:dynamic *save-state-cache*
15 (File. "/home/r/proj/pokemon-escape/save-states/"))
17 (def yellow-rom-image
18 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc"))
20 (def yellow-save-file
21 (File. "/home/r/proj/pokemon-escape/roms/yellow.sav"))
23 (def current-frame (atom 0))
25 (defn vba-init []
26 (reset! current-frame 0)
27 (.delete yellow-save-file)
28 (Gb/startEmulator (.getCanonicalPath yellow-rom-image)))
30 (defn shutdown [] (Gb/shutdown))
32 (defn reset [] (shutdown) (vba-init))
34 (defn cpu-data [size arr-fn]
35 (let [store (int-array size)]
36 (fn [] (arr-fn store) store)))
38 (def ram
39 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %)))
41 (def rom
42 (cpu-data (Gb/getROMSize) #(Gb/getROM %)))
44 (def working-ram
45 (cpu-data Gb/WRAM_SIZE #(Gb/getWRAM %)))
47 (def video-ram
48 (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %)))
50 (def registers
51 (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %)))
53 (def button-code
54 {;; main buttons
55 :a 0x0001
56 :b 0x0002
58 ;; directional pad
59 :r 0x0010
60 :l 0x0020
61 :u 0x0040
62 :d 0x0080
64 ;; meta buttons
65 :select 0x0004
66 :start 0x0008
68 ;; hard reset -- not really a button
69 :reset 0x0800})
71 (defn button-mask [buttons]
72 (reduce bit-or 0x0000 (map button-code buttons)))
74 (defn buttons [mask]
75 (loop [buttons []
76 masks (seq button-code)]
77 (if (empty? masks) buttons
78 (let [[button value] (first masks)]
79 (if (not= 0x0000 (bit-and value mask))
80 (recur (conj buttons button) (rest masks))
81 (recur buttons (rest masks)))))))
83 (defrecord SaveState [frame save-data])
85 (defn frame [] @current-frame)
87 (defn save-state []
88 (SaveState.
89 (frame)
90 (Gb/saveState)))
92 (defn load-state [#^SaveState save]
93 (reset! current-frame (:frame save))
94 (Gb/loadState (:save-data save)))
96 (def empty-history (sorted-map))
98 (def history (atom empty-history))
100 (defn frame->disk-save [frame]
101 (File. *save-state-cache*
102 (format "%07d.sav" frame)))
104 (defn get-save-from-disk [frame]
105 (let [save (frame->disk-save frame)]
106 (if (.exists save)
107 (let [buf (Gb/saveBuffer)
108 bytes (org.apache.commons.io.FileUtils/readFileToByteArray
109 save)]
110 (.put buf bytes)
111 (.flip buf)
112 (SaveState. frame buf)))))
114 (defn store-save-to-disk [^SaveState save]
115 (let [buf (:save-data save)
116 bytes (byte-array (.limit buf))
117 dest (frame->disk-save (:frame save))]
118 (.get buf bytes)
119 (org.apache.commons.io.FileUtils/writeByteArrayToFile
120 dest bytes)
121 (.rewind buf)))
123 (defn find-save-state [frame]
124 (let [save (@history frame)]
125 (if (not (nil? save)) save
126 (get-save-from-disk frame))))
128 (defn goto [frame]
129 (let [save (find-save-state frame)]
130 (if (nil? save)
131 (println frame "is not in history")
132 (do
133 (reset! current-frame frame)
134 (load-state save)))))
136 (defn clear-history [] (reset! history empty-history))
138 (defn rewind
139 ([] (rewind 1))
140 ([n] (goto (- @current-frame n))))
142 (defn backup-state [frame]
143 (swap! history #(assoc % frame (save-state)))
144 (if (> (count @history) *max-history*)
145 (swap! history #(dissoc % (first (first %))))))
147 (defn advance []
148 (if *save-history*
149 (backup-state @current-frame))
150 (swap! current-frame inc))
152 (defn step
153 ([] (advance) (Gb/step))
154 ([mask-or-buttons]
155 (advance)
156 (if (number? mask-or-buttons)
157 (Gb/step mask-or-buttons)
158 (Gb/step (button-mask mask-or-buttons)))))
160 (defn step! [& args]
161 (binding [*save-history* false]
162 (apply step args)))
164 (defn play
165 ([n] (dorun (dotimes [_ n] (step))))
166 ([] (play Integer/MAX_VALUE)))
168 (defn buf-seq [buffer]
169 (let [bytes (byte-array (.capacity buffer))]
170 (.get buffer bytes)
171 (.rewind buffer)
172 (seq bytes)))