Files
bl/modules/player/service/pet.go
昔念 0b2d127faf ```
refactor(pet): 重构宠物服务方法命名和优化数据库操作

- 统一PetService中方法命名规范,将驼峰命名改为标准驼峰格式
- 修复拼写错误:UPdate -> Update, UPdateFree -> UpdateFree等
- 重命名查询方法:PetInfo_One -> PetInfoOneByCatchTime,
  PetInfo_One_ID -> PetInfoOneByID, PetInfo_One_ohter -> PetInfoOneOther
- 优化BuyPet方法中的事务处理逻辑,使用结构体初始化简化代码
- 添加nextCatchTime辅助方法用于生成唯一的捕捉时间戳
- 优化PetAdd方法的实现逻辑,提高代码可读性
- 清理无用注释代码
```
2026-03-26 05:33:40 +08:00

288 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"blazing/cool"
basemodel "blazing/modules/base/model"
"blazing/modules/base/service"
"blazing/modules/player/model"
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// nextCatchTime 生成下一个唯一捕捉时间戳(原子递增 max_ts
func (s *PetService) nextCatchTime(m ...*gdb.Model) (uint32, error) {
dbm := cool.DBM(service.NewBaseSysUserService().Model)
if len(m) > 0 {
dbm = m[0]
}
sql := fmt.Sprintf(`
UPDATE %s
SET max_ts = CASE
WHEN max_ts < EXTRACT(EPOCH FROM NOW())::INT THEN EXTRACT(EPOCH FROM NOW())::INT
ELSE max_ts + 1
END
WHERE id = ? AND deleted_at IS NULL
RETURNING max_ts;`, service.NewBaseSysUserService().Model.TableName())
ret, err := dbm.Raw(sql, s.userid).All()
if err != nil {
return 0, fmt.Errorf("生成捕捉时间失败: %w", err)
}
arr := ret.Array()
if len(arr) == 0 {
return 0, fmt.Errorf("生成捕捉时间失败: 无返回数据")
}
return arr[0].Uint32(), nil
}
// setCatchTime 将 Pet.CatchTime 同步到 Pet.Data.CatchTime
func setCatchTime(pet *model.Pet) {
if pet != nil {
pet.Data.CatchTime = pet.CatchTime
}
}
// 获取精灵信息 0是仓库,1是放生
func (s *PetService) PetInfo(flag int) []model.Pet {
var tt []model.Pet
if err := s.dbm(s.Model).Where("free", flag).Scan(&tt); err != nil {
return nil
}
for i := range tt {
tt[i].Data.CatchTime = tt[i].CatchTime
}
return tt
}
func (s *PetService) PetCount(flag int) int {
ret, err := s.dbm(s.Model).Where("free", flag).Count()
if err != nil {
return 0
}
return ret
}
func (s *PetService) UpdateFree(catchTime, free uint32) bool {
res, err := s.dbm(s.Model).Where("catch_time", catchTime).Data("free", free).Update()
if err != nil {
return false
}
r, _ := res.RowsAffected()
return r > 0
}
func (s *PetService) UpdatePrice(catchTime, price, free uint32) error {
var item model.Pet
var feeRate float64
if free == 2 {
t, _ := s.dbm(s.Model).Where("free", 2).Count()
if t > 3 {
return fmt.Errorf("精灵数量已满")
}
} else {
if err := s.dbm(s.Model).Where("catch_time", catchTime).Scan(&item); err != nil {
return err
}
_, feeRate, _ = item.GetOffShelfFee()
_ = feeRate // feeRate 仅在 non-2 分支使用,在此声明以统一作用域
}
res, _ := s.dbm(s.Model).Where("catch_time", catchTime).Data(g.Map{
"sale_price": price,
"free": free,
}).Update()
affected, _ := res.RowsAffected()
if affected > 0 && free != 2 && feeRate != 0 {
amount := item.CalculateOffShelfAmount(feeRate)
service.NewBaseSysUserService().UpdateFreeGold(s.userid, -int64(amount*100))
}
return nil
}
func (s *PetService) BuyPet(pid uint32) error {
tt := NewPetService(0).PetInfoOneByID(pid)
if tt == nil {
return fmt.Errorf("没有此精灵")
}
if tt.IsVip != 0 {
return fmt.Errorf("不允许交易")
}
if tt.Free != 2 {
return fmt.Errorf("未上架")
}
if tt.SalePrice == 0 {
return fmt.Errorf("未设置价格")
}
if !tt.UpdateTime.AddDate(0, 0, 1).Before(gtime.Now()) {
return fmt.Errorf("未到购买时间")
}
return g.DB().Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
useGold := int64(tt.SalePrice)*102 + int64(tt.SaleCount)*5
var user basemodel.BaseSysUser
if err := tx.Model(basemodel.BaseSysUser{}).Where("id", s.userid).Fields("free_gold").Scan(&user); err != nil {
return err
}
if user.FreeGold < useGold {
return fmt.Errorf("余额不足")
}
if _, err := tx.Model(basemodel.BaseSysUser{}).Where("id", s.userid).Increment("free_gold", -useGold); err != nil {
return err
}
res, err := tx.Model(s.Model).Where("id", tt.ID).Delete()
if err != nil {
return err
}
affected, _ := res.RowsAffected()
if affected == 0 {
return fmt.Errorf("重复订单")
}
if _, err := tx.Model(basemodel.BaseSysUser{}).Where("id", tt.PlayerID).Increment("free_gold", int64(tt.SalePrice)*98); err != nil {
return err
}
catchTime, err := s.nextCatchTime(tx.Model(service.NewBaseSysUserService().Model))
if err != nil {
return err
}
player := model.Pet{
PlayerID: s.userid,
Data: tt.Data,
CatchTime: catchTime,
Free: 0,
SalePrice: tt.SalePrice,
SaleCount: tt.SaleCount + 1,
}
player.IsVip = cool.Config.ServerInfo.IsVip
player.Data.OldCatchTime = 0
if _, err := tx.Model(s.Model).Insert(player); err != nil {
return err
}
return nil
})
}
func (s *PetService) Update(t model.PetInfo) bool {
_, err := s.dbm(s.Model).Where("catch_time", t.CatchTime).Data("data", t).Update()
return err == nil
}
func (s *PetService) PetInfoOneByCatchTime(catchTime uint32) *model.Pet {
var tt *model.Pet
if err := s.dbm(s.Model).Where("catch_time", catchTime).Scan(&tt); err != nil || tt == nil {
return nil
}
setCatchTime(tt)
return tt
}
func (s *PetService) PetInfoOneByID(id uint32) *model.Pet {
var tt *model.Pet
if err := s.dbm(s.Model).Where("id", id).Scan(&tt); err != nil || tt == nil {
return nil
}
setCatchTime(tt)
return tt
}
func (s *PetService) PetInfoOneOther(userid, catchTime uint32) model.Pet {
var tt model.Pet
s.dbm(s.Model).Where("catch_time", catchTime).Scan(&tt)
tt.Data.CatchTime = tt.CatchTime
return tt
}
func (s *PetService) PetInfoOneUnscoped(catchTime uint32) *model.Pet {
var tt *model.Pet
if err := s.dbm(s.Model).Where("catch_time", catchTime).Unscoped().Scan(&tt); err != nil || tt == nil {
return nil
}
setCatchTime(tt)
return tt
}
func (s *PetService) PetDel(catchTime uint32) {
s.dbm(s.Model).Where("catch_time", catchTime).Delete()
}
func (s *PetService) PetLevelAll() []model.Pet {
var tt []model.Pet
s.dbm(s.Model).As("pp").
Wheref("(pp.data->>'Level')::INT > 100").
OrderDesc("(pp.data->>'Level')::INT").
Scan(&tt)
return tt
}
// PetAdd 精灵真正添加后的捕捉时间才是真正的时间
func (s *PetService) PetAdd(y *model.PetInfo, saleCount uint32) (uint32, error) {
if y == nil {
return 0, nil
}
catchTime, err := s.nextCatchTime()
if err != nil {
return 0, err
}
y.CatchTime = catchTime
player := model.Pet{
PlayerID: s.userid,
Data: *y,
CatchTime: catchTime,
Free: 0,
SaleCount: saleCount,
}
player.IsVip = cool.Config.ServerInfo.IsVip
if _, err := cool.DBM(s.Model).Where("player_id", s.userid).Insert(player); err != nil {
return 0, err
}
return catchTime, nil
}
type PetService struct {
BaseService
}
func NewPetService(userid uint32) *PetService {
return &PetService{
BaseService: BaseService{
userid: userid,
Service: &cool.Service{
Model: model.NewPet(),
ListQueryOp: &cool.QueryOp{
AddOrderby: g.MapStrStr{"updateTime": "asc"},
FieldEQ: []string{"player_id", "free"},
Where: func(ctx context.Context) [][]interface{} {
return [][]interface{}{
{"free", 0, false},
{"is_vip", 0, true},
}
},
},
PageQueryOp: &cool.QueryOp{
FieldEQ: []string{"player_id", "free"},
DataFieldEQ: []string{"ID"},
Where: func(ctx context.Context) [][]interface{} {
return [][]interface{}{
{"free", 0, false},
{"is_vip", 0, true},
}
},
},
},
},
}
}