增加fruit服务

This commit is contained in:
fatiao 2025-06-06 14:36:05 +08:00
parent 19bb96b315
commit 181fd7716f
10 changed files with 1733 additions and 0 deletions

View File

@ -0,0 +1,25 @@
#服务器都对内监听处理(处理服务器之间的连接)
#loglevel
# Debug 1
# Info 2
# Warning 3
# Error 4
# Fatal 5
# 服务器类型节点Type:[1 gate] [2 game] [3 db] [4 auth] [5 social chat mail] [10 map] [12 pve] [13 boss]
server:
- node:
nodename: fruit
addr: 0.0.0.0:51601
type: 13
id: 1
zone: 1
logfile: ../../logs
loglevel: 1
config: ./config
etcdaddr: 127.0.0.1:2379
concern: [game]
#处理redis连接使用
db:
redisaddr: [127.0.0.1:6379]
password: Luna2024!
dbindex: 2

View File

@ -0,0 +1,72 @@
package main
import (
"io/ioutil"
_ "net/http/pprof"
"os"
"rocommon"
"rocommon/service"
_ "rocommon/socket"
_ "rocommon/socket/tcp"
"roserver/baseserver"
"roserver/baseserver/model"
self "roserver/fruit/model"
_ "roserver/fruit/msg"
"runtime"
"strconv"
"syscall"
)
// todo...
// 单点有状态服务器
func main() {
//记录battleboss pid用来做关闭操作
sysType := runtime.GOOS
if sysType != "windows" {
if pid := syscall.Getpid(); pid != 1 {
fileName := "battleboss_server.pid" + strconv.Itoa(pid)
ioutil.WriteFile(fileName, []byte(strconv.Itoa(pid)), 0777)
defer os.Remove(fileName)
}
}
//go func(){
// log.Println(http.ListenAndServe("localhost:8005", nil))
//}()
//CPU
//prof := profile.Start(profile.CPUProfile, profile.ProfilePath("./pprof/serverboss.pprof"), profile.NoShutdownHook)
baseserver.Init(model.SERVICE_NODE_TYPE_FRUIT_STR, self.ConfigInit, &self.FruitUpdate{})
//prof := profile.Start(profile.MemProfile, profile.ProfilePath("./pprof/serverbossmem.pprof"), profile.NoShutdownHook)
sConfig := service.GetServiceConfig()
//先建立服务器对应的连接,在监听客户端
//创建监听器
var acceNode rocommon.ServerNode = nil
if sConfig.Node.Addr != "" {
acceNode = baseserver.CreateAcceptor(baseserver.ServiceParam{
ServiceType: "tcpAcceptor",
ServiceName: model.SERVICE_NODE_TYPE_FRUIT_STR,
ProcName: "common.backend",
LisAddr: sConfig.Node.Addr,
}, sConfig)
}
for _, concern := range sConfig.Node.Concern {
//建立需要链接的服务器,可以通过服务器发现etcd来处理(包含在了CreateConnector中)
baseserver.CreateConnector(baseserver.ServiceParam{
DiscoveryServiceName: concern,
DiscoveryServiceZone: sConfig.Node.Zone,
ServiceType: "tcpConnector",
ServiceName: model.SERVICE_NODE_TYPE_FRUIT_STR,
ProcName: "common.backend",
})
}
baseserver.Wait()
//CPU
//prof.Stop()
baseserver.Exit(acceNode)
}

View File

@ -0,0 +1,20 @@
package model
import (
"rocommon/service"
"rocommon/util"
"roserver/baseserver/model"
"runtime/debug"
)
func ConfigInit() {
defer func() {
if err := recover(); err != nil {
util.InfoF("Stack---::%v\n%s\n", err, string(debug.Stack()))
panic(nil)
}
}()
sConfig := service.GetServiceConfig()
model.BaseConfigInit(sConfig)
}

View File

