042a1d4773
* introduced central package registry by package init function * dynamic registration of routes, model, migrations and initializers. * setting a docker compose project name to prevent shutdown of other containers with the same (composer)name * ai documentation * app template * Create tests for ALL API entpoints in ALL packages Based on current data. Ensure that all API endpoints used in frontend are tested. These tests are crucial for the next refactoring tasks. * adopting agent instructions for a more consistent coding style * added desired module layout and debugging information * Fix All Failing tests All failing tests are fixed now that makes the refactoring more easy since all tests must pass * restored routes for maintenance * added common translations * added new tests for API Endpoint * Merge branch 'separate_business_logic' * added lern and skill improvement cost editing * Set Docker image tag when building to prevent rebuild when nothing has changed * add and remove PP for Weaponskill fixed * add and remove PP for same named skills fixed * add new task
351 lines
12 KiB
Go
351 lines
12 KiB
Go
package gsmaster
|
|
|
|
import (
|
|
"bamort/database"
|
|
"bamort/bmrt/models"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
// EnhanceLearningDataWithExistingTables ergänzt die neuen Lernkosten-Tabellen mit Daten aus den bereits vorhandenen Tabellen
|
|
func EnhanceLearningDataWithExistingTables() error {
|
|
log.Println("Starting enhancement of learning data with existing tables...")
|
|
|
|
// 1. Fertigkeiten aus der bestehenden Skill-Tabelle in SkillCategoryDifficulty einbinden
|
|
if err := linkExistingSkillsToCategories(); err != nil {
|
|
return fmt.Errorf("failed to link existing skills to categories: %w", err)
|
|
}
|
|
|
|
// 2. Zauber aus der bestehenden Spell-Tabelle mit Zauberschulen verknüpfen
|
|
if err := linkExistingSpellsToSchools(); err != nil {
|
|
return fmt.Errorf("failed to link existing spells to schools: %w", err)
|
|
}
|
|
|
|
// 3. Charaktere aus der bestehenden Character-Tabelle mit Charakterklassen verknüpfen
|
|
if err := linkExistingCharactersToClasses(); err != nil {
|
|
return fmt.Errorf("failed to link existing characters to classes: %w", err)
|
|
}
|
|
|
|
// 4. Fehlende Fertigkeiten aus der bestehenden Tabelle zu den Kategorien hinzufügen
|
|
if err := addMissingSkillsToCategories(); err != nil {
|
|
return fmt.Errorf("failed to add missing skills to categories: %w", err)
|
|
}
|
|
|
|
// 5. Verknüpfe bestehende Fertigkeiten und Zauber mit Standardquellen
|
|
if err := linkExistingItemsToDefaultSources(); err != nil {
|
|
return fmt.Errorf("failed to link existing items to default sources: %w", err)
|
|
}
|
|
|
|
log.Println("Enhancement completed successfully!")
|
|
return nil
|
|
}
|
|
|
|
// linkExistingSkillsToCategories verknüpft vorhandene Fertigkeiten mit Kategorien und Schwierigkeiten
|
|
func linkExistingSkillsToCategories() error {
|
|
var skills []models.Skill
|
|
if err := database.DB.Find(&skills).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch existing skills: %w", err)
|
|
}
|
|
|
|
for _, skill := range skills {
|
|
// Prüfe ob bereits Verknüpfungen für diese Fertigkeit existieren
|
|
var existingLinks []models.SkillCategoryDifficulty
|
|
if err := database.DB.Where("skill_id = ?", skill.ID).Find(&existingLinks).Error; err != nil {
|
|
return fmt.Errorf("failed to check existing links for skill %s: %w", skill.Name, err)
|
|
}
|
|
|
|
// Wenn bereits Verknüpfungen existieren, überspringe
|
|
if len(existingLinks) > 0 {
|
|
log.Printf("Skill %s already has category links, skipping", skill.Name)
|
|
continue
|
|
}
|
|
|
|
// Suche nach der Fertigkeit in den lerningCostsData
|
|
category, difficulty := findSkillInLearningData(skill.Name)
|
|
if category == "" {
|
|
log.Printf("Warning: Skill %s not found in learning data, using default category", skill.Name)
|
|
// Verwende eine Standard-Kategorie basierend auf der bestehenden Category
|
|
if skill.Category != "" {
|
|
category = skill.Category
|
|
difficulty = skill.Difficulty
|
|
if difficulty == "" {
|
|
difficulty = "normal"
|
|
}
|
|
} else {
|
|
category = "Unbekannt"
|
|
difficulty = "normal"
|
|
}
|
|
}
|
|
|
|
// Erstelle Verknüpfung
|
|
if err := createSkillCategoryLink(skill.ID, skill.Name, category, difficulty); err != nil {
|
|
log.Printf("Warning: Failed to create category link for skill %s: %v", skill.Name, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// linkExistingSpellsToSchools verknüpft vorhandene Zauber mit Zauberschulen
|
|
func linkExistingSpellsToSchools() error {
|
|
var spells []models.Spell
|
|
if err := database.DB.Find(&spells).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch existing spells: %w", err)
|
|
}
|
|
|
|
for _, spell := range spells {
|
|
// Prüfe ob die Zauberschule existiert
|
|
if spell.Category == "" {
|
|
log.Printf("Warning: Spell %s has no category, skipping", spell.Name)
|
|
continue
|
|
}
|
|
|
|
var spellSchool models.SpellSchool
|
|
if err := spellSchool.FirstByName(spell.Category); err != nil {
|
|
// Zauberschule existiert nicht, erstelle sie
|
|
newSchool := models.SpellSchool{
|
|
Name: spell.Category,
|
|
GameSystemId: 1,
|
|
}
|
|
if err := newSchool.Create(); err != nil {
|
|
log.Printf("Warning: Failed to create spell school %s for spell %s: %v", spell.Category, spell.Name, err)
|
|
continue
|
|
}
|
|
log.Printf("Created new spell school: %s", spell.Category)
|
|
}
|
|
|
|
log.Printf("Spell %s linked to school %s", spell.Name, spell.Category)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// linkExistingCharactersToClasses verknüpft vorhandene Charaktere mit Charakterklassen
|
|
func linkExistingCharactersToClasses() error {
|
|
var characters []models.Char
|
|
if err := database.DB.Find(&characters).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch existing characters: %w", err)
|
|
}
|
|
|
|
// Lade alle verfügbaren Charakterklassen aus der Datenbank
|
|
var characterClasses []models.CharacterClass
|
|
if err := database.DB.Find(&characterClasses).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch character classes from database: %w", err)
|
|
}
|
|
|
|
// Erstelle Mapping-Maps für beide Richtungen (Code->Klasse und Name->Klasse)
|
|
codeToClass := make(map[string]models.CharacterClass)
|
|
nameToClass := make(map[string]models.CharacterClass)
|
|
|
|
for _, class := range characterClasses {
|
|
codeToClass[class.Code] = class
|
|
nameToClass[class.Name] = class
|
|
}
|
|
|
|
for _, character := range characters {
|
|
var characterClass models.CharacterClass
|
|
var found bool
|
|
|
|
// Versuche zuerst über Code zu finden (falls character.Typ bereits ein Code ist)
|
|
if class, exists := codeToClass[character.Typ]; exists {
|
|
characterClass = class
|
|
found = true
|
|
} else if class, exists := nameToClass[character.Typ]; exists {
|
|
// Wenn nicht über Code gefunden, versuche über vollständigen Namen
|
|
characterClass = class
|
|
found = true
|
|
}
|
|
|
|
if !found {
|
|
log.Printf("Warning: Character class '%s' not found in database for character %s", character.Typ, character.Name)
|
|
continue
|
|
}
|
|
|
|
log.Printf("Character %s linked to class %s (%s)", character.Name, characterClass.Code, characterClass.Name)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// addMissingSkillsToCategories fügt Fertigkeiten hinzu, die in der Datenbank existieren aber nicht in den Lernkosten-Daten
|
|
func addMissingSkillsToCategories() error {
|
|
var skills []models.Skill
|
|
if err := database.DB.Find(&skills).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch skills: %w", err)
|
|
}
|
|
|
|
for _, skill := range skills {
|
|
// Prüfe ob bereits Kategorien-Verknüpfungen existieren
|
|
var count int64
|
|
if err := database.DB.Model(&models.SkillCategoryDifficulty{}).Where("skill_id = ?", skill.ID).Count(&count).Error; err != nil {
|
|
return fmt.Errorf("failed to count category links for skill %s: %w", skill.Name, err)
|
|
}
|
|
|
|
if count == 0 {
|
|
// Keine Kategorien-Verknüpfung gefunden, erstelle eine Standard-Verknüpfung
|
|
category := "Unbekannt"
|
|
difficulty := "normal"
|
|
|
|
// Verwende bestehende Kategorie falls vorhanden
|
|
if skill.Category != "" {
|
|
category = skill.Category
|
|
}
|
|
if skill.Difficulty != "" {
|
|
difficulty = skill.Difficulty
|
|
}
|
|
|
|
if err := createSkillCategoryLink(skill.ID, skill.Name, category, difficulty); err != nil {
|
|
log.Printf("Warning: Failed to create default category link for skill %s: %v", skill.Name, err)
|
|
} else {
|
|
log.Printf("Created default category link for skill %s: %s - %s", skill.Name, category, difficulty)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Hilfsfunktionen
|
|
|
|
// findSkillInLearningData sucht eine Fertigkeit in den learningCostsData und gibt Kategorie und Schwierigkeit zurück
|
|
func findSkillInLearningData(skillName string) (string, string) {
|
|
for categoryName, difficulties := range learningCostsData.ImprovementCost {
|
|
for difficultyName, data := range difficulties {
|
|
for _, skill := range data.Skills {
|
|
if skill == skillName {
|
|
return categoryName, difficultyName
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return "", ""
|
|
}
|
|
|
|
// createSkillCategoryLink erstellt eine Verknüpfung zwischen Fertigkeit, Kategorie und Schwierigkeit
|
|
func createSkillCategoryLink(skillID uint, skillName, categoryName, difficultyName string) error {
|
|
// Hole oder erstelle die Kategorie
|
|
var skillCategory models.SkillCategory
|
|
gs := GetGameSystem(0, "midgard")
|
|
if err := skillCategory.FirstByName(categoryName); err != nil {
|
|
// Kategorie existiert nicht, erstelle sie
|
|
skillCategory = models.SkillCategory{
|
|
Name: categoryName,
|
|
GameSystemId: gs.ID,
|
|
}
|
|
if err := skillCategory.Create(); err != nil {
|
|
return fmt.Errorf("failed to create skill category %s: %w", categoryName, err)
|
|
}
|
|
log.Printf("Created new skill category: %s", categoryName)
|
|
}
|
|
|
|
// Hole oder erstelle die Schwierigkeit
|
|
var skillDifficulty models.SkillDifficulty
|
|
if err := skillDifficulty.FirstByName(difficultyName); err != nil {
|
|
// Schwierigkeit existiert nicht, erstelle sie
|
|
skillDifficulty = models.SkillDifficulty{
|
|
Name: difficultyName,
|
|
GameSystemId: gs.ID,
|
|
}
|
|
if err := skillDifficulty.Create(); err != nil {
|
|
return fmt.Errorf("failed to create skill difficulty %s: %w", difficultyName, err)
|
|
}
|
|
log.Printf("Created new skill difficulty: %s", difficultyName)
|
|
}
|
|
|
|
// Bestimme LearnCost basierend auf den learningCostsData
|
|
learnCost := 2 // Standard-Wert
|
|
if categoryData, exists := learningCostsData.ImprovementCost[categoryName]; exists {
|
|
if difficultyData, exists := categoryData[difficultyName]; exists {
|
|
learnCost = difficultyData.LearnCost
|
|
}
|
|
}
|
|
|
|
// Erstelle die Verknüpfung
|
|
categoryDifficulty := models.SkillCategoryDifficulty{
|
|
SkillID: skillID,
|
|
SkillCategoryID: skillCategory.ID,
|
|
SkillDifficultyID: skillDifficulty.ID,
|
|
LearnCost: learnCost,
|
|
}
|
|
|
|
if err := categoryDifficulty.Create(); err != nil {
|
|
return fmt.Errorf("failed to create skill category difficulty link: %w", err)
|
|
}
|
|
|
|
log.Printf("Created skill category link: %s - %s - %s (Learn: %d LE)", skillName, categoryName, difficultyName, learnCost)
|
|
return nil
|
|
}
|
|
|
|
// CreateLearningCostsTables erstellt alle neuen Tabellen für das Lernkosten-System
|
|
func CreateLearningCostsTables() error {
|
|
log.Println("Creating learning costs tables...")
|
|
|
|
// Liste aller neuen Modelle
|
|
models := []interface{}{
|
|
&models.Source{},
|
|
&models.CharacterClass{},
|
|
&models.SkillCategory{},
|
|
&models.SkillDifficulty{},
|
|
&models.SpellSchool{},
|
|
&models.ClassCategoryEPCost{},
|
|
&models.ClassSpellSchoolEPCost{},
|
|
&models.SpellLevelLECost{},
|
|
&models.SkillCategoryDifficulty{},
|
|
&models.SkillImprovementCost{},
|
|
}
|
|
|
|
// Erstelle oder migriere alle Tabellen
|
|
for _, model := range models {
|
|
if err := database.DB.AutoMigrate(model); err != nil {
|
|
return fmt.Errorf("failed to migrate table for model %T: %w", model, err)
|
|
}
|
|
}
|
|
|
|
log.Println("Learning costs tables created successfully!")
|
|
return nil
|
|
}
|
|
|
|
// linkExistingItemsToDefaultSources verknüpft bestehende Fertigkeiten und Zauber mit Standardquellen
|
|
func linkExistingItemsToDefaultSources() error {
|
|
// Hole die Standardquellen
|
|
var kodSource models.Source
|
|
if err := kodSource.FirstByCode("KOD"); err != nil {
|
|
return fmt.Errorf("KOD source not found: %w", err)
|
|
}
|
|
|
|
var arkSource models.Source
|
|
if err := arkSource.FirstByCode("ARK"); err != nil {
|
|
return fmt.Errorf("ARK source not found: %w", err)
|
|
}
|
|
|
|
// Verknüpfe Fertigkeiten mit KOD (falls noch keine Quelle zugeordnet)
|
|
var skills []models.Skill
|
|
if err := database.DB.Where("source_id IS NULL OR source_id = 0").Find(&skills).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch skills without source: %w", err)
|
|
}
|
|
|
|
for _, skill := range skills {
|
|
if err := database.DB.Model(&skill).Update("source_id", kodSource.ID).Error; err != nil {
|
|
log.Printf("Warning: Failed to update source for skill %s: %v", skill.Name, err)
|
|
} else {
|
|
log.Printf("Linked skill %s to source KOD", skill.Name)
|
|
}
|
|
}
|
|
|
|
// Verknüpfe Zauber mit ARK (falls noch keine Quelle zugeordnet)
|
|
var spells []models.Spell
|
|
if err := database.DB.Where("source_id IS NULL OR source_id = 0").Find(&spells).Error; err != nil {
|
|
return fmt.Errorf("failed to fetch spells without source: %w", err)
|
|
}
|
|
|
|
for _, spell := range spells {
|
|
if err := database.DB.Model(&spell).Update("source_id", arkSource.ID).Error; err != nil {
|
|
log.Printf("Warning: Failed to update source for spell %s: %v", spell.Name, err)
|
|
} else {
|
|
log.Printf("Linked spell %s to source ARK", spell.Name)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|