package main import ( "context" "encoding/json" "log" "os" "sort" "github.com/redis/go-redis/v9" ) const ( Gravity = 1.8 JumpPower = -20.0 HighJumpPower = -28.0 GroundY = 350.0 PlayerHeight = 50.0 PlayerYBase = GroundY - PlayerHeight BaseSpeed = 15.0 GameWidth = 800.0 ) var ( ctx = context.Background() rdb *redis.Client defaultConfig GameConfig adminUser string adminPass string ) func getEnv(key, fallback string) string { if value, ok := os.LookupEnv(key); ok { return value } return fallback } func initGameConfig() { defaultConfig = GameConfig{ Obstacles: []ObstacleDef{ // --- HINDERNISSE --- {ID: "desk", Type: "obstacle", Width: 50, Height: 65, Color: "#ff0000", Image: "desk.png", YOffset: -19, ImgScale: 1.3, ImgOffsetX: 1, ImgOffsetY: 3}, // desk {ID: "teacher", Type: "teacher", Width: 30, Height: 60, Color: "#000080", Image: "teacher1.png"}, {ID: "k-m", Type: "teacher", Width: 45, Height: 80, Color: "#ff0000", Image: "k-m.png", YOffset: 5, ImgScale: 1.2, ImgOffsetX: -1, ImgOffsetY: 8}, // k-m {ID: "w-l", Type: "teacher", Width: 50, Height: 70, Color: "#ff0000", Image: "w-l.png", ImgScale: 1.1, ImgOffsetX: 1, ImgOffsetY: 3, CanTalk: true, SpeechLines: []string{"Halt!", "Handy weg!"}}, // w-l {ID: "trashcan", Type: "obstacle", Width: 25, Height: 35, Color: "#555", Image: "trash1.png"}, {ID: "eraser1", Type: "obstacle", Width: 56, Height: 37, Color: "#ff0000", Image: "eraser.png", YOffset: 35, ImgScale: 1.6, ImgOffsetY: 9}, // eraser1 {ID: "principal", Type: "teacher", Width: 40, Height: 70, Color: "#000", Image: "principal1.png", CanTalk: true, SpeechLines: []string{"EXMATRIKULATION!"}}, // --- COINS --- {ID: "coin0", Type: "coin", Width: 40, Height: 73, Color: "#ff0000", Image: "coin.png", ImgScale: 1.1, ImgOffsetY: 1}, {ID: "coin1", Type: "coin", Width: 40, Height: 73, Color: "#ff0000", Image: "coin.png", YOffset: 60, ImgScale: 1.1, ImgOffsetY: 1}, // --- POWERUPS --- {ID: "p_god", Type: "powerup", Width: 30, Height: 30, Color: "cyan", Image: "powerup_god1.png", YOffset: 20.0}, // Godmode {ID: "p_bat", Type: "powerup", Width: 30, Height: 30, Color: "red", Image: "powerup_bat1.png", YOffset: 20.0}, // Schläger {ID: "p_boot", Type: "powerup", Width: 30, Height: 30, Color: "lime", Image: "powerup_boot1.png", YOffset: 20.0}, // Boots }, Backgrounds: []string{"school-background.jpg", "gym-background.jpg", "school2-background.jpg"}, } log.Println("✅ Config mit Powerups geladen") defaultConfig.Chunks = loadChunksFromRedis() } func loadChunksFromRedis() []ChunkDef { if rdb == nil { return []ChunkDef{} } ids, err := rdb.SMembers(ctx, "config:chunks:list").Result() if err != nil { log.Println("Redis: Keine Chunks geladen") return []ChunkDef{} } sort.Strings(ids) var loadedChunks []ChunkDef for _, id := range ids { val, err := rdb.Get(ctx, "config:chunks:data:"+id).Result() if err == nil { var c ChunkDef json.Unmarshal([]byte(val), &c) c.ID = id loadedChunks = append(loadedChunks, c) } } if len(defaultConfig.Chunks) == 0 { log.Printf("📦 Lade %d Chunks aus Redis", len(loadedChunks)) } return loadedChunks }