Browse Source

Add recovery utility

master
Matthew Faltys 5 years ago
parent
commit
f3e30415be
  1. 1
      config.gcfg
  2. 128
      deps/nethackrc
  3. 166
      deps/nethackrc.full
  4. 1
      deps/server_config.gcfg
  5. 150
      nethack-launcher.go

1
config.gcfg

@ -4,6 +4,7 @@
nethackversion = "3.6.1" nethackversion = "3.6.1"
hackdir = "savedata/hack" hackdir = "savedata/hack"
nhdatlocation = "/usr/lib/games/nethack/nhdat" nhdatlocation = "/usr/lib/games/nethack/nhdat"
recoverbinary = "/usr/lib/games/nethack/recover"
bootstrapdelay = 1 bootstrapdelay = 1
[redis] [redis]

128
deps/nethackrc vendored

@ -2,13 +2,11 @@
# good luck escaping # good luck escaping
# jk, its vim # jk, its vim
#OPTIONS=showexp,showscore,time,color,!autopickup # standard options
#OPTIONS=autodig,fruit:slime mold,boulder:0
OPTIONS=menucolors OPTIONS=menucolors
OPTIONS=autodig OPTIONS=autodig
OPTIONS=autoopen OPTIONS=autoopen
#OPTIONS=autopickup,pickup_types:$!/="+? OPTIONS=autopickup,pickup_types:$!/="+?
OPTIONS=autoquiver OPTIONS=autoquiver
OPTIONS=bones OPTIONS=bones
OPTIONS=boulder:0 OPTIONS=boulder:0
@ -20,20 +18,23 @@ OPTIONS=hilite_pet
OPTIONS=hilite_pile OPTIONS=hilite_pile
OPTIONS=msg_window:reverse,msghistory:1000 OPTIONS=msg_window:reverse,msghistory:1000
OPTIONS=lit_corridor OPTIONS=lit_corridor
# statusbar options
OPTIONS=showrace OPTIONS=showrace
OPTIONS=showexp,time OPTIONS=showexp,time
OPTIONS=sortloot:full OPTIONS=sortloot:full
# curses interface
#OPTIONS=windowtype:curses
#OPTIONS=perm_invent
## Change symbols
SYMBOLS=S_ghost:X
SYMBOLS=S_mimic_def:m
SYMBOLS=S_water:~
SYMBOLS=S_lava:~
###
# COLORS
###
## Use status hilites ## Use status hilites
OPTIONS=statushilites OPTIONS=statushilites
# HP ## HP
OPTIONS=hitpointbar OPTIONS=hitpointbar
OPTIONS=hilite_status:hitpoints/100%/grey&normal OPTIONS=hilite_status:hitpoints/100%/grey&normal
OPTIONS=hilite_status:hitpoints/<100%/green&normal OPTIONS=hilite_status:hitpoints/<100%/green&normal
@ -59,108 +60,3 @@ OPTIONS=hilite_status:condition/stun/red&bold
OPTIONS=hilite_status:condition/termill/red&inverse OPTIONS=hilite_status:condition/termill/red&inverse
OPTIONS=hilite_status:condition/foodpois/red&inverse OPTIONS=hilite_status:condition/foodpois/red&inverse
OPTIONS=hilite_status:condition/slime/red&inverse OPTIONS=hilite_status:condition/slime/red&inverse
# Str, Con, Dex, Int, Wis, Cha
OPTIONS=hilite_status:characteristics/up/green/down/red
# gold
OPTIONS=hilite_status: gold/up/yellow/down/brown
# FORCE COLORS
MENUCOLOR="\{R\}"=red
MENUCOLOR="\{B\}"=blue
MENUCOLOR="\{C\}"=cyan
MENUCOLOR="\{G\}"=green
MENUCOLOR="\{Y\}"=yellow
MENUCOLOR="\{[MP]\}"=magenta
MENUCOLOR="\{O\}"=orange
MENUCOLOR="\{W\}"=white
MENUCOLOR="\{L\}"=black
MENUCOLOR="\{y\}"=gray
MENUCOLOR="\{g\}"=lightgreen
MENUCOLOR="\{b\}"=lightblue
MENUCOLOR="\{[mp]\}"=lightmagenta
MENUCOLOR="\{c\}"=lightcyan
# GOODIES
MENUCOLOR=" bag .* holding"=magenta
MENUCOLOR=" luck(stone)?($| )"=magenta
MENUCOLOR=" wand .* wish(ing)?($| )"=magenta
MENUCOLOR=" wand .* tele(port(ation)?)?($| )"=magenta
MENUCOLOR=" wand .* polymorph"=magenta
MENUCOLOR=" wand .* death"=magenta
MENUCOLOR=" gain level"=magenta
MENUCOLOR=" full healing"=magenta
MENUCOLOR=" magic marker"=magenta
MENUCOLOR=" magic lamp|lamp .* magic"=magenta
MENUCOLOR=" unicorn horn[^[]*$"=magenta
#this doesn't color the #enhance unicorn
MENUCOLOR=" tinning kit"=magenta
MENUCOLOR=" ring .* regen(eration)?($| )"=magenta
MENUCOLOR=" ring .* conflict"=magenta
MENUCOLOR=" ring .* (FA|free action)($| )"=magenta
MENUCOLOR=" ring .* (TC|teleport control)($| )"=magenta
MENUCOLOR=" ring .* lev(itation)?($| )"=magenta
MENUCOLOR=" scrolls? .* genocide($| )"=magenta
MENUCOLOR=" scrolls? .* charging($| )"=magenta
MENUCOLOR=" scrolls? .* identify($| )"=magenta
MENUCOLOR=" amulet .* (life ?saving|LS)($| )"=magenta
MENUCOLOR=" amulet .* ref(lection)?($| )"=magenta
MENUCOLOR=" c(o|hi)ckatrice (corpse|egg)"=magenta
MENUCOLOR=" egg .* cockatrice"=magenta
MENUCOLOR=" stethoscope"=magenta
#instruments
MENUCOLOR="tooled horn|fire horn|frost horn|horn .* (tooled|fire|frost)"=magenta
MENUCOLOR=" harp"=magenta
MENUCOLOR=" bugle"=magenta
MENUCOLOR=" flute"=magenta
# unidentified magic armor
MENUCOLOR="piece of cloth|opera cloak|ornamental cope|tattered cape"=magenta
MENUCOLOR="plumed helmet|etched helmet|crested helmet|visored helmet"=magenta
MENUCOLOR="(old|padded|riding|fencing) gloves"=magenta
MENUCOLOR="(mud|buckled|riding|snow|hiking|combat|jungle) boots"=magenta
# FOOD CONDUCTS
# vegan
MENUCOLOR="(food |cram |K-|C-)ration|gunyoki"=green&bold
MENUCOLOR="lembas wafer|melon|carrot|tins? .* spinach"=green&bold
MENUCOLOR=" oranges?( named.*)?$"=green&bold
# avoid coloring orange DSM
MENUCOLOR=" pears?( named.*)?$"=green&bold
# avoid coloring pearl rings
MENUCOLOR=" (apple|banana|kelp|eucalyptus|garlic|wolfsbane)"=green&bold
MENUCOLOR=" (slime mold|berries)"=green&bold
## YOUR FRUIT HERE
MENUCOLOR="(tins? of )?(gelatinous cube|acid blob|quivering blob)( corpse)?"=green&bold
MENUCOLOR="(tins? of )?(blue|spotted|ochre) jelly( corpse)?"=green&bold
MENUCOLOR="(tins? of )?lichen|shrieker|violet fungus|(brown|yellow|green|red) mold( corpse)?"=green&bold
# vegetarian
MENUCOLOR="egg|pancake|fortune cookie|candy bar|royal jelly|cream pie|candle"=green
MENUCOLOR="(tin of )?brown pudding|gray ooze( corpse)?"=green
# WATER SPORTS
MENUCOLOR=" holy water"=cyan&bold
MENUCOLOR=" blessed clear potion"=cyan&bold
MENUCOLOR=" blessed potions? called water"=cyan&bold
MENUCOLOR=" clear potions? named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" potions? of water named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" potions? called water named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" unholy water"=orange
MENUCOLOR=" cursed clear potion"=orange
MENUCOLOR=" cursed potions? called water"=orange
MENUCOLOR=" potions? called water named (unholy|cursed|C)($| )"=orange
# B/U/C
#MENUCOLOR="^[a-zA-Z$] - "=white #may want to enable this if regularly playing priest.. (priests don't see the 'uncursed')
MENUCOLOR=" !C"=white
MENUCOLOR=" !B"=white
MENUCOLOR=" !UC"=white
MENUCOLOR=" uncursed| UC?($| )"=white
MENUCOLOR=" \([-0-9]+:[-0-9]+\)"=white
#nethack doesn't display "uncursed" if charges are known
MENUCOLOR=" [+-][0-9]"=white
MENUCOLOR=" blessed| B($| )"=cyan
MENUCOLOR=" cursed| C($| )"=red

