Mercurial > vba-clojure
changeset 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 |
files | clojure/com/aurellem/fragments.clj clojure/com/aurellem/gb_driver.clj java/src/com/aurellem/gb/Gb.java src/clojure/clojure.cpp src/gb/GB.cpp src/gb/GB.h |
diffstat | 6 files changed, 134 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/clojure/com/aurellem/fragments.clj Thu Mar 08 06:01:09 2012 -0600 1.2 +++ b/clojure/com/aurellem/fragments.clj Thu Mar 08 19:48:54 2012 -0600 1.3 @@ -17,18 +17,19 @@ 1.4 (repeat (- start-frames n 1) [])) 1.5 moves (drop start moves)] 1.6 (goto start) 1.7 - (dorun (map step moves)) 1.8 + (dorun (map step! moves)) 1.9 (nth (registers) 2))) 1.10 1.11 - 1.12 (defn earliest-press 1.13 [start] 1.14 (print "determining bad program-counter...") 1.15 + (reset) 1.16 + (dorun (dotimes [_ start-frames] (step))) 1.17 (let [bad-counter (play-start 0 0)] 1.18 (println bad-counter) 1.19 (loop [n start] 1.20 (print "trying" n "...") 1.21 - (let [nth-counter (play-start n)] 1.22 + (let [nth-counter (play-start (dec n) n)] 1.23 (println "got" nth-counter) 1.24 (if (= nth-counter bad-counter) 1.25 (recur (inc n)) n)))))
2.1 --- a/clojure/com/aurellem/gb_driver.clj Thu Mar 08 06:01:09 2012 -0600 2.2 +++ b/clojure/com/aurellem/gb_driver.clj Thu Mar 08 19:48:54 2012 -0600 2.3 @@ -5,6 +5,15 @@ 2.4 2.5 (Gb/loadVBA) 2.6 2.7 +(def ^:dynamic *max-history* 1e4) 2.8 + 2.9 +(def ^:dynamic *backup-saves-to-disk* true) 2.10 + 2.11 +(def ^:dynamic *save-history* true) 2.12 + 2.13 +(def ^:dynamic *save-state-cache* 2.14 + (File. "/home/r/proj/pokemon-escape/save-states/")) 2.15 + 2.16 (def yellow-rom-image 2.17 (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc")) 2.18 2.19 @@ -24,9 +33,7 @@ 2.20 2.21 (defn cpu-data [size arr-fn] 2.22 (let [store (int-array size)] 2.23 - (fn [] 2.24 - (arr-fn store) 2.25 - store))) 2.26 + (fn [] (arr-fn store) store))) 2.27 2.28 (def ram 2.29 (cpu-data (Gb/getRAMSize) #(Gb/getRAM %))) 2.30 @@ -73,35 +80,74 @@ 2.31 (recur (conj buttons button) (rest masks)) 2.32 (recur buttons (rest masks))))))) 2.33 2.34 +(defrecord SaveState [frame save-data]) 2.35 2.36 -(defn save-state [] (Gb/saveState)) 2.37 +(defn frame [] @current-frame) 2.38 2.39 -(def history (atom {})) 2.40 +(defn save-state [] 2.41 + (SaveState. 2.42 + (frame) 2.43 + (Gb/saveState))) 2.44 + 2.45 +(defn load-state [#^SaveState save] 2.46 + (reset! current-frame (:frame save)) 2.47 + (Gb/loadState (:save-data save))) 2.48 + 2.49 +(def empty-history (sorted-map)) 2.50 + 2.51 +(def history (atom empty-history)) 2.52 + 2.53 +(defn frame->disk-save [frame] 2.54 + (File. *save-state-cache* 2.55 + (format "%07d.sav" frame))) 2.56 + 2.57 +(defn get-save-from-disk [frame] 2.58 + (let [save (frame->disk-save frame)] 2.59 + (if (.exists save) 2.60 + (let [buf (Gb/saveBuffer) 2.61 + bytes (org.apache.commons.io.FileUtils/readFileToByteArray 2.62 + save)] 2.63 + (.put buf bytes) 2.64 + (.flip buf) 2.65 + (SaveState. frame buf))))) 2.66 + 2.67 +(defn store-save-to-disk [^SaveState save] 2.68 + (let [buf (:save-data save) 2.69 + bytes (byte-array (.limit buf)) 2.70 + dest (frame->disk-save (:frame save))] 2.71 + (.get buf bytes) 2.72 + (org.apache.commons.io.FileUtils/writeByteArrayToFile 2.73 + dest bytes) 2.74 + (.rewind buf))) 2.75 + 2.76 +(defn find-save-state [frame] 2.77 + (let [save (@history frame)] 2.78 + (if (not (nil? save)) save 2.79 + (get-save-from-disk frame)))) 2.80 2.81 (defn goto [frame] 2.82 - (let [save (@history frame)] 2.83 - (if (not (nil? save)) 2.84 + (let [save (find-save-state frame)] 2.85 + (if (nil? save) 2.86 + (println frame "is not in history") 2.87 (do 2.88 (reset! current-frame frame) 2.89 - (Gb/loadState save)) 2.90 - (println "no backup state")))) 2.91 + (load-state save))))) 2.92 2.93 -(defn clear-history [] (reset! history {})) 2.94 +(defn clear-history [] (reset! history empty-history)) 2.95 2.96 (defn rewind 2.97 - ([n] (goto (- @current-frame n))) 2.98 - ([] (rewind 1))) 2.99 - 2.100 + ([] (rewind 1)) 2.101 + ([n] (goto (- @current-frame n)))) 2.102 + 2.103 (defn backup-state [frame] 2.104 - (swap! history #(assoc % frame (save-state)))) 2.105 - 2.106 -(def ^:dynamic *save-history* true) 2.107 + (swap! history #(assoc % frame (save-state))) 2.108 + (if (> (count @history) *max-history*) 2.109 + (swap! history #(dissoc % (first (first %)))))) 2.110 2.111 (defn advance [] 2.112 - (swap! current-frame inc) 2.113 (if *save-history* 2.114 - (let [save (save-state)] 2.115 - (backup-state @current-frame)))) 2.116 + (backup-state @current-frame)) 2.117 + (swap! current-frame inc)) 2.118 2.119 (defn step 2.120 ([] (advance) (Gb/step)) 2.121 @@ -114,7 +160,13 @@ 2.122 (defn step! [& args] 2.123 (binding [*save-history* false] 2.124 (apply step args))) 2.125 + 2.126 +(defn play 2.127 + ([n] (dorun (dotimes [_ n] (step)))) 2.128 + ([] (play Integer/MAX_VALUE))) 2.129 2.130 -(defn frame [] @current-frame) 2.131 - 2.132 - 2.133 +(defn buf-seq [buffer] 2.134 + (let [bytes (byte-array (.capacity buffer))] 2.135 + (.get buffer bytes) 2.136 + (.rewind buffer) 2.137 + (seq bytes))) 2.138 \ No newline at end of file
3.1 --- a/java/src/com/aurellem/gb/Gb.java Thu Mar 08 06:01:09 2012 -0600 3.2 +++ b/java/src/com/aurellem/gb/Gb.java Thu Mar 08 19:48:54 2012 -0600 3.3 @@ -32,24 +32,49 @@ 3.4 3.5 public static native void shutdown(); 3.6 3.7 - public static native void saveState(ByteBuffer buffer, int size); 3.8 + public static native long saveState(ByteBuffer buffer, int size); 3.9 3.10 public static native void loadState(ByteBuffer buffer, int size); 3.11 3.12 - public static final int SAVE_SIZE = 90000; 3.13 + public static final int MAX_SAVE_SIZE = 90000; 3.14 3.15 - public static ByteBuffer saveState(){ 3.16 + public static ByteBuffer createDirectByteBuffer(int capacity){ 3.17 + byte[] zeros = new byte[capacity]; 3.18 ByteBuffer buf = 3.19 - ByteBuffer.allocateDirect(SAVE_SIZE) 3.20 + ByteBuffer.allocateDirect(capacity) 3.21 .order(ByteOrder.nativeOrder()); 3.22 + buf.put(zeros); 3.23 buf.clear(); 3.24 - saveState(buf, SAVE_SIZE); 3.25 - buf.flip(); 3.26 return buf; 3.27 } 3.28 3.29 + public static ByteBuffer saveBuffer(){ 3.30 + return createDirectByteBuffer(MAX_SAVE_SIZE); 3.31 + } 3.32 + 3.33 + public static ByteBuffer saveState(){ 3.34 + ByteBuffer buf = saveBuffer(); 3.35 + 3.36 + saveState(buf, buf.capacity()); 3.37 + 3.38 + // determine the extent of the saved data 3.39 + int position = buf.capacity() - 1; 3.40 + for (int i = position; i > 0; i--){ 3.41 + if (0 != buf.get(i)){ 3.42 + position = i; 3.43 + break; 3.44 + }} 3.45 + System.out.println("Position: " + position); 3.46 + byte[] saveArray = new byte[position]; 3.47 + ByteBuffer save = createDirectByteBuffer(position); 3.48 + buf.get(saveArray, 0 , position); 3.49 + save.put(saveArray); 3.50 + save.rewind(); 3.51 + return save; 3.52 + } 3.53 + 3.54 public static void loadState(ByteBuffer saveState){ 3.55 - loadState(saveState, SAVE_SIZE); 3.56 + loadState(saveState, MAX_SAVE_SIZE); 3.57 } 3.58 3.59 public static native int getROMSize();
4.1 --- a/src/clojure/clojure.cpp Thu Mar 08 06:01:09 2012 -0600 4.2 +++ b/src/clojure/clojure.cpp Thu Mar 08 19:48:54 2012 -0600 4.3 @@ -79,13 +79,14 @@ 4.4 /* 4.5 * Class: com_aurellem_gb_Gb 4.6 * Method: saveState 4.7 - * Signature: (Ljava/nio/ByteBuffer;)V 4.8 + * Signature: (Ljava/nio/ByteBuffer;I)J 4.9 */ 4.10 -JNIEXPORT void JNICALL Java_com_aurellem_gb_Gb_saveState 4.11 +JNIEXPORT jlong JNICALL Java_com_aurellem_gb_Gb_saveState 4.12 (JNIEnv *env, jclass clazz, jobject buffer, jint size){ 4.13 char* buffer_address = 4.14 ((char*) env->GetDirectBufferAddress(buffer)); 4.15 - gbWriteMemSaveState(buffer_address, size); 4.16 + long limit = gbWriteMemSaveStatePos(buffer_address, size); 4.17 + return limit; 4.18 } 4.19 4.20 /*
5.1 --- a/src/gb/GB.cpp Thu Mar 08 06:01:09 2012 -0600 5.2 +++ b/src/gb/GB.cpp Thu Mar 08 19:48:54 2012 -0600 5.3 @@ -2463,14 +2463,16 @@ 5.4 5.5 bool gbWriteSaveStateToStream(gzFile gzFile) 5.6 { 5.7 + 5.8 utilWriteInt(gzFile, GBSAVE_GAME_VERSION); 5.9 5.10 + 5.11 utilGzWrite(gzFile, &gbRom[0x134], 15); 5.12 5.13 utilWriteData(gzFile, gbSaveGameStruct); 5.14 - 5.15 + 5.16 utilGzWrite(gzFile, &IFF, 2); 5.17 - 5.18 + 5.19 if (gbSgbMode) 5.20 { 5.21 gbSgbSaveGame(gzFile); 5.22 @@ -2549,11 +2551,12 @@ 5.23 utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); 5.24 } 5.25 5.26 + utilWriteInt(gzFile, 0x07); // RLM this is the end of file marker. 5.27 return true; 5.28 } 5.29 5.30 -bool gbWriteMemSaveState(char *memory, int available) 5.31 -{ 5.32 + 5.33 +long gbWriteMemSaveStatePos(char *memory, int available){ 5.34 gzFile gzFile = utilMemGzOpen(memory, available, "w"); 5.35 5.36 if (gzFile == NULL) 5.37 @@ -2565,12 +2568,21 @@ 5.38 5.39 long pos = utilGzTell(gzFile) + 8; 5.40 5.41 - if (pos >= (available)) 5.42 - res = false; 5.43 + if (pos >= available){ 5.44 + pos = 0; 5.45 + } 5.46 5.47 utilGzClose(gzFile); 5.48 5.49 - return res; 5.50 + return pos; 5.51 + 5.52 +} 5.53 + 5.54 +bool gbWriteMemSaveState(char *memory, int available) 5.55 +{ 5.56 + long pos = gbWriteMemSaveStatePos(memory, available); 5.57 + if (pos > 0) { return true; } 5.58 + else{ return false; } 5.59 } 5.60 5.61 bool gbWriteSaveState(const char *name)
6.1 --- a/src/gb/GB.h Thu Mar 08 06:01:09 2012 -0600 6.2 +++ b/src/gb/GB.h Thu Mar 08 19:48:54 2012 -0600 6.3 @@ -51,6 +51,7 @@ 6.4 extern void storeWRam(int32 *); 6.5 extern void storeVRam(int32 *); 6.6 extern void storeRegisters(int32 *); 6.7 +extern long gbWriteMemSaveStatePos(char *, int); 6.8 6.9 extern struct EmulatedSystem GBSystem; 6.10 extern struct EmulatedSystemCounters &GBSystemCounters;