@ -0,0 +1,757 @@
package model
import (
"rocommon/service"
"rocommon/util"
"roserver/baseserver/model"
"roserver/baseserver/set"
"roserver/serverproto"
"time"
)
const MAX_AOI_LINE_BOSS_NUM = 100
const MAX_BOSS_CHALLENGE_PLAYER_NUM = 8
const BOSS_REWARD_MAIL_CONFIG_ID_Other = 2
const (
BOSS_RESULT_WIN = 1
BOSS_RESULT_TIME_OUT = 2
INIT_STATE_NONE = 0
INIT_STATE_INIT = 1 //获取数据
INIT_STATE_FINISH = 2 //初始化完成
)
const NO_AOILINE_BOSS = "NOAOI"
const MAX_NO_AOILINE_BOSS_NUM = 20
type RefreshBossInfo struct {
posId int32
summonTimeIdx int
bossData *model.ConvertWorldBossData
refreshTime time.Time //刷新boss的时间错逻辑中使用
stop bool
}
func (this *RefreshBossInfo) printDebugString(addStr string) {
util.DebugF("msg=%v pos=%v bossid=%v summonidx=%v refreshtime=%v", addStr, this.posId,
this.bossData.Id, this.summonTimeIdx, this.refreshTime.String())
}
////////////////////////////////AoiLineBossManager
type WorldBossManager struct {
mapRouterNode string
socialNode string
updateTimer util.ServerTimer //定时器
bossList map[uint64]*PlayerBoss //[bossId *PlayerBoss]
//挑战玩家所在boss场景
challengePlayerList map[uint64]*PlayerBoss
initStartUp int32 //维护时需要加载维护前的boss状态信息(血量,攻击记录)
refreshBossInfoList map[int32]*RefreshBossInfo
refreshBossInfoActivityList map[int32]*RefreshBossInfo
startUpDayTime time.Time //开服整数点时间
startDiffDay int32 //当前距离开服时间的天数
}
func newWorldBossManager() *WorldBossManager {
mag := &WorldBossManager{
bossList: map[uint64]*PlayerBoss{},
challengePlayerList: map[uint64]*PlayerBoss{},
mapRouterNode: "",
socialNode: "",
refreshBossInfoList: map[int32]*RefreshBossInfo{},
refreshBossInfoActivityList: map[int32]*RefreshBossInfo{},
}
mag.challengePlayerList = map[uint64]*PlayerBoss{}
mag.updateTimer = util.NewDurationTimer(util.GetTimeMilliseconds(), 500)
mag.initRefresh()
return mag
}
//获取最近一天的boss刷新时间
func (this *WorldBossManager) getCurrentDayBossData(currentDay int32, pos int32) *model.ConvertWorldBossData {
valList, ok := model.ConvertWorldBoss[pos]
if !ok {
return nil
}
var retData *model.ConvertWorldBossData = nil
for idx := 0; idx < len(valList); idx++ {
if valList[idx].StartDay <= currentDay {
retData = valList[idx]
} else if valList[idx].StartDay > currentDay {
break
}
}
if retData == nil {
if len(valList) > 0 {
retData = valList[len(valList)-1]
}
}
return retData
}
func (this *WorldBossManager) initRefresh() bool {
startUpTime := service.GetServiceStartupTime() //ms
if startUpTime <= 0 {
return false
}
this.startUpDayTime = util.GetDayByTimeStr2(startUpTime)
this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
//util.DebugF("nowhourtime=%v", nowHourTime.String())
//普通世界boss
for key := range model.ConvertWorldBoss {
tmp := this.getRefreshInfo(key)
tmp.printDebugString("initrefresh")
}
//活动世界boss(变身)
for _, bossDataInfo := range model.ConvertWorldBossChangePlayList {
this.getRefreshInfoChangePlay(bossDataInfo)
}
this.initStartUp = INIT_STATE_FINISH
//开服时间
return true
}
func (this *WorldBossManager) getRefreshInfo(pos int32) *RefreshBossInfo {
bFind := false
k := 0
tmpStartDiffDay := this.startDiffDay
nowHourTime := util.GetHourByTime(0)
//key == 0 表示最后一个位置
bossDataInfo := this.getCurrentDayBossData(tmpStartDiffDay, pos)
if bossDataInfo == nil {
return nil
}
for k = 0; k < len(bossDataInfo.SummonTime); k++ {
if bossDataInfo.SummonTime[k].After(nowHourTime) {
bFind = true
break
}
}
if !bFind {
k = 0
tmpStartDiffDay++
bossDataInfo = this.getCurrentDayBossData(tmpStartDiffDay, pos)
if bossDataInfo != nil && len(bossDataInfo.SummonTime) > 0 {
bFind = true
}
}
if bFind {
tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpStartDiffDay-1))
tmpSummonTime := bossDataInfo.SummonTime[k].Hour()*60*60 + bossDataInfo.SummonTime[k].Minute()*60 + bossDataInfo.SummonTime[k].Second()
tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
//util.DebugF("%v tmpTime:%v :%v", key, tmpTime.String(), tmpSummonTime)
refreshInfo := &RefreshBossInfo{
posId: bossDataInfo.RefreshId,
bossData: bossDataInfo,
refreshTime: tmpTime,
}
refreshInfo.summonTimeIdx = k + int(tmpStartDiffDay-1)*len(bossDataInfo.SummonTime)
this.refreshBossInfoList[pos] = refreshInfo
return refreshInfo
}
return nil
}
func (this *WorldBossManager) getRefreshInfoChangePlay(bossDataInfo *model.ConvertWorldBossData) *RefreshBossInfo {
tmpStartDiffDay := this.startDiffDay
nowHourTime := util.GetHourByTime(0)
//<=0表示根据给定的时间来开启[BossBeginTime,BossEndTime]
if bossDataInfo.StartDay <= 0 {
bFind := false
k := 0
for k = 0; k < len(bossDataInfo.SummonTime); k++ {
if bossDataInfo.SummonTime[k].After(nowHourTime) {
bFind = true
break
}
}
if !bFind {
k = 0
tmpStartDiffDay++
bFind = true
}
tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpStartDiffDay-1))
tmpSummonTime := bossDataInfo.SummonTime[k].Hour()*60*60 + bossDataInfo.SummonTime[k].Minute()*60 + bossDataInfo.SummonTime[k].Second()
tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
refreshInfo := &RefreshBossInfo{
bossData: bossDataInfo,
refreshTime: tmpTime,
}
refreshInfo.summonTimeIdx = k + int(tmpStartDiffDay-1)*len(bossDataInfo.SummonTime)
this.refreshBossInfoActivityList[refreshInfo.bossData.Id] = refreshInfo
util.DebugF("getRefreshInfoChangePlay bossid=%v summonidx=%v refreshtime=%v",
bossDataInfo.Id, refreshInfo.summonTimeIdx, tmpTime.String())
return refreshInfo
} else {
//todo...
}
return nil
}
func (this *WorldBossManager) refreshBoss() {
if len(this.refreshBossInfoList) <= 0 {
return
}
nowTime := util.GetCurrentTimeNow()
for _, info := range this.refreshBossInfoList {
//util.InfoF("now=%v summon=%v", nowHourTime.String(), info.bossData.SummonTime[info.summonTimeIdx].String())
if nowTime.After(info.refreshTime) {
//refresh key-pos boss
//1,remove old-pos boss
//2,add new-pos boss
bRefresh := true
for _, bossVal := range this.bossList {
if bossVal.summonBossType != model.SummonBossType_Normal {
continue
}
if int32(bossVal.bossUid)%4 == info.posId {
//正在挑战中的boss不进行刷新处理
if bossVal.GetState() == BOSS_STATE_FIGHTING {
bRefresh = false
} else {
DelWorldBossList(bossVal)
delete(this.bossList, bossVal.bossUid)
}
break
}
}
if bRefresh {
this.AddBossFromRefresh(info.bossData, int32(info.summonTimeIdx))
}
tmpIdx := info.summonTimeIdx % len(info.bossData.SummonTime)
//if tmpIdx <= 0 && info.summonTimeIdx > 0 {
// tmpIdx = len(info.bossData.SummonTime)
//}
startUpTime := service.GetServiceStartupTime()
this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
tmpAddDay := this.startDiffDay
if len(info.bossData.SummonTime) <= tmpIdx+1 {
//boss存活时间可能到下一天
//判断下一天是否有新的boss刷新
if info.refreshTime.Day() == nowTime.Day() {
//如果当前刷新时间已经用完,则直接找第二天的刷新时间(需要判断刷新时对应的天数和当前时间做比较)
tmpAddDay++
}
nextBossInfo := this.getCurrentDayBossData(tmpAddDay, info.posId)
info.bossData = nextBossInfo
}
if nowTime.Day() != info.refreshTime.Day() { //应对测试期间之前改天数的方式
tmpPosId := info.posId
info = this.getRefreshInfo(tmpPosId)
} else {
info.summonTimeIdx++
k := info.summonTimeIdx % len(info.bossData.SummonTime)
tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpAddDay-1))
tmpSummonTime := info.bossData.SummonTime[k].Hour()*60*60 + info.bossData.SummonTime[k].Minute()*60 + info.bossData.SummonTime[k].Second()
tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
info.refreshTime = tmpTime
}
info.printDebugString("RefreshBoss")
}
}
}
func (this *WorldBossManager) refreshBossChangePlay(ms uint64) {
if len(this.refreshBossInfoActivityList) <= 0 {
return
}
nowTime := util.GetTimeByUint64(ms)
for key, info := range this.refreshBossInfoActivityList {
//活动过期
if nowTime.After(info.bossData.BossEndTime) {
bossVal, ok := this.bossList[uint64(info.bossData.Id)]
if ok {
bossVal.SwitchState(int32(BOSS_STATE_TIME_OUT), nil)
delete(this.bossList, uint64(info.bossData.Id))
}
delete(this.refreshBossInfoActivityList, key)
continue
}
if nowTime.Before(info.refreshTime) || nowTime.Before(info.bossData.BossBeginTime) {
continue
}
bRefresh := true
bossVal, ok := this.bossList[uint64(info.bossData.Id)]
if ok {
if bossVal.GetState() == BOSS_STATE_FIGHTING {
bRefresh = false
} else {
DelWorldBossList(bossVal)
delete(this.bossList, bossVal.bossUid)
}
}
if bRefresh {
this.AddBossFromRefresh(info.bossData, int32(info.summonTimeIdx))
}
tmpIdx := info.summonTimeIdx % len(info.bossData.SummonTime)
startUpTime := service.GetServiceStartupTime()
this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
tmpAddDay := this.startDiffDay
if len(info.bossData.SummonTime) <= tmpIdx+1 {
//boss存活时间可能到下一天
//判断下一天是否有新的boss刷新
if info.refreshTime.Day() == nowTime.Day() {
//如果当前刷新时间已经用完,则直接找第二天的刷新时间(需要判断刷新时对应的天数和当前时间做比较)
tmpAddDay++
}
info.summonTimeIdx = 0
} else {
info.summonTimeIdx++
}
if nowTime.Day() != info.refreshTime.Day() { //应对测试期间之前改天数的方式
info = this.getRefreshInfoChangePlay(info.bossData)
} else {
//info.summonTimeIdx++
k := info.summonTimeIdx % len(info.bossData.SummonTime)
tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpAddDay-1))
tmpSummonTime := info.bossData.SummonTime[k].Hour()*60*60 + info.bossData.SummonTime[k].Minute()*60 + info.bossData.SummonTime[k].Second()
tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
info.refreshTime = tmpTime
}
if bRefresh {
util.DebugF("nextWorldBossRefreshTime=%v", info.refreshTime.String())
}
info.printDebugString("RefreshBoss")
}
}
func (this *WorldBossManager) PlayerOffline(uid uint64) {
if playerBoss, ok := this.challengePlayerList[uid]; ok {
playerBoss.leaveNotify(uid)
}
}
func (this *WorldBossManager) Update(ms uint64) {
switch this.initStartUp {
case INIT_STATE_NONE:
if GetWorldBossList(this) {
this.initStartUp = INIT_STATE_INIT
util.InfoF("load from db worldboss len=%v", len(this.bossList))
} else {
this.initStartUp = INIT_STATE_NONE
return
}
case INIT_STATE_INIT:
if !this.initRefresh() {
return
}
}
if !this.updateTimer.IsStart() || !this.updateTimer.IsExpired(ms) ||
this.initStartUp != INIT_STATE_FINISH {
return
}
for _, boss := range this.bossList {
boss.broadcastBossHp()
if boss.finish {
//不从列表中删除,客户端实现需要
//delete(this.bossList, boss.bossUid)
continue
}
if !boss.checkTimeValid(ms) {
boss.SwitchState(int32(BOSS_STATE_TIME_OUT), nil)
}
//处理boss的定时掉血。
if boss.GetState() != BOSS_STATE_TIME_OUT && boss.GetState() != BOSS_STATE_DIED {
boss.updateBossHp(ms)
}
}
//判断是否需要重新刷新boss
this.refreshBoss() //普通世界boss
this.refreshBossChangePlay(ms) //活动世界boss
}
//DB中加载获取boss状态信息
func (this *WorldBossManager) AddBossFromDB(stateInfo *serverproto.WorldBossStateInfo) bool {
var summonId int32 = 0
if stateInfo.SummonBossType == model.SummonBossType_Normal {
cfgData, ok := model.ConvertWorldBossList[stateInfo.BossId]
if !ok {
return false
}
summonId = cfgData.SummonId
} else {
cfgData, ok := model.ConvertWorldBossChangePlayList[stateInfo.BossId]
if !ok {
return false
}
summonId = cfgData.SummonId
}
npcCfgData, ok1 := serverproto.NpcCfgLoader[summonId]
if !ok1 {
return false
}
playerBoss := newPlayerBoss(this)
playerBoss.bossUid = uint64(stateInfo.BossId)
playerBoss.summonBossId = summonId
playerBoss.summonBossType = stateInfo.SummonBossType
playerBoss.summonTime = stateInfo.SummonTime
playerBoss.durationTime = uint64(stateInfo.DurationTime) * 1000
playerBoss.summonBossIdx = stateInfo.SummonIdx
playerBoss.SetTotalHp(stateInfo.Hp)
playerBoss.maxHp = int32(npcCfgData.Hp)
playerBoss.lastHPReduceTime = 0
if playerBoss.totalHp < playerBoss.maxHp {
playerBoss.lastHPReduceTime = util.GetTimeMilliseconds()
}
//add challenge uid
for idx := 0; idx < len(stateInfo.UidList); idx++ {
playerBoss.allChallengeList.Add(stateInfo.UidList[idx])
}
nowTime := util.GetTimeMilliseconds()
endTime := stateInfo.SummonTime + uint64(stateInfo.DurationTime)*1000
if endTime <= nowTime {
playerBoss.SwitchState(int32(BOSS_STATE_TIME_OUT), true) //表示来自db
} else {
if playerBoss.totalHp <= 0 {
playerBoss.SwitchState(int32(BOSS_STATE_DIED), true) //表示来自db
} else {
playerBoss.SwitchState(int32(BOSS_STATE_FIGHTING), nil)
}
}
this.bossList[playerBoss.bossUid] = playerBoss
util.DebugF("msg=AddBossFromDB bossid=%v summonidx=%v", playerBoss.bossUid, playerBoss.summonBossIdx)
return true
}
const SystemMessageType_WorldBoss = 6 //召喚世界BOSS通知
func (this *WorldBossManager) AddBossFromRefresh(bossData *model.ConvertWorldBossData, summonIdx int32) bool {
var summonId int32 = 0
if bossData.SummonType == model.SummonBossType_Normal {
cfgData, ok := serverproto.WorldBossCfgLoader[bossData.Id]
if !ok {
util.InfoF("AddBossFromRefresh WorldBossCfgLoader not find boss=%v ", bossData.Id)
return false
}
summonId = cfgData.SummonId
} else {
cfgData, ok := serverproto.WorldBossChangePlayCfgLoader[bossData.Id]
if !ok {
util.InfoF("AddBossFromRefresh WorldBossChangePlayCfgLoader not find boss=%v ", bossData.Id)
return false
}
summonId = cfgData.SummonId
}
npcCfgData, ok1 := serverproto.NpcCfgLoader[summonId]
if !ok1 {
util.InfoF("AddBossFromRefresh npc data not find summonid=%v ", summonId)
return false
}
summonHp := int32(npcCfgData.Hp)
playerBoss := newPlayerBoss(this)
playerBoss.bossUid = uint64(bossData.Id)
playerBoss.summonBossId = summonId
playerBoss.summonTime = util.GetTimeMilliseconds()
playerBoss.durationTime = uint64(bossData.DurationTime) * 1000
playerBoss.summonBossIdx = summonIdx
playerBoss.SetTotalHp(summonHp)
playerBoss.lastHPReduceTime = 0
playerBoss.summonBossType = bossData.SummonType
playerBoss.SwitchState(int32(BOSS_STATE_FIGHTING), nil)
this.bossList[playerBoss.bossUid] = playerBoss
//add to db
UpdateWorldBossList(playerBoss)
util.DebugF("msg=AddBossFromRefresh bossid=%v summonidx=%v", bossData.Id, summonIdx)
//发送给所有game服务器
ssMsgNtf := &serverproto.SSSystemMessageNtf{}
ssMsg := &serverproto.SystemMessage{
Type: SystemMessageType_WorldBoss,
ParamId: []int32{int32(playerBoss.bossUid), bossData.SummonType},
SendTime: util.GetTimeMilliseconds(),
}
ssMsgNtf.SysMsg = append(ssMsgNtf.SysMsg, ssMsg)
SendToAllGame(ssMsgNtf)
return true
}
func (this *WorldBossManager) PlayerChallengeSummonBoss(uid, challengeBossUid uint64, clientId model.ClientID,
fightInfo *serverproto.FightRoleInfo) serverproto.ErrorCode {
//当前玩家是否正在挑战boss
if bossInfo, ok := this.challengePlayerList[uid]; ok {
if bossInfo.finish {
delete(this.challengePlayerList, uid)
} else {
bossInfo.leaveNotify(uid)
//util.InfoF("PlayerChallengeSummonBoss already in other boss=%v uid=%v", bossInfo, uid)
//return serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGING
}
}
//查找是否存在Boss
bossInfo, ok := this.bossList[challengeBossUid]
if !ok {
return serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND
}
ret := bossInfo.canChallenge(uid)
if ret != serverproto.ErrorCode_ERROR_OK {
return ret
}
//添加挑战玩家信息
bossInfo.addChallengePlayer(uid, clientId, fightInfo)
return serverproto.ErrorCode_ERROR_OK
}
func (this *WorldBossManager) DoSummonHp(uid, bossUid uint64, damageHp int32) {
bossInfo, ok := this.challengePlayerList[uid]
if !ok {
util.InfoF("DoSummonHp boss not find uId=%v boss=%v damageHp=%v", uid, bossUid, damageHp)
return
}
if bossInfo.bossUid != bossUid {
util.InfoF("DoSummonHp bossId invalid uid=%v boss=%v dobossid=%v", uid, bossInfo.bossUid, bossUid)
return
}
bossInfo.ProcessBattle(damageHp)
}
func (this *WorldBossManager) GetWorldBossInfo(bossUid uint64) *serverproto.WorldBossContentInfo {
bossInfo, ok1 := this.bossList[bossUid]
if !ok1 {
return nil
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(bossInfo.bossUid),
CfgId: bossInfo.summonBossId,
FighterNum: int32(len(bossInfo.challengeList)),
ExpireTime: bossInfo.summonTime + bossInfo.durationTime,
TotalHp: bossInfo.maxHp,
CurHp: bossInfo.totalHp,
BossSummonType: bossInfo.summonBossType,
}
return info
}
func (this *WorldBossManager) getBossRefreshInfo(posIdx int32) *RefreshBossInfo {
if data, ok := this.refreshBossInfoList[posIdx]; ok {
return data
}
return nil
}
func (this *WorldBossManager) getBossRefreshInfoChangePlay(bossId int32) *RefreshBossInfo {
if data, ok := this.refreshBossInfoActivityList[bossId]; ok {
refreshTime := uint64(data.refreshTime.Unix()) * 1000
if data.bossData.BossEndTimeStmp > refreshTime {
return data
}
}
return nil
}
func (this *WorldBossManager) GetWorldBossList() *serverproto.SCPlayerWorldBossListAck {
if len(this.bossList) <= 0 {
var tmpAckMsg = &serverproto.SCPlayerWorldBossListAck{}
//if len(tmpAckMsg.WorldBossList) > 0 {
// return tmpAckMsg
//}
//普通世界boss
for _, val := range this.refreshBossInfoList {
npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
if !ok1 {
util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
continue
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(val.bossData.Id),
CfgId: val.bossData.SummonId,
FighterNum: 0,
ExpireTime: 0,
NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
TotalHp: int32(npcCfgData.Hp),
CurHp: int32(npcCfgData.Hp),
}
tmpAckMsg.WorldBossList = append(tmpAckMsg.WorldBossList, info)
}
//变身类活动世界boss
nowTime := util.GetCurrentTimeNow()
for _, val := range this.refreshBossInfoActivityList {
npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
if !ok1 {
util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
continue
}
if nowTime.Before(val.bossData.BossBeginTime) || nowTime.After(val.bossData.BossEndTime) {
continue
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(val.bossData.Id),
CfgId: val.bossData.SummonId,
FighterNum: 0,
ExpireTime: 0,
NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
TotalHp: int32(npcCfgData.Hp),
CurHp: int32(npcCfgData.Hp),
BossSummonType: val.bossData.SummonType,
}
tmpAckMsg.WorldBossList = append(tmpAckMsg.WorldBossList, info)
}
return tmpAckMsg
} else {
ackMsg := &serverproto.SCPlayerWorldBossListAck{}
nowTime := util.GetTimeMilliseconds()
hasBossList := set.New(set.NonThreadSafe)
hasChangePlayBossList := set.New(set.NonThreadSafe)
for _, bossInfo := range this.bossList {
if bossInfo.summonBossType <= 0 {
hasBossList.Add(int32(bossInfo.bossUid) % 4)
} else {
hasChangePlayBossList.Add(int32(bossInfo.bossUid))
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(bossInfo.bossUid),
BossSummonIdx: bossInfo.summonBossIdx,
CfgId: bossInfo.summonBossId,
FighterNum: int32(len(bossInfo.challengeList)),
//ExpireTime: bossInfo.summonTime + bossInfo.durationTime,
TotalHp: bossInfo.maxHp,
CurHp: bossInfo.totalHp,
BossSummonType: bossInfo.summonBossType,
}
expireTime := bossInfo.summonTime + bossInfo.durationTime
if bossInfo.summonBossType == model.SummonBossType_ChangePlay {
changBossDataInfo, ok := model.ConvertWorldBossChangePlayList[int32(bossInfo.bossUid)]
if ok {
if expireTime > changBossDataInfo.BossEndTimeStmp {
expireTime = changBossDataInfo.BossEndTimeStmp
}
}
}
info.ExpireTime = expireTime
if nowTime > expireTime || bossInfo.totalHp <= 0 {
info.FighterNum = 0
info.ExpireTime = 0
switch bossInfo.summonBossType {
case model.SummonBossType_Normal:
bossRefreshInfo := this.getBossRefreshInfo(info.BossId % 4)
if bossRefreshInfo != nil {
info.NextRefreshTime = uint64(bossRefreshInfo.refreshTime.Unix()) * 1000
}
case model.SummonBossType_ChangePlay:
bossRefreshInfo := this.getBossRefreshInfoChangePlay(info.BossId)
if bossRefreshInfo != nil {
info.NextRefreshTime = uint64(bossRefreshInfo.refreshTime.Unix()) * 1000
} else {
continue
}
}
}
ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
}
for _, val := range this.refreshBossInfoList {
if hasBossList.Has(val.posId) {
continue
}
npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
if !ok1 {
util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
continue
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(val.bossData.Id),
CfgId: val.bossData.SummonId,
FighterNum: 0,
ExpireTime: 0,
NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
TotalHp: int32(npcCfgData.Hp),
CurHp: int32(npcCfgData.Hp),
}
ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
}
nowTime1 := util.GetCurrentTimeNow()
for _, val := range this.refreshBossInfoActivityList {
if hasChangePlayBossList.Has(val.bossData.Id) {
continue
}
npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
if !ok1 {
util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
continue
}
if nowTime1.Before(val.bossData.BossBeginTime) || nowTime1.After(val.bossData.BossEndTime) {
continue
}
info := &serverproto.WorldBossContentInfo{
BossId: int32(val.bossData.Id),
CfgId: val.bossData.SummonId,
FighterNum: 0,
ExpireTime: 0,
NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
TotalHp: int32(npcCfgData.Hp),
CurHp: int32(npcCfgData.Hp),
BossSummonType: val.bossData.SummonType,
}
ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
}
return ackMsg
}
}

