refactor: 优化代码结构和逻辑
This commit is contained in:
@@ -11,14 +11,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
"blazing/logic/service/common"
|
|
||||||
"blazing/logic/service/player"
|
"blazing/logic/service/player"
|
||||||
"blazing/modules/config/service"
|
"blazing/modules/config/service"
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
"github.com/panjf2000/gnet/v2"
|
"github.com/panjf2000/gnet/v2"
|
||||||
"github.com/valyala/bytebufferpool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) Boot(serverid, port uint32) error {
|
func (s *Server) Boot(serverid, port uint32) error {
|
||||||
@@ -266,30 +264,6 @@ func handle(c gnet.Conn) {
|
|||||||
|
|
||||||
func (s *Server) onevent(c gnet.Conn, v []byte) {
|
func (s *Server) onevent(c gnet.Conn, v []byte) {
|
||||||
if t, ok := c.Context().(*player.ClientData); ok {
|
if t, ok := c.Context().(*player.ClientData); ok {
|
||||||
var header common.TomeeHeader
|
t.PushEvent(v, s.workerPool.Submit)
|
||||||
// 解析Len(0-3字节)
|
|
||||||
header.Len = binary.BigEndian.Uint32(v[0:4])
|
|
||||||
// 解析Version(第4字节)
|
|
||||||
//header.Version = v[4]
|
|
||||||
// 解析CMD(5-8字节)
|
|
||||||
header.CMD = binary.BigEndian.Uint32(v[5:9])
|
|
||||||
// 解析UserID(9-12字节)
|
|
||||||
header.UserID = binary.BigEndian.Uint32(v[9:13])
|
|
||||||
// 解析Result(13-16字节)
|
|
||||||
//header.Result = binary.BigEndian.Uint32(v[13:17])
|
|
||||||
// 解析数据部分(17字节之后)
|
|
||||||
// 数据部分:直接引用切片,避免 make
|
|
||||||
if len(v) > 17 {
|
|
||||||
header.Data = bytebufferpool.Get()
|
|
||||||
header.Data.Write(v[17:])
|
|
||||||
//copy(header.Data, v[17:]) // 核心修改:拷贝数据
|
|
||||||
}
|
|
||||||
//t.OnEvent(header)
|
|
||||||
// t.LF.Push(header)
|
|
||||||
s.workerPool.Submit(func() {
|
|
||||||
t.LF.Producer().Write(header)
|
|
||||||
// t.LF.Producer().Write(header)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func NewServer(options ...Option) *Server {
|
|||||||
// handler: handler.NewTomeeHandler(), //请求返回
|
// handler: handler.NewTomeeHandler(), //请求返回
|
||||||
codec: codec.NewTomeeSocketCodec(), //默认解码器 len+pack
|
codec: codec.NewTomeeSocketCodec(), //默认解码器 len+pack
|
||||||
workerPool: goroutine.Default(),
|
workerPool: goroutine.Default(),
|
||||||
bufferSize: 40960, //默认缓冲区大小
|
bufferSize: 40960, //默认缓冲区大小
|
||||||
multicore: true,
|
multicore: true,
|
||||||
//batchRead: 8,
|
//batchRead: 8,
|
||||||
//discorse: true,
|
//discorse: true,
|
||||||
|
|||||||
30
logic/controller/buy_seerdou_item.go
Normal file
30
logic/controller/buy_seerdou_item.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"blazing/common/data/xmlres"
|
||||||
|
"blazing/common/socket/errorcode"
|
||||||
|
"blazing/logic/service/player"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buySeerdouBackpackItem(player *player.Player, itemID int64, count int64) (bought bool, err errorcode.ErrorCode) {
|
||||||
|
if itemID <= 0 || count <= 0 {
|
||||||
|
return false, errorcode.ErrorCodes.ErrSystemError
|
||||||
|
}
|
||||||
|
|
||||||
|
itemInfo, exists := xmlres.ItemsMAP[int(itemID)]
|
||||||
|
if !exists {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCost := int64(itemInfo.Price) * count
|
||||||
|
if totalCost > 0 && !player.GetCoins(totalCost) {
|
||||||
|
return false, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
||||||
|
}
|
||||||
|
|
||||||
|
if !player.ItemAdd(itemID, count) {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
player.Info.Coins -= totalCost
|
||||||
|
return true, 0
|
||||||
|
}
|
||||||
@@ -7,9 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"blazing/logic/service/fight"
|
"blazing/logic/service/fight"
|
||||||
"blazing/logic/service/fight/info"
|
fightinfo "blazing/logic/service/fight/info"
|
||||||
"blazing/logic/service/fight/input"
|
"blazing/logic/service/fight/input"
|
||||||
|
|
||||||
"blazing/logic/service/player"
|
"blazing/logic/service/player"
|
||||||
configmodel "blazing/modules/config/model"
|
configmodel "blazing/modules/config/model"
|
||||||
"blazing/modules/config/service"
|
"blazing/modules/config/service"
|
||||||
@@ -20,217 +19,259 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// PlayerFightBoss 挑战地图boss
|
// PlayerFightBoss 挑战地图boss
|
||||||
// data: 包含挑战Boss信息的输入数据
|
func (Controller) PlayerFightBoss(req *fight.ChallengeBossInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
// player: 当前玩家对象
|
if err = p.CanFight(); err != 0 {
|
||||||
// 返回: 战斗结果和错误码
|
return nil, err
|
||||||
func (Controller) PlayerFightBoss(data1 *fight.ChallengeBossInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
|
||||||
r := p.CanFight()
|
|
||||||
if p.CanFight() != 0 {
|
|
||||||
return nil, r
|
|
||||||
}
|
|
||||||
var monster *model.PetInfo
|
|
||||||
monsterInfo := &model.PlayerInfo{}
|
|
||||||
|
|
||||||
mdata := service.NewMapNodeService().GetDataNode(p.Info.MapID, data1.BossId)
|
|
||||||
if mdata == nil {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
var bosinfo []configmodel.BossConfig
|
|
||||||
switch len(mdata.BossIds) {
|
|
||||||
case 0:
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
case 1:
|
|
||||||
bosinfo = service.NewBossService().Get(mdata.BossIds[0])
|
|
||||||
default:
|
|
||||||
bosinfo = service.NewBossService().Get(mdata.BossIds[grand.Intn(len(mdata.BossIds))])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(bosinfo) == 0 {
|
mapNode := service.NewMapNodeService().GetDataNode(p.Info.MapID, req.BossId)
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
bossConfigs, err := loadMapBossConfigs(mapNode)
|
||||||
|
if err != 0 {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
dv := 24
|
|
||||||
ger := 0
|
monsterInfo, leadMonsterID, err := buildBossMonsterInfo(mapNode.NodeName, bossConfigs)
|
||||||
if bosinfo[0].IsCapture == 1 {
|
if err != 0 {
|
||||||
dv = -1
|
return nil, err
|
||||||
ger = -1
|
|
||||||
}
|
}
|
||||||
for i, bm := range bosinfo {
|
|
||||||
|
|
||||||
monster = model.GenPetInfo(
|
p.Fightinfo.Status = fightinfo.BattleMode.FIGHT_WITH_NPC
|
||||||
gconv.Int(bm.MonID), dv, //24个体
|
p.Fightinfo.Mode = fightinfo.BattleMode.MULTI_MODE
|
||||||
-1,
|
|
||||||
0, //野怪没特性
|
|
||||||
|
|
||||||
int(bm.Lv), nil, ger)
|
|
||||||
monster.CatchTime = uint32(i)
|
|
||||||
monster.ConfigBoss(bm.PetBaseConfig)
|
|
||||||
effects := service.NewEffectService().Args(bm.Effect)
|
|
||||||
|
|
||||||
for _, v := range effects {
|
|
||||||
monster.EffectInfo = append(monster.EffectInfo, model.PetEffectInfo{
|
|
||||||
Idx: uint16(v.SeIdx),
|
|
||||||
EID: gconv.Uint16(v.Eid),
|
|
||||||
Args: gconv.Ints(v.Args),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
|
|
||||||
}
|
|
||||||
if bosinfo[0].IsCapture == 1 {
|
|
||||||
monsterInfo.PetList[0].ShinyInfo = make([]data.GlowFilter, 0)
|
|
||||||
if grand.Meet(1, 500) {
|
|
||||||
monsterInfo.PetList[0].RandomByWeightShiny()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
monsterInfo.Nick = mdata.NodeName //xmlres.PetMAP[int(monster.ID)].DefName
|
|
||||||
|
|
||||||
if len(monsterInfo.PetList) == 0 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
p.Fightinfo.Status = info.BattleMode.FIGHT_WITH_NPC
|
|
||||||
p.Fightinfo.Mode = info.BattleMode.MULTI_MODE
|
|
||||||
|
|
||||||
ai := player.NewAI_player(monsterInfo)
|
ai := player.NewAI_player(monsterInfo)
|
||||||
ai.CanCapture = bosinfo[0].IsCapture
|
ai.CanCapture = resolveBossCaptureRate(bossConfigs[0].IsCapture, leadMonsterID)
|
||||||
if bosinfo[0].IsCapture != 0 {
|
|
||||||
ai.CanCapture = xmlres.PetMAP[int(monster.ID)].CatchRate
|
|
||||||
if xmlres.PetMAP[int(monster.ID)].CatchRate == 0 {
|
|
||||||
ai.CanCapture = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ai.Prop[0] = 2
|
ai.Prop[0] = 2
|
||||||
var fighc *fight.FightC
|
|
||||||
fighc, _ = fight.NewFight(p, ai, p.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
|
||||||
if mdata.WinBonusID != 0 {
|
|
||||||
if len(bosinfo[0].Rule) == 0 {
|
|
||||||
if foi.Reason == 0 && foi.WinnerId == p.Info.UserID {
|
|
||||||
p.SptCompletedTask(mdata.WinBonusID, 1)
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//说明是带规则的
|
|
||||||
iswin := true
|
|
||||||
for _, v := range service.NewFightRuleService().GetByRuleIdxs(bosinfo[0].Rule) {
|
|
||||||
r := input.GetRule(int64(v.RuleIdx))
|
|
||||||
if r != nil {
|
|
||||||
r.SetArgs(v.Args...)
|
|
||||||
|
|
||||||
if !(r.Exec(fighc, &foi)) {
|
|
||||||
iswin = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if iswin {
|
|
||||||
p.SptCompletedTask(mdata.WinBonusID, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var fightC *fight.FightC
|
||||||
|
fightC, err = fight.NewFight(p, ai, p.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
||||||
|
if mapNode.WinBonusID == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if shouldGrantBossWinBonus(fightC, p.Info.UserID, bossConfigs[0], foi) {
|
||||||
|
p.SptCompletedTask(mapNode.WinBonusID, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//p.Done.Exec(model.MilestoneMode.BOSS, []uint32{p.Info.MapID, data.BossId, uint32(foi.Reason)}, nil)
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
if err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return nil, -1
|
return nil, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnPlayerFightNpcMonster 战斗野怪
|
// OnPlayerFightNpcMonster 战斗野怪
|
||||||
// data: 包含战斗野怪信息的输入数据
|
func (Controller) OnPlayerFightNpcMonster(req *fight.FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
// player: 当前玩家对象
|
if err = p.CanFight(); err != 0 {
|
||||||
// 返回: 战斗结果和错误码
|
return nil, err
|
||||||
func (Controller) OnPlayerFightNpcMonster(data1 *fight.FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
|
||||||
r := p.CanFight()
|
|
||||||
if p.CanFight() != 0 {
|
|
||||||
return nil, r
|
|
||||||
}
|
}
|
||||||
if data1.Number > 9 {
|
if req.Number > 9 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||||
}
|
}
|
||||||
refPet := p.Data[data1.Number]
|
|
||||||
if refPet.ID == 0 {
|
|
||||||
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
refPet := p.Data[req.Number]
|
||||||
|
monster, monsterInfo, err := buildNpcMonsterInfo(refPet, p.Info.MapID)
|
||||||
|
if err != 0 {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
monster := model.GenPetInfo(
|
|
||||||
int(refPet.GetID()), -1,
|
|
||||||
-1,
|
|
||||||
0, //野怪没特性
|
|
||||||
|
|
||||||
int(refPet.GetLevel()),
|
|
||||||
refPet.ShinyInfo, -1)
|
|
||||||
monster.CatchMap = p.Info.MapID //设置当前地图
|
|
||||||
if refPet.Ext != 0 {
|
|
||||||
if grand.Meet(1, 500) {
|
|
||||||
monster.RandomByWeightShiny()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
monsterInfo := &model.PlayerInfo{}
|
|
||||||
monsterInfo.Nick = xmlres.PetMAP[int(monster.ID)].DefName
|
|
||||||
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
|
|
||||||
ai := player.NewAI_player(monsterInfo)
|
ai := player.NewAI_player(monsterInfo)
|
||||||
|
ai.CanCapture = refPet.IsCapture
|
||||||
|
|
||||||
ai.CanCapture = refPet.IsCapture //handleNPCFightSpecial(monster.ID)
|
p.Fightinfo.Status = fightinfo.BattleMode.FIGHT_WITH_NPC
|
||||||
|
p.Fightinfo.Mode = fightinfo.BattleMode.MULTI_MODE
|
||||||
p.Fightinfo.Status = info.BattleMode.FIGHT_WITH_NPC //打野怪
|
|
||||||
p.Fightinfo.Mode = info.BattleMode.MULTI_MODE //多人模式
|
|
||||||
|
|
||||||
fight.NewFight(p, ai, p.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
|
||||||
//p.Done.Exec(model.MilestoneMode.Moster, []uint32{p.Info.MapID, monsterInfo.PetList[0].ID, uint32(foi.Reason)}, nil)
|
|
||||||
if foi.Reason == 0 && foi.WinnerId == p.Info.UserID && p.CanGet() {
|
|
||||||
|
|
||||||
exp := uint32(xmlres.PetMAP[int(monster.ID)].YieldingExp) * monster.Level / 7
|
|
||||||
addlevel, poolevel := p.CanGetExp()
|
|
||||||
addexp := gconv.Float32(addlevel * gconv.Float32(exp))
|
|
||||||
|
|
||||||
poolexp := gconv.Float32(poolevel) * gconv.Float32((exp))
|
|
||||||
items := &info.S2C_GET_BOSS_MONSTER{}
|
|
||||||
|
|
||||||
p.ItemAdd(3, int64(poolexp+addexp))
|
|
||||||
items.ADDitem(3, uint32(poolexp))
|
|
||||||
|
|
||||||
p.AddPetExp(foi.Winpet, int64(addexp))
|
|
||||||
pettype := int64(xmlres.PetMAP[int(refPet.GetID())].Type)
|
|
||||||
|
|
||||||
if p.CanGetItem() {
|
|
||||||
|
|
||||||
item := p.GetSpace().GetDrop()
|
|
||||||
if item != 0 {
|
|
||||||
count := int64(grand.N(1, 2))
|
|
||||||
ok := p.ItemAdd(item, count)
|
|
||||||
if ok {
|
|
||||||
items.ADDitem(uint32(item), uint32(count))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if monster.IsShiny() && p.CanGetXUAN() && pettype < 16 {
|
|
||||||
xuan := 400686 + pettype
|
|
||||||
count := uint32(grand.N(1, 2))
|
|
||||||
ok := p.ItemAdd(xuan, int64(count))
|
|
||||||
if ok {
|
|
||||||
items.ADDitem(uint32(xuan), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
p.SendPackCmd(8004, items)
|
|
||||||
|
|
||||||
evs := gconv.Int64s(strings.Split(xmlres.PetMAP[int(monster.ID)].YieldingEV, " "))
|
|
||||||
|
|
||||||
foi.Winpet.AddEV(evs)
|
|
||||||
//取消累计学习力掉落
|
|
||||||
// if leve == 8 {
|
|
||||||
// items.EV = lo.Sum(evs) - 1
|
|
||||||
// p.Info.EVPool += lo.Sum(evs) //给予累计学习力
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_, err = fight.NewFight(p, ai, p.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
||||||
|
handleNpcFightRewards(p, foi, monster)
|
||||||
})
|
})
|
||||||
|
if err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return nil, -1
|
return nil, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadMapBossConfigs(mapNode *configmodel.MapNode) ([]configmodel.BossConfig, errorcode.ErrorCode) {
|
||||||
|
if mapNode == nil || len(mapNode.BossIds) == 0 {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
bossID := mapNode.BossIds[0]
|
||||||
|
if len(mapNode.BossIds) > 1 {
|
||||||
|
bossID = mapNode.BossIds[grand.Intn(len(mapNode.BossIds))]
|
||||||
|
}
|
||||||
|
|
||||||
|
bossConfigs := service.NewBossService().Get(bossID)
|
||||||
|
if len(bossConfigs) == 0 {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
return bossConfigs, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBossMonsterInfo(nodeName string, bossConfigs []configmodel.BossConfig) (*model.PlayerInfo, uint32, errorcode.ErrorCode) {
|
||||||
|
monsterInfo := &model.PlayerInfo{Nick: nodeName}
|
||||||
|
var leadMonsterID uint32
|
||||||
|
|
||||||
|
for i, bossConfig := range bossConfigs {
|
||||||
|
dv, generation := bossFightPetArgs(bossConfig.IsCapture)
|
||||||
|
monster := model.GenPetInfo(
|
||||||
|
gconv.Int(bossConfig.MonID),
|
||||||
|
dv,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
int(bossConfig.Lv),
|
||||||
|
nil,
|
||||||
|
generation,
|
||||||
|
)
|
||||||
|
if monster == nil {
|
||||||
|
return nil, 0, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
monster.CatchTime = uint32(i)
|
||||||
|
monster.ConfigBoss(bossConfig.PetBaseConfig)
|
||||||
|
appendPetEffects(monster, bossConfig.Effect)
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
leadMonsterID = monster.ID
|
||||||
|
}
|
||||||
|
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(monsterInfo.PetList) == 0 {
|
||||||
|
return nil, 0, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
if bossConfigs[0].IsCapture == 1 {
|
||||||
|
monsterInfo.PetList[0].ShinyInfo = make([]data.GlowFilter, 0)
|
||||||
|
if grand.Meet(1, 500) {
|
||||||
|
monsterInfo.PetList[0].RandomByWeightShiny()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return monsterInfo, leadMonsterID, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func bossFightPetArgs(canCapture int) (dv int, generation int) {
|
||||||
|
if canCapture == 1 {
|
||||||
|
return -1, -1
|
||||||
|
}
|
||||||
|
return 24, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendPetEffects(monster *model.PetInfo, effectIDs []uint32) {
|
||||||
|
effects := service.NewEffectService().Args(effectIDs)
|
||||||
|
for _, effect := range effects {
|
||||||
|
monster.EffectInfo = append(monster.EffectInfo, model.PetEffectInfo{
|
||||||
|
Idx: uint16(effect.SeIdx),
|
||||||
|
EID: gconv.Uint16(effect.Eid),
|
||||||
|
Args: gconv.Ints(effect.Args),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveBossCaptureRate(canCapture int, petID uint32) int {
|
||||||
|
if canCapture == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
petCfg, ok := xmlres.PetMAP[int(petID)]
|
||||||
|
if !ok || petCfg.CatchRate == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return petCfg.CatchRate
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldGrantBossWinBonus(fightC *fight.FightC, playerID uint32, bossConfig configmodel.BossConfig, foi model.FightOverInfo) bool {
|
||||||
|
if len(bossConfig.Rule) == 0 {
|
||||||
|
return foi.Reason == 0 && foi.WinnerId == playerID
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ruleConfig := range service.NewFightRuleService().GetByRuleIdxs(bossConfig.Rule) {
|
||||||
|
rule := input.GetRule(int64(ruleConfig.RuleIdx))
|
||||||
|
if rule == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rule.SetArgs(ruleConfig.Args...)
|
||||||
|
if !rule.Exec(fightC, &foi) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNpcMonsterInfo(refPet player.OgrePetInfo, mapID uint32) (*model.PetInfo, *model.PlayerInfo, errorcode.ErrorCode) {
|
||||||
|
if refPet.ID == 0 {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
monster := model.GenPetInfo(
|
||||||
|
refPet.GetID(),
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
refPet.GetLevel(),
|
||||||
|
refPet.ShinyInfo,
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
if monster == nil {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
monster.CatchMap = mapID
|
||||||
|
if refPet.Ext != 0 && grand.Meet(1, 500) {
|
||||||
|
monster.RandomByWeightShiny()
|
||||||
|
}
|
||||||
|
|
||||||
|
petCfg, ok := xmlres.PetMAP[int(monster.ID)]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
monsterInfo := &model.PlayerInfo{
|
||||||
|
Nick: petCfg.DefName,
|
||||||
|
PetList: []model.PetInfo{*monster},
|
||||||
|
}
|
||||||
|
return monster, monsterInfo, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleNpcFightRewards(p *player.Player, foi model.FightOverInfo, monster *model.PetInfo) {
|
||||||
|
if foi.Reason != 0 || foi.WinnerId != p.Info.UserID || !p.CanGet() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
petCfg, ok := xmlres.PetMAP[int(monster.ID)]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exp := uint32(petCfg.YieldingExp) * monster.Level / 7
|
||||||
|
addlevel, poolevel := p.CanGetExp()
|
||||||
|
addexp := gconv.Float32(addlevel * gconv.Float32(exp))
|
||||||
|
poolexp := gconv.Float32(poolevel) * gconv.Float32(exp)
|
||||||
|
rewards := &fightinfo.S2C_GET_BOSS_MONSTER{}
|
||||||
|
|
||||||
|
p.ItemAdd(3, int64(poolexp+addexp))
|
||||||
|
rewards.ADDitem(3, uint32(poolexp))
|
||||||
|
p.AddPetExp(foi.Winpet, int64(addexp))
|
||||||
|
|
||||||
|
if p.CanGetItem() {
|
||||||
|
itemID := p.GetSpace().GetDrop()
|
||||||
|
if itemID != 0 {
|
||||||
|
count := uint32(grand.N(1, 2))
|
||||||
|
if p.ItemAdd(itemID, int64(count)) {
|
||||||
|
rewards.ADDitem(uint32(itemID), count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
petType := int64(petCfg.Type)
|
||||||
|
if monster.IsShiny() && p.CanGetXUAN() && petType < 16 {
|
||||||
|
xuanID := uint32(400686 + petType)
|
||||||
|
count := uint32(grand.N(1, 2))
|
||||||
|
if p.ItemAdd(int64(xuanID), int64(count)) {
|
||||||
|
rewards.ADDitem(xuanID, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SendPackCmd(8004, rewards)
|
||||||
|
foi.Winpet.AddEV(gconv.Int64s(strings.Fields(petCfg.YieldingEV)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,201 +17,239 @@ import (
|
|||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
towerCmdChoiceTrial uint32 = 2428
|
||||||
|
towerCmdChoiceBrave uint32 = 2414
|
||||||
|
towerCmdFightTrial uint32 = 2429
|
||||||
|
towerCmdFightBrave uint32 = 2415
|
||||||
|
towerCmdFightDark uint32 = 2425
|
||||||
|
|
||||||
|
towerTaskDark int = 110
|
||||||
|
towerTaskBrave int = 500
|
||||||
|
towerTaskTrial int = 600
|
||||||
|
)
|
||||||
|
|
||||||
|
type towerChoiceState struct {
|
||||||
|
currentLevel *uint32
|
||||||
|
maxLevel *uint32
|
||||||
|
service *service.TowerService
|
||||||
|
}
|
||||||
|
|
||||||
// 暗黑门进入boss
|
// 暗黑门进入boss
|
||||||
func (h Controller) FreshOpen(data *fight.C2S_OPEN_DARKPORTAL, c *player.Player) (result *fight.S2C_OPEN_DARKPORTAL, err errorcode.ErrorCode) {
|
func (h Controller) FreshOpen(data *fight.C2S_OPEN_DARKPORTAL, c *player.Player) (result *fight.S2C_OPEN_DARKPORTAL, err errorcode.ErrorCode) {
|
||||||
|
|
||||||
result = &fight.S2C_OPEN_DARKPORTAL{}
|
result = &fight.S2C_OPEN_DARKPORTAL{}
|
||||||
// c.Info.CurrentFreshStage = utils.Max(c.Info.CurrentFreshStage, 1)
|
|
||||||
// c.Info.CurrentStage = utils.Max(c.Info.CurrentStage, 1)
|
towerBosses := service.NewTower110Service().Boss(uint32(data.Level))
|
||||||
boss := service.NewTower110Service().Boss(uint32(data.Level))
|
bossConfig, ok := firstTowerBossConfig(towerBosses)
|
||||||
if len(boss) == 0 {
|
if !ok {
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
}
|
}
|
||||||
if len(boss[0].BossIds) == 0 {
|
|
||||||
|
bosses := service.NewBossService().Get(bossConfig.BossIds[0])
|
||||||
|
if len(bosses) == 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
}
|
}
|
||||||
result = &fight.S2C_OPEN_DARKPORTAL{}
|
|
||||||
r := service.NewBossService().Get(boss[0].BossIds[0])
|
|
||||||
result.CurBossID = uint32(r[0].MonID)
|
|
||||||
|
|
||||||
|
result.CurBossID = uint32(bosses[0].MonID)
|
||||||
c.CurDark = uint32(data.Level)
|
c.CurDark = uint32(data.Level)
|
||||||
defer c.GetSpace().LeaveMap(c)
|
defer c.GetSpace().LeaveMap(c)
|
||||||
return result, 0
|
return result, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// FreshChoiceFightLevel 处理玩家选择挑战模式(试炼之塔或勇者之塔)
|
// FreshChoiceFightLevel 处理玩家选择挑战模式(试炼之塔或勇者之塔)
|
||||||
// 根据不同的CMD值设置玩家的挑战状态和地图信息,并返回当前挑战层级信息
|
|
||||||
// 参数:
|
|
||||||
//
|
|
||||||
// data: 客户端发送的挑战层级选择请求数据,包含CMD和挑战层级
|
|
||||||
// c: 玩家对象,包含玩家的详细信息
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
//
|
|
||||||
// result: 服务器返回给客户端的挑战层级信息,包含当前战斗层级和Boss ID
|
|
||||||
// err: 错误码,表示处理过程中是否出现错误
|
|
||||||
func (h Controller) FreshChoiceFightLevel(data *fight.C2S_FRESH_CHOICE_FIGHT_LEVEL, c *player.Player) (result *fight.S2C_FreshChoiceLevelRequestInfo, err errorcode.ErrorCode) {
|
func (h Controller) FreshChoiceFightLevel(data *fight.C2S_FRESH_CHOICE_FIGHT_LEVEL, c *player.Player) (result *fight.S2C_FreshChoiceLevelRequestInfo, err errorcode.ErrorCode) {
|
||||||
|
|
||||||
result = &fight.S2C_FreshChoiceLevelRequestInfo{}
|
result = &fight.S2C_FreshChoiceLevelRequestInfo{}
|
||||||
c.Info.CurrentFreshStage = utils.Max(c.Info.CurrentFreshStage, 1)
|
c.Info.CurrentFreshStage = utils.Max(c.Info.CurrentFreshStage, 1)
|
||||||
c.Info.CurrentStage = utils.Max(c.Info.CurrentStage, 1)
|
c.Info.CurrentStage = utils.Max(c.Info.CurrentStage, 1)
|
||||||
|
|
||||||
|
choiceState, ok := towerChoiceRuntime(c, data.Head.CMD)
|
||||||
|
if !ok {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||||
|
}
|
||||||
|
|
||||||
if data.Level > 0 {
|
if data.Level > 0 {
|
||||||
switch data.Head.CMD {
|
if !canSelectTowerLevel(data.Level, *choiceState.maxLevel) {
|
||||||
case 2428: //试炼之塔
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
if data.Level > uint(c.Info.MaxFreshStage) && data.Level != 1 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Info.CurrentFreshStage = uint32(data.Level)
|
|
||||||
case 2414: //勇者之塔
|
|
||||||
if data.Level > uint(c.Info.MaxStage) && data.Level != 1 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
c.Info.CurrentStage = uint32(data.Level)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*choiceState.currentLevel = uint32(data.Level)
|
||||||
}
|
}
|
||||||
var boss []configmodel.BaseTowerConfig
|
|
||||||
switch data.Head.CMD {
|
|
||||||
case 2428: //试炼之塔
|
|
||||||
|
|
||||||
result.CurFightLevel = uint32(c.Info.CurrentFreshStage)
|
result.CurFightLevel = *choiceState.currentLevel
|
||||||
boss = service.NewTower600Service().Boss(c.Info.CurrentFreshStage)
|
appendTowerBossPreview(&result.BossId, choiceState.service.Boss(*choiceState.currentLevel))
|
||||||
|
|
||||||
case 2414: //勇者之塔
|
|
||||||
|
|
||||||
result.CurFightLevel = uint32(c.Info.CurrentStage)
|
|
||||||
boss = service.NewTower500Service().Boss(c.Info.CurrentStage)
|
|
||||||
//next := service.NewTower600Service().Boss(c.Info.CurrentFreshStage + 1)
|
|
||||||
|
|
||||||
}
|
|
||||||
if len(boss) != 0 && len(boss[0].BossIds) != 0 {
|
|
||||||
//单节点,取获取到的一个,然后因为不是剧情,所以只有一层
|
|
||||||
r := service.NewBossService().Get(boss[0].BossIds[0])
|
|
||||||
for _, v := range r {
|
|
||||||
result.BossId = append(result.BossId, uint32(v.MonID))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// 重置玩家的Canmon标志位为0,表示可以刷怪
|
|
||||||
atomic.StoreUint32(&c.Canmon, 0)
|
atomic.StoreUint32(&c.Canmon, 0)
|
||||||
// 在函数结束时将玩家传送到对应地图
|
|
||||||
defer c.GetSpace().LeaveMap(c)
|
defer c.GetSpace().LeaveMap(c)
|
||||||
return result, 0
|
return result, 0
|
||||||
}
|
}
|
||||||
func (h Controller) FreshLeaveFightLevel(data *fight.FRESH_LEAVE_FIGHT_LEVEL, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
|
||||||
|
|
||||||
|
func (h Controller) FreshLeaveFightLevel(data *fight.FRESH_LEAVE_FIGHT_LEVEL, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
|
_ = data
|
||||||
defer c.GetSpace().EnterMap(c)
|
defer c.GetSpace().EnterMap(c)
|
||||||
|
|
||||||
out := info.NewOutInfo()
|
out := info.NewOutInfo()
|
||||||
copier.CopyWithOption(out, c.GetInfo(), copier.Option{DeepCopy: true})
|
copier.CopyWithOption(out, c.GetInfo(), copier.Option{DeepCopy: true})
|
||||||
|
|
||||||
//c.SendPackCmd(2001, out)
|
|
||||||
return result, 0
|
return result, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Controller) PetTawor(data *fight.StartTwarInboundInfo, c *player.Player) (result *fight.S2C_ChoiceLevelRequestInfo, err errorcode.ErrorCode) {
|
func (h Controller) PetTawor(data *fight.StartTwarInboundInfo, c *player.Player) (result *fight.S2C_ChoiceLevelRequestInfo, err errorcode.ErrorCode) {
|
||||||
r := c.CanFight()
|
if err = c.CanFight(); err != 0 {
|
||||||
if c.CanFight() != 0 {
|
return nil, err
|
||||||
return nil, r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bossList, currentLevel, taskID, ok := towerFightBosses(c, data.Head.CMD)
|
||||||
|
if !ok {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBoss, ok := firstTowerBossConfig(bossList)
|
||||||
|
if !ok {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
|
result = &fight.S2C_ChoiceLevelRequestInfo{CurFightLevel: currentLevel}
|
||||||
|
appendTowerNextBossPreview(&result.BossID, bossList)
|
||||||
|
|
||||||
|
monsterInfo, ok := buildTowerMonsterInfo(currentBoss)
|
||||||
|
if !ok {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
|
||||||
c.Fightinfo.Mode = fightinfo.BattleMode.MULTI_MODE
|
c.Fightinfo.Mode = fightinfo.BattleMode.MULTI_MODE
|
||||||
c.Fightinfo.Status = fightinfo.BattleMode.FIGHT_WITH_NPC
|
c.Fightinfo.Status = fightinfo.BattleMode.FIGHT_WITH_NPC
|
||||||
monsterInfo := &model.PlayerInfo{}
|
|
||||||
var boss []configmodel.BaseTowerConfig
|
|
||||||
|
|
||||||
result = &fight.S2C_ChoiceLevelRequestInfo{}
|
|
||||||
switch data.Head.CMD {
|
|
||||||
case 2429: //试炼之塔
|
|
||||||
boss = service.NewTower600Service().Boss(c.Info.CurrentFreshStage, c.Info.CurrentFreshStage+1)
|
|
||||||
|
|
||||||
result.CurFightLevel = uint32(c.Info.CurrentFreshStage)
|
|
||||||
case 2415: //勇者之塔
|
|
||||||
boss = service.NewTower500Service().Boss(c.Info.CurrentStage, c.Info.CurrentStage+1)
|
|
||||||
|
|
||||||
result.CurFightLevel = uint32(c.Info.CurrentStage)
|
|
||||||
case 2425:
|
|
||||||
boss = service.NewTower110Service().Boss(c.CurDark)
|
|
||||||
|
|
||||||
}
|
|
||||||
if len(boss) > 1 {
|
|
||||||
r := service.NewBossService().Get(boss[1].BossIds[0])
|
|
||||||
for _, v := range r {
|
|
||||||
result.BossID = append(result.BossID, uint32(v.MonID))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bosss := service.NewBossService().Get(boss[0].BossIds[0])
|
|
||||||
monsterInfo.Nick = boss[0].Name
|
|
||||||
for i, r := range bosss {
|
|
||||||
|
|
||||||
monster := model.GenPetInfo(int(r.MonID), 24, int(r.Nature), 0, int(r.Lv), nil, 0)
|
|
||||||
if r.Hp != 0 {
|
|
||||||
monster.Hp = uint32(r.Hp)
|
|
||||||
monster.MaxHp = uint32(r.Hp)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, v := range r.Prop {
|
|
||||||
if v != 0 {
|
|
||||||
monster.Prop[i] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.SKill) != 0 {
|
|
||||||
for i := 0; i < len(monster.SkillList); i++ {
|
|
||||||
if r.SKill[i] != 0 {
|
|
||||||
monster.SkillList[i].ID = r.SKill[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
effects := service.NewEffectService().Args(r.Effect)
|
|
||||||
|
|
||||||
for _, v := range effects {
|
|
||||||
monster.EffectInfo = append(monster.EffectInfo, model.PetEffectInfo{
|
|
||||||
Idx: uint16(v.SeIdx),
|
|
||||||
EID: gconv.Uint16(v.Eid),
|
|
||||||
Args: gconv.Ints(v.Args),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
monster.CatchTime = uint32(i)
|
|
||||||
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ai := player.NewAI_player(monsterInfo)
|
ai := player.NewAI_player(monsterInfo)
|
||||||
|
|
||||||
_, err = fight.NewFight(c, ai, c.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
_, err = fight.NewFight(c, ai, c.GetPetInfo(100), ai.GetPetInfo(0), func(foi model.FightOverInfo) {
|
||||||
|
if foi.Reason != 0 || foi.WinnerId != c.Info.UserID {
|
||||||
if foi.Reason == 0 && foi.WinnerId == c.Info.UserID { //我放获胜
|
return
|
||||||
switch data.Head.CMD {
|
|
||||||
case 2429: //试炼之塔
|
|
||||||
c.TawerCompletedTask(600, int(c.Info.CurrentFreshStage))
|
|
||||||
c.Info.CurrentFreshStage++
|
|
||||||
if c.Info.CurrentFreshStage >= c.Info.MaxFreshStage {
|
|
||||||
c.Info.MaxFreshStage = c.Info.CurrentFreshStage
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2415: //勇者之塔
|
|
||||||
c.TawerCompletedTask(500, int(c.Info.CurrentStage))
|
|
||||||
c.Info.CurrentStage++
|
|
||||||
if c.Info.CurrentStage >= c.Info.MaxStage {
|
|
||||||
c.Info.MaxStage = c.Info.CurrentStage
|
|
||||||
}
|
|
||||||
case 2425:
|
|
||||||
c.TawerCompletedTask(110, int(c.CurDark))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
handleTowerFightWin(c, data.Head.CMD, taskID, currentLevel)
|
||||||
}) ///开始对战,房主方以及被邀请方
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func towerChoiceRuntime(c *player.Player, cmd uint32) (towerChoiceState, bool) {
|
||||||
|
switch cmd {
|
||||||
|
case towerCmdChoiceTrial:
|
||||||
|
return towerChoiceState{
|
||||||
|
currentLevel: &c.Info.CurrentFreshStage,
|
||||||
|
maxLevel: &c.Info.MaxFreshStage,
|
||||||
|
service: service.NewTower600Service(),
|
||||||
|
}, true
|
||||||
|
case towerCmdChoiceBrave:
|
||||||
|
return towerChoiceState{
|
||||||
|
currentLevel: &c.Info.CurrentStage,
|
||||||
|
maxLevel: &c.Info.MaxStage,
|
||||||
|
service: service.NewTower500Service(),
|
||||||
|
}, true
|
||||||
|
default:
|
||||||
|
return towerChoiceState{}, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func towerFightBosses(c *player.Player, cmd uint32) ([]configmodel.BaseTowerConfig, uint32, int, bool) {
|
||||||
|
switch cmd {
|
||||||
|
case towerCmdFightTrial:
|
||||||
|
return service.NewTower600Service().Boss(c.Info.CurrentFreshStage, c.Info.CurrentFreshStage+1), c.Info.CurrentFreshStage, towerTaskTrial, true
|
||||||
|
case towerCmdFightBrave:
|
||||||
|
return service.NewTower500Service().Boss(c.Info.CurrentStage, c.Info.CurrentStage+1), c.Info.CurrentStage, towerTaskBrave, true
|
||||||
|
case towerCmdFightDark:
|
||||||
|
return service.NewTower110Service().Boss(c.CurDark), c.CurDark, towerTaskDark, true
|
||||||
|
default:
|
||||||
|
return nil, 0, 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func canSelectTowerLevel(targetLevel uint, maxLevel uint32) bool {
|
||||||
|
return targetLevel == 1 || targetLevel <= uint(maxLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstTowerBossConfig(bossList []configmodel.BaseTowerConfig) (configmodel.BaseTowerConfig, bool) {
|
||||||
|
if len(bossList) == 0 || len(bossList[0].BossIds) == 0 {
|
||||||
|
return configmodel.BaseTowerConfig{}, false
|
||||||
|
}
|
||||||
|
return bossList[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTowerBossPreview(dst *[]uint32, bossList []configmodel.BaseTowerConfig) {
|
||||||
|
bossConfig, ok := firstTowerBossConfig(bossList)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bosses := service.NewBossService().Get(bossConfig.BossIds[0])
|
||||||
|
for _, boss := range bosses {
|
||||||
|
*dst = append(*dst, uint32(boss.MonID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTowerNextBossPreview(dst *[]uint32, bossList []configmodel.BaseTowerConfig) {
|
||||||
|
if len(bossList) < 2 || len(bossList[1].BossIds) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bosses := service.NewBossService().Get(bossList[1].BossIds[0])
|
||||||
|
for _, boss := range bosses {
|
||||||
|
*dst = append(*dst, uint32(boss.MonID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTowerMonsterInfo(towerBoss configmodel.BaseTowerConfig) (*model.PlayerInfo, bool) {
|
||||||
|
bosses := service.NewBossService().Get(towerBoss.BossIds[0])
|
||||||
|
if len(bosses) == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
monsterInfo := &model.PlayerInfo{Nick: towerBoss.Name}
|
||||||
|
for i, boss := range bosses {
|
||||||
|
monster := model.GenPetInfo(int(boss.MonID), 24, int(boss.Nature), 0, int(boss.Lv), nil, 0)
|
||||||
|
if boss.Hp != 0 {
|
||||||
|
monster.Hp = uint32(boss.Hp)
|
||||||
|
monster.MaxHp = uint32(boss.Hp)
|
||||||
|
}
|
||||||
|
|
||||||
|
for statIdx, prop := range boss.Prop {
|
||||||
|
if prop != 0 {
|
||||||
|
monster.Prop[statIdx] = prop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for skillIdx := 0; skillIdx < len(monster.SkillList) && skillIdx < len(boss.SKill); skillIdx++ {
|
||||||
|
if boss.SKill[skillIdx] != 0 {
|
||||||
|
monster.SkillList[skillIdx].ID = boss.SKill[skillIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
effects := service.NewEffectService().Args(boss.Effect)
|
||||||
|
for _, effect := range effects {
|
||||||
|
monster.EffectInfo = append(monster.EffectInfo, model.PetEffectInfo{
|
||||||
|
Idx: uint16(effect.SeIdx),
|
||||||
|
EID: gconv.Uint16(effect.Eid),
|
||||||
|
Args: gconv.Ints(effect.Args),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
monster.CatchTime = uint32(i)
|
||||||
|
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
|
||||||
|
}
|
||||||
|
|
||||||
|
return monsterInfo, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTowerFightWin(c *player.Player, cmd uint32, taskID int, currentLevel uint32) {
|
||||||
|
c.TawerCompletedTask(taskID, int(currentLevel))
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case towerCmdFightTrial:
|
||||||
|
c.Info.CurrentFreshStage++
|
||||||
|
if c.Info.CurrentFreshStage >= c.Info.MaxFreshStage {
|
||||||
|
c.Info.MaxFreshStage = c.Info.CurrentFreshStage
|
||||||
|
}
|
||||||
|
case towerCmdFightBrave:
|
||||||
|
c.Info.CurrentStage++
|
||||||
|
if c.Info.CurrentStage >= c.Info.MaxStage {
|
||||||
|
c.Info.MaxStage = c.Info.CurrentStage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/common/data/xmlres"
|
|
||||||
"blazing/common/socket/errorcode"
|
"blazing/common/socket/errorcode"
|
||||||
"blazing/modules/config/service"
|
"blazing/modules/config/service"
|
||||||
|
|
||||||
@@ -12,73 +11,34 @@ import (
|
|||||||
// 防止封包通过领取来获取道具
|
// 防止封包通过领取来获取道具
|
||||||
|
|
||||||
// BuyItem 购买单个道具
|
// BuyItem 购买单个道具
|
||||||
// data: 包含购买道具信息的输入数据
|
|
||||||
// player: 当前玩家对象
|
|
||||||
// 返回: 购买结果和错误码
|
|
||||||
func (h Controller) BuyItem(data *item.BuyInboundInfo, player *player.Player) (result *item.BuyOutboundInfo, err errorcode.ErrorCode) {
|
func (h Controller) BuyItem(data *item.BuyInboundInfo, player *player.Player) (result *item.BuyOutboundInfo, err errorcode.ErrorCode) {
|
||||||
itemInfo, exists := xmlres.ItemsMAP[int(data.ItemId)]
|
result = &item.BuyOutboundInfo{Coins: player.Info.Coins}
|
||||||
if !exists {
|
|
||||||
return &item.BuyOutboundInfo{Coins: player.Info.Coins}, 0
|
bought, err := buySeerdouBackpackItem(player, data.ItemId, data.Count)
|
||||||
|
if err != 0 {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
if !bought {
|
||||||
|
result.Coins = player.Info.Coins
|
||||||
|
return result, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 免费道具直接添加
|
result.ItemId = data.ItemId
|
||||||
if itemInfo.Price == 0 {
|
result.Level = 1
|
||||||
if player.ItemAdd(data.ItemId, data.Count) {
|
result.Count = data.Count
|
||||||
return &item.BuyOutboundInfo{
|
result.Coins = player.Info.Coins
|
||||||
ItemId: data.ItemId,
|
return result, 0
|
||||||
Level: 1,
|
|
||||||
Count: data.Count,
|
|
||||||
Coins: player.Info.Coins,
|
|
||||||
}, 0
|
|
||||||
}
|
|
||||||
return &item.BuyOutboundInfo{Coins: player.Info.Coins}, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 需要付费的道具
|
|
||||||
totalCost := int64(data.Count) * int64(itemInfo.Price)
|
|
||||||
if !player.GetCoins(totalCost) {
|
|
||||||
return &item.BuyOutboundInfo{Coins: player.Info.Coins}, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
|
||||||
}
|
|
||||||
|
|
||||||
if player.ItemAdd(data.ItemId, data.Count) {
|
|
||||||
player.Info.Coins -= totalCost
|
|
||||||
return &item.BuyOutboundInfo{
|
|
||||||
ItemId: data.ItemId,
|
|
||||||
Level: 1,
|
|
||||||
Count: data.Count,
|
|
||||||
Coins: player.Info.Coins,
|
|
||||||
}, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 购买失败,返还赛尔豆
|
|
||||||
player.Info.Coins += totalCost
|
|
||||||
return &item.BuyOutboundInfo{Coins: player.Info.Coins}, 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuyMultipleItems 批量购买道具
|
// BuyMultipleItems 批量购买道具
|
||||||
// data: 包含批量购买道具信息的输入数据
|
|
||||||
// player: 当前玩家对象
|
|
||||||
// 返回: 批量购买结果和错误码
|
|
||||||
func (h Controller) BuyMultipleItems(data *item.BuyMultiInboundInfo, player *player.Player) (result *item.BuyMultiOutboundInfo, err errorcode.ErrorCode) {
|
func (h Controller) BuyMultipleItems(data *item.BuyMultiInboundInfo, player *player.Player) (result *item.BuyMultiOutboundInfo, err errorcode.ErrorCode) {
|
||||||
for _, itemID := range data.ItemIds {
|
for _, itemID := range data.ItemIds {
|
||||||
itemInfo, exists := xmlres.ItemsMAP[int(itemID)]
|
bought, buyErr := buySeerdouBackpackItem(player, int64(itemID), 1)
|
||||||
if !exists {
|
if buyErr == errorcode.ErrorCodes.ErrSunDouInsufficient10016 {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 免费道具直接添加
|
|
||||||
if itemInfo.Price == 0 {
|
|
||||||
player.ItemAdd(int64(itemID), 1)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 需要付费的道具
|
|
||||||
if !player.GetCoins(int64(itemInfo.Price)) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if buyErr != 0 || !bought {
|
||||||
if player.ItemAdd(int64(itemID), 1) {
|
continue
|
||||||
player.Info.Coins -= int64(itemInfo.Price)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,11 +48,7 @@ func (h Controller) BuyMultipleItems(data *item.BuyMultiInboundInfo, player *pla
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuyGoldItem 使用金豆购买商品
|
// BuyGoldItem 使用金豆购买商品
|
||||||
// data: 包含金豆购买商品信息的输入数据
|
|
||||||
// player: 当前玩家对象
|
|
||||||
// 返回: 金豆购买结果和错误码
|
|
||||||
func (h Controller) BuyGoldItem(data *item.C2S_GOLD_BUY_PRODUCT, player *player.Player) (result *item.S2C_GoldBuyProductInfo, err errorcode.ErrorCode) {
|
func (h Controller) BuyGoldItem(data *item.C2S_GOLD_BUY_PRODUCT, player *player.Player) (result *item.S2C_GoldBuyProductInfo, err errorcode.ErrorCode) {
|
||||||
//product, exists := xmlres.GoldProductMap[int(data.ProductID)]
|
|
||||||
pro := service.NewShopService().Get(data.ProductID)
|
pro := service.NewShopService().Get(data.ProductID)
|
||||||
if pro == nil {
|
if pro == nil {
|
||||||
return nil, errorcode.ErrorCodes.ErrTooManyProducts
|
return nil, errorcode.ErrorCodes.ErrTooManyProducts
|
||||||
@@ -105,15 +61,6 @@ func (h Controller) BuyGoldItem(data *item.C2S_GOLD_BUY_PRODUCT, player *player.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if pro.QuotaType != 0 {
|
|
||||||
// if data.Count > int64(pro.QuotaLimit) {
|
|
||||||
// return nil, errorcode.ErrorCodes.ErrExceedStock
|
|
||||||
// }
|
|
||||||
// if player.Service.Talk.Cheak(0, int(data.ProductID)) {
|
|
||||||
// return nil, errorcode.ErrorCodes.ErrExceedStock
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
var usegold uint64
|
var usegold uint64
|
||||||
|
|
||||||
switch data.Type {
|
switch data.Type {
|
||||||
@@ -136,12 +83,10 @@ func (h Controller) BuyGoldItem(data *item.C2S_GOLD_BUY_PRODUCT, player *player.
|
|||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||||
}
|
}
|
||||||
usegold = uint64(data.Count) * uint64(pro.JindouPrice*100)
|
usegold = uint64(data.Count) * uint64(pro.JindouPrice*100)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch data.Type {
|
switch data.Type {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
if player.ItemAdd(pro.ProductID, data.Count) {
|
if player.ItemAdd(pro.ProductID, data.Count) {
|
||||||
player.Info.Coins -= int64(usegold)
|
player.Info.Coins -= int64(usegold)
|
||||||
}
|
}
|
||||||
@@ -157,9 +102,6 @@ func (h Controller) BuyGoldItem(data *item.C2S_GOLD_BUY_PRODUCT, player *player.
|
|||||||
if player.ItemAdd(pro.ProductID, data.Count) {
|
if player.ItemAdd(pro.ProductID, data.Count) {
|
||||||
player.User.UpdateGold(player.Info.UserID, -int64(usegold))
|
player.User.UpdateGold(player.Info.UserID, -int64(usegold))
|
||||||
}
|
}
|
||||||
|
|
||||||
//购买成功,执行记录
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player.SendPackCmd(1105, item.GoldOnlineRemainOutboundInfo{
|
player.SendPackCmd(1105, item.GoldOnlineRemainOutboundInfo{
|
||||||
|
|||||||
@@ -22,16 +22,8 @@ const (
|
|||||||
// c: 当前玩家对象
|
// c: 当前玩家对象
|
||||||
// 返回: 道具列表和错误码
|
// 返回: 道具列表和错误码
|
||||||
func (h Controller) GetUserItemList(data *item.ItemListInboundInfo, c *player.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
|
func (h Controller) GetUserItemList(data *item.ItemListInboundInfo, c *player.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
|
||||||
result = &item.ItemListOutboundInfo{}
|
result = &item.ItemListOutboundInfo{
|
||||||
|
ItemList: c.Service.Item.GetUserItemList(data.Param1, data.Param2, ItemDefaultLeftTime),
|
||||||
items := c.Service.Item.Get(data.Param1, data.Param2)
|
|
||||||
result.ItemList = make([]model.SingleItemInfo, len(items))
|
|
||||||
for i, itemData := range items {
|
|
||||||
result.ItemList[i] = model.SingleItemInfo{
|
|
||||||
ItemId: itemData.ItemId,
|
|
||||||
ItemCnt: uint32(itemData.ItemCnt),
|
|
||||||
LeftTime: ItemDefaultLeftTime,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result, 0
|
return result, 0
|
||||||
}
|
}
|
||||||
@@ -48,7 +40,7 @@ func (h Controller) UsePetItemOutOfFight(data *item.C2S_USE_PET_ITEM_OUT_OF_FIGH
|
|||||||
|
|
||||||
itemID := uint32(data.ItemID)
|
itemID := uint32(data.ItemID)
|
||||||
if c.Service.Item.CheakItem(itemID) == 0 {
|
if c.Service.Item.CheakItem(itemID) == 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
}
|
}
|
||||||
|
|
||||||
itemCfg, ok := xmlres.ItemsMAP[int(itemID)]
|
itemCfg, ok := xmlres.ItemsMAP[int(itemID)]
|
||||||
@@ -195,7 +187,7 @@ func (h Controller) ResetNature(data *item.C2S_PET_RESET_NATURE, c *player.Playe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.Service.Item.CheakItem(data.ItemId) <= 0 {
|
if c.Service.Item.CheakItem(data.ItemId) <= 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
}
|
}
|
||||||
|
|
||||||
currentHP := currentPet.Hp
|
currentHP := currentPet.Hp
|
||||||
@@ -218,7 +210,7 @@ func (h Controller) UseSpeedupItem(data *item.C2S_USE_SPEEDUP_ITEM, c *player.Pl
|
|||||||
// 1. 校验道具是否存在且数量充足
|
// 1. 校验道具是否存在且数量充足
|
||||||
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
||||||
if itemCount <= 0 {
|
if itemCount <= 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError // 道具不足复用系统错误码(可根据需求改为专属错误码)
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
}
|
}
|
||||||
|
|
||||||
result = &item.S2C_USE_SPEEDUP_ITEM{}
|
result = &item.S2C_USE_SPEEDUP_ITEM{}
|
||||||
@@ -275,7 +267,7 @@ func (h Controller) UseEnergyXishou(data *item.C2S_USE_ENERGY_XISHOU, c *player.
|
|||||||
// 1. 校验道具是否存在且数量充足
|
// 1. 校验道具是否存在且数量充足
|
||||||
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
||||||
if itemCount <= 0 {
|
if itemCount <= 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
}
|
}
|
||||||
if c.Info.EnergyTime != 0 {
|
if c.Info.EnergyTime != 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrItemInUse
|
return nil, errorcode.ErrorCodes.ErrItemInUse
|
||||||
@@ -311,7 +303,7 @@ func (h Controller) UseAutoFightItem(data *item.C2S_USE_AUTO_FIGHT_ITEM, c *play
|
|||||||
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
itemCount := c.Service.Item.CheakItem(data.ItemID)
|
||||||
|
|
||||||
if itemCount <= 0 {
|
if itemCount <= 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
return nil, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
}
|
}
|
||||||
if c.Info.AutoFightTime != 0 {
|
if c.Info.AutoFightTime != 0 {
|
||||||
return nil, errorcode.ErrorCodes.ErrItemInUse
|
return nil, errorcode.ErrorCodes.ErrItemInUse
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
// var sg singleflight.Group
|
|
||||||
|
|
||||||
// var ServerList []rpc.ServerInfo
|
|
||||||
|
|
||||||
// func fetchData() (any, error) {
|
|
||||||
// ServerList = rpc.GetServerInfoList() //todo 待修改增加缓存
|
|
||||||
// return ServerList, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// GetServerOnline 处理命令: 105
|
|
||||||
// func (h Controller) GetServerOnline(data *user.SidInfo, c gnet.Conn) (result *rpc.CommendSvrInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
|
||||||
// result = rpc.NewInInfo()
|
|
||||||
// // tt, _ := cool.CacheManager.Keys(context.Background())
|
|
||||||
// //g.Dump(tt)
|
|
||||||
// t1 := hex.EncodeToString(data.Sid)
|
|
||||||
// userid, ok := playerservice.User.Load(t1)
|
|
||||||
// if !ok || userid != data.Head.UserID {
|
|
||||||
|
|
||||||
// defer c.Close()
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// result.IsVip = 1
|
|
||||||
// result.ServerList = rpc.GetServerInfoList(service.NewBaseSysUserService().GetPerson(data.Head.UserID).Debug)
|
|
||||||
// ser := playerservice.NewUserService(data.Head.UserID)
|
|
||||||
// f, b := ser.Friend.Get()
|
|
||||||
// for _, v := range f {
|
|
||||||
// result.FriendInfo = append(result.FriendInfo, rpc.FriendInfo{Userid: v, TimePoke: 1})
|
|
||||||
// }
|
|
||||||
// result.BlackInfo = b
|
|
||||||
// defer func() {
|
|
||||||
|
|
||||||
// // share.ShareManager.DeleteSession(t1)
|
|
||||||
|
|
||||||
// kickErr := ser.Info.Kick(data.Head.UserID)
|
|
||||||
// if kickErr != nil {
|
|
||||||
// fmt.Println("踢人失败", kickErr)
|
|
||||||
|
|
||||||
// }
|
|
||||||
// logininfo := ser.Info.SetLogin()
|
|
||||||
// if logininfo != nil {
|
|
||||||
// cool.CacheManager.Set(context.TODO(), fmt.Sprintf("player:%d", data.Head.UserID), logininfo, 0)
|
|
||||||
// cool.CacheManager.Set(context.Background(), fmt.Sprintf("session:%d", data.Head.UserID), t1, 0)
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }()
|
|
||||||
|
|
||||||
// return
|
|
||||||
|
|
||||||
// //return //TODO 这里待实现改成接口调用Ret方法
|
|
||||||
// }
|
|
||||||
@@ -4,20 +4,25 @@ import (
|
|||||||
"blazing/common/socket/errorcode"
|
"blazing/common/socket/errorcode"
|
||||||
"blazing/logic/service/nono"
|
"blazing/logic/service/nono"
|
||||||
"blazing/logic/service/player"
|
"blazing/logic/service/player"
|
||||||
|
)
|
||||||
|
|
||||||
"github.com/jinzhu/copier"
|
const (
|
||||||
|
nonoFuncValue = 255
|
||||||
|
nonoDefaultNum = 1
|
||||||
|
nonoDefaultPower = 0
|
||||||
|
nonoDefaultLevel = 12
|
||||||
|
nonoPetCureCost int64 = 50
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h Controller) NonoFollowOrHome(data *nono.NonoFollowOrHomeInInfo, c *player.Player) (result *nono.NonoFollowOutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
func (h Controller) NonoFollowOrHome(data *nono.NonoFollowOrHomeInInfo, c *player.Player) (result *nono.NonoFollowOutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
c.Info.NONO.Flag = data.Flag
|
c.Info.NONO.Flag = data.Flag
|
||||||
result = &nono.NonoFollowOutInfo{
|
result = &nono.NonoFollowOutInfo{
|
||||||
|
|
||||||
UserID: data.Head.UserID,
|
UserID: data.Head.UserID,
|
||||||
SuperStage: data.Flag,
|
SuperStage: data.Flag,
|
||||||
Flag: data.Flag,
|
Flag: data.Flag,
|
||||||
Nick: "",
|
Nick: "",
|
||||||
Color: c.Info.NONO.NonoColor,
|
Color: c.Info.NONO.NonoColor,
|
||||||
Power: 0,
|
Power: nonoDefaultPower,
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -25,22 +30,26 @@ func (h Controller) NonoFollowOrHome(data *nono.NonoFollowOrHomeInInfo, c *playe
|
|||||||
|
|
||||||
// GetNonoInfo 获取nono信息
|
// GetNonoInfo 获取nono信息
|
||||||
func (h *Controller) GetNonoInfo(data *nono.NonoInboundInfo, c *player.Player) (result *nono.NonoOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
func (h *Controller) GetNonoInfo(data *nono.NonoInboundInfo, c *player.Player) (result *nono.NonoOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
|
_ = data
|
||||||
|
|
||||||
result = &nono.NonoOutboundInfo{}
|
result = &nono.NonoOutboundInfo{
|
||||||
copier.Copy(result, &c.Info.NONO)
|
UserID: c.Info.UserID,
|
||||||
result.UserID = c.Info.UserID
|
Nick: c.Info.NONO.Nick,
|
||||||
|
SuperNono: nonoDefaultNum,
|
||||||
for i := 0; i < 20; i++ {
|
Color: c.Info.NONO.NonoColor,
|
||||||
result.Func[i] = 255
|
Num: nonoDefaultNum,
|
||||||
|
SuperLevel: nonoDefaultLevel,
|
||||||
|
SuperStage: c.Info.NONO.Flag,
|
||||||
|
Power: nonoDefaultPower,
|
||||||
|
SuperEnergy: nonoDefaultPower,
|
||||||
|
}
|
||||||
|
for i := range result.Func {
|
||||||
|
result.Func[i] = nonoFuncValue
|
||||||
}
|
}
|
||||||
result.Num = 1
|
|
||||||
result.SuperNono = 1
|
|
||||||
result.SuperLevel = 12
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Controller) SwitchFlying(data *nono.SwitchFlyingInboundInfo, c *player.Player) (result *nono.SwitchFlyingOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
func (h *Controller) SwitchFlying(data *nono.SwitchFlyingInboundInfo, c *player.Player) (result *nono.SwitchFlyingOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
|
|
||||||
result = &nono.SwitchFlyingOutboundInfo{
|
result = &nono.SwitchFlyingOutboundInfo{
|
||||||
UserId: data.Head.UserID,
|
UserId: data.Head.UserID,
|
||||||
Type: data.Type,
|
Type: data.Type,
|
||||||
@@ -51,16 +60,16 @@ func (h *Controller) SwitchFlying(data *nono.SwitchFlyingInboundInfo, c *player.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Controller) PlayerPetCure(data *nono.PetCureInboundInfo, c *player.Player) (result *nono.PetCureOutboundEmpty, err errorcode.ErrorCode) { //这个时候player应该是空的
|
func (h *Controller) PlayerPetCure(data *nono.PetCureInboundInfo, c *player.Player) (result *nono.PetCureOutboundEmpty, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
|
_ = data
|
||||||
if c.GetSpace().Owner.UserID == c.Info.UserID {
|
if c.GetSpace().Owner.UserID == c.Info.UserID {
|
||||||
return result, errorcode.ErrorCodes.ErrChampionCannotHeal
|
return result, errorcode.ErrorCodes.ErrChampionCannotHeal
|
||||||
}
|
}
|
||||||
if !c.GetCoins(50) {
|
if !c.GetCoins(nonoPetCureCost) {
|
||||||
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
||||||
}
|
}
|
||||||
for i := 0; i < len(c.Info.PetList); i++ {
|
for i := range c.Info.PetList {
|
||||||
c.Info.PetList[i].Cure()
|
c.Info.PetList[i].Cure()
|
||||||
|
|
||||||
}
|
}
|
||||||
c.Info.Coins -= 50
|
c.Info.Coins -= nonoPetCureCost
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,34 +18,34 @@ func (h Controller) PetELV(data *C2S_PET_EVOLVTION, c *player.Player) (result *f
|
|||||||
return nil, errorcode.ErrorCodes.Err10401
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
}
|
}
|
||||||
|
|
||||||
flag := xmlres.PetMAP[int(currentPet.ID)].EvolvFlag
|
petCfg, ok := xmlres.PetMAP[int(currentPet.ID)]
|
||||||
|
if !ok || petCfg.EvolvFlag == 0 {
|
||||||
if flag == 0 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotEvolveReady
|
return nil, errorcode.ErrorCodes.ErrPokemonNotEvolveReady
|
||||||
}
|
}
|
||||||
if xmlres.PetMAP[int(currentPet.ID)].EvolvingLv > int(currentPet.Level) {
|
if petCfg.EvolvingLv > int(currentPet.Level) {
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotEvolveReady
|
return nil, errorcode.ErrorCodes.ErrPokemonNotEvolveReady
|
||||||
}
|
}
|
||||||
evinfo := xmlres.EVOLVMAP[flag].Branches[data.Index-1]
|
|
||||||
|
|
||||||
if c.Service.Item.CheakItem(uint32(evinfo.EvolvItem)) < int64(evinfo.EvolvItemCount) {
|
evolveCfg, ok := xmlres.EVOLVMAP[petCfg.EvolvFlag]
|
||||||
|
if !ok || data.Index == 0 || int(data.Index) > len(evolveCfg.Branches) {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotEvolveReady
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := evolveCfg.Branches[data.Index-1]
|
||||||
|
if branch.EvolvItem != 0 && c.Service.Item.CheakItem(uint32(branch.EvolvItem)) < int64(branch.EvolvItemCount) {
|
||||||
return nil, errorcode.ErrorCodes.ErrInsufficientItemsMulti
|
return nil, errorcode.ErrorCodes.ErrInsufficientItemsMulti
|
||||||
}
|
}
|
||||||
if evinfo.EvolvItem != 0 {
|
if branch.EvolvItem != 0 {
|
||||||
c.Service.Item.UPDATE(uint32(evinfo.EvolvItem), -evinfo.EvolvItemCount)
|
c.Service.Item.UPDATE(uint32(branch.EvolvItem), -branch.EvolvItemCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPet.ID = uint32(xmlres.EVOLVMAP[flag].Branches[data.Index-1].MonTo)
|
currentPet.ID = uint32(branch.MonTo)
|
||||||
currentPet.Update(true)
|
currentPet.Update(true)
|
||||||
currentPet.CalculatePetPane(100)
|
currentPet.CalculatePetPane(100)
|
||||||
|
|
||||||
currentPet.Update(true)
|
|
||||||
updateOutbound := &info.PetUpdateOutboundInfo{}
|
updateOutbound := &info.PetUpdateOutboundInfo{}
|
||||||
|
|
||||||
var petUpdateInfo info.UpdatePropInfo
|
var petUpdateInfo info.UpdatePropInfo
|
||||||
|
|
||||||
copier.Copy(&petUpdateInfo, currentPet)
|
copier.Copy(&petUpdateInfo, currentPet)
|
||||||
|
|
||||||
updateOutbound.Data = append(updateOutbound.Data, petUpdateInfo)
|
updateOutbound.Data = append(updateOutbound.Data, petUpdateInfo)
|
||||||
c.SendPackCmd(2508, updateOutbound) //准备包由各自发,因为协议不一样
|
c.SendPackCmd(2508, updateOutbound) //准备包由各自发,因为协议不一样
|
||||||
return nil, -1
|
return nil, -1
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ import (
|
|||||||
"blazing/logic/service/common"
|
"blazing/logic/service/common"
|
||||||
"blazing/logic/service/fight"
|
"blazing/logic/service/fight"
|
||||||
"blazing/logic/service/player"
|
"blazing/logic/service/player"
|
||||||
|
)
|
||||||
|
|
||||||
"github.com/samber/lo"
|
const (
|
||||||
|
petEVMaxTotal uint32 = 510
|
||||||
|
petEVMaxSingle uint32 = 255
|
||||||
)
|
)
|
||||||
|
|
||||||
// PetEVDiy 自定义分配宠物努力值(EV)
|
// PetEVDiy 自定义分配宠物努力值(EV)
|
||||||
@@ -18,30 +21,39 @@ func (h Controller) PetEVDiy(data *PetEV, c *player.Player) (result *fight.NullO
|
|||||||
if !found {
|
if !found {
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
}
|
}
|
||||||
// 分配超过510的数据
|
|
||||||
if lo.Sum(data.EVs[:]) > 510 {
|
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var targetTotal uint32
|
||||||
|
var currentTotal uint32
|
||||||
for i, evValue := range data.EVs {
|
for i, evValue := range data.EVs {
|
||||||
// 分配超过255的数据
|
currentEV := currentPet.Ev[i]
|
||||||
if evValue > 255 {
|
|
||||||
|
// 单项分配不能超过上限。
|
||||||
|
if evValue > petEVMaxSingle {
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
}
|
}
|
||||||
// 分配比之前点数少的
|
|
||||||
if evValue < currentPet.Ev[i] {
|
targetTotal += evValue
|
||||||
|
if targetTotal > petEVMaxTotal {
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if lo.Sum(data.EVs[:]) < lo.Sum(currentPet.Ev[:]) {
|
// 不允许回退已分配的努力值。
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
if evValue < currentEV {
|
||||||
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
|
}
|
||||||
|
currentTotal += currentEV
|
||||||
}
|
}
|
||||||
|
|
||||||
usedEV := lo.Sum(data.EVs[:]) - lo.Sum(currentPet.Ev[:])
|
usedEV := targetTotal - currentTotal
|
||||||
// 加的比池子还多
|
if usedEV == 0 {
|
||||||
|
return result, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增分配不能超过玩家累计学习力池。
|
||||||
if int64(usedEV) > c.Info.EVPool {
|
if int64(usedEV) > c.Info.EVPool {
|
||||||
return nil, errorcode.ErrorCodes.Err10401
|
return nil, errorcode.ErrorCodes.Err10401
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPet.Ev = data.EVs
|
currentPet.Ev = data.EVs
|
||||||
currentPet.CalculatePetPane(100)
|
currentPet.CalculatePetPane(100)
|
||||||
c.Info.EVPool -= int64(usedEV)
|
c.Info.EVPool -= int64(usedEV)
|
||||||
|
|||||||
@@ -10,133 +10,159 @@ import (
|
|||||||
|
|
||||||
"github.com/alpacahq/alpacadecimal"
|
"github.com/alpacahq/alpacadecimal"
|
||||||
"github.com/gogf/gf/v2/util/grand"
|
"github.com/gogf/gf/v2/util/grand"
|
||||||
"github.com/samber/lo"
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
petFusionCost = 1000
|
||||||
|
petFusionKeepAuxItemID = 300043
|
||||||
|
petFusionFailureItemID = 300044
|
||||||
|
petFusionSoulID = 1000017
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h Controller) PetFusion(data *pet.C2S_PetFusion, c *player.Player) (result *pet.PetFusionInfo, err errorcode.ErrorCode) {
|
func (h Controller) PetFusion(data *pet.C2S_PetFusion, c *player.Player) (result *pet.PetFusionInfo, err errorcode.ErrorCode) {
|
||||||
if !c.GetCoins(1000) {
|
result = &pet.PetFusionInfo{
|
||||||
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
SoulID: petFusionSoulID,
|
||||||
}
|
}
|
||||||
c.Info.Coins -= 1000
|
|
||||||
// g.Dump(c.Info.PetList)
|
|
||||||
|
|
||||||
//防止同一只
|
|
||||||
if data.Mcatchtime == data.Auxcatchtime {
|
if data.Mcatchtime == data.Auxcatchtime {
|
||||||
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady
|
||||||
}
|
}
|
||||||
|
|
||||||
_, Mcatchpetinfo, ok := c.FindPet(data.Mcatchtime)
|
_, masterPet, ok := c.FindPet(data.Mcatchtime)
|
||||||
if !ok {
|
if !ok {
|
||||||
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
||||||
}
|
}
|
||||||
|
masterCfg, ok := xmlres.PetMAP[int(masterPet.ID)]
|
||||||
if xmlres.PetMAP[int(Mcatchpetinfo.ID)].FuseMaster == 0 {
|
if !ok || masterCfg.FuseMaster == 0 {
|
||||||
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
||||||
}
|
}
|
||||||
_, Auxpetinfo, ok := c.FindPet(data.Auxcatchtime)
|
|
||||||
|
_, auxPet, ok := c.FindPet(data.Auxcatchtime)
|
||||||
if !ok {
|
if !ok {
|
||||||
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
||||||
}
|
}
|
||||||
|
auxCfg, ok := xmlres.PetMAP[int(auxPet.ID)]
|
||||||
if xmlres.PetMAP[int(Auxpetinfo.ID)].FuseSub == 0 {
|
if !ok || auxCfg.FuseSub == 0 {
|
||||||
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
||||||
}
|
}
|
||||||
//println(len(c.Info.PetList), data.Mcatchtime, data.Auxcatchtime, Mcatchpetinfo.CatchTime, Auxpetinfo.CatchTime)
|
|
||||||
///性格生成
|
materialCounts := collectItemCounts(data.Item1[:])
|
||||||
var natureId int32 = -1
|
if !hasEnoughItems(c, materialCounts) {
|
||||||
if Auxpetinfo.Nature == Mcatchpetinfo.Nature {
|
return result, errorcode.ErrorCodes.ErrInsufficientItems
|
||||||
natureId = int32(Auxpetinfo.Nature)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range c.Service.Item.CheakItemM(data.Item1[:]...) {
|
materialService := service.NewPetFusionMaterialService()
|
||||||
|
effect := int(materialService.Data(data.Item1))
|
||||||
if v.ItemCnt <= 0 {
|
|
||||||
return result, errorcode.ErrorCodes.ErrInsufficientItems
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resid := int(service.NewPetFusionService().Data(Mcatchpetinfo.ID, Auxpetinfo.ID, Mcatchpetinfo.Level+Auxpetinfo.Level))
|
|
||||||
effect := int(service.NewPetFusionMaterialService().Data(data.Item1))
|
|
||||||
|
|
||||||
if effect == 0 {
|
if effect == 0 {
|
||||||
return result, errorcode.ErrorCodes.ErrSpiritOrbNotExists
|
return result, errorcode.ErrorCodes.ErrSpiritOrbNotExists
|
||||||
}
|
}
|
||||||
//c.Service.Item.UPDATEM(data.Item1[:], -1)
|
|
||||||
|
|
||||||
// utils.CountSliceElements(data.Item1[:])
|
fusionService := service.NewPetFusionService()
|
||||||
|
resultPetID := int(fusionService.Data(masterPet.ID, auxPet.ID, masterPet.Level+auxPet.Level))
|
||||||
for _, v := range data.Item1 {
|
|
||||||
err := c.Service.Item.UPDATE(v, -1)
|
|
||||||
if err != nil {
|
|
||||||
return result, errorcode.ErrorCodes.ErrInsufficientItems
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if !c.GetCoins(petFusionCost) {
|
||||||
|
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
||||||
}
|
}
|
||||||
result = &pet.PetFusionInfo{
|
|
||||||
|
|
||||||
SoulID: 1000017,
|
consumeItems(c, materialCounts)
|
||||||
|
c.Info.Coins -= petFusionCost
|
||||||
|
|
||||||
CostItemFlag: 0,
|
if resultPetID == 0 {
|
||||||
}
|
if useOptionalItem(c, data.GoldItem1[:], petFusionFailureItemID) {
|
||||||
if resid == 0 {
|
|
||||||
|
|
||||||
_, ok := lo.Find(data.GoldItem1[:], func(item uint32) bool {
|
|
||||||
return item == 300044
|
|
||||||
})
|
|
||||||
if c.Service.Item.CheakItem(300044) > 0 && ok {
|
|
||||||
c.Service.Item.UPDATE(300044, -1)
|
|
||||||
result.CostItemFlag = 1
|
result.CostItemFlag = 1
|
||||||
|
} else if auxPet.Level > 5 {
|
||||||
|
auxPet.Downgrade(auxPet.Level - 5)
|
||||||
} else {
|
} else {
|
||||||
if Auxpetinfo.Level > 5 {
|
auxPet.Downgrade(1)
|
||||||
// Auxpetinfo.Level = Auxpetinfo.Level - 5
|
|
||||||
Auxpetinfo.Downgrade(Auxpetinfo.Level - 5)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Auxpetinfo.Downgrade(1)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pet.PetFusionInfo{}, 0
|
return &pet.PetFusionInfo{}, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
dv1 := alpacadecimal.NewFromInt(2).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(Mcatchpetinfo.Dv)))
|
natureID := int32(-1)
|
||||||
dv2 := alpacadecimal.NewFromInt(1).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(Auxpetinfo.Dv)))
|
if auxPet.Nature == masterPet.Nature {
|
||||||
|
natureID = int32(auxPet.Nature)
|
||||||
|
}
|
||||||
|
|
||||||
|
dv1 := alpacadecimal.NewFromInt(2).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(masterPet.Dv)))
|
||||||
|
dv2 := alpacadecimal.NewFromInt(1).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(auxPet.Dv)))
|
||||||
dv := dv1.Add(dv2).Add(alpacadecimal.NewFromInt(1)).IntPart()
|
dv := dv1.Add(dv2).Add(alpacadecimal.NewFromInt(1)).IntPart()
|
||||||
r := model.GenPetInfo(resid, int(dv), int(natureId), effect, 1, nil, -1)
|
newPet := model.GenPetInfo(resultPetID, int(dv), int(natureID), effect, 1, nil, -1)
|
||||||
r.OldCatchTime = Mcatchpetinfo.CatchTime
|
newPet.OldCatchTime = masterPet.CatchTime
|
||||||
|
|
||||||
shinycont := 1
|
shinyChance := 1
|
||||||
if Mcatchpetinfo.IsShiny() || Auxpetinfo.IsShiny() {
|
if masterPet.IsShiny() || auxPet.IsShiny() {
|
||||||
shinycont = 50
|
shinyChance = 50
|
||||||
}
|
}
|
||||||
if Mcatchpetinfo.IsShiny() && Auxpetinfo.IsShiny() {
|
if masterPet.IsShiny() && auxPet.IsShiny() {
|
||||||
shinycont = 100
|
shinyChance = 100
|
||||||
|
}
|
||||||
|
if grand.Meet(shinyChance, 100) {
|
||||||
|
newPet.RandomByWeightShiny()
|
||||||
}
|
}
|
||||||
if grand.Meet(shinycont, 100) {
|
|
||||||
r.RandomByWeightShiny()
|
|
||||||
|
|
||||||
}
|
c.Service.Pet.PetAdd(newPet, 0)
|
||||||
c.Service.Pet.PetAdd(r, 0)
|
println(c.Info.UserID, "进行融合", len(c.Info.PetList), masterPet.ID, auxPet.ID, newPet.ID)
|
||||||
println(c.Info.UserID, "进行融合", len(c.Info.PetList), Mcatchpetinfo.ID, Auxpetinfo.ID, r.ID)
|
|
||||||
|
|
||||||
c.PetDel(data.Mcatchtime)
|
c.PetDel(data.Mcatchtime)
|
||||||
_, ok2 := lo.Find(data.GoldItem1[:], func(item uint32) bool {
|
if useOptionalItem(c, data.GoldItem1[:], petFusionKeepAuxItemID) {
|
||||||
return item == 300043
|
|
||||||
})
|
|
||||||
|
|
||||||
if c.Service.Item.CheakItem(300043) > 0 && ok2 {
|
|
||||||
c.Service.Item.UPDATE(300043, -1)
|
|
||||||
result.CostItemFlag = 1
|
result.CostItemFlag = 1
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
c.PetDel(data.Auxcatchtime)
|
c.PetDel(data.Auxcatchtime)
|
||||||
|
|
||||||
}
|
}
|
||||||
result.ObtainTime = r.CatchTime
|
|
||||||
result.StarterCpTm = r.ID
|
result.ObtainTime = newPet.CatchTime
|
||||||
//todo材料扣除
|
result.StarterCpTm = newPet.ID
|
||||||
return result, 0
|
return result, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func collectItemCounts(itemIDs []uint32) map[uint32]int {
|
||||||
|
counts := make(map[uint32]int, len(itemIDs))
|
||||||
|
for _, itemID := range itemIDs {
|
||||||
|
counts[itemID]++
|
||||||
|
}
|
||||||
|
return counts
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasEnoughItems(c *player.Player, itemCounts map[uint32]int) bool {
|
||||||
|
if len(itemCounts) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
itemIDs := make([]uint32, 0, len(itemCounts))
|
||||||
|
for itemID := range itemCounts {
|
||||||
|
itemIDs = append(itemIDs, itemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
hadItems := c.Service.Item.CheakItemM(itemIDs...)
|
||||||
|
ownedCounts := make(map[uint32]int64, len(hadItems))
|
||||||
|
for _, item := range hadItems {
|
||||||
|
ownedCounts[item.ItemId] = item.ItemCnt
|
||||||
|
}
|
||||||
|
|
||||||
|
for itemID, need := range itemCounts {
|
||||||
|
if ownedCounts[itemID] < int64(need) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func consumeItems(c *player.Player, itemCounts map[uint32]int) {
|
||||||
|
for itemID, count := range itemCounts {
|
||||||
|
_ = c.Service.Item.UPDATE(itemID, -count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func useOptionalItem(c *player.Player, itemIDs []uint32, target uint32) bool {
|
||||||
|
if c.Service.Item.CheakItem(target) <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, itemID := range itemIDs {
|
||||||
|
if itemID == target {
|
||||||
|
_ = c.Service.Item.UPDATE(target, -1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/util/grand"
|
"github.com/gogf/gf/v2/util/grand"
|
||||||
"github.com/samber/lo"
|
|
||||||
"github.com/yudeguang/ratelimit"
|
"github.com/yudeguang/ratelimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,40 +34,27 @@ func (ctl Controller) GetBreedInfo(
|
|||||||
// 前端到后端
|
// 前端到后端
|
||||||
func (ctl Controller) GetBreedPet(
|
func (ctl Controller) GetBreedPet(
|
||||||
data *pet.C2S_GET_BREED_PET, playerObj *player.Player) (result *pet.S2C_GET_BREED_PET, err errorcode.ErrorCode) { //这个时候player应该是空的
|
data *pet.C2S_GET_BREED_PET, playerObj *player.Player) (result *pet.S2C_GET_BREED_PET, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
_, fPet, found := playerObj.FindPet(data.MaleCatchTime)
|
_, malePet, found := playerObj.FindPet(data.MaleCatchTime)
|
||||||
if !found {
|
if !found || !canBreedPet(malePet, 1) {
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
if fPet.Gender != 1 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
if fPet.Generation > 9 {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
}
|
}
|
||||||
|
|
||||||
result = &pet.S2C_GET_BREED_PET{}
|
result = &pet.S2C_GET_BREED_PET{}
|
||||||
|
compatibleFemaleIDs := buildBreedPetIDSet(service.NewEggService().GetData(malePet.ID))
|
||||||
|
if len(compatibleFemaleIDs) == 0 {
|
||||||
|
return result, 0
|
||||||
|
}
|
||||||
|
|
||||||
MPETS := service.NewEggService().GetData(fPet.ID)
|
result.FemaleList = make([]uint32, 0, len(playerObj.Info.PetList))
|
||||||
|
for i := range playerObj.Info.PetList {
|
||||||
// 这里只是示例,实际应该根据雄性精灵的catchTime查找可繁殖的雌性精灵
|
femalePet := &playerObj.Info.PetList[i]
|
||||||
for _, v := range playerObj.Info.PetList {
|
if !canBreedPet(femalePet, 2) {
|
||||||
if v.Level < 50 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//不是雌性
|
if _, ok := compatibleFemaleIDs[femalePet.ID]; !ok {
|
||||||
if v.Gender != 2 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if v.Generation > 9 {
|
result.FemaleList = append(result.FemaleList, femalePet.CatchTime)
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, ok := lo.Find(MPETS, func(item int32) bool {
|
|
||||||
return item == int32(v.ID)
|
|
||||||
})
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// 如果是雌性精灵,且可以繁殖,则添加到列表
|
|
||||||
result.FemaleList = append(result.FemaleList, v.CatchTime)
|
|
||||||
}
|
}
|
||||||
return result, 0
|
return result, 0
|
||||||
|
|
||||||
@@ -78,34 +64,38 @@ func (ctl Controller) GetBreedPet(
|
|||||||
// 前端到后端
|
// 前端到后端
|
||||||
func (ctl Controller) StartBreed(
|
func (ctl Controller) StartBreed(
|
||||||
data *pet.C2S_START_BREED, player *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
data *pet.C2S_START_BREED, player *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
|
if data.Male == data.Female {
|
||||||
if !player.GetCoins(1000) {
|
|
||||||
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
|
||||||
}
|
|
||||||
player.Info.Coins -= 1000
|
|
||||||
_, MalePet, found := player.FindPet(data.Male)
|
|
||||||
if !found {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
_, Female, found := player.FindPet(data.Female)
|
|
||||||
if !found {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
|
||||||
}
|
|
||||||
// TODO: 实现开始繁殖的具体逻辑
|
|
||||||
result = &fight.NullOutboundInfo{}
|
|
||||||
r := player.Service.Egg.StartBreed(MalePet, Female)
|
|
||||||
if !r {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
|
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
|
||||||
}
|
}
|
||||||
MalePet.Generation++
|
|
||||||
|
|
||||||
Female.Generation++
|
_, malePet, found := player.FindPet(data.Male)
|
||||||
|
if !found || !canBreedPet(malePet, 1) {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
_, femalePet, found := player.FindPet(data.Female)
|
||||||
|
if !found || !canBreedPet(femalePet, 2) {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
|
||||||
|
}
|
||||||
|
if !canBreedPair(malePet.ID, femalePet.ID) {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
|
||||||
|
}
|
||||||
|
if !player.GetCoins(breedCost) {
|
||||||
|
return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
||||||
|
}
|
||||||
|
|
||||||
r1 := grand.Meet(1, 2)
|
result = &fight.NullOutboundInfo{}
|
||||||
if r1 {
|
if !player.Service.Egg.StartBreed(malePet, femalePet) {
|
||||||
MalePet.Gender = 0
|
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
|
||||||
|
}
|
||||||
|
|
||||||
|
player.Info.Coins -= breedCost
|
||||||
|
malePet.Generation++
|
||||||
|
femalePet.Generation++
|
||||||
|
|
||||||
|
if grand.Meet(1, 2) {
|
||||||
|
malePet.Gender = 0
|
||||||
} else {
|
} else {
|
||||||
Female.Gender = 0
|
femalePet.Gender = 0
|
||||||
}
|
}
|
||||||
return result, 0
|
return result, 0
|
||||||
|
|
||||||
@@ -113,6 +103,23 @@ func (ctl Controller) StartBreed(
|
|||||||
|
|
||||||
// GetEggList 获取精灵蛋数组
|
// GetEggList 获取精灵蛋数组
|
||||||
// 前端到后端无数据 请求协议
|
// 前端到后端无数据 请求协议
|
||||||
|
func canBreedPet(p *model.PetInfo, gender int) bool {
|
||||||
|
return p != nil && p.Level >= breedMinLevel && p.Gender == gender && p.Generation <= breedMaxGeneration
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBreedPetIDSet(ids []int32) map[uint32]struct{} {
|
||||||
|
ret := make(map[uint32]struct{}, len(ids))
|
||||||
|
for _, id := range ids {
|
||||||
|
ret[uint32(id)] = struct{}{}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func canBreedPair(maleID, femaleID uint32) bool {
|
||||||
|
_, ok := buildBreedPetIDSet(service.NewEggService().GetData(maleID))[femaleID]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
func (ctl Controller) GetEggList(
|
func (ctl Controller) GetEggList(
|
||||||
data *pet.C2S_GET_EGG_LIST, player *player.Player) (result *pet.S2C_GET_EGG_LIST, err errorcode.ErrorCode) { //这个时候player应该是空的
|
data *pet.C2S_GET_EGG_LIST, player *player.Player) (result *pet.S2C_GET_EGG_LIST, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||||
|
|
||||||
@@ -130,6 +137,12 @@ func (ctl Controller) GetEggList(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
breedMinLevel = 50
|
||||||
|
breedMaxGeneration = 9
|
||||||
|
breedCost = 1000
|
||||||
|
)
|
||||||
|
|
||||||
var limiter *ratelimit.Rule = ratelimit.NewRule()
|
var limiter *ratelimit.Rule = ratelimit.NewRule()
|
||||||
|
|
||||||
// 简单规则案例
|
// 简单规则案例
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/common/data/xmlres"
|
|
||||||
"blazing/common/socket/errorcode"
|
"blazing/common/socket/errorcode"
|
||||||
"blazing/logic/service/player"
|
"blazing/logic/service/player"
|
||||||
"blazing/logic/service/room"
|
"blazing/logic/service/room"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuyFitment 购买基地家具
|
// BuyFitment 购买基地家具
|
||||||
// data: 包含家具ID和购买数量的输入信息
|
|
||||||
// c: 当前玩家对象
|
|
||||||
// 返回: 购买结果和错误码
|
|
||||||
func (h Controller) BuyFitment(data *room.C2S_BUY_FITMENT, c *player.Player) (result *room.S2C_BUY_FITMENT, err errorcode.ErrorCode) {
|
func (h Controller) BuyFitment(data *room.C2S_BUY_FITMENT, c *player.Player) (result *room.S2C_BUY_FITMENT, err errorcode.ErrorCode) {
|
||||||
result = &room.S2C_BUY_FITMENT{}
|
result = &room.S2C_BUY_FITMENT{Coins: c.Info.Coins}
|
||||||
|
|
||||||
itemConfig := xmlres.ItemsMAP[int(data.ID)]
|
bought, err := buySeerdouBackpackItem(c, int64(data.ID), int64(data.Count))
|
||||||
totalCost := int64(itemConfig.Price) * int64(data.Count)
|
if err != 0 {
|
||||||
|
return nil, err
|
||||||
if !c.GetCoins((totalCost)) {
|
|
||||||
return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
|
||||||
}
|
}
|
||||||
c.Service.Item.UPDATE(data.ID, int(data.Count))
|
if !bought {
|
||||||
c.Info.Coins -= int64(totalCost)
|
result.Coins = c.Info.Coins
|
||||||
|
return result, 0
|
||||||
|
}
|
||||||
|
|
||||||
result.ID = data.ID
|
result.ID = data.ID
|
||||||
|
result.Count = data.Count
|
||||||
result.Coins = c.Info.Coins
|
result.Coins = c.Info.Coins
|
||||||
return
|
return result, 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,12 @@ import (
|
|||||||
func (h Controller) CDK(data *user.C2S_GET_GIFT_COMPLETE, player *player.Player) (result *user.S2C_GET_GIFT_COMPLETE, err errorcode.ErrorCode) {
|
func (h Controller) CDK(data *user.C2S_GET_GIFT_COMPLETE, player *player.Player) (result *user.S2C_GET_GIFT_COMPLETE, err errorcode.ErrorCode) {
|
||||||
result = &user.S2C_GET_GIFT_COMPLETE{}
|
result = &user.S2C_GET_GIFT_COMPLETE{}
|
||||||
|
|
||||||
r := service.NewCdkService().Get(data.PassText)
|
cdkService := service.NewCdkService()
|
||||||
|
rewardPetService := service.NewPetRewardService()
|
||||||
|
itemRewardService := service.NewItemService()
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
r := cdkService.Get(data.PassText)
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil, errorcode.ErrorCodes.ErrMolecularCodeNotExists
|
return nil, errorcode.ErrorCodes.ErrMolecularCodeNotExists
|
||||||
}
|
}
|
||||||
@@ -20,38 +25,36 @@ func (h Controller) CDK(data *user.C2S_GET_GIFT_COMPLETE, player *player.Player)
|
|||||||
return nil, errorcode.ErrorCodes.ErrMolecularCodeFrozen
|
return nil, errorcode.ErrorCodes.ErrMolecularCodeFrozen
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.ValidEndTime.Compare(time.Now()) == -1 {
|
if r.ValidEndTime.Compare(now) == -1 {
|
||||||
return nil, errorcode.ErrorCodes.ErrMolecularCodeExpired
|
return nil, errorcode.ErrorCodes.ErrMolecularCodeExpired
|
||||||
}
|
}
|
||||||
if !player.Service.Cdk.CanGet(uint32(r.ID)) {
|
if !player.Service.Cdk.CanGet(uint32(r.ID)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !service.NewCdkService().Set(data.PassText) {
|
if !cdkService.Set(data.PassText) {
|
||||||
return nil, errorcode.ErrorCodes.ErrMolecularCodeGiftsGone
|
return nil, errorcode.ErrorCodes.ErrMolecularCodeGiftsGone
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Flag = 1
|
result.Flag = 1
|
||||||
for _, v := range r.ElfRewardIds {
|
for _, rewardID := range r.ElfRewardIds {
|
||||||
pet := service.NewPetRewardService().Get(v)
|
pet := rewardPetService.Get(rewardID)
|
||||||
if pet != nil {
|
if pet == nil {
|
||||||
peti := model.GenPetInfo(int(pet.MonID), int(pet.DV), int(pet.Nature), int(pet.Effect), int(pet.Lv), nil, 0)
|
continue
|
||||||
player.Service.Pet.PetAdd(peti, 0)
|
|
||||||
result.PetGift = append(result.PetGift, user.PetGiftInfo{PetID: peti.ID, CacthTime: peti.CatchTime})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
petInfo := model.GenPetInfo(int(pet.MonID), int(pet.DV), int(pet.Nature), int(pet.Effect), int(pet.Lv), nil, 0)
|
||||||
|
player.Service.Pet.PetAdd(petInfo, 0)
|
||||||
|
result.PetGift = append(result.PetGift, user.PetGiftInfo{PetID: petInfo.ID, CacthTime: petInfo.CatchTime})
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, itemID := range r.ItemRewardIds {
|
for _, rewardID := range r.ItemRewardIds {
|
||||||
iteminfo := service.NewItemService().GetItemCount(itemID)
|
itemInfo := itemRewardService.GetItemCount(rewardID)
|
||||||
player.ItemAdd(iteminfo.ItemId, iteminfo.ItemCnt)
|
player.ItemAdd(itemInfo.ItemId, itemInfo.ItemCnt)
|
||||||
|
result.GiftList = append(result.GiftList, user.GiftInfo{GiftID: itemInfo.ItemId, Count: itemInfo.ItemCnt})
|
||||||
result.GiftList = append(result.GiftList, user.GiftInfo{GiftID: iteminfo.ItemId, Count: iteminfo.ItemCnt})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if r.TitleRewardIds != 0 {
|
if r.TitleRewardIds != 0 {
|
||||||
player.Service.Title.Give(r.TitleRewardIds)
|
player.Service.Title.Give(r.TitleRewardIds)
|
||||||
result.Tile = r.TitleRewardIds
|
result.Tile = r.TitleRewardIds
|
||||||
|
|
||||||
}
|
}
|
||||||
player.Service.Cdk.Log(uint32(r.ID))
|
player.Service.Cdk.Log(uint32(r.ID))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lunixbochs/struc"
|
"github.com/lunixbochs/struc"
|
||||||
"github.com/valyala/bytebufferpool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TomeeHeader 结构体字段定义
|
// TomeeHeader 结构体字段定义
|
||||||
@@ -17,9 +16,9 @@ type TomeeHeader struct {
|
|||||||
UserID uint32 `json:"userId"`
|
UserID uint32 `json:"userId"`
|
||||||
//Error uint32 `json:"error" struc:"skip"`
|
//Error uint32 `json:"error" struc:"skip"`
|
||||||
|
|
||||||
Result uint32 `json:"result"`
|
Result uint32 `json:"result"`
|
||||||
Data *bytebufferpool.ByteBuffer `json:"data" struc:"skip"` //组包忽略此字段// struc:"skip"
|
Data []byte `json:"data" struc:"skip"` //组包忽略此字段// struc:"skip"
|
||||||
Res []byte `struc:"skip"`
|
Res []byte `struc:"skip"`
|
||||||
//Return []byte `struc:"skip"` //返回记录
|
//Return []byte `struc:"skip"` //返回记录
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,22 +68,20 @@ type Effect796Sub struct {
|
|||||||
RoundEffectArg0Base
|
RoundEffectArg0Base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Effect796Sub) OnSkill() bool {
|
func (e *Effect796Sub) TurnEnd() {
|
||||||
if len(e.Args()) < 2 || e.Args()[1].Cmp(alpacadecimal.Zero) <= 0 {
|
if e.Ctx().Our.CurrentPet.Info.Hp > 0 && e.Ctx().Opp.CurrentPet.Info.Hp > 0 &&
|
||||||
return true
|
len(e.Args()) >= 2 && e.Args()[1].Cmp(alpacadecimal.Zero) > 0 {
|
||||||
|
damage := e.Ctx().Opp.CurrentPet.GetHP().Div(e.Args()[1])
|
||||||
|
if damage.Cmp(alpacadecimal.Zero) > 0 {
|
||||||
|
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
|
||||||
|
Type: info.DamageType.Percent,
|
||||||
|
Damage: damage,
|
||||||
|
})
|
||||||
|
e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, damage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
damage := e.Ctx().Opp.CurrentPet.GetHP().Div(e.Args()[1])
|
e.EffectNode.TurnEnd()
|
||||||
if damage.Cmp(alpacadecimal.Zero) <= 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
|
|
||||||
Type: info.DamageType.Percent,
|
|
||||||
Damage: damage,
|
|
||||||
})
|
|
||||||
e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, damage)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effect 797: 消除对手回合类效果,消除成功{0}回合内对手无法通过自身技能恢复体力
|
// Effect 797: 消除对手回合类效果,消除成功{0}回合内对手无法通过自身技能恢复体力
|
||||||
@@ -166,7 +164,7 @@ type Effect799 struct {
|
|||||||
node.EffectNode
|
node.EffectNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Effect799) OnSkill() bool {
|
func (e *Effect799) Skill_Use() bool {
|
||||||
if len(e.Args()) < 2 || e.Args()[0].Cmp(alpacadecimal.Zero) <= 0 {
|
if len(e.Args()) < 2 || e.Args()[0].Cmp(alpacadecimal.Zero) <= 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package effect
|
package effect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/logic/service/fight/action"
|
|
||||||
"blazing/logic/service/fight/info"
|
"blazing/logic/service/fight/info"
|
||||||
"blazing/logic/service/fight/input"
|
"blazing/logic/service/fight/input"
|
||||||
"blazing/logic/service/fight/node"
|
"blazing/logic/service/fight/node"
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/gogf/gf/v2/os/glog"
|
"github.com/gogf/gf/v2/os/glog"
|
||||||
"github.com/lunixbochs/struc"
|
"github.com/lunixbochs/struc"
|
||||||
"github.com/panjf2000/gnet/v2"
|
"github.com/panjf2000/gnet/v2"
|
||||||
"github.com/valyala/bytebufferpool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// getUnderlyingValue 递归解析reflect.Value,解包指针、interface{}到底层具体类型
|
// getUnderlyingValue 递归解析reflect.Value,解包指针、interface{}到底层具体类型
|
||||||
@@ -48,44 +47,73 @@ func getUnderlyingValue(val reflect.Value) (reflect.Value, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XORDecryptU 优化后的异或解密:减少内存分配,支持复用缓冲区
|
// XORDecryptU 原地执行异或解密,避免额外分配和拷贝。
|
||||||
// XORDecryptU 基于bytebufferpool优化的异或解密函数
|
|
||||||
// 保留原有接口,无侵入式优化,高频调用下大幅减少内存分配和GC
|
|
||||||
func XORDecryptU(encryptedData []byte, key uint32) []byte {
|
func XORDecryptU(encryptedData []byte, key uint32) []byte {
|
||||||
if len(encryptedData) == 0 {
|
if len(encryptedData) == 0 {
|
||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 栈上分配密钥字节数组(无GC压力,保留原优化)
|
|
||||||
var keyBytes [4]byte
|
var keyBytes [4]byte
|
||||||
binary.BigEndian.PutUint32(keyBytes[:], key)
|
binary.BigEndian.PutUint32(keyBytes[:], key)
|
||||||
keyLen := len(keyBytes)
|
keyLen := len(keyBytes)
|
||||||
|
|
||||||
// 2. 从bytebufferpool获取池化缓冲区(替代make分配)
|
|
||||||
buf := bytebufferpool.Get()
|
|
||||||
defer bytebufferpool.Put(buf) // 函数结束自动归还缓冲区到池
|
|
||||||
|
|
||||||
// 3. 调整缓冲区长度,匹配待解密数据(避免扩容)
|
|
||||||
buf.B = buf.B[:0] // 清空原有数据,保留底层数组
|
|
||||||
if cap(buf.B) < len(encryptedData) {
|
|
||||||
// 若缓冲区容量不足,直接扩容(bytebufferpool会自动管理)
|
|
||||||
buf.B = make([]byte, len(encryptedData))
|
|
||||||
} else {
|
|
||||||
// 容量足够,直接调整长度
|
|
||||||
buf.B = buf.B[:len(encryptedData)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 核心异或解密逻辑(直接操作buf.B,无额外内存分配)
|
|
||||||
decrypted := buf.B
|
|
||||||
for i, b := range encryptedData {
|
for i, b := range encryptedData {
|
||||||
decrypted[i] = b ^ keyBytes[i%keyLen]
|
encryptedData[i] = b ^ keyBytes[i%keyLen]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 拷贝结果(关键:避免返回池化缓冲区,防止被后续调用覆盖)
|
return encryptedData
|
||||||
result := make([]byte, len(decrypted))
|
}
|
||||||
copy(result, decrypted)
|
|
||||||
|
|
||||||
return result
|
var packetDataPoolSizes = [...]int{64, 128, 256, 512, 1024, 2048, 4096}
|
||||||
|
|
||||||
|
var packetDataPools = func() []sync.Pool {
|
||||||
|
pools := make([]sync.Pool, len(packetDataPoolSizes))
|
||||||
|
for i, size := range packetDataPoolSizes {
|
||||||
|
size := size
|
||||||
|
pools[i].New = func() any {
|
||||||
|
return make([]byte, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pools
|
||||||
|
}()
|
||||||
|
|
||||||
|
func getPacketData(size int) []byte {
|
||||||
|
if size <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i, poolSize := range packetDataPoolSizes {
|
||||||
|
if size <= poolSize {
|
||||||
|
return packetDataPools[i].Get().([]byte)[:size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return make([]byte, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putPacketData(buf []byte) {
|
||||||
|
if buf == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, poolSize := range packetDataPoolSizes {
|
||||||
|
if cap(buf) == poolSize {
|
||||||
|
packetDataPools[i].Put(buf[:poolSize])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ClientData) PushEvent(v []byte, submit func(task func()) error) {
|
||||||
|
var header common.TomeeHeader
|
||||||
|
header.Len = binary.BigEndian.Uint32(v[0:4])
|
||||||
|
header.CMD = binary.BigEndian.Uint32(v[5:9])
|
||||||
|
header.UserID = binary.BigEndian.Uint32(v[9:13])
|
||||||
|
if dataLen := len(v) - 17; dataLen > 0 {
|
||||||
|
header.Data = getPacketData(dataLen)
|
||||||
|
copy(header.Data, v[17:])
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = submit(func() {
|
||||||
|
h.LF.Producer().Write(header)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重写
|
// 重写
|
||||||
@@ -119,13 +147,13 @@ func (h *ClientData) OnEvent(data common.TomeeHeader) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data.Data != nil {
|
if data.Data != nil {
|
||||||
defer bytebufferpool.Put(data.Data)
|
defer putPacketData(data.Data)
|
||||||
data.Res = XORDecryptU(data.Data.Bytes(), h.Player.Hash)
|
data.Res = XORDecryptU(data.Data, h.Player.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else if data.Data != nil {
|
||||||
defer bytebufferpool.Put(data.Data)
|
defer putPacketData(data.Data)
|
||||||
data.Res = data.Data.Bytes()
|
data.Res = data.Data
|
||||||
}
|
}
|
||||||
if cool.Config.ServerInfo.IsDebug != 0 {
|
if cool.Config.ServerInfo.IsDebug != 0 {
|
||||||
fmt.Println("接收数据", data.UserID, data.CMD)
|
fmt.Println("接收数据", data.UserID, data.CMD)
|
||||||
@@ -172,7 +200,7 @@ func (h *ClientData) OnEvent(data common.TomeeHeader) {
|
|||||||
|
|
||||||
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
|
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
|
||||||
|
|
||||||
params = append(params, ptrValue1, reflect.ValueOf(h.Conn.Context().(*ClientData).Player))
|
params = append(params, ptrValue1, reflect.ValueOf(h.Player))
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
params = append(params, ptrValue1, reflect.ValueOf(h.Conn))
|
params = append(params, ptrValue1, reflect.ValueOf(h.Conn))
|
||||||
@@ -209,14 +237,10 @@ func (h *ClientData) OnEvent(data common.TomeeHeader) {
|
|||||||
type ClientData struct {
|
type ClientData struct {
|
||||||
IsCrossDomain sync.Once //是否跨域过
|
IsCrossDomain sync.Once //是否跨域过
|
||||||
Player *Player //客户实体
|
Player *Player //客户实体
|
||||||
//Mu sync.RWMutex
|
ERROR_CONNUT int
|
||||||
ERROR_CONNUT int
|
Wsmsg *WsCodec
|
||||||
Wsmsg *WsCodec
|
Conn gnet.Conn
|
||||||
Conn gnet.Conn
|
LF *lockfree.Lockfree[common.TomeeHeader]
|
||||||
LF *lockfree.Lockfree[common.TomeeHeader]
|
|
||||||
//SaveL sync.Once //保存锁
|
|
||||||
// MsgChan chan common.TomeeHeader
|
|
||||||
//SaveDone chan struct{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ClientData) GetPlayer(userid uint32) *Player { //TODO 这里待优化,可能存在内存泄漏问题
|
func (p *ClientData) GetPlayer(userid uint32) *Player { //TODO 这里待优化,可能存在内存泄漏问题
|
||||||
@@ -232,42 +256,18 @@ func (p *ClientData) GetPlayer(userid uint32) *Player { //TODO 这里待优化,
|
|||||||
// return nil
|
// return nil
|
||||||
}
|
}
|
||||||
func NewClientData(c gnet.Conn) *ClientData {
|
func NewClientData(c gnet.Conn) *ClientData {
|
||||||
// 创建事件处理器
|
|
||||||
// 创建消费端串行处理的Lockfree
|
|
||||||
|
|
||||||
cd := &ClientData{
|
cd := &ClientData{
|
||||||
|
|
||||||
Conn: c,
|
Conn: c,
|
||||||
Wsmsg: &WsCodec{},
|
Wsmsg: &WsCodec{},
|
||||||
// MsgChan: make(chan common.TomeeHeader, 100),
|
|
||||||
}
|
}
|
||||||
//cd.LF = make(chan common.TomeeHeader, 8)
|
|
||||||
// cd.LF = gqueue.NewTQueue[common.TomeeHeader](1)
|
|
||||||
// go func() {
|
|
||||||
// for {
|
|
||||||
// select {
|
|
||||||
// case queueItem := <-cd.LF.C:
|
|
||||||
// cd.OnEvent(queueItem)
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }()
|
|
||||||
cd.LF = lockfree.NewLockfree(
|
cd.LF = lockfree.NewLockfree(
|
||||||
8,
|
8,
|
||||||
cd,
|
cd,
|
||||||
lockfree.NewConditionBlockStrategy(),
|
lockfree.NewConditionBlockStrategy(),
|
||||||
)
|
)
|
||||||
// // // 启动Lockfree
|
|
||||||
if err := cd.LF.Start(); err != nil {
|
if err := cd.LF.Start(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// 启动每个连接的独立消费协程
|
|
||||||
// go cd.consumeMsg()
|
|
||||||
// // // 启动Lockfree
|
|
||||||
// // if err := cd.LF.Start(); err != nil {
|
|
||||||
// // panic(err)
|
|
||||||
// // }
|
|
||||||
return cd
|
return cd
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -305,16 +305,11 @@ func XORDecrypt(encryptedData []byte, keyStr string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ClientData) SendPack(b []byte) error {
|
func (p *ClientData) SendPack(b []byte) error {
|
||||||
cli, ok := p.Conn.Context().(*ClientData)
|
if p.Wsmsg == nil {
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("链接错误,取消发包")
|
|
||||||
|
|
||||||
}
|
|
||||||
if cli.Wsmsg == nil {
|
|
||||||
return fmt.Errorf("ws空")
|
return fmt.Errorf("ws空")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.Wsmsg.Upgraded {
|
if p.Wsmsg.Upgraded {
|
||||||
// This is the echo server
|
// This is the echo server
|
||||||
wsutil.WriteServerMessage(p.Conn, ws.OpBinary, b)
|
wsutil.WriteServerMessage(p.Conn, ws.OpBinary, b)
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,33 @@ package service
|
|||||||
import (
|
import (
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
"blazing/modules/player/model"
|
"blazing/modules/player/model"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CdkService struct {
|
type CdkService struct {
|
||||||
BaseService
|
BaseService
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
claimedCode map[uint32]struct{}
|
||||||
|
cacheLoaded bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CdkService) CanGet(id uint32) bool {
|
func (s *CdkService) CanGet(id uint32) bool {
|
||||||
m1, _ := s.dbm(s.Model).Where("code_id", id).Exist()
|
if s.isClaimed(id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return !m1
|
if err := s.loadClaimedCodes(); err != nil {
|
||||||
|
exists, _ := s.dbm(s.Model).Where("code_id", id).Exist()
|
||||||
|
if exists {
|
||||||
|
s.markClaimed(id)
|
||||||
|
}
|
||||||
|
return !exists
|
||||||
|
}
|
||||||
|
|
||||||
|
return !s.isClaimed(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CdkService) Log(id uint32) {
|
func (s *CdkService) Log(id uint32) {
|
||||||
@@ -26,17 +40,59 @@ func (s *CdkService) Log(id uint32) {
|
|||||||
"is_vip": cool.Config.ServerInfo.IsVip,
|
"is_vip": cool.Config.ServerInfo.IsVip,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Data(data).Insert()
|
if _, err := m.Data(data).Insert(); err == nil {
|
||||||
|
s.markClaimed(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CdkService) loadClaimedCodes() error {
|
||||||
|
s.mu.RLock()
|
||||||
|
if s.cacheLoaded {
|
||||||
|
s.mu.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.mu.RUnlock()
|
||||||
|
|
||||||
|
var logs []model.CdkLog
|
||||||
|
if err := s.dbm(s.Model).Fields("code_id").Scan(&logs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if s.cacheLoaded {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.claimedCode = make(map[uint32]struct{}, len(logs))
|
||||||
|
for _, log := range logs {
|
||||||
|
s.claimedCode[log.CodeID] = struct{}{}
|
||||||
|
}
|
||||||
|
s.cacheLoaded = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CdkService) isClaimed(id uint32) bool {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
_, ok := s.claimedCode[id]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CdkService) markClaimed(id uint32) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if s.claimedCode == nil {
|
||||||
|
s.claimedCode = make(map[uint32]struct{})
|
||||||
|
}
|
||||||
|
s.claimedCode[id] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCdkService(id uint32) *CdkService {
|
func NewCdkService(id uint32) *CdkService {
|
||||||
return &CdkService{
|
return &CdkService{
|
||||||
|
|
||||||
BaseService: BaseService{userid: id,
|
BaseService: BaseService{userid: id,
|
||||||
|
|
||||||
Service: &cool.Service{Model: model.NewCdkLog()},
|
Service: &cool.Service{Model: model.NewCdkLog()},
|
||||||
},
|
},
|
||||||
|
claimedCode: make(map[uint32]struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,21 @@ func (s *ItemService) Get(min, max uint32) []model.Item {
|
|||||||
return ttt
|
return ttt
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ItemService) GetUserItemList(min, max, leftTime uint32) []model.SingleItemInfo {
|
||||||
|
var items []model.SingleItemInfo
|
||||||
|
s.dbm(s.Model).
|
||||||
|
Fields("item_id,item_cnt").
|
||||||
|
WhereBetween("item_id", min, max).
|
||||||
|
Where("item_cnt >", 0).
|
||||||
|
Scan(&items)
|
||||||
|
|
||||||
|
for i := range items {
|
||||||
|
items[i].LeftTime = leftTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
func (s *ItemService) UPDATE(id uint32, count int) error {
|
func (s *ItemService) UPDATE(id uint32, count int) error {
|
||||||
if cool.Config.ServerInfo.IsVip != 0 && count < 0 {
|
if cool.Config.ServerInfo.IsVip != 0 && count < 0 {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user