270 lines
6.3 KiB
Go
270 lines
6.3 KiB
Go
package service
|
|
|
|
import (
|
|
"blazing/common/socket/errorcode"
|
|
"blazing/cool"
|
|
baseservice "blazing/modules/base/service"
|
|
"blazing/modules/player/model"
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
)
|
|
|
|
var (
|
|
errPetFusionInsufficientItems = errors.New("pet fusion insufficient items")
|
|
errPetFusionPetNotFound = errors.New("pet fusion pet not found")
|
|
errPetFusionPlayerNotFound = errors.New("pet fusion player not found")
|
|
)
|
|
|
|
type PetFusionTxResult struct {
|
|
NewPet *model.PetInfo
|
|
CostItemUsed bool
|
|
UpdatedAux *model.PetInfo
|
|
}
|
|
|
|
func (s *UserService) PetFusionTx(
|
|
currentInfo model.PlayerInfo,
|
|
masterCatchTime uint32,
|
|
auxCatchTime uint32,
|
|
materialCounts map[uint32]int,
|
|
goldItemIDs []uint32,
|
|
keepAuxItemID uint32,
|
|
failureItemID uint32,
|
|
cost int64,
|
|
newPet *model.PetInfo,
|
|
failedAux *model.PetInfo,
|
|
) (*PetFusionTxResult, errorcode.ErrorCode) {
|
|
if s == nil || s.Pet == nil {
|
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
|
}
|
|
|
|
userID := s.Pet.userid
|
|
nextInfo := currentInfo
|
|
if nextInfo.Coins < cost {
|
|
return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
|
}
|
|
nextInfo.Coins -= cost
|
|
|
|
result := &PetFusionTxResult{}
|
|
err := g.DB().Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
|
|
if err := updatePlayerInfoTx(tx, userID, nextInfo); err != nil {
|
|
return err
|
|
}
|
|
if err := consumeItemCountsTx(tx, userID, materialCounts); err != nil {
|
|
return err
|
|
}
|
|
|
|
if newPet == nil {
|
|
used, err := consumeOptionalItemTx(tx, userID, goldItemIDs, failureItemID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result.CostItemUsed = used
|
|
if !used && failedAux != nil {
|
|
if err := updatePetDataTx(tx, userID, auxCatchTime, *failedAux); err != nil {
|
|
return err
|
|
}
|
|
auxCopy := *failedAux
|
|
result.UpdatedAux = &auxCopy
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if err := deletePetTx(tx, userID, masterCatchTime); err != nil {
|
|
return err
|
|
}
|
|
|
|
used, err := consumeOptionalItemTx(tx, userID, goldItemIDs, keepAuxItemID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result.CostItemUsed = used
|
|
if !used {
|
|
if err := deletePetTx(tx, userID, auxCatchTime); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
catchTime, err := addPetTx(tx, s.Pet, newPet, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
petCopy := *newPet
|
|
petCopy.CatchTime = catchTime
|
|
result.NewPet = &petCopy
|
|
return nil
|
|
})
|
|
if err == nil {
|
|
return result, 0
|
|
}
|
|
|
|
switch {
|
|
case errors.Is(err, errPetFusionInsufficientItems):
|
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
|
case errors.Is(err, errPetFusionPetNotFound):
|
|
return nil, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
|
case errors.Is(err, errPetFusionPlayerNotFound):
|
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
|
default:
|
|
cool.Logger.Error(context.TODO(), "pet fusion tx failed", userID, err)
|
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
|
}
|
|
}
|
|
|
|
func updatePlayerInfoTx(tx gdb.TX, userID uint32, info model.PlayerInfo) error {
|
|
res, err := tx.Model(model.NewPlayer()).Where("player_id", userID).Data("data", info).Update()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, err := res.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if affected == 0 {
|
|
return errPetFusionPlayerNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func consumeItemCountsTx(tx gdb.TX, userID uint32, itemCounts map[uint32]int) error {
|
|
for itemID, count := range itemCounts {
|
|
if err := updateItemCountTx(tx, userID, itemID, -count); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func consumeOptionalItemTx(tx gdb.TX, userID uint32, itemIDs []uint32, target uint32) (bool, error) {
|
|
for _, itemID := range itemIDs {
|
|
if itemID != target {
|
|
continue
|
|
}
|
|
if err := updateItemCountTx(tx, userID, target, -1); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func updateItemCountTx(tx gdb.TX, userID uint32, id uint32, count int) error {
|
|
if cool.Config.ServerInfo.IsVip != 0 && count < 0 {
|
|
return nil
|
|
}
|
|
if id == 0 {
|
|
return nil
|
|
}
|
|
|
|
baseModel := tx.Model(model.NewPlayerBag()).
|
|
Where("player_id", userID).
|
|
Where("is_vip", cool.Config.ServerInfo.IsVip)
|
|
|
|
ok, err := baseModel.Where("item_id", id).Exist()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if ok {
|
|
updateModel := tx.Model(model.NewPlayerBag()).
|
|
Where("player_id", userID).
|
|
Where("is_vip", cool.Config.ServerInfo.IsVip).
|
|
Where("item_id", id)
|
|
if count < 0 {
|
|
updateModel = updateModel.Where("item_cnt + ? > 0", count)
|
|
}
|
|
|
|
result, err := updateModel.Increment("item_cnt", count)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if affected == 0 {
|
|
return errPetFusionInsufficientItems
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if count <= 0 {
|
|
return errPetFusionInsufficientItems
|
|
}
|
|
|
|
_, err = tx.Model(model.NewPlayerBag()).Data(g.Map{
|
|
"player_id": userID,
|
|
"item_id": id,
|
|
"item_cnt": count,
|
|
"is_vip": cool.Config.ServerInfo.IsVip,
|
|
}).Insert()
|
|
return err
|
|
}
|
|
|
|
func updatePetDataTx(tx gdb.TX, userID uint32, catchTime uint32, pet model.PetInfo) error {
|
|
res, err := tx.Model(model.NewPet()).
|
|
Where("player_id", userID).
|
|
Where("is_vip", cool.Config.ServerInfo.IsVip).
|
|
Where("catch_time", catchTime).
|
|
Data("data", pet).
|
|
Update()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, err := res.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if affected == 0 {
|
|
return errPetFusionPetNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func deletePetTx(tx gdb.TX, userID uint32, catchTime uint32) error {
|
|
res, err := tx.Model(model.NewPet()).
|
|
Where("player_id", userID).
|
|
Where("is_vip", cool.Config.ServerInfo.IsVip).
|
|
Where("catch_time", catchTime).
|
|
Delete()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, err := res.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if affected == 0 {
|
|
return errPetFusionPetNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func addPetTx(tx gdb.TX, petService *PetService, petInfo *model.PetInfo, saleCount uint32) (uint32, error) {
|
|
if petInfo == nil {
|
|
return 0, nil
|
|
}
|
|
|
|
catchTime, err := petService.nextCatchTime(tx.Model(baseservice.NewBaseSysUserService().Model))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
petCopy := *petInfo
|
|
petCopy.CatchTime = catchTime
|
|
playerPet := model.Pet{
|
|
PlayerID: petService.userid,
|
|
Data: petCopy,
|
|
CatchTime: catchTime,
|
|
Free: 0,
|
|
SaleCount: saleCount,
|
|
}
|
|
playerPet.IsVip = cool.Config.ServerInfo.IsVip
|
|
if _, err := tx.Model(model.NewPet()).Insert(playerPet); err != nil {
|
|
return 0, err
|
|
}
|
|
return catchTime, nil
|
|
}
|