From c00a796203427618249e0fa64e28de79ee4805c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <12574910+72wo@users.noreply.github.com> Date: Wed, 25 Feb 2026 13:20:38 +0800 Subject: [PATCH] =?UTF-8?q?```=20refactor(common/utils):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84concurrent=5Fswiss=5Fmap=E4=BD=BF=E7=94=A8=E5=AE=98?= =?UTF-8?q?=E6=96=B9sync.Map=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 替换原有的第三方并发map实现,改为基于标准库sync.Map的封装 - 保持完全的API兼容性,原有配置方法变为无实际作用的占位符 - 优化Range方法实现,移除goroutine/channel开销,避免潜在的死锁风险 - 移除依赖的外部库和 --- .../concurrent_swiss_map.go | 372 ++++++------------ .../admin/{map_boss.go => map_node.go} | 0 modules/config/model/base_pet.go | 2 - modules/config/model/boss_pet.go | 11 +- modules/config/model/map_boos.go | 47 --- modules/config/model/map_node.go | 20 +- modules/config/model/tower_110.go | 10 +- modules/config/service/boss.go | 6 +- modules/config/service/map.go | 1 + modules/config/service/map_boos.go | 2 +- 10 files changed, 140 insertions(+), 331 deletions(-) rename modules/config/controller/admin/{map_boss.go => map_node.go} (100%) delete mode 100644 modules/config/model/map_boos.go diff --git a/common/utils/concurrent-swiss-map/concurrent_swiss_map.go b/common/utils/concurrent-swiss-map/concurrent_swiss_map.go index 6066ac600..62e7358cd 100644 --- a/common/utils/concurrent-swiss-map/concurrent_swiss_map.go +++ b/common/utils/concurrent-swiss-map/concurrent_swiss_map.go @@ -1,284 +1,191 @@ package csmap import ( - "blazing/cool" - "context" "encoding/json" - "runtime" "sync" "sync/atomic" - - "github.com/mhmtszr/concurrent-swiss-map/maphash" - - "github.com/mhmtszr/concurrent-swiss-map/swiss" ) +// CsMap 基于官方 sync.Map 重构,完全兼容原有接口 type CsMap[K comparable, V any] struct { - hasher func(key K) uint64 - shards []shard[K, V] - shardCount uint64 - size uint64 + inner sync.Map // 核心替换为官方 sync.Map } -type HashShardPair[K comparable, V any] struct { - shard shard[K, V] - hash uint64 -} - -type shard[K comparable, V any] struct { - items *swiss.Map[K, V] - *sync.RWMutex -} - -// OptFunc is a type that is used in New function for passing options. +// 以下配置方法保留(兼容原有调用方式,但内部无实际作用) type OptFunc[K comparable, V any] func(o *CsMap[K, V]) -// New function creates *CsMap[K, V]. +// New 创建基于 sync.Map 的并发安全 Map,兼容原有配置参数(参数无实际作用) func New[K comparable, V any](options ...OptFunc[K, V]) *CsMap[K, V] { - m := CsMap[K, V]{ - hasher: maphash.NewHasher[K]().Hash, - shardCount: uint64(runtime.NumCPU()), - } + m := &CsMap[K, V]{} + // 遍历配置项(兼容原有代码,无实际逻辑) for _, option := range options { - option(&m) + option(m) } - - m.shards = make([]shard[K, V], m.shardCount) - - for i := 0; i < int(m.shardCount); i++ { - m.shards[i] = shard[K, V]{items: swiss.NewMap[K, V](uint32((m.size / m.shardCount) + 1)), RWMutex: &sync.RWMutex{}} - } - - return &m + return m } -// // Create creates *CsMap. -// // -// // Deprecated: New function should be used instead. -// func Create[K comparable, V any](options ...func(options *CsMap[K, V])) *CsMap[K, V] { -// m := CsMap[K, V]{ -// hasher: maphash.NewHasher[K]().Hash, -// shardCount: 32, -// } -// for _, option := range options { -// option(&m) -// } - -// m.shards = make([]shard[K, V], m.shardCount) - -// for i := 0; i < int(m.shardCount); i++ { -// m.shards[i] = shard[K, V]{items: swiss.NewMap[K, V](uint32((m.size / m.shardCount) + 1)), RWMutex: &sync.RWMutex{}} -// } -// return &m -// } - +// 保留原有配置方法(空实现,保证接口兼容) func WithShardCount[K comparable, V any](count uint64) func(csMap *CsMap[K, V]) { - return func(csMap *CsMap[K, V]) { - csMap.shardCount = count - } + return func(csMap *CsMap[K, V]) {} } func WithCustomHasher[K comparable, V any](h func(key K) uint64) func(csMap *CsMap[K, V]) { - return func(csMap *CsMap[K, V]) { - csMap.hasher = h - } + return func(csMap *CsMap[K, V]) {} } func WithSize[K comparable, V any](size uint64) func(csMap *CsMap[K, V]) { - return func(csMap *CsMap[K, V]) { - csMap.size = size - } + return func(csMap *CsMap[K, V]) {} } -func (m *CsMap[K, V]) getShard(key K) HashShardPair[K, V] { - u := m.hasher(key) - return HashShardPair[K, V]{ - hash: u, - shard: m.shards[u%m.shardCount], - } -} +// -------------------------- 核心操作方法(基于 sync.Map 实现) -------------------------- +// Store 存储键值对,兼容原有接口 func (m *CsMap[K, V]) Store(key K, value V) { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - shard.items.PutWithHash(key, value, hashShardPair.hash) - shard.Unlock() + m.inner.Store(key, value) } +// Delete 删除指定键,返回是否删除成功 func (m *CsMap[K, V]) Delete(key K) bool { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - defer shard.Unlock() - return shard.items.DeleteWithHash(key, hashShardPair.hash) + // sync.Map.Delete 无返回值,需先 Load 判断是否存在 + _, ok := m.inner.Load(key) + if ok { + m.inner.Delete(key) + } + return ok } +// DeleteIf 满足条件时删除 func (m *CsMap[K, V]) DeleteIf(key K, condition func(value V) bool) bool { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - defer shard.Unlock() - value, ok := shard.items.GetWithHash(key, hashShardPair.hash) - if ok && condition(value) { - return shard.items.DeleteWithHash(key, hashShardPair.hash) + // 先 Load 获取值,再判断条件 + val, ok := m.inner.Load(key) + if !ok { + return false + } + + v, okCast := val.(V) + if !okCast { + return false + } + + if condition(v) { + m.inner.Delete(key) + return true } return false } +// Load 获取指定键的值 func (m *CsMap[K, V]) Load(key K) (V, bool) { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.RLock() - defer shard.RUnlock() - return shard.items.GetWithHash(key, hashShardPair.hash) -} - -func (m *CsMap[K, V]) Has(key K) bool { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.RLock() - defer shard.RUnlock() - return shard.items.HasWithHash(key, hashShardPair.hash) -} - -func (m *CsMap[K, V]) Clear() { - for i := range m.shards { - shard := m.shards[i] - - shard.Lock() - shard.items.Clear() - shard.Unlock() + var zero V + val, ok := m.inner.Load(key) + if !ok { + return zero, false } + + // 类型断言(保证类型安全) + v, okCast := val.(V) + if !okCast { + return zero, false + } + return v, true } +// Has 判断键是否存在 +func (m *CsMap[K, V]) Has(key K) bool { + _, ok := m.inner.Load(key) + return ok +} + +// Clear 清空所有数据 +func (m *CsMap[K, V]) Clear() { + // sync.Map 无直接 Clear 方法,通过 Range 遍历删除 + m.inner.Range(func(key, value any) bool { + m.inner.Delete(key) + return true + }) +} + +// Count 统计元素数量 func (m *CsMap[K, V]) Count() int { count := 0 - for i := range m.shards { - shard := m.shards[i] - shard.RLock() - count += shard.items.Count() - shard.RUnlock() - } + m.inner.Range(func(key, value any) bool { + count++ + return true + }) return count } +// SetIfAbsent 仅当键不存在时设置值 func (m *CsMap[K, V]) SetIfAbsent(key K, value V) { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - _, ok := shard.items.GetWithHash(key, hashShardPair.hash) - if !ok { - shard.items.PutWithHash(key, value, hashShardPair.hash) - } - shard.Unlock() + m.inner.LoadOrStore(key, value) } -func (m *CsMap[K, V]) SetIf(key K, conditionFn func(previousVale V, previousFound bool) (value V, set bool)) { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - value, found := shard.items.GetWithHash(key, hashShardPair.hash) - value, ok := conditionFn(value, found) - if ok { - shard.items.PutWithHash(key, value, hashShardPair.hash) +// SetIf 根据条件设置值 +func (m *CsMap[K, V]) SetIf(key K, conditionFn func(previousValue V, previousFound bool) (value V, set bool)) { + prevVal, found := m.inner.Load(key) + var prevV V + if found { + prevV, _ = prevVal.(V) + } + + // 执行条件函数 + newVal, set := conditionFn(prevV, found) + if set { + m.inner.Store(key, newVal) } - shard.Unlock() } +// SetIfPresent 仅当键存在时设置值 func (m *CsMap[K, V]) SetIfPresent(key K, value V) { - hashShardPair := m.getShard(key) - shard := hashShardPair.shard - shard.Lock() - _, ok := shard.items.GetWithHash(key, hashShardPair.hash) - if ok { - shard.items.PutWithHash(key, value, hashShardPair.hash) + // 先判断是否存在,再设置 + if _, ok := m.inner.Load(key); ok { + m.inner.Store(key, value) } - shard.Unlock() } +// IsEmpty 判断是否为空 func (m *CsMap[K, V]) IsEmpty() bool { return m.Count() == 0 } +// Tuple 保留原有结构体(兼容序列化逻辑) type Tuple[K comparable, V any] struct { Key K Val V } -// -------------------------- 保留所有原有方法(无修改) -------------------------- -// 注:以下方法和你的源码完全一致,仅省略实现(避免冗余) -// New/WithShardCount/WithCustomHasher/WithSize/getShard/Store/Delete/DeleteIf/ -// Load/Has/Clear/Count/SetIfAbsent/SetIf/SetIfPresent/IsEmpty/MarshalJSON/UnmarshalJSON - -// -------------------------- 核心优化:Range 方法 -------------------------- -// Range 同步遍历所有分段,无 channel/goroutine/context 开销,保留 panic 恢复和提前终止 -// 回调签名完全兼容:返回 true 终止遍历 +// -------------------------- 关键修复:Range 方法(无锁阻塞风险) -------------------------- func (m *CsMap[K, V]) Range(f func(key K, value V) (stop bool)) { - // 1. 提前判空:回调为 nil 直接返回 if f == nil { return } - // 2. 原子标志:控制是否终止遍历(替代 context) var stopFlag atomic.Bool - // 3. 遍历所有分段(同步执行,无额外 goroutine) - for i := range m.shards { - // 检测终止标志:提前退出,避免无效遍历 + // 基于 sync.Map 的 Range 实现,无额外 goroutine/channel + m.inner.Range(func(key, value any) bool { + // 检测终止标志 if stopFlag.Load() { - break + return false } - // 每个分段的遍历逻辑(带 panic 恢复,和原逻辑一致) - func(shardIdx int) { - // 保留原有的 panic 恢复逻辑 - defer func() { - if err := recover(); err != nil { - cool.Logger.Error(context.TODO(), "csmap Range shard panic 错误:", err) - } - }() + // 类型断言 + k, okK := key.(K) + v, okV := value.(V) + if !okK || !okV { + return true // 类型不匹配时跳过,继续遍历 + } - shard := &m.shards[shardIdx] - // 加读锁(并发安全,和原逻辑一致) - shard.RLock() - defer shard.RUnlock() // 延迟释放,避免锁泄漏 - - // 跳过空分段:核心优化点(减少无效遍历) - if shard.items.Count() == 0 { - return - } - - // 遍历当前分段的元素(复用 swiss.Map 的 Iter 方法) - shard.items.Iter(func(k K, v V) (stop bool) { - // 检测终止标志:终止当前分段遍历 - if stopFlag.Load() { - return true - } - - // 执行用户回调,保留提前终止逻辑 - if f(k, v) { - stopFlag.Store(true) // 设置全局终止标志 - return true - } - return false - }) - }(i) // 立即执行函数,避免循环变量捕获问题 - } + // 执行用户回调 + if f(k, v) { + stopFlag.Store(true) + return false // 终止遍历 + } + return true + }) } -// // Range If the callback function returns true iteration will stop. -// func (m *CsMap[K, V]) Range(f func(key K, value V) (stop bool)) { -// ch := make(chan Tuple[K, V], m.Count()) - -// ctx, cancel := context.WithCancel(context.Background()) -// defer cancel() - -// listenCompleted := m.listen(f, ch) -// m.produce(ctx, ch) -// listenCompleted.Wait() -// } - +// -------------------------- 序列化方法(兼容原有逻辑) -------------------------- func (m *CsMap[K, V]) MarshalJSON() ([]byte, error) { tmp := make(map[K]V, m.Count()) m.Range(func(key K, value V) (stop bool) { @@ -289,71 +196,18 @@ func (m *CsMap[K, V]) MarshalJSON() ([]byte, error) { } func (m *CsMap[K, V]) UnmarshalJSON(b []byte) error { - tmp := make(map[K]V, m.Count()) - + tmp := make(map[K]V) if err := json.Unmarshal(b, &tmp); err != nil { return err } + // 清空原有数据 + m.Clear() + // 批量存储 for key, val := range tmp { m.Store(key, val) } return nil } -func (m *CsMap[K, V]) produce(ctx context.Context, ch chan Tuple[K, V]) { - var wg sync.WaitGroup - wg.Add(len(m.shards)) - for i := range m.shards { - go func(i int) { - defer wg.Done() - defer func() { - if err := recover(); err != nil { // 恢复 panic,err 为 panic 错误值 - // 1. 打印错误信息 - - cool.Logger.Error(context.TODO(), "csmap panic 错误:", err) - - } - }() - shard := m.shards[i] - shard.RLock() - shard.items.Iter(func(k K, v V) (stop bool) { - select { - case <-ctx.Done(): - return true - default: - ch <- Tuple[K, V]{Key: k, Val: v} - } - return false - }) - shard.RUnlock() - }(i) - } - go func() { - wg.Wait() - close(ch) - }() -} - -func (m *CsMap[K, V]) listen(f func(key K, value V) (stop bool), ch chan Tuple[K, V]) *sync.WaitGroup { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - defer func() { - if err := recover(); err != nil { // 恢复 panic,err 为 panic 错误值 - // 1. 打印错误信息 - - cool.Logger.Error(context.TODO(), " csmap panic 错误:", err) - - } - }() - for t := range ch { - if stop := f(t.Key, t.Val); stop { - return - } - } - }() - - return &wg -} +// -------------------------- 移除所有无用的旧方法(produce/listen 等) -------------------------- diff --git a/modules/config/controller/admin/map_boss.go b/modules/config/controller/admin/map_node.go similarity index 100% rename from modules/config/controller/admin/map_boss.go rename to modules/config/controller/admin/map_node.go diff --git a/modules/config/model/base_pet.go b/modules/config/model/base_pet.go index e6a1760a9..7608a5019 100644 --- a/modules/config/model/base_pet.go +++ b/modules/config/model/base_pet.go @@ -37,8 +37,6 @@ type PetBaseConfig struct { SKill []uint32 `gorm:"type:jsonb;not null;default:'[]';comment:'BOSS技能'" json:"skill"` - Remark string `gorm:"comment:'BOSS备注'" json:"remark"` - // ISMELEE uint32 `gorm:"not null;default:0;comment:'是否乱斗配置'" json:"is_melee"` // // ===================== BOSS奖励规则(Boss_bonus) ===================== // BonusProbability int32 `gorm:"not null;default:0;comment:'打赢BOSS给奖励概率-分子(值域:0-1000,默认0)'" json:"bonus_probability"` diff --git a/modules/config/model/boss_pet.go b/modules/config/model/boss_pet.go index 6cd80f964..a4945cabe 100644 --- a/modules/config/model/boss_pet.go +++ b/modules/config/model/boss_pet.go @@ -13,11 +13,14 @@ type BossConfig struct { *cool.Model // 嵌入通用Model(包含ID/创建时间/更新时间等通用字段) PetBaseConfig - MapID int32 `gorm:"not null;index;comment:'所属地图ID'" json:"map_id" description:"地图ID"` - BossID int32 `gorm:"not null;index;comment:'所属BOSSID'" json:"boss_id" description:"BOSSID"` - Order int32 `gorm:"not null;comment:'排序'" json:"order" description:"排序"` + MapID int32 `gorm:"not null;index;comment:'所属地图ID'" json:"map_id" description:"地图ID"` - Script string `gorm:"size:1024;default:'';comment:'BOSS脚本'" json:"script"` //boss出招逻辑做成js脚本 + Ordernum int32 `gorm:"not null;comment:'排序'" json:"ordernum" description:"排序"` + ParentID int32 `gorm:"column:parentId;type:int" json:"parentId"` // 父ID + Remark string `gorm:"comment:'BOSS备注'" json:"remark"` + //是否可捕捉MapPit + IsCapture int `gorm:"type:int;default:0;comment:'是否可捕捉'" json:"is_capture"` + Script string `gorm:"size:1024;default:'';comment:'BOSS脚本'" json:"script"` //boss出招逻辑做成js脚本 } diff --git a/modules/config/model/map_boos.go b/modules/config/model/map_boos.go deleted file mode 100644 index 82110a4dc..000000000 --- a/modules/config/model/map_boos.go +++ /dev/null @@ -1,47 +0,0 @@ -package model - -import ( - "blazing/cool" -) - -const ( - TableNameMapBoss = "config_map_boss" // 地图BOSS配置表(记录BOSS归属、属性、刷新规则、奖励等) -) - -// MapBoss 地图BOSS核心配置模型(完全仿照MapPit实现风格) -type MapBoss struct { - *BaseConfig // 复用通用基础配置(ID/创建时间/更新时间/删除时间/备注等) - *Event // 嵌入BOSS事件配置 - MapID int32 `gorm:"not null;index;comment:'所属地图ID'" json:"map_id" description:"地图ID"` - // BOSS唯一标识ID - BossID int `gorm:"not null;index;comment:'BOSSID'" json:"boss_id"` - BossName string `gorm:"type:varchar(100);default:'';comment:'BOSS名称'" json:"boss_name" description:"BOSS名称"` - - WinBonusID int `gorm:"type:int;default:0;comment:'胜利奖励ID'" json:"win_bonus_id"` - FailBonusID int `gorm:"type:int;default:0;comment:'失败奖励ID'" json:"fail_bonus_id"` - //是否可捕捉MapPit - IsCapture int `gorm:"type:int;default:0;comment:'是否可捕捉'" json:"is_capture"` -} - -// TableName 指定MapBoss对应的数据库表名(遵循原模型规范) -func (*MapBoss) TableName() string { - return TableNameMapBoss -} - -// GroupName 指定表所属的分组(保持和MapPit一致) -func (*MapBoss) GroupName() string { - return "default" -} - -// NewMapBoss 创建一个新的MapBoss实例(初始化通用BaseConfig和BossEvent) -func NewMapBoss() *MapBoss { - return &MapBoss{ - BaseConfig: NewBaseConfig(), - Event: &Event{}, - } -} - -// init 初始化表结构(程序启动时自动创建/同步表) -func init() { - cool.CreateTable(&MapBoss{}) -} diff --git a/modules/config/model/map_node.go b/modules/config/model/map_node.go index 4b51befd5..8b81fa00a 100644 --- a/modules/config/model/map_node.go +++ b/modules/config/model/map_node.go @@ -22,26 +22,26 @@ const ( // MapNode 地图节点配置模型 type MapNode struct { *BaseConfig - + *Event // 嵌入BOSS事件配置 // 基础关联字段 - MapID uint32 `gorm:"not null;index;comment:'所属地图ID'" json:"map_id" description:"地图ID"` + NodeType int `gorm:"not null;default:0;comment:'节点类型(0是游戏自带分支,其余自增)'" json:"node_type" description:"节点类型"` + NodeID uint32 `gorm:"not null;default:0;comment:'节点ID'" json:"node_id" description:"节点ID"` + NodeName string `gorm:"type:varchar(100);default:'';comment:'节点名称'" json:"node_name" description:"节点名称"` //节点激活脚本 - // NodeActiveScript string `gorm:"type:text;comment:'节点激活脚本'" json:"node_active_script" description:"节点激活脚本"` - // - // 节点核心配置 - NodeType int `gorm:"not null;default:0;comment:'节点类型(1-BOSS,2-NPC,3-场景触发,4-传送门)'" json:"node_type" description:"节点类型"` PositionX float64 `gorm:"not null;default:0;comment:'节点X坐标'" json:"position_x" description:"X坐标"` PositionY float64 `gorm:"not null;default:0;comment:'节点Y坐标'" json:"position_y" description:"Y坐标"` + WinBonusID int `gorm:"type:int;default:0;comment:'胜利奖励ID'" json:"win_bonus_id"` + FailBonusID int `gorm:"type:int;default:0;comment:'失败奖励ID'" json:"fail_bonus_id"` // 剧情相关配置 - TriggerPlotID uint32 `gorm:"default:0;comment:'触发剧情ID(0表示无剧情)'" json:"trigger_plot_id" description:"触发剧情ID"` - BindPlotIDs []uint32 `gorm:"type:int[];comment:'绑定的剧情ID列表'" json:"bind_plot_ids" description:"绑定剧情ID列表"` + TriggerPlotID uint32 `gorm:"default:0;comment:'触发剧情ID(0表示无剧情)'" json:"trigger_plot_id" description:"触发剧情ID"` + //BindPlotIDs []uint32 `gorm:"type:int[];comment:'绑定的剧情ID列表'" json:"bind_plot_ids" description:"绑定剧情ID列表"` //完成后的脚本回调,比如战胜和击败绑定不同的任务ID,以及剧情绑定不同的ID - PlotFinishScript string `gorm:"type:text;comment:'剧情完成后脚本回调'" json:"plot_finish_script" description:"剧情完成后脚本回调"` + //回调通boss打完给前端发送固定事件 + //PlotFinishScript string `gorm:"type:text;comment:'剧情完成后脚本回调'" json:"plot_finish_script" description:"剧情完成后脚本回调"` - // BOSS相关配置 BindBossID uint32 `gorm:"default:0;comment:'绑定的BOSS ID(0表示无BOSS)'" json:"bind_boss_id" description:"绑定BOSS ID"` } diff --git a/modules/config/model/tower_110.go b/modules/config/model/tower_110.go index 9509eb4fe..32a9ef499 100644 --- a/modules/config/model/tower_110.go +++ b/modules/config/model/tower_110.go @@ -11,12 +11,11 @@ const ( TableNameBraveTowerConfig = "config_tower_600" // 勇者之塔600配置表 ) -// -------------------------- 核心基类:所有塔配置的通用结构 -------------------------- type BaseTowerConfig struct { *BaseConfig - - TowerLevel uint32 `gorm:"not null;default:0;uniqueIndex;comment:'塔层数(唯一标识每层配置)'" json:"tower_level" description:"塔层数"` - BossIds []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'绑定BOSS ID数组,关联config_pet_boss表主键'" json:"boss_ids" description:"绑定BOSS数组"` + Name string `gorm:"type:varchar(100);default:'';comment:'塔名称'" json:"name" description:"塔名称"` + TowerLevel uint32 `gorm:"not null;default:0;uniqueIndex;comment:'塔层数'" json:"tower_level" ` + BossIds []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'绑定BOSS ID数组'" json:"boss_ids" ` } // NewBaseTowerConfig 创建基础塔配置实例(所有塔类型共用) @@ -26,9 +25,6 @@ func NewBaseTowerConfig() *BaseTowerConfig { } } -// -------------------------- 各塔类型专属配置模型(无额外字段,仅绑定不同表名)-------------------------- - -// Tower110Config 勇者之塔110配置模型 type Tower110Config struct { *BaseTowerConfig } diff --git a/modules/config/service/boss.go b/modules/config/service/boss.go index f8ed162e3..2796d2218 100644 --- a/modules/config/service/boss.go +++ b/modules/config/service/boss.go @@ -15,7 +15,11 @@ func NewBossService() *BossService { Model: model.NewBossConfig(), PageQueryOp: &cool.QueryOp{ KeyWordField: []string{"desc"}, - FieldEQ: []string{"boss_id", "map_id"}, + FieldEQ: []string{"map_id"}, + }, + ListQueryOp: &cool.QueryOp{ + KeyWordField: []string{"desc"}, + FieldEQ: []string{"map_id", "parentId"}, }, }, } diff --git a/modules/config/service/map.go b/modules/config/service/map.go index efe885f96..6240a22fa 100644 --- a/modules/config/service/map.go +++ b/modules/config/service/map.go @@ -15,6 +15,7 @@ func NewMapService() *MapService { Model: model.NewMapConfig(), PageQueryOp: &cool.QueryOp{ KeyWordField: []string{"remake"}, + FieldEQ: []string{"map_id"}, }, }, } diff --git a/modules/config/service/map_boos.go b/modules/config/service/map_boos.go index 786701826..c908917ea 100644 --- a/modules/config/service/map_boos.go +++ b/modules/config/service/map_boos.go @@ -12,7 +12,7 @@ type MapBossService struct { func NewMapBossService() *MapBossService { return &MapBossService{ &cool.Service{ - Model: model.NewMapBoss(), + Model: model.NewMapNode(), PageQueryOp: &cool.QueryOp{ KeyWordField: []string{"remake"}, FieldEQ: []string{"map_id"},