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

View File

@@ -3,6 +3,7 @@ package rpc
import (
"blazing/common/data/share"
"blazing/cool"
"sync"
"blazing/modules/base/service"
"context"
@@ -18,7 +19,26 @@ import (
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 {
KickPerson func(uint32) error //踢人,这里是返回具体的logic
@@ -37,7 +57,8 @@ func (h *ServerHandler) Kick(ctx context.Context, userid uint32) error {
if err != nil {
return fmt.Errorf("user not found", err)
}
cl, ok := Clientmap[useid1]
cl, ok := getClient(useid1)
if ok {
err := cl.KickPerson(userid) //实现指定服务器踢人
if err != nil {
@@ -57,11 +78,11 @@ func (h *ServerHandler) RegisterLogic(ctx context.Context, id, port uint16) erro
return fmt.Errorf("no reverse client")
}
t, _ := blservice.NewLoginServiceService().GetServerID(id)
aa, ok := Clientmap[t]
aa, ok := getClient(t)
if ok && aa != nil { //如果已经存在且这个端口已经被存过
aa.QuitSelf(0)
}
Clientmap[port] = &revClient
addClient(port, &revClient)
//Refurh()
return nil

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -294,6 +294,9 @@ func (i *Input) GetAction(opp *Input) {
allSkills := make([]skillWithDamage, 0, len(skills))
for _, s := range skills {
if s == nil {
continue
}
// 计算技能对对方的伤害假设CalculatePower返回伤害值或需从技能中获取
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 {
var ret []Effect
for _, v := range c.Effects {
if v.ID() == id &&v.Alive(){
if v.ID() == id+int(etype) && v.Alive() {
ret = append(ret, v)
}
@@ -99,6 +99,21 @@ func (c *Input) GetCurrAttr(id int) *model.PetInfo {
//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) {
//todo 免疫
@@ -106,19 +121,25 @@ func (c *Input) AddEffect(e Effect) {
fmt.Println("产生回合数", e.ID(), e.Duration())
// 如果已有同 ID 的效果,尝试叠加
for _, v := range c.Effects {
if v.ID() == e.ID() && v.Alive() {
//如果效果相同,id相同,参数相同,就是同一个,确认是否可以叠加,正常来说本身就可以共存
//衰弱本身参数也是相同的,区别只是传入的回合数不一样和层数不一样
if v.MaxStack() > 0 {
e.Alive(false) //取消之前效果
if v.Stack() <= v.MaxStack() { //如果小于最大叠层,状态可以叠层
e.SetArgs(v.GetInput(), v.GetArgs()...) //参数输入
e.Stack(v.Stack() + e.Stack()) //获取到当前叠层数然后叠加
//v.Duration(e.Duration()) //回合数覆盖
}
if v.ID() == e.ID() &&
v.Alive() &&
equalInts(v.GetArgs(), e.GetArgs()) &&
v.MaxStack() != 0 { //如果层数可以叠加或者是无限层数
///e.Alive(false) //取消之前效果
if v.Stack() <= v.MaxStack() { //如果小于最大叠层,状态可以叠层
e.Stack(v.Stack() + e.Stack()) //获取到当前叠层数然后叠加
//这里直接返回,不再继续执行后续效果,因为这里是可以叠加的效果
//v.Duration(e.Duration()) //回合数覆盖
}
c.Effects = append(c.Effects, e)
return
// c.Effects = append(c.Effects, e)
//return
}
}

View File

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

Binary file not shown.