Private
Public Access
1
0

Introduce room assignment logic based on POD_NAME and TOTAL_REPLICAS, enable selective handling for game.join and score.submit events, and update environment configurations.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m28s

This commit is contained in:
Sebastian Unterschütz
2026-01-04 17:16:09 +01:00
parent a17a6f5e9f
commit 8f49a691f7
2 changed files with 68 additions and 7 deletions

View File

@@ -21,11 +21,22 @@ var (
playerSessions = make(map[string]*server.Room)
mu sync.RWMutex
globalWorld *game.World
serverID string // Eindeutige Server-ID für diesen Pod
)
func main() {
log.Println("🚀 Escape From Teacher SERVER startet...")
// 0. Server-ID generieren (Hostname oder zufällig)
serverID = os.Getenv("HOSTNAME")
if serverID == "" {
serverID = os.Getenv("POD_NAME")
}
if serverID == "" {
serverID = "server-" + time.Now().Format("150405")
}
log.Printf("🆔 Server-ID: %s", serverID)
// 1. WELT & ASSETS LADEN
globalWorld = game.NewWorld()
loadServerAssets(globalWorld)
@@ -100,10 +111,8 @@ func main() {
}
log.Printf("✅ Verbunden mit NATS: %s", natsURL)
// 3. HANDLER: GAME JOIN (mit Queue Group für Load Balancing)
sub, err := ec.QueueSubscribe("game.join", "game-servers", func(req *game.JoinRequest) {
log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s", req.Name, req.RoomID)
// 3. HANDLER: GAME JOIN (broadcast - alle Pods hören, aber nur zuständiger erstellt)
sub, err := ec.Subscribe("game.join", func(req *game.JoinRequest) {
playerID := req.Name
if playerID == "" {
playerID = "Unknown"
@@ -114,13 +123,21 @@ func main() {
roomID = "lobby"
}
log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s", req.Name, roomID)
// Prüfe ob dieser Pod für den Raum zuständig ist
if !isResponsibleForRoom(roomID) {
log.Printf("⏭️ Überspringe JOIN - nicht zuständig für Raum '%s'", roomID)
return
}
mu.Lock()
defer mu.Unlock()
// Raum finden oder erstellen
room, exists := rooms[roomID]
if !exists {
log.Printf("🆕 Erstelle neuen Raum: '%s'", roomID)
log.Printf("🆕 Erstelle neuen Raum: '%s' (zuständiger Pod)", roomID)
room = server.NewRoom(roomID, nc, globalWorld)
rooms[roomID] = room
@@ -170,8 +187,8 @@ func main() {
}
})
// 6. HANDLER: SCORE SUBMISSION
_, _ = ec.Subscribe("score.submit", func(submission *game.ScoreSubmission) {
// 6. HANDLER: SCORE SUBMISSION (Queue Group - nur ein Pod speichert)
_, _ = ec.QueueSubscribe("score.submit", "score-handlers", func(submission *game.ScoreSubmission) {
// Verwende Team-Name wenn vorhanden (Coop-Mode), sonst Player-Name (Solo-Mode)
displayName := submission.PlayerName
if submission.TeamName != "" {
@@ -234,6 +251,44 @@ func getEnv(key, defaultValue string) string {
return defaultValue
}
// isResponsibleForRoom prüft ob dieser Pod für den Raum zuständig ist
func isResponsibleForRoom(roomID string) bool {
// Wenn nur 1 Replica läuft, sind wir immer zuständig
totalReplicas := getEnv("TOTAL_REPLICAS", "1")
if totalReplicas == "1" {
return true
}
// Hash-basierte Zuweisung: RoomID → Pod
// Einfacher Ansatz: erster Buchstabe von RoomID
// A-M → Pod 0, N-Z → Pod 1
if len(roomID) == 0 {
return true
}
firstChar := roomID[0]
// Für 2 Replicas: A-M und N-Z splitten
if totalReplicas == "2" {
// Pod Namen sind meist: escape-game-0, escape-game-1, etc.
if firstChar <= 'M' || firstChar <= 'm' {
return serverID[len(serverID)-1] == '0' || !hasDigitSuffix()
}
return serverID[len(serverID)-1] == '1' || hasDigitSuffix()
}
// Fallback: immer zuständig
return true
}
func hasDigitSuffix() bool {
if len(serverID) == 0 {
return false
}
lastChar := serverID[len(serverID)-1]
return lastChar >= '0' && lastChar <= '9'
}
func loadServerAssets(w *game.World) {
assetDir := "./cmd/client/web/assets"
chunkDir := filepath.Join(assetDir, "chunks")