Improve rendering process
This commit is contained in:
parent
f09ceab006
commit
92273d1c31
15 changed files with 236 additions and 253 deletions
18
README.md
18
README.md
|
@ -5,8 +5,6 @@
|
|||
|
||||
Multiplayer Tetris clone
|
||||
|
||||
This project is not yet stable. Feedback is welcome.
|
||||
|
||||
![](https://netris.rocketnine.space/static/screenshot2.png)
|
||||
|
||||
## Demo
|
||||
|
@ -30,22 +28,6 @@ go get -u git.sr.ht/~tslocum/netris/cmd/netris-server
|
|||
|
||||
See [CONFIGURATION.md](https://man.sr.ht/~tslocum/netris/CONFIGURATION.md)
|
||||
|
||||
## Play
|
||||
|
||||
A single player game may be played by launching without any options.
|
||||
|
||||
To play online, connect to the official server:
|
||||
|
||||
```netris --nick <name> --connect netris.rocketnine.space```
|
||||
|
||||
To host a private game, start a dedicated server:
|
||||
|
||||
```netris-server --listen-tcp :1984```
|
||||
|
||||
Then, connect with:
|
||||
|
||||
```netris --nick <name> --connect ip.or.dns.address:1984```
|
||||
|
||||
## Support
|
||||
|
||||
Please share suggestions/issues [here](https://todo.sr.ht/~tslocum/netris).
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -60,6 +61,8 @@ var (
|
|||
nicknameDraft string
|
||||
|
||||
inputHeight, mainHeight, newLogLines int
|
||||
|
||||
profileCPU *os.File
|
||||
)
|
||||
|
||||
const DefaultStatusText = "Press Enter to chat, Z/X to rotate, arrow keys or HJKL to move/drop"
|
||||
|
@ -132,6 +135,7 @@ func initGUI() (*tview.Application, error) {
|
|||
side.SetDynamicColors(true)
|
||||
|
||||
buffer = tview.NewTextView().
|
||||
SetScrollable(false).
|
||||
SetTextAlign(tview.AlignLeft).
|
||||
SetWrap(false).
|
||||
SetWordWrap(false)
|
||||
|
@ -188,16 +192,19 @@ func initGUI() (*tview.Application, error) {
|
|||
}
|
||||
|
||||
titleName = tview.NewTextView().
|
||||
SetScrollable(false).
|
||||
SetTextAlign(tview.AlignLeft).
|
||||
SetWrap(false).
|
||||
SetWordWrap(false).SetDynamicColors(true)
|
||||
|
||||
titleL = tview.NewTextView().
|
||||
SetScrollable(false).
|
||||
SetTextAlign(tview.AlignLeft).
|
||||
SetWrap(false).
|
||||
SetWordWrap(false).SetDynamicColors(true)
|
||||
|
||||
titleR = tview.NewTextView().
|
||||
SetScrollable(false).
|
||||
SetTextAlign(tview.AlignLeft).
|
||||
SetWrap(false).
|
||||
SetWordWrap(false).SetDynamicColors(true)
|
||||
|
@ -435,15 +442,6 @@ func handleDraw() {
|
|||
case event.DrawMessages:
|
||||
app.QueueUpdateDraw(renderRecentMessages)
|
||||
default:
|
||||
DRAW:
|
||||
for {
|
||||
select {
|
||||
case <-draw:
|
||||
default:
|
||||
break DRAW
|
||||
}
|
||||
}
|
||||
|
||||
app.QueueUpdateDraw(drawAll)
|
||||
}
|
||||
}
|
||||
|
@ -510,28 +508,28 @@ func renderPreviewMatrix() {
|
|||
comboTime float64
|
||||
combo int
|
||||
)
|
||||
if m.Combo > 0 && time.Since(m.ComboEnd) < 0 {
|
||||
comboTime = 1.0 + (float64(m.ComboEnd.Sub(time.Now())) / 1000000000)
|
||||
if m.Combo > 0 && time.Until(m.ComboEnd) > 0 {
|
||||
comboTime = 1.0 + (float64(time.Until(m.ComboEnd)) / 1000000000)
|
||||
combo = m.Combo
|
||||
}
|
||||
m.Unlock()
|
||||
|
||||
side.Clear()
|
||||
side.Write(renderMatrix(g.Players[g.LocalPlayer].Preview))
|
||||
m.Lock()
|
||||
renderLock.Lock()
|
||||
renderBuffer.Reset()
|
||||
var speed = strconv.Itoa(m.Speed)
|
||||
if m.Speed < 100 {
|
||||
renderBuffer.WriteRune(' ')
|
||||
speed = " " + speed
|
||||
}
|
||||
renderBuffer.WriteString(strconv.Itoa(m.Speed))
|
||||
|
||||
renderLock.Lock()
|
||||
renderMatrix(g.Players[g.LocalPlayer].Preview)
|
||||
|
||||
if blockSize > 1 {
|
||||
fmt.Fprint(side, fmt.Sprintf("\n\n\n\n\n Combo\n\n %d\n\n\n\n\n Timer\n\n %.0f\n\n\n\n\nPending\n\n %d\n\n\n\n\n Speed\n\n %s", combo, comboTime, m.PendingGarbage, renderBuffer.Bytes()))
|
||||
renderBuffer.WriteString(fmt.Sprintf("\n\n\n\n\n Combo\n\n %d\n\n\n\n\n Timer\n\n %.0f\n\n\n\n\nPending\n\n %d\n\n\n\n\n Speed\n\n %s", combo, comboTime, m.PendingGarbage, speed))
|
||||
} else {
|
||||
fmt.Fprint(side, fmt.Sprintf("\n\n Combo\n\n %d\n\n Timer\n\n %.0f\n\nPending\n\n %d\n\n Speed\n\n %s", combo, comboTime, m.PendingGarbage, renderBuffer.Bytes()))
|
||||
renderBuffer.WriteString(fmt.Sprintf("\n\n Combo\n\n %d\n\n Timer\n\n %.0f\n\nPending\n\n %d\n\n Speed\n\n %s", combo, comboTime, m.PendingGarbage, speed))
|
||||
}
|
||||
|
||||
side.Clear()
|
||||
side.Write(renderBuffer.Bytes())
|
||||
|
||||
renderLock.Unlock()
|
||||
m.Unlock()
|
||||
}
|
||||
|
@ -542,8 +540,11 @@ func renderPlayerMatrix() {
|
|||
return
|
||||
}
|
||||
|
||||
renderLock.Lock()
|
||||
renderMatrix(g.Players[g.LocalPlayer].Matrix)
|
||||
mtx.Clear()
|
||||
mtx.Write(renderMatrix(g.Players[g.LocalPlayer].Matrix))
|
||||
mtx.Write(renderBuffer.Bytes())
|
||||
renderLock.Unlock()
|
||||
}
|
||||
|
||||
func renderMultiplayerMatrix() {
|
||||
|
@ -591,23 +592,23 @@ func renderMultiplayerMatrix() {
|
|||
|
||||
g.Unlock()
|
||||
|
||||
renderLock.Lock()
|
||||
renderMatrixes(matrixes)
|
||||
buffer.Clear()
|
||||
buffer.Write(renderMatrixes(matrixes))
|
||||
buffer.Write(renderBuffer.Bytes())
|
||||
renderLock.Unlock()
|
||||
}
|
||||
|
||||
func renderMatrix(m *mino.Matrix) []byte {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
func renderMatrix(m *mino.Matrix) {
|
||||
renderBuffer.Reset()
|
||||
|
||||
renderLock.Lock()
|
||||
defer renderLock.Unlock()
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
renderBuffer.Reset()
|
||||
|
||||
m.DrawPiecesL()
|
||||
|
||||
bs := blockSize
|
||||
|
@ -647,14 +648,14 @@ func renderMatrix(m *mino.Matrix) []byte {
|
|||
renderBuffer.Write(renderVLine)
|
||||
}
|
||||
|
||||
if y != 0 || m.Type == mino.MatrixStandard {
|
||||
if y != 0 || m.Type != mino.MatrixCustom {
|
||||
renderBuffer.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if m.Type != mino.MatrixStandard {
|
||||
return renderBuffer.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
renderBuffer.Write(renderLLCorner)
|
||||
|
@ -665,8 +666,6 @@ func renderMatrix(m *mino.Matrix) []byte {
|
|||
|
||||
renderBuffer.WriteRune('\n')
|
||||
renderPlayerDetails(m, bs)
|
||||
|
||||
return renderBuffer.Bytes()
|
||||
}
|
||||
|
||||
func renderPlayerDetails(m *mino.Matrix, bs int) {
|
||||
|
@ -695,21 +694,18 @@ func renderPlayerDetails(m *mino.Matrix, bs int) {
|
|||
}
|
||||
}
|
||||
|
||||
func renderMatrixes(mx []*mino.Matrix) []byte {
|
||||
if mx == nil {
|
||||
return nil
|
||||
}
|
||||
func renderMatrixes(mx []*mino.Matrix) {
|
||||
renderBuffer.Reset()
|
||||
|
||||
renderLock.Lock()
|
||||
defer renderLock.Unlock()
|
||||
if mx == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range mx {
|
||||
mx[i].Lock()
|
||||
mx[i].DrawPiecesL()
|
||||
}
|
||||
|
||||
renderBuffer.Reset()
|
||||
|
||||
div := " "
|
||||
|
||||
height := mx[0].H
|
||||
|
@ -767,8 +763,6 @@ func renderMatrixes(mx []*mino.Matrix) []byte {
|
|||
for i := range mx {
|
||||
mx[i].Unlock()
|
||||
}
|
||||
|
||||
return renderBuffer.Bytes()
|
||||
}
|
||||
|
||||
func logMessage(message string) {
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
|
||||
"git.sr.ht/~tslocum/netris/pkg/event"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
@ -110,10 +116,39 @@ func handleKeypress(ev *tcell.EventKey) *tcell.EventKey {
|
|||
if k == tcell.KeyEnter {
|
||||
msg := inputView.GetText()
|
||||
if msg != "" {
|
||||
if activeGame != nil {
|
||||
activeGame.Event <- &event.MessageEvent{Message: msg}
|
||||
if strings.HasPrefix(msg, "/cpu") {
|
||||
if profileCPU == nil {
|
||||
if len(msg) < 5 {
|
||||
logMessage("Profile name must be specified")
|
||||
} else {
|
||||
profileName := strings.TrimSpace(msg[5:])
|
||||
|
||||
var err error
|
||||
profileCPU, err = os.Create(profileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = pprof.StartCPUProfile(profileCPU)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
logMessage(fmt.Sprintf("Started profiling CPU usage as %s", profileName))
|
||||
}
|
||||
} else {
|
||||
pprof.StopCPUProfile()
|
||||
profileCPU.Close()
|
||||
profileCPU = nil
|
||||
|
||||
logMessage("Stopped profiling CPU usage")
|
||||
}
|
||||
} else {
|
||||
logMessage("Message not sent - not currently connected to any game")
|
||||
if activeGame != nil {
|
||||
activeGame.Event <- &event.MessageEvent{Message: msg}
|
||||
} else {
|
||||
logMessage("Message not sent - not currently connected to any game")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,66 +207,66 @@ func handleKeypress(ev *tcell.EventKey) *tcell.EventKey {
|
|||
setShowDetails(!showDetails)
|
||||
case tcell.KeyEscape:
|
||||
setTitleVisible(true)
|
||||
}
|
||||
default:
|
||||
switch r {
|
||||
case 'z', 'Z':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
switch r {
|
||||
case 'z', 'Z':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.RotatePiece(1, 1)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'x', 'X':
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.RotatePiece(1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'h', 'H':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(-1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'j', 'J':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(0, -1)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'k', 'K':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.HardDropPiece()
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'l', 'L':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.RotatePiece(1, 1)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'x', 'X':
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.RotatePiece(1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'h', 'H':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(-1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'j', 'J':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(0, -1)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'k', 'K':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.HardDropPiece()
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
case 'l', 'L':
|
||||
if activeGame == nil {
|
||||
return ev
|
||||
}
|
||||
|
||||
activeGame.Lock()
|
||||
activeGame.Players[activeGame.LocalPlayer].Matrix.MovePiece(1, 0)
|
||||
activeGame.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return ev
|
||||
|
|
|
@ -7,6 +7,9 @@ import (
|
|||
)
|
||||
|
||||
func TestRenderMatrix(t *testing.T) {
|
||||
renderLock.Lock()
|
||||
defer renderLock.Unlock()
|
||||
|
||||
blockSize = 1
|
||||
|
||||
m, err := mino.NewTestMatrix()
|
||||
|
@ -16,13 +19,13 @@ func TestRenderMatrix(t *testing.T) {
|
|||
|
||||
m.AddTestBlocks()
|
||||
|
||||
var renderedMatrix []byte
|
||||
renderedMatrix = renderMatrix(m)
|
||||
|
||||
_ = renderedMatrix
|
||||
renderMatrix(m)
|
||||
}
|
||||
|
||||
func BenchmarkRenderStandardMatrix(b *testing.B) {
|
||||
renderLock.Lock()
|
||||
defer renderLock.Unlock()
|
||||
|
||||
blockSize = 1
|
||||
|
||||
m, err := mino.NewTestMatrix()
|
||||
|
@ -32,18 +35,18 @@ func BenchmarkRenderStandardMatrix(b *testing.B) {
|
|||
|
||||
m.AddTestBlocks()
|
||||
|
||||
var renderedMatrix []byte
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
renderedMatrix = renderMatrix(m)
|
||||
renderMatrix(m)
|
||||
}
|
||||
|
||||
_ = renderedMatrix
|
||||
}
|
||||
|
||||
func BenchmarkRenderLargeMatrix(b *testing.B) {
|
||||
renderLock.Lock()
|
||||
defer renderLock.Unlock()
|
||||
|
||||
blockSize = 2
|
||||
|
||||
m, err := mino.NewTestMatrix()
|
||||
|
@ -53,15 +56,12 @@ func BenchmarkRenderLargeMatrix(b *testing.B) {
|
|||
|
||||
m.AddTestBlocks()
|
||||
|
||||
var renderedMatrix []byte
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
renderedMatrix = renderMatrix(m)
|
||||
renderMatrix(m)
|
||||
}
|
||||
|
||||
_ = renderedMatrix
|
||||
|
||||
blockSize = 1
|
||||
}
|
||||
|
|
|
@ -12,13 +12,17 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
playerForm *tview.Form
|
||||
|
||||
titleVisible bool
|
||||
titleScreen int
|
||||
titleSelectedButton int
|
||||
drawTitle = make(chan struct{}, game.CommandQueueSize)
|
||||
|
||||
titleMatrixL = newTitleMatrixSide()
|
||||
titleMatrix = newTitleMatrixName()
|
||||
titleMatrixR = newTitleMatrixSide()
|
||||
titlePiecesL []*mino.Piece
|
||||
titlePiecesR []*mino.Piece
|
||||
|
||||
buttonA *tview.Button
|
||||
buttonB *tview.Button
|
||||
buttonC *tview.Button
|
||||
|
@ -26,12 +30,6 @@ var (
|
|||
buttonLabelA *tview.TextView
|
||||
buttonLabelB *tview.TextView
|
||||
buttonLabelC *tview.TextView
|
||||
|
||||
titleMatrixL = newTitleMatrixSide()
|
||||
titleMatrix = newTitleMatrixName()
|
||||
titleMatrixR = newTitleMatrixSide()
|
||||
titlePiecesL []*mino.Piece
|
||||
titlePiecesR []*mino.Piece
|
||||
)
|
||||
|
||||
func previousTitleButton() {
|
||||
|
@ -205,14 +203,21 @@ func renderTitle() {
|
|||
titleMatrix.M[i] = newBlock
|
||||
}
|
||||
|
||||
renderLock.Lock()
|
||||
|
||||
renderMatrix(titleMatrix)
|
||||
titleName.Clear()
|
||||
titleName.Write(renderMatrix(titleMatrix))
|
||||
titleName.Write(renderBuffer.Bytes())
|
||||
|
||||
renderMatrix(titleMatrixL)
|
||||
titleL.Clear()
|
||||
titleL.Write(renderMatrix(titleMatrixL))
|
||||
titleL.Write(renderBuffer.Bytes())
|
||||
|
||||
renderMatrix(titleMatrixR)
|
||||
titleR.Clear()
|
||||
titleR.Write(renderMatrix(titleMatrixR))
|
||||
titleR.Write(renderBuffer.Bytes())
|
||||
|
||||
renderLock.Unlock()
|
||||
}
|
||||
|
||||
func newTitleMatrixSide() *mino.Matrix {
|
||||
|
|
|
@ -23,8 +23,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ready = make(chan bool)
|
||||
done = make(chan bool)
|
||||
done = make(chan bool)
|
||||
|
||||
activeGame *game.Game
|
||||
|
||||
|
|
4
go.mod
4
go.mod
|
@ -9,9 +9,9 @@ require (
|
|||
github.com/gdamore/tcell v1.3.0
|
||||
github.com/gliderlabs/ssh v0.2.2
|
||||
github.com/mattn/go-isatty v0.0.10
|
||||
github.com/rivo/tview v0.0.0-20190829161255-f8bc69b90341
|
||||
github.com/rivo/tview v0.0.0-20191017100741-c35e6b2b4c98
|
||||
github.com/rivo/uniseg v0.1.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20191011161858-a950601f39e6
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
)
|
||||
|
|
8
go.sum
8
go.sum
|
@ -20,15 +20,15 @@ github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW1
|
|||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/rivo/tview v0.0.0-20190829161255-f8bc69b90341 h1:d2Z5U4d3fenPRFFweaMCogbXiRywM5kgYtu20/hol3M=
|
||||
github.com/rivo/tview v0.0.0-20190829161255-f8bc69b90341/go.mod h1:+rKjP5+h9HMwWRpAfhIkkQ9KE3m3Nz5rwn7YtUpwgqk=
|
||||
github.com/rivo/tview v0.0.0-20191017100741-c35e6b2b4c98 h1:nPfVK45RSX656/m0SXLl0GfhQbBgIUjojrbVxpOA8Ak=
|
||||
github.com/rivo/tview v0.0.0-20191017100741-c35e6b2b4c98/go.mod h1:+rKjP5+h9HMwWRpAfhIkkQ9KE3m3Nz5rwn7YtUpwgqk=
|
||||
github.com/rivo/uniseg v0.0.0-20190513083848-b9f5b9457d44 h1:XKCbzPvK4/BbMXoMJOkYP2ANxiAEO0HM1xn6psSbXxY=
|
||||
github.com/rivo/uniseg v0.0.0-20190513083848-b9f5b9457d44/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011161858-a950601f39e6 h1:w8KIlm7HkDEQx6EtcrA+tJK38f+NJTDOKKFSM96fwBA=
|
||||
golang.org/x/crypto v0.0.0-20191011161858-a950601f39e6/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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 h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
|
|
|
@ -145,30 +145,6 @@ func (s *Server) FindGame(p *Player, gameID int) *Game {
|
|||
return g
|
||||
}
|
||||
|
||||
func (s *Server) joinGame(p *Player, g *Game) {
|
||||
var notified bool
|
||||
for {
|
||||
if p.Terminated {
|
||||
return
|
||||
}
|
||||
|
||||
g.Lock()
|
||||
if !g.Started {
|
||||
break
|
||||
} else if !notified {
|
||||
p.Write(&GameCommandMessage{Message: "Game in progress, waiting to join next game.."})
|
||||
}
|
||||
|
||||
g.Unlock()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
if !g.Starting {
|
||||
|
||||
}
|
||||
g.Unlock()
|
||||
}
|
||||
|
||||
func (s *Server) accept() {
|
||||
for {
|
||||
np := <-s.NewPlayers
|
||||
|
@ -182,16 +158,14 @@ func (s *Server) accept() {
|
|||
}
|
||||
|
||||
func (s *Server) handleJoinGame(pl *Player) {
|
||||
s.Log("waiting first msg handle join game ")
|
||||
for e := range pl.In {
|
||||
s.Log("handle join game ", e.Command(), e)
|
||||
if e.Command() == CommandJoinGame {
|
||||
if p, ok := e.(*GameCommandJoinGame); ok {
|
||||
pl.Name = Nickname(p.Name)
|
||||
|
||||
g := s.FindGame(pl, p.GameID)
|
||||
|
||||
s.Log("New player added to game", *pl, p.GameID)
|
||||
s.Logf("Adding %s to game %d", pl.Name, p.GameID)
|
||||
|
||||
go s.handleGameCommands(pl, g)
|
||||
return
|
||||
|
@ -298,7 +272,7 @@ func (s *Server) Listen(address string) {
|
|||
|
||||
listener, err := net.Listen(network, address)
|
||||
if err != nil {
|
||||
log.Fatal("Listen error: ", err)
|
||||
log.Fatalf("failed to listen on %s: %s", address, err)
|
||||
}
|
||||
|
||||
s.listeners = append(s.listeners, listener)
|
||||
|
|
|
@ -366,9 +366,7 @@ func (s *ServerConn) handleWrite() {
|
|||
}
|
||||
|
||||
s.LastTransfer = time.Now()
|
||||
|
||||
err = s.Conn.SetWriteDeadline(time.Time{})
|
||||
|
||||
s.Conn.SetWriteDeadline(time.Time{})
|
||||
s.Done()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,37 +46,38 @@ func (s *SSHServer) Host(newPlayers chan<- *game.IncomingPlayer) {
|
|||
Addr: s.ListenAddress,
|
||||
IdleTimeout: ServerIdleTimeout,
|
||||
Handler: func(sshSession ssh.Session) {
|
||||
ctx := sshSession.Context()
|
||||
|
||||
cmdCtx, cancelCmd := context.WithCancel(ctx)
|
||||
cmd := exec.CommandContext(cmdCtx, s.NetrisBinary, "--nick", game.Nickname(sshSession.User()), "--connect", s.NetrisAddress)
|
||||
ptyReq, winCh, isPty := sshSession.Pty()
|
||||
if isPty {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
|
||||
if !isPty {
|
||||
io.WriteString(sshSession, "failed to start netris: non-interactive terminals are not supported\n")
|
||||
|
||||
f, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
go func() {
|
||||
for win := range winCh {
|
||||
setWinsize(f, win.Width, win.Height)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(f, sshSession)
|
||||
}()
|
||||
io.Copy(sshSession, f)
|
||||
|
||||
cancelCmd()
|
||||
cmd.Wait()
|
||||
} else {
|
||||
io.WriteString(sshSession, "No PTY requested.\n")
|
||||
sshSession.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
cmdCtx, cancelCmd := context.WithCancel(sshSession.Context())
|
||||
|
||||
cmd := exec.CommandContext(cmdCtx, s.NetrisBinary, "--nick", game.Nickname(sshSession.User()), "--connect", s.NetrisAddress)
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
|
||||
|
||||
f, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
go func() {
|
||||
for win := range winCh {
|
||||
setWinsize(f, win.Width, win.Height)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(f, sshSession)
|
||||
}()
|
||||
io.Copy(sshSession, f)
|
||||
|
||||
cancelCmd()
|
||||
cmd.Wait()
|
||||
},
|
||||
PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool {
|
||||
// TODO: Compare public key
|
||||
|
|
|
@ -52,7 +52,7 @@ func (b *Bag) Next() Mino {
|
|||
|
||||
func (b *Bag) shuffle() {
|
||||
if b.Minos == nil {
|
||||
b.Minos = make([]Mino, len(b.Original), len(b.Original))
|
||||
b.Minos = make([]Mino, len(b.Original))
|
||||
}
|
||||
copy(b.Minos, b.Original)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ type Matrix struct {
|
|||
B int `json:"-"` // Buffer height
|
||||
|
||||
M map[int]Block // Matrix
|
||||
O map[int]Block // Overlay
|
||||
O map[int]Block `json:"-"` // Overlay
|
||||
|
||||
Bag *Bag `json:"-"`
|
||||
P *Piece
|
||||
|
@ -35,9 +35,9 @@ type Matrix struct {
|
|||
|
||||
Type MatrixType
|
||||
|
||||
Event chan<- interface{} `json:"-"`
|
||||
Move chan int `json:"-"`
|
||||
draw chan event.DrawObject `json:"-"`
|
||||
Event chan<- interface{} `json:"-"`
|
||||
Move chan int `json:"-"`
|
||||
draw chan event.DrawObject
|
||||
|
||||
Combo int
|
||||
ComboStart time.Time `json:"-"`
|
||||
|
@ -52,7 +52,7 @@ type Matrix struct {
|
|||
|
||||
GameOver bool
|
||||
|
||||
lands []time.Time `json:"-"`
|
||||
lands []time.Time
|
||||
|
||||
sync.Mutex `json:"-"`
|
||||
}
|
||||
|
@ -630,11 +630,11 @@ func (m *Matrix) LowerPiece() {
|
|||
}
|
||||
|
||||
func (m *Matrix) finishLandingPiece() {
|
||||
if m.GameOver || m.P.Landed {
|
||||
if m.GameOver || m.P.landed {
|
||||
return
|
||||
}
|
||||
|
||||
m.P.Landed = true
|
||||
m.P.landed = true
|
||||
|
||||
dropped := false
|
||||
LANDPIECE:
|
||||
|
@ -738,7 +738,7 @@ func (m *Matrix) addToCombo(lines int) int {
|
|||
baseTime := 2.4
|
||||
bonusTime := baseTime / 2
|
||||
|
||||
if time.Now().Sub(m.ComboEnd) > 0 {
|
||||
if time.Until(m.ComboEnd) <= 0 {
|
||||
m.Combo = 0
|
||||
}
|
||||
|
||||
|
@ -787,32 +787,31 @@ func (m *Matrix) CalculateBonusGarbage() int {
|
|||
func (m *Matrix) landPiece() {
|
||||
p := m.P
|
||||
p.Lock()
|
||||
if p.Landing || p.Landed || m.GameOver {
|
||||
if p.landing || p.landed || m.GameOver {
|
||||
p.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
p.Landing = true
|
||||
p.landing = true
|
||||
p.Unlock()
|
||||
|
||||
go func() {
|
||||
landStart := time.Now()
|
||||
|
||||
var t *time.Ticker
|
||||
t = time.NewTicker(100 * time.Millisecond)
|
||||
t := time.NewTicker(100 * time.Millisecond)
|
||||
for {
|
||||
<-t.C
|
||||
|
||||
m.Lock()
|
||||
p.Lock()
|
||||
|
||||
if p.Landed {
|
||||
if p.landed {
|
||||
p.Unlock()
|
||||
m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
if p.Resets > 0 && time.Since(p.LastReset) < 500*time.Millisecond {
|
||||
if p.resets > 0 && time.Since(p.lastReset) < 500*time.Millisecond {
|
||||
p.Unlock()
|
||||
m.Unlock()
|
||||
continue
|
||||
|
|
|
@ -59,7 +59,7 @@ func TestMatrix(t *testing.T) {
|
|||
for i := 0; i < 4; i++ {
|
||||
ok := m.movePiece(1, 0)
|
||||
if !ok {
|
||||
t.Errorf("failed to move piece on iteration %d", i)
|
||||
t.Errorf("failed to Move piece on iteration %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ func TestMatrix(t *testing.T) {
|
|||
for i := 0; i < 7; i++ {
|
||||
ok := m.movePiece(-1, 0)
|
||||
if !ok {
|
||||
t.Errorf("failed to move piece on iteration %d", i)
|
||||
t.Errorf("failed to Move piece on iteration %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,21 +75,17 @@ var AllRotationOffsets = map[PieceType][]RotationOffsets{
|
|||
type Piece struct {
|
||||
Point
|
||||
Mino
|
||||
Original Mino
|
||||
Ghost Block
|
||||
Solid Block
|
||||
Rotation int
|
||||
|
||||
Ghost Block
|
||||
Solid Block
|
||||
|
||||
Rotation int
|
||||
PivotsCW []Point
|
||||
PivotsCCW []Point
|
||||
|
||||
Color int
|
||||
|
||||
Landing bool
|
||||
Resets int
|
||||
LastReset time.Time
|
||||
Landed bool
|
||||
original Mino
|
||||
pivotsCW []Point
|
||||
pivotsCCW []Point
|
||||
resets int
|
||||
lastReset time.Time
|
||||
landing bool
|
||||
landed bool
|
||||
|
||||
sync.Mutex `json:"-"`
|
||||
}
|
||||
|
@ -101,7 +97,7 @@ func (p *Piece) String() string {
|
|||
}
|
||||
|
||||
func NewPiece(m Mino, loc Point) *Piece {
|
||||
p := &Piece{Mino: m, Original: m, Point: loc, Color: 0}
|
||||
p := &Piece{Mino: m, original: m, Point: loc}
|
||||
|
||||
var pieceType PieceType
|
||||
switch m.Canonical().String() {
|
||||
|
@ -138,8 +134,8 @@ func NewPiece(m Mino, loc Point) *Piece {
|
|||
p.Ghost = BlockGhostYellow
|
||||
}
|
||||
|
||||
p.PivotsCW = AllRotationPivotsCW[pieceType]
|
||||
p.PivotsCCW = AllRotationPivotsCCW[pieceType]
|
||||
p.pivotsCW = AllRotationPivotsCW[pieceType]
|
||||
p.pivotsCCW = AllRotationPivotsCCW[pieceType]
|
||||
|
||||
return p
|
||||
}
|
||||
|
@ -179,11 +175,11 @@ func (p *Piece) Rotate(rotations int, direction int) Mino {
|
|||
}
|
||||
|
||||
if (rotationPivot == 3 && direction == 0) || (rotationPivot == 1 && direction == 1) {
|
||||
newMino = p.Original
|
||||
newMino = p.original
|
||||
} else {
|
||||
pp := p.PivotsCW[rotationPivot%RotationStates]
|
||||
pp := p.pivotsCW[rotationPivot%RotationStates]
|
||||
if direction == 1 {
|
||||
pp = p.PivotsCCW[rotationPivot%RotationStates]
|
||||
pp = p.pivotsCCW[rotationPivot%RotationStates]
|
||||
}
|
||||
px, py := pp.X, pp.Y
|
||||
|
||||
|
@ -207,12 +203,12 @@ func (p *Piece) ApplyReset() {
|
|||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if !p.Landing || p.Resets >= 15 {
|
||||
if !p.landing || p.resets >= 15 {
|
||||
return
|
||||
}
|
||||
|
||||
p.Resets++
|
||||
p.LastReset = time.Now()
|
||||
p.resets++
|
||||
p.lastReset = time.Now()
|
||||
}
|
||||
|
||||
func (p *Piece) ApplyRotation(rotations int, direction int) {
|
||||
|
|
Loading…
Reference in a new issue