131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net"
|
|
"time"
|
|
|
|
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func ConnectToServer() (net.Conn, int32, error) {
|
|
// Attempt to connect to the server
|
|
conn, err := net.Dial("tcp", serverAddr)
|
|
if err != nil {
|
|
log.Printf("Failed to dial server: %v", err)
|
|
return nil, 0, err
|
|
}
|
|
|
|
log.Println("Connected to server. Waiting for player ID...")
|
|
// Buffer for incoming server message
|
|
buf := make([]byte, 1024)
|
|
n, err := conn.Read(buf)
|
|
if err != nil {
|
|
log.Printf("Error reading player ID from server: %v", err)
|
|
return nil, 0, err
|
|
}
|
|
|
|
log.Printf("Received data: %x", buf[:n])
|
|
|
|
// Unmarshal server message to extract the player ID
|
|
var response pb.ServerMessage
|
|
if err := proto.Unmarshal(buf[:n], &response); err != nil {
|
|
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 *Player, otherPlayers map[int32]*Player) {
|
|
buf := make([]byte, 4096)
|
|
|
|
// Ticker for sending actions
|
|
actionTicker := time.NewTicker(ClientTickRate)
|
|
defer actionTicker.Stop()
|
|
|
|
go func() {
|
|
for range actionTicker.C {
|
|
player.Lock()
|
|
if len(player.ActionQueue) > 0 {
|
|
// Bundle all actions that occurred during this tick
|
|
actions := make([]*pb.Action, len(player.ActionQueue))
|
|
copy(actions, player.ActionQueue) // Copy to avoid holding lock while sending
|
|
|
|
// Create a batch message
|
|
batch := &pb.ActionBatch{
|
|
PlayerId: playerID,
|
|
Actions: actions,
|
|
Tick: player.CurrentTick,
|
|
}
|
|
|
|
// Clear the action queue after copying
|
|
player.ActionQueue = player.ActionQueue[:0]
|
|
player.Unlock()
|
|
|
|
// Serialize and send the batch
|
|
data, err := proto.Marshal(batch)
|
|
if err != nil {
|
|
log.Printf("Failed to marshal action batch: %v", err)
|
|
continue
|
|
}
|
|
|
|
if _, err = conn.Write(data); err != nil {
|
|
log.Printf("Failed to send actions to server: %v", err)
|
|
return
|
|
}
|
|
} else {
|
|
player.Unlock()
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Main loop to handle receiving updates from the server
|
|
for {
|
|
n, err := conn.Read(buf)
|
|
if err != nil {
|
|
log.Printf("Failed to read from server: %v", err)
|
|
return
|
|
}
|
|
|
|
var serverMessage pb.ServerMessage
|
|
if err := proto.Unmarshal(buf[:n], &serverMessage); err != nil {
|
|
log.Printf("Failed to unmarshal server message: %v", err)
|
|
continue
|
|
}
|
|
|
|
// Update game state with received data
|
|
player.Lock()
|
|
player.CurrentTick = serverMessage.CurrentTick
|
|
|
|
// Check for desync
|
|
tickDiff := serverMessage.CurrentTick - player.CurrentTick
|
|
if tickDiff > MaxTickDesync {
|
|
// Force resync if we're too far behind
|
|
for _, state := range serverMessage.Players {
|
|
if state.PlayerId == playerID {
|
|
player.ForceResync(state)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
player.Unlock()
|
|
|
|
// Update other players
|
|
for _, state := range serverMessage.Players {
|
|
if state.PlayerId == playerID {
|
|
continue // Skip self
|
|
}
|
|
|
|
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
|
|
otherPlayer.UpdatePosition(state, ServerTickRate)
|
|
} else {
|
|
otherPlayers[state.PlayerId] = NewPlayer(state)
|
|
}
|
|
}
|
|
}
|
|
}
|