View File

@ -0,0 +1,28 @@
package model
import (
"rocommon"
)
var (
updateList []interface{}
AoiLineMag *WorldBossManager = nil
)
type FruitUpdate struct {
rocommon.UpdateModule //eventqueue.go
}
// 定义初始化模块比方说角色管理模块任务模块等然后通过update来处理定时器相关的处理
func (this *FruitUpdate) Init() {
AoiLineMag = newWorldBossManager()
updateList = append(updateList, AoiLineMag)
}
func (this *FruitUpdate) Update(ms uint64) {
//对管理器进行更新操作
for _, data := range updateList {
data.(rocommon.UpdateLogic).Update(ms)
}
}

View File

@ -0,0 +1,129 @@
package model
import (
"encoding/base64"
"rocommon"
"rocommon/service"
"rocommon/util"
"roserver/baseserver/model"
"roserver/serverproto"
"strconv"
)
const (
WorldBossStatePrefix = "wb_state_"
WorldBossStateUidListPrefix = "wb_state_list_"
)
func GetWorldBossList(bossMag *WorldBossManager) bool {
wbList, err := service.GetRedis().HGetAll(WorldBossStatePrefix).Result()
if err != nil && err != service.NIL {
util.InfoF("GetWorldBossList key=%v err=%v", WorldBossStatePrefix, err)
return false
}
for key, val := range wbList {
worldBossId, _ := model.Str2Num(key)
if worldBossId > 0 {
msgStr, err := base64.StdEncoding.DecodeString(val)
if err != nil {
util.InfoF("GetWorldBossList key=%v err=%v", key, err)
continue
}
stateInfo := &serverproto.WorldBossStateInfo{}
err = rocommon.GetCodec().Unmarshal(msgStr, stateInfo)
if err != nil {
continue
}
//challenge uid list
key := WorldBossStateUidListPrefix + key
uidListLen, err := service.GetRedis().LLen(key).Result()
if uidListLen > 0 {
var idx int64 = 0
for {
uidStrList, _ := service.GetRedis().LRange(key, idx, idx+200).Result()
if len(uidStrList) <= 0 {
break
}
for idx := 0; idx < len(uidStrList); idx++ {
tmpUid, _ := model.Str2NumU64(uidStrList[idx])
if tmpUid > 0 {
stateInfo.UidList = append(stateInfo.UidList, tmpUid)
}
}
idx += 100
if idx >= uidListLen {
break
}
}
}
util.InfoF("GetWorldBossList key=%v err=%v len=%v", key, err, uidListLen)
//add failed,then remove current item
if !bossMag.AddBossFromDB(stateInfo) {
service.GetRedis().HDel(WorldBossStatePrefix, key)
}
}
}
return true
}
func UpdateWorldBossList(bossInfo *PlayerBoss) bool {
if bossInfo.bossUid <= 0 {
util.InfoF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
return false
}
stateInfo := &serverproto.WorldBossStateInfo{
BossId: int32(bossInfo.bossUid),
Hp: bossInfo.totalHp,
SummonTime: bossInfo.summonTime,
DurationTime: int32(bossInfo.durationTime / 1000),
SummonIdx: bossInfo.summonBossIdx,
SummonBossType: bossInfo.summonBossType,
}
msgData, err := rocommon.GetCodec().Marshal(stateInfo)
if err != nil {
util.InfoF("UpdateWorldBossList bossId=%v err=%v", bossInfo.bossUid, err)
return false
}
msgStr := base64.StdEncoding.EncodeToString(msgData.([]byte))
fieldStr := strconv.Itoa(int(bossInfo.bossUid))
service.GetRedis().HSet(WorldBossStatePrefix, fieldStr, msgStr)
return true
}
func DelWorldBossList(bossInfo *PlayerBoss) bool {
if bossInfo.bossUid <= 0 {
util.InfoF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
return false
}
//boss info
fieldStr := strconv.Itoa(int(bossInfo.bossUid))
service.GetRedis().HDel(WorldBossStatePrefix, fieldStr)
//boss challenge uid list
bossIdStr := strconv.Itoa(int(bossInfo.bossUid))
keyStr := WorldBossStateUidListPrefix + bossIdStr
service.GetRedis().Del(keyStr)
return true
}
func WorldBossListAddChallenge(bossInfo *PlayerBoss, uid uint64) bool {
if uid <= 0 || bossInfo.bossUid <= 0 {
util.ErrorF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
return false
}
bossIdStr := strconv.Itoa(int(bossInfo.bossUid))
keyStr := WorldBossStateUidListPrefix + bossIdStr
service.GetRedis().LPush(keyStr, uid)
return true
}

