fix transmute package

This commit is contained in:
Sky Johnson 2025-08-06 13:37:44 -05:00
parent fa47af5ffe
commit cc49aac689
4 changed files with 1374 additions and 74 deletions

View File

@ -2,16 +2,16 @@ package transmute
// Item flags that disqualify items from transmutation
const (
NoZone = 1 << 0 // NO_ZONE flag
NoValue = 1 << 1 // NO_VALUE flag
Temporary = 1 << 2 // TEMPORARY flag
NoDestroy = 1 << 3 // NO_DESTROY flag
NoTransmute = 1 << 14 // NO_TRANSMUTE flag (16384)
NoZone = int32(1 << 0) // NO_ZONE flag
NoValue = int32(1 << 1) // NO_VALUE flag
Temporary = int32(1 << 2) // TEMPORARY flag
NoDestroy = int32(1 << 3) // NO_DESTROY flag
NoTransmute = int32(1 << 14) // NO_TRANSMUTE flag (16384)
)
// Item flags2 that disqualify items from transmutation
const (
Ornate = 1 << 0 // ORNATE flag
Ornate = int32(1 << 0) // ORNATE flag
)
// Item tiers/rarities

View File

@ -2,25 +2,49 @@ package transmute
import (
"fmt"
"time"
"eq2emu/internal/database"
"zombiezen.com/go/sqlite"
"zombiezen.com/go/sqlite/sqlitex"
)
// DatabaseImpl provides a default implementation of the Database interface
type DatabaseImpl struct {
db *database.DB
conn *sqlite.Conn
}
// NewDatabase creates a new database implementation
func NewDatabase(db *database.DB) *DatabaseImpl {
return &DatabaseImpl{db: db}
func NewDatabase(conn *sqlite.Conn) *DatabaseImpl {
return &DatabaseImpl{conn: conn}
}
// OpenDB opens a database connection for transmutation system
func OpenDB(path string) (*DatabaseImpl, error) {
conn, err := sqlite.OpenConn(path, sqlite.OpenReadWrite|sqlite.OpenCreate|sqlite.OpenWAL)
if err != nil {
return nil, fmt.Errorf("failed to open database: %w", err)
}
// Enable foreign keys
if err := sqlitex.ExecTransient(conn, "PRAGMA foreign_keys = ON;", nil); err != nil {
conn.Close()
return nil, fmt.Errorf("failed to enable foreign keys: %w", err)
}
return &DatabaseImpl{conn: conn}, nil
}
// Close closes the database connection
func (dbi *DatabaseImpl) Close() error {
if dbi.conn != nil {
return dbi.conn.Close()
}
return nil
}
// LoadTransmutingTiers loads transmuting tiers from the database
func (dbi *DatabaseImpl) LoadTransmutingTiers() ([]*TransmutingTier, error) {
// Create transmuting_tiers table if it doesn't exist
if err := dbi.db.Exec(`
if err := sqlitex.ExecuteScript(dbi.conn, `
CREATE TABLE IF NOT EXISTS transmuting_tiers (
min_level INTEGER NOT NULL,
max_level INTEGER NOT NULL,
@ -31,20 +55,21 @@ func (dbi *DatabaseImpl) LoadTransmutingTiers() ([]*TransmutingTier, error) {
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (min_level, max_level)
)
`); err != nil {
`, &sqlitex.ExecOptions{}); err != nil {
return nil, fmt.Errorf("failed to create transmuting_tiers table: %w", err)
}
// Check if table is empty and populate with default data
var count int
row, err := dbi.db.QueryRow("SELECT COUNT(*) FROM transmuting_tiers")
var count int64
err := sqlitex.Execute(dbi.conn, "SELECT COUNT(*) FROM transmuting_tiers", &sqlitex.ExecOptions{
ResultFunc: func(stmt *sqlite.Stmt) error {
count = stmt.ColumnInt64(0)
return nil
},
})
if err != nil {
return nil, fmt.Errorf("failed to count transmuting tiers: %w", err)
}
if row != nil {
count = row.Int(0)
row.Close()
}
// If empty, populate with default EQ2 transmuting tiers
if count == 0 {
@ -55,19 +80,20 @@ func (dbi *DatabaseImpl) LoadTransmutingTiers() ([]*TransmutingTier, error) {
// Load all tiers from database
var tiers []*TransmutingTier
err = dbi.db.Query("SELECT min_level, max_level, fragment_id, powder_id, infusion_id, mana_id FROM transmuting_tiers ORDER BY min_level",
func(row *database.Row) error {
err = sqlitex.Execute(dbi.conn, "SELECT min_level, max_level, fragment_id, powder_id, infusion_id, mana_id FROM transmuting_tiers ORDER BY min_level", &sqlitex.ExecOptions{
ResultFunc: func(stmt *sqlite.Stmt) error {
tier := &TransmutingTier{
MinLevel: int32(row.Int64(0)),
MaxLevel: int32(row.Int64(1)),
FragmentID: int32(row.Int64(2)),
PowderID: int32(row.Int64(3)),
InfusionID: int32(row.Int64(4)),
ManaID: int32(row.Int64(5)),
MinLevel: int32(stmt.ColumnInt64(0)),
MaxLevel: int32(stmt.ColumnInt64(1)),
FragmentID: int32(stmt.ColumnInt64(2)),
PowderID: int32(stmt.ColumnInt64(3)),
InfusionID: int32(stmt.ColumnInt64(4)),
ManaID: int32(stmt.ColumnInt64(5)),
}
tiers = append(tiers, tier)
return nil
})
},
})
if err != nil {
return nil, fmt.Errorf("failed to load transmuting tiers: %w", err)
@ -94,19 +120,26 @@ func (dbi *DatabaseImpl) populateDefaultTiers() error {
{90, 100, 1037, 1038, 1039, 1040},
}
return dbi.db.Transaction(func(txDB *database.DB) error {
for _, tier := range defaultTiers {
err := txDB.Exec(`
INSERT INTO transmuting_tiers (min_level, max_level, fragment_id, powder_id, infusion_id, mana_id)
VALUES (?, ?, ?, ?, ?, ?)
`, tier.minLevel, tier.maxLevel, tier.fragmentID, tier.powderID, tier.infusionID, tier.manaID)
// Use transaction for atomic inserts
endFn, err := sqlitex.ImmediateTransaction(dbi.conn)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer endFn(&err)
if err != nil {
return fmt.Errorf("failed to insert tier %d-%d: %w", tier.minLevel, tier.maxLevel, err)
}
for _, tier := range defaultTiers {
err = sqlitex.Execute(dbi.conn, `
INSERT INTO transmuting_tiers (min_level, max_level, fragment_id, powder_id, infusion_id, mana_id)
VALUES (?, ?, ?, ?, ?, ?)
`, &sqlitex.ExecOptions{
Args: []any{tier.minLevel, tier.maxLevel, tier.fragmentID, tier.powderID, tier.infusionID, tier.manaID},
})
if err != nil {
return fmt.Errorf("failed to insert tier %d-%d: %w", tier.minLevel, tier.maxLevel, err)
}
return nil
})
}
return nil
}
// TODO: When integrating with a real database system, replace this with actual database queries
@ -167,10 +200,12 @@ func (dbi *DatabaseImpl) SaveTransmutingTier(tier *TransmutingTier) error {
return fmt.Errorf("all material IDs must be positive")
}
err := dbi.db.Exec(`
err := sqlitex.Execute(dbi.conn, `
INSERT OR REPLACE INTO transmuting_tiers (min_level, max_level, fragment_id, powder_id, infusion_id, mana_id)
VALUES (?, ?, ?, ?, ?, ?)
`, tier.MinLevel, tier.MaxLevel, tier.FragmentID, tier.PowderID, tier.InfusionID, tier.ManaID)
`, &sqlitex.ExecOptions{
Args: []any{tier.MinLevel, tier.MaxLevel, tier.FragmentID, tier.PowderID, tier.InfusionID, tier.ManaID},
})
if err != nil {
return fmt.Errorf("failed to save transmuting tier %d-%d: %w", tier.MinLevel, tier.MaxLevel, err)
@ -185,7 +220,9 @@ func (dbi *DatabaseImpl) DeleteTransmutingTier(minLevel, maxLevel int32) error {
return fmt.Errorf("invalid level range: %d-%d", minLevel, maxLevel)
}
err := dbi.db.Exec("DELETE FROM transmuting_tiers WHERE min_level = ? AND max_level = ?", minLevel, maxLevel)
err := sqlitex.Execute(dbi.conn, "DELETE FROM transmuting_tiers WHERE min_level = ? AND max_level = ?", &sqlitex.ExecOptions{
Args: []any{minLevel, maxLevel},
})
if err != nil {
return fmt.Errorf("failed to delete transmuting tier %d-%d: %w", minLevel, maxLevel, err)
}
@ -195,26 +232,31 @@ func (dbi *DatabaseImpl) DeleteTransmutingTier(minLevel, maxLevel int32) error {
// GetTransmutingTierByLevel gets a specific transmuting tier by level range
func (dbi *DatabaseImpl) GetTransmutingTierByLevel(itemLevel int32) (*TransmutingTier, error) {
row, err := dbi.db.QueryRow("SELECT min_level, max_level, fragment_id, powder_id, infusion_id, mana_id FROM transmuting_tiers WHERE min_level <= ? AND max_level >= ?", itemLevel, itemLevel)
var tier *TransmutingTier
err := sqlitex.Execute(dbi.conn, "SELECT min_level, max_level, fragment_id, powder_id, infusion_id, mana_id FROM transmuting_tiers WHERE min_level <= ? AND max_level >= ?", &sqlitex.ExecOptions{
Args: []any{itemLevel, itemLevel},
ResultFunc: func(stmt *sqlite.Stmt) error {
tier = &TransmutingTier{
MinLevel: int32(stmt.ColumnInt64(0)),
MaxLevel: int32(stmt.ColumnInt64(1)),
FragmentID: int32(stmt.ColumnInt64(2)),
PowderID: int32(stmt.ColumnInt64(3)),
InfusionID: int32(stmt.ColumnInt64(4)),
ManaID: int32(stmt.ColumnInt64(5)),
}
return nil
},
})
if err != nil {
return nil, fmt.Errorf("failed to query transmuting tier for level %d: %w", itemLevel, err)
}
if row == nil {
if tier == nil {
return nil, fmt.Errorf("no transmuting tier found for level %d", itemLevel)
}
defer row.Close()
tier := &TransmutingTier{
MinLevel: int32(row.Int64(0)),
MaxLevel: int32(row.Int64(1)),
FragmentID: int32(row.Int64(2)),
PowderID: int32(row.Int64(3)),
InfusionID: int32(row.Int64(4)),
ManaID: int32(row.Int64(5)),
}
return tier, nil
}
@ -237,12 +279,14 @@ func (dbi *DatabaseImpl) UpdateTransmutingTier(oldMinLevel, oldMaxLevel int32, n
return fmt.Errorf("all material IDs must be positive")
}
err := dbi.db.Exec(`
err := sqlitex.Execute(dbi.conn, `
UPDATE transmuting_tiers
SET min_level=?, max_level=?, fragment_id=?, powder_id=?, infusion_id=?, mana_id=?
WHERE min_level=? AND max_level=?
`, newTier.MinLevel, newTier.MaxLevel, newTier.FragmentID, newTier.PowderID,
newTier.InfusionID, newTier.ManaID, oldMinLevel, oldMaxLevel)
`, &sqlitex.ExecOptions{
Args: []any{newTier.MinLevel, newTier.MaxLevel, newTier.FragmentID, newTier.PowderID,
newTier.InfusionID, newTier.ManaID, oldMinLevel, oldMaxLevel},
})
if err != nil {
return fmt.Errorf("failed to update transmuting tier %d-%d: %w", oldMinLevel, oldMaxLevel, err)
@ -252,21 +296,20 @@ func (dbi *DatabaseImpl) UpdateTransmutingTier(oldMinLevel, oldMaxLevel int32, n
}
// TransmutingTierExists checks if a transmuting tier exists for the given level range
func (db *DatabaseImpl) TransmutingTierExists(minLevel, maxLevel int32) (bool, error) {
// Placeholder implementation
// In a real implementation:
// SELECT COUNT(*) FROM transmuting WHERE min_level = ? AND max_level = ?
tiers, err := db.LoadTransmutingTiers()
func (dbi *DatabaseImpl) TransmutingTierExists(minLevel, maxLevel int32) (bool, error) {
var count int64
err := sqlitex.Execute(dbi.conn, "SELECT COUNT(*) FROM transmuting_tiers WHERE min_level = ? AND max_level = ?", &sqlitex.ExecOptions{
Args: []any{minLevel, maxLevel},
ResultFunc: func(stmt *sqlite.Stmt) error {
count = stmt.ColumnInt64(0)
return nil
},
})
if err != nil {
return false, err
return false, fmt.Errorf("failed to check tier existence: %w", err)
}
for _, tier := range tiers {
if tier.MinLevel == minLevel && tier.MaxLevel == maxLevel {
return true, nil
}
}
return false, nil
return count > 0, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -31,8 +31,8 @@ const (
// TransmuteResult represents the outcome of a transmutation
type TransmuteResult struct {
Success bool // Whether transmutation was successful
CommonMaterial *Item // Common material received (if any)
RareMaterial *Item // Rare material received (if any)
CommonMaterial Item // Common material received (if any)
RareMaterial Item // Rare material received (if any)
ErrorMessage string // Error message if unsuccessful
SkillIncrease bool // Whether player received skill increase
}