eq2go/internal/factions/database.go

264 lines
8.1 KiB
Go

package factions
import (
"fmt"
"time"
"eq2emu/internal/database"
)
// DatabaseAdapter implements the factions.Database interface using our database wrapper
type DatabaseAdapter struct {
db *database.DB
}
// NewDatabaseAdapter creates a new database adapter for factions
func NewDatabaseAdapter(db *database.DB) *DatabaseAdapter {
return &DatabaseAdapter{db: db}
}
// LoadAllFactions loads all factions from the database
func (da *DatabaseAdapter) LoadAllFactions() ([]*Faction, error) {
// Create factions table if it doesn't exist
if err := da.db.Exec(`
CREATE TABLE IF NOT EXISTS factions (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
type TEXT,
description TEXT,
negative_change INTEGER DEFAULT 0,
positive_change INTEGER DEFAULT 0,
default_value INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`); err != nil {
return nil, fmt.Errorf("failed to create factions table: %w", err)
}
var factions []*Faction
err := da.db.Query("SELECT id, name, type, description, negative_change, positive_change, default_value FROM factions", func(row *database.Row) error {
faction := &Faction{
ID: int32(row.Int64(0)),
Name: row.Text(1),
Type: row.Text(2),
Description: row.Text(3),
NegativeChange: int16(row.Int64(4)),
PositiveChange: int16(row.Int64(5)),
DefaultValue: int32(row.Int64(6)),
}
factions = append(factions, faction)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to load factions: %w", err)
}
return factions, nil
}
// SaveFaction saves a faction to the database
func (da *DatabaseAdapter) SaveFaction(faction *Faction) error {
if faction == nil {
return fmt.Errorf("faction is nil")
}
// Use INSERT OR REPLACE to handle both insert and update
err := da.db.Exec(`
INSERT OR REPLACE INTO factions (id, name, type, description, negative_change, positive_change, default_value, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`, faction.ID, faction.Name, faction.Type, faction.Description,
faction.NegativeChange, faction.PositiveChange, faction.DefaultValue, time.Now().Unix())
if err != nil {
return fmt.Errorf("failed to save faction %d: %w", faction.ID, err)
}
return nil
}
// DeleteFaction deletes a faction from the database
func (da *DatabaseAdapter) DeleteFaction(factionID int32) error {
err := da.db.Exec("DELETE FROM factions WHERE id = ?", factionID)
if err != nil {
return fmt.Errorf("failed to delete faction %d: %w", factionID, err)
}
return nil
}
// LoadHostileFactionRelations loads all hostile faction relations
func (da *DatabaseAdapter) LoadHostileFactionRelations() ([]*FactionRelation, error) {
// Create faction_relations table if it doesn't exist
if err := da.db.Exec(`
CREATE TABLE IF NOT EXISTS faction_relations (
faction_id INTEGER NOT NULL,
related_faction_id INTEGER NOT NULL,
is_hostile INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (faction_id, related_faction_id),
FOREIGN KEY (faction_id) REFERENCES factions(id),
FOREIGN KEY (related_faction_id) REFERENCES factions(id)
)
`); err != nil {
return nil, fmt.Errorf("failed to create faction_relations table: %w", err)
}
var relations []*FactionRelation
err := da.db.Query("SELECT faction_id, related_faction_id FROM faction_relations WHERE is_hostile = 1",
func(row *database.Row) error {
relation := &FactionRelation{
FactionID: int32(row.Int64(0)),
HostileFactionID: int32(row.Int64(1)),
}
relations = append(relations, relation)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to load hostile faction relations: %w", err)
}
return relations, nil
}
// LoadFriendlyFactionRelations loads all friendly faction relations
func (da *DatabaseAdapter) LoadFriendlyFactionRelations() ([]*FactionRelation, error) {
var relations []*FactionRelation
err := da.db.Query("SELECT faction_id, related_faction_id FROM faction_relations WHERE is_hostile = 0",
func(row *database.Row) error {
relation := &FactionRelation{
FactionID: int32(row.Int64(0)),
FriendlyFactionID: int32(row.Int64(1)),
}
relations = append(relations, relation)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to load friendly faction relations: %w", err)
}
return relations, nil
}
// SaveFactionRelation saves a faction relation to the database
func (da *DatabaseAdapter) SaveFactionRelation(relation *FactionRelation) error {
if relation == nil {
return fmt.Errorf("faction relation is nil")
}
var relatedFactionID int32
var isHostile int
if relation.HostileFactionID != 0 {
relatedFactionID = relation.HostileFactionID
isHostile = 1
} else if relation.FriendlyFactionID != 0 {
relatedFactionID = relation.FriendlyFactionID
isHostile = 0
} else {
return fmt.Errorf("faction relation has no related faction ID")
}
err := da.db.Exec(`
INSERT OR REPLACE INTO faction_relations (faction_id, related_faction_id, is_hostile)
VALUES (?, ?, ?)
`, relation.FactionID, relatedFactionID, isHostile)
if err != nil {
return fmt.Errorf("failed to save faction relation %d -> %d: %w",
relation.FactionID, relatedFactionID, err)
}
return nil
}
// DeleteFactionRelation deletes a faction relation from the database
func (da *DatabaseAdapter) DeleteFactionRelation(factionID, relatedFactionID int32, isHostile bool) error {
hostileFlag := 0
if isHostile {
hostileFlag = 1
}
err := da.db.Exec("DELETE FROM faction_relations WHERE faction_id = ? AND related_faction_id = ? AND is_hostile = ?",
factionID, relatedFactionID, hostileFlag)
if err != nil {
return fmt.Errorf("failed to delete faction relation %d -> %d: %w",
factionID, relatedFactionID, err)
}
return nil
}
// LoadPlayerFactions loads player faction values from the database
func (da *DatabaseAdapter) LoadPlayerFactions(playerID int32) (map[int32]int32, error) {
// Create player_factions table if it doesn't exist
if err := da.db.Exec(`
CREATE TABLE IF NOT EXISTS player_factions (
player_id INTEGER NOT NULL,
faction_id INTEGER NOT NULL,
faction_value INTEGER NOT NULL DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (player_id, faction_id),
FOREIGN KEY (faction_id) REFERENCES factions(id)
)
`); err != nil {
return nil, fmt.Errorf("failed to create player_factions table: %w", err)
}
factionValues := make(map[int32]int32)
err := da.db.Query("SELECT faction_id, faction_value FROM player_factions WHERE player_id = ?",
func(row *database.Row) error {
factionID := int32(row.Int64(0))
factionValue := int32(row.Int64(1))
factionValues[factionID] = factionValue
return nil
}, playerID)
if err != nil {
return nil, fmt.Errorf("failed to load player factions for player %d: %w", playerID, err)
}
return factionValues, nil
}
// SavePlayerFaction saves a player's faction value to the database
func (da *DatabaseAdapter) SavePlayerFaction(playerID, factionID, factionValue int32) error {
err := da.db.Exec(`
INSERT OR REPLACE INTO player_factions (player_id, faction_id, faction_value, updated_at)
VALUES (?, ?, ?, ?)
`, playerID, factionID, factionValue, time.Now().Unix())
if err != nil {
return fmt.Errorf("failed to save player faction %d/%d: %w", playerID, factionID, err)
}
return nil
}
// SaveAllPlayerFactions saves all faction values for a player
func (da *DatabaseAdapter) SaveAllPlayerFactions(playerID int32, factionValues map[int32]int32) error {
return da.db.Transaction(func(txDB *database.DB) error {
// Clear existing faction values for this player
if err := txDB.Exec("DELETE FROM player_factions WHERE player_id = ?", playerID); err != nil {
return fmt.Errorf("failed to clear player factions: %w", err)
}
// Insert all current faction values
for factionID, factionValue := range factionValues {
err := txDB.Exec(`
INSERT INTO player_factions (player_id, faction_id, faction_value, updated_at)
VALUES (?, ?, ?, ?)
`, playerID, factionID, factionValue, time.Now().Unix())
if err != nil {
return fmt.Errorf("failed to insert player faction %d/%d: %w", playerID, factionID, err)
}
}
return nil
})
}