Skip to content

Commit

Permalink
Merge pull request #1189 from domino14/bot-make-move
Browse files Browse the repository at this point in the history
Bot make move
  • Loading branch information
domino14 committed Aug 13, 2023
2 parents 445098c + afff5ee commit 1a3cbfb
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 30 deletions.
10 changes: 10 additions & 0 deletions pkg/bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func (b *Bus) ProcessMessages(ctx context.Context) {
outerfor:
for {
select {
// NATS message usually from socket service:
case msg := <-b.subchans["ipc.pb.>"]:
// Regular messages.
log := log.With().Interface("msg-subject", msg.Subject).Logger()
Expand All @@ -204,6 +205,7 @@ outerfor:
}
}(subtopics, msg.Data)

// NATS message usually from socket service:
case msg := <-b.subchans["ipc.request.>"]:
log := log.With().Interface("msg-subject", msg.Subject).Logger()
log.Debug().Msg("got ipc.request")
Expand All @@ -229,6 +231,7 @@ outerfor:
}
}()

// NATS message from macondo bot
case msg := <-b.subchans["bot.publish_event.>"]:
log := log.With().Interface("msg-subject", msg.Subject).Logger()
log.Debug().Msg("got-bot-publish")
Expand All @@ -246,20 +249,25 @@ outerfor:
}
b.goHandleBotMove(ctx, resp, gid, msg.Reply)

// NATS message from internal sources (within liwords)
case msg := <-b.subchans["user.>"]:
log := log.With().Interface("msg-user.>", msg.Subject).Logger()
log.Debug().Msg("got-user-event")
err := b.gameEventAPIServer.processEvent(msg.Subject, msg.Data)
if err != nil {
log.Err(err).Msg("user-event-process-error")
}

// NATS message from internal sources (within liwords)
case msg := <-b.subchans["game.>"]:
log := log.With().Interface("msg-game.>", msg.Subject).Logger()
log.Debug().Msg("got-game-event")
err := b.gameEventAPIServer.processEvent(msg.Subject, msg.Data)
if err != nil {
log.Err(err).Msg("game-event-process-error")
}

// Regular Go chan message from within liwords:
case msg := <-b.gameEventChan:
if msg.Type == pb.MessageType_ACTIVE_GAME_ENTRY {
// This message usually has no audience.
Expand Down Expand Up @@ -319,6 +327,7 @@ outerfor:
}
}

// Regular Go chan message from within liwords:
case msg := <-b.tournamentEventChan:
// A tournament event. Publish to the right realm.
log.Debug().Interface("msg", msg).Msg("tournament event chan")
Expand All @@ -332,6 +341,7 @@ outerfor:
b.natsconn.Publish(topic, data)
}

// Regular Go chan message from within liwords:
case msg := <-b.genericEventChan:
// a Generic event to be published via NATS.
// Publish to the right realm.
Expand Down
9 changes: 5 additions & 4 deletions pkg/bus/gameplay.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func (b *Bus) readyForGame(ctx context.Context, evt *pb.ReadyForGame, userID str
}
g.Lock()
defer g.Unlock()

