mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
An MMO server without multiplayer defeats the purpose. PostgreSQL is the right choice and Docker Compose already solves the setup pain. This reverts the common/db wrapper, SQLite schema, config Driver field, modernc.org/sqlite dependency, and all repo type changes while keeping the dashboard, wizard, and CI improvements from the previous commit.
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
|
|
}
|