module Game.LambdaHack.Client.Action.Save
( saveGameCli, restoreGameCli
) where
import Control.Concurrent
import qualified Control.Exception as Ex hiding (handle)
import Control.Monad
import Data.Text (Text)
import qualified Data.Text as T
import System.Directory
import System.FilePath
import System.IO.Unsafe (unsafePerformIO)
import Game.LambdaHack.Client.Config
import Game.LambdaHack.Client.State
import Game.LambdaHack.Common.Msg
import Game.LambdaHack.Common.State
import Game.LambdaHack.Utils.File
_saveLock :: MVar ()
_saveLock = unsafePerformIO newEmptyMVar
saveGameBkpCli :: String -> ConfigUI -> State -> StateClient -> IO ()
saveGameBkpCli saveName ConfigUI{configAppDataDirUI} s cli = do
let saveFile = configAppDataDirUI </> saveName
saveFileBkp = saveFile <.> ".bkp"
encodeEOF saveFile (s, cli)
renameFile saveFile saveFileBkp
saveGameCli :: String -> Bool -> ConfigUI -> State -> StateClient -> IO ()
saveGameCli saveName True configUI s cl =
saveGameBkpCli saveName configUI s cl
saveGameCli saveName False ConfigUI{configAppDataDirUI} s cli = do
let saveFile = configAppDataDirUI </> saveName
encodeEOF saveFile (s, cli)
restoreGameCli :: String -> ConfigUI -> (FilePath -> IO FilePath) -> Text
-> IO (Either (State, StateClient, Msg) Msg)
restoreGameCli saveName ConfigUI{ configAppDataDirUI
, configUICfgFile }
pathsDataFile title = do
tryCreateDir configAppDataDirUI
tryCopyDataFiles pathsDataFile
[(configUICfgFile <.> ".default", configUICfgFile <.> ".ini")]
let saveFile = configAppDataDirUI </> saveName
saveFileBkp = saveFile <.> ".bkp"
sb <- doesFileExist saveFile
bb <- doesFileExist saveFileBkp
when sb $ renameFile saveFile saveFileBkp
res <- Ex.try $
if sb
then do
(s, cli) <- strictDecodeEOF saveFileBkp
let msg = "Welcome back to" <+> title <> "."
return $ Left (s, cli, msg)
else
if bb
then do
(s, cli) <- strictDecodeEOF saveFileBkp
let msg = "No client savefile found."
<+> "Restoring from a backup savefile."
return $ Left (s, cli, msg)
else do
let msg = "Welcome to" <+> title <> "!"
return $ Right msg
let handler :: Ex.SomeException -> IO (Either (State, StateClient, Msg) Msg)
handler e = let msg = "Client restore failed. The error message is:"
<+> (T.unwords . T.lines) (showT e)
in return $ Right msg
either handler return res