1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
|
{-# LANGUAGE ApplicativeDo #-}
-- | Parsing of commandline arguments.
module Game.LambdaHack.Server.Commandline
( serverOptionsPI
#ifdef EXPOSE_INTERNAL
-- * Internal operations
, serverOptionsP
-- other internal operations too numerous and changing, so not listed
#endif
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
-- Cabal
import qualified Paths_LambdaHack as Self (version)
import qualified Data.Text as T
import Data.Version
import Options.Applicative
import qualified System.Random.SplitMix32 as SM
-- Dependence on ClientOptions is an anomaly. Instead, probably the raw
-- remaining commandline should be passed and parsed by the client to extract
-- client and ui options from and singnal an error if anything was left.
import Game.LambdaHack.Common.ClientOptions
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Content.ModeKind
import Game.LambdaHack.Definition.Defs
import qualified Game.LambdaHack.Definition.DefsInternal as DefsInternal
import Game.LambdaHack.Server.ServerOptions
-- | Parser for server options from commandline arguments.
serverOptionsPI :: ParserInfo ServerOptions
serverOptionsPI = info (serverOptionsP <**> helper <**> version)
$ fullDesc
<> progDesc "Configure debug options here, gameplay options in configuration file."
version :: Parser (a -> a)
version = infoOption (showVersion Self.version)
(long "version"
<> help "Print engine version information")
serverOptionsP :: Parser ServerOptions
serverOptionsP = do
~(snewGameSer, scurChalSer)
<- serToChallenge <$> newGameP
sfullscreenMode <- fullscreenModeP
knowMap <- knowMapP
knowEvents <- knowEventsP
knowItems <- knowItemsP
showItemSamples <- showItemSamplesP
sexposePlaces <- exposePlacesP
sexposeItems <- exposeItemsP
sexposeActors <- exposeActorsP
sniff <- sniffP
sallClear <- allClearP
sboostRandomItem <- boostRandItemP
sgameMode <- gameModeP
sautomateAll <- automateAllP
skeepAutomated <- keepAutomatedP
sstopAfterSeconds <- stopAfterSecsP
sstopAfterFrames <- stopAfterFramesP
sstopAfterGameOver <- stopAfterGameOverP
sprintEachScreen <- printEachScreenP
sbenchmark <- benchmarkP
sbenchMessages <- benchMessagesP
sdungeonRng <- setDungeonRngP
smainRng <- setMainRngP
sdumpInitRngs <- dumpInitRngsP
sdbgMsgCli <- dbgMsgCliP
sdbgMsgSer <- dbgMsgSerP
slogPriority <- logPriorityP
sassertExplored <- assertExploredP
schosenFontset <- chosenFontsetP
sallFontsScale <- allFontsScaleP
smaxFps <- maxFpsP
sdisableAutoYes <- disableAutoYesP
snoAnim <- noAnimP
ssavePrefixSer <- savePrefixP
sfrontendANSI <- frontendANSIP
sfrontendTeletype <- frontendTeletypeP
sfrontendNull <- frontendNullP
sfrontendLazy <- frontendLazyP
pure ServerOptions
{
sclientOptions = ClientOptions
{ sfonts = [] -- comes only from config file
, sfontsets = [] -- comes only from config file
, stitle = Nothing
, snewGameCli = snewGameSer
, ssavePrefixCli = ssavePrefixSer
, ..
}
, sknowMap = knowMap || knowEvents || knowItems
, sknowEvents = knowEvents || knowItems
, sknowItems = knowItems
, sshowItemSamples = not (knowEvents || knowItems) && showItemSamples
, ..
}
where
serToChallenge :: Maybe Int -> (Bool, Challenge)
serToChallenge Nothing = (False, defaultChallenge)
serToChallenge (Just cdiff) = (True, defaultChallenge {cdiff})
knowMapP :: Parser Bool
knowMapP =
switch ( long "knowMap"
<> help "Reveal map for all clients in the next game" )
knowEventsP :: Parser Bool
knowEventsP =
switch ( long "knowEvents"
<> help "Show all events in the next game (implies --knowMap)" )
knowItemsP :: Parser Bool
knowItemsP =
switch ( long "knowItems"
<> help "Auto-identify all items in the next game (implies --knowEvents)" )
exposePlacesP :: Parser Bool
exposePlacesP =
switch ( long "exposePlaces"
<> help "Expose all possible places in the next game" )
exposeItemsP :: Parser Bool
exposeItemsP =
switch ( long "exposeItems"
<> help "Expose all possible items in the next game" )
exposeActorsP :: Parser Bool
exposeActorsP =
switch ( long "exposeActors"
<> help "Expose all killable actors in the next game" )
showItemSamplesP :: Parser Bool
showItemSamplesP =
switch ( long "showItemSamples"
<> help "At game over show samples of all items (--knowEvents disables this)" )
sniffP :: Parser Bool
sniffP =
switch ( long "sniff"
<> help "Monitor all trafic between server and clients" )
allClearP :: Parser Bool
allClearP =
switch ( long "allClear"
<> help "Let all map tiles be translucent" )
boostRandItemP :: Parser Bool
boostRandItemP =
switch ( long "boostRandomItem"
<> help "Pick a random item and make it very common" )
gameModeP :: Parser (Maybe (GroupName ModeKind))
gameModeP = optional $ toGameMode <$>
option nonEmptyStr
( long "gameMode"
<> metavar "MODE"
<> help "Start next game in the scenario indicated by MODE" )
where
-- This ignores all but the first word of a game mode name
-- and assumes the fist word is present among its frequencies.
toGameMode :: String -> GroupName ModeKind
toGameMode = DefsInternal.GroupName . head . T.words . T.pack
nonEmptyStr :: ReadM String
nonEmptyStr = eitherReader $ \case
"" -> Left "name of game mode cannot be empty"
ns -> Right ns
automateAllP :: Parser Bool
automateAllP =
switch ( long "automateAll"
<> help "Give control of all UI teams to computer" )
keepAutomatedP :: Parser Bool
keepAutomatedP =
switch ( long "keepAutomated"
<> help "Keep factions automated after game over" )
newGameP :: Parser (Maybe Int)
newGameP = optional $ max 1 . min difficultyBound <$>
option auto ( long "newGame"
<> help "Start a new game, overwriting the save file and often forgetting history, with difficulty for all UI players set to N"
<> metavar "N" )
fullscreenModeP :: Parser (Maybe FullscreenMode)
fullscreenModeP = optional $
option auto ( long "fullscreenMode"
<> short 'f'
<> metavar "MODE"
<> help "Display in MODE, one of NotFullscreen (default), BigBorderlessWindow (preferred), ModeChange" )
stopAfterSecsP :: Parser (Maybe Int)
stopAfterSecsP = optional $ max 0 <$>
option auto ( long "stopAfterSeconds"
<> help "Exit game session after around N seconds"
<> metavar "N" )
stopAfterFramesP :: Parser (Maybe Int)
stopAfterFramesP = optional $ max 0 <$>
option auto ( long "stopAfterFrames"
<> help "Exit game session after around N frames"
<> metavar "N" )
stopAfterGameOverP :: Parser Bool
stopAfterGameOverP =
switch ( long "stopAfterGameOver"
<> help "Exit the application after game over" )
printEachScreenP :: Parser Bool
printEachScreenP =
switch ( long "printEachScreen"
<> help "Take a screenshot of each rendered distinct frame (SDL only)" )
benchmarkP :: Parser Bool
benchmarkP =
switch ( long "benchmark"
<> help "Restrict file IO, print timing stats" )
benchMessagesP :: Parser Bool
benchMessagesP =
switch ( long "benchMessages"
<> help "Display messages in realistic was under AI control (for benchmarks)" )
setDungeonRngP :: Parser (Maybe SM.SMGen)
setDungeonRngP = optional $
option auto ( long "setDungeonRng"
<> metavar "RNG_SEED"
<> help "Set dungeon generation RNG seed to string RNG_SEED" )
setMainRngP :: Parser (Maybe SM.SMGen)
setMainRngP = optional $
option auto ( long "setMainRng"
<> metavar "RNG_SEED"
<> help "Set the main game RNG seed to string RNG_SEED" )
dumpInitRngsP :: Parser Bool
dumpInitRngsP =
switch ( long "dumpInitRngs"
<> help "Dump the RNG seeds used to initialize the game" )
dbgMsgCliP :: Parser Bool
dbgMsgCliP =
switch ( long "dbgMsgCli"
<> help "Emit extra internal client debug messages" )
dbgMsgSerP :: Parser Bool
dbgMsgSerP =
switch ( long "dbgMsgSer"
<> help "Emit extra internal server debug messages" )
logPriorityP :: Parser (Maybe Int)
logPriorityP = optional $
option (auto >>= verifyLogPriority) $
long "logPriority"
<> showDefault
<> value 5
<> metavar "N"
<> help ( "Log only messages of priority at least N, where 1 (all) is "
++ "the lowest and 5 logs errors only; use value 0 for testing on "
++ "CIs without graphics access; setting priority to 0 causes "
++ "SDL frontend to init and quit at once" )
where
verifyLogPriority n =
if n >= 0 && n <= 5
then return n
else readerError "N has to be 0 or a positive integer not larger than 5"
assertExploredP :: Parser (Maybe Int)
assertExploredP = optional $ max 1 <$>
option auto ( long "assertExplored"
<> help "Check that when the session ends, the indicated level has been explored"
<> metavar "N" )
chosenFontsetP :: Parser (Maybe Text)
chosenFontsetP = optional $ T.pack <$>
strOption ( long "fontset"
<> metavar "FONTSET_ID"
<> help "Render UI using the given fontset from config file" )
allFontsScaleP :: Parser (Maybe Double)
allFontsScaleP = optional $ max 0 <$>
option auto ( long "allFontsScale"
<> metavar "D"
<> help "Scale all fonts by D, resizing the whole UI" )
maxFpsP :: Parser (Maybe Double)
maxFpsP = optional $ max 0 <$>
option auto ( long "maxFps"
<> metavar "D"
<> help "Display at most D frames per second" )
disableAutoYesP :: Parser Bool
disableAutoYesP =
switch ( long "disableAutoYes"
<> help "Never auto-answer prompts, not even when UI faction is automated" )
noAnimP :: Parser (Maybe Bool)
noAnimP =
flag Nothing (Just True)
( long "noAnim"
<> help "Don't show any animations" )
savePrefixP :: Parser String
savePrefixP =
strOption ( long "savePrefix"
<> metavar "PREFIX"
<> showDefault
<> value ""
<> help "Prepend PREFIX to all savefile names" )
frontendANSIP :: Parser Bool
frontendANSIP =
switch ( long "frontendANSI"
<> help "Use the ANSI terminal frontend (best for screen readers)" )
frontendTeletypeP :: Parser Bool
frontendTeletypeP =
switch ( long "frontendTeletype"
<> help "Use the line terminal frontend (for tests)" )
frontendNullP :: Parser Bool
frontendNullP =
switch ( long "frontendNull"
<> help "Use frontend with no display (for benchmarks)" )
frontendLazyP :: Parser Bool
frontendLazyP =
switch ( long "frontendLazy"
<> help "Use frontend that not even computes frames (for benchmarks)" )
|