diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2025-07-28 18:07:11 +0200 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-07-28 18:36:55 +0200 |
| commit | fe817908683b3a86de0566a7376ebb305ae3e5e0 (patch) | |
| tree | e12e9a10009e5a6275275cd700555d9f60f5985f /go | |
| parent | 3f4c96b24697ac92901f26afdf4f65faddae8b23 (diff) | |
| download | muhqs-game-rwc-player-ctrl.tar.gz muhqs-game-rwc-player-ctrl.zip | |
add player control over a ReadWriteCloserrwc-player-ctrl
Diffstat (limited to 'go')
| -rw-r--r-- | go/game/playerControl.go | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/go/game/playerControl.go b/go/game/playerControl.go index 74af6702..832b248c 100644 --- a/go/game/playerControl.go +++ b/go/game/playerControl.go @@ -1,7 +1,9 @@ package game import ( + "bufio" "fmt" + "io" "log" "regexp" ) @@ -290,3 +292,91 @@ func promptBuy(ctrl PlayerControl) (Action, error) { func promptAction(ctrl PlayerControl) (Action, error) { return prompt(ctrl, newPriorityNotification()) } + +// RWPlayerControl implements a player control over any io.ReadWriteCloser. +// The transfer happens in a plain text wire format and is suitable for communication between memory space boundaries. +// Transmission control, such as timeouts or reconnection, is not supported. +type RWPlayerControl struct { + player *Player + rwc io.ReadWriteCloser + r *bufio.Reader + nch chan PlayerNotification + done chan struct{} + nerr error +} + +func NewRWPlayerControl(p *Player, rwc io.ReadWriteCloser) *RWPlayerControl { + ctrl := &RWPlayerControl{ + p, + rwc, + bufio.NewReader(rwc), + make(chan PlayerNotification), + make(chan struct{}), + nil, + } + + go func() { + for { + in, err := ctrl.r.ReadBytes('\n') + if err != nil { + // FIXME + } + + var n PlayerNotification + n, ctrl.nerr = UnmarshalPlayerNotification(ctrl.player.gameState, in) + if n.Valid() { + select { + case ctrl.nch <- n: + case _, ok := <-ctrl.done: + if !ok { + close(ctrl.nch) + return + } + } + } + } + }() + + return ctrl +} + +func (c *RWPlayerControl) Player() *Player { return c.player } + +// SendAction encodes and sends an action. +// It is used by the player to respond to a received notification. +func (c *RWPlayerControl) SendAction(a Action) error { + out := MarshalAction(a) + _, err := c.rwc.Write(out) + return err +} + +// RecvAction returns the next received and decoded action. +// It is called by the game logic to receive a players action. +func (c *RWPlayerControl) RecvAction() (Action, error) { + in, err := c.r.ReadBytes('\n') + + a, err := UnmarshalAction(c.player.gameState, in) + return a, err +} + +// SendNotification encodes and sends a PlayerNotification. +func (c *RWPlayerControl) SendNotification(n PlayerNotification) error { + out := n.Marshal(c.player.gameState) + _, err := c.rwc.Write(out) + return err +} + +// RecvNotification returns a received and decoded PlayerNotification. +// It is called by the client to be notified about progress in the game. +func (c *RWPlayerControl) RecvNotification() (n PlayerNotification, err error) { + select { + case n = <-c.nch: + default: + } + return n, c.nerr +} + +func (c *RWPlayerControl) Close() { + c.rwc.Close() + close(c.nch) +} |
