aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go/game/playerControl.go90
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)
+}