goonscape/network/network.go

191 lines
4.7 KiB
Go
Raw Permalink Normal View History

2025-01-13 11:10:48 +01:00
package network
2024-10-31 01:06:39 +01:00
import (
2025-01-15 10:50:51 +01:00
"bufio"
"encoding/binary"
"io"
2024-10-31 01:06:39 +01:00
"log"
"net"
"time"
2025-01-13 13:23:52 +01:00
"gitea.boner.be/bdnugget/goonscape/game"
2025-01-13 11:10:48 +01:00
"gitea.boner.be/bdnugget/goonscape/types"
2024-10-31 01:06:39 +01:00
pb "gitea.boner.be/bdnugget/goonserver/actions"
"google.golang.org/protobuf/proto"
)
var serverAddr = "boner.be:6969"
func SetServerAddr(addr string) {
serverAddr = addr
}
2024-10-31 01:06:39 +01:00
func ConnectToServer() (net.Conn, int32, error) {
conn, err := net.Dial("tcp", serverAddr)
2024-10-31 01:06:39 +01:00
if err != nil {
log.Printf("Failed to dial server: %v", err)
return nil, 0, err
}
log.Println("Connected to server. Waiting for player ID...")
2025-01-15 10:58:11 +01:00
reader := bufio.NewReader(conn)
// Read message length (4 bytes)
lengthBuf := make([]byte, 4)
if _, err := io.ReadFull(reader, lengthBuf); err != nil {
log.Printf("Failed to read message length: %v", err)
return nil, 0, err
}
messageLength := binary.BigEndian.Uint32(lengthBuf)
// Read the full message
messageBuf := make([]byte, messageLength)
if _, err := io.ReadFull(reader, messageBuf); err != nil {
log.Printf("Failed to read message body: %v", err)
2024-10-31 01:06:39 +01:00
return nil, 0, err
}
var response pb.ServerMessage
2025-01-15 10:58:11 +01:00
if err := proto.Unmarshal(messageBuf, &response); err != nil {
2024-10-31 01:06:39 +01:00
log.Printf("Failed to unmarshal server response: %v", err)
return nil, 0, err
}
playerID := response.GetPlayerId()
log.Printf("Successfully connected with player ID: %d", playerID)
return conn, playerID, nil
}
func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player, quitChan <-chan struct{}) {
2025-01-15 10:50:51 +01:00
reader := bufio.NewReader(conn)
2025-01-13 10:00:23 +01:00
2025-01-13 11:10:48 +01:00
actionTicker := time.NewTicker(types.ClientTickRate)
2025-01-13 10:00:23 +01:00
defer actionTicker.Stop()
2025-01-18 23:23:03 +01:00
defer conn.Close()
defer close(player.QuitDone)
// Create a channel to signal when goroutines are done
done := make(chan struct{})
2025-01-13 00:31:15 +01:00
2024-10-31 01:06:39 +01:00
go func() {
for {
select {
case <-quitChan:
2025-01-18 23:23:03 +01:00
// Send disconnect message to server
disconnectMsg := &pb.ActionBatch{
PlayerId: playerID,
Actions: []*pb.Action{{
Type: pb.Action_DISCONNECT,
PlayerId: playerID,
}},
}
writeMessage(conn, disconnectMsg)
done <- struct{}{}
return
case <-actionTicker.C:
player.Lock()
if len(player.ActionQueue) > 0 {
actions := make([]*pb.Action, len(player.ActionQueue))
copy(actions, player.ActionQueue)
batch := &pb.ActionBatch{
PlayerId: playerID,
Actions: actions,
Tick: player.CurrentTick,
}
player.ActionQueue = player.ActionQueue[:0]
player.Unlock()
if err := writeMessage(conn, batch); err != nil {
log.Printf("Failed to send actions to server: %v", err)
return
}
} else {
player.Unlock()
2024-10-31 01:06:39 +01:00
}
}
}
}()
for {
select {
case <-quitChan:
2025-01-18 23:23:03 +01:00
<-done // Wait for action goroutine to finish
close(done)
time.Sleep(100 * time.Millisecond) // Give time for disconnect message to be sent
2025-01-15 10:50:51 +01:00
return
default:
// Read message length (4 bytes)
lengthBuf := make([]byte, 4)
if _, err := io.ReadFull(reader, lengthBuf); err != nil {
log.Printf("Failed to read message length: %v", err)
return
}
messageLength := binary.BigEndian.Uint32(lengthBuf)
2025-01-15 10:50:51 +01:00
// Read the full message
messageBuf := make([]byte, messageLength)
if _, err := io.ReadFull(reader, messageBuf); err != nil {
log.Printf("Failed to read message body: %v", err)
return
}
2024-10-31 01:06:39 +01:00
var serverMessage pb.ServerMessage
if err := proto.Unmarshal(messageBuf, &serverMessage); err != nil {
log.Printf("Failed to unmarshal server message: %v", err)
continue
}
2024-10-31 01:06:39 +01:00
player.Lock()
player.CurrentTick = serverMessage.CurrentTick
tickDiff := serverMessage.CurrentTick - player.CurrentTick
if tickDiff > types.MaxTickDesync {
for _, state := range serverMessage.Players {
if state.PlayerId == playerID {
player.ForceResync(state)
break
}
}
}
player.Unlock()
2025-01-13 10:00:23 +01:00
for _, state := range serverMessage.Players {
if state.PlayerId == playerID {
continue
2025-01-13 10:00:23 +01:00
}
2025-01-13 00:31:15 +01:00
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
otherPlayer.UpdatePosition(state, types.ServerTickRate)
} else {
otherPlayers[state.PlayerId] = types.NewPlayer(state)
}
2025-01-13 10:00:23 +01:00
}
if g, ok := player.UserData.(*game.Game); ok && len(serverMessage.ChatMessages) > 0 {
g.Chat.HandleServerMessages(serverMessage.ChatMessages)
2024-10-31 01:06:39 +01:00
}
}
}
}
2025-01-15 10:50:51 +01:00
// Helper function to write length-prefixed messages
func writeMessage(conn net.Conn, msg proto.Message) error {
data, err := proto.Marshal(msg)
if err != nil {
return err
}
// Write length prefix
lengthBuf := make([]byte, 4)
binary.BigEndian.PutUint32(lengthBuf, uint32(len(data)))
if _, err := conn.Write(lengthBuf); err != nil {
return err
}
// Write message body
_, err = conn.Write(data)
return err
}