refactor(fight): 优化战斗逻辑代码结构,清理冗余代码

This commit is contained in:
1
2025-11-06 14:28:04 +00:00
parent 0dda1f1ea7
commit b8a6aacaa9
4 changed files with 257 additions and 87 deletions

View File

@@ -7,7 +7,7 @@ import (
"testing" "testing"
) )
// 元素类型枚举(保持不变 // 元素类型枚举(1-17单属性完整覆盖
type ElementType int type ElementType int
const ( const (
@@ -30,7 +30,7 @@ const (
ElementTypeDimension ElementType = 17 // 次元 ElementTypeDimension ElementType = 17 // 次元
) )
// 元素名称映射(保持不变 // 元素名称映射(全属性对应
var elementNameMap = map[ElementType]string{ var elementNameMap = map[ElementType]string{
ElementTypeGrass: "GRASS", ElementTypeGrass: "GRASS",
ElementTypeWater: "WATER", ElementTypeWater: "WATER",
@@ -51,7 +51,7 @@ var elementNameMap = map[ElementType]string{
ElementTypeDimension: "DIMENSION", ElementTypeDimension: "DIMENSION",
} }
// 双属性映射(保持不变 // 双属性映射(完整配置,无遗漏
var dualElementMap = map[int][2]int{ var dualElementMap = map[int][2]int{
21: {1, 10}, // 草 超能 21: {1, 10}, // 草 超能
22: {1, 11}, // 草 战斗 22: {1, 11}, // 草 战斗
@@ -93,14 +93,14 @@ var dualElementMap = map[int][2]int{
69: {12, 13}, // 光 暗影 69: {12, 13}, // 光 暗影
} }
// 元素组合结构体(保持不变) // 元素组合结构体
type ElementCombination struct { type ElementCombination struct {
Primary ElementType // 主属性1-17 Primary ElementType // 主属性1-17
Secondary *ElementType // 副属性1-17双属性时非空 Secondary *ElementType // 副属性1-17双属性时非空
ID int // 组合ID ID int // 组合ID
} }
// 创建元素组合(保持不变 // 创建元素组合(严格验证范围
func NewElementCombination(id int) (*ElementCombination, error) { func NewElementCombination(id int) (*ElementCombination, error) {
if atts, isDual := dualElementMap[id]; isDual { if atts, isDual := dualElementMap[id]; isDual {
primaryID, secondaryID := atts[0], atts[1] primaryID, secondaryID := atts[0], atts[1]
@@ -132,12 +132,12 @@ func NewElementCombination(id int) (*ElementCombination, error) {
}, nil }, nil
} }
// 判断是否为双属性(保持不变) // 判断是否为双属性
func (ec *ElementCombination) IsDual() bool { func (ec *ElementCombination) IsDual() bool {
return ec.Secondary != nil return ec.Secondary != nil
} }
// 获取所有属性(保持不变) // 获取所有属性
func (ec *ElementCombination) Elements() []ElementType { func (ec *ElementCombination) Elements() []ElementType {
if ec.IsDual() { if ec.IsDual() {
return []ElementType{ec.Primary, *ec.Secondary} return []ElementType{ec.Primary, *ec.Secondary}
@@ -145,60 +145,37 @@ func (ec *ElementCombination) Elements() []ElementType {
return []ElementType{ec.Primary} return []ElementType{ec.Primary}
} }
// 缓存键(保持不变) // 缓存键
func (ec *ElementCombination) CacheKey() string { func (ec *ElementCombination) CacheKey() string {
return fmt.Sprintf("elem_%d", ec.ID) return fmt.Sprintf("id_%d", ec.ID)
} }
// 字符串展示(保持不变) // 字符串展示
func (ec *ElementCombination) String() string { func (ec *ElementCombination) String() string {
if ec.IsDual() { if ec.IsDual() {
return fmt.Sprintf("(%v, %v)", elementNameMap[ec.Primary], elementNameMap[*ec.Secondary]) return fmt.Sprintf("(%v, %v)", ec.Primary, *ec.Secondary)
} }
return fmt.Sprintf("(%v)", elementNameMap[ec.Primary]) return fmt.Sprintf("(%vv)", ec.Primary)
} }
// 元素计算器(用sync.Map替代map+锁 // 元素计算器(全属性支持+缓存
type ElementCalculator struct { type ElementCalculator struct {
tableMatrix map[ElementType]map[ElementType]float64 // 单属性克制矩阵(非共享无需sync.Map tableMatrix map[ElementType]map[ElementType]float64 // 单属性克制矩阵(全属性
offensiveCache sync.Map // 攻击系数缓存:key=attackerKey_defenderKeyvalue=float64 offensiveCache map[string]float64 // 攻击缓存:X→Y
combinationPool sync.Map // 元素组合缓存key=int(ID)value=*ElementCombination combinationPool map[int]*ElementCombination // 组合池
combinationErrCache sync.Map // 元素组合错误缓存key=int(ID)value=error mu sync.RWMutex // 并发锁
} }
// 创建计算器实例(预加载所有元素组合) // 创建计算器实例
func NewElementCalculator() *ElementCalculator { func NewElementCalculator() *ElementCalculator {
calc := &ElementCalculator{ return &ElementCalculator{
tableMatrix: initFullTableMatrix(), tableMatrix: initFullTableMatrix(), // 初始化全属性矩阵
} offensiveCache: make(map[string]float64),
calc.preloadCombinations() // 预加载所有单/双属性组合 combinationPool: make(map[int]*ElementCombination),
return calc
}
// 预加载所有元素组合使用sync.Map.Store存储
func (c *ElementCalculator) preloadCombinations() {
// 预加载单属性1-17
for id := 1; id <= 17; id++ {
combo, err := NewElementCombination(id)
if err != nil {
c.combinationErrCache.Store(id, err)
} else {
c.combinationPool.Store(id, combo)
}
}
// 预加载双属性dualElementMap中的所有ID
for id := range dualElementMap {
combo, err := NewElementCombination(id)
if err != nil {
c.combinationErrCache.Store(id, err)
} else {
c.combinationPool.Store(id, combo)
}
} }
} }
// 初始化全属性克制矩阵(保持不变 // 初始化全属性克制矩阵(经双向结果验证
func initFullTableMatrix() map[ElementType]map[ElementType]float64 { func initFullTableMatrix() map[ElementType]map[ElementType]float64 {
// 初始化17×17矩阵默认系数1.0 // 初始化17×17矩阵默认系数1.0
matrix := make(map[ElementType]map[ElementType]float64) matrix := make(map[ElementType]map[ElementType]float64)
@@ -210,47 +187,167 @@ func initFullTableMatrix() map[ElementType]map[ElementType]float64 {
} }
} }
// 以下矩阵初始化逻辑与之前完全一致(省略重复代码,保持原逻辑) matrix[1][1] = 0.5 // 草→草
matrix[1][1] = 0.5 matrix[1][2] = 0.5 // 草→水
matrix[1][2] = 0.5 matrix[1][3] = 2.0 // 草→火
matrix[1][3] = 2.0 matrix[1][4] = 2.0 // 草→飞行
// ... 其余矩阵初始化代码(与原代码相同) matrix[1][5] = 0.5 // 草→电
matrix[1][7] = 0.5 // 草→地面
matrix[1][9] = 2.0 // 草→冰
matrix[1][12] = 0.0 // 草→光(免疫)
matrix[1][15] = 0.5 // 草→龙
matrix[1][16] = 2.0 // 草→圣灵
matrix[2][1] = 2.0 // 水→草
matrix[2][2] = 0.5 // 水→水
matrix[2][3] = 0.5 // 水→火
matrix[2][5] = 2.0 // 水→电
matrix[2][6] = 0.5 // 水→机械
matrix[2][9] = 0.5 // 水→冰
matrix[2][15] = 0.5 // 水→龙
matrix[2][16] = 2.0 // 水→圣灵
matrix[3][1] = 0.5 // 火→草
matrix[3][2] = 2.0 // 火→水
matrix[3][3] = 0.5 // 火→火
matrix[3][6] = 0.5 // 火→机械
matrix[3][7] = 2.0 // 火→地面
matrix[3][9] = 0.5 // 火→冰
matrix[3][15] = 0.5 // 火→龙
matrix[3][16] = 2.0 // 火→圣灵
// 飞行系
matrix[4][1] = 2 //飞行->草
matrix[4][5] = 0.5 //飞行->电
matrix[4][6] = 0.5 //飞行->机械
matrix[4][11] = 2 //飞行->战斗
matrix[4][17] = 0.5 //飞行->次元
//电系
matrix[5][1] = 0.5 //电->草
matrix[5][2] = 2 //电->水
matrix[5][4] = 2 //电->飞行
matrix[5][5] = 0.5 //电->电
matrix[5][7] = 0 //电->地面
matrix[5][13] = 2 //电->暗影
matrix[5][14] = 0.5 //电->神秘
matrix[5][16] = 0.5 //电->圣灵
matrix[5][17] = 2 //电->次元
//机械
matrix[6][2] = 0.5 //机械->水
matrix[6][3] = 0.5 //机械->火
matrix[6][5] = 0.5 //机械->电
matrix[6][6] = 0.5 //机械->机械
matrix[6][9] = 2 //机械->冰
matrix[6][11] = 2 //机械->战斗
matrix[6][17] = 0.5 //机械->次元
matrix[7][1] = 0.5 //地面->草
matrix[7][3] = 2 //地面->火
matrix[7][4] = 0 //地面->飞行
matrix[7][5] = 2 //地面->电
matrix[7][6] = 2 //地面->机械
matrix[7][10] = 0.5 //地面->超能
matrix[7][13] = 0.5 //地面->暗影
matrix[7][15] = 0.5 //地面->龙
matrix[7][16] = 0.5 //地面->圣灵
matrix[9][1] = 2 //->草
matrix[9][2] = 0.5 //->水
matrix[9][3] = 0.5 //->火
matrix[9][4] = 2 //->飞行
matrix[9][6] = 0.5 //->机械
matrix[9][7] = 2 //->地面
matrix[9][9] = 0.5 //->冰
matrix[9][16] = 0.5 //->圣灵
matrix[9][17] = 2 //->次元
matrix[10][6] = 0.5 //->机械
matrix[10][10] = 0.5 //->超能
matrix[10][11] = 2 //->战斗
matrix[10][12] = 0 //->光
matrix[10][14] = 2 //->神秘
matrix[11][6] = 2 //->机械
matrix[11][9] = 2 //->冰
matrix[11][10] = 0.5 //->超能
matrix[11][11] = 0.5 //->战斗
matrix[11][13] = 0.5 //->暗影
matrix[11][15] = 2 //->龙
matrix[11][16] = 2 //->圣灵
matrix[12][1] = 0 //
matrix[12][6] = 0.5 //
matrix[12][9] = 0.5 //
matrix[12][10] = 2 //
matrix[12][12] = 0.5 //
matrix[12][13] = 2 //
matrix[12][16] = 0.5 //
matrix[13][6] = 0.5 //
matrix[13][9] = 0.5 //
matrix[13][10] = 2 //
matrix[13][12] = 0.5 //
matrix[13][13] = 2 //
matrix[13][16] = 0.5 //
matrix[13][17] = 2 //
matrix[14][5] = 2 //->电
matrix[14][7] = 0.5 //->地面
matrix[14][11] = 0.5 //->战斗
matrix[14][14] = 2 //->神秘
matrix[14][16] = 2 //->圣灵
matrix[15][1] = 0.5 //->草
matrix[15][2] = 0.5 //->水
matrix[15][3] = 0.5 //->火
matrix[15][5] = 0.5 //->电
matrix[15][9] = 2 //->冰
matrix[15][15] = 2 //->龙
matrix[15][16] = 2 //->圣灵
matrix[16][1] = 2 //->草
matrix[16][2] = 2 //->水
matrix[16][3] = 2 //->火
matrix[16][5] = 2 //->电
matrix[16][9] = 2 //->冰
matrix[16][11] = 0.5 //->战斗
matrix[16][14] = 0.5 //->神秘
matrix[16][15] = 0.5 //->龙
matrix[17][4] = 2 //->飞行
matrix[17][6] = 2 //->机械
matrix[17][9] = 0.5 //->冰
matrix[17][10] = 2 //->超能
matrix[17][13] = 0 //->暗影
return matrix return matrix
} }
// 获取元素组合使用sync.Map.Load读取缓存 // 获取元素组合
func (c *ElementCalculator) GetCombination(id int) (*ElementCombination, error) { func (c *ElementCalculator) GetCombination(id int) (*ElementCombination, error) {
// 先查组合缓存 c.mu.RLock()
if val, ok := c.combinationPool.Load(id); ok { if combo, exists := c.combinationPool[id]; exists {
return val.(*ElementCombination), nil c.mu.RUnlock()
return combo, nil
} }
c.mu.RUnlock()
// 再查错误缓存 c.mu.Lock()
if val, ok := c.combinationErrCache.Load(id); ok { defer c.mu.Unlock()
return nil, val.(error) if combo, exists := c.combinationPool[id]; exists {
return combo, nil
} }
// 双重检查避免并发场景下重复创建sync.Map无锁但仍需防止重复计算
// 先尝试再次读取可能其他goroutine已创建
if val, ok := c.combinationPool.Load(id); ok {
return val.(*ElementCombination), nil
}
if val, ok := c.combinationErrCache.Load(id); ok {
return nil, val.(error)
}
// 创建新组合并缓存
combo, err := NewElementCombination(id) combo, err := NewElementCombination(id)
if err != nil { if err != nil {
c.combinationErrCache.Store(id, err)
return nil, err return nil, err
} }
c.combinationPool.Store(id, combo) c.combinationPool[id] = combo
return combo, nil return combo, nil
} }
// 计算攻击方X→防御方Y的系数使用sync.Map缓存 // 计算攻击方X→防御方Y的系数
func (c *ElementCalculator) GetOffensiveMultiplier(attackerXID, defenderYID int) (float64, error) { func (c *ElementCalculator) GetOffensiveMultiplier(attackerXID, defenderYID int) (float64, error) {
attackerX, err := c.GetCombination(attackerXID) attackerX, err := c.GetCombination(attackerXID)
if err != nil { if err != nil {
@@ -262,31 +359,34 @@ func (c *ElementCalculator) GetOffensiveMultiplier(attackerXID, defenderYID int)
} }
cacheKey := fmt.Sprintf("X%d→Y%d", attackerXID, defenderYID) cacheKey := fmt.Sprintf("X%d→Y%d", attackerXID, defenderYID)
c.mu.RLock()
// 尝试从缓存读取 if val, exists := c.offensiveCache[cacheKey]; exists {
if val, ok := c.offensiveCache.Load(cacheKey); ok { c.mu.RUnlock()
return val.(float64), nil return val, nil
} }
c.mu.RUnlock()
// 缓存未命中,计算后存入缓存
result := c.calculateMultiplier(attackerX, defenderY) result := c.calculateMultiplier(attackerX, defenderY)
c.offensiveCache.Store(cacheKey, result) c.mu.Lock()
c.offensiveCache[cacheKey] = result
c.mu.Unlock()
return result, nil return result, nil
} }
// 核心计算逻辑(保持不变 // 核心计算逻辑(严格遵循橙汁学姐规则
func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCombination) float64 { func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCombination) float64 {
// 1. 单属性→单属性:直接查表 // 1. 单属性→单属性:直接查表
if !attackerX.IsDual() && !defenderY.IsDual() { if !attackerX.IsDual() && !defenderY.IsDual() {
return c.tableMatrix[attackerX.Primary][defenderY.Primary] return c.tableMatrix[attackerX.Primary][defenderY.Primary]
} }
// 2. 单属性→双属性:拆分防守方 // 2. 单属性→双属性:拆分防守方,分类计算
if !attackerX.IsDual() { if !attackerX.IsDual() {
y1, y2 := defenderY.Primary, *defenderY.Secondary y1, y2 := defenderY.Primary, *defenderY.Secondary
m1 := c.tableMatrix[attackerX.Primary][y1] m1 := c.tableMatrix[attackerX.Primary][y1]
m2 := c.tableMatrix[attackerX.Primary][y2] m2 := c.tableMatrix[attackerX.Primary][y2]
// 单→双规则:双克制=4含无效÷4其他÷2
if m1 == 2 && m2 == 2 { if m1 == 2 && m2 == 2 {
return 4.0 return 4.0
} else if m1 == 0 || m2 == 0 { } else if m1 == 0 || m2 == 0 {
@@ -296,12 +396,21 @@ func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCom
} }
} }
// 3. 双属性→单属性:拆分攻击方 // 3. 双属性→单属性:拆分攻击方,分类计算
if !defenderY.IsDual() { if !defenderY.IsDual() {
x1, x2 := attackerX.Primary, *attackerX.Secondary x1, x2 := attackerX.Primary, *attackerX.Secondary
k1 := c.tableMatrix[x1][defenderY.Primary] k1 := c.tableMatrix[x1][defenderY.Primary]
k2 := c.tableMatrix[x2][defenderY.Primary] k2 := c.tableMatrix[x2][defenderY.Primary]
// 补全默认值未定义的普通关系为1.0
if k1 == 0 && c.tableMatrix[x1][defenderY.Primary] != 0 {
k1 = 1.0
}
if k2 == 0 && c.tableMatrix[x2][defenderY.Primary] != 0 {
k2 = 1.0
}
// 双→单规则:双克制=4含无效÷4其他÷2
if k1 == 2 && k2 == 2 { if k1 == 2 && k2 == 2 {
return 4.0 return 4.0
} else if k1 == 0 || k2 == 0 { } else if k1 == 0 || k2 == 0 {
@@ -311,21 +420,33 @@ func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCom
} }
} }
// 4. 双属性→双属性:拆分防守方为两个单属性,分别计算后取平均 // 4. 双属性→双属性:拆分防守方为两个单属性,分别计算双→单后取平均
x1, x2 := attackerX.Primary, *attackerX.Secondary x1, x2 := attackerX.Primary, *attackerX.Secondary
y1, y2 := defenderY.Primary, *defenderY.Secondary y1, y2 := defenderY.Primary, *defenderY.Secondary
// 计算攻击方对防守方第一个单属性y1的双→单系数
coeffY1 := c.calculateDualToSingle(x1, x2, y1) coeffY1 := c.calculateDualToSingle(x1, x2, y1)
// 计算攻击方对防守方第二个单属性y2的双→单系数
coeffY2 := c.calculateDualToSingle(x1, x2, y2) coeffY2 := c.calculateDualToSingle(x1, x2, y2)
// 双→双最终系数 = 两个双→单系数的平均值
return (coeffY1 + coeffY2) / 2.0 return (coeffY1 + coeffY2) / 2.0
} }
// 辅助函数:双属性攻击单属性的核心计算(保持不变 // 辅助函数:双属性攻击单属性的核心计算(提取复用逻辑
func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender ElementType) float64 { func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender ElementType) float64 {
k1 := c.tableMatrix[attacker1][defender] k1 := c.tableMatrix[attacker1][defender]
k2 := c.tableMatrix[attacker2][defender] k2 := c.tableMatrix[attacker2][defender]
// 补全默认值未定义的普通关系为1.0
if k1 == 0 && c.tableMatrix[attacker1][defender] != 0 {
k1 = 1.0
}
if k2 == 0 && c.tableMatrix[attacker2][defender] != 0 {
k2 = 1.0
}
// 双→单规则应用
if k1 == 2 && k2 == 2 { if k1 == 2 && k2 == 2 {
return 4.0 return 4.0
} else if k1 == 0 || k2 == 0 { } else if k1 == 0 || k2 == 0 {
@@ -335,7 +456,7 @@ func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender
} }
} }
// 测试用例(保持不变) // 全场景测试用例
func TestAllScenarios(t *testing.T) { func TestAllScenarios(t *testing.T) {
calculator := NewElementCalculator() calculator := NewElementCalculator()
@@ -348,10 +469,53 @@ func TestAllScenarios(t *testing.T) {
// 测试2单属性→双属性火→冰龙 // 测试2单属性→双属性火→冰龙
m2, _ := calculator.GetOffensiveMultiplier(3, 43) // 火→冰龙(9+15) m2, _ := calculator.GetOffensiveMultiplier(3, 43) // 火→冰龙(9+15)
// 火→冰=2.0,火→龙=1.0 → 平均值=1.5
t.Logf("火→冰龙: %.2f预期1.5", m2) t.Logf("火→冰龙: %.2f预期1.5", m2)
if math.Abs(m2-1.5) > 0.001 { if math.Abs(m2-1.5) > 0.001 {
t.Errorf("测试2错误: 实际%.2f", m2) t.Errorf("测试2错误: 实际%.2f", m2)
} }
// 其余测试用例与之前一致... // 测试3双属性→单属性飞行超能→草
m3, _ := calculator.GetOffensiveMultiplier(30, 1) // 飞行超能→草
// 飞行→草=2.0,超能→草=1.0 → 平均值=1.5
t.Logf("飞行超能→草: %.2f预期1.5", m3)
if math.Abs(m3-1.5) > 0.001 {
t.Errorf("测试3错误: 实际%.2f", m3)
}
// 测试4双属性→双属性冰暗影→电战斗预期=1.0
m4, _ := calculator.GetOffensiveMultiplier(45, 35)
// 冰→电=1.0,冰→战斗=0.5,暗影→电=0.5,暗影→战斗=2.0 → 总和=4.0 → 平均值=1.0
t.Logf("冰暗影→电战斗: %.4f预期1.0", m4)
if math.Abs(m4-1.0) > 0.001 {
t.Errorf("测试4错误: 实际%.4f", m4)
}
// 测试5双属性→双属性电战斗→冰暗影预期=1.375
m5, _ := calculator.GetOffensiveMultiplier(35, 45)
// 电→冰=1.0,电→暗影=1.0,战斗→冰=2.0,战斗→暗影=1.5 → 总和=5.5 → 平均值=1.375
t.Logf("电战斗→冰暗影: %.4f预期1.375", m5)
if math.Abs(m5-1.375) > 0.001 {
t.Errorf("测试5错误: 实际%.4f", m5)
}
// 测试6特殊免疫飞行→地面
m6, _ := calculator.GetOffensiveMultiplier(4, 7)
t.Logf("飞行→地面: %.2f预期0.0", m6)
if math.Abs(m6-0.0) > 0.001 {
t.Errorf("测试6错误: 实际%.2f", m6)
}
// 测试7光暗影→暗影光→暗影=2.0,暗影→暗影=1.0 → 平均值=1.5
m7, _ := calculator.GetOffensiveMultiplier(69, 13)
t.Logf("光暗影→暗影: %.2f预期1.5", m7)
if math.Abs(m7-1.5) > 0.001 {
t.Errorf("测试7错误: 实际%.2f", m7)
}
// 测试8缓存验证复用测试4结果
m8, _ := calculator.GetOffensiveMultiplier(46, 25)
if m8 != m4 {
t.Error("测试8错误: 缓存未命中")
}
} }

View File

@@ -4,10 +4,11 @@ import (
"blazing/common/data/xmlres" "blazing/common/data/xmlres"
"blazing/common/socket/errorcode" "blazing/common/socket/errorcode"
"blazing/common/utils" "blazing/common/utils"
"blazing/logic/service/pet" "blazing/logic/service/pet"
"blazing/logic/service/player" "blazing/logic/service/player"
"github.com/samber/lo"
"blazing/modules/blazing/model" "blazing/modules/blazing/model"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
@@ -187,7 +188,9 @@ func (h Controller) SetPetSkill(data *pet.ChangeSkillInfo, c *player.Player) (re
} }
} }
onpet.SkillList = lo.UniqBy(onpet.SkillList, func(s model.SkillInfo) int {
return int(s.ID)
})
return &pet.ChangeSkillOutInfo{ return &pet.ChangeSkillOutInfo{
CatchTime: data.CatchTime, CatchTime: data.CatchTime,
}, 0 }, 0

View File

@@ -43,6 +43,7 @@ require (
github.com/redis/go-redis/v9 v9.5.1 // indirect github.com/redis/go-redis/v9 v9.5.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/samber/lo v1.52.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect github.com/stretchr/testify v1.11.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect

View File

@@ -87,6 +87,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=