diff --git a/common/utils/emap.go b/common/utils/emap.go new file mode 100644 index 00000000..56e05ccd --- /dev/null +++ b/common/utils/emap.go @@ -0,0 +1,206 @@ +package utils + +import ( + "fmt" + "hash/maphash" + "sync" +) + +// 泛型有序Map的实现,结合了SliceMap的并发安全和orderedMap的有序性及高效查找 + +// MapEntry 表示Map中的一个键值对条目 +type MapEntry[K comparable, V any] struct { + key K + value V + + // 用于维护插入顺序的双向链表指针 + prev, next *MapEntry[K, V] + // 用于哈希表碰撞处理的链表指针 + hashNext *MapEntry[K, V] + // 标记是否被删除 + deleted bool +} + +// OrderedMap 是一个泛型的有序Map实现 +type OrderedMap[K comparable, V any] struct { + mu sync.RWMutex // 并发安全锁 + hash *maphash.Hash // 哈希计算器 + hashTable map[uint64]*MapEntry[K, V] // 哈希表,用于快速查找 + first *MapEntry[K, V] // 双向链表头,维护插入顺序 + last *MapEntry[K, V] // 双向链表尾,维护插入顺序 + size int // 当前元素数量(排除已删除的) +} + +// NewOrderedMap 创建一个新的泛型有序Map +func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] { + return &OrderedMap[K, V]{ + hash: &maphash.Hash{}, + hashTable: make(map[uint64]*MapEntry[K, V]), + } +} + +// 计算键的哈希值 +func (m *OrderedMap[K, V]) hashKey(key K) uint64 { + // 这里简化实现,实际使用中可能需要根据K的类型做特殊处理 + // 对于基本类型可以直接写入,复杂类型可能需要序列化 + m.hash.Reset() + // 注意:实际使用时需要根据K的具体类型实现正确的哈希计算 + // 这里只是示例,可能需要调整 + m.hash.WriteString(fmt.Sprintf("%v", key)) + return m.hash.Sum64() +} + +// 查找键对应的条目 +func (m *OrderedMap[K, V]) lookup(key K) (hash uint64, entry, prevEntry *MapEntry[K, V]) { + hash = m.hashKey(key) + for entry = m.hashTable[hash]; entry != nil; prevEntry, entry = entry, entry.hashNext { + if !entry.deleted && entry.key == key { + break + } + } + return +} + +// Store 存储键值对,如果键已存在则更新值 +func (m *OrderedMap[K, V]) Store(key K, value V) { + m.mu.Lock() + defer m.mu.Unlock() + + hash, entry, prevEntry := m.lookup(key) + + if entry != nil { + // 键已存在,更新值并确保标记为未删除 + entry.value = value + if entry.deleted { + entry.deleted = false + m.size++ + } + return + } + + // 创建新条目 + entry = &MapEntry[K, V]{ + key: key, + value: value, + } + + // 添加到哈希表 + if prevEntry == nil { + m.hashTable[hash] = entry + } else { + prevEntry.hashNext = entry + } + + // 添加到双向链表末尾以保持插入顺序 + if m.last != nil { + entry.prev = m.last + m.last.next = entry + } else { + // 第一个元素 + m.first = entry + } + m.last = entry + m.size++ +} + +// Load 查找并返回键对应的值,如果不存在则返回零值和false +func (m *OrderedMap[K, V]) Load(key K) (value V, exists bool) { + m.mu.RLock() + defer m.mu.RUnlock() + + _, entry, _ := m.lookup(key) + if entry != nil && !entry.deleted { + return entry.value, true + } + return value, false +} + +// LoadOrStore 查找并返回键对应的值,如果不存在则存储并返回给定值 +func (m *OrderedMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { + m.mu.Lock() + defer m.mu.Unlock() + + _, entry, _ := m.lookup(key) + if entry != nil && !entry.deleted { + return entry.value, true + } + + // 执行存储操作 + hash := m.hashKey(key) + entry = &MapEntry[K, V]{ + key: key, + value: value, + } + + // 添加到哈希表 + if m.hashTable[hash] == nil { + m.hashTable[hash] = entry + } else { + // 处理哈希冲突 + last := m.hashTable[hash] + for last.hashNext != nil { + last = last.hashNext + } + last.hashNext = entry + } + + // 添加到双向链表 + if m.last != nil { + entry.prev = m.last + m.last.next = entry + } else { + m.first = entry + } + m.last = entry + m.size++ + + return value, false +} + +// Delete 标记删除指定的键 +func (m *OrderedMap[K, V]) Delete(key K) { + m.mu.Lock() + defer m.mu.Unlock() + + _, entry, _ := m.lookup(key) + if entry != nil && !entry.deleted { + entry.deleted = true + m.size-- + } +} + +// Range 按插入顺序迭代Map中的所有键值对 +// 如果f返回false,则停止迭代 +func (m *OrderedMap[K, V]) Range(f func(key K, value V) bool) { + m.mu.RLock() + defer m.mu.RUnlock() + + current := m.first + for current != nil { + if !current.deleted { + if !f(current.key, current.value) { + return + } + } + current = current.next + } +} + +// Len 返回当前Map中的元素数量(排除已删除的) +func (m *OrderedMap[K, V]) Len() int { + m.mu.RLock() + defer m.mu.RUnlock() + return m.size +} + +// Clear 清空Map中的所有元素 +func (m *OrderedMap[K, V]) Clear() { + m.mu.Lock() + defer m.mu.Unlock() + + // 重置所有指针和计数器 + m.first = nil + m.last = nil + m.hashTable = make(map[uint64]*MapEntry[K, V]) + m.size = 0 +} diff --git a/logic/service/fight/fightc.go b/logic/service/fight/fightc.go index c0b350f1..14e4cbd2 100644 --- a/logic/service/fight/fightc.go +++ b/logic/service/fight/fightc.go @@ -384,9 +384,10 @@ func (f *FightC) parseskill(attacker, defender *input.Input, id *SelectSkillActi temparg = temparg[args:] if t.GetOwner() { //如果取反,说明是给对方添加的回合效果 //实际上,owner永远为反,说明是对方给我添加的 - defender.AddEffect(t) + + defender.AddEffect(defender.GetSkillEffect(v)) } else { - attacker.AddEffect(t) + attacker.AddEffect(attacker.GetSkillEffect(v)) } } diff --git a/logic/service/fight/input/input.go b/logic/service/fight/input/input.go index fd8f8177..0721c8aa 100644 --- a/logic/service/fight/input/input.go +++ b/logic/service/fight/input/input.go @@ -1,6 +1,7 @@ package input import ( + "blazing/common/utils" "blazing/logic/service/common" "blazing/logic/service/fight/info" "fmt" @@ -19,7 +20,7 @@ type Input struct { *info.AttackValue FightC common.FightI // info.BattleActionI - Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的 + Effects *utils.OrderedMap[int, Effect] //effects 实际上全局就是effect无限回合 //effects容器 技能的 //Damage decimal.Decimal //造成伤害 First bool //是否先手 } @@ -29,6 +30,7 @@ func NewInput(c common.FightI, p common.PlayerI) *Input { t := ret.GetDamageEffect(0) ret.AddEffect(t) //添加默认基类,实现继承 p.SetFightC(c) //给玩家设置战斗容器 + ret.Effects = utils.NewOrderedMap[int, Effect]() return ret } diff --git a/logic/service/fight/input/nodemanger.go b/logic/service/fight/input/nodemanger.go index 17416d3e..214e19fe 100644 --- a/logic/service/fight/input/nodemanger.go +++ b/logic/service/fight/input/nodemanger.go @@ -66,7 +66,6 @@ type Effect interface { //回合数,然后次数另外维护 Duration(...int) int - ID() int Alive() bool Stack(...int) int @@ -130,15 +129,36 @@ func InitDamageEffect(id int, t Effect) { } // 1为红伤 -func (c *Input) GetDamageEffect(id int) Effect { - - ret, ok := Geteffect(id + 4000000) +func (c *Input) GetDamageEffect(id int) *EffectID { + id1 := id + 4000000 + ret, ok := Geteffect(id1) if ok { //todo 获取前GetEffect - return ret + return &EffectID{ + ID: id1, + Effect: ret, + } //todo 获取后GetEffect } - return nil + return &EffectID{} +} +func (c *Input) GetSkillEffect(id int) *EffectID { + id1 := id + 1000000 + ret, ok := Geteffect(id1) + if ok { + + return &EffectID{ + ID: id1, + Effect: ret, + } + + } + return &EffectID{} +} + +type EffectID struct { + ID int + Effect Effect } func (c *Input) GetPropEffect(id int) Effect { @@ -191,59 +211,54 @@ func getTypeName(v interface{}) string { return t.Kind().String() } -func (c *Input) AddEffect(e Effect) { +func (c *Input) AddEffect(e *EffectID) { + if e.ID == 0 { + return + } //todo 免疫 //TODO 先激活 - e.SetInput(c) + e.Effect.SetInput(c) // 如果已有同 ID 的效果,尝试叠加 - for _, eff := range c.Effects { - if eff.ID() == e.ID() { + _, ok := c.Effects.Load(e.ID) + if !ok { + // 否则新加入 + c.Effects.Store(e.ID, e.Effect) + return + } + + c.Effects.Range(func(key int, value Effect) bool { + if e.ID == key { //设置输入源 - if eff.Stack() < eff.GetMaxStack() { //如果小于最大叠层 - eff.Stack(e.Stack()) //获取到当前叠层数然后叠加 + if value.Stack() < value.GetMaxStack() { //如果小于最大叠层 + value.Stack(value.Stack()) //获取到当前叠层数然后叠加 } else { //这里,说明是延续回合效果 - eff.Duration(e.Duration()) + value.Duration(value.Duration()) } - - return + return false } - } - // 否则新加入 - c.Effects = append(c.Effects, e) -} -// 删除 -func (c *Input) RemoveEffect(e Effect) { + return true + }) - slice := c.Effects - for i := 0; i < len(slice); { - if slice[i].ID() == e.ID() { - slice = append(slice[:i], slice[i+1:]...) - } else { - i++ - } - } - c.Effects = slice } // ForEachEffectBool 遍历所有 Effect,执行“无参数、返回 bool”的方法 // 参数 fn:接收单个 Effect,返回 bool(如 func(e Effect) bool { return e.OnBattleStart() }) // 返回值:所有 Effect 的方法返回值列表 func (c *Input) Exec(fn func(Effect) bool) bool { - - for _, effect := range c.Effects { - if effect.Alive() { - result := fn(effect) + c.Effects.Range(func(key int, value Effect) bool { + if value.Alive() { + result := fn(value) if !result { return result //如果是false,说明存在阻止向下执行的effect,比如免疫能力提升效果 } } - - } + return true + }) return true } @@ -251,14 +266,12 @@ func (c *Input) Exec(fn func(Effect) bool) bool { // 消除回合类效果 efftype 输入是消对方的还是自己的,false是自己,true是对方 func (c *Input) CancelTurn(efftype bool) { - slice := c.Effects - for i := 0; i < len(slice); { - if slice[i].Duration() > 0 { //false是自身,true是对方,反转后为真就是自己的 - slice = append(slice[:i], slice[i+1:]...) - } else { - i++ + c.Effects.Range(func(key int, value Effect) bool { + if value.Duration() > 0 { //false是自身,true是对方,反转后为真就是自己的 + //slice = append(slice[:i], slice[i+1:]...) + value.NotALive() } - } - c.Effects = slice + return true + }) } diff --git a/logic/service/fight/node/node.go b/logic/service/fight/node/node.go index bc01c894..d38418b4 100644 --- a/logic/service/fight/node/node.go +++ b/logic/service/fight/node/node.go @@ -31,11 +31,7 @@ func (this *EffectNode) Alive() bool { return !this.notAlive } -func (this *EffectNode) ID() int { - return 0 - -} func (this *EffectNode) NotALive() { this.notAlive = true