feature/menu #3

Merged
bdnugget merged 4 commits from feature/menu into master 2025-01-18 22:26:19 +00:00
3 changed files with 80 additions and 65 deletions
Showing only changes of commit d86cbe15a3 - Show all commits

View File

@ -17,6 +17,7 @@ type Game struct {
Music rl.Music Music rl.Music
Chat *Chat Chat *Chat
MenuOpen bool MenuOpen bool
QuitChan chan struct{} // Channel to signal shutdown
} }
func New() *Game { func New() *Game {
@ -37,7 +38,8 @@ func New() *Game {
Fovy: 45.0, Fovy: 45.0,
Projection: rl.CameraPerspective, Projection: rl.CameraPerspective,
}, },
Chat: NewChat(), Chat: NewChat(),
QuitChan: make(chan struct{}),
} }
game.Player.UserData = game game.Player.UserData = game
game.Chat.userData = game game.Chat.userData = game
@ -259,6 +261,7 @@ func (g *Game) DrawMenu() {
case "Settings": case "Settings":
// TODO: Implement settings // TODO: Implement settings
case "Exit Game": case "Exit Game":
close(g.QuitChan) // Signal all goroutines to shut down
rl.CloseWindow() rl.CloseWindow()
} }
} }

View File

@ -52,7 +52,7 @@ func main() {
game.Player.Model = game.Models[modelIndex].Model game.Player.Model = game.Models[modelIndex].Model
game.Player.Texture = game.Models[modelIndex].Texture game.Player.Texture = game.Models[modelIndex].Texture
go network.HandleServerCommunication(conn, playerID, game.Player, game.OtherPlayers) go network.HandleServerCommunication(conn, playerID, game.Player, game.OtherPlayers, game.QuitChan)
rl.PlayMusicStream(game.Music) rl.PlayMusicStream(game.Music)
rl.SetMusicVolume(game.Music, 0.5) rl.SetMusicVolume(game.Music, 0.5)
@ -65,4 +65,7 @@ func main() {
game.Update(deltaTime) game.Update(deltaTime)
game.Render() game.Render()
} }
// Wait for clean shutdown
<-game.QuitChan
} }

View File

@ -56,89 +56,98 @@ func ConnectToServer() (net.Conn, int32, error) {
return conn, playerID, nil return conn, playerID, nil
} }
func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player) { func HandleServerCommunication(conn net.Conn, playerID int32, player *types.Player, otherPlayers map[int32]*types.Player, quitChan <-chan struct{}) {
// Create a buffered reader for the connection
reader := bufio.NewReader(conn) reader := bufio.NewReader(conn)
actionTicker := time.NewTicker(types.ClientTickRate) actionTicker := time.NewTicker(types.ClientTickRate)
defer actionTicker.Stop() defer actionTicker.Stop()
go func() { go func() {
for range actionTicker.C { for {
player.Lock() select {
if len(player.ActionQueue) > 0 { case <-quitChan:
actions := make([]*pb.Action, len(player.ActionQueue)) return
copy(actions, player.ActionQueue) case <-actionTicker.C:
player.Lock()
if len(player.ActionQueue) > 0 {
actions := make([]*pb.Action, len(player.ActionQueue))
copy(actions, player.ActionQueue)
batch := &pb.ActionBatch{ batch := &pb.ActionBatch{
PlayerId: playerID, PlayerId: playerID,
Actions: actions, Actions: actions,
Tick: player.CurrentTick, 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()
} }
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()
} }
} }
}() }()
for { for {
// Read message length (4 bytes) select {
lengthBuf := make([]byte, 4) case <-quitChan:
if _, err := io.ReadFull(reader, lengthBuf); err != nil {
log.Printf("Failed to read message length: %v", err)
return return
} default:
messageLength := binary.BigEndian.Uint32(lengthBuf) // Read message length (4 bytes)
lengthBuf := make([]byte, 4)
// Read the full message if _, err := io.ReadFull(reader, lengthBuf); err != nil {
messageBuf := make([]byte, messageLength) log.Printf("Failed to read message length: %v", err)
if _, err := io.ReadFull(reader, messageBuf); err != nil { return
log.Printf("Failed to read message body: %v", err)
return
}
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
}
} }
} messageLength := binary.BigEndian.Uint32(lengthBuf)
player.Unlock()
for _, state := range serverMessage.Players { // Read the full message
if state.PlayerId == playerID { messageBuf := make([]byte, messageLength)
if _, err := io.ReadFull(reader, messageBuf); err != nil {
log.Printf("Failed to read message body: %v", err)
return
}
var serverMessage pb.ServerMessage
if err := proto.Unmarshal(messageBuf, &serverMessage); err != nil {
log.Printf("Failed to unmarshal server message: %v", err)
continue continue
} }
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists { player.Lock()
otherPlayer.UpdatePosition(state, types.ServerTickRate) player.CurrentTick = serverMessage.CurrentTick
} else {
otherPlayers[state.PlayerId] = types.NewPlayer(state)
}
}
if g, ok := player.UserData.(*game.Game); ok && len(serverMessage.ChatMessages) > 0 { tickDiff := serverMessage.CurrentTick - player.CurrentTick
g.Chat.HandleServerMessages(serverMessage.ChatMessages) if tickDiff > types.MaxTickDesync {
for _, state := range serverMessage.Players {
if state.PlayerId == playerID {
player.ForceResync(state)
break
}
}
}
player.Unlock()
for _, state := range serverMessage.Players {
if state.PlayerId == playerID {
continue
}
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
otherPlayer.UpdatePosition(state, types.ServerTickRate)
} else {
otherPlayers[state.PlayerId] = types.NewPlayer(state)
}
}
if g, ok := player.UserData.(*game.Game); ok && len(serverMessage.ChatMessages) > 0 {
g.Chat.HandleServerMessages(serverMessage.ChatMessages)
}
} }
} }
} }