268 lines
9.9 KiB
Python
268 lines
9.9 KiB
Python
import sqlite3
|
|
import os
|
|
import json
|
|
|
|
dummy_is_in = False
|
|
|
|
# 1. Sucht den exakten, absoluten Pfad zu diesem Skript (z.B. /srv/Diceghost-Liga-System/data/)
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
# 2. Klebt den Datenbank-Namen an diesen Ordner
|
|
DB_PATH = os.path.join(BASE_DIR, "league_database.db")
|
|
|
|
def init_db():
|
|
connection = sqlite3.connect(DB_PATH)
|
|
cursor = connection.cursor()
|
|
|
|
# Fremdschlüssel (Foreign Keys) in SQLite aktivieren
|
|
cursor.execute('PRAGMA foreign_keys = ON;')
|
|
|
|
# 1. Tabelle: players (Stammdaten)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS players (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
discord_id TEXT UNIQUE,
|
|
discord_name TEXT NOT NULL,
|
|
discord_avatar_url TEXT,
|
|
display_name TEXT
|
|
)
|
|
''')
|
|
|
|
# 2. Tabelle: gamesystems (Globale Spielsysteme)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS gamesystems (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
picture TEXT,
|
|
description TEXT,
|
|
active_players INTEGER DEFAULT 0,
|
|
min_score INTEGER DEFAULT 0,
|
|
max_score INTEGER DEFAULT 100
|
|
)
|
|
''')
|
|
|
|
# 3. Tabelle: player_game_statistic (Welcher Spieler hat in welchem System welche Stats?)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS player_game_statistic (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
player_id INTEGER,
|
|
gamesystem_id INTEGER,
|
|
mmr INTEGER DEFAULT 1000,
|
|
games_in_system INTEGER DEFAULT 0,
|
|
points INTEGER DEFAULT 0,
|
|
avv_points INTEGER DEFAULT 0,
|
|
last_played TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (player_id) REFERENCES players (id),
|
|
FOREIGN KEY (gamesystem_id) REFERENCES gamesystems (id)
|
|
)
|
|
''')
|
|
|
|
# 4. Tabelle: matches (Wer hat wann gegen wen in welchem System gespielt?)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS matches (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
gamesystem_id INTEGER,
|
|
player1_id INTEGER,
|
|
score_player1 INTEGER,
|
|
player2_id INTEGER,
|
|
score_player2 INTEGER,
|
|
played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
player1_mmr_change INTEGER,
|
|
player2_mmr_change INTEGER,
|
|
player2_check INTEGER DEFAULT 0,
|
|
match_is_counted INTEGER DEFAULT 0,
|
|
FOREIGN KEY (gamesystem_id) REFERENCES gamesystems (id),
|
|
FOREIGN KEY (player1_id) REFERENCES players (id),
|
|
FOREIGN KEY (player2_id) REFERENCES players (id)
|
|
)
|
|
''')
|
|
|
|
# 5. Tabelle: achievements (Der globale Katalog aller möglichen Erfolge - Stammdaten)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS achievements (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
description TEXT NOT NULL,
|
|
icon TEXT
|
|
)
|
|
''')
|
|
|
|
# 6. Tabelle: player_achievements (Wer hat welchen Erfolg wann bekommen? - Bewegungsdaten)
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS player_achievements (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
player_id INTEGER,
|
|
achievement_id INTEGER,
|
|
earned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
earned_in INTEGER,
|
|
FOREIGN KEY (earned_in) REFERENCES gamesystems (id),
|
|
FOREIGN KEY (player_id) REFERENCES players (id),
|
|
FOREIGN KEY (achievement_id) REFERENCES achievements (id)
|
|
)
|
|
''')
|
|
|
|
connection.commit()
|
|
connection.close()
|
|
print("Datenbank Struktur aufgebaut")
|
|
|
|
#nächster Schritt: Standard Spielsysteme eintragen
|
|
seed_gamesystems()
|
|
|
|
|
|
# --------------------
|
|
# --- Start Setup der DB Daten. Damit sie nicht GANZ leer sind.
|
|
# --------------------
|
|
def seed_gamesystems():
|
|
connection = sqlite3.connect(DB_PATH)
|
|
cursor = connection.cursor()
|
|
systems = [
|
|
("Warhammer 40k", "/gui/pictures/wsdg.png", "Die Schlacht um die Galaxie in einer entfernten Zukunft.", 0, 100),
|
|
("Warhammer Age of Sigmar", "/gui/pictures/wsdg.png", "Der ewige Krieg um die Reiche der Sterblichen in einer epischen Fantasy-Welt.", 0, 50),
|
|
("Spearhead", "/gui/pictures/wsdg.png", "Schnelle und taktische Scharmützel für actiongeladene Kämpfe.", 0, 50)
|
|
]
|
|
|
|
# executemany ist eine extrem schnelle SQL For-Schleife für Inserts
|
|
cursor.executemany("INSERT INTO gamesystems (name, picture, description, min_score, max_score) VALUES (?, ?, ?, ?, ?)", systems)
|
|
|
|
connection.commit()
|
|
connection.close()
|
|
print("Spielsysteme angelegt!")
|
|
|
|
#Nächster Schritt: Standard Achievments eintragen.
|
|
generate_default_mmr_rules()
|
|
seed_achievements()
|
|
|
|
def seed_achievements():
|
|
connection = sqlite3.connect(DB_PATH)
|
|
cursor = connection.cursor()
|
|
|
|
# Unsere Start-Stückliste an Erfolgen (Name, Beschreibung, Icon)
|
|
achievements = [
|
|
("Kingslayer", "Hat den Spieler auf Platz 1 besiegt!", "👑"),
|
|
("Unstoppable", "3 Spiele in Folge gewonnen.", "🔥"),
|
|
("First Blood", "Das allererste Ligaspiel absolviert.", "🩸")
|
|
]
|
|
|
|
cursor.executemany("INSERT INTO achievements (name, description, icon) VALUES (?, ?, ?)", achievements)
|
|
|
|
connection.commit()
|
|
connection.close()
|
|
print("Achievements angelegt.")
|
|
|
|
if dummy_is_in:
|
|
seed_dummy_player()
|
|
|
|
|
|
def seed_dummy_player():
|
|
connection = sqlite3.connect(DB_PATH)
|
|
cursor = connection.cursor()
|
|
|
|
# 1. Dummy-Spieler anlegen (falls noch nicht vorhanden)
|
|
query_player = """
|
|
INSERT OR IGNORE INTO players
|
|
(discord_id, discord_name, display_name, discord_avatar_url)
|
|
VALUES (?, ?, ?, ?)
|
|
"""
|
|
cursor.execute(query_player, ("dummy_001", "dummy_user", "Dummy Mc DummDumm", ""))
|
|
|
|
# 2. Wir holen uns die ID des Dummys (egal ob neu oder alt)
|
|
cursor.execute("SELECT id FROM players WHERE discord_id = 'dummy_001'")
|
|
dummy_row = cursor.fetchone()
|
|
|
|
if dummy_row:
|
|
dummy_id = dummy_row[0]
|
|
|
|
# 3. Wir holen alle IDs der aktuellen Spielsysteme
|
|
cursor.execute("SELECT id FROM gamesystems")
|
|
systems = cursor.fetchall()
|
|
|
|
# 4. Wir gehen jedes System durch und prüfen, ob er schon drin ist
|
|
for sys in systems:
|
|
sys_id = sys[0]
|
|
|
|
cursor.execute("SELECT id FROM player_game_statistic WHERE player_id = ? AND gamesystem_id = ?", (dummy_id, sys_id))
|
|
is_in_league = cursor.fetchone()
|
|
|
|
if not is_in_league:
|
|
# Er ist noch nicht drin -> Eintragen! (MMR startet durch DEFAULT automatisch bei 1000)
|
|
cursor.execute("""
|
|
INSERT INTO player_game_statistic (player_id, gamesystem_id)
|
|
VALUES (?, ?)
|
|
""", (dummy_id, sys_id))
|
|
|
|
connection.commit()
|
|
connection.close()
|
|
print("Test-Gegner 'Dummy Mc DummDumm' ist bereit und in allen Ligen angemeldet!")
|
|
|
|
|
|
|
|
def generate_default_mmr_rules():
|
|
"""Erstellt für jedes Spielsystem eine Standard-JSON-Datei, falls sie noch nicht existiert."""
|
|
connection = sqlite3.connect(DB_PATH)
|
|
cursor = connection.cursor()
|
|
|
|
cursor.execute("SELECT name FROM gamesystems")
|
|
systems = cursor.fetchall()
|
|
connection.close()
|
|
|
|
# 1. Sicherstellen, dass der Ordner existiert (Best Practice!)
|
|
folder_path = "mmr_calculations"
|
|
os.makedirs(folder_path, exist_ok=True)
|
|
|
|
# 2. Wir gehen jedes gefundene Spielsystem durch
|
|
for sys in systems:
|
|
sys_name = sys[0]
|
|
|
|
# Wir machen den Namen "dateisicher" (z.B. "Warhammer 40k" -> "warhammer_40k")
|
|
safe_name = sys_name.replace(" ", "_").lower()
|
|
file_path = os.path.join(folder_path, f"mmr_rules_{safe_name}.json")
|
|
|
|
# 3. SICHERHEITS-CHECK: Existiert die Datei schon?
|
|
# Wenn ja, ignorieren wir sie, damit wir dein händisches Balancing nicht überschreiben!
|
|
if not os.path.exists(file_path):
|
|
|
|
# Das ist unsere Standard-Vorlage (Faktor 10)
|
|
default_rules = {
|
|
"system_info": f"Balancing für {sys_name}",
|
|
"draw_point_difference": 3,
|
|
"rank_matrix": {
|
|
"10": {"win": 10, "draw": 30},
|
|
"9": {"win": 10, "draw": 30},
|
|
"8": {"win": 10, "draw": 20},
|
|
"7": {"win": 10, "draw": 20},
|
|
"6": {"win": 20, "draw": 10},
|
|
"5": {"win": 20, "draw": 10},
|
|
"4": {"win": 20, "draw": 0},
|
|
"3": {"win": 20, "draw": 0},
|
|
"2": {"win": 30, "draw": 0},
|
|
"1": {"win": 30, "draw": 0},
|
|
"0": {"win": 30, "draw": 0},
|
|
"-1": {"win": 30, "draw": 0},
|
|
"-2": {"win": 40, "draw": 0},
|
|
"-3": {"win": 40, "draw": -10},
|
|
"-4": {"win": 50, "draw": -20},
|
|
"-5": {"win": 60, "draw": -20},
|
|
"-6": {"win": 70, "draw": -20},
|
|
"-7": {"win": 80, "draw": -50},
|
|
"-8": {"win": 100, "draw": -50},
|
|
"-9": {"win": 120, "draw": -60},
|
|
"-10": {"win": 150, "draw": -60}
|
|
},
|
|
"score_bonus": [
|
|
{"min_diff": 95, "bonus": 40},
|
|
{"min_diff": 85, "bonus": 30},
|
|
{"min_diff": 65, "bonus": 20},
|
|
{"min_diff": 35, "bonus": 10},
|
|
{"min_diff": 0, "bonus": 0}
|
|
]
|
|
}
|
|
|
|
# 4. JSON-Datei schreiben
|
|
# 'w' steht für write (schreiben). indent=4 macht es für Menschen schön lesbar formatiert.
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
json.dump(default_rules, f, indent=4, ensure_ascii=False)
|
|
|
|
print(f"Neu: Balancing-Datei für '{sys_name}' wurde erstellt -> {file_path}")
|
|
else:
|
|
print(f"OK: Balancing-Datei für '{sys_name}' existiert bereits.")
|
|
|