Migrate accessories to user data

- Add user_accessory as the per-user accessory inventory table.
- Migrate old accessory wear records to user-owned accessory ids, including legacy common_accessory_m lookups for old installs.
- Allocate default accessories for newly created users and update accessory reads to use user_accessory at runtime.
- Validate accessory ownership when wearing accessories and keep existing accessory-based responses working.

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2026-06-13 07:36:21 +08:00
parent 17336de1b7
commit cb0200ff29
11 changed files with 436 additions and 72 deletions
+4 -14
View File
@@ -325,17 +325,7 @@ func getAccessoryInfo(ss *session.Session, targetUserID, unitOwningUserID int) (
return nil, nil return nil, nil
} }
accessoryData := struct { has, accessoryData := ss.GetAccessoryByAccessoryOwningUserID(accessoryOwningID)
AccessoryID int `xorm:"accessory_id"`
Exp int `xorm:"exp"`
}{}
has, err = ss.MainEng.Table("common_accessory_m").
Where("accessory_owning_user_id = ?", accessoryOwningID).
Cols("accessory_id,exp").
Get(&accessoryData)
if err != nil {
return nil, err
}
if !has { if !has {
return nil, nil return nil, nil
} }
@@ -345,9 +335,9 @@ func getAccessoryInfo(ss *session.Session, targetUserID, unitOwningUserID int) (
AccessoryID: accessoryData.AccessoryID, AccessoryID: accessoryData.AccessoryID,
Exp: accessoryData.Exp, Exp: accessoryData.Exp,
NextExp: 0, NextExp: 0,
Level: 8, Level: accessoryData.MaxLevel,
MaxLevel: 8, MaxLevel: accessoryData.MaxLevel,
RankUpCount: 4, RankUpCount: accessoryData.MaxLevel - accessoryData.DefaultMaxLevel,
FavoriteFlag: true, FavoriteFlag: true,
}, nil }, nil
} }
+1 -1
View File
@@ -12,7 +12,7 @@ func unitAccessoryAll(ctx *gin.Context) (res any, err error) {
ss := session.Get(ctx) ss := session.Get(ctx)
accessoryList := []unitapischema.AccessoryList{} accessoryList := []unitapischema.AccessoryList{}
err = ss.MainEng.Table("common_accessory_m").Find(&accessoryList) err = ss.UserEng.Table("user_accessory").Where("user_id = ?", ss.UserID).Find(&accessoryList)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+12 -17
View File
@@ -178,23 +178,18 @@ func buildCenterUnitInfo(ss *session.Session, userID, unitOwningUserID, awardID
return info, err return info, err
} }
if has && accessoryWear.AccessoryOwningUserID > 0 { if has && accessoryWear.AccessoryOwningUserID > 0 {
var accessoryID, exp int hasAccessory, accessoryData := ss.GetAccessoryByAccessoryOwningUserID(accessoryWear.AccessoryOwningUserID)
_, err = ss.MainEng.Table("common_accessory_m"). if hasAccessory {
Where("accessory_owning_user_id = ?", accessoryWear.AccessoryOwningUserID). accessoryInfo = friendschema.AccessoryInfo{
Cols("accessory_id,exp"). AccessoryOwningUserID: accessoryWear.AccessoryOwningUserID,
Get(&accessoryID, &exp) AccessoryID: accessoryData.AccessoryID,
if err != nil { Exp: accessoryData.Exp,
return info, err NextExp: 0,
} Level: accessoryData.MaxLevel,
accessoryInfo = friendschema.AccessoryInfo{ MaxLevel: accessoryData.MaxLevel,
AccessoryOwningUserID: accessoryWear.AccessoryOwningUserID, RankUpCount: accessoryData.MaxLevel - accessoryData.DefaultMaxLevel,
AccessoryID: accessoryID, FavoriteFlag: true,
Exp: exp, }
NextExp: 0,
Level: 8,
MaxLevel: 8,
RankUpCount: 4,
FavoriteFlag: true,
} }
} }
+8
View File
@@ -290,6 +290,14 @@ func addUser(dbSession *xorm.Session, phone, password string, isDefault bool) (g
} }
return loginData, loginCode, loginMsg, created, err return loginData, loginCode, loginMsg, created, err
} }
err = usermodel.EnsureUserAccessories(dbSession, db.MainEng, userID, nil)
if err != nil {
if localSession {
dbSession.Rollback()
}
return loginData, loginCode, loginMsg, created, err
}
} }
// 检查用户卡组配置 // 检查用户卡组配置
+34 -6
View File
@@ -47,6 +47,7 @@ type memberTagMatchKey struct {
type accessoryBonusRow struct { type accessoryBonusRow struct {
AccessoryOwningUserID int `xorm:"accessory_owning_user_id"` AccessoryOwningUserID int `xorm:"accessory_owning_user_id"`
AccessoryID int `xorm:"accessory_id"`
Smile float64 `xorm:"smile_max"` Smile float64 `xorm:"smile_max"`
Pure float64 `xorm:"pure_max"` Pure float64 `xorm:"pure_max"`
Cool float64 `xorm:"cool_max"` Cool float64 `xorm:"cool_max"`
@@ -219,24 +220,51 @@ func loadAccessoryBonusMap(ss *session.Session, userID int, unitOwningUserIDs []
} }
rows := []accessoryBonusRow{} rows := []accessoryBonusRow{}
err = ss.MainEng.Table("common_accessory_m"). err = ss.UserEng.Table("user_accessory").
Join("LEFT", "accessory_m", "common_accessory_m.accessory_id = accessory_m.accessory_id"). In("accessory_owning_user_id", accessoryIDs).
In("common_accessory_m.accessory_owning_user_id", accessoryIDs). Cols("accessory_owning_user_id,accessory_id").
Cols("common_accessory_m.accessory_owning_user_id,smile_max,pure_max,cool_max").
Find(&rows) Find(&rows)
if err != nil { if err != nil {
return nil, err return nil, err
} }
accessoryMap := make(map[int]accessoryBonus, len(rows)) accessoryIDSet := make(map[int]struct{}, len(rows))
for _, row := range rows { for _, row := range rows {
accessoryMap[row.AccessoryOwningUserID] = accessoryBonus{ accessoryIDSet[row.AccessoryID] = struct{}{}
}
accessoryIDList := make([]int, 0, len(accessoryIDSet))
for accessoryID := range accessoryIDSet {
accessoryIDList = append(accessoryIDList, accessoryID)
}
staticRows := []accessoryBonusRow{}
err = ss.MainEng.Table("accessory_m").
In("accessory_id", accessoryIDList).
Cols("accessory_id,smile_max,pure_max,cool_max").
Find(&staticRows)
if err != nil {
return nil, err
}
staticBonusMap := make(map[int]accessoryBonus, len(staticRows))
for _, row := range staticRows {
staticBonusMap[row.AccessoryID] = accessoryBonus{
Smile: row.Smile, Smile: row.Smile,
Pure: row.Pure, Pure: row.Pure,
Cool: row.Cool, Cool: row.Cool,
} }
} }
accessoryMap := make(map[int]accessoryBonus, len(rows))
for _, row := range rows {
bonus, ok := staticBonusMap[row.AccessoryID]
if !ok {
continue
}
accessoryMap[row.AccessoryOwningUserID] = bonus
}
result := make(map[int]accessoryBonus, len(unitToAccessoryID)) result := make(map[int]accessoryBonus, len(unitToAccessoryID))
for unitOwningUserID, accessoryOwningUserID := range unitToAccessoryID { for unitOwningUserID, accessoryOwningUserID := range unitToAccessoryID {
if bonus, ok := accessoryMap[accessoryOwningUserID]; ok { if bonus, ok := accessoryMap[accessoryOwningUserID]; ok {
+4 -14
View File
@@ -134,17 +134,7 @@ func getGreetingAccessoryInfo(ss *session.Session, userID, unitOwningUserID int)
return nil, nil return nil, nil
} }
accessoryData := struct { has, accessoryData := ss.GetAccessoryByAccessoryOwningUserID(accessoryWear.AccessoryOwningUserID)
AccessoryID int `xorm:"accessory_id"`
Exp int `xorm:"exp"`
}{}
has, err = ss.MainEng.Table("common_accessory_m").
Where("accessory_owning_user_id = ?", accessoryWear.AccessoryOwningUserID).
Cols("accessory_id,exp").
Get(&accessoryData)
if err != nil {
return nil, err
}
if !has { if !has {
return nil, nil return nil, nil
} }
@@ -154,9 +144,9 @@ func getGreetingAccessoryInfo(ss *session.Session, userID, unitOwningUserID int)
AccessoryID: accessoryData.AccessoryID, AccessoryID: accessoryData.AccessoryID,
Exp: accessoryData.Exp, Exp: accessoryData.Exp,
NextExp: 0, NextExp: 0,
Level: 8, Level: accessoryData.MaxLevel,
MaxLevel: 8, MaxLevel: accessoryData.MaxLevel,
RankUpCount: 4, RankUpCount: accessoryData.MaxLevel - accessoryData.DefaultMaxLevel,
FavoriteFlag: true, FavoriteFlag: true,
}, nil }, nil
} }
+4 -14
View File
@@ -199,17 +199,7 @@ func getRankingAccessoryInfo(ss *session.Session, targetUserID, unitOwningUserID
return nil, nil return nil, nil
} }
accessoryData := struct { has, accessoryData := ss.GetAccessoryByAccessoryOwningUserID(accessoryOwningID)
AccessoryID int `xorm:"accessory_id"`
Exp int `xorm:"exp"`
}{}
has, err = ss.MainEng.Table("common_accessory_m").
Where("accessory_owning_user_id = ?", accessoryOwningID).
Cols("accessory_id,exp").
Get(&accessoryData)
if err != nil {
return nil, err
}
if !has { if !has {
return nil, nil return nil, nil
} }
@@ -219,9 +209,9 @@ func getRankingAccessoryInfo(ss *session.Session, targetUserID, unitOwningUserID
AccessoryID: accessoryData.AccessoryID, AccessoryID: accessoryData.AccessoryID,
Exp: accessoryData.Exp, Exp: accessoryData.Exp,
NextExp: 0, NextExp: 0,
Level: 8, Level: accessoryData.MaxLevel,
MaxLevel: 8, MaxLevel: accessoryData.MaxLevel,
RankUpCount: 4, RankUpCount: accessoryData.MaxLevel - accessoryData.DefaultMaxLevel,
FavoriteFlag: true, FavoriteFlag: true,
}, nil }, nil
} }
+14
View File
@@ -1,7 +1,9 @@
package unit package unit
import ( import (
"errors"
"honoka-chan/internal/middleware" "honoka-chan/internal/middleware"
usermodel "honoka-chan/internal/model/user"
"honoka-chan/internal/router" "honoka-chan/internal/router"
unitschema "honoka-chan/internal/schema/unit" unitschema "honoka-chan/internal/schema/unit"
"honoka-chan/internal/session" "honoka-chan/internal/session"
@@ -32,8 +34,20 @@ func wearAccessory(ctx *gin.Context) {
} }
// 佩戴饰品 // 佩戴饰品
var exists bool
for _, v := range req.Wear { for _, v := range req.Wear {
// fmt.Println("Wear:", v.AccessoryOwningUserID, v.UnitOwningUserID) // fmt.Println("Wear:", v.AccessoryOwningUserID, v.UnitOwningUserID)
exists, err = ss.UserEng.Table(new(usermodel.UserAccessory)).
Where("user_id = ? AND accessory_owning_user_id = ?", ss.UserID, v.AccessoryOwningUserID).
Exist()
if ss.CheckErr(err) {
return
}
if !exists {
ss.CheckErr(errors.New("accessory not found for user"))
return
}
data := unitschema.WearAccessoryData{ data := unitschema.WearAccessoryData{
AccessoryOwningUserID: v.AccessoryOwningUserID, AccessoryOwningUserID: v.AccessoryOwningUserID,
UnitOwningUserID: v.UnitOwningUserID, UnitOwningUserID: v.UnitOwningUserID,
+123
View File
@@ -0,0 +1,123 @@
package usermodel
import (
"fmt"
"sort"
"xorm.io/xorm"
)
type UserAccessory struct {
AccessoryOwningUserID int `xorm:"accessory_owning_user_id pk autoincr"`
UserID int `xorm:"user_id index"`
AccessoryID int `xorm:"accessory_id index"`
Exp int `xorm:"exp"`
}
func (UserAccessory) TableName() string {
return "user_accessory"
}
type accessoryTemplateRow struct {
AccessoryID int `xorm:"accessory_id"`
}
type userAccessoryCountRow struct {
AccessoryID int `xorm:"accessory_id"`
Count int `xorm:"cnt"`
}
func LoadAccessoryTemplateIDs(mainSession xorm.Interface) ([]int, error) {
rows := []accessoryTemplateRow{}
err := mainSession.Table("accessory_m").
Where("is_material = ? AND rarity = ?", 0, 4).
Cols("accessory_id").
OrderBy("accessory_id ASC").
Find(&rows)
if err != nil {
return nil, err
}
ids := make([]int, 0, len(rows))
for _, row := range rows {
ids = append(ids, row.AccessoryID)
}
return ids, nil
}
func EnsureUserAccessories(userSession *xorm.Session, mainSession xorm.Interface, userID int, minCount map[int]int) error {
accessoryIDs, err := LoadAccessoryTemplateIDs(mainSession)
if err != nil {
return err
}
existingRows := []userAccessoryCountRow{}
err = userSession.Table(new(UserAccessory)).
Select("accessory_id, COUNT(*) AS cnt").
Where("user_id = ?", userID).
GroupBy("accessory_id").
Find(&existingRows)
if err != nil {
return err
}
existingCount := make(map[int]int, len(existingRows))
for _, row := range existingRows {
existingCount[row.AccessoryID] = row.Count
}
for _, accessoryID := range accessoryIDs {
targetCount := 1
if count, ok := minCount[accessoryID]; ok && count > targetCount {
targetCount = count
}
for existingCount[accessoryID] < targetCount {
_, err = userSession.Insert(&UserAccessory{
UserID: userID,
AccessoryID: accessoryID,
Exp: 0,
})
if err != nil {
return err
}
existingCount[accessoryID]++
}
}
return nil
}
func BuildAccessoryOwningUserIDMap(userSession *xorm.Session, userID int) (map[int][]int, error) {
rows := []UserAccessory{}
err := userSession.Table(new(UserAccessory)).
Where("user_id = ?", userID).
OrderBy("accessory_id ASC, accessory_owning_user_id ASC").
Find(&rows)
if err != nil {
return nil, err
}
result := make(map[int][]int)
for _, row := range rows {
result[row.AccessoryID] = append(result[row.AccessoryID], row.AccessoryOwningUserID)
}
return result, nil
}
func ResolveAccessoryOwningUserIDsByAccessoryID(owningIDs map[int][]int, requiredCounts map[int]int) (map[int][]int, error) {
result := make(map[int][]int, len(requiredCounts))
for accessoryID, count := range requiredCounts {
ids := owningIDs[accessoryID]
if len(ids) < count {
return nil, fmt.Errorf("insufficient user accessories for accessory_id=%d need=%d have=%d", accessoryID, count, len(ids))
}
result[accessoryID] = append([]int(nil), ids[:count]...)
}
for accessoryID := range result {
sort.Ints(result[accessoryID])
}
return result, nil
}
+27 -6
View File
@@ -17,12 +17,11 @@ func (ss *Session) GetUserAccessoryWearByUnitOwningUserID(unitOwningUserID int)
return has, &wearData return has, &wearData
} }
func (ss *Session) GetAccessoryByAccessoryOwningUserID(accessoryOwningUserID int) (bool, *accessorymodel.Accessory) { func (ss *Session) GetUserAccessoryByAccessoryOwningUserID(accessoryOwningUserID int) (bool, *usermodel.UserAccessory) {
accessoryData := accessorymodel.Accessory{} accessoryData := usermodel.UserAccessory{}
has, err := ss.MainEng.Table("common_accessory_m").Alias("a"). has, err := ss.UserEng.Table(new(usermodel.UserAccessory)).
Join("LEFT", "accessory_m", "a.accessory_id = accessory_m.accessory_id"). Where("accessory_owning_user_id = ?", accessoryOwningUserID).
Where("a.accessory_owning_user_id = ?", accessoryOwningUserID). Get(&accessoryData)
Cols("accessory_m.*,a.exp").Get(&accessoryData)
if ss.CheckErr(err) { if ss.CheckErr(err) {
return false, nil return false, nil
} }
@@ -30,6 +29,28 @@ func (ss *Session) GetAccessoryByAccessoryOwningUserID(accessoryOwningUserID int
return has, &accessoryData return has, &accessoryData
} }
func (ss *Session) GetAccessoryByAccessoryOwningUserID(accessoryOwningUserID int) (bool, *accessorymodel.Accessory) {
has, userAccessoryData := ss.GetUserAccessoryByAccessoryOwningUserID(accessoryOwningUserID)
if !has {
return false, nil
}
accessoryData := accessorymodel.Accessory{}
has, err := ss.MainEng.Table("accessory_m").
Where("accessory_id = ?", userAccessoryData.AccessoryID).
Get(&accessoryData)
if ss.CheckErr(err) {
return false, nil
}
if !has {
return false, nil
}
accessoryData.Exp = userAccessoryData.Exp
return has, &accessoryData
}
func (ss *Session) GetUserAccessoryInfoByUnitOwningUserID(unitOwningUserID int) (bool, *liverecordschema.AccessoryInfo) { func (ss *Session) GetUserAccessoryInfoByUnitOwningUserID(unitOwningUserID int) (bool, *liverecordschema.AccessoryInfo) {
has, wearData := ss.GetUserAccessoryWearByUnitOwningUserID(unitOwningUserID) has, wearData := ss.GetUserAccessoryWearByUnitOwningUserID(unitOwningUserID)
if !has { if !has {
+205
View File
@@ -22,6 +22,7 @@ func CreateTables() {
// db.UserEng.ShowSQL(true) // db.UserEng.ShowSQL(true)
db.UserEng.Sync2(new(ghomemodel.DeviceKey)) db.UserEng.Sync2(new(ghomemodel.DeviceKey))
db.UserEng.Sync2(new(loginmodel.AuthKey)) db.UserEng.Sync2(new(loginmodel.AuthKey))
db.UserEng.Sync2(new(usermodel.UserAccessory))
db.UserEng.Sync2(new(usermodel.UserAccessoryWear)) db.UserEng.Sync2(new(usermodel.UserAccessoryWear))
db.UserEng.Sync2(new(usermodel.UserDeck)) db.UserEng.Sync2(new(usermodel.UserDeck))
db.UserEng.Sync2(new(usermodel.UserDeckUnit)) db.UserEng.Sync2(new(usermodel.UserDeckUnit))
@@ -39,6 +40,7 @@ func CreateTables() {
db.UserEng.Sync2(new(usermodel.UserUnitSkillEquip)) db.UserEng.Sync2(new(usermodel.UserUnitSkillEquip))
MigrateUserPref() MigrateUserPref()
MigrateUserAccessories()
MigrateUserLiveData() MigrateUserLiveData()
} }
@@ -67,6 +69,209 @@ func MigrateUserPref() {
} }
} }
type accessoryOwningMapRow struct {
AccessoryOwningUserID int `xorm:"accessory_owning_user_id"`
AccessoryID int `xorm:"accessory_id"`
}
func MigrateUserAccessories() {
session := db.UserEng.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
userIDs := []int{}
if err := session.Table(new(usermodel.Users)).Cols("user_id").Find(&userIDs); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
templateAccessoryIDs, err := usermodel.LoadAccessoryTemplateIDs(db.MainEng)
if err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
legacyAccessoryMap := map[int]int{}
hasLegacyTable, err := db.MainEng.IsTableExist("common_accessory_m")
if err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
if hasLegacyTable {
legacyRows := []accessoryOwningMapRow{}
if err := db.MainEng.Table("common_accessory_m").
Cols("accessory_owning_user_id,accessory_id").
Find(&legacyRows); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
for _, row := range legacyRows {
legacyAccessoryMap[row.AccessoryOwningUserID] = row.AccessoryID
}
}
wearRows := []usermodel.UserAccessoryWear{}
if err := session.Table(new(usermodel.UserAccessoryWear)).Find(&wearRows); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
existingAccessories := []usermodel.UserAccessory{}
if err := session.Table(new(usermodel.UserAccessory)).Find(&existingAccessories); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
currentAccessoryMap := make(map[int]map[int]int)
for _, row := range existingAccessories {
if currentAccessoryMap[row.UserID] == nil {
currentAccessoryMap[row.UserID] = map[int]int{}
}
currentAccessoryMap[row.UserID][row.AccessoryOwningUserID] = row.AccessoryID
}
requiredCountsByUser := make(map[int]map[int]int, len(userIDs))
for _, row := range wearRows {
accessoryID, ok := resolveAccessoryIDForWear(currentAccessoryMap, legacyAccessoryMap, templateAccessoryIDs, row.UserID, row.AccessoryOwningUserID)
if !ok {
continue
}
if requiredCountsByUser[row.UserID] == nil {
requiredCountsByUser[row.UserID] = map[int]int{}
}
requiredCountsByUser[row.UserID][accessoryID]++
}
for _, userID := range userIDs {
if err := usermodel.EnsureUserAccessories(session, db.MainEng, userID, requiredCountsByUser[userID]); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
}
updatedAccessories := []usermodel.UserAccessory{}
if err := session.Table(new(usermodel.UserAccessory)).
OrderBy("user_id ASC, accessory_id ASC, accessory_owning_user_id ASC").
Find(&updatedAccessories); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
currentAccessoryMap = make(map[int]map[int]int)
availableOwningIDs := make(map[int]map[int][]int)
for _, row := range updatedAccessories {
if currentAccessoryMap[row.UserID] == nil {
currentAccessoryMap[row.UserID] = map[int]int{}
}
if availableOwningIDs[row.UserID] == nil {
availableOwningIDs[row.UserID] = map[int][]int{}
}
currentAccessoryMap[row.UserID][row.AccessoryOwningUserID] = row.AccessoryID
availableOwningIDs[row.UserID][row.AccessoryID] = append(availableOwningIDs[row.UserID][row.AccessoryID], row.AccessoryOwningUserID)
}
usedOwningIDs := make(map[int]map[int]struct{})
for _, row := range wearRows {
if currentAccessoryMap[row.UserID] == nil {
continue
}
if _, ok := currentAccessoryMap[row.UserID][row.AccessoryOwningUserID]; !ok {
continue
}
if usedOwningIDs[row.UserID] == nil {
usedOwningIDs[row.UserID] = map[int]struct{}{}
}
usedOwningIDs[row.UserID][row.AccessoryOwningUserID] = struct{}{}
}
for i := range wearRows {
row := wearRows[i]
if row.AccessoryOwningUserID <= 0 {
continue
}
if currentAccessoryMap[row.UserID] != nil {
if _, ok := currentAccessoryMap[row.UserID][row.AccessoryOwningUserID]; ok {
continue
}
}
accessoryID, ok := resolveAccessoryIDForWear(currentAccessoryMap, legacyAccessoryMap, templateAccessoryIDs, row.UserID, row.AccessoryOwningUserID)
if !ok {
continue
}
candidates := availableOwningIDs[row.UserID][accessoryID]
if len(candidates) == 0 {
continue
}
if usedOwningIDs[row.UserID] == nil {
usedOwningIDs[row.UserID] = map[int]struct{}{}
}
newOwningID := 0
for _, candidate := range candidates {
if _, used := usedOwningIDs[row.UserID][candidate]; used {
continue
}
newOwningID = candidate
break
}
if newOwningID == 0 {
newOwningID = candidates[0]
}
if _, err := session.Table(new(usermodel.UserAccessoryWear)).
ID(row.ID).
Cols("accessory_owning_user_id").
Update(&usermodel.UserAccessoryWear{AccessoryOwningUserID: newOwningID}); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
wearRows[i].AccessoryOwningUserID = newOwningID
usedOwningIDs[row.UserID][newOwningID] = struct{}{}
}
if err := session.Commit(); err != nil {
session.Rollback()
log.Fatalln("迁移 user_accessory 失败:", err.Error())
}
}
func resolveAccessoryIDForWear(currentAccessoryMap map[int]map[int]int, legacyAccessoryMap map[int]int, accessoryIDs []int, userID int, accessoryOwningUserID int) (int, bool) {
if accessoryOwningUserID <= 0 {
return 0, false
}
if currentAccessoryMap[userID] != nil {
if accessoryID, ok := currentAccessoryMap[userID][accessoryOwningUserID]; ok {
return accessoryID, true
}
}
if accessoryID, ok := legacyAccessoryMap[accessoryOwningUserID]; ok {
return accessoryID, true
}
return legacyAccessoryOwningUserIDToAccessoryID(accessoryIDs, accessoryOwningUserID)
}
func legacyAccessoryOwningUserIDToAccessoryID(accessoryIDs []int, accessoryOwningUserID int) (int, bool) {
if accessoryOwningUserID <= 0 {
return 0, false
}
index := (accessoryOwningUserID - 1) / 9
if index < 0 || index >= len(accessoryIDs) {
return 0, false
}
return accessoryIDs[index], true
}
type liveGoalRewardMigrationRow struct { type liveGoalRewardMigrationRow struct {
LiveGoalRewardID int `xorm:"live_goal_reward_id"` LiveGoalRewardID int `xorm:"live_goal_reward_id"`
LiveDifficultyID int `xorm:"live_difficulty_id"` LiveDifficultyID int `xorm:"live_difficulty_id"`