vcmibuilder 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #!/bin/bash -e
  2. #
  3. # VCMI data builder script
  4. # Extracts game data from various sources and creates a tree with the right files
  5. #
  6. # Authors: listed in file AUTHORS in main folder
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # no console arguments - print help
  14. if [ $# -eq 0 ] ; then
  15. print_help=true
  16. fi
  17. # command line parsing
  18. # can't use system getopt which is not cross-platform (BSD/Mac)
  19. # can't use built-in getopts which can't parse long options (too difficult to avoid - e.g. CD1/CD2)
  20. while [ $# -gt 0 ]
  21. do
  22. case $1 in
  23. --cd1) cd1_dir=$2 ; shift 2 ;;
  24. --cd2) cd2_dir=$2 ; shift 2 ;;
  25. --gog) gog_file=$2 ; shift 2 ;;
  26. --data) data_dir=$2 ; shift 2 ;;
  27. --dest) dest_dir=$2 ; shift 2 ;;
  28. --convertMP3) useffmpeg=true; shift 1 ;;
  29. --validate) validate=true ; shift 1 ;;
  30. *) print_help=true ; shift 1 ;;
  31. esac
  32. done
  33. if [[ -n "$print_help" ]]
  34. then
  35. echo "VCMI data builder utility"
  36. echo "Usage: vcmibuilder <options>"
  37. echo "Options:"
  38. echo " --cd1 DIRECTORY " "Path to mounted first CD with Heroes 3 install files"
  39. echo " " "Requires unshield"
  40. echo
  41. echo " --cd2 DIRECTORY " "Path to second CD with Heroes 3 data files."
  42. echo
  43. echo " --gog EXECUTABLE " "Path to gog.com executable"
  44. echo " " "Requires innoextract ( http://constexpr.org/innoextract/ )"
  45. echo
  46. echo " --data DIRECTORY " "Path to installed Heroes 3 data"
  47. echo
  48. echo " --convertMP3 " "Convert all mp3 files into ogg/vorbis"
  49. echo " " "Requires ffmpeg or avconv"
  50. echo
  51. echo " --dest DIRECTORY " "Path where resulting data will be placed. Default is ~/.local/share/vcmi"
  52. echo
  53. echo " --validate " "Run basic validness checks"
  54. exit 0
  55. fi
  56. # test if a program version ($1) is less than the required one ($2)
  57. verlt() {
  58. [ "$1" = "$2" ] && return 1 || \
  59. [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
  60. }
  61. # test presence of program $1, $2 will be passed as parameters to test presence
  62. test_utility ()
  63. {
  64. $1 $2 > /dev/null 2>&1 || { echo "$1 was not found. Please install it" 1>&2 ; exit 1; }
  65. }
  66. # print error message and exit
  67. fail ()
  68. {
  69. $2
  70. echo "$1" 1>&2
  71. rm -rf "$temp_dir"
  72. exit 1
  73. }
  74. # print warning to stderr.
  75. warning ()
  76. {
  77. echo "$1" 1>&2
  78. warn_user=true
  79. }
  80. # check if selected options are correct.
  81. if [[ -n "$data_dir" ]]
  82. then
  83. if [[ -n "$gog_file" ]] || [[ -n "$cd1_dir" ]] || [[ -n "$cd2_dir" ]]
  84. then
  85. warning "Warning: Installed data dir was specified. Both gog and cd options will be ignored"
  86. unset gog_file cd1_dir cd2_dir
  87. fi
  88. fi
  89. if [[ -n "$gog_file" ]]
  90. then
  91. test_utility "innoextract"
  92. if [[ -n "$cd1_dir" ]] || [[ -n "$cd2_dir" ]]
  93. then
  94. warning "Warning: Both gog and cd options were specified. cd options will be ignored"
  95. unset cd1_dir cd2_dir
  96. fi
  97. fi
  98. if [[ -n "$gog_file" ]]
  99. then
  100. currentver="$(innoextract --version | head -n1 | cut -d ' ' -f2)"
  101. requiredver="1.6"
  102. if verlt $currentver $requiredver;
  103. then
  104. fail "innoextract version is $currentver, update it to version $requiredver or higher"
  105. fi
  106. fi
  107. if [[ -n "$useffmpeg" ]]
  108. then
  109. ffmpeg -version > /dev/null 2>&1 && AUDIO_CONV=ffmpeg
  110. avconv -version > /dev/null 2>&1 && AUDIO_CONV=avconv
  111. if [[ -z "$AUDIO_CONV" ]]
  112. then
  113. fail "Error: neither ffmpeg nor avconv were found. Please install it."
  114. fi
  115. fi
  116. if [[ -n "$cd1_dir" ]]
  117. then
  118. test_utility "unshield" "-V"
  119. fi
  120. if [[ -z "$gog_file" ]] && [[ -z "$data_dir" ]] && ( [[ -z "$cd1_dir" ]] || [[ -z "$cd2_dir" ]] )
  121. then
  122. warning "Warning: Selected options will not create complete Heroes 3 data!"
  123. fi
  124. # if at least one warning has been printed - ask for confirmation
  125. if [[ -n "$warn_user" ]]
  126. then
  127. read -p "Do you wish to continue? (y/n) " -n 1
  128. echo #print eol
  129. if [[ ! $REPLY =~ ^[Yy]$ ]]
  130. then
  131. exit 1
  132. fi
  133. fi
  134. if [[ -z "$dest_dir" ]]
  135. then
  136. if [[ -z "$XDG_DATA_HOME" ]]
  137. then
  138. dest_dir="$HOME/.local/share/vcmi"
  139. else
  140. dest_dir="$XDG_DATA_HOME/vcmi"
  141. fi
  142. fi
  143. temp_dir="$dest_dir"/buildertmp
  144. # start installation
  145. mkdir -p "$dest_dir"
  146. mkdir -p "$temp_dir"
  147. if [[ -n "$gog_file" ]]
  148. then
  149. data_dir="$temp_dir"/gog
  150. mkdir -p "$data_dir"
  151. # innoextract always reports error (iconv 84 error). Just test file for presence
  152. test -f "$gog_file" || fail "Error: gog.com executable was not found!"
  153. gog_file="$(cd "$(dirname "$gog_file")"; pwd)/$(basename "$gog_file")"
  154. cd "$data_dir" && innoextract "$gog_file"
  155. # some versions of gog.com installer (or innoextract tool?) place game files inside /app directory
  156. if [[ -d "$data_dir"/app ]]
  157. then
  158. data_dir="$data_dir"/app
  159. fi
  160. fi
  161. if [[ -n "$cd1_dir" ]]
  162. then
  163. data_dir="$temp_dir"/cddir
  164. mkdir -p "$data_dir"
  165. unshield -d "$data_dir" x "$cd1_dir"/_setup/data1.cab || fail "Error: failed to extract from Install Shield installer!" "rm -rf $data_dir"
  166. # a bit tricky - different releases have different root directory. Move extracted files to data_dir
  167. if [ -d "$data_dir"/Heroes3 ]
  168. then
  169. mv "$data_dir"/Heroes3/* "$data_dir"
  170. elif [ -d "$data_dir""/Program_Files" ]
  171. then
  172. mv "$data_dir"/Program_Files/* "$data_dir"
  173. elif [ -d "$data_dir""/LangInde_Program_Files" ]
  174. then
  175. mv "$data_dir"/LangInde_Program_Files/* "$data_dir"
  176. else
  177. echo "Error: failed to find extracted game files!"
  178. echo "Extracted directories are: "
  179. ls -la "$data_dir"
  180. echo "Please report this on vcmi.eu"
  181. exit 1;
  182. fi
  183. fi
  184. if [[ -n "$cd2_dir" ]]
  185. then
  186. mkdir -p "$dest_dir"/Data
  187. if [ -d "$cd2_dir"/heroes3 ]
  188. then
  189. cp "$cd2_dir"/heroes3/Data/Heroes3.vid "$dest_dir"/Data/Heroes3.vid
  190. cp "$cd2_dir"/heroes3/Data/Heroes3.snd "$dest_dir"/Data/Heroes3-cd2.snd
  191. else
  192. cp "$cd2_dir"/Heroes3/Data/Heroes3.vid "$dest_dir"/Data/Heroes3.vid
  193. cp "$cd2_dir"/Heroes3/Data/Heroes3.snd "$dest_dir"/Data/Heroes3-cd2.snd
  194. fi
  195. fi
  196. if [[ -n "$data_dir" ]]
  197. then
  198. # this folder is named differently from time to time
  199. # bash also has `shopt -s nocaseglob` but we don't want this to
  200. # accidentally influence other parts of this script
  201. # since the directory names are short, we use this pattern matching
  202. cp -r "$data_dir"/[Dd][Aa][Tt][Aa] "$dest_dir"
  203. cp -r "$data_dir"/[Mm][Aa][Pp][Ss] "$dest_dir"
  204. cp -r "$data_dir"/[Mm][Pp]3 "$dest_dir"
  205. fi
  206. if [[ -n "$useffmpeg" ]]
  207. then
  208. # now when all music files were installed convert them to ogg
  209. echo "Converting mp3 files..."
  210. OIFS="$IFS"
  211. IFS=$'\n'
  212. for file in `find "$dest_dir" -type f -iname "*.mp3"`
  213. do
  214. echo "Converting $file"
  215. ogg=${file%.*}
  216. $AUDIO_CONV -y -i "$file" -acodec libvorbis "$ogg".ogg 2>/dev/null || fail "Error: failed to convert $file to ogg/vorbis using $AUDIO_CONV" "rm -f "$ogg".ogg"
  217. rm -f $file
  218. done
  219. IFS="$OIFS"
  220. fi
  221. if [[ -n "$validate" ]]
  222. then
  223. test -f "$dest_dir"/[Dd][Aa][Tt][Aa]/H3bitmap.lod || fail "Error: Heroes 3 data files are missing!"
  224. test -f "$dest_dir"/[Dd][Aa][Tt][Aa]/H3sprite.lod || fail "Error: Heroes 3 data files are missing!"
  225. test -f "$dest_dir"/[Dd][Aa][Tt][Aa]/VIDEO.VID || fail "Error: Heroes 3 data files (CD2) are missing!"
  226. #test -d "$dest_dir"/Mods/vcmi/Data || fail "Error: VCMI data files are missing!"
  227. fi
  228. rm -rf "$temp_dir"