feat(rpc): 优化客户端连接管理,使用 sync.Map 替代普通 map

将 `Clientmap` 从普通 map 改为 `sync.Map`,提升并发安全性。新增
`addClient` 和 `getClient` 方法封装存取逻辑,并在多处调用点进行了替换。

fix(fight): 修复战斗逻辑中技能ID与攻击时间字段引用错误

将 `attacker.AttackValue.SkillID` 和
`attacker.AttackValue.AttackTime` 的访问方式修正为正确的字段路径。

refactor(fight): 调整战斗结束信息处理流程

合并 `FightOverInfo` 结构到 `FightC` 中,简化广播发送逻辑,统一通过
`f.FightOverInfo` 发送战斗结果。

refactor(effect): 修改效果叠加判断逻辑并增强健壮性

更新效果节点比较方法,增加参数匹配检查以支持更精确的效果识别;同时添加
`equalInts` 工具函数用于数组内容对比。
This commit is contained in:
2025-11-07 22:50:34 +08:00
parent 31b8a27eeb
commit e2a184b687
13 changed files with 93 additions and 47 deletions

View File

@@ -20,6 +20,7 @@ func GetServerInfoList() []ServerInfo {
var ret1 []ServerInfo var ret1 []ServerInfo
ip, _ := service.NewBaseSysParamService().DataByKey(context.Background(), "server_ip") ip, _ := service.NewBaseSysParamService().DataByKey(context.Background(), "server_ip")
testip, _ := service.NewBaseSysParamService().DataByKey(context.Background(), "test_ip") testip, _ := service.NewBaseSysParamService().DataByKey(context.Background(), "test_ip")
for _, v := range ret { for _, v := range ret {
tt := newServerInfo() tt := newServerInfo()
tt.OnlineID = uint32(v.OnlineID) tt.OnlineID = uint32(v.OnlineID)
@@ -30,7 +31,8 @@ func GetServerInfoList() []ServerInfo {
tt.IP = testip tt.IP = testip
} }
tt.Port = v.Port tt.Port = v.Port
t, ok := Clientmap[v.Port]
t, ok := getClient(v.Port)
if ok { if ok {
cool.Loger.Info(context.TODO(), "服务器假踢人") cool.Loger.Info(context.TODO(), "服务器假踢人")

View File

@@ -3,6 +3,7 @@ package rpc
import ( import (
"blazing/common/data/share" "blazing/common/data/share"
"blazing/cool" "blazing/cool"
"sync"
"blazing/modules/base/service" "blazing/modules/base/service"
"context" "context"
@@ -18,7 +19,26 @@ import (
var rpcport = gconv.String(cool.Config.RPC) var rpcport = gconv.String(cool.Config.RPC)
var Clientmap = make(map[uint16]*ClientHandler) //客户端map // 定义改为sync.Map
var Clientmap sync.Map
// 存值示例
func addClient(id uint16, client *ClientHandler) {
// 普通mapClientmap[id] = client
Clientmap.Store(id, client) // sync.Map存值
}
// 取值示例
func getClient(id uint16) (*ClientHandler, bool) {
// 普通mapclient, ok := Clientmap[id]
val, ok := Clientmap.Load(id) // sync.Map取值
if !ok {
return nil, false
}
// 类型断言确保value是*ClientHandler
client, ok := val.(*ClientHandler)
return client, ok
}
type ClientHandler struct { type ClientHandler struct {
KickPerson func(uint32) error //踢人,这里是返回具体的logic KickPerson func(uint32) error //踢人,这里是返回具体的logic
@@ -37,7 +57,8 @@ func (h *ServerHandler) Kick(ctx context.Context, userid uint32) error {
if err != nil { if err != nil {
return fmt.Errorf("user not found", err) return fmt.Errorf("user not found", err)
} }
cl, ok := Clientmap[useid1]
cl, ok := getClient(useid1)
if ok { if ok {
err := cl.KickPerson(userid) //实现指定服务器踢人 err := cl.KickPerson(userid) //实现指定服务器踢人
if err != nil { if err != nil {
@@ -57,11 +78,11 @@ func (h *ServerHandler) RegisterLogic(ctx context.Context, id, port uint16) erro
return fmt.Errorf("no reverse client") return fmt.Errorf("no reverse client")
} }
t, _ := blservice.NewLoginServiceService().GetServerID(id) t, _ := blservice.NewLoginServiceService().GetServerID(id)
aa, ok := Clientmap[t] aa, ok := getClient(t)
if ok && aa != nil { //如果已经存在且这个端口已经被存过 if ok && aa != nil { //如果已经存在且这个端口已经被存过
aa.QuitSelf(0) aa.QuitSelf(0)
} }
Clientmap[port] = &revClient addClient(port, &revClient)
//Refurh() //Refurh()
return nil return nil

View File

@@ -64,9 +64,9 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
-1, -1,
0, //野怪没特性 0, //野怪没特性
0, 0,
2) bm.Lv)
mo.Level = uint32(bm.Lv) // mo.Level = uint32(bm.Lv)
mo.CalculatePetPane() mo.CalculatePetPane()
mo.Hp = uint32(bm.Hp) mo.Hp = uint32(bm.Hp)
mo.MaxHp = uint32(bm.Hp) mo.MaxHp = uint32(bm.Hp)

View File

@@ -89,15 +89,11 @@ func (u *UseItemAction) Priority() int {
// EscapeAction 逃跑的战斗动作 // EscapeAction 逃跑的战斗动作
type EscapeAction struct { type EscapeAction struct {
BaseAction BaseAction
Reason info.FightOverInfo Reason info.EnumBattleOverReason
Our common.PlayerI Our common.PlayerI
Opp common.PlayerI Opp common.PlayerI
} }
func (e *EscapeAction) GetInfo() info.FightOverInfo {
return e.Reason
}
// Priority 返回动作优先级 // Priority 返回动作优先级
func (e *EscapeAction) Priority() int { func (e *EscapeAction) Priority() int {
return int(PlayerOperations.Escape) return int(PlayerOperations.Escape)

View File

@@ -23,7 +23,7 @@ func newEffectStat(targetOpponent bool) input.Effect {
e := &EffectStat{ e := &EffectStat{
Etype: targetOpponent, Etype: targetOpponent,
} }
e.MaxStack(-1) // 无限叠加 //e.MaxStack(-1) // 无限叠加
return e return e
} }

View File

@@ -11,9 +11,12 @@ import (
*/ */
func init() { func init() {
input.InitEffect(input.EffectType.Skill, 9, &Effect9{ t := &Effect9{
EffectNode: node.EffectNode{}, EffectNode: node.EffectNode{},
}) }
t.Duration(-1)
t.MaxStack(-1)
input.InitEffect(input.EffectType.Skill, 9, t)
} }

View File

@@ -34,6 +34,7 @@ type FightC struct {
First *input.Input First *input.Input
Second *input.Input Second *input.Input
closefight bool closefight bool
info.FightOverInfo
} }
func (f *FightC) CanEscape() bool { func (f *FightC) CanEscape() bool {
@@ -274,8 +275,8 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
//技能miss+效果生效 这里属于强制改命中效果,但是正常来说,技能miss掉后效果也应该失效 //技能miss+效果生效 这里属于强制改命中效果,但是正常来说,技能miss掉后效果也应该失效
//技能失效+效果失效 //技能失效+效果失效
// 记录技能信息 // 记录技能信息
attacker.AttackValue.SkillID = uint32(a.ID) //获取技能ID attacker.SkillID = uint32(a.ID) //获取技能ID
if attacker.AttackValue.AttackTime > 0 { //如果命中 if attacker.AttackTime > 0 { //如果命中
attacker.UseSkill(defender, a) //暴击计算 attacker.UseSkill(defender, a) //暴击计算
attacker.AttackValue.IsCritical = a.Crit attacker.AttackValue.IsCritical = a.Crit
@@ -366,6 +367,7 @@ func copyskill(t *action.SelectSkillAction) *action.SelectSkillAction {
func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) { func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
if f.closefight { //战斗结束 if f.closefight { //战斗结束
return return
} }
// 伤害值 // 伤害值
@@ -526,13 +528,8 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
} else { } else {
WinnerId = f.Second.Player.GetInfo().UserID WinnerId = f.Second.Player.GetInfo().UserID
} }
defer f.Broadcast(func(ff *input.Input) { f.FightOverInfo.WinnerId = WinnerId
//todo 将血量和技能pp传回enterturn
ff.Player.SendFightEndInfo(info.FightOverInfo{
WinnerId: WinnerId,
})
})
f.closefight = true f.closefight = true
} }

View File

@@ -261,11 +261,14 @@ type ReadyFightPetInfo struct {
// FightOverInfo 战斗结束信息结构体 2506 // FightOverInfo 战斗结束信息结构体 2506
type FightOverInfo struct { type FightOverInfo struct {
//0 正常结束
//1=isPlayerLost 对方玩家退出 //1=isPlayerLost 对方玩家退出
// 2=isOvertime 正常对战结束?有质疑 // 2=isOvertime 超时
// 3=isDraw 双方平手 // 3=isDraw 双方平手
// 4=isSysError 系统错误 // 4=isSysError 系统错误
// 5=isNpcEscape 精灵主动逃跑 // 5=isNpcEscape 精灵主动逃跑
//7 切磋结束
Reason EnumBattleOverReason // 固定值0 Reason EnumBattleOverReason // 固定值0
WinnerId uint32 // 胜者的米米号 野怪为0 WinnerId uint32 // 胜者的米米号 野怪为0
TwoTimes uint32 // 双倍经验剩余次数 TwoTimes uint32 // 双倍经验剩余次数

View File

@@ -294,6 +294,9 @@ func (i *Input) GetAction(opp *Input) {
allSkills := make([]skillWithDamage, 0, len(skills)) allSkills := make([]skillWithDamage, 0, len(skills))
for _, s := range skills { for _, s := range skills {
if s == nil {
continue
}
// 计算技能对对方的伤害假设CalculatePower返回伤害值或需从技能中获取 // 计算技能对对方的伤害假设CalculatePower返回伤害值或需从技能中获取
damage := i.CalculatePower(opp, s) damage := i.CalculatePower(opp, s)

View File

@@ -70,7 +70,7 @@ func (c *Input) GetProp(id int, istue bool) int {
func (c *Input) GetEffect(etype EnumEffectType, id int) Effect { func (c *Input) GetEffect(etype EnumEffectType, id int) Effect {
var ret []Effect var ret []Effect
for _, v := range c.Effects { for _, v := range c.Effects {
if v.ID() == id &&v.Alive(){ if v.ID() == id+int(etype) && v.Alive() {
ret = append(ret, v) ret = append(ret, v)
} }
@@ -99,6 +99,21 @@ func (c *Input) GetCurrAttr(id int) *model.PetInfo {
//todo 获取后GetEffect //todo 获取后GetEffect
} }
// 比较两个[]int是否内容相等
func equalInts(a, b []int) bool {
// 先判断长度是否相等
if len(a) != len(b) {
return false
}
// 逐个比较元素
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func (c *Input) AddEffect(e Effect) { func (c *Input) AddEffect(e Effect) {
//todo 免疫 //todo 免疫
@@ -106,19 +121,25 @@ func (c *Input) AddEffect(e Effect) {
fmt.Println("产生回合数", e.ID(), e.Duration()) fmt.Println("产生回合数", e.ID(), e.Duration())
// 如果已有同 ID 的效果,尝试叠加 // 如果已有同 ID 的效果,尝试叠加
for _, v := range c.Effects { for _, v := range c.Effects {
if v.ID() == e.ID() && v.Alive() { //如果效果相同,id相同,参数相同,就是同一个,确认是否可以叠加,正常来说本身就可以共存
//衰弱本身参数也是相同的,区别只是传入的回合数不一样和层数不一样
if v.MaxStack() > 0 { if v.ID() == e.ID() &&
e.Alive(false) //取消之前效果 v.Alive() &&
equalInts(v.GetArgs(), e.GetArgs()) &&
v.MaxStack() != 0 { //如果层数可以叠加或者是无限层数
///e.Alive(false) //取消之前效果
if v.Stack() <= v.MaxStack() { //如果小于最大叠层,状态可以叠层 if v.Stack() <= v.MaxStack() { //如果小于最大叠层,状态可以叠层
e.SetArgs(v.GetInput(), v.GetArgs()...) //参数输入
e.Stack(v.Stack() + e.Stack()) //获取到当前叠层数然后叠加 e.Stack(v.Stack() + e.Stack()) //获取到当前叠层数然后叠加
//这里直接返回,不再继续执行后续效果,因为这里是可以叠加的效果
//v.Duration(e.Duration()) //回合数覆盖 //v.Duration(e.Duration()) //回合数覆盖
}
} }
c.Effects = append(c.Effects, e)
return return
// c.Effects = append(c.Effects, e)
//return
} }
} }

View File

@@ -19,6 +19,12 @@ func (f *FightC) battleLoop() {
for { for {
if f.closefight { if f.closefight {
f.Broadcast(func(ff *input.Input) {
//todo 将血量和技能pp传回enterturn
ff.Player.SendFightEndInfo(f.FightOverInfo)
})
close(f.actionChan) close(f.actionChan)
break break
} }
@@ -119,9 +125,9 @@ func (f *FightC) resolveRound(p1Action, p2Action action.BattleActionI) {
switch a := b1.(type) { switch a := b1.(type) {
case *action.EscapeAction: case *action.EscapeAction:
f.Broadcast(func(ff *input.Input) { f.FightOverInfo.WinnerId = b2.GetPlayerID() //对方胜利
ff.Player.SendFightEndInfo(a.Reason) f.FightOverInfo.Reason = a.Reason
})
f.closefight = true f.closefight = true
case *action.ActiveSwitchAction: case *action.ActiveSwitchAction:
@@ -154,7 +160,9 @@ func (f *FightC) handleItemAction(a *action.UseItemAction, other action.BattleAc
CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime), CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime),
PetId: uint32(f.Opp.CurrentPet.ID), PetId: uint32(f.Opp.CurrentPet.ID),
}) })
our.SendFightEndInfo(info.FightOverInfo{WinnerId: f.ownerID}) //f.WinnerId = 0 //捕捉成功不算胜利
f.Reason = 6
f.closefight = true f.closefight = true
} else { } else {
our.CatchPetInfo(info.CatchMonsterOutboundInfo{}) our.CatchPetInfo(info.CatchMonsterOutboundInfo{})

View File

@@ -31,17 +31,9 @@ func (f *FightC) Compare(a, b action.BattleActionI) (action.BattleActionI, actio
func (f *FightC) Over(c common.PlayerI, res info.EnumBattleOverReason) { func (f *FightC) Over(c common.PlayerI, res info.EnumBattleOverReason) {
ret := &action.EscapeAction{ ret := &action.EscapeAction{
BaseAction: action.NewBaseAction(c.GetInfo().UserID), BaseAction: action.NewBaseAction(c.GetInfo().UserID),
Reason: info.FightOverInfo{
Reason: res, Reason: res,
},
} }
if c.GetInfo().UserID == f.ownerID {
ret.Reason.WinnerId = f.Opp.Player.GetInfo().UserID
} else {
ret.Reason.WinnerId = f.Our.Player.GetInfo().UserID
}
f.actionChan <- ret f.actionChan <- ret
} }

Binary file not shown.