mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 23:54:33 +01:00
The tower repo had business logic beyond simple CRUD: AddGem used a fetch-transform-save pattern, progress capping was inline in the handler, and RP donation orchestrated multiple repo calls with conditional page advancement. Move these into a new TowerService following the established service layer pattern.
153 lines
5.4 KiB
Go
153 lines
5.4 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
// TowerRepository centralizes all database access for tower-related tables
|
|
// (tower, guilds tower columns, guild_characters tower columns).
|
|
type TowerRepository struct {
|
|
db *sqlx.DB
|
|
}
|
|
|
|
// NewTowerRepository creates a new TowerRepository.
|
|
func NewTowerRepository(db *sqlx.DB) *TowerRepository {
|
|
return &TowerRepository{db: db}
|
|
}
|
|
|
|
// TowerData holds the core tower stats for a character.
|
|
type TowerData struct {
|
|
TR int32
|
|
TRP int32
|
|
TSP int32
|
|
Block1 int32
|
|
Block2 int32
|
|
Skills string
|
|
}
|
|
|
|
// GetTowerData returns tower stats for a character, creating the row if it doesn't exist.
|
|
func (r *TowerRepository) GetTowerData(charID uint32) (TowerData, error) {
|
|
var td TowerData
|
|
err := r.db.QueryRow(
|
|
`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), COALESCE(skills, $1) FROM tower WHERE char_id=$2`,
|
|
EmptyTowerCSV(64), charID,
|
|
).Scan(&td.TR, &td.TRP, &td.TSP, &td.Block1, &td.Block2, &td.Skills)
|
|
if err != nil {
|
|
_, err = r.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, charID)
|
|
return TowerData{Skills: EmptyTowerCSV(64)}, err
|
|
}
|
|
return td, nil
|
|
}
|
|
|
|
// GetSkills returns the skills CSV string for a character.
|
|
func (r *TowerRepository) GetSkills(charID uint32) (string, error) {
|
|
var skills string
|
|
err := r.db.QueryRow(`SELECT COALESCE(skills, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(64), charID).Scan(&skills)
|
|
return skills, err
|
|
}
|
|
|
|
// UpdateSkills updates a single skill and deducts TSP cost.
|
|
func (r *TowerRepository) UpdateSkills(charID uint32, skills string, cost int32) error {
|
|
_, err := r.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, skills, cost, charID)
|
|
return err
|
|
}
|
|
|
|
// UpdateProgress updates tower progress (TR, TRP, TSP, block1).
|
|
func (r *TowerRepository) UpdateProgress(charID uint32, tr, trp, cost, block1 int32) error {
|
|
_, err := r.db.Exec(
|
|
`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`,
|
|
tr, trp, cost, block1, charID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
// GetGems returns the gems CSV string for a character.
|
|
func (r *TowerRepository) GetGems(charID uint32) (string, error) {
|
|
var gems string
|
|
err := r.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), charID).Scan(&gems)
|
|
return gems, err
|
|
}
|
|
|
|
// UpdateGems saves the gems CSV string for a character.
|
|
func (r *TowerRepository) UpdateGems(charID uint32, gems string) error {
|
|
_, err := r.db.Exec(`UPDATE tower SET gems=$1 WHERE char_id=$2`, gems, charID)
|
|
return err
|
|
}
|
|
|
|
// TenrouiraiProgressData holds the guild's tenrouirai (sky corridor) progress.
|
|
type TenrouiraiProgressData struct {
|
|
Page uint8
|
|
Mission1 uint16
|
|
Mission2 uint16
|
|
Mission3 uint16
|
|
}
|
|
|
|
// GetTenrouiraiProgress returns the guild's tower mission page and aggregated mission scores.
|
|
func (r *TowerRepository) GetTenrouiraiProgress(guildID uint32) (TenrouiraiProgressData, error) {
|
|
var p TenrouiraiProgressData
|
|
if err := r.db.QueryRow(`SELECT tower_mission_page FROM guilds WHERE id=$1`, guildID).Scan(&p.Page); err != nil {
|
|
return p, err
|
|
}
|
|
_ = r.db.QueryRow(
|
|
`SELECT SUM(tower_mission_1) AS _, SUM(tower_mission_2) AS _, SUM(tower_mission_3) AS _ FROM guild_characters WHERE guild_id=$1`,
|
|
guildID,
|
|
).Scan(&p.Mission1, &p.Mission2, &p.Mission3)
|
|
return p, nil
|
|
}
|
|
|
|
// GetTenrouiraiMissionScores returns per-character scores for a specific mission index (1-3).
|
|
func (r *TowerRepository) GetTenrouiraiMissionScores(guildID uint32, missionIndex uint8) ([]TenrouiraiCharScore, error) {
|
|
if missionIndex < 1 || missionIndex > 3 {
|
|
missionIndex = (missionIndex % 3) + 1
|
|
}
|
|
rows, err := r.db.Query(
|
|
fmt.Sprintf(
|
|
`SELECT name, tower_mission_%d FROM guild_characters gc INNER JOIN characters c ON gc.character_id = c.id WHERE guild_id=$1 AND tower_mission_%d IS NOT NULL ORDER BY tower_mission_%d DESC`,
|
|
missionIndex, missionIndex, missionIndex,
|
|
),
|
|
guildID,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() { _ = rows.Close() }()
|
|
var scores []TenrouiraiCharScore
|
|
for rows.Next() {
|
|
var cs TenrouiraiCharScore
|
|
if err := rows.Scan(&cs.Name, &cs.Score); err == nil {
|
|
scores = append(scores, cs)
|
|
}
|
|
}
|
|
return scores, nil
|
|
}
|
|
|
|
// GetGuildTowerRP returns the guild's tower RP.
|
|
func (r *TowerRepository) GetGuildTowerRP(guildID uint32) (uint32, error) {
|
|
var rp uint32
|
|
err := r.db.QueryRow(`SELECT tower_rp FROM guilds WHERE id=$1`, guildID).Scan(&rp)
|
|
return rp, err
|
|
}
|
|
|
|
// GetGuildTowerPageAndRP returns the guild's tower mission page and donated RP.
|
|
func (r *TowerRepository) GetGuildTowerPageAndRP(guildID uint32) (page int, donated int, err error) {
|
|
err = r.db.QueryRow(`SELECT tower_mission_page, tower_rp FROM guilds WHERE id=$1`, guildID).Scan(&page, &donated)
|
|
return
|
|
}
|
|
|
|
// AdvanceTenrouiraiPage increments the guild's tower mission page and resets member mission progress.
|
|
func (r *TowerRepository) AdvanceTenrouiraiPage(guildID uint32) error {
|
|
if _, err := r.db.Exec(`UPDATE guilds SET tower_mission_page=tower_mission_page+1 WHERE id=$1`, guildID); err != nil {
|
|
return err
|
|
}
|
|
_, err := r.db.Exec(`UPDATE guild_characters SET tower_mission_1=NULL, tower_mission_2=NULL, tower_mission_3=NULL WHERE guild_id=$1`, guildID)
|
|
return err
|
|
}
|
|
|
|
// DonateGuildTowerRP adds RP to the guild's tower total.
|
|
func (r *TowerRepository) DonateGuildTowerRP(guildID uint32, rp uint16) error {
|
|
_, err := r.db.Exec(`UPDATE guilds SET tower_rp=tower_rp+$1 WHERE id=$2`, rp, guildID)
|
|
return err
|
|
}
|