Introduce core components for "Escape From Teacher" game: server, client, physics, asset system, and protocol definitions. Add Docker-Compose setup for Redis and NATS infrastructure.
This commit is contained in:
146
cmd/server/main.go
Normal file
146
cmd/server/main.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/game"
|
||||
"git.zb-server.de/ZB-Server/EscapeFromTeacher/pkg/server"
|
||||
)
|
||||
|
||||
// Globaler Zustand des Servers
|
||||
var (
|
||||
rooms = make(map[string]*server.Room)
|
||||
playerSessions = make(map[string]*server.Room)
|
||||
mu sync.RWMutex
|
||||
globalWorld *game.World
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("🚀 Escape From Teacher SERVER startet...")
|
||||
|
||||
// 1. WELT & ASSETS LADEN
|
||||
globalWorld = game.NewWorld()
|
||||
loadServerAssets(globalWorld)
|
||||
|
||||
// 2. NATS VERBINDUNG
|
||||
natsURL := "nats://localhost:4222"
|
||||
nc, err := nats.Connect(natsURL)
|
||||
if err != nil {
|
||||
log.Fatal("❌ Konnte nicht zu NATS verbinden: ", err)
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
ec, err := nats.NewEncodedConn(nc, nats.JSON_ENCODER)
|
||||
if err != nil {
|
||||
log.Fatal("❌ JSON Encoder Fehler: ", err)
|
||||
}
|
||||
log.Println("✅ Verbunden mit NATS unter", natsURL)
|
||||
|
||||
// 3. HANDLER: GAME JOIN
|
||||
sub, err := ec.Subscribe("game.join", func(req *game.JoinRequest) {
|
||||
log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s", req.Name, req.RoomID)
|
||||
|
||||
playerID := req.Name
|
||||
if playerID == "" {
|
||||
playerID = "Unknown"
|
||||
}
|
||||
|
||||
roomID := req.RoomID
|
||||
if roomID == "" {
|
||||
roomID = "lobby"
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
// Raum finden oder erstellen
|
||||
room, exists := rooms[roomID]
|
||||
if !exists {
|
||||
log.Printf("🆕 Erstelle neuen Raum: '%s'", roomID)
|
||||
room = server.NewRoom(roomID, nc, globalWorld)
|
||||
rooms[roomID] = room
|
||||
|
||||
// Starte den Game-Loop (Physik)
|
||||
go room.RunLoop()
|
||||
}
|
||||
|
||||
// Spieler hinzufügen (ID, Name)
|
||||
room.AddPlayer(playerID, req.Name)
|
||||
|
||||
// Session speichern
|
||||
playerSessions[playerID] = room
|
||||
log.Printf("➡️ Spieler '%s' ist Raum '%s' beigetreten.", playerID, roomID)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("❌ Fehler beim Subscribe auf game.join:", err)
|
||||
}
|
||||
log.Printf("👂 Lausche auf 'game.join'... (Sub Valid: %v)", sub.IsValid())
|
||||
|
||||
// TEST: Auch mit Raw-NATS lauschen
|
||||
nc.Subscribe("game.join", func(m *nats.Msg) {
|
||||
log.Printf("🔍 RAW NATS: Nachricht empfangen auf game.join: %s", string(m.Data))
|
||||
})
|
||||
|
||||
// 4. HANDLER: INPUT
|
||||
_, _ = ec.Subscribe("game.input", func(input *game.ClientInput) {
|
||||
mu.RLock()
|
||||
room, ok := playerSessions[input.PlayerID]
|
||||
mu.RUnlock()
|
||||
|
||||
if ok {
|
||||
room.HandleInput(*input)
|
||||
}
|
||||
})
|
||||
|
||||
log.Println("✅ Server bereit. Warte auf Spieler...")
|
||||
|
||||
// Block forever
|
||||
select {}
|
||||
}
|
||||
|
||||
func loadServerAssets(w *game.World) {
|
||||
assetDir := "./cmd/client/assets"
|
||||
chunkDir := filepath.Join(assetDir, "chunks")
|
||||
|
||||
// Manifest laden
|
||||
manifestPath := filepath.Join(assetDir, "assets.json")
|
||||
data, err := ioutil.ReadFile(manifestPath)
|
||||
if err == nil {
|
||||
var m game.AssetManifest
|
||||
json.Unmarshal(data, &m)
|
||||
w.Manifest = m
|
||||
log.Printf("📦 Manifest geladen: %d Assets", len(m.Assets))
|
||||
} else {
|
||||
log.Println("⚠️ Manifest nicht gefunden:", manifestPath)
|
||||
}
|
||||
|
||||
// Chunks laden
|
||||
files, err := ioutil.ReadDir(chunkDir)
|
||||
if err == nil {
|
||||
for _, f := range files {
|
||||
if filepath.Ext(f.Name()) == ".json" {
|
||||
fullPath := filepath.Join(chunkDir, f.Name())
|
||||
cData, err := ioutil.ReadFile(fullPath)
|
||||
if err == nil {
|
||||
var chunk game.Chunk
|
||||
json.Unmarshal(cData, &chunk)
|
||||
if chunk.ID == "" {
|
||||
chunk.ID = f.Name()[0 : len(f.Name())-5]
|
||||
}
|
||||
w.ChunkLibrary[chunk.ID] = chunk
|
||||
log.Printf("🧩 Chunk geladen: %s", chunk.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Println("⚠️ Chunk Ordner nicht gefunden:", chunkDir)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user