Broken bullshit

This commit is contained in:
2025-02-14 13:35:09 +01:00
parent a1aeb71512
commit 53cc9bca6b
20 changed files with 590 additions and 207 deletions

View File

@ -2,16 +2,18 @@ package network
import (
"bufio"
"context"
"encoding/binary"
"fmt"
"io"
"log"
"net"
"sync"
"time"
"gitea.boner.be/bdnugget/goonscape/logging"
"gitea.boner.be/bdnugget/goonscape/types"
pb "gitea.boner.be/bdnugget/goonserver/actions"
rl "github.com/gen2brain/raylib-go/raylib"
"google.golang.org/protobuf/proto"
)
@ -19,18 +21,84 @@ const protoVersion = 1
var serverAddr = "boner.be:6969"
type NetworkManager struct {
ctx context.Context
conn net.Conn
reader *bufio.Reader
writer *bufio.Writer
mu sync.Mutex
}
func NewNetworkManager(ctx context.Context) *NetworkManager {
return &NetworkManager{
ctx: ctx,
}
}
func SetServerAddr(addr string) {
serverAddr = addr
}
func ConnectToServer(username, password string, isRegistering bool) (net.Conn, int32, error) {
conn, err := net.Dial("tcp", serverAddr)
func (nm *NetworkManager) Connect(addr string) error {
nm.mu.Lock()
defer nm.mu.Unlock()
var err error
nm.conn, err = net.Dial("tcp", addr)
if err != nil {
log.Printf("Failed to dial server: %v", err)
return nil, 0, err
return err
}
log.Println("Connected to server. Authenticating...")
nm.reader = bufio.NewReader(nm.conn)
nm.writer = bufio.NewWriter(nm.conn)
go nm.readLoop()
return nil
}
func (nm *NetworkManager) readLoop() {
for {
select {
case <-nm.ctx.Done():
return
default:
// Read and process messages
}
}
}
func (nm *NetworkManager) Send(message proto.Message) error {
nm.mu.Lock()
defer nm.mu.Unlock()
data, err := proto.Marshal(message)
if err != nil {
return err
}
// Write length prefix
lengthBuf := make([]byte, 4)
binary.BigEndian.PutUint32(lengthBuf, uint32(len(data)))
if _, err := nm.writer.Write(lengthBuf); err != nil {
return err
}
// Write message body
if _, err := nm.writer.Write(data); err != nil {
return err
}
return nm.writer.Flush()
}
func ConnectToServer(username, password string, isRegistering bool) (net.Conn, int32, error) {
logging.Info.Println("Attempting to connect to server at", serverAddr)
conn, err := net.Dial("tcp", serverAddr)
if err != nil {
logging.Error.Printf("Failed to dial server: %v", err)
return nil, 0, err
}
logging.Info.Println("Connected to server. Authenticating...")
// Send auth message
authAction := &pb.Action{
@ -81,7 +149,7 @@ func ConnectToServer(username, password string, isRegistering bool) (net.Conn, i
if !response.AuthSuccess {
conn.Close()
return nil, 0, fmt.Errorf(response.ErrorMessage)
return nil, 0, fmt.Errorf("authentication failed: %s", response.ErrorMessage)
}
playerID := response.GetPlayerId()
@ -89,145 +157,63 @@ func ConnectToServer(username, password string, isRegistering bool) (net.Conn, i
return conn, playerID, nil
}
func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player, quitChan <-chan struct{}) {
reader := bufio.NewReader(conn)
actionTicker := time.NewTicker(types.ClientTickRate)
defer actionTicker.Stop()
defer conn.Close()
defer close(player.QuitDone)
// Create a channel to signal when goroutines are done
done := make(chan struct{})
// Create a set of current players to track disconnects
currentPlayers := make(map[int32]bool)
go func() {
for {
select {
case <-quitChan:
// 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()
}
}
}
func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers *sync.Map, quitChan <-chan struct{}) {
defer func() {
logging.Info.Println("Closing connection and cleaning up for player", playerID)
conn.Close()
close(player.QuitDone)
}()
reader := bufio.NewReader(conn)
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-quitChan:
done := make(chan struct{})
go func() {
<-done
close(player.QuitDone)
}()
select {
case <-done:
time.Sleep(100 * time.Millisecond)
case <-time.After(1 * time.Second):
log.Println("Shutdown timed out")
}
return
default:
// Read message length (4 bytes)
case <-ticker.C:
// Read message length
lengthBuf := make([]byte, 4)
if _, err := io.ReadFull(reader, lengthBuf); err != nil {
log.Printf("Failed to read message length: %v", err)
return
continue
}
messageLength := binary.BigEndian.Uint32(lengthBuf)
// Read the full message
// Read message body
messageBuf := make([]byte, messageLength)
if _, err := io.ReadFull(reader, messageBuf); err != nil {
log.Printf("Failed to read message body: %v", err)
return
continue
}
// Process server message
var serverMessage pb.ServerMessage
if err := proto.Unmarshal(messageBuf, &serverMessage); err != nil {
log.Printf("Failed to unmarshal server message: %v", err)
continue
}
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()
// Update player states
for _, state := range serverMessage.Players {
currentPlayers[state.PlayerId] = true
if state.PlayerId == playerID {
player.Lock()
// Update initial position if not set
if player.PosActual.X == 0 && player.PosActual.Z == 0 {
player.PosActual = rl.Vector3{
X: float32(state.X * types.TileSize),
Y: 0,
Z: float32(state.Y * types.TileSize),
}
player.PosTile = types.Tile{X: int(state.X), Y: int(state.Y)}
}
player.Unlock()
if state == nil {
logging.Error.Println("Received nil player state")
continue
}
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
otherPlayer.UpdatePosition(state, types.ServerTickRate)
if state.PlayerId == playerID {
player.UpdatePosition(state, types.ServerTickRate)
} else if existing, ok := otherPlayers.Load(state.PlayerId); ok {
existing.(*types.Player).UpdatePosition(state, types.ServerTickRate)
} else {
otherPlayers[state.PlayerId] = types.NewPlayer(state)
newPlayer := types.NewPlayer(state)
otherPlayers.Store(state.PlayerId, newPlayer)
}
}
// Remove players that are no longer in the server state
for id := range otherPlayers {
if !currentPlayers[id] {
delete(otherPlayers, id)
}
}
if handler, ok := player.UserData.(types.ChatMessageHandler); ok && len(serverMessage.ChatMessages) > 0 {
// Handle chat messages
if handler, ok := player.UserData.(types.ChatMessageHandler); ok {
handler.HandleServerMessages(serverMessage.ChatMessages)
}
}