View File

@ -0,0 +1,455 @@
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
}

View File

@ -0,0 +1,40 @@
package model
import (
"roserver/baseserver/model"
"unsafe"
)
const (
BOSS_STATE_FIGHTING = 1 //正在战斗中
BOSS_STATE_DIED = 2 //死亡
BOSS_STATE_TIME_OUT = 3 //召唤持续时间达到上限
BOSS_STATE_REFRESH = 4 //系统刷新方式
)
var bossStateFighting = func(r *model.StateMachineCore, data interface{}) int32 {
//parent := unsafe.Pointer(r)
//return (*PlayerBoss)(parent).pullingRoleList()
//return ROLE_STATE_PULLING_LIST
return BOSS_STATE_FIGHTING
}
var bossStateDie = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
if data != nil {
(*PlayerBoss)(parent).battleBossDie(data.(bool))
} else {
(*PlayerBoss)(parent).battleBossDie(false)
}
return BOSS_STATE_DIED
}
var bossStateTimeout = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
if data != nil {
(*PlayerBoss)(parent).battleTimeOut(data.(bool))
} else {
(*PlayerBoss)(parent).battleTimeOut(false)
}
return BOSS_STATE_TIME_OUT
}

View File

@ -0,0 +1,146 @@
package model
import (
"rocommon/rpc"
"rocommon/util"
"roserver/baseserver/model"
"roserver/serverproto"
)
/////////////////////////////////////////////发送数据
func (this *WorldBossManager) SendMapRouter(msg interface{}, uid uint64) bool {
data, meta, err := rpc.EncodeMessage(msg)
if err != nil {
util.InfoF("[SendMapRouter] EncodeMessage err:%v %v", err, msg)
return false
}
if this.mapRouterNode == "" {
this.mapRouterNode = model.SelectServiceNode(model.SERVICE_NODE_TYPE_MAP_ROUTER_STR, 0)
}
if this.mapRouterNode == "" {
util.InfoF("[SendMapRouter] map router node not exist msg:%v", msg)
return false
}
mapRouterSess := model.GetServiceNode(this.mapRouterNode)
if mapRouterSess == nil {
util.InfoF("[SendMapRouter] aoiRouter session not exist:%v", this.mapRouterNode)
} else {
//如果玩家信息存在ClientId中存放的是玩家ID否则存放的是玩家的gate sessionId
mapRouterSess.Send(&serverproto.ServiceTransmitAck{
MsgId: uint32(meta.ID),
MsgData: data,
//todo...
// 对应的玩家 gate channelId channelRoleList[key]
// 后续和gate直接通信时使用如果断线重连需要重新绑定
ClientId: uid, //对应的玩家 gate uuid uuidRoleList[key]
})
}
return true
}
func (this *WorldBossManager) SendSocial(msg interface{}) bool {
data, meta, err := rpc.EncodeMessage(msg)
if err != nil {
util.ErrorF("[SendSocial] EncodeMessage err:%v %v", err, msg)
return false
}
if this.socialNode == "" {
this.socialNode = model.SelectServiceNode(model.SERVICE_NODE_TYPE_SOCIAL_STR, 0)
}
if this.socialNode == "" {
util.ErrorF("[SendSocial] social node not exist msg:%v", msg)
return false
}
socialSess := model.GetServiceNode(this.socialNode)
if socialSess == nil {
util.ErrorF("[SendSocial] social session not exist:%v", this.mapRouterNode)
} else {
//如果玩家信息存在ClientId中存放的是玩家ID否则存放的是玩家的gate sessionId
socialSess.Send(&serverproto.ServiceTransmitAck{
MsgId: uint32(meta.ID),
MsgData: data,
})
}
return true
}
func SendDB(msg interface{}) bool {
data, meta, err := rpc.EncodeMessage(msg)
if err != nil {
util.InfoF("[SendDB] EncodeMessage err:%v %v", err, msg)
return false
}
dbNode := model.SelectServiceNode(model.SERVICE_NODE_TYPE_DB_STR, 0)
if dbNode == "" {
util.InfoF("[SendDB] db node not exist msg:%v", msg)
return false
}
dbSess := model.GetServiceNode(dbNode)
if dbSess == nil {
util.ErrorF("[SendDB] db session not exist:%v", dbSess)
return false
} else {
//如果玩家信息存在ClientId中存放的是玩家ID否则存放的是玩家的gate sessionId
dbSess.Send(&serverproto.ServiceTransmitAck{
MsgId: uint32(meta.ID),
MsgData: data,
})
}
return true
}
func (this *WorldBossManager) SendGame(msg interface{}, gameNode string, uid uint64) bool {
return this.SendServiceByNode(msg, gameNode, uid)
}
func (this *WorldBossManager) SendServiceByNode(msg interface{}, serviceNode string, uid uint64) bool {
data, meta, err := rpc.EncodeMessage(msg)
if err != nil {
util.InfoF("[SendServiceByNode] EncodeMessage err:%v %v", err, msg)
return false
}
nodeSess := model.GetServiceNode(serviceNode)
if nodeSess == nil {
util.InfoF("[SendServiceByNode] service session not exist:%v", serviceNode)
} else {
//如果玩家信息存在ClientId中存放的是玩家ID否则存放的是玩家的gate sessionId
ackMsg := &serverproto.ServiceTransmitAck{
MsgId: uint32(meta.ID),
MsgData: data,
}
if uid != 0 {
ackMsg.ClientId = uid
}
nodeSess.Send(ackMsg)
}
return true
}
func SendToAllGame(msg interface{}) {
data, info, err := rpc.EncodeMessage(msg)
if err != nil {
util.InfoF("[SendGame]EncodeMessage err:%v %v", err, msg)
return
}
sendMsg := &serverproto.ServiceTransmitAck{
MsgId: uint32(info.ID),
MsgData: data,
}
serviceList := model.GetAllServiceNodeByName(model.SERVICE_NODE_TYPE_GAME_STR)
if len(serviceList) > 0 {
for _, node := range serviceList {
gameSess := model.GetServiceNode(node)
if gameSess != nil {
gameSess.Send(sendMsg)
}
}
}
}

