Only send/recieve new unread chat messages instead of spamming entire bandwidth

This commit is contained in:
bdnugget 2025-04-16 11:51:00 +02:00
parent 555b8118f2
commit b866ac879e
2 changed files with 84 additions and 10 deletions

@ -1 +1 @@
Subproject commit f9ec811b10bbab54e843199eb68156e9e7c143cc
Subproject commit c720b668180d46b8eb37747f9c24d2fa1f49de72

View File

@ -18,7 +18,8 @@ import (
const protoVersion = 1
var serverAddr = "boner.be:6969" // Default server address
var serverAddr = "boner.be:6969" // Default server address
var lastSeenMessageTimestamp int64 = 0 // Track the last message timestamp seen by this client
func SetServerAddr(addr string) {
serverAddr = addr
@ -26,10 +27,32 @@ func SetServerAddr(addr string) {
}
func ConnectToServer(username, password string, isRegistering bool) (net.Conn, int32, error) {
conn, err := net.Dial("tcp", serverAddr)
if err != nil {
log.Printf("Failed to dial server: %v", err)
return nil, 0, err
log.Printf("Connecting to server at %s...", serverAddr)
var err error
var conn net.Conn
// Try connecting with a timeout
connChan := make(chan net.Conn, 1)
errChan := make(chan error, 1)
go func() {
c, e := net.Dial("tcp", serverAddr)
if e != nil {
errChan <- e
return
}
connChan <- c
}()
// Wait for connection with timeout
select {
case conn = <-connChan:
// Connection successful, continue
case err = <-errChan:
return nil, 0, fmt.Errorf("failed to dial server: %v", err)
case <-time.After(5 * time.Second):
return nil, 0, fmt.Errorf("connection timeout after 5 seconds")
}
log.Println("Connected to server. Authenticating...")
@ -54,8 +77,12 @@ func ConnectToServer(username, password string, isRegistering bool) (net.Conn, i
return nil, 0, fmt.Errorf("failed to send auth: %v", err)
}
// Read server response
// Read server response with timeout
reader := bufio.NewReader(conn)
// Set a read deadline for authentication
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
lengthBuf := make([]byte, 4)
if _, err := io.ReadFull(reader, lengthBuf); err != nil {
conn.Close()
@ -63,12 +90,21 @@ func ConnectToServer(username, password string, isRegistering bool) (net.Conn, i
}
messageLength := binary.BigEndian.Uint32(lengthBuf)
// Sanity check message size
if messageLength > 1024*1024 { // 1MB max message size
conn.Close()
return nil, 0, fmt.Errorf("authentication response too large: %d bytes", messageLength)
}
messageBuf := make([]byte, messageLength)
if _, err := io.ReadFull(reader, messageBuf); err != nil {
conn.Close()
return nil, 0, fmt.Errorf("failed to read auth response body: %v", err)
}
// Clear read deadline after authentication
conn.SetReadDeadline(time.Time{})
var response pb.ServerMessage
if err := proto.Unmarshal(messageBuf, &response); err != nil {
conn.Close()
@ -88,6 +124,10 @@ func ConnectToServer(username, password string, isRegistering bool) (net.Conn, i
playerID := response.GetPlayerId()
log.Printf("Successfully authenticated with player ID: %d", playerID)
// Reset the lastSeenMessageTimestamp when reconnecting
lastSeenMessageTimestamp = 0
return conn, playerID, nil
}
@ -110,6 +150,12 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
errChan := make(chan error, 1)
done := make(chan struct{})
// Add a heartbeat ticker to detect connection issues
heartbeatTicker := time.NewTicker(5 * time.Second)
defer heartbeatTicker.Stop()
lastMessageTime := time.Now()
// Start message sending goroutine
go func() {
defer func() {
@ -135,15 +181,32 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
return
case <-done:
return
case <-heartbeatTicker.C:
// If no message has been sent for a while, send a heartbeat
timeSinceLastMessage := time.Since(lastMessageTime)
if timeSinceLastMessage > 5*time.Second {
// Send an empty batch as a heartbeat
emptyBatch := &pb.ActionBatch{
PlayerId: playerID,
LastSeenMessageTimestamp: lastSeenMessageTimestamp,
}
if err := writeMessage(conn, emptyBatch); err != nil {
log.Printf("Failed to send heartbeat: %v", err)
errChan <- err
return
}
lastMessageTime = time.Now()
}
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,
PlayerId: playerID,
Actions: actions,
Tick: player.CurrentTick,
LastSeenMessageTimestamp: lastSeenMessageTimestamp,
}
player.ActionQueue = player.ActionQueue[:0]
player.Unlock()
@ -152,6 +215,7 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
errChan <- err
return
}
lastMessageTime = time.Now()
} else {
player.Unlock()
}
@ -260,6 +324,13 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
if handler, ok := player.UserData.(types.ChatMessageHandler); ok && len(serverMessage.ChatMessages) > 0 {
log.Printf("Received %d chat messages from server", len(serverMessage.ChatMessages))
handler.HandleServerMessages(serverMessage.ChatMessages)
// Update the last seen message timestamp to the most recent message
if len(serverMessage.ChatMessages) > 0 {
lastMsg := serverMessage.ChatMessages[len(serverMessage.ChatMessages)-1]
lastSeenMessageTimestamp = lastMsg.Timestamp
log.Printf("Updated last seen message timestamp to %d", lastSeenMessageTimestamp)
}
}
}
}
@ -268,6 +339,7 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
// Wait for error or quit signal
select {
case <-quitChan:
log.Printf("Received quit signal, sending disconnect message")
// Send disconnect message
disconnectMsg := &pb.ActionBatch{
PlayerId: playerID,
@ -277,8 +349,10 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Play
}},
}
writeMessage(conn, disconnectMsg)
close(done)
case err := <-errChan:
log.Printf("Network error: %v", err)
close(done)
}
}