diff --git a/common/data/xmlres/file.go b/common/data/xmlres/file.go index 8b885d8a4..9f9005097 100644 --- a/common/data/xmlres/file.go +++ b/common/data/xmlres/file.go @@ -49,10 +49,18 @@ func initfile() { }) Skill := getXml[MovesTbl](path + "227.xml") - SkillMap = utils.ToMap[Move, int](Skill.Moves, func(m Move) int { - return m.ID + // SkillMap = utils.ToMap[Move, int](Skill.Moves, func(m Move) int { + + // return m.ID + + // }) + SkillMap = make(map[int]Move, len(Skill.Moves)) + for _, v := range Skill.Moves { + v.SideEffectS = parseSideEffectArgs(v.SideEffect) + v.SideEffectArgS = parseSideEffectArgs(v.SideEffectArg) + SkillMap[v.ID] = v + } - }) pet := getXml[Monsters](path + "226.xml") PetMAP = utils.ToMap[PetInfo, int](pet.Monsters, func(m PetInfo) int { return m.ID diff --git a/common/data/xmlres/pet.go b/common/data/xmlres/pet.go index 8a9aec5a4..334d9f7a8 100644 --- a/common/data/xmlres/pet.go +++ b/common/data/xmlres/pet.go @@ -20,11 +20,11 @@ type PetInfo struct { Type int `xml:"Type,attr"` //类型 GrowthType int `xml:"GrowthType,attr"` //成长类型 HP int `xml:"HP,attr"` //血量种族值 - Atk int `xml:"Atk,attr"` - Def int `xml:"Def,attr"` - SpAtk int `xml:"SpAtk,attr"` - SpDef int `xml:"SpDef,attr"` - Spd int `xml:"Spd,attr"` + Atk uint32 `xml:"Atk,attr"` //攻击种族值 + Def uint32 `xml:"Def,attr"` + SpAtk uint32 `xml:"SpAtk,attr"` + SpDef uint32 `xml:"SpDef,attr"` + Spd uint32 `xml:"Spd,attr"` YieldingExp int `xml:"YieldingExp,attr"` CatchRate string `xml:"CatchRate,attr"` YieldingEV string `xml:"YieldingEV,attr"` diff --git a/common/data/xmlres/skill.go b/common/data/xmlres/skill.go index be806491e..720b344d4 100644 --- a/common/data/xmlres/skill.go +++ b/common/data/xmlres/skill.go @@ -5,9 +5,28 @@ import ( "fmt" "io" "net/http" + "strconv" + "strings" "time" ) +func parseSideEffectArgs(argsStr string) []int { + if argsStr == "" { + return []int{} + } + + parts := strings.Fields(argsStr) + args := make([]int, 0, len(parts)) + + for _, part := range parts { + if num, err := strconv.Atoi(part); err == nil { + args = append(args, num) + } + } + + return args +} + // MovesTbl 定义 XML 根元素 type MovesTbl struct { XMLName xml.Name `xml:"MovesTbl"` @@ -43,15 +62,18 @@ type Move struct { PwrBindDv int `xml:"PwrBindDv,attr,omitempty"` //威力(power)取决于自身的潜力(个体值) PwrDouble int `xml:"PwrDouble,attr,omitempty"` //攻击时,若对方处于异常状态, 则威力翻倍; - SideEffect string `xml:"SideEffect,attr,omitempty"` - SideEffectArg string `xml:"SideEffectArg,attr,omitempty"` - AtkNum int `xml:"AtkNum,attr,omitempty"` - Url string `xml:"Url,attr,omitempty"` + SideEffect string `xml:"SideEffect,attr,omitempty"` + SideEffectArg string `xml:"SideEffectArg,attr,omitempty"` + SideEffectS []int + SideEffectArgS []int + AtkNum int `xml:"AtkNum,attr,omitempty"` + Url string `xml:"Url,attr,omitempty"` Info string `xml:"info,attr,omitempty"` CD int `xml:"CD,attr"` } + type SideEffect struct { ID int `xml:"ID,attr"` Help string `xml:"help,attr"` diff --git a/common/data/xmlres/xml_test.go b/common/data/xmlres/xml_test.go index 8eaaf2f4f..620e3836a 100644 --- a/common/data/xmlres/xml_test.go +++ b/common/data/xmlres/xml_test.go @@ -50,6 +50,7 @@ var s = ` func Test_main(t *testing.T) { initfile() + fmt.Println(SkillMap[10073]) } diff --git a/logic/controller/fight.go b/logic/controller/fight.go index da198c243..5c9837867 100644 --- a/logic/controller/fight.go +++ b/logic/controller/fight.go @@ -17,7 +17,7 @@ import ( func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { ttt := info.NoteReadyToFightInfo{ - OwnerID: data.Head.UserID, + FightId: 3, } @@ -45,7 +45,7 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn } c.FightC = &service.FightC{} c.FightC.NewFight(&ttt, c) //把两个玩家都传进去 - + c.FightC.OwnerID = c.Info.UserID return nil, -1 } @@ -64,7 +64,7 @@ func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInbou // 使用技能包 func (h Controller) UseSkill(data *fight.UseSkillInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { - + c.FightC.UseSkill(c, data.SkillId) return nil, 0 } diff --git a/logic/service/ai.go b/logic/service/ai.go index 72e076c05..99b07b239 100644 --- a/logic/service/ai.go +++ b/logic/service/ai.go @@ -2,7 +2,6 @@ package service import ( "blazing/logic/service/fight/info" - "blazing/modules/blazing/model" "fmt" ) @@ -22,9 +21,10 @@ func (f *AI_player) MapID() uint32 { panic("not implemented") // TODO: Implement } -func (f *AI_player) GetInfo() model.PlayerInfo { - panic("not implemented") // TODO: Implement -} +// func (f *AI_player) GetInfo() model.PlayerInfo { +// return f.FightC.Opp. + +// } func (f *AI_player) SendPack(b []byte) error { panic("not implemented") // TODO: Implement diff --git a/logic/service/fight/battle/node/node.go b/logic/service/fight/battle/node/node.go index 3182d3f1d..928dac123 100644 --- a/logic/service/fight/battle/node/node.go +++ b/logic/service/fight/battle/node/node.go @@ -77,20 +77,14 @@ func (this *EffectNode) GetSkill() *info.BattleSkillEntity { } // 获取对方精灵 -func (this *EffectNode) GetBattle() *info.Battle1V1 { - pet, _ := this.Ctx.Value(info.BattleContainerCtx).(*info.Battle1V1) - return pet +// // 获取我方输入源 +// func (this *EffectNode) GetInput() *info.BattleInputSourceEntity { +// pet, _ := this.Ctx.Value(info.Input_ctx).(*info.BattleInputSourceEntity) -} +// return pet -// 获取我方输入源 -func (this *EffectNode) GetInput() *info.BattleInputSourceEntity { - pet, _ := this.Ctx.Value(info.Input_ctx).(*info.BattleInputSourceEntity) - - return pet - -} +// } // 获取自身精灵 func (this *EffectNode) GetOwnerPet() *info.BattlePetEntity { diff --git a/logic/service/fight/battle/skill/effect/base/base.go b/logic/service/fight/battle/skill/effect/base/base.go deleted file mode 100644 index 02f3e57a8..000000000 --- a/logic/service/fight/battle/skill/effect/base/base.go +++ /dev/null @@ -1,36 +0,0 @@ -package base - -// 生命周期管理器 -type LifeCycle struct { - remainTurn int // 剩余回合(-1 表示不限回合) - remainCount int // 剩余次数(-1 表示不限次数) -} - -// 创建一个回合持续类效果 -func NewTurnLife(turns int) LifeCycle { - return LifeCycle{remainTurn: turns, remainCount: -1} -} - -// 创建一个次数持续类效果 -func NewCountLife(count int) LifeCycle { - return LifeCycle{remainTurn: -1, remainCount: count} -} - -// 每回合 tick -func (lc *LifeCycle) Tick() { - if lc.remainTurn > 0 { - lc.remainTurn-- - } -} - -// 使用一次 -func (lc *LifeCycle) Use() { - if lc.remainCount > 0 { - lc.remainCount-- - } -} - -// 是否还活跃 -func (lc *LifeCycle) Alive() bool { - return (lc.remainTurn != 0) && (lc.remainCount != 0) -} diff --git a/logic/service/fight/info/BattleAction.go b/logic/service/fight/info/BattleAction.go index 0b25082a7..8136f78b7 100644 --- a/logic/service/fight/info/BattleAction.go +++ b/logic/service/fight/info/BattleAction.go @@ -1,8 +1,6 @@ package info import ( - "context" - "github.com/tnnmigga/enum" ) @@ -17,14 +15,18 @@ var PlayerOperations = enum.New[struct { ActiveSwitch EnumPlayerOperation `enum:"2"` //`enum:"主动切换(中切)"` UsePotion EnumPlayerOperation `enum:"3"` //`enum:"使用药剂"` 捕捉 逃跑 - Escape EnumPlayerOperation `enum:"4"` //`enum:"使用药剂"` 逃跑 等级最高 + Escape EnumPlayerOperation `enum:"4"` //`enum:"使用药剂"` 逃跑 等级最高 ,以及掉线 + //DeathSwitch EnumPlayerOperation `enum:"4"` //`enum:"死亡切换"` 这两个本质上还是对action的比较 // ExpelledSwitch EnumPlayerOperation `enum:"5"` //`enum:"(被)驱逐切换"` }]() type BattleAction struct { + PlayerID uint32 Priority EnumPlayerOperation //优先级本质上是action的itoa - ctx context.Context + Skill BattleSkillEntity + PetInfo BattlePetEntity + //ctx context.Context } // Compare 比较两个1v1战斗动作的执行优先级(核心逻辑) @@ -39,20 +41,15 @@ func (c *BattleAction) Compare(a *BattleAction) *BattleAction { } if a.Priority == 0 { - skillo, _ := a.ctx.Value(BattleSkillEntityCtx).(*BattleSkillEntity) - skillt, _ := a.ctx.Value(BattleSkillEntityCtx).(*BattleSkillEntity) - // 使用技能 - p2 := skillo.Priority - skillt.Priority + p2 := a.Skill.Priority - c.Skill.Priority //对方减自己 if p2 > 0 { return a } else if p2 < 0 { return c } - peto, _ := a.ctx.Value(Pet_O_Ctx).(*BattlePetEntity) - pett, _ := a.ctx.Value(Pet_O_Ctx).(*BattlePetEntity) - p2 = int(peto.info.Speed) - int(pett.info.Speed) // 假设 Use1v1SkillAction 有 SkillPriority() 方法 + p2 = int(a.PetInfo.Value(4)) - int(c.PetInfo.Value(4)) // 假设 Use1v1SkillAction 有 SkillPriority() 方法 if p2 > 0 { return a } else if p2 < 0 { diff --git a/logic/service/fight/info/BattleInputSourceEntity.go b/logic/service/fight/info/BattleInputSourceEntity.go deleted file mode 100644 index abc93ba3e..000000000 --- a/logic/service/fight/info/BattleInputSourceEntity.go +++ /dev/null @@ -1,35 +0,0 @@ -package info - -import ( - "context" -) - -const Input_ctx = "player" - -type BattleInputSourceEntity struct { - FightUserInfo //用户信息 - PetEntities []*BattlePetEntity //宠物信息 - ctx context.Context //输入源的上下文 - -} - -// 新建一个宠物 -func (u *BattleInputSourceEntity) NewBattlePetEntity(ctx context.Context) { - - ret := BattlePetEntity{} - - //ret.UnitAttributes = make(map[EnumAttrType]*Attribute) - //todo 待实现精灵特性+加成的封装 - ctx = context.WithValue(ctx, Input_ctx, &ret) //添加用户到上下文 - ret.ctx = ctx - -} -func (u *BattleInputSourceEntity) NewBattleAction(ctx context.Context, actiontype EnumPlayerOperation) { - - ret := BattleAction{ - Priority: actiontype, - } - ctx = context.WithValue(ctx, Input_ctx, &ret) //添加用户到上下文 - ret.ctx = ctx - -} diff --git a/logic/service/fight/info/BattlePetEntity.go b/logic/service/fight/info/BattlePetEntity.go index b06c858f4..0eff0fda1 100644 --- a/logic/service/fight/info/BattlePetEntity.go +++ b/logic/service/fight/info/BattlePetEntity.go @@ -6,6 +6,7 @@ import ( "blazing/modules/blazing/model" "context" "sync" + "unsafe" ) // 战斗属性类型 @@ -15,18 +16,20 @@ type EnumAttrType int const Pet_O_Ctx = "PET_O" const Pet_T_Ctx = "PET_T" -// 属性封装结构:Ext 存储临时血量增量(key=状态ID,value=增量值) -type Attribute struct { - //CanSet bool // 是否允许修改 - originalValue int +// 这里获得攻击,防御,特工,特防,速度 +func (a *BattlePetEntity) Value(tt uint32) uint32 { - Stat int //提升等级 - //Ext map[string]interface{} // 例如:{"buff_hp_123": 200} 存储临时血量增量 -} + offsetAtk := unsafe.Offsetof(a.info.Attack) // c字段的偏移量(通常为4+16=20) + // 2. 将结构体指针转换为原始内存地址(uintptr) + baseAddr := uintptr(unsafe.Pointer(&offsetAtk)) -func (a *Attribute) Value() int64 { + addrA := unsafe.Pointer(baseAddr + 4*uintptr(tt)) //根据0是攻击 + offsetAtkP := unsafe.Offsetof(a.Prop.Attack) // c字段的偏移量(通常为4+16=20) + // 2. 将结构体指针转换为原始内存地址(uintptr) + baseAddrp := uintptr(unsafe.Pointer(&offsetAtkP)) - return calculateRealValue(int64(a.originalValue), a.Stat) + addrB := unsafe.Pointer(baseAddrp + 4*uintptr(tt)) //根据0是攻击 + return uint32(calculateRealValue(int64(*(*uint32)(addrA)), int(*(*byte)(addrB)))) } type BattlePetEntity struct { @@ -36,7 +39,9 @@ type BattlePetEntity struct { Capturable bool // 是否可捕获 statusConditions sync.Map // key: StatusCondition, value: int (剩余回合) skills [4]*BattleSkillEntity // 技能槽(最多4个技能) - + Status StatusDict //精灵的状态 + //能力提升属性 + Prop PropDict } // calculateRealValue 计算实际属性值根据状态变化计算实际值 @@ -64,15 +69,6 @@ func calculateRealValue(value int64, stat int) int64 { } } -// 新建一个宠物 -func (u *BattlePetEntity) NewBattleSkillEntity(ctx context.Context, id, pp int) { - - ret := CreateBattleSkillWithInfinity(id, pp) //创建PP - ctx = context.WithValue(ctx, "pet", &ret) //添加用户到上下文 - ret.ctx = ctx - -} - func (u *BattlePetEntity) Type() element.ElementType { //todo 待实现获取精灵的类型 diff --git a/logic/service/fight/info/BattleSkillEntity.go b/logic/service/fight/info/BattleSkillEntity.go index 5e5f712b9..c8691d0e1 100644 --- a/logic/service/fight/info/BattleSkillEntity.go +++ b/logic/service/fight/info/BattleSkillEntity.go @@ -3,12 +3,10 @@ package info import ( element "blazing/common/data/Element" "blazing/common/data/xmlres" - "blazing/common/utils/random" "context" "fmt" "strconv" - "strings" "github.com/gogf/gf/v2/os/glog" "github.com/shopspring/decimal" @@ -36,15 +34,11 @@ var Category = enum.New[struct { // 战斗中可以修改技能实体值,比如是否暴击,是否必中等 type BattleSkillEntity struct { xmlres.Move - ctx context.Context - SideEffects []int - SideEffectArgs []int - PP int - InfinityPP bool - DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值 - - ATTACK_COUNT_ZONE int //攻击次数 - DamageValue decimal.Decimal // 伤害值 + // SideEffects []int + // SideEffectArgs []int + PP int + DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值 + DamageValue decimal.Decimal // 伤害值 // 技能类型属性 //SkillType EnumCategory // 技能类型(物理/特殊/状态) @@ -52,28 +46,30 @@ type BattleSkillEntity struct { } // CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP) -func CreateBattleSkillWithInfinity(id int, pp int) *BattleSkillEntity { +func CreateBattleSkillWithInfinity(id uint32) *BattleSkillEntity { //如果PP是-1 ,那就是无限PP // ID小于10001的视为无效技能 + if id < 10001 { return nil } - + var ret BattleSkillEntity // 从资源仓库获取技能数据 - move, ok := xmlres.SkillMap[id] + move, ok := xmlres.SkillMap[int(id)] + if !ok { glog.Error(context.Background(), "技能ID无效", "id", id) } - var ret BattleSkillEntity - // 解析副作用参数 - sideEffectArgs := parseSideEffectArgs(move.SideEffectArg) - tt := strings.Split(move.SideEffect, " ") - rf, err := strSliceToIntSlice(tt) - if err == nil { - ret.SideEffects = rf - } + ret.Move = move + // // 解析副作用参数 + // sideEffectArgs := parseSideEffectArgs(move.SideEffectArg) + // tt := strings.Split(move.SideEffect, " ") + // rf, err := strSliceToIntSlice(tt) + // if err == nil { + // ret.SideEffects = rf + // } - ret.SideEffectArgs = sideEffectArgs + // ret.SideEffectArgs = sideEffectArgs ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型 for _, v := range enum.Values[EnumCategory](Category) { @@ -122,15 +118,6 @@ func (s *BattleSkillEntity) Type() element.ElementType { return element.ElementType(s.Move.Type) } -// 技能产生动作 -func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) { - - ret := BattleAction{} - ctx = context.WithValue(ctx, BattleSkillEntityCtx, &ret) //添加用户到上下文 - ret.ctx = ctx - -} - // // 技能产生effect // func (u *BattleSkillEntity) NewEffect(ctx context.Context)*node.EffectNode { @@ -140,22 +127,6 @@ func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) { // } // 解析副作用参数字符串为整数列表 -func parseSideEffectArgs(argsStr string) []int { - if argsStr == "" { - return []int{} - } - - parts := strings.Fields(argsStr) - args := make([]int, 0, len(parts)) - - for _, part := range parts { - if num, err := strconv.Atoi(part); err == nil { - args = append(args, num) - } - } - - return args -} // 获取技能名称,为空时使用ID func getSkillName(move *BattleSkillEntity) string { @@ -166,12 +137,12 @@ func getSkillName(move *BattleSkillEntity) string { } // 获取副作用列表,处理空值情况 -func getSideEffects(move *BattleSkillEntity) []int { - if move.SideEffect == "" { - return []int{} - } - return move.SideEffects -} +// func getSideEffects(move *BattleSkillEntity) []int { +// if move.SideEffect == "" { +// return []int{} +// } +// return move.SideEffects +// } type EnumsZoneType int @@ -185,12 +156,12 @@ var DamageC = enum.New[struct { reduction EnumsZoneType // 减伤区 }]() -func (s *BattleSkillEntity) Random() *random.RandomXS128 { - battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1) +// func (s *BattleSkillEntity) Random() *random.RandomXS128 { +// battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1) - return battle.Rand +// return battle.Rand -} +// } // 获得指定的+-区 func (s *BattleSkillEntity) GetAddValue(e EnumCategory, c EnumsZoneType) decimal.Decimal { @@ -253,12 +224,13 @@ func (s *BattleSkillEntity) PutDamageZone(e EnumCategory, dtype EnumsZoneType, v // } } -func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) { - pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity) - return pet, ok +// func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) { +// pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity) -} +// return pet, ok + +// } // 暴击伤害 返回暴击率和是否暴击 func (s *BattleSkillEntity) CriticalRate() decimal.Decimal { @@ -267,16 +239,16 @@ func (s *BattleSkillEntity) CriticalRate() decimal.Decimal { } -func (s *BattleSkillEntity) criticalrandom() decimal.Decimal { - //这里应该算上威力区 - // 初始化随机值,范围217~255 +// func (s *BattleSkillEntity) criticalrandom() decimal.Decimal { +// //这里应该算上威力区 +// // 初始化随机值,范围217~255 - randomnum := s.Random().NextLongN(39) + 217 - // 10. 随机倍率,随机值除以255 - randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255)) - return randomFactor +// randomnum := s.Random().NextLongN(39) + 217 +// // 10. 随机倍率,随机值除以255 +// randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255)) +// return randomFactor -} +// } // // 计算技能威力 // func (s *BattleSkillEntity) CalculatePower(p *BattlePetEntity) int64 { diff --git a/logic/service/fight/info/battle.go b/logic/service/fight/info/battle.go index 1b25fbc5e..c9b0e6a43 100644 --- a/logic/service/fight/info/battle.go +++ b/logic/service/fight/info/battle.go @@ -1,28 +1,26 @@ package info import ( - "blazing/common/utils/random" - "github.com/tnnmigga/enum" ) -type Battle struct { - Rand *random.RandomXS128 //本次战斗随机数 - same []BattleInputSourceEntity //同阵营 - Round int //回合数 - BattleMode EnumBattleMode //战斗模式 - opposite []BattleInputSourceEntity //不同阵营 - Effects *NodeManager //挂载effect,实际上是给每个输入源,然后触发时候循环调用Effects , +// type Battle struct { +// Rand *random.RandomXS128 //本次战斗随机数 +// same []BattleInputSourceEntity //同阵营 +// Round int //回合数 +// BattleMode EnumBattleMode //战斗模式 +// opposite []BattleInputSourceEntity //不同阵营 +// Effects *NodeManager //挂载effect,实际上是给每个输入源,然后触发时候循环调用Effects , - //A的effect->触发死亡->这时候就应该调用对手的切换,实现effect62 -} +// //A的effect->触发死亡->这时候就应该调用对手的切换,实现effect62 +// } // 执行下一回合 -func (b *Battle) NextRound() { +// func (b *Battle) NextRound() { - b.Round++ //回合数加1 +// b.Round++ //回合数加1 -} +// } // 战斗模式 type EnumBattleMode int diff --git a/logic/service/fight/info/battle_1v1.go b/logic/service/fight/info/battle_1v1.go deleted file mode 100644 index 533773391..000000000 --- a/logic/service/fight/info/battle_1v1.go +++ /dev/null @@ -1,51 +0,0 @@ -package info - -import ( - "blazing/common/utils/random" - - "context" - "time" -) - -type Battle1V1 struct { - Battle - Ownerid uint32 // 房主ID - FirstPerson uint32 //先手方ID - -} - -// 返回房主信息 -func (b *Battle1V1) Owner() *BattleInputSourceEntity { - - return &b.same[0] -} - -// 返回邀请者信息,比如野怪 -func (b *Battle1V1) Target() *BattleInputSourceEntity { - - return &b.opposite[0] -} -func NewBattleContainer1v1(i NoteReadyToFightInfo) *Battle1V1 { - - ret := Battle1V1{} - ret.same = make([]BattleInputSourceEntity, 0) //初始化本阵营 - ret.opposite = make([]BattleInputSourceEntity, 0) //初始化敌方阵营 - - ret.same = append(ret.same, BattleInputSourceEntity{ - FightUserInfo: i.OurInfo, - //todo 待初始化精灵实体 - - }) //添加战斗实体 - ret.opposite = append(ret.same, BattleInputSourceEntity{ - FightUserInfo: i.OpponentInfo, - }) - ret.Ownerid = i.OwnerID //房主ID - - ret.Rand = random.NewRandomXS128WithTwoSeeds(uint64(ret.Ownerid), uint64(time.Now().Unix())) - ctx := context.Background() - context.WithValue(ctx, BattleContainerCtx, &ret) //传入容器的上下文 - - return &ret -} - -const BattleContainerCtx = "battle" diff --git a/logic/service/fight/info/info.go b/logic/service/fight/info/info.go index a6d98b4e0..cfaf753e7 100644 --- a/logic/service/fight/info/info.go +++ b/logic/service/fight/info/info.go @@ -77,18 +77,18 @@ type StatusDict struct { // 精灵的能力提升 type PropDict struct { // 攻击(@UInt long → uint32) - Attack uint32 `struc:"[1]byte"` + Attack byte // 防御(@UInt long → uint32) - Defence uint32 `struc:"[1]byte"` + Defence byte // 特攻(@UInt long → uint32) - SpecialAttack uint32 `struc:"[1]byte"` + SpecialAttack byte // 特防(@UInt long → uint32) - SpecialDefence uint32 `struc:"[1]byte"` + SpecialDefence byte // 速度(@UInt long → uint32) - Speed uint32 `struc:"[1]byte"` + Speed byte // 命中(@UInt long → uint32) - Accuracy uint32 `struc:"[1]byte"` + Accuracy byte } // BattleLevels 战斗属性等级结构体,对应原6字节数组 diff --git a/logic/service/fightc.go b/logic/service/fightc.go index 29b8a2b16..a3a8ecacc 100644 --- a/logic/service/fightc.go +++ b/logic/service/fightc.go @@ -2,8 +2,8 @@ package service import ( "blazing/logic/service/fight/info" - "blazing/modules/blazing/model" "fmt" + "math/rand" "time" "github.com/jinzhu/copier" @@ -12,167 +12,147 @@ import ( type PlayerI interface { ID() uint32 MapID() uint32 - GetInfo() model.PlayerInfo + //GetInfo() info.BattlePetEntity SendPack(b []byte) error SendReadyToFightInfo(info.FightStartOutboundInfo) SendNoteReadyToFightInfo(info.NoteReadyToFightInfo) } + type FightC struct { - Info *info.NoteReadyToFightInfo - Our PlayerI - Opp PlayerI - MAXPET uint32 //,最大精灵数 - //战斗发起者ID - OwnerID uint32 - //玩家拥有者是否准备完成 + Info *info.NoteReadyToFightInfo + Our PlayerI + Opp PlayerI + MAXPET uint32 // 最大精灵数 + OwnerID uint32 // 战斗发起者ID AFinished bool BFinished bool + //random *rand.Rand //随机数种子 + StartTime time.Time + actionChan chan info.BattleAction // 所有操作统一从这里进入 + Round int //回合数 } -// 使用技能 +// 玩家使用技能 func (f *FightC) UseSkill(c PlayerI, id uint32) { + ret := info.BattleAction{ + PlayerID: c.ID(), + Priority: info.PlayerOperations.SelectSkill, + // Skill: info.CreateBattleSkillWithInfinity(id), + } + + f.actionChan <- ret } + +// 战斗准备 func (f *FightC) ReadyFight(c PlayerI) { - rett := info.FightStartOutboundInfo{} - copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) //复制自己的信息 - switch f.Info.FightId { //判断战斗类型 - case 1: - //1v1 - if c == f.Our { //这个时候是房主发来的消息 - f.Info.AFinished = true - if f.Info.BFinished { + copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) // 复制自己的信息 - copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0]) //复制对方信息 + switch f.Info.FightId { + case 1: // 1v1 + if c == f.Our { + f.AFinished = true + if f.BFinished { + copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0]) f.Our.SendReadyToFightInfo(rett) f.Opp.SendReadyToFightInfo(rett) } - } else { - f.Our = c - f.Info.BFinished = true - if f.Info.AFinished { //如果房主完成 - - copier.Copy(&rett.Info2, &f.Info.OurPetList[0]) //复制房主信息,因为这时候不是房主发来的消息 + f.Opp = c + f.BFinished = true + if f.AFinished { + copier.Copy(&rett.Info2, &f.Info.OurPetList[0]) f.Our.SendReadyToFightInfo(rett) f.Opp.SendReadyToFightInfo(rett) } } - - case 3: //野怪战斗 - + case 3: // 野怪战斗 copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0]) rett.Info1.UserID = f.Info.OurInfo.UserID f.Our.SendReadyToFightInfo(rett) f.Opp.SendReadyToFightInfo(rett) } +} +func (f *FightC) Random() { + //先产生战斗的随机数 + // 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子 + + seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息 + rand.Seed(seed) } + +// 创建新战斗 func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI) { + f.Our = plays f.Info = i + f.StartTime = time.Now() + f.actionChan = make(chan info.BattleAction, 2) // 初始化全局操作通道 - f.Info.FightId = i.FightId switch i.FightId { case 1: - //1v1 - - case 3: //野怪战斗 + // 1v1,等双方进入 + case 3: // 野怪战斗 plays.SendNoteReadyToFightInfo(*i) - f.Opp = &AI_player{ - fightinfo: *i, - } - - //这时候应该建立一个虚拟的player - + f.Opp = &AI_player{fightinfo: *i, FightC: f} // 创建虚拟对手 } - f.battleLoop() + go f.battleLoop() // 起战斗循环 } -// 定义操作类型,存储玩家的操作信息(如技能选择、目标等) -type Action struct { - PlayerID int // 玩家ID:1或2 - SkillID int // 使用的技能ID - TargetID int // 目标ID -} - +// 战斗回合循环 func (f *FightC) battleLoop() { - for { // 战斗回合循环 - // 每个回合重置:创建两个通道接收双方操作 - p1ActionChan := make(chan Action) // 玩家1的操作通道 - p2ActionChan := make(chan Action) // 玩家2的操作通道 + for { + f.Round++ //回合数自增 + actions := make(map[uint32]info.BattleAction) // 每个玩家一条记录 + timeout := time.After(60 * time.Second) - // 启动goroutine处理双方输入(实际项目中这里会绑定用户输入逻辑) - go handlePlayerInput(1, p1ActionChan) - go handlePlayerInput(2, p2ActionChan) - - // 等待双方操作或超时 - var p1Action, p2Action Action - var p1Done, p2Done bool - timeout := time.After(60 * time.Second) // 60秒超时 - - // 循环等待双方都完成操作 - for !(p1Done && p2Done) { + for len(actions) < 2 { select { - case action := <-p1ActionChan: - p1Action = action - p1Done = true - fmt.Printf("玩家%d已选择技能%d\n", action.PlayerID, action.SkillID) - case action := <-p2ActionChan: - p2Action = action - p2Done = true - fmt.Printf("玩家%d已选择技能%d\n", action.PlayerID, action.SkillID) + case action := <-f.actionChan: + // 只接受有效玩家 ID + if action.PlayerID != f.Our.ID() && action.PlayerID != f.Opp.ID() { + continue + } + // 如果该玩家已经提交过,就忽略重复动作 + if _, exists := actions[uint32(action.PlayerID)]; exists { + fmt.Printf("玩家%d 已经提交过动作,忽略重复\n", action.PlayerID) + continue + } + + actions[uint32(action.PlayerID)] = action + fmt.Printf("玩家%d 执行动作", action.PlayerID) + case <-timeout: - // 超时处理:未操作的视为放弃 - fmt.Println("操作超时,未操作方视为放弃本回合") - // 根据超时情况补充未完成的操作(如空操作) - if !p1Done { - p1Action = Action{PlayerID: 1, SkillID: 0} // 0表示放弃 + fmt.Println("回合操作超时") + if _, exists := actions[f.Our.ID()]; !exists { + actions[f.Our.ID()] = info.BattleAction{PlayerID: f.Our.ID(), Priority: info.PlayerOperations.SystemGiveUp} //系统选择出手 } - if !p2Done { - p2Action = Action{PlayerID: 2, SkillID: 0} + if _, exists := actions[f.Opp.ID()]; !exists { + actions[f.Opp.ID()] = info.BattleAction{PlayerID: f.Our.ID(), Priority: info.PlayerOperations.SystemGiveUp} //系统选择出手 } - p1Done = true - p2Done = true } } - // 双方都已操作,执行战斗计算 - fmt.Println("双方操作完成,开始计算本回合结果...") - calculateBattleResult(p1Action, p2Action) + // 双方动作齐了,取出来结算 + p1Action := actions[f.Our.ID()] + p2Action := actions[f.Opp.ID()] + fmt.Printf("开始结算回合") + fmt.Println(p1Action) + fmt.Println(p2Action) + // TODO: 在这里调用技能结算逻辑 - // 检查战斗是否结束(如一方血量为0) if isBattleEnd() { fmt.Println("战斗结束") - break + return } } } -// 模拟处理玩家输入(实际中会绑定UI或网络输入) -func handlePlayerInput(playerID int, actionChan chan<- Action) { - // 这里只是示例:实际中会等待用户输入(如点击技能按钮) - // 假设玩家1选择技能1,目标是玩家2;玩家2选择技能2,目标是玩家1 - time.Sleep(time.Second * 2) // 模拟思考时间 - if playerID == 1 { - actionChan <- Action{PlayerID: 1, SkillID: 1, TargetID: 2} - } else { - actionChan <- Action{PlayerID: 2, SkillID: 2, TargetID: 1} - } -} - -// 战斗计算逻辑(示例) -func calculateBattleResult(p1, p2 Action) { - // 实际项目中会根据技能ID计算伤害、 buff等 - fmt.Printf("玩家1使用技能%d攻击玩家%d,玩家2使用技能%d攻击玩家%d\n", - p1.SkillID, p1.TargetID, p2.SkillID, p2.TargetID) -} - -// 检查战斗是否结束(示例) +// 判断战斗是否结束 func isBattleEnd() bool { - // 实际中会判断双方血量等条件 - return false // 暂时返回false,持续战斗 + return false } diff --git a/login/main.go b/login/main.go index 4fb8b8491..0fde24317 100644 --- a/login/main.go +++ b/login/main.go @@ -34,6 +34,7 @@ var tt task.GetTaskBufOutboundInfo func main() { //Test_kick() + cmd.Main.Run(gctx.New()) }