Reorganize directory structures

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2025-08-05 20:06:35 +08:00
parent d666470272
commit adf2a72630
2087 changed files with 637 additions and 603 deletions
+83
View File
@@ -0,0 +1,83 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"github.com/gin-gonic/gin"
)
type AlbumRes struct {
UnitId int `xorm:"unit_id"`
Rarity int `xorm:"rarity"`
}
func AlbumSeriesAll(ctx *gin.Context) {
var albumIds []int
err := MainEng.Table("album_series_m").Select("album_series_id").Find(&albumIds)
utils.CheckErr(err)
// fmt.Println(albumIds)
albumSeriesAllRes := []model.AlbumSeriesRes{}
for _, albumId := range albumIds {
unitList := []AlbumRes{}
err = MainEng.Table("unit_m").Where("album_series_id = ?", albumId).Cols("unit_id,rarity").Find(&unitList)
utils.CheckErr(err)
albumSeriesAll := []model.AlbumResult{}
for _, unit := range unitList {
albumSeries := model.AlbumResult{
UnitID: unit.UnitId,
RankMaxFlag: true,
LoveMaxFlag: true,
RankLevelMaxFlag: true,
AllMaxFlag: true,
TotalLove: 10000,
FavoritePoint: 1000,
}
if unit.Rarity != 4 {
switch unit.Rarity {
case 1:
// N
albumSeries.HighestLovePerUnit = 50
case 2:
// R
albumSeries.HighestLovePerUnit = 200
case 3:
// SR
albumSeries.HighestLovePerUnit = 500
case 5:
// SSR
albumSeries.HighestLovePerUnit = 750
}
} else {
// UR
albumSeries.HighestLovePerUnit = 1000
// IsSigned
albumSeries.SignFlag = utils.IsSigned(unit.UnitId)
}
albumSeriesAll = append(albumSeriesAll, albumSeries)
}
albumSeriesAllRes = append(albumSeriesAllRes, model.AlbumSeriesRes{
SeriesID: albumId,
UnitList: albumSeriesAll,
})
}
albumResp := model.AlbumSeriesResp{
ResponseData: albumSeriesAllRes,
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(albumResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+37
View File
@@ -0,0 +1,37 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"html/template"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func AnnounceIndex(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "common/announce.html", gin.H{
"title": "Love Live! 学园偶像祭 本地服务器",
"content": template.HTML(`目前开发完毕的功能包括:<br><ul><li>登录</li><li>相册</li><li>编队</li><li>饰品</li><li>宝石</li><li>Live</li><li>个人信息设置</li><li>官方漫画</li><ul><br>
其他功能仍在开发中,有报错属于正常现象。<br><br>
侵权联系:<a href="https://space.bilibili.com/671443">梦路_YumeMichi @bilibili</a> 进行删除。`),
})
}
func AnnounceCheckState(ctx *gin.Context) {
announceResp := model.AnnounceResp{
ResponseData: model.AnnounceRes{
HasUnreadAnnounce: false,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(announceResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"net/http"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)
func AwardSet(ctx *gin.Context) {
req := gjson.Parse(ctx.PostForm("request_data"))
pref := tools.UserPref{
AwardID: int(req.Get("award_id").Int()),
}
_, err := UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref)
utils.CheckErr(err)
awardResp := model.AwardSetResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(awardResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+31
View File
@@ -0,0 +1,31 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"net/http"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)
func BackgroundSet(ctx *gin.Context) {
req := gjson.Parse(ctx.PostForm("request_data"))
pref := tools.UserPref{
BackgroundID: int(req.Get("background_id").Int()),
}
_, err := UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref)
utils.CheckErr(err)
backgroundResp := model.BackgroundSetResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(backgroundResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+176
View File
@@ -0,0 +1,176 @@
package handler
import (
"encoding/json"
"fmt"
"honoka-chan/config"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"io"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"xorm.io/builder"
)
type PkgInfo struct {
Id int `xorm:"pkg_id"`
Order int `xorm:"pkg_order"`
Size int `xorm:"pkg_size"`
}
func DownloadAdditional(ctx *gin.Context) {
downloadReq := model.AdditionalReq{}
if err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.AdditionalRes{}
if SifCdnServer != "" {
pkgType, pkgId := downloadReq.PackageType, downloadReq.PackageID
var pkgInfo []PkgInfo
err := MainEng.Table("download_m").Where("pkg_type = ? AND pkg_id = ? AND pkg_os = ?", pkgType, pkgId, downloadReq.TargetOs).
Cols("pkg_id,pkg_order,pkg_size").
OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo)
utils.CheckErr(err)
for _, pkg := range pkgInfo {
pkgList = append(pkgList, model.AdditionalRes{
Size: pkg.Size,
URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", SifCdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order),
})
}
}
addResp := model.AdditionalResp{
ResponseData: pkgList,
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(addResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func DownloadBatch(ctx *gin.Context) {
downloadReq := model.BatchReq{}
if err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.BatchRes{}
if downloadReq.ClientVersion == config.PackageVersion && SifCdnServer != "" {
pkgType := downloadReq.PackageType
var pkgInfo []PkgInfo
err := MainEng.Table("download_m").Where(builder.NotIn("pkg_id", downloadReq.ExcludedPackageIds)).Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.Os).
Cols("pkg_id,pkg_order,pkg_size").
OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo)
utils.CheckErr(err)
for _, pkg := range pkgInfo {
pkgList = append(pkgList, model.BatchRes{
Size: pkg.Size,
URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", SifCdnServer, downloadReq.Os, pkgType, pkg.Id, pkg.Order),
})
}
}
batchResp := model.BatchResp{
ResponseData: pkgList,
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(batchResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func DownloadUpdate(ctx *gin.Context) {
downloadReq := model.UpdateReq{}
if err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq); err != nil {
panic(err)
}
pkgList := []model.UpdateRes{}
if downloadReq.ExternalVersion != config.PackageVersion && SifCdnServer != "" {
pkgType := 99
var pkgInfo []PkgInfo
err := MainEng.Table("download_m").Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.TargetOs).
Cols("pkg_id,pkg_order,pkg_size").
OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo)
utils.CheckErr(err)
for _, pkg := range pkgInfo {
pkgList = append(pkgList, model.UpdateRes{
Size: pkg.Size,
URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", SifCdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order),
Version: config.PackageVersion,
})
}
patchFileUrl := fmt.Sprintf("%s/%s/archives/99_0_115.zip", SifCdnServer, downloadReq.TargetOs)
resp, err := http.Get(patchFileUrl)
if err == nil {
res, err := io.ReadAll(resp.Body)
if err == nil {
pkgList = append(pkgList, model.UpdateRes{
Size: len(res),
URL: patchFileUrl,
Version: config.PackageVersion,
})
}
defer resp.Body.Close()
}
}
updateResp := model.UpdateResp{
ResponseData: pkgList,
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(updateResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func DownloadUrl(ctx *gin.Context) {
// Extract SQL: SELECT CAST(pkg_type AS TEXT) || '_' || CAST(pkg_id AS TEXT) || '_' || CAST(pkg_order AS TEXT) || '.zip' AS zip_name FROM download_m ORDER BY pkg_type ASC,pkg_id ASC, pkg_order ASC;
// Extract Cmd: cat list.txt | while read line; do; unzip -o $line; done
downloadReq := model.UrlReq{}
if err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq); err != nil {
panic(err)
}
urlList := []string{}
for _, v := range downloadReq.PathList {
urlList = append(urlList, fmt.Sprintf("%s/%s/extracted/%s", SifCdnServer, downloadReq.Os, strings.ReplaceAll(v, "\\", "")))
}
urlResp := model.UrlResp{
ResponseData: model.UrlRes{
UrlList: urlList,
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(urlResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func DownloadEvent(ctx *gin.Context) {
eventResp := model.EventResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(eventResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+34
View File
@@ -0,0 +1,34 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func EventList(ctx *gin.Context) {
targets := []model.TargetList{}
for i := 0; i < 6; i++ {
targets = append(targets, model.TargetList{
Position: i + 1,
IsDisplayable: false,
})
}
eventsResp := model.EventsResp{
ResponseData: model.EventsRes{
TargetList: targets,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(eventsResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+28
View File
@@ -0,0 +1,28 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func Gdpr(ctx *gin.Context) {
gdprResp := model.GdprResp{
ResponseData: model.GdprRes{
EnableGdpr: true,
IsEea: false,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(gdprResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+23
View File
@@ -0,0 +1,23 @@
package handler
import (
"honoka-chan/config"
"honoka-chan/pkg/db"
"xorm.io/xorm"
)
var (
SifCdnServer string
AsCdnServer string
ErrorMsg = `{"code":20001,"message":""}`
MainEng *xorm.Engine
UserEng *xorm.Engine
)
func init() {
SifCdnServer = config.Conf.Settings.SifCdnServer
MainEng = db.MainEng
UserEng = db.UserEng
}
+156
View File
@@ -0,0 +1,156 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func LBonusExecute(ctx *gin.Context) {
weeks := map[string]int{
"Monday": 1,
"Tuesday": 2,
"Wednesday": 3,
"Thursday": 4,
"Friday": 5,
"Saturday": 6,
"Sunday": 7,
}
// 本月日历
y, m, d := time.Now().Local().Date()
cm := m
d1 := time.Date(y, m, 1, 0, 0, 0, 0, time.Local)
// fmt.Println(d1)
// fmt.Println(weeks[d1.Weekday().String()])
d2 := d1.AddDate(0, 1, -1)
// fmt.Println(d2)
weeksList := []model.LbDays{}
for c := d1; ; c = c.AddDate(0, 0, 1) {
_, _, rd := c.Date()
received := false
if rd <= d {
received = true
}
rw := weeks[c.Weekday().String()]
weeksList = append(weeksList, model.LbDays{
Day: rd,
DayOfTheWeek: rw,
SpecialDay: false,
SpecialImageAsset: "",
Received: received,
AdReceived: false,
Item: model.LbDayItem{
ItemID: 4,
AddType: 3001,
Amount: 1,
},
})
if c == d2 {
break
}
}
// 下月日历
y, m, _ = time.Now().AddDate(0, 1, 0).Date()
// fmt.Println(y, m, d)
d1 = time.Date(y, m, 1, 0, 0, 0, 0, time.Local)
// fmt.Println(d1)
// fmt.Println(weeks[d1.Weekday().String()])
d2 = d1.AddDate(0, 1, -1)
// fmt.Println(d2)
nextWeeksList := []model.LbDays{}
for c := d1; ; c = c.AddDate(0, 0, 1) {
_, _, rd := c.Date()
rw := weeks[c.Weekday().String()]
nextWeeksList = append(nextWeeksList, model.LbDays{
Day: rd,
DayOfTheWeek: rw,
SpecialDay: false,
SpecialImageAsset: "",
Received: false,
AdReceived: false,
Item: model.LbDayItem{
ItemID: 4,
AddType: 3001,
Amount: 1,
},
})
if c == d2 {
break
}
}
LbRes := model.LbResp{
ResponseData: model.LbRes{
Sheets: []any{},
CalendarInfo: model.CalendarInfo{
CurrentDate: time.Now().Format("2006-01-02 03:04:05"),
CurrentMonth: model.LbMonth{
Year: y,
Month: int(cm),
Days: weeksList,
},
NextMonth: model.LbMonth{
Year: y,
Month: int(m),
Days: nextWeeksList,
},
},
TotalLoginInfo: model.TotalLoginInfo{
LoginCount: 2626,
RemainingCount: 74,
Reward: []model.Reward{
{
ItemID: 5,
AddType: 1000,
Amount: 5,
},
},
},
LicenseLbonusList: []any{},
ClassSystem: model.LbClassSystem{
RankInfo: model.LbRankInfo{
BeforeClassRankID: 10,
AfterClassRankID: 10,
RankUpDate: "2020-02-12 11:57:15",
},
CompleteFlag: false,
IsOpened: true,
IsVisible: true,
},
StartDashSheets: []any{},
EffortPoint: []model.EffortPoint{
{
LiveEffortPointBoxSpecID: 5,
Capacity: 4000000,
Before: 1400116,
After: 1400116,
Rewards: []model.Rewards{},
},
},
LimitedEffortBox: []any{},
MuseumInfo: model.Museum{},
ServerTimestamp: time.Now().Unix(),
PresentCnt: 0,
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(LbRes)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+693
View File
@@ -0,0 +1,693 @@
package handler
import (
"encoding/json"
"honoka-chan/config"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"honoka-chan/pkg/db"
honokautils "honoka-chan/pkg/utils"
"math"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)
func PartyList(ctx *gin.Context) {
resp := honokautils.ReadAllText("assets/serverdata/partylist.json")
ctx.Header("X-Message-Sign", utils.GenXMS([]byte(resp)))
ctx.String(http.StatusOK, resp)
}
func PlayLive(ctx *gin.Context) {
playReq := model.PlayReq{}
err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playReq)
utils.CheckErr(err)
tDifficultyId := playReq.LiveDifficultyID
difficultyId, err := strconv.Atoi(tDifficultyId)
utils.CheckErr(err)
deckId := playReq.UnitDeckID
// Save Deck Id for /live/reward
key := "live_deck_" + ctx.GetString("userid")
err = db.DB.Set([]byte(key), []byte(strconv.Itoa(deckId)))
utils.CheckErr(err)
// Song type: normal / special
// sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here.
sql := `SELECT notes_setting_asset,c_rank_score,b_rank_score,a_rank_score,s_rank_score,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)`
var notes_setting_asset string
var c_rank_score, b_rank_score, a_rank_score, s_rank_score, ac_flag, swing_flag int
err = MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(&notes_setting_asset, &c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &ac_flag, &swing_flag)
utils.CheckErr(err)
// fmt.Println(notes_setting_asset)
// fmt.Println(c_rank_score, b_rank_score, a_rank_score, s_rank_score)
notes := []model.NotesList{}
// fmt.Println("./assets/notes/" + notes_setting_asset)
notes_list := honokautils.ReadAllText("./assets/serverdata/notes/" + notes_setting_asset)
err = json.Unmarshal([]byte(notes_list), &notes)
utils.CheckErr(err)
ranks := []model.RankInfo{}
ranks = append(ranks, model.RankInfo{
Rank: 5,
RankMin: 0,
RankMax: c_rank_score,
}, model.RankInfo{
Rank: 4,
RankMin: c_rank_score + 1,
RankMax: b_rank_score,
}, model.RankInfo{
Rank: 3,
RankMin: b_rank_score + 1,
RankMax: a_rank_score,
}, model.RankInfo{
Rank: 2,
RankMin: a_rank_score + 1,
RankMax: s_rank_score,
}, model.RankInfo{
Rank: 1,
RankMin: s_rank_score + 1,
RankMax: 0,
})
// UserEng.ShowSQL(true)
// MainEng.ShowSQL(true)
owningIdList := []int{}
err = UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id").
Where("user_id = ? AND deck_id = ?", ctx.GetString("userid"), deckId).Cols("unit_owning_user_id").
OrderBy("deck_unit_m.position ASC").Find(&owningIdList)
utils.CheckErr(err)
unitList := []model.UnitList{}
var totalSmile, totalPure, totalCool, maxLove float64
var totalHp int
for _, owningId := range owningIdList {
var uId int
exists, err := MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", owningId).Cols("unit_id").Get(&uId)
utils.CheckErr(err)
var maxHp, attrId, unitTypeId int
var baseSmile, basePure, baseCool, smileMax, pureMax, coolMax float64
if exists {
// 公共卡片仅为100级属性
_, err = MainEng.Table("unit_m").Where("unit_id = ?", uId).
Join("LEFT", "unit_rarity_m", "unit_m.rarity = unit_rarity_m.rarity").
Cols("attribute_id,hp_max,smile_max,pure_max,cool_max,after_love_max,unit_type_id").
Get(&attrId, &maxHp, &baseSmile, &basePure, &baseCool, &maxLove, &unitTypeId)
utils.CheckErr(err)
} else {
// 用户卡片暂时固定为满级350级
exists, err := UserEng.Table("user_unit_m").Where("unit_owning_user_id = ?", owningId).Cols("unit_id").Get(&uId)
utils.CheckErr(err)
if exists {
// 卡片100级基础属性
_, err = MainEng.Table("unit_m").Where("unit_id = ?", uId).
Join("LEFT", "unit_rarity_m", "unit_m.rarity = unit_rarity_m.rarity").
Cols("attribute_id,hp_max,smile_max,pure_max,cool_max,after_love_max,unit_type_id").
Get(&attrId, &maxHp, &baseSmile, &basePure, &baseCool, &maxLove, &unitTypeId)
utils.CheckErr(err)
// 增量属性
var diffSmile, diffPure, diffCool float64
_, err = MainEng.Table("unit_level_limit_pattern_m").Where("unit_level_limit_id = 1 AND unit_level = 350").
Cols("smile_diff,pure_diff,cool_diff").Get(&diffSmile, &diffPure, &diffCool)
utils.CheckErr(err)
// 更新卡片属性(注意这里是负数,要用减号)
baseSmile -= diffSmile
basePure -= diffPure
baseCool -= diffCool
} else {
panic("no such unit")
}
}
// 饰品属性加成(满级)
var accessoryOwningId int
_, err = UserEng.Table("accessory_wear_m").Where("unit_owning_user_id = ?", owningId).
Cols("accessory_owning_user_id").Get(&accessoryOwningId)
utils.CheckErr(err)
var smileAccessory, pureAccessory, coolAccessory float64
_, err = MainEng.Table("common_accessory_m").Join("LEFT", "accessory_m", "common_accessory_m.accessory_id = accessory_m.accessory_id").
Where("accessory_owning_user_id = ?", accessoryOwningId).Cols("smile_max,pure_max,cool_max").
Get(&smileAccessory, &pureAccessory, &coolAccessory)
utils.CheckErr(err)
// fmt.Println("基础属性:", baseSmile, basePure, baseCool)
// 饰品属性加成(该加成会影响个宝等百分比宝石属性加成的计算,故先计算。)
baseSmile += smileAccessory
basePure += pureAccessory
baseCool += coolAccessory
// fmt.Println("饰品属性加成:", smileAccessory, pureAccessory, coolAccessory)
// fmt.Println("饰品属性加成后的基础属性:", baseSmile, basePure, baseCool)
// 回忆画廊属性加成(该加成会影响个宝等百分比宝石属性加成的计算,故先计算。)
var smileBuff, pureBuff, coolBuff float64
_, err = MainEng.Table("museum_contents_m").Select("SUM(smile_buff),SUM(pure_buff),SUM(cool_buff)").Get(&smileBuff, &pureBuff, &coolBuff)
utils.CheckErr(err)
baseSmile += smileBuff
basePure += pureBuff
baseCool += coolBuff
// fmt.Println("回忆画廊属性加成:", smileBuff, pureBuff, coolBuff)
// fmt.Println("回忆画廊属性加成后的基础属性:", baseSmile, basePure, baseCool)
// 绊属性加成(该加成会影响个宝等百分比宝石属性加成的计算,故先计算。)
if attrId == 1 {
baseSmile += maxLove
} else if attrId == 2 {
basePure += maxLove
} else if attrId == 3 {
baseCool += maxLove
}
// fmt.Println("绊属性加成:", maxLove)
// fmt.Println("绊属性加成后的基础属性:", baseSmile, basePure, baseCool)
// 宝石属性加成
var kissSmile, kissPure, kissCool float64
var skillSmile, skillPure, skillCool float64
// var mainCenterSmile, mainCenterPure, mainCenterCool float64
// var secCenterSmile, secCenterPure, secCenterCool float64
// 宝石加成(满级)
removableSkillIds := []int{}
err = UserEng.Table("skill_equip_m").Where("unit_owning_user_id = ? AND user_id = ?", owningId, ctx.GetString("userid")).
Cols("unit_removable_skill_id").Find(&removableSkillIds)
utils.CheckErr(err)
for _, sk := range removableSkillIds {
// 判断宝石效果类型(效果范围、效果类型、效果值、是否固定数值)
var effectRange, effectType, fixedValueFlag, refType int
var effectValue float64
_, err = MainEng.Table("unit_removable_skill_m").Where("unit_removable_skill_id = ?", sk).
Cols("effect_range,effect_type,effect_value,fixed_value_flag,target_reference_type").
Get(&effectRange, &effectType, &effectValue, &fixedValueFlag, &refType)
utils.CheckErr(err)
if fixedValueFlag == 1 {
// 吻、眼神属性加成(固定数值)
if effectType == 1 {
kissSmile += effectValue
} else if effectType == 2 {
kissPure += effectValue
} else if effectType == 3 {
kissCool += effectValue
}
// fmt.Println("吻、眼神属性加成:", kissSmile, kissPure, kissCool)
} else {
// 仅效果类型为1、2、3的有属性加成
if effectType == 1 || effectType == 2 || effectType == 3 {
// 加成范围:2:全员 1:非全员
if effectRange == 2 {
if effectType == 1 {
skillSmile += math.Ceil(baseSmile * (effectValue / 100))
} else if effectType == 2 {
skillPure += math.Ceil(basePure * (effectValue / 100))
} else if effectType == 3 {
skillCool += math.Ceil(baseCool * (effectValue / 100))
}
// fmt.Println("全员类宝石属性加成:", skillSmile, skillPure, skillCool)
} else {
// refType: 1 -> 年级类加成, target_type -> 指定年级(这里不需要使用,因为能装上宝石肯定是符合的)
// refType: 2 -> 个宝
// refType: 3 -> 爆分、奶、判宝石, 0 -> 竞技场宝石
if refType == 1 || refType == 2 { // 年级类和个宝都是百分比加成
if effectType == 1 {
skillSmile += math.Ceil(baseSmile * (effectValue / 100))
} else if effectType == 2 {
skillPure += math.Ceil(basePure * (effectValue / 100))
} else if effectValue == 3 {
skillCool += math.Ceil(baseCool * (effectValue / 100))
}
// fmt.Println("年级类宝石、个宝属性加成:", skillSmile, skillPure, skillCool)
}
}
}
}
}
// 单卡属性
smileMax = baseSmile + kissSmile + skillSmile
pureMax = basePure + kissPure + skillPure
coolMax = baseCool + kissCool + skillCool
// 主唱技能加成
var myCenterUnitId int
_, err = UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id").
Where("user_deck_m.deck_id = ? AND user_deck_m.user_id = ? AND deck_unit_m.position = 5", playReq.UnitDeckID, ctx.GetString("userid")).
Cols("deck_unit_m.unit_id").Get(&myCenterUnitId)
utils.CheckErr(err)
// 主唱技能加成:主C技能(这里不使用新C技能,即以某属性的百分比提升另一属性)
var myAttrId int
var myEffectValue float64
_, err = MainEng.Table("unit_m").
Join("LEFT", "unit_leader_skill_m", "unit_m.default_leader_skill_id = unit_leader_skill_m.unit_leader_skill_id").
Where("unit_m.unit_id = ?", myCenterUnitId).
Cols("unit_m.attribute_id,unit_leader_skill_m.effect_value").Get(&myAttrId, &myEffectValue)
utils.CheckErr(err)
var myCenterSmile, myCenterPure, myCenterCool float64
if myAttrId == 1 {
myCenterSmile = math.Ceil(smileMax * (myEffectValue / 100))
} else if myAttrId == 2 {
myCenterPure = math.Ceil(pureMax * (myEffectValue / 100))
} else if myAttrId == 3 {
myCenterCool = math.Ceil(coolMax * (myEffectValue / 100))
}
// fmt.Println("主C技能属性加成:", myCenterSmile, myCenterPure, myCenterCool)
// 主唱技能加成:副C技能
var mySubEffectValue float64
var myMemberTagId int
_, err = MainEng.Table("unit_m").
Join("LEFT", "unit_leader_skill_extra_m", "unit_m.default_leader_skill_id = unit_leader_skill_extra_m.unit_leader_skill_id").
Where("unit_m.unit_id = ?", myCenterUnitId).
Cols("unit_leader_skill_extra_m.effect_value,unit_leader_skill_extra_m.member_tag_id").Get(&mySubEffectValue, &myMemberTagId)
utils.CheckErr(err)
exists, err = MainEng.Table("unit_type_member_tag_m").
Where("unit_type_id = ? AND member_tag_id = ?", unitTypeId, myMemberTagId).Exist()
utils.CheckErr(err)
var mySubSmile, mySubPure, mySubCool float64
if exists {
if myAttrId == 1 {
mySubSmile = math.Ceil(smileMax * (mySubEffectValue / 100))
} else if myAttrId == 2 {
mySubPure = math.Ceil(pureMax * (mySubEffectValue / 100))
} else if myAttrId == 3 {
mySubCool = math.Ceil(coolMax * (mySubEffectValue / 100))
}
// fmt.Println("副C技能属性加成:", mySubSmile, mySubPure, mySubCool)
}
// 好友主唱技能加成
// TODO 好友支援存入数据库
var tomoUnitId int64
partyList := gjson.Parse(honokautils.ReadAllText("assets/serverdata/partylist.json")).Get("response_data.party_list")
partyList.ForEach(func(key, value gjson.Result) bool {
if value.Get("user_info.user_id").Int() == playReq.PartyUserID {
tomoUnitId = value.Get("center_unit_info.unit_id").Int()
return false
}
return true
})
// fmt.Println("好友UnitID:", tomoUnitId)
// 好友主唱技能加成:主C技能(这里不使用新C技能,即以某属性的百分比提升另一属性)
var tomoAttrId int
var tomoEffectValue float64
_, err = MainEng.Table("unit_m").
Join("LEFT", "unit_leader_skill_m", "unit_m.default_leader_skill_id = unit_leader_skill_m.unit_leader_skill_id").
Where("unit_m.unit_id = ?", tomoUnitId).
Cols("unit_m.attribute_id,unit_leader_skill_m.effect_value").Get(&tomoAttrId, &tomoEffectValue)
utils.CheckErr(err)
var tomoCenterSmile, tomoCenterPure, tomoCenterCool float64
if myAttrId == 1 {
tomoCenterSmile = math.Ceil(smileMax * (tomoEffectValue / 100))
} else if myAttrId == 2 {
tomoCenterPure = math.Ceil(pureMax * (tomoEffectValue / 100))
} else if myAttrId == 3 {
tomoCenterCool = math.Ceil(coolMax * (tomoEffectValue / 100))
}
// fmt.Println("好友主C技能属性加成:", tomoCenterSmile, tomoCenterPure, tomoCenterCool)
// 好友主唱技能加成:副C技能
var tomoSubEffectValue float64
var tomoMemberTagId int
_, err = MainEng.Table("unit_m").
Join("LEFT", "unit_leader_skill_extra_m", "unit_m.default_leader_skill_id = unit_leader_skill_extra_m.unit_leader_skill_id").
Where("unit_m.unit_id = ?", tomoUnitId).
Cols("unit_leader_skill_extra_m.effect_value,unit_leader_skill_extra_m.member_tag_id").Get(&tomoSubEffectValue, &tomoMemberTagId)
utils.CheckErr(err)
exists, err = MainEng.Table("unit_type_member_tag_m").
Where("unit_type_id = ? AND member_tag_id = ?", unitTypeId, tomoMemberTagId).Exist()
utils.CheckErr(err)
var tomoSubSmile, tomoSubPure, tomoSubCool float64
if exists {
if myAttrId == 1 {
tomoSubSmile = math.Ceil(smileMax * (tomoSubEffectValue / 100))
} else if myAttrId == 2 {
tomoSubPure = math.Ceil(pureMax * (tomoSubEffectValue / 100))
} else if myAttrId == 3 {
tomoSubCool = math.Ceil(coolMax * (tomoSubEffectValue / 100))
}
// fmt.Println("好友副C技能属性加成:", tomoSubSmile, tomoSubPure, tomoSubCool)
}
// 全部卡属性
totalSmile += smileMax + myCenterSmile + mySubSmile + tomoCenterSmile + tomoSubSmile
totalPure += pureMax + myCenterPure + mySubPure + tomoCenterPure + tomoSubPure
totalCool += coolMax + myCenterCool + mySubCool + tomoCenterCool + tomoSubCool
totalHp += maxHp
// 单卡属性计算结果取上取整
fixedSmileMax := int(smileMax)
fixedPureMax := int(pureMax)
fixedCoolMax := int(coolMax)
// fmt.Println("单卡属性:", fixedSmileMax, fixedPureMax, fixedCoolMax)
unitList = append(unitList, model.UnitList{
Smile: fixedSmileMax,
Cute: fixedPureMax,
Cool: fixedCoolMax,
})
}
// 全部卡属性计算结果取上取整
fixedTotalSmile := int(math.Ceil(totalSmile))
fixedTotalPure := int(math.Ceil(totalPure))
fixedTotalCool := int(math.Ceil(totalCool))
// fmt.Println("全卡组属性:", fixedTotalSmile, fixedTotalPure, fixedTotalCool)
lives := []model.PlayLiveList{}
lives = append(lives, model.PlayLiveList{
LiveInfo: model.LiveInfo{
LiveDifficultyID: difficultyId,
IsRandom: false,
AcFlag: ac_flag,
SwingFlag: swing_flag,
NotesList: notes,
},
DeckInfo: model.DeckInfo{
UnitDeckID: deckId,
TotalSmile: fixedTotalSmile,
TotalCute: fixedTotalPure,
TotalCool: fixedTotalCool,
TotalHp: totalHp,
PreparedHpDamage: 0,
UnitList: unitList,
},
})
playResp := model.PlayResp{
ResponseData: model.PlayRes{
RankInfo: ranks,
EnergyFullTime: "2023-03-20 01:28:55",
OverMaxEnergy: 0,
AvailableLiveResume: false,
LiveList: lives,
IsMarathonEvent: false,
MarathonEventID: nil,
NoSkill: false,
CanActivateEffect: true,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(playResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func GameOver(ctx *gin.Context) {
overResp := model.GameOverResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(overResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func PlayScore(ctx *gin.Context) {
playScoreReq := model.PlayScoreReq{}
err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playScoreReq)
utils.CheckErr(err)
tDifficultyId := playScoreReq.LiveDifficultyID
difficultyId, err := strconv.Atoi(tDifficultyId)
utils.CheckErr(err)
// Song type: normal / special
// sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here.
sql := `SELECT notes_setting_asset,c_rank_score,b_rank_score,a_rank_score,s_rank_score,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)`
var notes_setting_asset string
var c_rank_score, b_rank_score, a_rank_score, s_rank_score, ac_flag, swing_flag int
err = MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(&notes_setting_asset, &c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &ac_flag, &swing_flag)
utils.CheckErr(err)
// fmt.Println(notes_setting_asset)
// fmt.Println(c_rank_score, b_rank_score, a_rank_score, s_rank_score)
notes := []model.NotesList{}
// fmt.Println("./assets/notes/" + notes_setting_asset)
notes_list := honokautils.ReadAllText("./assets/serverdata/notes/" + notes_setting_asset)
err = json.Unmarshal([]byte(notes_list), &notes)
utils.CheckErr(err)
ranks := []model.RankInfo{}
ranks = append(ranks, model.RankInfo{
Rank: 5,
RankMin: 0,
RankMax: c_rank_score,
}, model.RankInfo{
Rank: 4,
RankMin: c_rank_score + 1,
RankMax: b_rank_score,
}, model.RankInfo{
Rank: 3,
RankMin: b_rank_score + 1,
RankMax: a_rank_score,
}, model.RankInfo{
Rank: 2,
RankMin: a_rank_score + 1,
RankMax: s_rank_score,
}, model.RankInfo{
Rank: 1,
RankMin: s_rank_score + 1,
RankMax: 0,
})
playResp := model.PlayScoreResp{
ResponseData: model.PlayScoreRes{
On: model.On{
HasRecord: false,
LiveInfo: model.LiveInfo{
LiveDifficultyID: difficultyId,
IsRandom: false,
AcFlag: ac_flag,
SwingFlag: swing_flag,
NotesList: notes,
},
},
Off: model.Off{
HasRecord: false,
LiveInfo: model.LiveInfo{
LiveDifficultyID: difficultyId,
IsRandom: false,
AcFlag: ac_flag,
SwingFlag: swing_flag,
NotesList: notes,
},
},
RankInfo: ranks,
CanActivateEffect: true,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(playResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func PlayReward(ctx *gin.Context) {
playRewardReq := model.PlayRewardReq{}
err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playRewardReq)
utils.CheckErr(err)
difficultyId := playRewardReq.LiveDifficultyID
// Song type: normal / special
// sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here.
sql := `SELECT c_rank_score,b_rank_score,a_rank_score,s_rank_score,c_rank_combo,b_rank_combo,a_rank_combo,s_rank_combo,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)`
var c_rank_score, b_rank_score, a_rank_score, s_rank_score, c_rank_combo, b_rank_combo, a_rank_combo, s_rank_combo, ac_flag, swing_flag int
err = MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(&c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &c_rank_combo, &b_rank_combo, &a_rank_combo, &s_rank_combo, &ac_flag, &swing_flag)
utils.CheckErr(err)
key := "live_deck_" + ctx.GetString("userid")
deckId, err := db.DB.Get([]byte(key))
utils.CheckErr(err)
unitsList := []model.PlayRewardUnitList{}
err = UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id").
Where("user_id = ? AND deck_id = ?", ctx.GetString("userid"), string(deckId)).Find(&unitsList)
utils.CheckErr(err)
totalScore := playRewardReq.ScoreSmile + playRewardReq.ScoreCool + playRewardReq.ScoreCute
playResp := model.RewardResp{
ResponseData: model.RewardRes{
LiveInfo: []model.RewardLiveInfo{
{
LiveDifficultyID: difficultyId,
IsRandom: false,
AcFlag: ac_flag,
SwingFlag: swing_flag,
},
},
TotalLove: 0,
IsHighScore: true,
HiScore: totalScore,
BaseRewardInfo: model.BaseRewardInfo{
PlayerExp: 0,
PlayerExpUnitMax: model.PlayerExpUnitMax{
Before: 0,
After: 0,
},
PlayerExpFriendMax: model.PlayerExpFriendMax{
Before: 99,
After: 99,
},
PlayerExpLpMax: model.PlayerExpLpMax{
Before: config.Conf.UserPrefs.EnergyMax,
After: config.Conf.UserPrefs.EnergyMax,
},
GameCoin: 0,
GameCoinRewardBoxFlag: false,
SocialPoint: 0,
},
RewardUnitList: model.RewardUnitList{
LiveClear: []model.LiveClear{},
LiveRank: []model.LiveRank{},
LiveCombo: []any{},
},
UnlockedSubscenarioIds: []any{},
UnlockedMultiUnitScenarioIds: []any{},
EffortPoint: []model.EffortPoint{},
IsEffortPointVisible: false,
LimitedEffortBox: []any{},
UnitList: unitsList,
BeforeUserInfo: model.BeforeUserInfo{
Level: config.Conf.UserPrefs.Level,
Exp: config.Conf.UserPrefs.ExpNumerator,
PreviousExp: 0,
NextExp: config.Conf.UserPrefs.ExpDenominator,
GameCoin: config.Conf.UserPrefs.GameCoin,
SnsCoin: config.Conf.UserPrefs.SnsCoin,
FreeSnsCoin: config.Conf.UserPrefs.SnsCoin,
PaidSnsCoin: 0,
SocialPoint: 1438165,
UnitMax: 5000,
WaitingUnitMax: 1000,
CurrentEnergy: config.Conf.UserPrefs.EnergyMax,
EnergyMax: config.Conf.UserPrefs.EnergyMax,
TrainingEnergy: 9,
TrainingEnergyMax: 10,
EnergyFullTime: "2023-03-20 01:28:55",
LicenseLiveEnergyRecoverlyTime: 60,
FriendMax: 99,
TutorialState: -1,
OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy,
UnlockRandomLiveMuse: 1,
UnlockRandomLiveAqours: 1,
},
AfterUserInfo: model.AfterUserInfo{
Level: config.Conf.UserPrefs.Level,
Exp: config.Conf.UserPrefs.ExpNumerator,
PreviousExp: 0,
NextExp: config.Conf.UserPrefs.ExpDenominator,
GameCoin: config.Conf.UserPrefs.GameCoin,
SnsCoin: config.Conf.UserPrefs.SnsCoin,
FreeSnsCoin: config.Conf.UserPrefs.SnsCoin,
PaidSnsCoin: 0,
SocialPoint: 1438375,
UnitMax: 5000,
WaitingUnitMax: 1000,
CurrentEnergy: config.Conf.UserPrefs.EnergyMax,
EnergyMax: config.Conf.UserPrefs.EnergyMax,
TrainingEnergy: 9,
TrainingEnergyMax: 10,
EnergyFullTime: "2023-03-20 01:28:55",
LicenseLiveEnergyRecoverlyTime: 60,
FriendMax: 99,
TutorialState: -1,
OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy,
UnlockRandomLiveMuse: 1,
UnlockRandomLiveAqours: 1,
},
NextLevelInfo: []model.NextLevelInfo{
{
Level: config.Conf.UserPrefs.Level,
FromExp: config.Conf.UserPrefs.ExpNumerator,
},
},
GoalAccompInfo: model.GoalAccompInfo{
AchievedIds: []any{},
Rewards: []any{},
},
SpecialRewardInfo: []any{},
EventInfo: []any{},
DailyRewardInfo: []any{},
CanSendFriendRequest: false,
UsingBuffInfo: []any{},
ClassSystem: model.ClassSystem{
RankInfo: model.RewardRankInfo{
BeforeClassRankID: 10,
AfterClassRankID: 10,
RankUpDate: "2020-02-12 11:57:15",
},
CompleteFlag: false,
IsOpened: true,
IsVisible: true,
},
AccomplishedAchievementList: []model.AccomplishedAchievementList{},
UnaccomplishedAchievementCnt: 0,
AddedAchievementList: []any{},
MuseumInfo: model.Museum{},
UnitSupportList: []model.RewardUnitSupportList{},
ServerTimestamp: time.Now().Unix(),
PresentCnt: 0,
},
ReleaseInfo: []any{},
StatusCode: 200,
}
if playRewardReq.MaxCombo > s_rank_combo {
playResp.ResponseData.ComboRank = 1
} else if playRewardReq.MaxCombo > a_rank_combo {
playResp.ResponseData.ComboRank = 2
} else if playRewardReq.MaxCombo > b_rank_combo {
playResp.ResponseData.ComboRank = 3
} else if playRewardReq.MaxCombo > c_rank_combo {
playResp.ResponseData.ComboRank = 4
} else {
playResp.ResponseData.ComboRank = 5
}
if totalScore > s_rank_score {
playResp.ResponseData.Rank = 1
} else if totalScore > a_rank_score {
playResp.ResponseData.Rank = 2
} else if totalScore > b_rank_score {
playResp.ResponseData.Rank = 3
} else if totalScore > c_rank_score {
playResp.ResponseData.Rank = 4
} else {
playResp.ResponseData.Rank = 5
}
resp, err := json.Marshal(playResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+60
View File
@@ -0,0 +1,60 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"honoka-chan/pkg/db"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
func AuthKey(ctx *gin.Context) {
authResp := model.AuthKeyResp{
ResponseData: model.AuthKeyRes{
AuthorizeToken: ctx.GetString("authorize_token"),
DummyToken: ctx.GetString("dummy_token"),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(authResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.JSON(http.StatusOK, authResp)
}
func Login(ctx *gin.Context) {
loginKey := ctx.GetString("login_key")
var userId int
exists, err := UserEng.Table("user_key").Where("key = ?", loginKey).Cols("userid").Get(&userId)
utils.CheckErr(err)
if !exists || userId == 0 {
userId = 9999999
}
ctx.Set("userid", userId)
err = db.DB.Set([]byte(strconv.Itoa(userId)), []byte(ctx.GetString("authorize_token")))
utils.CheckErr(err)
loginResp := model.LoginResp{
ResponseData: model.LoginRes{
AuthorizeToken: ctx.GetString("authorize_token"),
UserId: userId,
ServerTimestamp: time.Now().Unix(),
AdultFlag: 2,
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(loginResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.JSON(http.StatusOK, loginResp)
}
+32
View File
@@ -0,0 +1,32 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func MultiUnitStartUp(ctx *gin.Context) {
startReq := model.MultiUnitStartUpReq{}
err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq)
utils.CheckErr(err)
startResp := model.MultiUnitStartUpResp{
ResponseData: model.MultiUnitStartUpRes{
MultiUnitScenarioID: startReq.MultiUnitScenarioID,
ScenarioAdjustment: 50,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(startResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+52
View File
@@ -0,0 +1,52 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
type MuseumContent struct {
MuseumContentsId int `xorm:"museum_contents_id"`
SmileBuff int `xorm:"smile_buff"`
PureBuff int `xorm:"pure_buff"`
CoolBuff int `xorm:"cool_buff"`
}
func MuseumInfo(ctx *gin.Context) {
var contents []MuseumContent
err := MainEng.Table("museum_contents_m").Cols("museum_contents_id,smile_buff,pure_buff,cool_buff").Find(&contents)
utils.CheckErr(err)
var smileBuff, pureBuff, coolBuff int
var contentsList []int
for _, content := range contents {
smileBuff += content.SmileBuff
pureBuff += content.PureBuff
coolBuff += content.CoolBuff
contentsList = append(contentsList, content.MuseumContentsId)
}
museumResp := model.MuseumResp{
ResponseData: model.MuseumRes{
MuseumInfo: model.Museum{
Parameter: model.MuseumParameter{
Smile: smileBuff,
Pure: pureBuff,
Cool: coolBuff,
},
ContentsIDList: contentsList,
},
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(museumResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+63
View File
@@ -0,0 +1,63 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func NoticeFriendVariety(ctx *gin.Context) {
noticeResp := model.NoticeFriendVarietyResp{
ResponseData: model.NoticeFriendVarietyRes{
ItemCount: 1,
NoticeList: []any{},
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(noticeResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func NoticeFriendGreeting(ctx *gin.Context) {
noticeResp := model.NoticeFriendGreetingResp{
ResponseData: model.NoticeFriendGreetingRes{
NextId: 0,
NoticeList: []any{},
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(noticeResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func NoticeUserGreeting(ctx *gin.Context) {
noticeResp := model.NoticeUserGreetingResp{
ResponseData: model.NoticeUserGreetingRes{
ItemCount: 0,
HasNext: false,
NoticeList: []any{},
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(noticeResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+39
View File
@@ -0,0 +1,39 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func ProductList(ctx *gin.Context) {
prodReesp := model.ProductResp{
ResponseData: model.ProductRes{
RestrictionInfo: model.RestrictionInfo{
Restricted: false,
},
UnderAgeInfo: model.UnderAgeInfo{
BirthSet: true,
HasLimit: false,
LimitAmount: nil,
MonthUsed: 0,
},
SnsProductList: []any{},
ProductList: []any{},
SubscriptionList: []any{},
ShowPointShop: true,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(prodReesp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+31
View File
@@ -0,0 +1,31 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func PersonalNotice(ctx *gin.Context) {
noticeResp := model.PersonalNoticeResp{
ResponseData: model.PersonalNoticeRes{
HasNotice: false,
NoticeID: 0,
Type: 0,
Title: "",
Contents: "",
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(noticeResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+495
View File
@@ -0,0 +1,495 @@
package handler
import (
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/config"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"honoka-chan/pkg/db"
"honoka-chan/pkg/encrypt"
honokautils "honoka-chan/pkg/utils"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/forgoer/openssl"
"github.com/gin-gonic/gin"
)
type LoginResp struct {
Activation int `json:"activation"`
Autokey string `json:"autokey"`
CaptchaParams string `json:"captchaParams"`
CheckCodeGUID string `json:"checkCodeGuid"`
CheckCodeURL string `json:"checkCodeUrl"`
HasExtendAccs int `json:"hasExtendAccs"`
HasRealInfo int `json:"has_realInfo"`
ImagecodeType int `json:"imagecodeType"`
IsNewUser int `json:"isNewUser"`
Message string `json:"message"`
NextAction int `json:"nextAction"`
PromptMsg string `json:"prompt_msg"`
RealInfoNotification string `json:"realInfoNotification"`
RealInfoForce int `json:"realInfo_force"`
RealInfoForcePay int `json:"realInfo_force_pay"`
RealInfoStatus int `json:"realInfo_status"`
RealInfoStatusPay int `json:"realInfo_status_pay"`
Result int `json:"result"`
SdgHeight int `json:"sdg_height"`
SdgWidth int `json:"sdg_width"`
Ticket string `json:"ticket"`
UserAttribute string `json:"userAttribute"`
Userid string `json:"userid"`
}
type LoginAutoResp struct {
Result int `json:"result"`
Message string `json:"message"`
Autokey string `json:"autokey"`
UserId string `json:"userid"`
Ticket string `json:"ticket"`
}
type InitializeResp struct {
BrandLogo string `json:"brand_logo"`
BrandName string `json:"brand_name"`
DaoyuClientid string `json:"daoyu_clientid"`
DaoyuDownloadURL string `json:"daoyu_download_url"`
DeviceFeature string `json:"device_feature"`
DisplayThirdaccout int `json:"display_thirdaccout"`
ForceShowAgreement int `json:"force_show_agreement"`
GreportLogLevel string `json:"greport_log_level"`
GuestEnable int `json:"guest_enable"`
IsMatch int `json:"is_match"`
LogLevel string `json:"log_level"`
LoginButton []string `json:"login_button"`
LoginIcon []any `json:"login_icon"`
LoginLimitEnable int `json:"login_limit_enable"`
NeedFloatWindowPermission int `json:"need_float_window_permission"`
NewDeviceIDServer string `json:"new_device_id_server"`
QqAppID string `json:"qq_appId"`
QqKey string `json:"qq_key"`
ShowGuestConfirm int `json:"show_guest_confirm"`
VoicetipButton int `json:"voicetip_button"`
VoicetipOne string `json:"voicetip_one"`
VoicetipTwo string `json:"voicetip_two"`
WegameAppid string `json:"wegame_appid"`
WegameAppkey string `json:"wegame_appkey"`
WegameClientid string `json:"wegame_clientid"`
WegameCompanyID string `json:"wegame_companyId"`
WegameLoginURL string `json:"wegame_loginUrl"`
WeiboAppKey string `json:"weibo_appKey"`
WeiboRedirectURL string `json:"weibo_redirectUrl"`
WeixinAppID string `json:"weixin_appId"`
WeixinKey string `json:"weixin_key"`
}
func Active(ctx *gin.Context) {
// body, err := io.ReadAll(ctx.Request.Body)
// utils.CheckErr(err)
// defer ctx.Request.Body.Close()
// fmt.Println(string(body))
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, `{ "code": 0, "msg": "ok", "data": { "message": "ok", "result": 0 } }`)
}
func PublicKey(ctx *gin.Context) {
publicKey := honokautils.ReadAllText(config.PublicKeyPath)
publicKey = strings.ReplaceAll(publicKey, "\n", "")
publicKey = strings.ReplaceAll(publicKey, "-----BEGIN PUBLIC KEY-----", "")
publicKey = strings.ReplaceAll(publicKey, "-----END PUBLIC KEY-----", "")
publicKey = strings.ReplaceAll(publicKey, "/", "\\/")
// fmt.Println(publicKey)
resp := fmt.Sprintf(`{ "code": 0, "msg": "", "data": { "result": 0, "message": "ok", "key": "%s", "method": "rsa" } }`, publicKey)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func Handshake(ctx *gin.Context) {
body, err := io.ReadAll(ctx.Request.Body)
utils.CheckErr(err)
defer ctx.Request.Body.Close()
// fmt.Println(string(body))
body64, err := base64.StdEncoding.DecodeString(string(body))
utils.CheckErr(err)
decryptedBody := encrypt.RSADecrypt(body64)
// fmt.Println(decryptedBody)
// fmt.Println(string(decryptedBody))
params, err := url.ParseQuery(string(decryptedBody))
utils.CheckErr(err)
randKey := params.Get("randkey")
deviceId := ctx.Request.Header.Get("X-DEVICEID")
// fmt.Println(randKey)
// fmt.Println(deviceId)
err = db.DB.Set([]byte(deviceId), []byte(randKey))
utils.CheckErr(err)
token := strings.ToUpper(honokautils.RandomStr(33))
token = fmt.Sprintf(`{"message":"ok","result":0,"token":"%s"}`, token)
encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), []byte(randKey)[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedToken64 := base64.StdEncoding.EncodeToString(encryptedToken)
// fmt.Println(encryptedToken64)
resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedToken64)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func Initialize(ctx *gin.Context) {
// body, err := io.ReadAll(ctx.Request.Body)
// utils.CheckErr(err)
// defer ctx.Request.Body.Close()
// fmt.Println(string(body))
// body64, err := base64.StdEncoding.DecodeString(string(body))
// utils.CheckErr(err)
// fmt.Println(string(body64))
deviceId := ctx.Request.Header.Get("X-DEVICEID")
randKey, err := db.DB.Get([]byte(deviceId))
utils.CheckErr(err)
// decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING)
// utils.CheckErr(err)
// fmt.Println(string(decryptedBody))
initResp := InitializeResp{
BrandLogo: "http://gskd.sdo.com/ghome/ztc/logo/og/logo_xhdpi.png",
BrandName: "盛趣游戏",
ForceShowAgreement: 1,
GreportLogLevel: "off",
LogLevel: "off",
LoginButton: []string{"official"},
LoginIcon: []any{},
NeedFloatWindowPermission: 1,
NewDeviceIDServer: strings.ToUpper(openssl.Md5ToString(deviceId)),
ShowGuestConfirm: 1,
VoicetipButton: 1,
}
data, err := json.Marshal(initResp)
utils.CheckErr(err)
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData)
// fmt.Println(encryptedToken64)
resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedData64)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func GetCode(ctx *gin.Context) {
resp := `{ "code": 0, "msg": "ok", "data": { "codeArray": [ { "btntext": "好的", "code": "-10264022", "msg_from": 2, "text": "", "title": "短信验证码被阻止", "type": 1 }, { "btntext": " ", "code": "-10869623", "msg_from": 2, "text": "", "title": "网络连接失败,无法一键登录", "type": 2 }, { "btntext": " ", "code": "10298300", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": "", "code": "10298311", "msg_from": 2, "text": "", "title": "", "type": 3 }, { "btntext": " ", "code": "10298312", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": " ", "code": "10298313", "msg_from": 2, "text": "", "title": " ", "type": 1 }, { "btntext": " ", "code": "10298321", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": " ", "code": "10298322", "msg_from": 2, "text": "", "title": " ", "type": 3 } ], "codeVersion": "1.0.5" } }`
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func LoginAuto(ctx *gin.Context) {
body, err := io.ReadAll(ctx.Request.Body)
utils.CheckErr(err)
defer ctx.Request.Body.Close()
// fmt.Println(string(body))
body64, err := base64.StdEncoding.DecodeString(string(body))
utils.CheckErr(err)
// fmt.Println(string(body64))
deviceId := ctx.Request.Header.Get("X-DEVICEID")
randKey, err := db.DB.Get([]byte(deviceId))
utils.CheckErr(err)
decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
queryStr := string(decryptedBody)
// fmt.Println(queryStr)
params, err := url.ParseQuery(queryStr)
utils.CheckErr(err)
autoKey := params.Get("autokey")
// fmt.Println(autoKey)
if autoKey == "" {
ctx.String(http.StatusForbidden, ErrorMsg)
return
}
var userId, ticket string
_, err = UserEng.Table("users").Cols("userid,ticket").Where("autokey = ?", autoKey).Get(&userId, &ticket)
utils.CheckErr(err)
var resp string
if userId != "" {
autoResp := LoginAutoResp{
Result: 0,
Message: "ok",
Autokey: autoKey,
UserId: userId,
Ticket: ticket,
}
data, err := json.Marshal(autoResp)
// fmt.Println(string(data))
utils.CheckErr(err)
encryptedData, err := openssl.Des3ECBEncrypt(data, randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData)
// fmt.Println(encryptedData64)
resp = fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedData64)
} else {
data := `{"message":"账号不存在或者登陆状态已过期!","result":31}`
encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData)
// fmt.Println(encryptedData64)
resp = fmt.Sprintf(`{ "code": 31, "msg": "账号不存在或者登陆状态已过期!", "data": "%s" }`, encryptedData64)
}
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func LoginArea(ctx *gin.Context) {
userId := ctx.PostForm("userid")
if userId != "" {
// fmt.Println(userId)
resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": { "userid": "%s" } }`, userId)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
}
func AccountLogin(ctx *gin.Context) {
body, err := io.ReadAll(ctx.Request.Body)
utils.CheckErr(err)
defer ctx.Request.Body.Close()
// fmt.Println(string(body))
body64, err := base64.StdEncoding.DecodeString(string(body))
utils.CheckErr(err)
// fmt.Println(string(body64))
deviceId := ctx.Request.Header.Get("X-DEVICEID")
randKey, err := db.DB.Get([]byte(deviceId))
utils.CheckErr(err)
decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
queryStr, err := url.QueryUnescape(string(decryptedBody))
utils.CheckErr(err)
params, err := url.ParseQuery(queryStr)
utils.CheckErr(err)
phone, password := params.Get("phone"), params.Get("password")
if phone == "" || password == "" {
ctx.String(http.StatusForbidden, ErrorMsg)
return
}
// sql := `CREATE TABLE "users" (
// "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
// "phone" TEXT,
// "password" TEXT,
// "autokey" TEXT,
// "ticket" TEXT,
// "userid" INTEGER,
// "last_login_time" INTEGER
// );
// CREATE TABLE "user_key" (
// "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
// "userid" INTEGER,
// "key" INTEGER
// );`
var pass, autoKey, ticket, userId string
_, err = UserEng.Table("users").Cols("password,autokey,ticket,userid").Where("phone = ?", phone).
Get(&pass, &autoKey, &ticket, &userId)
utils.CheckErr(err)
loginResp := LoginResp{}
loginCode := 0
loginMsg := "ok"
loginTime := time.Now().Unix()
if pass == "" {
// 未注册 - 自动注册
session := UserEng.NewSession()
defer session.Close()
// 开始会话
if err = session.Begin(); err != nil {
session.Rollback()
panic(err)
}
pass = openssl.Md5ToString(password)
autoKey = "AUTO" + strings.ToUpper(honokautils.RandomStr(32))
userId = strconv.Itoa(int(loginTime))
ticket = "9999999" + userId + userId
userStmt, err := session.DB().Prepare("INSERT INTO users(phone,password,autokey,ticket,userid,last_login_time) VALUES (?,?,?,?,?,?)")
if err != nil {
session.Rollback()
panic(err)
}
defer userStmt.Close()
_, err = userStmt.Exec(phone, pass, autoKey, ticket, userId, loginTime)
if err != nil {
session.Rollback()
panic(err)
}
// id, _ := res.LastInsertId()
// fmt.Println("LastInsertId:", id)
keyStmt, err := session.DB().Prepare("INSERT INTO user_key(userid,key) VALUES(?,?)")
if err != nil {
session.Rollback()
panic(err)
}
// 方便起见初始化 userid 和 key 一样
// 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的
_, err = keyStmt.Exec(userId, userId)
if err != nil {
session.Rollback()
panic(err)
}
// 结束会话
if err = session.Commit(); err != nil {
session.Rollback()
panic(err)
}
tools.InitUserData(int(loginTime))
// Login Response
loginResp.Autokey = autoKey
loginResp.HasRealInfo = 1
loginResp.Message = "ok"
loginResp.RealInfoForce = 1
loginResp.Ticket = ticket
loginResp.UserAttribute = "0"
loginResp.Userid = userId
} else {
// 已注册
if openssl.Md5ToString(password) == pass {
// 密码正确
// Login Response
loginResp.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey
loginResp.HasRealInfo = 1
loginResp.Message = "ok"
loginResp.RealInfoForce = 1
loginResp.Ticket = "9999999" + userId + strconv.Itoa(int(loginTime)) // 实际登录用的密码(每次登录都会重新生成新的)
loginResp.UserAttribute = "0"
loginResp.Userid = userId // 实际登录用的账号
// 更新信息
userStmt, err := UserEng.DB().Prepare("UPDATE users SET autokey=?,ticket=?,last_login_time=? WHERE userid=?")
utils.CheckErr(err)
defer userStmt.Close()
_, err = userStmt.Exec(autoKey, ticket, loginTime, userId)
utils.CheckErr(err)
// aff, _ := res.RowsAffected()
// fmt.Println("RowsAffected:", aff)
} else {
// 密码错误
loginCode = 31
loginMsg = "账号不存在或者密码有误!"
}
}
data, err := json.Marshal(loginResp)
utils.CheckErr(err)
// fmt.Println(string(data))
encryptedData, err := openssl.Des3ECBEncrypt(data, randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData)
// fmt.Println(encryptedToken64)
resp := fmt.Sprintf(`{ "code": %d, "msg": "%s", "data": "%s" }`, loginCode, loginMsg, encryptedData64)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func ReportRole(ctx *gin.Context) {
// body, err := io.ReadAll(ctx.Request.Body)
// utils.CheckErr(err)
// defer ctx.Request.Body.Close()
// fmt.Println(string(body))
// body64, err := base64.StdEncoding.DecodeString(string(body))
// utils.CheckErr(err)
// fmt.Println(string(body64))
deviceId := ctx.Request.Header.Get("X-DEVICEID")
randKey, err := db.DB.Get([]byte(deviceId))
utils.CheckErr(err)
// decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING)
// utils.CheckErr(err)
// fmt.Println(string(decryptedBody))
// decrypted, err := url.QueryUnescape(string(decryptedBody))
// utils.CheckErr(err)
// fmt.Println(decrypted)
// Unable to decrypt server data
token := `{"message":"Hello, world!"}`
encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING)
utils.CheckErr(err)
encryptedToken64 := base64.StdEncoding.EncodeToString(encryptedToken)
// fmt.Println(encryptedToken64)
resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedToken64)
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func GetProductList(ctx *gin.Context) {
resp := `{ "code": 0, "msg": "ok", "data": { "message": [ ], "result": 0 } }`
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func GuestStatus(ctx *gin.Context) {
resp := `{"code":0,"msg":"ok","data":{"disablead":1,"loginswitch":1,"message":"ok","result":0}}`
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func ReportLog(ctx *gin.Context) {
// body, err := io.ReadAll(ctx.Request.Body)
// utils.CheckErr(err)
// defer ctx.Request.Body.Close()
// fmt.Println(string(body))
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, "")
}
func ReportApp(ctx *gin.Context) {
// body, err := io.ReadAll(ctx.Request.Body)
// utils.CheckErr(err)
// defer ctx.Request.Body.Close()
// fmt.Println(string(body))
resp := `{ "code": 0, "msg": "", "data": { "needReport": 0 } }`
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
func Agreement(ctx *gin.Context) {
resp := `{ "return_code": 0, "error_type": 0, "return_message": "", "data": { } }`
ctx.Header("Content-Type", "text/html;charset=utf-8")
ctx.String(http.StatusOK, resp)
}
+31
View File
@@ -0,0 +1,31 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"net/http"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)
func ProfileRegister(ctx *gin.Context) {
req := gjson.Parse(ctx.PostForm("request_data"))
pref := tools.UserPref{
UserDesc: req.Get("introduction").String(),
}
_, err := UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref)
utils.CheckErr(err)
profileResp := model.ProfileRegisterResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(profileResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+49
View File
@@ -0,0 +1,49 @@
package handler
import (
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"honoka-chan/pkg/encrypt"
honokautils "honoka-chan/pkg/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func ScenarioStartup(ctx *gin.Context) {
startReq := model.ScenarioReq{}
err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq)
utils.CheckErr(err)
startResp := model.ScenarioResp{
ResponseData: model.ScenarioRes{
ScenarioID: startReq.ScenarioID,
ScenarioAdjustment: 50,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(startResp)
utils.CheckErr(err)
nonce := ctx.GetInt("nonce")
nonce++
ctx.Header("user_id", ctx.GetString("userid"))
ctx.Header("authorize", fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", time.Now().Unix(), ctx.GetString("token"), nonce, ctx.GetString("userid"), ctx.GetInt64("req_time")))
ctx.Header("X-Message-Sign", base64.StdEncoding.EncodeToString(encrypt.RSASignSHA1(resp)))
ctx.String(http.StatusOK, string(resp))
}
func ScenarioReward(ctx *gin.Context) {
resp := honokautils.ReadAllText("assets/serverdata/reward.json")
ctx.Header("X-Message-Sign", utils.GenXMS([]byte(resp)))
ctx.String(http.StatusOK, resp)
}
+49
View File
@@ -0,0 +1,49 @@
package handler
import (
"encoding/base64"
"encoding/json"
"fmt"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"honoka-chan/pkg/encrypt"
honokautils "honoka-chan/pkg/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func SubScenarioStartup(ctx *gin.Context) {
startReq := model.SubScenarioReq{}
err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq)
utils.CheckErr(err)
startResp := model.SubScenarioResp{
ResponseData: model.SubScenarioRes{
SubscenarioID: startReq.SubscenarioID,
ScenarioAdjustment: 50,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(startResp)
utils.CheckErr(err)
nonce := ctx.GetInt("nonce")
nonce++
ctx.Header("user_id", ctx.GetString("userid"))
ctx.Header("authorize", fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", time.Now().Unix(), ctx.GetString("token"), nonce, ctx.GetString("userid"), ctx.GetInt64("req_time")))
ctx.Header("X-Message-Sign", base64.StdEncoding.EncodeToString(encrypt.RSASignSHA1(resp)))
ctx.String(http.StatusOK, string(resp))
}
func SubScenarioReward(ctx *gin.Context) {
resp := honokautils.ReadAllText("assets/serverdata/subreward.json")
ctx.Header("X-Message-Sign", utils.GenXMS([]byte(resp)))
ctx.String(http.StatusOK, resp)
}
+29
View File
@@ -0,0 +1,29 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func TosCheck(ctx *gin.Context) {
tosResp := model.TosResp{
ResponseData: model.TosRes{
TosID: 1,
TosType: 1,
IsAgreed: true,
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(tosResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+316
View File
@@ -0,0 +1,316 @@
package handler
import (
"encoding/json"
"fmt"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
func SetDisplayRank(ctx *gin.Context) {
dispResp := model.SetDisplayRankResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(dispResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func SetDeck(ctx *gin.Context) {
userId, err := strconv.Atoi(ctx.GetString("userid"))
utils.CheckErr(err)
deckReq := model.UnitDeckReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &deckReq); err != nil {
panic(err)
}
// 开始事务
// UserEng.ShowSQL(true)
session := UserEng.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
session.Rollback()
panic(err)
}
// 原有队伍信息
var userDeckId []int
err = session.Table("user_deck_m").Cols("id").Where("user_id = ?", userId).Find(&userDeckId)
if err != nil {
session.Rollback()
panic(err)
}
// 删除全部原有队伍成员
_, err = session.Table("deck_unit_m").In("user_deck_id", userDeckId).Delete()
if err != nil {
session.Rollback()
panic(err)
}
// 删除全部原有队伍
_, err = session.Table("user_deck_m").In("id", userDeckId).Delete()
if err != nil {
session.Rollback()
panic(err)
}
// 遍历新队伍
for _, deck := range deckReq.UnitDeckList {
// 新队伍信息
userDeck := model.UserDeckData{
DeckID: deck.UnitDeckID,
MainFlag: deck.MainFlag,
DeckName: deck.DeckName,
UserID: userId,
InsertDate: time.Now().Unix(),
}
_, err = session.Table("user_deck_m").Insert(&userDeck)
if err != nil {
session.Rollback()
panic(err)
}
userDeckId := userDeck.ID
// fmt.Println("新队伍 ID:", userDeckId)
// 队伍成员信息
for _, unit := range deck.UnitDeckDetail {
// 成员信息
newUnitData := model.UnitData{}
exists, err := session.Table("user_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Exist()
if err != nil {
session.Rollback()
panic(err)
}
if exists {
// fmt.Println("新成员为用户增加成员")
_, err = session.Table("user_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Get(&newUnitData)
if err != nil {
session.Rollback()
panic(err)
}
} else {
exists, err := MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Exist()
if err != nil {
session.Rollback()
panic(err)
}
if exists {
// fmt.Println("新成员为公共成员")
_, err = MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Get(&newUnitData)
if err != nil {
session.Rollback()
panic(err)
}
} else {
// fmt.Println("新成员不存在")
session.Rollback()
panic("unexpected operation")
}
}
// fmt.Println("新的成员信息:", newUnitData)
// 插入新成员信息
newUnitDeckData := model.UnitDeckData{}
b, err := json.Marshal(newUnitData)
if err != nil {
session.Rollback()
panic(err)
}
if err = json.Unmarshal(b, &newUnitDeckData); err != nil {
session.Rollback()
panic(err)
}
newUnitDeckData.BeforeLove = newUnitDeckData.MaxLove
newUnitDeckData.Position = unit.Position
newUnitDeckData.UserDeckID = userDeckId
newUnitDeckData.InsertData = time.Now().Unix()
_, err = session.Table("deck_unit_m").Insert(&newUnitDeckData)
if err != nil {
session.Rollback()
panic(err)
}
}
}
// 结束事务
if err = session.Commit(); err != nil {
session.Rollback()
panic(err)
}
dispResp := model.SetDeckResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(dispResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func SetDeckName(ctx *gin.Context) {
userId, err := strconv.Atoi(ctx.GetString("userid"))
utils.CheckErr(err)
deckReq := model.DeckNameReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &deckReq); err != nil {
panic(err)
}
exists, err := UserEng.Table("user_deck_m").Where("user_id = ? AND deck_id = ?", userId, deckReq.UnitDeckID).Exist()
utils.CheckErr(err)
if !exists {
ctx.String(http.StatusForbidden, ErrorMsg)
return
}
userDeck := model.UserDeckData{
DeckName: deckReq.DeckName,
}
_, err = UserEng.Table("user_deck_m").Update(&userDeck, &model.UserDeckData{
UserID: userId,
DeckID: deckReq.UnitDeckID,
})
utils.CheckErr(err)
dispResp := model.SetDeckResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(dispResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func WearAccessory(ctx *gin.Context) {
fmt.Println(ctx.PostForm("request_data"))
req := model.WearAccessoryReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &req); err != nil {
panic(err)
}
// UserEng.ShowSQL(true)
// 开始事务
session := UserEng.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
session.Rollback()
panic(err)
}
// 取下饰品
for _, v := range req.Remove {
fmt.Println("Remove:", v.AccessoryOwningUserID, v.UnitOwningUserID)
_, err := session.Table("accessory_wear_m").
Where("accessory_owning_user_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.AccessoryOwningUserID, v.UnitOwningUserID, ctx.GetString("userid")).
Delete()
if err != nil {
session.Rollback()
panic(err)
}
}
// 佩戴饰品
for _, v := range req.Wear {
fmt.Println("Wear:", v.AccessoryOwningUserID, v.UnitOwningUserID)
data := model.AccessoryWearData{
AccessoryOwningUserID: v.AccessoryOwningUserID,
UnitOwningUserID: v.UnitOwningUserID,
UserId: ctx.GetString("userid"),
}
_, err := session.Table("accessory_wear_m").Insert(&data)
utils.CheckErr(err)
}
// 结束事务
if err := session.Commit(); err != nil {
session.Rollback()
panic(err)
}
wearResp := model.AwardSetResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(wearResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func RemoveSkillEquip(ctx *gin.Context) {
fmt.Println(ctx.PostForm("request_data"))
req := model.SkillEquipReq{}
if err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &req); err != nil {
panic(err)
}
// UserEng.ShowSQL(true)
// 开始事务
session := UserEng.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
session.Rollback()
panic(err)
}
// 取下宝石
for _, v := range req.Remove {
fmt.Println("Remove:", v.UnitOwningUserID, v.UnitRemovableSkillID)
_, err := session.Table("skill_equip_m").
Where("unit_removable_skill_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.UnitRemovableSkillID, v.UnitOwningUserID, ctx.GetString("userid")).
Delete()
if err != nil {
session.Rollback()
panic(err)
}
}
// 佩戴宝石
for _, v := range req.Equip {
fmt.Println("Equip:", v.UnitOwningUserID, v.UnitRemovableSkillID)
data := model.SkillEquipData{
UnitRemovableSkillId: v.UnitRemovableSkillID,
UnitOwningUserID: v.UnitOwningUserID,
UserId: ctx.GetString("userid"),
}
_, err := session.Table("skill_equip_m").Insert(&data)
utils.CheckErr(err)
}
// 结束事务
if err := session.Commit(); err != nil {
session.Rollback()
panic(err)
}
wearResp := model.AwardSetResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(wearResp)
utils.CheckErr(err)
fmt.Println(string(resp))
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+75
View File
@@ -0,0 +1,75 @@
package handler
import (
"encoding/json"
"honoka-chan/internal/model"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)
func SetNotificationToken(ctx *gin.Context) {
notifResp := model.NotificationResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(notifResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func ChangeNavi(ctx *gin.Context) {
req := gjson.Parse(ctx.PostForm("request_data"))
pref := tools.UserPref{
UnitOwningUserID: int(req.Get("unit_owning_user_id").Int()),
}
_, err := UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref)
utils.CheckErr(err)
naviResp := model.UserNaviChangeResp{
ResponseData: []any{},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(naviResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
func ChangeName(ctx *gin.Context) {
req := gjson.Parse(ctx.PostForm("request_data"))
var oldName string
exists, err := UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Cols("user_name").Get(&oldName)
utils.CheckErr(err)
if !exists {
ctx.String(http.StatusForbidden, ErrorMsg)
return
}
pref := tools.UserPref{
UserName: req.Get("name").String(),
}
_, err = UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref)
utils.CheckErr(err)
nameResp := model.UserNameChangeResp{
ResponseData: model.UserNameChangeRes{
BeforeName: oldName,
AfterName: req.Get("name").String(),
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(nameResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+74
View File
@@ -0,0 +1,74 @@
package handler
import (
"encoding/json"
"honoka-chan/config"
"honoka-chan/internal/model"
"honoka-chan/internal/tools"
"honoka-chan/internal/utils"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
func UserInfo(ctx *gin.Context) {
userId, err := strconv.Atoi(ctx.GetString("userid"))
utils.CheckErr(err)
pref := tools.UserPref{}
exists, err := UserEng.Table("user_preference_m").Where("user_id = ?", userId).Get(&pref)
utils.CheckErr(err)
if !exists {
ctx.String(http.StatusForbidden, ErrorMsg)
return
}
userResp := model.UserInfoResp{
ResponseData: model.UserInfoRes{
User: model.UserInfo{
UserID: userId,
Name: pref.UserName,
Level: config.Conf.UserPrefs.Level,
Exp: config.Conf.UserPrefs.ExpNumerator,
PreviousExp: 0,
NextExp: config.Conf.UserPrefs.ExpDenominator,
GameCoin: config.Conf.UserPrefs.GameCoin,
SnsCoin: config.Conf.UserPrefs.SnsCoin,
FreeSnsCoin: config.Conf.UserPrefs.SnsCoin,
PaidSnsCoin: 0,
SocialPoint: 1438395,
UnitMax: 5000,
WaitingUnitMax: 1000,
EnergyMax: config.Conf.UserPrefs.EnergyMax,
EnergyFullTime: "2023-03-20 03:58:55",
LicenseLiveEnergyRecoverlyTime: 60,
EnergyFullNeedTime: 0,
OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy,
TrainingEnergy: 100,
TrainingEnergyMax: 100,
FriendMax: 99,
InviteCode: config.Conf.UserPrefs.InviteCode,
InsertDate: "2015-08-10 18:58:30",
UpdateDate: "2018-08-09 18:13:12",
TutorialState: -1,
DiamondCoin: 0,
CrystalCoin: 0,
LpRecoveryItem: []model.LpRecoveryItem{},
},
Birth: model.Birth{
BirthMonth: 10,
BirthDay: 18,
},
ServerTimestamp: time.Now().Unix(),
},
ReleaseInfo: []any{},
StatusCode: 200,
}
resp, err := json.Marshal(userResp)
utils.CheckErr(err)
ctx.Header("X-Message-Sign", utils.GenXMS(resp))
ctx.String(http.StatusOK, string(resp))
}
+197
View File
@@ -0,0 +1,197 @@
package handler
import (
"encoding/csv"
"honoka-chan/internal/model"
"honoka-chan/internal/utils"
"net/http"
"os"
"path"
"strconv"
"time"
"github.com/forgoer/openssl"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
type ErrMsg struct {
Error int `json:"error"`
Msg string `json:"msg"`
}
func WebLogin(ctx *gin.Context) {
area := ctx.PostForm("area")
user := ctx.PostForm("user")
pass := ctx.PostForm("pass")
if area == "" || user == "" || pass == "" {
ctx.JSON(http.StatusOK, model.Msg{
Code: 1,
Message: "参数不完整!",
Redirect: "",
})
return
}
userName := " " + area + "-" + user
var userId int
exists, err := UserEng.Table("users").Where("phone = ? AND password = ?", userName, openssl.Md5ToString(pass)).Cols("userid").Get(&userId)
utils.CheckErr(err)
if !exists {
ctx.JSON(http.StatusOK, model.Msg{
Code: 1,
Message: "账号不存在或者密码有误!",
Redirect: "",
})
return
}
session := sessions.Default(ctx)
session.Options(sessions.Options{
MaxAge: 3600 * 24,
})
session.Set("userid", userId)
session.Save()
ctx.JSON(http.StatusOK, model.Msg{
Code: 0,
Message: "登录成功!",
Redirect: "/admin/index",
})
}
func WebLogout(ctx *gin.Context) {
session := sessions.Default(ctx)
session.Clear()
session.Options(sessions.Options{
Path: "/admin",
MaxAge: -1,
})
session.Save()
ctx.Redirect(http.StatusFound, "/admin/login")
}
func Upload(ctx *gin.Context) {
file, err := ctx.FormFile("file")
utils.CheckErr(err)
tmpPath := path.Join("./temp", file.Filename)
err = ctx.SaveUploadedFile(file, tmpPath)
utils.CheckErr(err)
session := UserEng.NewSession()
defer session.Close()
if err = session.Begin(); err != nil {
session.Rollback()
panic(err)
}
f, err := os.Open(tmpPath)
utils.CheckErr(err)
defer f.Close()
r := csv.NewReader(f)
rs, err := r.ReadAll()
if err != nil {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "文件解析失败!"})
return
}
for _, rr := range rs {
if len(rr) != 2 || rr[0] == "" || rr[1] == "" {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "文件解析失败!"})
return
}
skillLv, err := strconv.Atoi(rr[1])
if err != nil {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "文件解析失败!"})
return
}
var unitId, unitExp, unitRarity, unitHp, unitSigned int
exists, err := MainEng.Table("common_unit_m").Join("LEFT", "unit_m", "common_unit_m.unit_id = unit_m.unit_id").
Where("unit_m.unit_number = ?", rr[0]).
Cols("common_unit_m.unit_id,common_unit_m.exp,unit_m.rarity,common_unit_m.max_hp,common_unit_m.is_signed").
Get(&unitId, &unitExp, &unitRarity, &unitHp, &unitSigned)
utils.CheckErr(err)
if !exists {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "卡片不存在!"})
return
}
if unitRarity != 4 {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "仅支持导入UR卡片!"})
return
}
if skillLv < 0 || skillLv > 8 {
session.Rollback()
ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "技能等级设置有误!"})
return
}
var diffExp, diffSmile, diffPure, diffCool int
_, err = MainEng.Table("unit_level_limit_pattern_m").Where("unit_level_limit_id = 1 AND unit_level = 350").
Cols("next_exp,smile_diff,pure_diff,cool_diff").Get(&diffExp, &diffSmile, &diffPure, &diffCool)
utils.CheckErr(err)
isSigned := false
if unitSigned == 1 {
isSigned = true
}
var skillExp int
if skillLv != 8 {
skillExp = 0
} else {
skillExp = 29900
}
unitData := model.UnitData{
UserID: ctx.GetInt("userid"),
UnitID: unitId,
Exp: unitExp + diffExp,
NextExp: 0,
Level: 350,
MaxLevel: 350,
LevelLimitID: 1,
Rank: 2,
MaxRank: 2,
Love: 1000,
MaxLove: 1000,
UnitSkillExp: skillExp,
UnitSkillLevel: skillLv,
MaxHp: unitHp,
UnitRemovableSkillCapacity: 8,
FavoriteFlag: false,
DisplayRank: 2,
IsRankMax: true,
IsLoveMax: true,
IsLevelMax: true,
IsSigned: isSigned,
IsSkillLevelMax: true,
IsRemovableSkillCapacityMax: true,
InsertDate: time.Now().Format("2006-01-02 03:04:05"),
}
_, err = session.Table("user_unit_m").Insert(&unitData)
if err != nil {
session.Rollback()
panic(err)
}
if err = session.Commit(); err != nil {
session.Rollback()
panic(err)
}
}
ctx.JSON(http.StatusOK, ErrMsg{Error: 0, Msg: "上传成功!"})
}