log.Debug().Str("userID", userID).Interface("playing", g.Playing()).Msg("ready-for-game")
if g.Playing() != macondopb.PlayState_PLAYING {
return errors.New("game is over")
Expand All @@ -242,12 +243,13 @@ func (b *Bus) readyForGame(ctx context.Context, evt *pb.ReadyForGame, userID str
// Start the game if both players are ready (or if it's a bot game).
// readyflag will be (01 | 10) = 3 for two players.
if rf == (1<<len(g.History().Players))-1 || g.GameReq.PlayerVsBot {
err = gameplay.StartGame(ctx, b.gameStore, b.userStore, b.gameEventChan, g.GameID())
err = gameplay.StartGame(ctx, b.gameStore, b.userStore, b.gameEventChan, g)
if err != nil {
log.Err(err).Msg("starting-game")
} else {
// Note: for PlayerVsBot, readyForGame is called twice when player is ready and every time player refreshes, why? :-(
g.SendChange(g.NewActiveGameEntry(true))
}
// Note: for PlayerVsBot, readyForGame is called twice when player is ready and every time player refreshes, why? :-(
g.SendChange(g.NewActiveGameEntry(true))

}
return nil
Expand Down Expand Up @@ -437,7 +439,6 @@ func (b *Bus) sendGameRefresher(ctx context.Context, gameID, connID, userID stri
evt = entity.WrapEvent(hre,
pb.MessageType_GAME_HISTORY_REFRESHER)
}
// retain RLock() to prevent handleBotMoveInternally from making a new move not in evt
err = b.pubToConnectionID(connID, userID, evt)
if err != nil {
return err
Expand Down
7 changes: 4 additions & 3 deletions pkg/gameplay/end.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/rs/zerolog"
"google.golang.org/protobuf/proto"

"github.com/domino14/liwords/pkg/config"
"github.com/domino14/liwords/pkg/entity"
Expand Down Expand Up @@ -147,7 +148,7 @@ func performEndgameDuties(ctx context.Context, g *entity.Game, gameStore GameSto
defer users[1-firstLockingIndex].Unlock()

// Send a gameEndedEvent, which rates the game.
evt := gameEndedEvent(ctx, g, userStore)
evt := proto.Clone(gameEndedEvent(ctx, g, userStore)).(*pb.GameEndedEvent)
wrapped := entity.WrapEvent(evt, pb.MessageType_GAME_ENDED_EVENT)
for _, p := range players(g) {
wrapped.AddAudience(entity.AudUser, p+".game."+g.GameID())
Expand Down Expand Up @@ -366,11 +367,11 @@ func AbortGame(ctx context.Context, gameStore GameStore, tournamentStore tournam
}
evtChan <- wrapped

evt := &pb.GameEndedEvent{
evt := proto.Clone(&pb.GameEndedEvent{
EndReason: gameEndReason,
Time: g.Timers.TimeOfLastUpdate,
History: g.History(),
}
}).(*pb.GameEndedEvent)

wrapped = entity.WrapEvent(evt, pb.MessageType_GAME_ENDED_EVENT)
for _, p := range players(g) {
Expand Down
33 changes: 17 additions & 16 deletions pkg/gameplay/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/domino14/macondo/tilemapping"
"github.com/domino14/macondo/turnplayer"
"github.com/lithammer/shortuuid"
"google.golang.org/protobuf/proto"

"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
Expand All @@ -32,9 +33,10 @@ import (
)

var (
errGameNotActive = errors.New("game is not currently active")
errNotOnTurn = errors.New("player not on turn")
errTimeDidntRunOut = errors.New("got time ran out, but it did not actually")
errGameNotActive = errors.New("game is not currently active")
errNotOnTurn = errors.New("player not on turn")
errTimeDidntRunOut = errors.New("got time ran out, but it did not actually")
errGameAlreadyStarted = errors.New("game already started")
)

const (
Expand Down Expand Up @@ -218,20 +220,19 @@ func clientEventToMove(cge *pb.ClientGameplayEvent, g *game.Game) (*move.Move, e
return nil, errors.New("client gameplay event not handled")
}

func StartGame(ctx context.Context, gameStore GameStore, userStore user.Store, eventChan chan<- *entity.EventWrapper, id string) error {
func StartGame(ctx context.Context, gameStore GameStore, userStore user.Store, eventChan chan<- *entity.EventWrapper,
entGame *entity.Game) error {
// Note that StartGame does _not_ start the Macondo game, which
// has already started, but we don't "know" that. It is _this_
// function that will actually start the game in the user's eyes.
// It needs to reset the timer to now.
entGame, err := gameStore.Get(ctx, id)
if err != nil {
return err
}
// This should be True, see comment above.
if entGame.Game.Playing() != macondopb.PlayState_PLAYING {
return errGameNotActive
}
log.Debug().Str("gameid", id).Msg("reset timers (and start)")
if entGame.Started {
return errGameAlreadyStarted
}
log.Debug().Str("gameid", entGame.GameID()).Msg("reset timers (and start)")
entGame.ResetTimersAndStart()
log.Debug().Msg("going-to-save")
// Save the game back to the store always.
Expand All @@ -246,11 +247,11 @@ func StartGame(ctx context.Context, gameStore GameStore, userStore user.Store, e
log.Debug().Interface("history", entGame.Game.History()).Msg("game history")

evt := entGame.HistoryRefresherEvent()
evt.History = mod.CensorHistory(ctx, userStore, evt.History)
evt.History = proto.Clone(mod.CensorHistory(ctx, userStore, evt.History)).(*macondopb.GameHistory)
wrapped := entity.WrapEvent(evt, pb.MessageType_GAME_HISTORY_REFRESHER)
wrapped.AddAudience(entity.AudGameTV, entGame.GameID())
for _, p := range players(entGame) {
wrapped.AddAudience(entity.AudUser, p+".game."+id)
wrapped.AddAudience(entity.AudUser, p+".game."+entGame.GameID())
}
entGame.SendChange(wrapped)

Expand Down Expand Up @@ -701,16 +702,16 @@ func potentiallySendBotMoveRequest(ctx context.Context, userStore user.Store, g
return nil
}

evt := &macondopb.BotRequest{
evt := proto.Clone(&macondopb.BotRequest{
GameHistory: g.History(),
BotType: g.GameReq.BotType,
}
}).(*macondopb.BotRequest)
// message type doesn't matter here; we're going to make sure
// this doesn't get serialized with a message type.
wrapped := entity.WrapEvent(evt, 0)
wrapped.SetAudience(entity.AudBotCommands)
// serialize without any length/type headers! This is an internal
// message, and not meant for the socket.
// serialize without any length/type headers! This message is meant to
// go straight to a bot. See bus.go `case msg := <-b.gameEventChan:`
wrapped.SetSerializationProtocol(entity.EvtSerializationProto)
g.SendChange(wrapped)

Expand Down
2 changes: 1 addition & 1 deletion pkg/gameplay/game_playing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func makeGame(cfg *config.Config, ustore pkguser.Store, gstore gameplay.GameStor
nower := entity.NewFakeNower(1234)
g.SetTimerModule(nower)

gameplay.StartGame(ctx, gstore, ustore, ch, g.GameID())
gameplay.StartGame(ctx, gstore, ustore, ch, g)

return g, nower, cancel, donechan, consumer
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/mod/automod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func makeGame(cfg *config.Config, ustore pkguser.Store, gstore gameplay.GameStor
nower := entity.NewFakeNower(1234)
g.SetTimerModule(nower)

err = gameplay.StartGame(ctx, gstore, ustore, ch, g.GameID())
err = gameplay.StartGame(ctx, gstore, ustore, ch, g)
if err != nil {
panic(err)
}
Expand Down
1 change: 0 additions & 1 deletion pkg/mod/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ var RemovalDuration = 60
// This can be deleted once the above function uses the DB to get the actions.
func ActionExists(ctx context.Context, us user.Store, uuid string, forceInsistLogout bool, actionTypes []ms.ModActionType) (bool, error) {
currentActions, err := us.GetActions(ctx, uuid)
fmt.Println(currentActions)
if err != nil {
return false, err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/omgwords/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/domino14/liwords/pkg/omgwords/stores"
"github.com/domino14/liwords/rpc/api/proto/ipc"
"github.com/twitchtv/twirp"
"google.golang.org/protobuf/proto"
)

// handlers handle events from either the HTTP API or from the websocket/bus
Expand Down Expand Up @@ -85,7 +86,7 @@ func handleEvent(ctx context.Context, userID string, evt *ipc.ClientGameplayEven
if amendment {
// Send an entire document event.
evt := &ipc.GameDocumentEvent{
Doc: g.GameDocument,
Doc: proto.Clone(g.GameDocument).(*ipc.GameDocument),
}
wrapped := entity.WrapEvent(evt, ipc.MessageType_OMGWORDS_GAMEDOCUMENT)
wrapped.AddAudience(entity.AudChannel, AnnotatedChannelName(g.Uid))
Expand Down
7 changes: 4 additions & 3 deletions pkg/omgwords/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/rs/zerolog/log"
"github.com/samber/lo"
"github.com/twitchtv/twirp"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/domino14/liwords/pkg/apiserver"
Expand Down Expand Up @@ -211,7 +212,7 @@ func (gs *OMGWordsService) ReplaceGameDocument(ctx context.Context, req *pb.Repl
}
// And send an event.
evt := &ipc.GameDocumentEvent{
Doc: req.Document,
Doc: proto.Clone(req.Document).(*ipc.GameDocument),
}
wrapped := entity.WrapEvent(evt, ipc.MessageType_OMGWORDS_GAMEDOCUMENT)
wrapped.AddAudience(entity.AudChannel, AnnotatedChannelName(gid))
Expand Down Expand Up @@ -278,7 +279,7 @@ func (gs *OMGWordsService) PatchGameDocument(ctx context.Context, req *pb.PatchD
}
// And send an event.
evt := &ipc.GameDocumentEvent{
Doc: g.GameDocument,
Doc: proto.Clone(g.GameDocument).(*ipc.GameDocument),
}
wrapped := entity.WrapEvent(evt, ipc.MessageType_OMGWORDS_GAMEDOCUMENT)
wrapped.AddAudience(entity.AudChannel, AnnotatedChannelName(gid))
Expand Down Expand Up @@ -455,7 +456,7 @@ func (gs *OMGWordsService) SetRacks(ctx context.Context, req *pb.SetRacksEvent)

// And send an event.
evt := &ipc.GameDocumentEvent{
Doc: g.GameDocument,
Doc: proto.Clone(g.GameDocument).(*ipc.GameDocument),
}
wrapped := entity.WrapEvent(evt, ipc.MessageType_OMGWORDS_GAMEDOCUMENT)
wrapped.AddAudience(entity.AudChannel, AnnotatedChannelName(g.Uid))
Expand Down

0 comments on commit 1a3cbfb

Please sign in to comment.