Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f623388291 | ||
|
|
74185d92d4 |
+455
@@ -0,0 +1,455 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitemigration"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/umadump/ism"
|
||||
)
|
||||
|
||||
const appID int32 = 0x157db
|
||||
|
||||
//go:embed schema-00.sql
|
||||
var schema0 string
|
||||
|
||||
//go:embed schema-final.sql
|
||||
var schemaFinal string
|
||||
|
||||
func opendb(uri, journalMode string) *sqlitemigration.Pool {
|
||||
schema := sqlitemigration.Schema{
|
||||
Migrations: []string{
|
||||
schema0,
|
||||
},
|
||||
AppID: appID,
|
||||
RepeatableMigration: schemaFinal,
|
||||
}
|
||||
j := "PRAGMA journal_mode=" + journalMode
|
||||
opts := sqlitemigration.Options{
|
||||
Flags: sqlite.OpenReadWrite | sqlite.OpenCreate | sqlite.OpenURI,
|
||||
PrepareConn: func(conn *sqlite.Conn) error {
|
||||
if journalMode == "" {
|
||||
return nil
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(j)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Step()
|
||||
return errors.Join(err, stmt.Finalize())
|
||||
},
|
||||
}
|
||||
db := sqlitemigration.NewPool(uri, schema, opts)
|
||||
return db
|
||||
}
|
||||
|
||||
func insert(ctx context.Context, db *sqlitemigration.Pool, log *slog.Logger, career *ism.WorkIdleSingleMode, trainerID int64) (err error) {
|
||||
log = log.With(slog.Int64("trainer", trainerID), slog.Int("id", int(career.End.Chara.SingleModeCharaID)))
|
||||
|
||||
conn, err := db.Take(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Put(conn)
|
||||
|
||||
defer sqlitex.Transaction(conn)(&err)
|
||||
|
||||
// Do the first insert separately so we can check whether the career is
|
||||
// already in, and so that the join doesn't report the same error repeatedly
|
||||
// if there's something wrong with the db.
|
||||
if err := insertCareer(conn, log, career, trainerID); err != nil {
|
||||
code := sqlite.ErrCode(err)
|
||||
if code == sqlite.ResultConstraintUnique {
|
||||
log.InfoContext(ctx, "already loaded")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
trainedChara := career.End.Chara.SingleModeCharaID
|
||||
err = errors.Join(
|
||||
insertConditions(conn, log, career.ProgressLog.CharaEffectLog, trainerID, trainedChara),
|
||||
insertGain(conn, log, &career.ProgressLog.EventGain, trainerID, trainedChara, 0),
|
||||
insertGainSkillHint(conn, log, career.ProgressLog.EventGain.SkillTips, trainerID, trainedChara, 0),
|
||||
insertGain(conn, log, &career.ProgressLog.SuccessionGain, trainerID, trainedChara, 1),
|
||||
insertGainSkillHint(conn, log, career.ProgressLog.SuccessionGain.SkillTips, trainerID, trainedChara, 1),
|
||||
)
|
||||
for _, s := range career.ProgressLog.SupportCardGains {
|
||||
err = errors.Join(
|
||||
err,
|
||||
insertGain(conn, log, &s.GainInfo, trainerID, trainedChara, int32(s.SupportCardID)),
|
||||
insertGainSkillHint(conn, log, s.GainInfo.SkillTips, trainerID, trainedChara, int32(s.SupportCardID)),
|
||||
)
|
||||
}
|
||||
err = errors.Join(
|
||||
err,
|
||||
insertInspirations(conn, log, career.ProgressLog.SuccessionFactorGains, trainerID, trainedChara),
|
||||
insertRaces(conn, log, career.ProgressLog.RaceHistory, trainerID, trainedChara),
|
||||
insertGainedSkills(conn, log, career.ProgressLog.GainSkillIDs, trainerID, trainedChara),
|
||||
insertCareerSkills(conn, log, career.End.Chara.Skills, trainerID, trainedChara),
|
||||
insertCareerSkillHints(conn, log, career.End.Chara.SkillTips, trainerID, trainedChara),
|
||||
insertSupportCards(conn, log, career.End.Chara.SupportCards, trainerID, trainedChara),
|
||||
insertStartSkills(conn, log, career.ProgressInfo.Chara.Skills, trainerID, trainedChara),
|
||||
insertStartSkillHints(conn, log, career.ProgressInfo.Chara.SkillTips, trainerID, trainedChara),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
//go:embed insert-career.sql
|
||||
var insertCareerSQL string
|
||||
|
||||
func insertCareer(conn *sqlite.Conn, log *slog.Logger, career *ism.WorkIdleSingleMode, trainerID int64) error {
|
||||
log.Debug("insert career")
|
||||
stmt := conn.Prep(insertCareerSQL)
|
||||
stmt.SetInt64("$trainer_id", trainerID)
|
||||
stmt.SetInt64("$trained_chara_id", int64(career.End.Chara.SingleModeCharaID))
|
||||
stmt.SetInt64("$card_id", int64(career.End.Chara.CardID))
|
||||
stmt.SetInt64("$scenario_id", int64(career.End.Chara.ScenarioID))
|
||||
stmt.SetInt64("$route_id", int64(career.End.Chara.RouteID))
|
||||
stmt.SetText("$start_time", career.ProgressInfo.StartTime)
|
||||
stmt.SetText("$end_time", career.ProgressInfo.EndTime)
|
||||
stmt.SetInt64("$chara_grade", int64(career.End.Chara.CharaGrade))
|
||||
stmt.SetInt64("$star_level", int64(career.End.Chara.Rarity))
|
||||
stmt.SetInt64("$potential_level", int64(career.End.Chara.TalentLevel))
|
||||
stmt.SetInt64("$speed", int64(career.End.Chara.Speed))
|
||||
stmt.SetInt64("$stamina", int64(career.End.Chara.Stamina))
|
||||
stmt.SetInt64("$power", int64(career.End.Chara.Power))
|
||||
stmt.SetInt64("$guts", int64(career.End.Chara.Guts))
|
||||
stmt.SetInt64("$wit", int64(career.End.Chara.Wiz))
|
||||
stmt.SetInt64("$energy", int64(career.End.Chara.Vital))
|
||||
stmt.SetInt64("$max_speed", int64(career.End.Chara.MaxSpeed))
|
||||
stmt.SetInt64("$max_stamina", int64(career.End.Chara.MaxStamina))
|
||||
stmt.SetInt64("$max_power", int64(career.End.Chara.MaxPower))
|
||||
stmt.SetInt64("$max_guts", int64(career.End.Chara.MaxGuts))
|
||||
stmt.SetInt64("$max_wit", int64(career.End.Chara.MaxWiz))
|
||||
stmt.SetInt64("$max_energy", int64(career.End.Chara.MaxVital))
|
||||
stmt.SetInt64("$skill_point", int64(career.ProgressLog.TotalSkillPoint))
|
||||
stmt.SetInt64("$mood", int64(career.End.Chara.Motivation))
|
||||
stmt.SetInt64("$turf", int64(career.End.Chara.ProperGroundTurf))
|
||||
stmt.SetInt64("$dirt", int64(career.End.Chara.ProperGroundDirt))
|
||||
stmt.SetInt64("$sprint", int64(career.End.Chara.ProperDistanceShort))
|
||||
stmt.SetInt64("$mile", int64(career.End.Chara.ProperDistanceMile))
|
||||
stmt.SetInt64("$medium", int64(career.End.Chara.ProperDistanceMiddle))
|
||||
stmt.SetInt64("$long", int64(career.End.Chara.ProperDistanceLong))
|
||||
stmt.SetInt64("$front_runner", int64(career.End.Chara.ProperRunningStyleNige))
|
||||
stmt.SetInt64("$pace_chaser", int64(career.End.Chara.ProperRunningStyleSenko))
|
||||
stmt.SetInt64("$late_surger", int64(career.End.Chara.ProperRunningStyleSashi))
|
||||
stmt.SetInt64("$end_closer", int64(career.End.Chara.ProperRunningStyleOikomi))
|
||||
stmt.SetInt64("$start_speed", int64(career.ProgressInfo.Chara.Speed))
|
||||
stmt.SetInt64("$start_stamina", int64(career.ProgressInfo.Chara.Stamina))
|
||||
stmt.SetInt64("$start_power", int64(career.ProgressInfo.Chara.Power))
|
||||
stmt.SetInt64("$start_guts", int64(career.ProgressInfo.Chara.Guts))
|
||||
stmt.SetInt64("$start_wit", int64(career.ProgressInfo.Chara.Wiz))
|
||||
stmt.SetInt64("$start_max_speed", int64(career.ProgressInfo.Chara.MaxSpeed))
|
||||
stmt.SetInt64("$start_max_stamina", int64(career.ProgressInfo.Chara.MaxStamina))
|
||||
stmt.SetInt64("$start_max_power", int64(career.ProgressInfo.Chara.MaxPower))
|
||||
stmt.SetInt64("$start_max_guts", int64(career.ProgressInfo.Chara.MaxGuts))
|
||||
stmt.SetInt64("$start_max_wit", int64(career.ProgressInfo.Chara.MaxWiz))
|
||||
stmt.SetInt64("$start_turf", int64(career.ProgressInfo.Chara.ProperGroundTurf))
|
||||
stmt.SetInt64("$start_dirt", int64(career.ProgressInfo.Chara.ProperGroundDirt))
|
||||
stmt.SetInt64("$start_sprint", int64(career.ProgressInfo.Chara.ProperDistanceShort))
|
||||
stmt.SetInt64("$start_mile", int64(career.ProgressInfo.Chara.ProperDistanceMile))
|
||||
stmt.SetInt64("$start_medium", int64(career.ProgressInfo.Chara.ProperDistanceMiddle))
|
||||
stmt.SetInt64("$start_long", int64(career.ProgressInfo.Chara.ProperDistanceLong))
|
||||
stmt.SetInt64("$start_front_runner", int64(career.ProgressInfo.Chara.ProperRunningStyleNige))
|
||||
stmt.SetInt64("$start_pace_chaser", int64(career.ProgressInfo.Chara.ProperRunningStyleSenko))
|
||||
stmt.SetInt64("$start_late_surger", int64(career.ProgressInfo.Chara.ProperRunningStyleSashi))
|
||||
stmt.SetInt64("$start_end_closer", int64(career.ProgressInfo.Chara.ProperRunningStyleOikomi))
|
||||
stmt.SetInt64("$fans", int64(career.End.Chara.Fans))
|
||||
stmt.SetInt64("$race_program_id", int64(career.End.Chara.RaceProgramID))
|
||||
stmt.SetInt64("$reserve_race_program_id", int64(career.End.Chara.ReserveRaceProgramID))
|
||||
stmt.SetInt64("$race_running_style", int64(career.End.Chara.RaceRunningStyle))
|
||||
stmt.SetInt64("$is_short_race", int64(career.End.Chara.IsShortRace))
|
||||
stmt.SetInt64("$succession_trained_chara_id_1", int64(career.End.Chara.SuccessionTrainedCharaID1))
|
||||
stmt.SetInt64("$succession_trained_chara_id_2", int64(career.End.Chara.SuccessionTrainedCharaID2))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting career: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertConditions(conn *sqlite.Conn, log *slog.Logger, cs []ism.CharaEffectLog, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert conditions")
|
||||
const sql = `INSERT INTO condition VALUES (?, ?, ?, ?)`
|
||||
stmt := conn.Prep(sql)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, c := range cs {
|
||||
stmt.BindInt64(3, int64(c.CharaEffectID))
|
||||
stmt.BindBool(4, c.IsActive)
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting condition: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:embed insert-gain.sql
|
||||
var insertGainSQL string
|
||||
|
||||
func insertGain(conn *sqlite.Conn, log *slog.Logger, gain *ism.IdleSingleModeGainInfo, trainerID int64, trainedChara int32, source int32) error {
|
||||
log.Debug("insert gain", slog.Int("source", int(source)))
|
||||
stmt := conn.Prep(insertGainSQL)
|
||||
stmt.SetInt64("$trainer_id", trainerID)
|
||||
stmt.SetInt64("$trained_chara_id", int64(trainedChara))
|
||||
stmt.SetInt64("$source", int64(source))
|
||||
stmt.SetInt64("$gain_speed", int64(gain.Speed.Value))
|
||||
stmt.SetInt64("$gain_stamina", int64(gain.Stamina.Value))
|
||||
stmt.SetInt64("$gain_power", int64(gain.Power.Value))
|
||||
stmt.SetInt64("$gain_guts", int64(gain.Guts.Value))
|
||||
stmt.SetInt64("$gain_wit", int64(gain.Wiz.Value))
|
||||
stmt.SetInt64("$gain_skill_point", int64(gain.SkillPoint))
|
||||
stmt.SetInt64("$gain_max_speed", int64(gain.MaxSpeed))
|
||||
stmt.SetInt64("$gain_max_stamina", int64(gain.MaxStamina))
|
||||
stmt.SetInt64("$gain_max_power", int64(gain.MaxPower))
|
||||
stmt.SetInt64("$gain_max_guts", int64(gain.MaxGuts))
|
||||
stmt.SetInt64("$gain_max_wit", int64(gain.MaxWiz))
|
||||
stmt.SetInt64("$gain_turf", int64(gain.ProperGroundTurf))
|
||||
stmt.SetInt64("$gain_dirt", int64(gain.ProperGroundDirt))
|
||||
stmt.SetInt64("$gain_sprint", int64(gain.ProperDistanceShort))
|
||||
stmt.SetInt64("$gain_mile", int64(gain.ProperDistanceMile))
|
||||
stmt.SetInt64("$gain_medium", int64(gain.ProperDistanceMiddle))
|
||||
stmt.SetInt64("$gain_long", int64(gain.ProperDistanceLong))
|
||||
stmt.SetInt64("$gain_front_runner", int64(gain.ProperRunningStyleNige))
|
||||
stmt.SetInt64("$gain_pace_chaser", int64(gain.ProperRunningStyleSenko))
|
||||
stmt.SetInt64("$gain_late_surger", int64(gain.ProperRunningStyleSashi))
|
||||
stmt.SetInt64("$gain_end_closer", int64(gain.ProperRunningStyleOikomi))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting gain info for source %d: %w", source, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertGainSkillHint(conn *sqlite.Conn, log *slog.Logger, tips []ism.SkillTip, trainerID int64, trainedChara int32, source int32) error {
|
||||
log.Debug("insert gain skill hints", slog.Int("source", int(source)))
|
||||
stmt := conn.Prep(`INSERT INTO gain_skill_hint VALUES (?, ?, ?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
stmt.BindInt64(3, int64(source))
|
||||
for _, t := range tips {
|
||||
stmt.BindInt64(4, int64(t.GroupID))
|
||||
stmt.BindInt64(5, int64(t.Rarity))
|
||||
stmt.BindInt64(6, int64(t.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting skill hint for group %d, rarity %d from source %d: %w", t.GroupID, t.Rarity, source, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertInspirations(conn *sqlite.Conn, log *slog.Logger, inspos []ism.IdleSingleModeSuccessionFactorGain, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert inspirations")
|
||||
stmt := conn.Prep(`INSERT INTO inspiration VALUES (?, ?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, yr := range inspos {
|
||||
stmt.BindInt64(3, int64(yr.Year))
|
||||
for _, f := range yr.GainFactorInfo {
|
||||
stmt.BindInt64(4, int64(f.FactorID))
|
||||
stmt.BindInt64(5, int64(f.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting spark: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertRaces(conn *sqlite.Conn, log *slog.Logger, races []ism.IdleSingleModeRaceHistory, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert races")
|
||||
raceStmt := conn.Prep(`INSERT INTO race_history VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
rewardStmt := conn.Prep(`INSERT INTO race_reward VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
raceStmt.BindInt64(1, trainerID)
|
||||
raceStmt.BindInt64(2, int64(trainedChara))
|
||||
rewardStmt.BindInt64(1, trainerID)
|
||||
rewardStmt.BindInt64(2, int64(trainedChara))
|
||||
for _, r := range races {
|
||||
raceStmt.BindInt64(3, int64(r.RaceHistory.Turn))
|
||||
raceStmt.BindInt64(4, int64(r.RaceHistory.ProgramID))
|
||||
raceStmt.BindInt64(5, int64(r.RaceHistory.Weather))
|
||||
raceStmt.BindInt64(6, int64(r.RaceHistory.GroundCondition))
|
||||
raceStmt.BindInt64(7, int64(r.RaceHistory.RunningStyle))
|
||||
raceStmt.BindInt64(8, int64(r.RaceHistory.ResultRank))
|
||||
raceStmt.BindInt64(9, int64(r.RaceHistory.FrameOrder))
|
||||
raceStmt.BindInt64(10, int64(r.RaceRewardInfo.GainedFans))
|
||||
raceStmt.BindInt64(11, int64(r.LoseTipsID))
|
||||
_, err := raceStmt.Step()
|
||||
err = errors.Join(err, raceStmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting race history: %w", err)
|
||||
}
|
||||
|
||||
rewardStmt.BindInt64(3, int64(r.RaceHistory.Turn))
|
||||
rewardStmt.BindBool(7, false)
|
||||
rewardStmt.BindBool(8, false)
|
||||
rewardStmt.BindBool(9, false)
|
||||
for _, reward := range r.RaceRewardInfo.RaceReward {
|
||||
rewardStmt.BindInt64(4, int64(reward.ItemType))
|
||||
rewardStmt.BindInt64(5, int64(reward.ItemID))
|
||||
rewardStmt.BindInt64(6, int64(reward.ItemNum))
|
||||
_, err := rewardStmt.Step()
|
||||
err = errors.Join(err, rewardStmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting race reward: %w", err)
|
||||
}
|
||||
}
|
||||
rewardStmt.BindBool(7, true)
|
||||
for _, reward := range r.RaceRewardInfo.RaceRewardBonus {
|
||||
rewardStmt.BindInt64(4, int64(reward.ItemType))
|
||||
rewardStmt.BindInt64(5, int64(reward.ItemID))
|
||||
rewardStmt.BindInt64(6, int64(reward.ItemNum))
|
||||
_, err := rewardStmt.Step()
|
||||
err = errors.Join(err, rewardStmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting race reward: %w", err)
|
||||
}
|
||||
}
|
||||
rewardStmt.BindBool(7, false)
|
||||
rewardStmt.BindBool(8, true)
|
||||
for _, reward := range r.RaceRewardInfo.RaceRewardPlusBonus {
|
||||
rewardStmt.BindInt64(4, int64(reward.ItemType))
|
||||
rewardStmt.BindInt64(5, int64(reward.ItemID))
|
||||
rewardStmt.BindInt64(6, int64(reward.ItemNum))
|
||||
_, err := rewardStmt.Step()
|
||||
err = errors.Join(err, rewardStmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting race reward: %w", err)
|
||||
}
|
||||
}
|
||||
rewardStmt.BindBool(8, false)
|
||||
rewardStmt.BindBool(9, true)
|
||||
for _, reward := range r.RaceRewardInfo.RaceRewardBonusWin {
|
||||
rewardStmt.BindInt64(4, int64(reward.ItemType))
|
||||
rewardStmt.BindInt64(5, int64(reward.ItemID))
|
||||
rewardStmt.BindInt64(6, int64(reward.ItemNum))
|
||||
_, err := rewardStmt.Step()
|
||||
err = errors.Join(err, rewardStmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting race reward: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertGainedSkills(conn *sqlite.Conn, log *slog.Logger, skills []horse.SkillID, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert gained skills")
|
||||
stmt := conn.Prep(`INSERT INTO gained_skill VALUES (?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, sk := range skills {
|
||||
stmt.BindInt64(3, int64(sk))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting gain skill: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertCareerSkills(conn *sqlite.Conn, log *slog.Logger, skills []ism.Skill, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert career skills")
|
||||
stmt := conn.Prep(`INSERT INTO career_skill VALUES (?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, sk := range skills {
|
||||
stmt.BindInt64(3, int64(sk.ID))
|
||||
stmt.BindInt64(4, int64(sk.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting skill: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertCareerSkillHints(conn *sqlite.Conn, log *slog.Logger, hints []ism.SkillTip, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert career skill hints")
|
||||
stmt := conn.Prep(`INSERT INTO career_skill_hint VALUES (?, ?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, h := range hints {
|
||||
stmt.BindInt64(3, int64(h.GroupID))
|
||||
stmt.BindInt64(4, int64(h.Rarity))
|
||||
stmt.BindInt64(5, int64(h.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting skill hint: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertSupportCards(conn *sqlite.Conn, log *slog.Logger, supps []ism.SingleModeSupportCard, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert support cards")
|
||||
stmt := conn.Prep(`INSERT INTO career_support_card VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, s := range supps {
|
||||
stmt.BindInt64(3, int64(s.Position))
|
||||
stmt.BindInt64(4, int64(s.ID))
|
||||
stmt.BindInt64(5, int64(s.LimitBreak))
|
||||
stmt.BindInt64(6, int64(s.Exp))
|
||||
stmt.BindInt64(7, int64(s.OwnerID))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting support card: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertStartSkills(conn *sqlite.Conn, log *slog.Logger, skills []ism.Skill, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert starting skills")
|
||||
stmt := conn.Prep(`INSERT INTO start_skill VALUES (?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, sk := range skills {
|
||||
stmt.BindInt64(3, int64(sk.ID))
|
||||
stmt.BindInt64(4, int64(sk.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting skill: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertStartSkillHints(conn *sqlite.Conn, log *slog.Logger, hints []ism.SkillTip, trainerID int64, trainedChara int32) error {
|
||||
log.Debug("insert starting skill hints")
|
||||
stmt := conn.Prep(`INSERT INTO start_skill_hint VALUES (?, ?, ?, ?, ?)`)
|
||||
stmt.BindInt64(1, trainerID)
|
||||
stmt.BindInt64(2, int64(trainedChara))
|
||||
for _, h := range hints {
|
||||
stmt.BindInt64(3, int64(h.GroupID))
|
||||
stmt.BindInt64(4, int64(h.Rarity))
|
||||
stmt.BindInt64(5, int64(h.Level))
|
||||
_, err := stmt.Step()
|
||||
err = errors.Join(err, stmt.Reset())
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting skill hint: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
INSERT INTO career VALUES (
|
||||
$trainer_id,
|
||||
$trained_chara_id,
|
||||
$card_id,
|
||||
$scenario_id,
|
||||
$route_id,
|
||||
$start_time,
|
||||
$end_time,
|
||||
|
||||
$chara_grade,
|
||||
$star_level,
|
||||
$potential_level,
|
||||
|
||||
$speed,
|
||||
$stamina,
|
||||
$power,
|
||||
$guts,
|
||||
$wit,
|
||||
$energy,
|
||||
$max_speed,
|
||||
$max_stamina,
|
||||
$max_power,
|
||||
$max_guts,
|
||||
$max_wit,
|
||||
$max_energy,
|
||||
$skill_point,
|
||||
$mood,
|
||||
|
||||
$turf,
|
||||
$dirt,
|
||||
$sprint,
|
||||
$mile,
|
||||
$medium,
|
||||
$long,
|
||||
$front_runner,
|
||||
$pace_chaser,
|
||||
$late_surger,
|
||||
$end_closer,
|
||||
|
||||
$start_speed,
|
||||
$start_stamina,
|
||||
$start_power,
|
||||
$start_guts,
|
||||
$start_wit,
|
||||
$start_max_speed,
|
||||
$start_max_stamina,
|
||||
$start_max_power,
|
||||
$start_max_guts,
|
||||
$start_max_wit,
|
||||
$start_turf,
|
||||
$start_dirt,
|
||||
$start_sprint,
|
||||
$start_mile,
|
||||
$start_medium,
|
||||
$start_long,
|
||||
$start_front_runner,
|
||||
$start_pace_chaser,
|
||||
$start_late_surger,
|
||||
$start_end_closer,
|
||||
|
||||
$fans,
|
||||
$race_program_id,
|
||||
$reserve_race_program_id,
|
||||
$race_running_style,
|
||||
$is_short_race,
|
||||
|
||||
$succession_trained_chara_id_1,
|
||||
$succession_trained_chara_id_2
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
INSERT INTO gain VALUES (
|
||||
$trainer_id,
|
||||
$trained_chara_id,
|
||||
$source,
|
||||
|
||||
$gain_speed,
|
||||
$gain_stamina,
|
||||
$gain_power,
|
||||
$gain_guts,
|
||||
$gain_wit,
|
||||
$gain_skill_point,
|
||||
|
||||
$gain_max_speed,
|
||||
$gain_max_stamina,
|
||||
$gain_max_power,
|
||||
$gain_max_guts,
|
||||
$gain_max_wit,
|
||||
|
||||
$gain_turf,
|
||||
$gain_dirt,
|
||||
|
||||
$gain_sprint,
|
||||
$gain_mile,
|
||||
$gain_medium,
|
||||
$gain_long,
|
||||
|
||||
$gain_front_runner,
|
||||
$gain_pace_chaser,
|
||||
$gain_late_surger,
|
||||
$gain_end_closer
|
||||
)
|
||||
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/umadump/ism"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
uri, journalMode string
|
||||
fs []string
|
||||
trainer int64
|
||||
logLevel slog.Level
|
||||
)
|
||||
flag.StringVar(&uri, "db", "idle_single_mode.sqlite3", "output database `URI` or filename")
|
||||
flag.StringVar(&journalMode, "journal", "memory", "journal `mode` to apply to database connections")
|
||||
flag.Int64Var(&trainer, "t", 0, "trainer `ID` to associate with the data")
|
||||
flag.TextVar(&logLevel, "log", slog.LevelInfo, "log `level`")
|
||||
flag.Func("d", "`dir`ectory containing idle single mode dumps to load (repeatable)", func(s string) error {
|
||||
es, err := os.ReadDir(s)
|
||||
for _, e := range es {
|
||||
if e.IsDir() {
|
||||
continue
|
||||
}
|
||||
fs = append(fs, filepath.Join(s, e.Name()))
|
||||
}
|
||||
return err
|
||||
})
|
||||
flag.Parse()
|
||||
fs = append(fs, flag.Args()...)
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
stop()
|
||||
}()
|
||||
|
||||
log := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}))
|
||||
db := opendb(uri, journalMode)
|
||||
ok := 0
|
||||
for _, n := range fs {
|
||||
log := log.With(slog.String("file", n))
|
||||
log.Info("begin")
|
||||
f, err := os.Open(n)
|
||||
if err != nil {
|
||||
log.Error("open", slog.Any("err", err))
|
||||
continue
|
||||
}
|
||||
var career ism.WorkIdleSingleMode
|
||||
d := json.NewDecoder(f)
|
||||
d.DisallowUnknownFields()
|
||||
log.Debug("decode")
|
||||
if err := d.Decode(&career); err != nil {
|
||||
log.Error("load", slog.Any("err", err))
|
||||
continue
|
||||
}
|
||||
log.Debug("insert")
|
||||
err = insert(ctx, db, log, &career, trainer)
|
||||
if err != nil {
|
||||
log.Error("insert", slog.Any("err", err))
|
||||
continue
|
||||
}
|
||||
ok++
|
||||
}
|
||||
slog.Info("done", slog.Int("careers", ok))
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
CREATE TABLE IF NOT EXISTS career (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
card_id INTEGER NOT NULL,
|
||||
scenario_id INTEGER NOT NULL,
|
||||
route_id INTEGER NOT NULL,
|
||||
start_time TEXT NOT NULL,
|
||||
end_time TEXT NOT NULL,
|
||||
|
||||
chara_grade INTEGER NOT NULL,
|
||||
star_level INTEGER NOT NULL,
|
||||
potential_level INTEGER NOT NULL,
|
||||
|
||||
speed INTEGER NOT NULL,
|
||||
stamina INTEGER NOT NULL,
|
||||
power INTEGER NOT NULL,
|
||||
guts INTEGER NOT NULL,
|
||||
wit INTEGER NOT NULL,
|
||||
energy INTEGER NOT NULL,
|
||||
max_speed INTEGER NOT NULL,
|
||||
max_stamina INTEGER NOT NULL,
|
||||
max_power INTEGER NOT NULL,
|
||||
max_guts INTEGER NOT NULL,
|
||||
max_wit INTEGER NOT NULL,
|
||||
max_energy INTEGER NOT NULL,
|
||||
skill_point INTEGER NOT NULL,
|
||||
mood INTEGER NOT NULL,
|
||||
|
||||
turf INTEGER NOT NULL,
|
||||
dirt INTEGER NOT NULL,
|
||||
sprint INTEGER NOT NULL,
|
||||
mile INTEGER NOT NULL,
|
||||
medium INTEGER NOT NULL,
|
||||
long INTEGER NOT NULL,
|
||||
front_runner INTEGER NOT NULL,
|
||||
pace_chaser INTEGER NOT NULL,
|
||||
late_surger INTEGER NOT NULL,
|
||||
end_closer INTEGER NOT NULL,
|
||||
|
||||
-- These fields are 0 if the career finished while it was not actively
|
||||
-- displayed on the client used to dump it.
|
||||
start_speed INTEGER NOT NULL,
|
||||
start_stamina INTEGER NOT NULL,
|
||||
start_power INTEGER NOT NULL,
|
||||
start_guts INTEGER NOT NULL,
|
||||
start_wit INTEGER NOT NULL,
|
||||
start_max_speed INTEGER NOT NULL,
|
||||
start_max_stamina INTEGER NOT NULL,
|
||||
start_max_power INTEGER NOT NULL,
|
||||
start_max_guts INTEGER NOT NULL,
|
||||
start_max_wit INTEGER NOT NULL,
|
||||
start_turf INTEGER NOT NULL,
|
||||
start_dirt INTEGER NOT NULL,
|
||||
start_sprint INTEGER NOT NULL,
|
||||
start_mile INTEGER NOT NULL,
|
||||
start_medium INTEGER NOT NULL,
|
||||
start_long INTEGER NOT NULL,
|
||||
start_front_runner INTEGER NOT NULL,
|
||||
start_pace_chaser INTEGER NOT NULL,
|
||||
start_late_surger INTEGER NOT NULL,
|
||||
start_end_closer INTEGER NOT NULL,
|
||||
|
||||
fans INTEGER NOT NULL,
|
||||
race_program_id INTEGER NOT NULL,
|
||||
reserve_race_program_id INTEGER NOT NULL,
|
||||
race_running_style INTEGER NOT NULL,
|
||||
is_short_race INTEGER NOT NULL,
|
||||
|
||||
succession_trained_chara_id_1 INTEGER NOT NULL,
|
||||
succession_trained_chara_id_2 INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id)
|
||||
) STRICT;
|
||||
CREATE INDEX IF NOT EXISTS career_by_scenario ON career (scenario_id);
|
||||
CREATE INDEX IF NOT EXISTS career_by_start_time ON career (start_time);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS condition (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
condition INTEGER NOT NULL,
|
||||
is_active INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, condition),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gain (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
source INTEGER NOT NULL, -- 0 for events, 1 for inspiration, otherwise support card id
|
||||
|
||||
gain_speed INTEGER NOT NULL,
|
||||
gain_stamina INTEGER NOT NULL,
|
||||
gain_power INTEGER NOT NULL,
|
||||
gain_guts INTEGER NOT NULL,
|
||||
gain_wit INTEGER NOT NULL,
|
||||
gain_skill_point INTEGER NOT NULL,
|
||||
|
||||
gain_max_speed INTEGER NOT NULL,
|
||||
gain_max_stamina INTEGER NOT NULL,
|
||||
gain_max_power INTEGER NOT NULL,
|
||||
gain_max_guts INTEGER NOT NULL,
|
||||
gain_max_wit INTEGER NOT NULL,
|
||||
|
||||
gain_turf INTEGER NOT NULL,
|
||||
gain_dirt INTEGER NOT NULL,
|
||||
|
||||
gain_sprint INTEGER NOT NULL,
|
||||
gain_mile INTEGER NOT NULL,
|
||||
gain_medium INTEGER NOT NULL,
|
||||
gain_long INTEGER NOT NULL,
|
||||
|
||||
gain_front_runner INTEGER NOT NULL,
|
||||
gain_pace_chaser INTEGER NOT NULL,
|
||||
gain_late_surger INTEGER NOT NULL,
|
||||
gain_end_closer INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, source),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
CREATE INDEX IF NOT EXISTS gain_by_source ON gain (source);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gain_skill_hint (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
source INTEGER NOT NULL,
|
||||
|
||||
group_id INTEGER NOT NULL,
|
||||
rarity INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, source, group_id, rarity),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id, source) REFERENCES gain ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS inspiration (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
year INTEGER NOT NULL,
|
||||
factor_id INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL, -- always 0 but just in case we get it in the future
|
||||
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
CREATE INDEX IF NOT EXISTS inspiration_by_career ON inspiration (trainer_id, trained_chara_id);
|
||||
CREATE INDEX IF NOT EXISTS inspiration_by_factor_id ON inspiration (factor_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS race_history (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
|
||||
turn INTEGER NOT NULL,
|
||||
program_id INTEGER NOT NULL,
|
||||
weather INTEGER NOT NULL,
|
||||
ground_condition INTEGER NOT NULL,
|
||||
running_style INTEGER NOT NULL,
|
||||
result_rank INTEGER NOT NULL,
|
||||
frame_order INTEGER NOT NULL,
|
||||
gained_fans INTEGER NOT NULL,
|
||||
lose_tips_id INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, turn),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS race_reward (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
turn INTEGER NOT NULL,
|
||||
|
||||
item_type INTEGER NOT NULL,
|
||||
item_id INTEGER NOT NULL,
|
||||
item_num INTEGER NOT NULL,
|
||||
|
||||
is_bonus INTEGER NOT NULL,
|
||||
is_plus_bonus INTEGER NOT NULL,
|
||||
is_bonus_win INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY (trainer_id, trained_chara_id, turn) REFERENCES race_history ON DELETE CASCADE
|
||||
) STRICT;
|
||||
CREATE INDEX IF NOT EXISTS race_reward_by_career_turn ON race_reward (trainer_id, trained_chara_id, turn);
|
||||
CREATE INDEX IF NOT EXISTS race_reward_by_item ON race_reward (item_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gained_skill (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
skill_id INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, skill_id),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS career_skill (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
skill_id INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, skill_id),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS career_skill_hint (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
|
||||
group_id INTEGER NOT NULL,
|
||||
rarity INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, group_id, rarity),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS career_support_card (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
position INTEGER NOT NULL,
|
||||
support_card_id INTEGER NOT NULL,
|
||||
limit_break_count INTEGER NOT NULL,
|
||||
exp INTEGER NOT NULL,
|
||||
owner_viewer_id INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, position),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE,
|
||||
UNIQUE (trainer_id, trained_chara_id, support_card_id)
|
||||
) STRICT;
|
||||
CREATE INDEX IF NOT EXISTS career_support_card_by_card ON career_support_card (support_card_id, exp);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS start_skill (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
skill_id INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, skill_id),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS start_skill_hint (
|
||||
trainer_id INTEGER NOT NULL DEFAULT 0,
|
||||
trained_chara_id INTEGER NOT NULL,
|
||||
|
||||
group_id INTEGER NOT NULL,
|
||||
rarity INTEGER NOT NULL,
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (trainer_id, trained_chara_id, group_id, rarity),
|
||||
FOREIGN KEY (trainer_id, trained_chara_id) REFERENCES career ON DELETE CASCADE
|
||||
) STRICT;
|
||||
@@ -0,0 +1,88 @@
|
||||
DROP VIEW IF EXISTS gain_event;
|
||||
DROP VIEW IF EXISTS gain_inspiration;
|
||||
DROP VIEW IF EXISTS gain_support_card;
|
||||
|
||||
CREATE VIEW gain_event AS
|
||||
SELECT
|
||||
trainer_id,
|
||||
trained_chara_id,
|
||||
gain_speed,
|
||||
gain_stamina,
|
||||
gain_power,
|
||||
gain_guts,
|
||||
gain_wit,
|
||||
gain_skill_point,
|
||||
gain_max_speed,
|
||||
gain_max_stamina,
|
||||
gain_max_power,
|
||||
gain_max_guts,
|
||||
gain_max_wit,
|
||||
gain_turf,
|
||||
gain_dirt,
|
||||
gain_sprint,
|
||||
gain_mile,
|
||||
gain_medium,
|
||||
gain_long,
|
||||
gain_front_runner,
|
||||
gain_pace_chaser,
|
||||
gain_late_surger,
|
||||
gain_end_closer
|
||||
FROM gain
|
||||
WHERE source = 0;
|
||||
|
||||
CREATE VIEW gain_inspiration AS
|
||||
SELECT
|
||||
trainer_id,
|
||||
trained_chara_id,
|
||||
gain_speed,
|
||||
gain_stamina,
|
||||
gain_power,
|
||||
gain_guts,
|
||||
gain_wit,
|
||||
gain_skill_point,
|
||||
gain_max_speed,
|
||||
gain_max_stamina,
|
||||
gain_max_power,
|
||||
gain_max_guts,
|
||||
gain_max_wit,
|
||||
gain_turf,
|
||||
gain_dirt,
|
||||
gain_sprint,
|
||||
gain_mile,
|
||||
gain_medium,
|
||||
gain_long,
|
||||
gain_front_runner,
|
||||
gain_pace_chaser,
|
||||
gain_late_surger,
|
||||
gain_end_closer
|
||||
FROM gain
|
||||
WHERE source = 1;
|
||||
|
||||
CREATE VIEW gain_support_card AS
|
||||
SELECT
|
||||
trainer_id,
|
||||
trained_chara_id,
|
||||
source AS support_card_id,
|
||||
gain_speed,
|
||||
gain_stamina,
|
||||
gain_power,
|
||||
gain_guts,
|
||||
gain_wit,
|
||||
gain_skill_point,
|
||||
gain_max_speed,
|
||||
gain_max_stamina,
|
||||
gain_max_power,
|
||||
gain_max_guts,
|
||||
gain_max_wit,
|
||||
gain_turf,
|
||||
gain_dirt,
|
||||
gain_sprint,
|
||||
gain_mile,
|
||||
gain_medium,
|
||||
gain_long,
|
||||
gain_front_runner,
|
||||
gain_pace_chaser,
|
||||
gain_late_surger,
|
||||
gain_end_closer
|
||||
FROM gain
|
||||
WHERE source > 1;
|
||||
+5
-1
@@ -21,7 +21,7 @@ type SingleModeSupportCard struct {
|
||||
ID horse.SupportCardID `json:"support_card_id"`
|
||||
LimitBreak int32 `json:"limit_break_count"`
|
||||
Exp int32 `json:"exp"`
|
||||
OwnerID int32 `json:"owner_viewer_id"`
|
||||
OwnerID int64 `json:"owner_viewer_id"`
|
||||
}
|
||||
|
||||
type GroupOuting struct {
|
||||
@@ -318,6 +318,7 @@ type End struct {
|
||||
TrophyRewardInfo *umadump.Never `json:"trophy_reward_info"`
|
||||
PrevCharaGrade *umadump.Never `json:"prev_chara_grade"`
|
||||
RaceAddRewardInfo []umadump.Never `json:"race_add_reward_info"`
|
||||
ReservedRaceInfo *umadump.Never `json:"reserved_race_info"`
|
||||
Missions []umadump.Never `json:"mission_list"`
|
||||
StoryEventMissions []umadump.Never `json:"story_event_mission_list"`
|
||||
StoryEventCharaBonuses []umadump.Never `json:"story_event_chara_bonus_list"`
|
||||
@@ -335,6 +336,8 @@ type ProgressInfo struct {
|
||||
StartTime string `json:"start_time"`
|
||||
EndTime string `json:"end_time"`
|
||||
DressID int32 `json:"dress_id"`
|
||||
StoryEventMissions []umadump.Never `json:"story_event_mission_list"`
|
||||
StoryEventCharaBonuses []umadump.Never `json:"story_event_chara_bonus_list"`
|
||||
}
|
||||
|
||||
type WorkIdleSingleMode struct {
|
||||
@@ -342,4 +345,5 @@ type WorkIdleSingleMode struct {
|
||||
ProgressLog IdleSingleModeProgressLog `json:"progress_log_info"`
|
||||
End End `json:"end_info"`
|
||||
OldChara *SingleModeChara `json:"chara_info"`
|
||||
Extra map[string]any `json:"extra_data"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user