| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- package model
- import (
- "container/heap"
- "math/rand"
- "rocommon/util"
- "roserver/baseserver/model"
- "roserver/baseserver/set"
- "roserver/serverproto"
- "sort"
- )
- ////////////////////////////////PlayerBoss
- type BossRoom struct {
- roomId int32
- uidList map[uint64]struct{}
- }
- func (this *BossRoom) AddUid(uid uint64) {
- this.uidList[uid] = struct{}{}
- }
- func (this *BossRoom) RemUid(uid uint64) {
- delete(this.uidList, uid)
- }
- type PlayerBoss struct {
- model.StateMachineCore
- mag *WorldBossManager
- bossUid uint64 //worldbosscfgid
- summonBossId int32 //bossCfgId
- summonBossType int32 //SummonBossType
- summonBossIdx int32 //召唤次数
- summonTime uint64 //召唤时间戳
- durationTime uint64 //boss持续时间s
- totalHp int32
- maxHp int32
- hpDirty bool
- SummonRewardList []*serverproto.KeyValueType //参与boss挑战奖励
- KillNormalRewardList, KillSpecialRewardList serverproto.KeyValueType //击杀参与奖 drop //击杀大奖 drop
- challengeList map[uint64]model.ClientID //当前正在挑战的玩家列表
- allChallengeList set.Interface //挑战玩家列表,包行当前正在挑战玩家
- challengeDataList map[uint64]*serverproto.FightRoleInfo //玩家数据
- maxPoint int32 //最大点数
- uidRoomList map[uint64]int32 //[uid,roomId]
- roomList map[int32]*BossRoom //[roomId,[uid...]]
- freeRoomList *model.MinHeap //[roomId]
- maxRoomId int32
- lastHPReduceTime uint64
- finish bool
- }
- func newPlayerBoss(mag *WorldBossManager) *PlayerBoss {
- playerBoss := &PlayerBoss{
- mag: mag,
- roomList: map[int32]*BossRoom{},
- uidRoomList: map[uint64]int32{},
- }
- playerBoss.challengeList = map[uint64]model.ClientID{}
- playerBoss.allChallengeList = set.New(set.NonThreadSafe)
- playerBoss.challengeDataList = map[uint64]*serverproto.FightRoleInfo{}
- //min heap
- playerBoss.freeRoomList = &model.MinHeap{}
- heap.Init(playerBoss.freeRoomList)
- return playerBoss
- }
- func (this *PlayerBoss) Init() {
- this.InitState()
- this.RegisterState(int32(BOSS_STATE_FIGHTING), bossStateFighting)
- this.RegisterState(int32(BOSS_STATE_DIED), bossStateDie)
- this.RegisterState(int32(BOSS_STATE_TIME_OUT), bossStateTimeout)
- }
- func (this *PlayerBoss) SetTotalHp(hp int32) {
- this.totalHp = hp
- this.maxHp = hp
- }
- func (this *PlayerBoss) clear() {
- for uid, _ := range this.challengeList {
- delete(this.mag.challengePlayerList, uid)
- delete(this.challengeList, uid)
- }
- this.allChallengeList.Clear()
- this.challengeDataList = map[uint64]*serverproto.FightRoleInfo{}
- this.maxRoomId = 0
- this.uidRoomList = map[uint64]int32{}
- this.roomList = map[int32]*BossRoom{}
- }
- //是否在挑战boss时间内
- func (this *PlayerBoss) checkTimeValid(nowTime uint64) bool {
- if this.summonTime > 0 {
- oldTime := this.summonTime + this.durationTime
- return oldTime > nowTime
- }
- return false
- }
- func (this *PlayerBoss) addChallengePlayer(uid uint64, id model.ClientID, roleData *serverproto.FightRoleInfo) {
- if !this.allChallengeList.Has(uid) {
- this.allChallengeList.Add(uid)
- WorldBossListAddChallenge(this, uid)
- }
- //self
- this.bossChangePlay(roleData)
- this.challengeList[uid] = id
- this.challengeDataList[uid] = roleData
- //manager
- this.mag.challengePlayerList[uid] = this
- //use for notify(enter/leave)
- var tmpRoomId int32 = 0
- if this.freeRoomList.Len() > 0 {
- tmpRoomId = heap.Pop(this.freeRoomList).(int32)
- } else {
- this.maxRoomId++
- tmpRoomId = this.maxRoomId
- }
- this.uidRoomList[uid] = tmpRoomId
- if this.roomList[tmpRoomId] == nil {
- this.roomList[tmpRoomId] = &BossRoom{
- uidList: map[uint64]struct{}{},
- }
- }
- this.roomList[tmpRoomId].AddUid(uid)
- if len(this.roomList[tmpRoomId].uidList) < MAX_BOSS_CHALLENGE_PLAYER_NUM {
- heap.Push(this.freeRoomList, tmpRoomId)
- }
- //通知自己和其他玩家
- this.enterNotify(uid, tmpRoomId)
- }
- //玩家挑战boss触发变身操作
- func (this *PlayerBoss) bossChangePlay(roleData *serverproto.FightRoleInfo) {
- switch this.summonBossType {
- case model.SummonBossType_ChangePlay:
- cfgData, ok := model.ConvertWorldBossChangePlayList[int32(this.bossUid)]
- if !ok {
- util.InfoF("AddBossFromRefresh WorldBossChangePlayCfgLoader not find boss=%v ", this.summonBossId)
- return
- }
- changePlayId := cfgData.RandChangePlayId()
- if changePlayId > 0 {
- roleData.ChangePlayId = changePlayId
- }
- }
- }
- func (this *PlayerBoss) canChallenge(uid uint64) serverproto.ErrorCode {
- if len(this.challengeList) >= 1000 {
- return serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGE_NUM_LIMIT
- }
- if this.totalHp <= 0 {
- return serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND
- }
- return serverproto.ErrorCode_ERROR_OK
- }
- //通知自己和其他玩家
- func (this *PlayerBoss) enterNotify(enterUid uint64, roomId int32) {
- //发送其他玩家信息给自己,并发送自己信息给其他玩家
- selfNtfMsg := &serverproto.SSPlayerEnterChallengeNtf{
- BossUid: this.bossUid,
- EnterUid: enterUid,
- SelfChangePlayId: this.challengeDataList[enterUid].ChangePlayId,
- SummonBossType: this.summonBossType,
- }
- otherNtfMsg := &serverproto.SSPlayerEnterChallengeNtf{
- BossUid: this.bossUid,
- EnterUid: enterUid,
- SummonBossType: this.summonBossType,
- }
- otherNtfMsg.FightList = append(otherNtfMsg.FightList, this.challengeDataList[enterUid])
- var otherSendList = map[string][]uint64{}
- roomInfo := this.roomList[roomId]
- for tmpUid, _ := range roomInfo.uidList {
- if tmpUid == enterUid {
- continue
- }
- tmpUidCli, ok := this.challengeList[tmpUid]
- if !ok {
- continue
- }
- selfNtfMsg.FightList = append(selfNtfMsg.FightList, this.challengeDataList[tmpUid])
- otherSendList[tmpUidCli.ServiceID] = append(otherSendList[tmpUidCli.ServiceID], tmpUid)
- }
- sort.Slice(selfNtfMsg.FightList, func(i, j int) bool {
- return selfNtfMsg.FightList[i].BriefInfo.Uid < selfNtfMsg.FightList[j].BriefInfo.Uid
- })
- //send self
- this.mag.SendGame(selfNtfMsg, this.challengeList[enterUid].ServiceID, 0)
- //send other
- for idx := range otherSendList {
- otherNtfMsg.NotifyList = otherNtfMsg.NotifyList[:0]
- otherNtfMsg.NotifyList = append(otherSendList[idx])
- this.mag.SendGame(otherNtfMsg, idx, 0)
- }
- }
- //离开boss,发送其他玩家信息给当前玩家
- func (this *PlayerBoss) leaveNotify(leaveUid uint64) {
- var notifyList = map[string][]uint64{}
- if leaveUidData, ok := this.challengeList[leaveUid]; ok {
- //需要做rand点处理
- _, ok := this.mag.challengePlayerList[leaveUid]
- if ok {
- //需要做rand点处理
- pointNtfMsg := &serverproto.SCPlayerWorldBossRandNtf{
- PointInfo: &serverproto.WorldBossRandPointInfo{
- BossSummonType: this.summonBossType,
- },
- }
- pointNtfMsg.PointInfo.BossId = int32(this.bossUid)
- pointNtfMsg.PointInfo.BossSummonIdx = this.summonBossIdx
- this.mag.SendGame(pointNtfMsg, leaveUidData.ServiceID, leaveUid)
- delete(this.mag.challengePlayerList, leaveUid)
- }
- delete(this.challengeList, leaveUid)
- if roomId, ok := this.uidRoomList[leaveUid]; ok {
- roomInfo := this.roomList[roomId]
- for tmpUid, _ := range roomInfo.uidList {
- if tmpUid == leaveUid {
- continue
- }
- if notifyData, ok := this.challengeList[tmpUid]; ok {
- notifyList[notifyData.ServiceID] = append(notifyList[notifyData.ServiceID], tmpUid)
- }
- }
- roomInfo.RemUid(leaveUid)
- bPushed := false
- for idx := 0; idx < this.freeRoomList.Len(); idx++ {
- if this.freeRoomList.ItemList[idx] == roomId {
- bPushed = true
- break
- }
- }
- if !bPushed {
- heap.Push(this.freeRoomList, roomId)
- }
- delete(this.uidRoomList, leaveUid)
- }
- }
- leaveNtfMsg := &serverproto.SSPlayerLeaveChallengeNtf{
- LeaveUid: leaveUid,
- }
- for serviceNode := range notifyList {
- leaveNtfMsg.NotifyList = leaveNtfMsg.NotifyList[:0]
- leaveNtfMsg.NotifyList = append(notifyList[serviceNode])
- this.mag.SendGame(leaveNtfMsg, serviceNode, 0)
- }
- }
- func (this *PlayerBoss) updateBossHp(ms uint64) {
- //boss没人打过,则不触发掉血
- if this.GetState() == BOSS_STATE_TIME_OUT {
- return
- }
- if this.totalHp >= this.maxHp || this.lastHPReduceTime == 0 {
- return
- }
- cfgData, ok := model.ConvertWorldBossList[int32(this.bossUid)]
- if !ok || cfgData.ReduceHp.Key <= 0 || cfgData.ReduceHp.Value <= 0 {
- return
- }
- if ms > this.lastHPReduceTime+uint64(cfgData.ReduceHp.Key)*1000 {
- reduceHp := (this.maxHp / 10000) * cfgData.ReduceHp.Value
- if reduceHp > 0 {
- this.hpDirty = true
- this.totalHp -= reduceHp
- if this.totalHp <= 0 {
- this.totalHp = 0
- util.InfoF("update world boss reduce hp bossid= %v hp= %v", this.bossUid, cfgData.ReduceHp.Value)
- this.SwitchState(int32(BOSS_STATE_DIED), nil)
- }
- this.lastHPReduceTime = ms
- }
- }
- }
- func (this *PlayerBoss) broadcastBossHp() {
- if len(this.challengeList) <= 0 {
- return
- }
- if !this.hpDirty {
- return
- }
- this.hpDirty = false
- //update to db
- UpdateWorldBossList(this)
- var notifyList = map[string][]uint64{}
- for uid, data := range this.challengeList {
- notifyList[data.ServiceID] = append(notifyList[data.ServiceID], uid)
- }
- hpNtfMsg := &serverproto.SSPlayerChallengeHpNtf{
- CurBossHp: this.totalHp,
- }
- sendCount := 50
- for serviceNode := range notifyList {
- uidLen := len(notifyList[serviceNode])
- if uidLen <= 0 {
- continue
- }
- idx := 0
- if uidLen > sendCount {
- idx = 0
- }
- for {
- if idx+sendCount < uidLen {
- hpNtfMsg.NotifyList = notifyList[serviceNode][idx : idx+sendCount]
- idx += sendCount
- } else {
- hpNtfMsg.NotifyList = notifyList[serviceNode][idx:uidLen]
- this.mag.SendGame(hpNtfMsg, serviceNode, 0)
- break
- }
- this.mag.SendGame(hpNtfMsg, serviceNode, 0)
- }
- }
- }
- func (this *PlayerBoss) broadcastResult(result int32) {
- if len(this.challengeList) <= 0 {
- return
- }
- var notifyList = map[string][]uint64{}
- for uid, data := range this.challengeList {
- notifyList[data.ServiceID] = append(notifyList[data.ServiceID], uid)
- }
- resultNtfMsg := &serverproto.SSPlayerChallengeResultNtf{
- Result: result,
- }
- for serviceNode := range notifyList {
- resultNtfMsg.NotifyList = resultNtfMsg.NotifyList[:0]
- resultNtfMsg.NotifyList = append(notifyList[serviceNode])
- this.mag.SendGame(resultNtfMsg, serviceNode, 0)
- }
- }
- func (this *PlayerBoss) battleTimeOut(fromDB bool) {
- util.InfoF("battleTimeOut bossid=%v", this.bossUid)
- if !fromDB {
- //非正常结束战斗
- this.broadcastResult(BOSS_RESULT_TIME_OUT)
- }
- this.finish = true
- //清理数据
- this.clear()
- }
- func (this *PlayerBoss) battleBossDie(fromDB bool) {
- util.InfoF("battleWin bossid=%v", this.bossUid)
- if !fromDB {
- this.broadcastResult(BOSS_RESULT_WIN)
- this.battleReward()
- }
- this.finish = true
- //清理数据
- this.clear()
- }
- func (this *PlayerBoss) battleReward() {
- if len(this.challengeList) > 0 {
- //需要做rand点处理
- pointNtfMsg := &serverproto.SCPlayerWorldBossRandNtf{
- PointInfo: &serverproto.WorldBossRandPointInfo{},
- }
- for uid, data := range this.challengeList {
- pointNtfMsg.PointInfo.BossId = int32(this.bossUid)
- this.mag.SendGame(pointNtfMsg, data.ServiceID, uid)
- }
- }
- ////参与boss奖励
- //// 发送邮件奖励
- //cfgData, ok := model.ConvertWorldBossList[int32(this.bossUid)]
- //if ok {
- // normalMailNtfMsg := &serverproto.SSAddMailNtf{
- // MailConfigId: BOSS_REWARD_MAIL_CONFIG_ID_Other,
- // MailType: int32(serverproto.MailType_MailType_Boss),
- // }
- // normalMailNtfMsg.RewardList = append(normalMailNtfMsg.RewardList, cfgData.SummonRewardList...)
- // normalMailNtfMsg.MailParamList = append(normalMailNtfMsg.MailParamList, cfgData.Id)
- //
- // for _, data := range this.allChallengeList.List() {
- // normalMailNtfMsg.NotifyList = append(normalMailNtfMsg.NotifyList, data.(uint64))
- // }
- //
- // this.mag.SendSocial(normalMailNtfMsg)
- //}
- }
- //boss战斗
- func (this *PlayerBoss) ProcessBattle(damageHp int32) {
- if this.totalHp > 0 && damageHp > 0 {
- this.hpDirty = true
- this.totalHp -= damageHp
- if this.totalHp <= 0 {
- this.totalHp = 0
- util.InfoF("ProcessBattle battle finish success")
- this.SwitchState(int32(BOSS_STATE_DIED), nil)
- }
- this.lastHPReduceTime = util.GetTimeMilliseconds()
- }
- }
- func (this *PlayerBoss) RandPoint(uid uint64) (serverproto.ErrorCode, bool, int32) {
- _, ok := this.challengeDataList[uid]
- if !ok {
- return serverproto.ErrorCode_ERROR_FAIL, false, 0
- }
- rand.Seed(int64(util.GetTimeMilliseconds()))
- randNum := rand.Int31n(100) + 1
- if randNum >= this.maxPoint {
- return serverproto.ErrorCode_ERROR_OK, true, randNum
- }
- return serverproto.ErrorCode_ERROR_OK, false, randNum
- }
|