Fix server deadlock
This commit is contained in:
parent
5074c6e607
commit
8ba9582ab9
10 changed files with 144 additions and 57 deletions
|
@ -1,6 +1,7 @@
|
|||
0.1.8:
|
||||
- Add custom color support
|
||||
- Improve SSH host key file not found error
|
||||
- Fix server deadlock
|
||||
|
||||
0.1.7:
|
||||
- Spawn pieces within view
|
||||
|
|
|
@ -429,7 +429,8 @@ func renderMatrixes(mx []*mino.Matrix) {
|
|||
}
|
||||
|
||||
for i := range mx {
|
||||
mx[i].Lock()
|
||||
mx[i].Lock() // Unlocked later in this function
|
||||
|
||||
if mt == mino.MatrixCustom {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ func initGUI(skipTitle bool) (*cview.Application, error) {
|
|||
cview.Styles.PrimaryTextColor = tcell.ColorDefault
|
||||
cview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
|
||||
|
||||
app = cview.NewApplication().EnableMouse()
|
||||
app = cview.NewApplication().EnableMouse(true)
|
||||
|
||||
app.SetAfterResizeFunc(handleResize)
|
||||
|
||||
|
|
15
go.mod
15
go.mod
|
@ -3,15 +3,14 @@ module gitlab.com/tslocum/netris
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||
github.com/creack/pty v1.1.9
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/creack/pty v1.1.11
|
||||
github.com/gdamore/tcell v1.3.0
|
||||
github.com/gliderlabs/ssh v0.2.2
|
||||
github.com/gliderlabs/ssh v0.3.0
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
gitlab.com/tslocum/cbind v0.1.1
|
||||
gitlab.com/tslocum/cview v1.4.4-0.20200220174815-3bf6bb259c75
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gitlab.com/tslocum/cview v1.4.6
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
|
35
go.sum
35
go.sum
|
@ -1,16 +1,14 @@
|
|||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
|
||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.3.0 h1:7GcKy4erEljCE/QeQ2jTVpu+3f3zkpZOxOJjFYkMqYU=
|
||||
github.com/gliderlabs/ssh v0.3.0/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
|
@ -19,15 +17,17 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
gitlab.com/tslocum/cbind v0.1.1 h1:JXXtxMWHgWLvoF+QkrvcNvOQ59juy7OE1RhT7hZfdt0=
|
||||
gitlab.com/tslocum/cbind v0.1.1/go.mod h1:rX7vkl0pUSg/yy427MmD1FZAf99S7WwpUlxF/qTpPqk=
|
||||
gitlab.com/tslocum/cview v1.4.4-0.20200220174815-3bf6bb259c75 h1:htStKLVVrf77HtDVx0jFY4YUO45w/FaESnu2U+T2gKY=
|
||||
gitlab.com/tslocum/cview v1.4.4-0.20200220174815-3bf6bb259c75/go.mod h1:+bEf1cg6IoWvL16YHJAKwGGpQf5s/nxXAA7YJr+WOHE=
|
||||
gitlab.com/tslocum/cview v1.4.6 h1:dEM/aOsatoaNZOZ511n8hhZABPzTunUdi0RpUw9uXjM=
|
||||
gitlab.com/tslocum/cview v1.4.6/go.mod h1:PW2Ucec7oTYOfK4N+hqm/CKEN9B1PBidq5YJ3ZaeknU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -35,15 +35,14 @@ golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
@ -30,6 +30,7 @@ type Conn struct {
|
|||
forwardOut chan GameCommandInterface
|
||||
|
||||
*sync.WaitGroup
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func NewServerConn(conn net.Conn, forwardOut chan GameCommandInterface) *Conn {
|
||||
|
@ -112,7 +113,12 @@ func (s *Conn) Write(gc GameCommandInterface) {
|
|||
func (s *Conn) handleLocalWrite() {
|
||||
for e := range s.out {
|
||||
if s.forwardOut != nil {
|
||||
s.forwardOut <- e
|
||||
select {
|
||||
case s.forwardOut <- e:
|
||||
default:
|
||||
s.Done()
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
s.Done()
|
||||
|
@ -228,7 +234,12 @@ func (s *Conn) handleRead() {
|
|||
|
||||
if !processed {
|
||||
s.addSourceID(gc)
|
||||
s.In <- gc
|
||||
|
||||
select {
|
||||
case s.In <- gc:
|
||||
default:
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
err = s.conn.SetReadDeadline(time.Now().Add(ConnTimeout))
|
||||
|
@ -290,16 +301,25 @@ func (s *Conn) handleWrite() {
|
|||
}
|
||||
|
||||
func (s *Conn) Close() {
|
||||
s.Lock()
|
||||
|
||||
if s.Terminated {
|
||||
s.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
s.Terminated = true
|
||||
|
||||
s.Unlock()
|
||||
|
||||
s.conn.Close()
|
||||
|
||||
go func() {
|
||||
s.Wait()
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
close(s.In)
|
||||
close(s.out)
|
||||
}()
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"time"
|
||||
|
||||
"gitlab.com/tslocum/netris/pkg/event"
|
||||
|
||||
"gitlab.com/tslocum/netris/pkg/mino"
|
||||
)
|
||||
|
||||
|
@ -65,7 +64,7 @@ type Game struct {
|
|||
SpeedLimit int
|
||||
|
||||
sentPing time.Time
|
||||
*sync.Mutex
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func NewGame(rank int, out func(GameCommandInterface), logger chan string, draw chan event.DrawObject) (*Game, error) {
|
||||
|
@ -83,7 +82,7 @@ func NewGame(rank int, out func(GameCommandInterface), logger chan string, draw
|
|||
Event: make(chan interface{}, CommandQueueSize),
|
||||
draw: draw,
|
||||
logger: logger,
|
||||
Mutex: new(sync.Mutex)}
|
||||
}
|
||||
|
||||
if out != nil {
|
||||
g.out = out
|
||||
|
@ -385,6 +384,7 @@ func (g *Game) handleDistributeMatrixes() {
|
|||
|
||||
if g.Terminated {
|
||||
t.Stop()
|
||||
g.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -470,13 +470,20 @@ func (g *Game) handleDistributeMatrixes() {
|
|||
go func() {
|
||||
for {
|
||||
time.Sleep(7 * time.Second)
|
||||
|
||||
g.Lock()
|
||||
|
||||
if g.Terminated {
|
||||
g.Unlock()
|
||||
return
|
||||
} else if len(g.Players) > 1 {
|
||||
g.Unlock()
|
||||
g.Reset()
|
||||
g.Start(0)
|
||||
return
|
||||
}
|
||||
|
||||
g.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -648,6 +655,12 @@ func (g *Game) handleDistributeGarbage() {
|
|||
|
||||
g.Lock()
|
||||
|
||||
if g.Terminated {
|
||||
t.Stop()
|
||||
g.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
for i := range g.Players {
|
||||
if g.Players[i].pendingGarbage > 0 {
|
||||
g.Players[i].Write(&GameCommandReceiveGarbage{Lines: g.Players[i].pendingGarbage})
|
||||
|
@ -655,6 +668,7 @@ func (g *Game) handleDistributeGarbage() {
|
|||
g.Players[i].pendingGarbage = 0
|
||||
}
|
||||
}
|
||||
|
||||
g.Unlock()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@ func NewServer(si []ServerInterface, logLevel int) *Server {
|
|||
}
|
||||
|
||||
func (s *Server) NewGame() (*Game, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
gameID := 1
|
||||
for {
|
||||
if _, ok := s.Games[gameID]; !ok {
|
||||
|
@ -136,27 +139,27 @@ func (s *Server) handle() {
|
|||
for {
|
||||
time.Sleep(1 * time.Minute)
|
||||
|
||||
s.Lock()
|
||||
s.removeTerminatedGames()
|
||||
s.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) removeTerminatedGames() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
for gameID, g := range s.Games {
|
||||
if g != nil && !g.Terminated {
|
||||
g.Lock()
|
||||
if !g.Terminated {
|
||||
g.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
delete(s.Games, gameID)
|
||||
g = nil
|
||||
g.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) FindGame(p *Player, gameID int, newGame ListedGame) *Game {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var (
|
||||
g *Game
|
||||
err error
|
||||
|
@ -190,20 +193,39 @@ func (s *Server) FindGame(p *Player, gameID int, newGame ListedGame) *Game {
|
|||
g.Unlock()
|
||||
} else if gameID > 0 {
|
||||
// Join a game by its ID
|
||||
if gm, ok := s.Games[gameID]; ok && !gm.Terminated && (gm.MaxPlayers == 0 || len(gm.Players) < gm.MaxPlayers) {
|
||||
g = gm
|
||||
s.Lock()
|
||||
gm := s.Games[gameID]
|
||||
s.Unlock()
|
||||
|
||||
if gm != nil {
|
||||
gm.Lock()
|
||||
canJoin := !gm.Terminated && (gm.MaxPlayers == 0 || len(gm.Players) < gm.MaxPlayers)
|
||||
gm.Unlock()
|
||||
|
||||
if canJoin {
|
||||
g = gm
|
||||
} else {
|
||||
p.Write(&GameCommandMessage{Message: "Failed to join game - Player limit reached"})
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
p.Write(&GameCommandMessage{Message: "Failed to join game - Player limit reached"})
|
||||
p.Write(&GameCommandMessage{Message: "Failed to join game - Invalid game ID"})
|
||||
return nil
|
||||
}
|
||||
} else if gameID == 0 {
|
||||
// Join any game
|
||||
s.Lock()
|
||||
for _, gm := range s.Games {
|
||||
if gm != nil && !gm.Terminated && (gm.MaxPlayers == 0 || len(gm.Players) < gm.MaxPlayers) {
|
||||
gm.Lock()
|
||||
if !gm.Terminated && (gm.MaxPlayers == 0 || len(gm.Players) < gm.MaxPlayers) {
|
||||
gm.Unlock()
|
||||
g = gm
|
||||
break
|
||||
}
|
||||
|
||||
gm.Unlock()
|
||||
}
|
||||
s.Unlock()
|
||||
} else {
|
||||
// Create a local game
|
||||
g, err = s.NewGame()
|
||||
|
@ -261,13 +283,18 @@ func (s *Server) handleNewPlayer(pl *Player) {
|
|||
if _, ok := e.(*GameCommandListGames); ok {
|
||||
var gl []*ListedGame
|
||||
|
||||
s.Lock()
|
||||
for _, g := range s.Games {
|
||||
g.Lock()
|
||||
if g.Terminated {
|
||||
g.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
gl = append(gl, &ListedGame{ID: g.ID, Name: g.Name, Players: len(g.Players), MaxPlayers: g.MaxPlayers, SpeedLimit: g.SpeedLimit})
|
||||
g.Unlock()
|
||||
}
|
||||
s.Unlock()
|
||||
|
||||
sort.Slice(gl, func(i, j int) bool {
|
||||
if gl[i].Players == gl[j].Players {
|
||||
|
@ -407,15 +434,19 @@ func (s *Server) handleGameCommands(pl *Player, g *Game) {
|
|||
g.Players[p.SourcePlayer].totalGarbageSent += p.Lines
|
||||
}
|
||||
case *GameCommandStats:
|
||||
players := 0
|
||||
games := 0
|
||||
go func(p *Player) {
|
||||
players := 0
|
||||
games := 0
|
||||
|
||||
for _, g := range s.Games {
|
||||
players += len(g.Players)
|
||||
games++
|
||||
}
|
||||
s.Lock()
|
||||
for _, g := range s.Games {
|
||||
players += len(g.Players)
|
||||
games++
|
||||
}
|
||||
s.Unlock()
|
||||
|
||||
g.Players[p.SourcePlayer].Write(&GameCommandStats{Created: s.created, Players: players, Games: games})
|
||||
p.Write(&GameCommandStats{Created: s.created, Players: players, Games: games})
|
||||
}(g.Players[p.SourcePlayer])
|
||||
}
|
||||
|
||||
g.Unlock()
|
||||
|
|
|
@ -14,13 +14,13 @@ type Bag struct {
|
|||
|
||||
i int
|
||||
width int
|
||||
*sync.Mutex
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func NewBag(seed int64, minos []Mino, width int) (*Bag, error) {
|
||||
minoSource := rand.NewSource(seed)
|
||||
garbageSource := rand.NewSource(seed)
|
||||
b := &Bag{Original: minos, minoRandomizer: rand.New(minoSource), garbageRandomizer: rand.New(garbageSource), width: width, Mutex: new(sync.Mutex)}
|
||||
b := &Bag{Original: minos, minoRandomizer: rand.New(minoSource), garbageRandomizer: rand.New(garbageSource), width: width}
|
||||
|
||||
b.shuffle()
|
||||
|
||||
|
|
|
@ -361,7 +361,9 @@ func (m *Matrix) Draw() {
|
|||
return
|
||||
}
|
||||
|
||||
m.draw <- event.DrawPlayerMatrix
|
||||
select {
|
||||
case m.draw <- event.DrawPlayerMatrix:
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Matrix) ClearOverlay() {
|
||||
|
@ -458,6 +460,10 @@ func (m *Matrix) SetGameOver() {
|
|||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.setGameOver()
|
||||
}
|
||||
|
||||
func (m *Matrix) setGameOver() {
|
||||
if m.GameOver {
|
||||
return
|
||||
}
|
||||
|
@ -682,7 +688,7 @@ LANDPIECE:
|
|||
|
||||
_ = score
|
||||
|
||||
m.Moved()
|
||||
m.moved()
|
||||
|
||||
for i := range m.lands {
|
||||
if time.Since(m.lands[i]) > 2*time.Minute {
|
||||
|
@ -855,7 +861,7 @@ func (m *Matrix) movePiece(x int, y int) bool {
|
|||
}
|
||||
|
||||
if y < 0 {
|
||||
m.Moved()
|
||||
m.moved()
|
||||
}
|
||||
|
||||
m.Draw()
|
||||
|
@ -864,6 +870,22 @@ func (m *Matrix) movePiece(x int, y int) bool {
|
|||
}
|
||||
|
||||
func (m *Matrix) Moved() {
|
||||
m.Lock()
|
||||
if m.Move == nil {
|
||||
m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case m.Move <- 0:
|
||||
m.Unlock()
|
||||
default:
|
||||
m.Unlock()
|
||||
m.SetGameOver()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Matrix) moved() {
|
||||
if m.Move == nil {
|
||||
return
|
||||
}
|
||||
|
@ -871,7 +893,7 @@ func (m *Matrix) Moved() {
|
|||
select {
|
||||
case m.Move <- 0:
|
||||
default:
|
||||
m.SetGameOver()
|
||||
m.setGameOver()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue