Updated to Multi-Lobby-Service
This commit is contained in:
226
main.go
226
main.go
@@ -37,6 +37,52 @@ type GuildConfig struct {
|
||||
Language string `json:"language"` // Neue Eigenschaft für Sprache
|
||||
}
|
||||
|
||||
type LobbyRule struct {
|
||||
LobbyName string
|
||||
CategoryName string
|
||||
TimeoutMin int
|
||||
}
|
||||
|
||||
func getLobbyRules(guildID string) ([]LobbyRule, error) {
|
||||
rows, err := db.Query(`SELECT lobby_name, category_name, timeout_min FROM lobby_rule WHERE guild_id = ?`, guildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var rules []LobbyRule
|
||||
for rows.Next() {
|
||||
var r LobbyRule
|
||||
if err := rows.Scan(&r.LobbyName, &r.CategoryName, &r.TimeoutMin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules = append(rules, r)
|
||||
}
|
||||
return rules, rows.Err()
|
||||
}
|
||||
|
||||
func upsertLobbyRule(guildID, lobby, category string, timeout int) error {
|
||||
if timeout < 1 {
|
||||
timeout = 1
|
||||
}
|
||||
_, err := db.Exec(`
|
||||
INSERT INTO lobby_rule (guild_id, lobby_name, category_name, timeout_min)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(guild_id, lobby_name) DO UPDATE SET
|
||||
category_name=excluded.category_name,
|
||||
timeout_min=excluded.timeout_min
|
||||
`, guildID, lobby, category, timeout)
|
||||
return err
|
||||
}
|
||||
|
||||
func deleteLobbyRule(guildID, lobby string) (bool, error) {
|
||||
res, err := db.Exec(`DELETE FROM lobby_rule WHERE guild_id=? AND lobby_name=?`, guildID, lobby)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
n, _ := res.RowsAffected()
|
||||
return n > 0, nil
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
// ===== Global variables for sync.Map =====
|
||||
@@ -56,6 +102,25 @@ func getLanguage(guildID string) string {
|
||||
return cfg.Language
|
||||
}
|
||||
|
||||
// neue Tabelle für mehrere Lobby-Regeln pro Guild
|
||||
func ensureLobbyRuleTable() {
|
||||
const create = `
|
||||
CREATE TABLE IF NOT EXISTS lobby_rule (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
guild_id TEXT NOT NULL,
|
||||
lobby_name TEXT NOT NULL,
|
||||
category_name TEXT NOT NULL,
|
||||
timeout_min INTEGER NOT NULL DEFAULT 60,
|
||||
UNIQUE (guild_id, lobby_name)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_lobby_rule_guild ON lobby_rule(guild_id);
|
||||
`
|
||||
_, err := db.Exec(create)
|
||||
if err != nil {
|
||||
log.Fatalf("Fehler beim Erstellen lobby_rule: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Hinzufügen der 'language' Spalte, falls sie nicht existiert
|
||||
func addLanguageColumnIfNotExists() {
|
||||
// Überprüfen, ob die Tabelle 'guild_config' existiert
|
||||
@@ -103,6 +168,7 @@ func initDB() {
|
||||
|
||||
// Neue Spalte für die Sprache hinzufügen, wenn sie noch nicht existiert
|
||||
addLanguageColumnIfNotExists()
|
||||
ensureLobbyRuleTable()
|
||||
|
||||
}
|
||||
|
||||
@@ -410,20 +476,62 @@ func onVoiceStateUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) {
|
||||
if e.UserID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 1) Versuch: Regeln aus DB
|
||||
rules, err := getLobbyRules(e.GuildID)
|
||||
if err != nil {
|
||||
log.Printf("getLobbyRules: %v", err)
|
||||
}
|
||||
if len(rules) > 0 {
|
||||
// checke, ob der Join in eine der konfigurierten Lobbys erfolgte
|
||||
var matched *LobbyRule
|
||||
for idx := range rules {
|
||||
lobbyID := findVoiceChannelIDByName(s, e.GuildID, rules[idx].LobbyName)
|
||||
if lobbyID != "" && e.ChannelID == lobbyID && (e.BeforeUpdate == nil || e.BeforeUpdate.ChannelID != lobbyID) {
|
||||
matched = &rules[idx]
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched == nil {
|
||||
return
|
||||
}
|
||||
|
||||
m, _ := s.GuildMember(e.GuildID, e.UserID)
|
||||
if m != nil && m.User.Bot {
|
||||
return
|
||||
}
|
||||
|
||||
catID, err := findOrCreateCategoryID(s, e.GuildID, matched.CategoryName)
|
||||
if err != nil {
|
||||
log.Printf("Kategorie: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = createPrivateVCAndMove(s, e.GuildID, e.UserID, safeDisplayName(m), catID, 0, matched.TimeoutMin, e.ChannelID)
|
||||
if err != nil {
|
||||
log.Printf("VC/Move: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 2) Fallback: alte Single-Config (deine bisherige Logik)
|
||||
cfg := getCfg(e.GuildID)
|
||||
lobby := findVoiceChannelIDByName(s, e.GuildID, cfg.LobbyName)
|
||||
if lobby == "" || e.ChannelID != lobby || (e.BeforeUpdate != nil && e.BeforeUpdate.ChannelID == lobby) {
|
||||
return
|
||||
}
|
||||
|
||||
m, err := s.GuildMember(e.GuildID, e.UserID)
|
||||
if err == nil && m.User.Bot {
|
||||
return
|
||||
}
|
||||
|
||||
catID, err := findOrCreateCategoryID(s, e.GuildID, cfg.CategoryName)
|
||||
if err != nil {
|
||||
log.Printf("Kategorie-Auflösung fehlgeschlagen: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = createPrivateVCAndMove(s, e.GuildID, e.UserID, safeDisplayName(m), catID, 0, cfg.TimeoutMin, lobby)
|
||||
if err != nil {
|
||||
log.Printf("VC-Erstellung/Move fehlgeschlagen: %v", err)
|
||||
@@ -824,6 +932,100 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter
|
||||
},
|
||||
})
|
||||
|
||||
case "addlobby":
|
||||
if !isGuildAdmin(s, guildID, i.User, i.Member) {
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: "❌ Admins only.", Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
return
|
||||
}
|
||||
var lobby, category string
|
||||
timeout := int64(envTimeoutDefault(60))
|
||||
for _, o := range data.Options {
|
||||
switch o.Name {
|
||||
case "lobby":
|
||||
lobby = o.StringValue()
|
||||
case "category":
|
||||
category = o.StringValue()
|
||||
case "timeout":
|
||||
timeout = o.IntValue()
|
||||
}
|
||||
}
|
||||
if lobby == "" || category == "" { /* antworten mit Fehler */
|
||||
}
|
||||
if err := upsertLobbyRule(guildID, lobby, category, int(timeout)); err != nil {
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("⚠️ Failed: %v", err), Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
return
|
||||
}
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("✅ Rule saved: lobby \"%s\" → category \"%s\" (timeout %d min).", lobby, category, timeout), Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
|
||||
case "removelobby":
|
||||
if !isGuildAdmin(s, guildID, i.User, i.Member) { /* gleiche Admin-Antwort */
|
||||
return
|
||||
}
|
||||
var lobby string
|
||||
for _, o := range data.Options {
|
||||
if o.Name == "lobby" {
|
||||
lobby = o.StringValue()
|
||||
}
|
||||
}
|
||||
if lobby == "" { /* Fehlerantwort */
|
||||
return
|
||||
}
|
||||
removed, err := deleteLobbyRule(guildID, lobby)
|
||||
if err != nil {
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("⚠️ Failed: %v", err), Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
return
|
||||
}
|
||||
msg := "ℹ️ No rule found."
|
||||
if removed {
|
||||
msg = "✅ Rule removed."
|
||||
}
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: msg, Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
|
||||
case "listlobbies":
|
||||
if !isGuildAdmin(s, guildID, i.User, i.Member) { /* Admin-Antwort */
|
||||
return
|
||||
}
|
||||
rules, err := getLobbyRules(guildID)
|
||||
if err != nil {
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: fmt.Sprintf("⚠️ Failed: %v", err), Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
return
|
||||
}
|
||||
if len(rules) == 0 {
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: "ℹ️ No lobby rules configured (fallback to single-config).", Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
return
|
||||
}
|
||||
// kompakte Ausgabe
|
||||
var b strings.Builder
|
||||
b.WriteString("**Configured lobby rules:**\n")
|
||||
for _, r := range rules {
|
||||
fmt.Fprintf(&b, "• Lobby: `%s` → Category: `%s`, Timeout: `%d min`\n", r.LobbyName, r.CategoryName, r.TimeoutMin)
|
||||
}
|
||||
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{Content: b.String(), Flags: discordgo.MessageFlagsEphemeral},
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -911,6 +1113,29 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "addlobby",
|
||||
Description: "Adds/updates a lobby rule (lobby → category → timeout)",
|
||||
DefaultMemberPermissions: &adminPerm,
|
||||
Options: []*discordgo.ApplicationCommandOption{
|
||||
{Type: discordgo.ApplicationCommandOptionString, Name: "lobby", Description: "Lobby voice channel name", Required: true},
|
||||
{Type: discordgo.ApplicationCommandOptionString, Name: "category", Description: "Category for private rooms", Required: true},
|
||||
{Type: discordgo.ApplicationCommandOptionInteger, Name: "timeout", Description: "Timeout in minutes (>=1)", Required: false, MaxValue: 480},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "removelobby",
|
||||
Description: "Removes a lobby rule by lobby name",
|
||||
DefaultMemberPermissions: &adminPerm,
|
||||
Options: []*discordgo.ApplicationCommandOption{
|
||||
{Type: discordgo.ApplicationCommandOptionString, Name: "lobby", Description: "Lobby voice channel name", Required: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "listlobbies",
|
||||
Description: "Lists all lobby rules for this guild",
|
||||
DefaultMemberPermissions: &adminPerm,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -935,7 +1160,6 @@ func main() {
|
||||
|
||||
loadTranslationsFromFile(GetENV("TRANSLATIONS_FILE", "./language.json"))
|
||||
token := GetENV("DISCORD_TOKEN", "")
|
||||
token = "MTQwMzg1MTM5NDQ1MjI5MTU4NA.GVi04l.qjraLIbFdi_N49UcSUv_BqK89ihb6xXY648J7A"
|
||||
if token == "" {
|
||||
log.Fatal("Bitte setze DISCORD_TOKEN")
|
||||
}
|
||||
|
Reference in New Issue
Block a user