Safe Haskell | None |
---|---|
Language | Haskell2010 |
Atomic game state transformations, their representation and semantics.
See https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture.
Synopsis
- data CmdAtomic
- data UpdAtomic
- = UpdCreateActor ActorId Actor [(ItemId, Item)]
- | UpdDestroyActor ActorId Actor [(ItemId, Item)]
- | UpdCreateItem ItemId Item ItemQuant Container
- | UpdDestroyItem ItemId Item ItemQuant Container
- | UpdSpotActor ActorId Actor [(ItemId, Item)]
- | UpdLoseActor ActorId Actor [(ItemId, Item)]
- | UpdSpotItem Bool ItemId Item ItemQuant Container
- | UpdLoseItem Bool ItemId Item ItemQuant Container
- | UpdSpotItemBag Container ItemBag [(ItemId, Item)]
- | UpdLoseItemBag Container ItemBag [(ItemId, Item)]
- | UpdMoveActor ActorId Point Point
- | UpdWaitActor ActorId Bool
- | UpdDisplaceActor ActorId ActorId
- | UpdMoveItem ItemId Int ActorId CStore CStore
- | UpdRefillHP ActorId Int64
- | UpdRefillCalm ActorId Int64
- | UpdTrajectory ActorId (Maybe ([Vector], Speed)) (Maybe ([Vector], Speed))
- | UpdQuitFaction FactionId (Maybe Status) (Maybe Status)
- | UpdLeadFaction FactionId (Maybe ActorId) (Maybe ActorId)
- | UpdDiplFaction FactionId FactionId Diplomacy Diplomacy
- | UpdTacticFaction FactionId Tactic Tactic
- | UpdAutoFaction FactionId Bool
- | UpdRecordKill ActorId (ContentId ItemKind) Int
- | UpdAlterTile LevelId Point (ContentId TileKind) (ContentId TileKind)
- | UpdAlterExplorable LevelId Int
- | UpdAlterGold Int
- | UpdSearchTile ActorId Point (ContentId TileKind)
- | UpdHideTile ActorId Point (ContentId TileKind)
- | UpdSpotTile LevelId [(Point, ContentId TileKind)]
- | UpdLoseTile LevelId [(Point, ContentId TileKind)]
- | UpdAlterSmell LevelId Point Time Time
- | UpdSpotSmell LevelId [(Point, Time)]
- | UpdLoseSmell LevelId [(Point, Time)]
- | UpdTimeItem ItemId Container ItemTimer ItemTimer
- | UpdAgeGame [LevelId]
- | UpdUnAgeGame [LevelId]
- | UpdDiscover Container ItemId (ContentId ItemKind) ItemSeed
- | UpdCover Container ItemId (ContentId ItemKind) ItemSeed
- | UpdDiscoverKind Container ItemKindIx (ContentId ItemKind)
- | UpdCoverKind Container ItemKindIx (ContentId ItemKind)
- | UpdDiscoverSeed Container ItemId ItemSeed
- | UpdCoverSeed Container ItemId ItemSeed
- | UpdDiscoverServer ItemId AspectRecord
- | UpdCoverServer ItemId AspectRecord
- | UpdPerception LevelId Perception Perception
- | UpdRestart FactionId PerLid State Challenge ClientOptions
- | UpdRestartServer State
- | UpdResume FactionId PerLid
- | UpdResumeServer State
- | UpdKillExit FactionId
- | UpdWriteSave
- data SfxAtomic
- = SfxStrike ActorId ActorId ItemId CStore
- | SfxRecoil ActorId ActorId ItemId CStore
- | SfxSteal ActorId ActorId ItemId CStore
- | SfxRelease ActorId ActorId ItemId CStore
- | SfxProject ActorId ItemId CStore
- | SfxReceive ActorId ItemId CStore
- | SfxApply ActorId ItemId CStore
- | SfxCheck ActorId ItemId CStore
- | SfxTrigger ActorId Point
- | SfxShun ActorId Point
- | SfxEffect FactionId ActorId Effect Int64
- | SfxMsgFid FactionId SfxMsg
- | SfxSortSlots
- | SfxCollideTile ActorId Point
- data SfxMsg
- = SfxUnexpected ReqFailure
- | SfxExpected Text ReqFailure
- | SfxLoudUpd Bool UpdAtomic
- | SfxLoudStrike Bool (ContentId ItemKind) Int
- | SfxLoudSummon Bool (GroupName ItemKind) Dice
- | SfxFizzles
- | SfxNothingHappens
- | SfxVoidDetection DetectKind
- | SfxUnimpressed ActorId
- | SfxSummonLackCalm ActorId
- | SfxLevelNoMore
- | SfxLevelPushed
- | SfxBracedImmune ActorId
- | SfxEscapeImpossible
- | SfxStasisProtects
- | SfxTransImpossible
- | SfxIdentifyNothing
- | SfxPurposeNothing CStore
- | SfxPurposeTooFew Int Int
- | SfxPurposeUnique
- | SfxPurposeNotCommon
- | SfxColdFish
- | SfxTimerExtended LevelId ActorId ItemId CStore
- | SfxCollideActor LevelId ActorId ActorId
- handleUpdAtomic :: MonadStateWrite m => UpdAtomic -> m ()
- data PosAtomic
- posUpdAtomic :: MonadStateRead m => UpdAtomic -> m PosAtomic
- posSfxAtomic :: MonadStateRead m => SfxAtomic -> m PosAtomic
- breakUpdAtomic :: MonadStateRead m => UpdAtomic -> m [UpdAtomic]
- seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool
- seenAtomicSer :: PosAtomic -> Bool
- class MonadStateRead m => MonadStateWrite m where
- newtype AtomicFail = AtomicFail String
- putState :: MonadStateWrite m => State -> m ()
Re-exported from Game.LambdaHack.Atomic.CmdAtomic
Abstract syntax of atomic commands, that is, atomic game state transformations.
Instances
Eq CmdAtomic Source # | |
Show CmdAtomic Source # | |
Generic CmdAtomic Source # | |
Binary CmdAtomic Source # | |
type Rep CmdAtomic Source # | |
Defined in Game.LambdaHack.Atomic.CmdAtomic type Rep CmdAtomic = D1 (MetaData "CmdAtomic" "Game.LambdaHack.Atomic.CmdAtomic" "LambdaHack-0.8.1.2-9Fmfvbfsr9xEInnejydwaW" False) (C1 (MetaCons "UpdAtomic" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedStrict) (Rec0 UpdAtomic)) :+: C1 (MetaCons "SfxAtomic" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedStrict) (Rec0 SfxAtomic))) |
Abstract syntax of atomic updates, that is, atomic commands
that really change the State
. Most of them are an encoding of a game
state diff, though they also carry some intentional hints
that help clients determine whether and how to communicate it to players.
Instances
Abstract syntax of atomic special effects, that is, atomic commands
that only display special effects and don't change State
.
Instances
Symbolic representation of text messages sent by server to clients and shown to players.
Instances
Re-exported from Game.LambdaHack.Atomic.HandleAtomicWrite
handleUpdAtomic :: MonadStateWrite m => UpdAtomic -> m () Source #
The game-state semantics of atomic game commands.
There is no corresponding definition for special effects (SfxAtomic
),
because they don't modify State
.
For each of the commands, we are guaranteed that the client,
the command is addressed to, perceives all the positions the command
affects (as computed by posUpdAtomic
).
In the code for each semantic function we additonally verify
the client is aware of any relevant items and/or actors and we throw
the AtomicFail
exception if it's not.
The server keeps copies of all clients' states and, before sending a command
to a client, applies it to the client's state copy.
If AtomicFail
is signalled, the command is ignored for that client.
This enables simpler server code that addresses commands to all clients
that can see it, even though not all are able to process it.
Re-exported from Game.LambdaHack.Atomic.PosAtomicRead
The type representing visibility of atomic commands to factions, based on the position of the command, etc. Note that the server sees and smells all positions.
PosSight LevelId [Point] | whomever sees all the positions, notices |
PosFidAndSight [FactionId] LevelId [Point] | observers and the faction notice |
PosSmell LevelId [Point] | whomever smells all the positions, notices |
PosFid FactionId | only the faction notices, server doesn't |
PosFidAndSer (Maybe LevelId) FactionId | faction and server notices |
PosSer | only the server notices |
PosAll | everybody notices |
PosNone | never broadcasted, but sent manually |
posUpdAtomic :: MonadStateRead m => UpdAtomic -> m PosAtomic Source #
Produce the positions where the atomic update takes place or, more generally, the conditions under which the update can be noticed by a client.
The goal of this mechanics is to ensure that atomic commands involving some positions visible by a client convey similar information as the client would get by directly observing the changes of the portion of server state limited to the visible positions. Consequently, when the visible commands are later applied to the client's state, the state stays consistent --- in sync with the server state and correctly limited by visiblity. There is some wiggle room both in what "in sync" and "visible" means and how they propagate through time.
E.g., UpdDisplaceActor
in a black room between two enemy actors,
with only one actor carrying a 0-radius light would not be
distinguishable by looking at the state (or the screen) from UpdMoveActor
of the illuminated actor, hence such UpdDisplaceActor
should not be
observable, but UpdMoveActor
in similar cotext would be
(or the former should be perceived as the latter).
However, to simplify, we assign as strict visibility
requirements to UpdMoveActor
as to UpdDisplaceActor
and fall back
to UpdSpotActor
(which provides minimal information that does not
contradict state) if the visibility is lower.
posSfxAtomic :: MonadStateRead m => SfxAtomic -> m PosAtomic Source #
Produce the positions where the atomic special effect takes place.
breakUpdAtomic :: MonadStateRead m => UpdAtomic -> m [UpdAtomic] Source #
Decompose an atomic action that is outside a client's visiblity.
The decomposed actions give less information that the original command,
but some of them may fall within the visibility range of the client.
The original action may give more information than even the total sum
of all actions it's broken into. E.g., UpdMoveActor
informs about the continued existence of the actor between
moves vs popping out of existence and then back in.
This is computed in server's State
from before performing the command.
seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool Source #
Given the client, its perception and an atomic command, determine if the client notices the command.
seenAtomicSer :: PosAtomic -> Bool Source #
Determine whether the server would see a command that has the given visibilty conditions.
Re-exported from Game.LambdaHack.Atomic.MonadStateWrite
class MonadStateRead m => MonadStateWrite m where Source #
The monad for writing to the main game state. Atomic updates (UpdAtomic
)
are given semantics in this monad.
modifyState :: (State -> State) -> m () Source #
newtype AtomicFail Source #
Exception signifying that atomic action failed because
the information it carries is inconsistent with the client's state,
(e.g., because the client knows too little to understand the command
or already deduced the state change from earlier commands
or is confused, amnesiac or sees illusory actors or tiles).
Whenever we know the failure is logically impossible,
we don't throw the AtomicFail
exception, but insert a normal assertion
or error
call, which are never caught nor handled.
Instances
Show AtomicFail Source # | |
Defined in Game.LambdaHack.Atomic.MonadStateWrite showsPrec :: Int -> AtomicFail -> ShowS # show :: AtomicFail -> String # showList :: [AtomicFail] -> ShowS # | |
Exception AtomicFail Source # | |
Defined in Game.LambdaHack.Atomic.MonadStateWrite toException :: AtomicFail -> SomeException # fromException :: SomeException -> Maybe AtomicFail # displayException :: AtomicFail -> String # |
putState :: MonadStateWrite m => State -> m () Source #