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:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查用户卡组配置
|
// 检查用户卡组配置
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
Reference in New Issue
Block a user