Skip to content

Commit

Permalink
setup 2way server communciation for network play
Browse files Browse the repository at this point in the history
  • Loading branch information
Warsinger committed Aug 11, 2024
1 parent ce04562 commit ae3de29
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 55 deletions.
67 changes: 38 additions & 29 deletions game/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/leap-fish/necs/router"
"github.com/yohamta/donburi"
)

Expand All @@ -22,12 +23,11 @@ type Scene interface {
}
type GameData struct {
world donburi.World
clientWorld donburi.World
scenes []Scene
width, height, speed int
gameStats *scenes.GameStats
debug bool
server *network.Server
client *network.Client
}

func NewGame(width, height, speed int, debug bool, server, client string) (*GameData, error) {
Expand All @@ -43,60 +43,69 @@ func NewGame(width, height, speed int, debug bool, server, client string) (*Game
game := &GameData{world: donburi.NewWorld(), width: width, height: height, speed: speed, gameStats: gameStats, debug: debug}

if server != "" {
ebiten.SetWindowTitle("Tower Defense (server)")
fmt.Printf("listening on port %v\n", server)
game.server = network.NewServer(game.world, "", server)
err = game.server.Start()
gameserver := network.NewServer(game.world, "", server)
err = gameserver.Start()
if err != nil {
return nil, err
}
}

if client != "" {
fmt.Printf("connect to %v\n", client)
game.client = network.NewClientNewWorld(client)
err = game.client.Start()
router.On(func(sender *router.NetworkClient, message network.ClientConnectMessage) {
fmt.Println("recv client connect message")
game.startClient(message.Address)
})
game.registerStartGame()
} else if client != "" {
ebiten.SetWindowTitle("Tower Defense (client)")
err := game.startClient(client)
if err != nil {
return nil, err
}
game.registerStartGame()
}

if game.client != nil {
err = game.switchToViewer()
} else {
err = game.switchToTitle(gameStats)
}
err = game.switchToTitle(gameStats)
if err != nil {
return nil, err
}
return game, nil
}

func (g *GameData) switchToViewer() error {
scene, err := scenes.NewViewerScene(g.client.World, g.width, g.height, g.debug, g.client == nil)
func (g *GameData) registerStartGame() {
router.On(func(sender *router.NetworkClient, message network.StartGameMessage) {
fmt.Println("recv start game message")
g.switchToBattle(false)
})

}

func (g *GameData) startClient(address string) error {
fmt.Printf("connect to %v\n", address)
gameclient, err := network.NewClientNewWorld(address)
if err != nil {
return err
}
g.clientWorld = gameclient.World
err = gameclient.Start(g.world)
if err != nil {
return err
}
ebiten.SetWindowSize(g.width, g.height)
g.scenes = []Scene{scene}
return nil
}

func (g *GameData) switchToBattle(viewerMode bool) error {
func (g *GameData) switchToBattle(broadcast bool) error {
if broadcast {
router.Broadcast(network.StartGameMessage{})
}
battle, err := scenes.NewBattleScene(g.world, g.width, g.height, g.speed, g.gameStats, g.debug, g.switchToTitle)
if err != nil {
return err
}
battle.Init()
g.scenes = []Scene{battle}

if viewerMode || g.client != nil {
var world donburi.World
if g.client != nil {
world = g.client.World
} else {
world = g.world
}
scene, err := scenes.NewViewerScene(world, g.width, g.height, g.debug, g.client == nil)
g.scenes = []Scene{battle}
if g.clientWorld != nil {
scene, err := scenes.NewViewerScene(g.clientWorld, g.width, g.height, g.debug, true)
if err != nil {
return err
}
Expand Down
68 changes: 58 additions & 10 deletions network/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package network
import (
"context"
"fmt"
"log"
"net"
"net/url"
"strconv"

"github.com/leap-fish/necs/esync/clisync"
"github.com/leap-fish/necs/router"
Expand All @@ -15,33 +19,77 @@ type Client struct {
Transport *transports.WsClientTransport
Network *router.NetworkClient
World donburi.World
port string
}

func NewClient(world donburi.World, address string) *Client {
return &Client{
World: world,
Transport: transports.NewWsClientTransport(address),
func NewClientNewWorld(address string) (*Client, error) {

url, err := url.ParseRequestURI(address)
if err != nil {
fmt.Printf("Error parsing address: %s, %v\n", address, err)
return nil, err
}
}
func NewClientNewWorld(address string) *Client {
port := url.Port()
return &Client{
World: donburi.NewWorld(),
Transport: transports.NewWsClientTransport(address),
}
port: port,
}, nil
}

func (c *Client) Start() error {
func (c *Client) Start(world donburi.World) error {
router.OnConnect(func(client *router.NetworkClient) {
fmt.Println("Client connected")
fmt.Println("Client connected, starting server")
// start server on a port one higher than the port we connected on and send the address to the server so it can connect back to us
port, err := strconv.Atoi(c.port)
if err != nil {
log.Fatalf("Error getting port: %v", err)
}
port++
address, err := getIPAddress()
if err != nil {
log.Fatalf("Error getting address: %v", err)
}
server := NewServer(world, address, c.port)
err = server.Start()
if err != nil {
log.Fatalf("Error starting server: %v", err)
}
connStr := fmt.Sprintf("ws://%s:%d", address, port)
c.Network.SendMessage(ClientConnectMessage{connStr})
})
RegisterComponenets()
clisync.RegisterClient(c.World)

fmt.Println("registered world")
go func() {
c.Transport.Start(func(conn *websocket.Conn) {
fmt.Println("starting client connection")
c.Network = router.NewNetworkClient(context.Background(), conn)
})
}()

return nil
}

func getIPAddress() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", err
}
var ip net.IP
for _, addr := range addrs {
switch v := addr.(type) {
case *net.IPNet:
if !v.IP.IsLoopback() {
if v.IP.To4() != nil { //Verify if IP is IPV4
ip = v.IP
}
}
}
}
if ip != nil {
return ip.String(), nil
} else {
return "", err
}
}
3 changes: 2 additions & 1 deletion network/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ func (s *Server) Start() error {
router.OnDisconnect(func(sender *router.NetworkClient, err error) {
fmt.Printf("Client %s disconnected from the server! / Reason [%s]\n", sender.Id(), err)
})

RegisterComponenets()
srvsync.UseEsync(s.world)

go s.startTicking()
go s.StartHost()
go s.startTicking()

return nil
}
Expand Down
6 changes: 6 additions & 0 deletions network/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ func RegisterComponenets() {
_ = esync.RegisterComponent(23, comp.LevelData{}, comp.Level)
_ = esync.RegisterComponent(24, scenes.BattleSceneState{}, scenes.BattleState)
}

type ClientConnectMessage struct {
Address string
}

type StartGameMessage struct{}
5 changes: 1 addition & 4 deletions scenes/battle.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"tower-defense/config"

"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text/v2"
"github.com/leap-fish/necs/esync/srvsync"
Expand Down Expand Up @@ -300,7 +299,6 @@ func (b *BattleScene) End() {

func (b *BattleScene) Draw(screen *ebiten.Image) {
comp.DrawBoard(screen, b.world, b.config, b.DrawText)
comp.DrawTextLines(screen, assets.InfoFace, fmt.Sprintf("Timer %d", b.creepTimer), comp.TextBorder, 100, text.AlignStart, text.AlignStart)
}

func (b *BattleScene) DrawText(screen *ebiten.Image) {
Expand All @@ -317,8 +315,7 @@ func (b *BattleScene) DrawText(screen *ebiten.Image) {
b.battleState.Draw(screen, width, height)

if b.config.IsDebug() {
str := fmt.Sprintf("Speed %v\nTPS %2.1f", b.speed, ebiten.ActualTPS())
ebitenutil.DebugPrintAt(screen, str, 5, 400)
comp.DrawTextLines(screen, assets.InfoFace, fmt.Sprintf("Speed %v\nTPS %2.1f\nCreep Timer %d", b.speed, ebiten.ActualTPS(), b.creepTimer), comp.TextBorder, 400, text.AlignStart, text.AlignStart)
}
}

Expand Down
17 changes: 6 additions & 11 deletions scenes/title.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,19 @@ type TitleScene struct {
width int
height int
gameStats *GameStats
newGameCallback func(bool) error
viewer bool
newGameCallback NewGameCallback
}
type NewGameCallback func(broadcast bool) error

func NewTitleScene(width, height int, gameStats *GameStats, newGameCallback func(bool) error) (*TitleScene, error) {
func NewTitleScene(width, height int, gameStats *GameStats, newGameCallback NewGameCallback) (*TitleScene, error) {
return &TitleScene{width: width, height: height, gameStats: gameStats, newGameCallback: newGameCallback}, nil
}

func (t *TitleScene) Update() error {
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) || ebiten.IsKeyPressed(ebiten.KeySpace) {
return t.newGameCallback(t.viewer)
}
if inpututil.IsKeyJustPressed(ebiten.KeyV) {
t.viewer = !t.viewer
return t.newGameCallback(true)
}

return nil
}

Expand Down Expand Up @@ -77,8 +75,5 @@ func (t *TitleScene) Draw(screen *ebiten.Image) {

nextY = 600
str = "Click or press space to start"
nextY = comp.DrawTextLines(screen, assets.ScoreFace, str, width, nextY, text.AlignCenter, text.AlignStart)

str = fmt.Sprintf("Viewer mode %v (Press V to toggle)", t.viewer)
_ = comp.DrawTextLines(screen, assets.InfoFace, str, width, nextY, text.AlignCenter, text.AlignStart)
_ = comp.DrawTextLines(screen, assets.ScoreFace, str, width, nextY, text.AlignCenter, text.AlignStart)
}

0 comments on commit ae3de29

Please sign in to comment.