166
deps/nethackrc.full vendored

@ -0,0 +1,166 @@
# welcome to the real unixvoid dungeon
# good luck escaping
# jk, its vim
#OPTIONS=showexp,showscore,time,color,!autopickup
#OPTIONS=autodig,fruit:slime mold,boulder:0
OPTIONS=menucolors
OPTIONS=autodig
OPTIONS=autoopen
OPTIONS=autopickup,pickup_types:$!/="+?
OPTIONS=autoquiver
OPTIONS=bones
OPTIONS=boulder:0
OPTIONS=checkpoint
OPTIONS=color
OPTIONS=confirm
OPTIONS=dark_room
OPTIONS=hilite_pet
OPTIONS=hilite_pile
OPTIONS=msg_window:reverse,msghistory:1000
OPTIONS=lit_corridor
OPTIONS=showrace
OPTIONS=showexp,time
OPTIONS=sortloot:full
## Change symbols
SYMBOLS=S_ghost:X
SYMBOLS=S_mimic_def:m
SYMBOLS=S_water:~
SYMBOLS=S_lava:~
## Use status hilites
OPTIONS=statushilites
# HP
OPTIONS=hitpointbar
OPTIONS=hilite_status:hitpoints/100%/grey&normal
OPTIONS=hilite_status:hitpoints/<100%/green&normal
OPTIONS=hilite_status:hitpoints/<66%/yellow&normal
OPTIONS=hilite_status:hitpoints/<50%/orange&normal
OPTIONS=hilite_status:hitpoints/<33%/red&bold
OPTIONS=hilite_status:hitpoints/<15%/red&inverse
## Pw
OPTIONS=hilite_status:power/100%/grey&normal
OPTIONS=hilite_status:power/<100%/green&normal
OPTIONS=hilite_status:power/<66%/yellow&normal
OPTIONS=hilite_status:power/<50%/orange&normal
OPTIONS=hilite_status:power/<33%/red&bold
## Carry
OPTIONS=hilite_status:cap/burdened/yellow/stressed/orange/strained/red&bold/overtaxed/red&inverse/overloaded/red&inverse&blink
## Hunger
OPTIONS=hilite_status:hunger/satiated/yellow/hungry/orange/weak/red&bold/fainting/red&inverse/fainted/red&inverse&blink
## Mental
OPTIONS=hilite_status:condition/hallu/yellow
OPTIONS=hilite_status:condition/conf/orange
OPTIONS=hilite_status:condition/stun/red&bold
## Health
OPTIONS=hilite_status:condition/termill/red&inverse
OPTIONS=hilite_status:condition/foodpois/red&inverse
OPTIONS=hilite_status:condition/slime/red&inverse
# Str, Con, Dex, Int, Wis, Cha
OPTIONS=hilite_status:characteristics/up/green/down/red
# gold
OPTIONS=hilite_status: gold/up/yellow/down/brown
# FORCE COLORS
MENUCOLOR="\{R\}"=red
MENUCOLOR="\{B\}"=blue
MENUCOLOR="\{C\}"=cyan
MENUCOLOR="\{G\}"=green
MENUCOLOR="\{Y\}"=yellow
MENUCOLOR="\{[MP]\}"=magenta
MENUCOLOR="\{O\}"=orange
MENUCOLOR="\{W\}"=white
MENUCOLOR="\{L\}"=black
MENUCOLOR="\{y\}"=gray
MENUCOLOR="\{g\}"=lightgreen
MENUCOLOR="\{b\}"=lightblue
MENUCOLOR="\{[mp]\}"=lightmagenta
MENUCOLOR="\{c\}"=lightcyan
# GOODIES
MENUCOLOR=" bag .* holding"=magenta
MENUCOLOR=" luck(stone)?($| )"=magenta
MENUCOLOR=" wand .* wish(ing)?($| )"=magenta
MENUCOLOR=" wand .* tele(port(ation)?)?($| )"=magenta
MENUCOLOR=" wand .* polymorph"=magenta
MENUCOLOR=" wand .* death"=magenta
MENUCOLOR=" gain level"=magenta
MENUCOLOR=" full healing"=magenta
MENUCOLOR=" magic marker"=magenta
MENUCOLOR=" magic lamp|lamp .* magic"=magenta
MENUCOLOR=" unicorn horn[^[]*$"=magenta
#this doesn't color the #enhance unicorn
MENUCOLOR=" tinning kit"=magenta
MENUCOLOR=" ring .* regen(eration)?($| )"=magenta
MENUCOLOR=" ring .* conflict"=magenta
MENUCOLOR=" ring .* (FA|free action)($| )"=magenta
MENUCOLOR=" ring .* (TC|teleport control)($| )"=magenta
MENUCOLOR=" ring .* lev(itation)?($| )"=magenta
MENUCOLOR=" scrolls? .* genocide($| )"=magenta
MENUCOLOR=" scrolls? .* charging($| )"=magenta
MENUCOLOR=" scrolls? .* identify($| )"=magenta
MENUCOLOR=" amulet .* (life ?saving|LS)($| )"=magenta
MENUCOLOR=" amulet .* ref(lection)?($| )"=magenta
MENUCOLOR=" c(o|hi)ckatrice (corpse|egg)"=magenta
MENUCOLOR=" egg .* cockatrice"=magenta
MENUCOLOR=" stethoscope"=magenta
#instruments
MENUCOLOR="tooled horn|fire horn|frost horn|horn .* (tooled|fire|frost)"=magenta
MENUCOLOR=" harp"=magenta
MENUCOLOR=" bugle"=magenta
MENUCOLOR=" flute"=magenta
# unidentified magic armor
MENUCOLOR="piece of cloth|opera cloak|ornamental cope|tattered cape"=magenta
MENUCOLOR="plumed helmet|etched helmet|crested helmet|visored helmet"=magenta
MENUCOLOR="(old|padded|riding|fencing) gloves"=magenta
MENUCOLOR="(mud|buckled|riding|snow|hiking|combat|jungle) boots"=magenta
# FOOD CONDUCTS
# vegan
MENUCOLOR="(food |cram |K-|C-)ration|gunyoki"=green&bold
MENUCOLOR="lembas wafer|melon|carrot|tins? .* spinach"=green&bold
MENUCOLOR=" oranges?( named.*)?$"=green&bold
# avoid coloring orange DSM
MENUCOLOR=" pears?( named.*)?$"=green&bold
# avoid coloring pearl rings
MENUCOLOR=" (apple|banana|kelp|eucalyptus|garlic|wolfsbane)"=green&bold
MENUCOLOR=" (slime mold|berries)"=green&bold
## YOUR FRUIT HERE
MENUCOLOR="(tins? of )?(gelatinous cube|acid blob|quivering blob)( corpse)?"=green&bold
MENUCOLOR="(tins? of )?(blue|spotted|ochre) jelly( corpse)?"=green&bold
MENUCOLOR="(tins? of )?lichen|shrieker|violet fungus|(brown|yellow|green|red) mold( corpse)?"=green&bold
# vegetarian
MENUCOLOR="egg|pancake|fortune cookie|candy bar|royal jelly|cream pie|candle"=green
MENUCOLOR="(tin of )?brown pudding|gray ooze( corpse)?"=green
# WATER SPORTS
MENUCOLOR=" holy water"=cyan&bold
MENUCOLOR=" blessed clear potion"=cyan&bold
MENUCOLOR=" blessed potions? called water"=cyan&bold
MENUCOLOR=" clear potions? named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" potions? of water named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" potions? called water named (holy|blessed|B)($| )"=cyan&bold
MENUCOLOR=" unholy water"=orange
MENUCOLOR=" cursed clear potion"=orange
MENUCOLOR=" cursed potions? called water"=orange
MENUCOLOR=" potions? called water named (unholy|cursed|C)($| )"=orange
# B/U/C
#MENUCOLOR="^[a-zA-Z$] - "=white #may want to enable this if regularly playing priest.. (priests don't see the 'uncursed')
MENUCOLOR=" !C"=white
MENUCOLOR=" !B"=white
MENUCOLOR=" !UC"=white
MENUCOLOR=" uncursed| UC?($| )"=white
MENUCOLOR=" \([-0-9]+:[-0-9]+\)"=white
#nethack doesn't display "uncursed" if charges are known
MENUCOLOR=" [+-][0-9]"=white
MENUCOLOR=" blessed| B($| )"=cyan
MENUCOLOR=" cursed| C($| )"=red

