Browse Source

Puzzles are now loaded from binary format

* Created PuzzleIO.cake for translating from the Decompression.cake
text format to a binary format which is easy to load on PC and
Android (especially Android). It should be much faster to load as a
side-effect of this change
* Fix bug in Main.cake where libSDL was actually resolving to the
system SDL. This happened because the executable was being relocated,
but the rpath wasn't being updated to reflect that
* Added hacky comptime-conds so Main could be included in PuzzleIO
executable without conflicting
master
Macoy Madson 3 years ago
parent
commit
fabf520157
  1. 2
      .gitignore
  2. 2
      Android/app/jni/src/Android.mk
  3. 3
      Build.sh
  4. 116
      src/Main.cake
  5. 149
      src/PuzzleIO.cake

2
.gitignore

@ -64,6 +64,7 @@ test/data/Models/*
kitty-gridlock
decompression-test
generate-puzzles
*.kra-autosave.kra
.stfolder
@ -72,6 +73,7 @@ decompression-test
# Generated from database
data/puzzles.txt
data/puzzles.bin

2
Android/app/jni/src/Android.mk

@ -12,7 +12,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include $(LOCAL_PATH)/../../../../
LOCAL_CFLAGS += -Wno-parentheses-equality
# Add your application source files here...
LOCAL_SRC_FILES := Main.cake.cpp Math.cake.cpp SDL.cake.cpp
LOCAL_SRC_FILES := Main.cake.cpp Math.cake.cpp SDL.cake.cpp PuzzleIO.cake.cpp
LOCAL_SHARED_LIBRARIES := SDL2

3
Build.sh

@ -10,7 +10,10 @@ CAKELISP=./Dependencies/cakelisp/bin/cakelisp
# After relocation, this will be able to be simply .
KITTY_DIR=../..
# These both happen by Main.cake as a pre-build step, but you can do it manually here
# Uncomment to generate data/puzzles.txt
# $CAKELISP --execute $KITTY_DIR/src/Decompression.cake || exit $?
# Uncomment to generate data/puzzles.bin
# $CAKELISP --execute $KITTY_DIR/src/PuzzleIO.cake || exit $?
$CAKELISP --execute $KITTY_DIR/src/Main.cake || exit $?

116
src/Main.cake

@ -1,5 +1,7 @@
(comptime-define-symbol 'Unix)
(comptime-define-symbol 'Kitty-Main)
(comptime-cond ('No-Kitty-Main)
(true
(comptime-define-symbol 'Kitty-Main)))
;; Until GameLib is relocatable, we will build from it; All comptime paths in this file are relative
;; to Dependencies/gamelib!
@ -11,6 +13,7 @@
"../../src")
(import "SDL.cake" "Math.cake" ;; GameLib
"PuzzleIO.cake" ;; kitty-gridlock
;; "Decompression.cake" ;; kitty-gridlock ;; Not used for runtime game
&comptime-only "Macros.cake" "BuildTools.cake") ;; cakelisp/runtime
@ -290,69 +293,13 @@
(return true))
(defstruct-local puzzle-data
(defstruct puzzle-data
num-moves char
num-states int
board ([] 36 char))
(var g-puzzle-list (* puzzle-data) null)
(var g-num-puzzles int 0)
(defun-local read-puzzles (&return bool)
(var puzzles-file (* FILE) (fopen (in-data-dir "puzzles.txt") "r"))
(unless puzzles-file
(SDL_Log "Failed to load puzzles. Did the pre-build step generate-puzzles-list fail? You can
also run Decompression.cake directly (see Build.sh)\n")
(return true))
;; 48 = max length of a single line in puzzles .txt
(var line-buffer ([] 48 char) (array 0))
(unless (fgets line-buffer (array-size line-buffer) puzzles-file)
(SDL_Log "Puzzle file malformed\n") (return false))
(var num-puzzles int (atoi line-buffer))
(SDL_Log "Reading %d puzzles\n" num-puzzles)
(when g-puzzle-list (free (type-cast g-puzzle-list (* void))))
(set g-num-puzzles num-puzzles)
(set g-puzzle-list (type-cast (calloc g-num-puzzles (sizeof (type puzzle-data))) (* puzzle-data)))
;; Read puzzles line by line
(var current-puzzle (* puzzle-data) g-puzzle-list)
(while (and (fgets line-buffer (array-size line-buffer) puzzles-file)
(< (- current-puzzle g-puzzle-list) g-num-puzzles))
(var num-moves int 0)
(var num-states int 0)
(var pieces-read bool false)
(var buffer ([] 37 char) (array 0))
(var write-char (* char) buffer)
(var current-char (* (const char)) line-buffer)
(while (deref current-char)
(cond
;; Space field delimiter
((= (deref current-char) (space-hack))
(cond
((not num-moves)
(set num-moves (atoi buffer)))
(true ;; Copy pieces
;; TODO Magic number
(memcpy (path current-puzzle > board) buffer 36)
(set pieces-read true)))
;; Reset buffer after space
(memset buffer 0 (sizeof buffer))
(set write-char buffer))
((= (deref current-char) '\n')
(break))
(true
(set (deref write-char) (deref current-char))
(incr write-char)))
(incr current-char))
(set (path current-puzzle > num-moves) num-moves)
(set num-states (atoi buffer))
(set (path current-puzzle > num-states) num-states)
(incr current-puzzle))
(fclose puzzles-file)
(return (> g-num-puzzles 0)))
(var-global g-puzzle-list (* puzzle-data) null)
(var-global g-num-puzzles int 0)
(defun-local game-piece-grid-position-to-screen-position (piece (* (const board-piece)) &return vec2)
(var piece-position vec2 (array (type-cast (vec-x (path piece > grid-position)) float)
@ -679,6 +626,7 @@
;; Main
;;
(comptime-cond ('Kitty-Main
(defun main (num-args int args ([] (* char)) &return int)
(SDL_Log "Kitty Gridlock\n\n
Created by Macoy Madson <macoy@macoy.me>.\n
@ -744,7 +692,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(sdl-print-time-delta start-load-ticks "Loading screen displayed")
(unless (read-puzzles) (return 1))
(unless (read-puzzles-binary (in-data-dir "puzzles.bin")) (return 1))
(sdl-print-time-delta start-load-ticks "Puzzles loaded")
(var background-texture (* SDL_Texture) (sdl-texture-from-bmp (in-data-dir "Board.bmp")
@ -810,8 +758,8 @@ Rush Hour database from Michael Fogleman.\n\n")
(srand (type-cast (SDL_GetPerformanceCounter) int))
(game-board-load "IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM")
;; (game-board-load-next-puzzle)
;; (game-board-load "IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM")
(game-board-load-next-puzzle)
;;
;; Game loop
@ -1074,7 +1022,8 @@ Rush Hour database from Michael Fogleman.\n\n")
(when exit-reason
(SDL_Log "Exiting. Reason: %s\n" exit-reason))
(when g-puzzle-list (free (type-cast g-puzzle-list (* void))))
(when g-puzzle-list (free (type-cast g-puzzle-list (* void)))
(set g-puzzle-list null))
(var i int 0)
(while (< i (array-size textures-to-destroy))
@ -1086,7 +1035,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(sdl-shutdown window)
(return 0))
))
;;
;; Macros and generators
;;
@ -1176,20 +1125,31 @@ Rush Hour database from Michael Fogleman.\n\n")
;;
(defun-comptime generate-puzzles-list (manager (& ModuleManager) module (* Module) &return bool)
;; Already built?
(when (fileExists "../../data/puzzles.txt")
(when (fileExists "../../data/puzzles.bin")
(Log "generate-puzzles-list: Puzzles list already built\n")
(return true))
(Log "generate-puzzles-list: Building puzzles list from database\n")
(unless (fileExists "../../data/puzzles.txt")
(Log "generate-puzzles-list: Building puzzles list from database\n")
(run-process-sequential-or
;; Note that we're still relative to Dependencies/gamelib
("./Dependencies/cakelisp/bin/cakelisp" "--execute" "../../src/Decompression.cake")
(Log "generate-puzzles-list: Failed to run Decompression for puzzle database reading\n")
(return false))
(unless (fileExists "../../data/puzzles.txt")
(Log "generate-puzzles-list: Successfully executed Decompression, but didn't find
data/puzzles.txt. Are paths incorrect?\n")
(return false)))
(run-process-sequential-or
;; Note that we're still relative to Dependencies/gamelib
("./Dependencies/cakelisp/bin/cakelisp" "--execute" "../../src/Decompression.cake")
(Log "generate-puzzles-list: Failed to run Decompression for puzzle database reading\n")
("./Dependencies/cakelisp/bin/cakelisp" "--execute" "../../src/PuzzleIO.cake")
(Log "generate-puzzles-list: Failed to run PuzzleIO for puzzle database reading\n")
(return false))
(unless (fileExists "../../data/puzzles.txt")
(Log "generate-puzzles-list: Successfully executed Decompression, but didn't find
data/puzzles.txt. Are paths incorrect?\n")
(unless (fileExists "../../data/puzzles.bin")
(Log "generate-puzzles-list: Successfully executed PuzzleIO, but didn't find
data/puzzles.bin. Are paths incorrect?\n")
(return false))
(return true))
@ -1218,13 +1178,19 @@ This tool requires rsync to be installed.\n")
(return true))
;; Order matters here, because we want to copy the generated puzzles list to android
(add-compile-time-hook-module pre-build generate-puzzles-list)
(add-compile-time-hook-module pre-build copy-src-files-to-android)
(comptime-cond
('Kitty-Main
(add-compile-time-hook-module pre-build generate-puzzles-list)
(add-compile-time-hook-module pre-build copy-src-files-to-android)))
(module-use-sdl-build-options)
(comptime-cond ('Kitty-Main
;; Note that this executable still pulls .so files from Dependencies
(set-cakelisp-option executable-output "../../kitty-gridlock")
(set-cakelisp-option executable-output "../../kitty-gridlock")))
; This ensures we still find SDL even after we've relocated the executable
(add-library-runtime-search-directory "Dependencies/gamelib/Dependencies/SDL/buildSDLBuild/lib")
;; Use build label to make it easier to find in cakelisp_cache
(add-build-config-label "Kitty")

149
src/PuzzleIO.cake

@ -0,0 +1,149 @@
(comptime-define-symbol 'Unix)
(comptime-define-symbol 'No-Kitty-Main)
(define-constant DATA_DIR "data/")
;; Until GameLib is relocatable, we will build from it; All comptime paths in this file are relative
;; to Dependencies/gamelib!
;; (add-cakelisp-search-directory "Dependencies/gamelib/src")
;; (set-cakelisp-option cakelisp-src-dir "Dependencies/gamelib/Dependencies/cakelisp/src")
;; (add-cakelisp-search-directory "Dependencies/gamelib/Dependencies/cakelisp/runtime")
(add-cakelisp-search-directory "src" "Dependencies/cakelisp/runtime"
;; kitty-gridlock src
"../../src")
(import "SDL.cake" ;; GameLib
"Main.cake" ;; kitty-gridlock
&comptime-only "Macros.cake" "BuildTools.cake") ;; cakelisp/runtime
(c-import "<stdio.h>" "<stdlib.h>"
"SDL.h" "SDL_rwops.h")
(defun-local read-puzzles-text (&return bool)
(var puzzles-file (* FILE) (fopen (in-data-dir "puzzles.txt") "r"))
(unless puzzles-file
(SDL_Log "Failed to load puzzles. Did the pre-build step generate-puzzles-list fail? You can
also run Decompression.cake directly (see Build.sh)\n")
(return true))
;; 48 = max length of a single line in puzzles .txt
(var line-buffer ([] 48 char) (array 0))
(unless (fgets line-buffer (array-size line-buffer) puzzles-file)
(SDL_Log "Puzzle file malformed\n") (return false))
(var num-puzzles int (atoi line-buffer))
(SDL_Log "Reading %d puzzles\n" num-puzzles)
(when g-puzzle-list (free (type-cast g-puzzle-list (* void))))
(set g-num-puzzles num-puzzles)
(set g-puzzle-list (type-cast (calloc g-num-puzzles (sizeof (type puzzle-data))) (* puzzle-data)))
;; Read puzzles line by line
(var current-puzzle (* puzzle-data) g-puzzle-list)
(while (and (fgets line-buffer (array-size line-buffer) puzzles-file)
(< (- current-puzzle g-puzzle-list) g-num-puzzles))
(var num-moves int 0)
(var num-states int 0)
(var pieces-read bool false)
(var buffer ([] 37 char) (array 0))
(var write-char (* char) buffer)
(var current-char (* (const char)) line-buffer)
(while (deref current-char)
(cond
;; Space field delimiter
((= (deref current-char) (space-hack))
(cond
((not num-moves)
(set num-moves (atoi buffer)))
(true ;; Copy pieces
;; TODO Magic number
(memcpy (path current-puzzle > board) buffer 36)
(set pieces-read true)))
;; Reset buffer after space
(memset buffer 0 (sizeof buffer))
(set write-char buffer))
((= (deref current-char) '\n')
(break))
(true
(set (deref write-char) (deref current-char))
(incr write-char)))
(incr current-char))
(set (path current-puzzle > num-moves) num-moves)
(set num-states (atoi buffer))
(set (path current-puzzle > num-states) num-states)
(incr current-puzzle))
(fclose puzzles-file)
(return (> g-num-puzzles 0)))
(var g-puzzle-binary-version Uint32 1)
(defun-local write-puzzles-binary (filename (* (const char)) &return bool)
(unless g-num-puzzles
(printf "No puzzles to write\n")
(return false))
(var puzzles-file (* SDL_RWops) (SDL_RWFromFile filename "w"))
(unless puzzles-file
(printf "Failed to open puzzles output file\n")
(return false))
(SDL_WriteLE32 puzzles-file g-puzzle-binary-version)
(SDL_WriteLE32 puzzles-file g-num-puzzles)
(unless (SDL_RWwrite puzzles-file g-puzzle-list (sizeof (type puzzle-data)) g-num-puzzles)
(printf "Failed to write puzzles\n")
(return false))
(SDL_RWclose puzzles-file)
(return true))
(defun read-puzzles-binary (filename (* (const char)) &return bool)
(when g-puzzle-list
(free (type-cast g-puzzle-list (* void)))
(set g-puzzle-list null))
(var puzzles-file (* SDL_RWops) (SDL_RWFromFile filename "r"))
(unless puzzles-file
(printf "Failed to open puzzles output file\n")
(return false))
(var version Uint32 (SDL_ReadLE32 puzzles-file))
(unless (= g-puzzle-binary-version version)
(printf "Version mismatch: expected %d, got %d\n" g-puzzle-binary-version version)
(return false))
(set g-num-puzzles (SDL_ReadLE32 puzzles-file))
(unless g-num-puzzles
(printf "No puzzles to read\n")
(return false))
(set g-puzzle-list (type-cast (calloc g-num-puzzles (sizeof (type puzzle-data))) (* puzzle-data)))
(unless (SDL_RWread puzzles-file g-puzzle-list (sizeof (type puzzle-data)) g-num-puzzles)
(printf "Failed to read puzzles\n")
(return false))
(SDL_RWclose puzzles-file)
(return true))
(comptime-cond
('Kitty-Main)
(true
(defun main (&return int)
(unless (read-puzzles-text) (return 1))
(unless (write-puzzles-binary (in-data-dir "puzzles.bin")) (return 1))
(unless (read-puzzles-binary (in-data-dir "puzzles.bin")) (return 1))
(return 0))))
;;
;; Building
;;
(module-use-sdl-build-options)
(add-library-runtime-search-directory "Dependencies/gamelib/Dependencies/SDL/buildSDLBuild/lib")
;; Note that this executable still pulls .so files from Dependencies
(comptime-cond
('Kitty-Main)
(true
(set-cakelisp-option executable-output "../../generate-puzzles")
;; Need a label so that our special version of Main.cake isn't used
(add-build-config-label "GeneratePuzzles")))
Loading…
Cancel
Save