diff --git a/nethack-launcher/run_game.go b/nethack-launcher/run_game.go index 0bf7c73..9ccb9a2 100644 --- a/nethack-launcher/run_game.go +++ b/nethack-launcher/run_game.go @@ -2,11 +2,21 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" + "path/filepath" + "strings" ) func runGame(username, timestamp string) { + // check if a lockfile exists + matches, _ := filepath.Glob(fmt.Sprintf("%s/user/%s/*lock*", config.NethackLauncher.HackDir, username)) + if matches != nil { + clearScreen() + runtimeRecover(username) + } + exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run() clearScreen() @@ -29,3 +39,101 @@ func runGame(username, timestamp string) { exec.Command("exit").Run() wg.Done() } + +func runtimeRecover(username string) { + fmt.Printf(" %s\n", config.NethackLauncher.ServerDisplay) + println("") + println(" Existing lockfile found.") + println(" This generally means that your last session crashed") + println(" or you are logged in more than once.") + println("") + println(" What would you like to do with the lockfile?") + println(" d) delete it and contiue to a new adventure") + println(" r) recover it and continue your last adventure") + println(" n) nothing at all and get this prompt again next time") + println("") + fmt.Printf(">> ") + + // disable input buffering + exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run() + // do not display entered characters on the screen + exec.Command("stty", "-F", "/dev/tty", "-echo").Run() + + var b []byte = make([]byte, 1) + for { + os.Stdin.Read(b) + switch string(b) { + case "n": + clearScreen() + return + case "r": + // set user path to save file candidates + userPath := fmt.Sprintf("%s/user/%s/", config.NethackLauncher.HackDir, username) + + // read in all files + candidates, err := ioutil.ReadDir(userPath) + if err != nil { + fmt.Println(err) + } + var newestFile string + var newestTime int64 = 0 + for _, f := range candidates { + // loop through save file candidates + if strings.Contains(f.Name(), "lock") { + fi, err := os.Stat(userPath + f.Name()) + if err != nil { + fmt.Println(err) + } + currTime := fi.ModTime().Unix() + if currTime > newestTime { + newestTime = currTime + newestFile = f.Name() + } + } + } + + // get prefix for latest file + latestFile := strings.Split(newestFile, ".") + + // run recover on file + out, err := exec.Command(config.NethackLauncher.RecoverBinary, "-d", fmt.Sprintf("%s/user/%s", config.NethackLauncher.HackDir, username), latestFile[0]).Output() + if err != nil { + fmt.Println(out) + panic(err) + } + + // make sure save file exists before removing the extra locks + isEmpty, _ := checkDir(fmt.Sprintf("%s/user/%s/save/", config.NethackLauncher.HackDir, username)) + if !isEmpty { + // save file made it, clean up old cruft + files, err := filepath.Glob(fmt.Sprintf("%s/*lock*", userPath)) + if err != nil { + panic(err) + } + for _, f := range files { + if err := os.Remove(f); err != nil { + panic(err) + } + } + // alert user that the save file was recovered + println("") + println(" Statefile was recovered successfully! (press enter to return)") + fmt.Printf(">> ") + } + return + case "d": + // remove all lockfiles and continue + userPath := fmt.Sprintf("%s/user/%s/", config.NethackLauncher.HackDir, username) + files, err := filepath.Glob(fmt.Sprintf("%s/*lock*", userPath)) + if err != nil { + panic(err) + } + for _, f := range files { + if err := os.Remove(f); err != nil { + panic(err) + } + } + return + } + } +}