1
deps/server_config.gcfg vendored

@ -4,6 +4,7 @@
nethackversion = "3.6.1" nethackversion = "3.6.1"
hackdir = "/hack" hackdir = "/hack"
nhdatlocation = "/usr/lib/games/nethack/nhdat" nhdatlocation = "/usr/lib/games/nethack/nhdat"
recoverbinary = "/usr/lib/games/nethack/recover"
bootstrapdelay = 1 bootstrapdelay = 1
[redis] [redis]

150
nethack-launcher.go

@ -1,14 +1,15 @@
package main package main
// TODO make poll time faster // TODO split up into multiple files
// TODO password redo field
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -26,6 +27,7 @@ type Config struct {
NethackVersion string NethackVersion string
HackDir string HackDir string
NhdatLocation string NhdatLocation string
RecoverBinary string
BootstrapDelay time.Duration BootstrapDelay time.Duration
} }
@ -167,6 +169,7 @@ func printUserScreen(redisClient *redis.Client, username string) string {
println(" w) Watch games in progress") println(" w) Watch games in progress")
println(" h) View highscores") println(" h) View highscores")
println(" e) Edit config") println(" e) Edit config")
println(" r) Recover from crash")
fmt.Printf(" p) Play NetHack %s\n", config.NethackLauncher.NethackVersion) fmt.Printf(" p) Play NetHack %s\n", config.NethackLauncher.NethackVersion)
println(" q) Quit") println(" q) Quit")
println("") println("")
@ -215,6 +218,9 @@ func printUserScreen(redisClient *redis.Client, username string) string {
wg.Wait() wg.Wait()
close(watcher) close(watcher)
printUserScreen(redisClient, username) printUserScreen(redisClient, username)
case "r":
clearScreen()
recoverSave(redisClient, username)
case "q": case "q":
exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run() exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run()
clearScreen() clearScreen()
@ -348,6 +354,9 @@ func printRegisterScreen(redisClient *redis.Client) {
hackRCDest := fmt.Sprintf("%s/user/%s/.nethackrc", config.NethackLauncher.HackDir, username) hackRCDest := fmt.Sprintf("%s/user/%s/.nethackrc", config.NethackLauncher.HackDir, username)
exec.Command("cp", hackRCLoc, hackRCDest).Run() exec.Command("cp", hackRCLoc, hackRCDest).Run()
// TODO: move the above creation code into the createUserFiles() function
createUserFiles(username)
// back to main screen // back to main screen
printUserScreen(redisClient, username) printUserScreen(redisClient, username)
} }
@ -515,7 +524,7 @@ func runGame(username, timestamp string) {
nh.Env = os.Environ() nh.Env = os.Environ()
nh.Env = append(nh.Env, fmt.Sprintf("HOME=%s", homeDir)) nh.Env = append(nh.Env, fmt.Sprintf("HOME=%s", homeDir))
nh.Env = append(nh.Env, fmt.Sprintf("USER=%s", username)) nh.Env = append(nh.Env, fmt.Sprintf("USER=%s", username))
nh.Env = append(nh.Env, fmt.Sprintf("NETHACKDIR=%s", config.NethackLauncher.HackDir)) nh.Env = append(nh.Env, fmt.Sprintf("NETHACKDIR=%s/user/%s", config.NethackLauncher.HackDir, username))
nh.Stdout = os.Stdout nh.Stdout = os.Stdout
nh.Stdin = os.Stdin nh.Stdin = os.Stdin
nh.Stderr = os.Stderr nh.Stderr = os.Stderr
@ -590,6 +599,141 @@ func createInitialFiles() {
} }
} }
func createUserFiles(username string) {
// create necessary directories if they dont exist
userpath := fmt.Sprintf("%s/user/%s", config.NethackLauncher.HackDir, username)
if _, err := os.Stat(fmt.Sprintf("%s/dumps/", userpath)); os.IsNotExist(err) {
os.Mkdir(fmt.Sprintf("%s/dumps/", userpath), os.ModeDir)
}
if _, err := os.Stat(fmt.Sprintf("%s/save/", userpath)); os.IsNotExist(err) {
os.Mkdir(fmt.Sprintf("%s/save/", userpath), os.ModeDir)
}
// create necessary files if they dont exist
os.OpenFile(fmt.Sprintf("%s/logfile", userpath), os.O_RDONLY|os.O_CREATE, 0666)
os.OpenFile(fmt.Sprintf("%s/perm", userpath), os.O_RDONLY|os.O_CREATE, 0666)
os.OpenFile(fmt.Sprintf("%s/record", userpath), os.O_RDONLY|os.O_CREATE, 0666)
os.OpenFile(fmt.Sprintf("%s/xlogfile", userpath), os.O_RDONLY|os.O_CREATE, 0666)
// move in nhdat file if it does not exist
exec.Command("cp", config.NethackLauncher.NhdatLocation, userpath).Run()
}
func recoverSave(redisClient *redis.Client, username string) {
// if no statefile exist, exit early as we cannot recover
matches, _ := filepath.Glob(fmt.Sprintf("%s/user/%s/*lock*", config.NethackLauncher.HackDir, username))
if matches == nil {
fmt.Printf(" %s\n", config.NethackLauncher.ServerDisplay)
println("")
println(" The dungeon crumbles around you, darkness remains...")
println(" Godspeed adventurer..")
println("")
println(" No statefiles exist. (press enter to return)")
println("")
fmt.Printf(">> ")
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if scanner.Text() == "" {
printUserScreen(redisClient, username)
}
}
}
fmt.Printf(" %s\n", config.NethackLauncher.ServerDisplay)
println("")
println(" Recover utilty.")
println("")
// check if dir is empty
isEmpty, _ := checkDir(fmt.Sprintf("%s/user/%s/save/", config.NethackLauncher.HackDir, username))
if !isEmpty {
// save file exists, overwrite?
println(" Save file already exists!")
println(" Overwrite? (y/n)")
println("")
fmt.Printf(">> ")
} else {
println(" Attempt to recovery statefile? (y/n)")
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()
printUserScreen(redisClient, username)
case "y":
// 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, ".")
//fmt.Printf("recover string: %s -d %s/user/%s %s", config.NethackLauncher.RecoverBinary, config.NethackLauncher.HackDir, username, latestFile[0])
// 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(">> ")
}
case "\n":
clearScreen()
printUserScreen(redisClient, username)
default:
}
}
}
func janitor(redisClient *redis.Client) { func janitor(redisClient *redis.Client) {
// loop through the set // loop through the set
for { for {

Loading…
Cancel
Save