View File

@ -0,0 +1,61 @@
package msg
import (
"rocommon"
"rocommon/util"
"roserver/baseserver/model"
model2 "roserver/battleboss/model"
"roserver/serverproto"
)
func init() {
//玩家下线处理/主动离开boss场景
serverproto.Handle_BATTLEBOSS_SSPlayerOfflineNtf = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
msg := ev.Msg().(*serverproto.SSPlayerOfflineNtf)
util.InfoF("receive SSPlayerOfflineNtf msg:%v", msg)
model2.AoiLineMag.PlayerOffline(msg.Uid)
})
//挑战召唤物
serverproto.Handle_BATTLEBOSS_CSPlayerChallengeSummonReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
msg := ev.Msg().(*serverproto.CSPlayerChallengeSummonReq)
util.InfoF("receive CSPlayerChallengeSummonReq msg:%v", msg)
ret := model2.AoiLineMag.PlayerChallengeSummonBoss(msg.Uid, msg.ChallengeBossUid, cliId, msg.FightInfo)
ackMsg := &serverproto.SCPlayerChallengeSummonAck{
Error: int32(ret),
BossInfo: model2.AoiLineMag.GetWorldBossInfo(msg.ChallengeBossUid),
}
//删除boss使用
if ret == serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND {
ackMsg.BossInfo = &serverproto.WorldBossContentInfo{
BossId: int32(msg.ChallengeBossUid),
}
//更新boss信息
} else if ret == serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGE_NUM_LIMIT {
ackMsg.BossInfo = model2.AoiLineMag.GetWorldBossInfo(msg.ChallengeBossUid)
}
model.ServiceReplay(ev, ackMsg)
})
//血量上报
serverproto.Handle_BATTLEBOSS_CSPlayerChallengeHpReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
msg := ev.Msg().(*serverproto.CSPlayerChallengeHpReq)
util.InfoF("receive CSPlayerChallengeHpReq msg:%v %v", msg, cliId.SessID)
model2.AoiLineMag.DoSummonHp(cliId.SessID, msg.ActionUid, msg.DamageHp)
})
//获取WorldBoss列表
serverproto.Handle_BATTLEBOSS_CSPlayerWorldBossListReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
msg := ev.Msg().(*serverproto.CSPlayerWorldBossListReq)
util.DebugF("receive CSPlayerWorldBossListReq msg:%v %v", msg, cliId.SessID)
ackMsg := model2.AoiLineMag.GetWorldBossList()
model.ServiceReplay(ev, ackMsg)
})
}