Mercurial > vba-clojure
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-driver2 (: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-image18 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc"))20 (def yellow-save-file21 (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 ram39 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %)))41 (def rom42 (cpu-data (Gb/getROMSize) #(Gb/getROM %)))44 (def working-ram45 (cpu-data Gb/WRAM_SIZE #(Gb/getWRAM %)))47 (def video-ram48 (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %)))50 (def registers51 (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %)))53 (def button-code54 {;; main buttons55 :a 0x000156 :b 0x000258 ;; directional pad59 :r 0x001060 :l 0x002061 :u 0x004062 :d 0x008064 ;; meta buttons65 :select 0x000466 :start 0x000868 ;; hard reset -- not really a button69 :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) buttons78 (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/readFileToByteArray109 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/writeByteArrayToFile120 dest bytes)121 (.rewind buf)))123 (defn find-save-state [frame]124 (let [save (@history frame)]125 (if (not (nil? save)) save126 (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 (do133 (reset! current-frame frame)134 (load-state save)))))136 (defn clear-history [] (reset! history empty-history))138 (defn rewind139 ([] (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 step153 ([] (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 play165 ([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)))