Files
bl/modules/player/service/pet.go
昔念 eb76c22c41
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
1
2026-04-22 01:21:07 +08:00

352 lines
8.8 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("generate catch time failed: empty result")
}
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) StorageInfo(isVip int, free int) []model.Pet {
var tt []model.Pet
if err := s.dbm_fix(s.Model).Where("free", free).Where("is_vip", isVip).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
}
// GetShowPets 获取基地展示的精灵列表is_show=1
func (s *PetService) GetShowPets() []model.Pet {
var tt []model.Pet
if err := s.dbm_fix(s.Model).Where("is_show", 1).Scan(&tt); err != nil {
return nil
}
for i := range tt {
tt[i].Data.CatchTime = tt[i].CatchTime
}
return tt
}
// UpdateIsShow 更新精灵基地展示状态
func (s *PetService) UpdateIsShow(catchTime uint32, isShow int) bool {
res, err := s.dbm(s.Model).
Where("catch_time", catchTime).
Data("is_show", isShow).
Update()
if err != nil {
return false
}
r, _ := res.RowsAffected()
return r > 0
}
// SetShowCatchTimes 批量设置基地展示精灵:
// 先清空当前玩家的展示状态,再将传入 catchTime 列表置为展示。
func (s *PetService) SetShowCatchTimes(catchTimes []uint32) bool {
if _, err := s.dbm(s.Model).
Where("is_show", 1).
Data("is_show", 0).
Update(); err != nil {
return false
}
if len(catchTimes) == 0 {
return true
}
if _, err := s.dbm(s.Model).
WhereIn("catch_time", catchTimes).
Data("is_show", 1).
Update(); err != nil {
return false
}
return true
}
func (s *PetService) UpdateFree(catchTime, fromFree, toFree uint32) bool {
res, err := s.dbm(s.Model).
Where("catch_time", catchTime).
Where("free", fromFree).
Data(g.Map{
"free": toFree,
"is_show": 0, // 放回背包/放生时取消基地展示
}).
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 鍒嗘敮浣跨敤锛屽湪姝ゅ0鏄庝互缁熶竴浣滅敤鍩?
}
res, _ := s.dbm(s.Model).Where("catch_time", catchTime).Data(g.Map{
"sale_price": price,
"free": free,
"is_show": 0, // 上架/下架时取消基地展示
}).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("pet not found")
}
if tt.IsVip != 0 {
return fmt.Errorf("pet cannot be traded")
}
if tt.Free != 2 {
return fmt.Errorf("pet is not on sale")
}
if tt.SalePrice == 0 {
return fmt.Errorf("pet sale price is not set")
}
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},
}
},
},
},
},
}
}