2026-01-08 12:45:09 +08:00

543 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package model
import (
"math/rand"
"rocommon"
"rocommon/service"
"rocommon/util"
"roserver/baseserver"
"roserver/baseserver/model"
"roserver/serverproto"
"runtime/debug"
"strconv"
"time"
"unsafe"
)
// 状态机枚举
const (
ROLE_STATE_ONLINE = 1 //在线
ROLE_STATE_OFFLINE = 2 //离线
ROLE_STATE_PULLING_LIST = 3 //拉取角色信息
ROLE_STATE_PULLED_LIST = 4 //拉去角色列表完成(从db返回信息)
ROLE_STATE_CREATE = 5 //正在创建角色
ROLE_STATE_CREATE_SUCCESS = 6 //创建角色成功
ROLE_STATE_CREATE_FAILURE = 7 //创建角色失败
ROLE_STATE_DB_ADD_ROLE_SUCCESS = 8 //数据库添加角色信息成功
ROLE_STATE_DB_ADD_ROLE_FAILURE = 9 //数据库添加角色信息失败
ROLE_STATE_SELECT_ROLE = 10
ROLE_STATE_SELECT_ROLE_SUCCESS = 11 //选择角色成功
ROLE_STATE_SELECT_ROLE_FAILURE = 12 //选择角色失败
ROLE_STATE_ZOMBIE = 13
)
// 状态机执行信息
// 拉取角色信息
var pullingRoleList = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).pullingRoleList()
//return ROLE_STATE_PULLING_LIST
}
var pulledRoleList = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).pulledRoleList()
//return ROLE_STATE_PULLED_LIST
}
var createRole = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).createRole()
//return ROLE_STATE_CREATE
}
var createDbRoleSuccess = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).createDbRoleSuccess()
//return ROLE_STATE_DB_ADD_ROLE_SUCCESS
}
var createDbRoleFailure = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).createDbRoleFailure(data)
//return ROLE_STATE_DB_ADD_ROLE_FAILURE
}
var SelectingRole = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).SelectingRole()
//return ROLE_STATE_SELECT_ROLE
}
var SelectRoleSuccess = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).SelectRoleSuccess()
//return ROLE_STATE_SELECT_ROLE_SUCCESS
}
var RoleOnline = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).RoleOnline(data)
}
var RoleOffline = func(r *model.StateMachineCore, data interface{}) int32 {
parent := unsafe.Pointer(r)
return (*Role)(parent).RoleOffline()
//return ROLE_STATE_OFFLINE
}
func (this *Role) pullingRoleList() int32 {
util.DebugF("pullingRoleList... %v,%v", this.cliID, this.UuidList)
//选择DB节点
this.dbNode = model.SelectServiceNode(model.SERVICE_NODE_TYPE_DB_STR, 0)
this.setUUid(0) //获取成功后会再次赋值
//发送获取角色信息消息给db服务器
msg := &serverproto.SSAccountGetRoleListReq{
ChannelId: this.cliID.SessID,
OpenId: this.openId,
//ZoneId: int32(service.GetServiceConfig().Node.Zone),
}
//使用服务器选择的服务器使用
if this.selectZone > 0 {
msg.ZoneId = this.selectZone
} else {
msg.ZoneId = int32(service.GetServiceConfig().Node.Zone)
}
ret := this.SendDb(msg)
if !ret {
ackMsg := &serverproto.SCLoginAck{
Error: int32(serverproto.ErrorCode_ERROR_FAIL),
}
this.ReplayGate(ackMsg, true)
return ROLE_STATE_ZOMBIE
}
return ROLE_STATE_PULLING_LIST
}
func (this *Role) pulledRoleList() int32 {
util.DebugF("pulledRoleList... %v,%v", this.cliID, this.UuidList)
//角色信息不存在则创建角色信息
if len(this.UuidList) <= 0 {
if service.GetServiceConfig().Node.RobotMode == 2 {
this.LoginAck(serverproto.ErrorCode_ERROR_ROLE_CAN_NOT_REGISTER)
return ROLE_STATE_ZOMBIE
} else {
if service.GetServiceConfig().Node.AuthMode == AUTHMODE_ACTIVE {
this.LoginAck(serverproto.ErrorCode_ERROR_ROLE_NOT_FOUND_NEED_ACTIVE_CODE)
} else {
this.LoginAck(serverproto.ErrorCode_ERROR_ROLE_NOT_FOUND)
}
}
return ROLE_STATE_PULLED_LIST
} else {
//默认选择第一个,如果后续做成多角色系统,由客户端发起选择操作
this.SetSelectUUid(this.UuidList[0])
//this.SwitchState(ROLE_STATE_SELECT_ROLE, nil)
return ROLE_STATE_SELECT_ROLE
}
}
func (this *Role) createRole() int32 {
this.setUUid(model.GenerateUidByZone(int(this.GetSelectZone())))
//生成唯一索引ID失败
if this.GetUUid() <= 0 {
msg := &serverproto.SCCreateRoleAck{
Error: int32(serverproto.ErrorCode_ERROR_FAIL),
}
util.InfoF("createRole err uid invalid!!!")
this.ReplayGate(msg, true)
return ROLE_STATE_CREATE_FAILURE
}
RoleMag.Resolve(this)
data := this.base.roleBase
msg := &serverproto.SSAddRoleBaseReq{}
//初始化创建角色数据
msg.Base = &serverproto.RoleBase{
Id: this.uuid,
Coin: 0, //默认值通过配置表处理
Rmb: 0,
NickName: this.base.roleBase.NickName,
Sex: data.Sex,
Country: data.Country,
GuideId: 0,
RoleData: &serverproto.RoleData{
HeroData: &serverproto.HeroData{
Id: 1,
BaseLevel: 1,
ConfigId: data.RoleData.HeroData.ConfigId,
IsBattle: true,
Skill: &serverproto.RoleSkill{},
Slot: &serverproto.SlotData{
HeroId: 1,
},
SkillEquipSlot: &serverproto.SkillEquipSlotData{
HeroId: 1,
},
},
HeadId: this.base.roleBase.RoleData.HeadId,
},
FashionData: data.FashionData,
}
//激活码
msg.ActiveCode = this.activeCode
msg.OpenId = this.GetOpenId()
msg.SubPlatform = this.GetSubPlatform()
msg.Zone = this.GetSelectZone()
this.SendDb(msg)
return ROLE_STATE_CREATE
}
type OpenIdServeNode struct {
ServerId int32
HeadFrameId int32
Level int32
JobCfgId int32
Gender int32
NickName string
}
func (this *Role) createDbRoleSuccess() int32 {
//todo...流程上有问题,这边需要返回成功才能做后续操作
//角色基本信息添加成功后再添加到openId对应的玩家列表中(多角色登录处理)
if this.GetUUid() == 0 {
util.ErrorF("createDbRoleSuccess failed uuid is zero openId=%d sessionId=%d", this.GetOpenId(), this.cliID)
return ROLE_STATE_ZOMBIE
}
msg := &serverproto.SSAccountAddRoleNtf{}
accRole := &serverproto.AccountRole{}
accRole.Uid = this.GetUUid()
accRole.OpenId = this.GetOpenId()
accRole.RegisterTime = util.GetTimeMilliseconds()
if this.GetSelectZone() > 0 {
accRole.ZoneId = this.GetSelectZone()
} else {
accRole.ZoneId = int32(service.GetServiceConfig().Node.Zone)
}
msg.Roles = append(msg.Roles, accRole)
util.DebugF("uid=%v SSAccountAddRoleNtf send to db ", accRole.Uid)
this.SendDb(msg)
//todo...
// 默认选择创建的角色,后续做成多角色的话需要客户端发起选择角色操作
// 注意以后合区操作
this.UuidList = append(this.UuidList, this.GetUUid())
this.UuidRoleList[this.GetUUid()] = accRole
this.SetSelectUUid(this.GetUUid())
this.setUUid(this.GetUUid())
//创建角色成功后发送给roweb服务器记录当前openID登录的服务器信息
this.registerServerList(0, 1)
//创建角色成功发送给客户端用户sdk处理
createMsg := &serverproto.SCCreateRoleAck{
Error: int32(serverproto.ErrorCode_ERROR_OK),
CreateRoleTime: accRole.RegisterTime,
Uid: accRole.Uid,
Gender: this.GetRoleBase().GetRoleSex(),
}
this.ReplayGate(createMsg, true)
this.roleTask.AddTypeCnt(serverproto.TaskType_Eve_Login_Day, 1)
this.WriteMiaojuCreateRoleLog(accRole.RegisterTime)
return ROLE_STATE_SELECT_ROLE
}
func (this *Role) WriteMiaojuCreateRoleLog(regTime uint64) {
//写妙聚日志。
createRoleLog := &MiaojuLogCreateRole{
Properties: CreateRole{
PkgName: "",
},
}
createRoleLog.UUID = ""
createRoleLog.OpenId = this.GetLunaAccount()
createRoleLog.DistinctId = ""
createRoleLog.Type = "track"
createRoleLog.CurTime = time.Unix(int64(util.GetTimeSeconds()), 0).Format(util.DATE_FORMAT)
createRoleLog.EventName = "role_create"
createRoleLog.Properties.RoleId = strconv.FormatUint(this.GetUUid(), 10)
createRoleLog.Properties.OpenId = this.GetOpenId()
createRoleLog.Properties.ChannelId = this.clientParamInfo.AppChannel
createRoleLog.Properties.DeviceId = this.clientParamInfo.UnisdkDeviceId
createRoleLog.Properties.ServerId = strconv.Itoa(int(this.GetSelectZone()))
createRoleLog.Properties.RoleName = this.GetNickName()
createRoleLog.Properties.RoleLevel = int(this.GetRoleLevel())
createRoleLog.Properties.VIPLevel = int(this.GetRoleVipLevel())
createRoleLog.Properties.RegisterCountry = ""
createRoleLog.Properties.CurTime = time.Unix(int64(util.GetTimeSeconds()), 0).Format(util.DATE_FORMAT)
createRoleLog.Properties.RegistTime = time.Unix(int64(regTime/1000), 0).Format(util.DATE_FORMAT)
createRoleLog.Log(this)
}
func (this *Role) createDbRoleFailure(data interface{}) int32 {
msg := &serverproto.SCCreateRoleAck{}
//msg.Error = data.(int32)
msg.Error = int32(serverproto.ErrorCode_ERROR_FAIL)
//log.Println("[createDbRoleFailure]")
util.InfoF("createDbRoleFailure")
this.ReplayGate(msg, true)
return ROLE_STATE_CREATE_FAILURE
}
func (this *Role) SelectingRole() int32 {
//检查合法性
valid := false
for _, data := range this.UuidList {
if data == this.SelectedUuid {
valid = true
break
}
}
if !valid {
this.LoginAck(serverproto.ErrorCode_ERROR_FAIL)
util.InfoF("select role not found uuid=%v", this.SelectedUuid)
return ROLE_STATE_ZOMBIE
}
this.setUUid(this.SelectedUuid)
return ROLE_STATE_SELECT_ROLE_SUCCESS
}
func (this *Role) SelectRoleSuccess() int32 {
//非创建流程时此时才获得角色的uuid
RoleMag.Resolve(this)
//缓存数据处理
if !this.reLogin {
//获取角色信息其他信息
msg := &serverproto.SSGetRoleReq{
RoleRegisterTime: this.RegisterTime,
}
this.SendDb(msg)
} else {
//数据在缓存中,直接切换成在线状态
//this.LoginAck(serverproto.ErrorCode_ERROR_OK)
return ROLE_STATE_ONLINE
}
return ROLE_STATE_SELECT_ROLE_SUCCESS
}
func (this *Role) RoleOnline(data interface{}) int32 {
if !this.isLoad {
this.KickNotSave(int32(serverproto.ErrorCode_ERROR_FAIL))
return ROLE_STATE_ZOMBIE
}
//be baned by webgm
banTime := this.isBan()
if banTime > 0 {
this.LoginAck(serverproto.ErrorCode_ERROR_ROLE_BANED)
this.KickWithSaveAndBan(int32(serverproto.ErrorCode_ERROR_ROLE_BANED), banTime)
return ROLE_STATE_ZOMBIE
}
this.LoginAck(serverproto.ErrorCode_ERROR_OK)
this.tmpState = true
//每日5点重置
if this.isDailyReset() {
this.DailyReset(false)
}
this.GetRoleBase().SetLastLoginTime()
//记录最近在线玩家列表
RoleMag.AddFIFOList(this.GetUUid())
//如果是从离线池中获取,停止离线定时器
this.offlineTimer.Cancel()
//启动数据保存定时器
nowTime := util.GetTimeMilliseconds()
this.saveTimer.Reset(nowTime, roleSaveTimeout, false)
this.mysqlLogSaveTimer.Reset(nowTime, mysqlSaveTimeout, false)
this.onlineProcess(this.reLogin)
//断线重连时不需要重新下发
//if data == nil || data.(bool) {
// this.StartupProto()
//}
//暂时处理成全量下发
this.StartupProto()
//获取创建角色时的奖励
//新注册的系统邮件需求
this.createRoleReward()
this.registerServerList(this.GetRoleBase().RoleData().HeadFrameId, this.GetRoleLevel())
///////////////////////////////
//通知social玩家上线
this.playerSocialOnline()
//上线请求公会信息//不一定是重登陆,有可能是顶号
/*//客户端确定会发,不需要做保底
reqMsg := &serverproto.SSOnlineGuildInfoReq{}
reqMsg.Uid = this.GetUUid()
reqMsg.GuildId = this.GetRoleGuildId()
reqMsg.IsRelogin = true
this.SendGuild(reqMsg)
*/
if this.reLogin {
this.playerGuildOnline(1)
}
//获取功能屏蔽标记
this.playerFuncDisableFlagInfo()
this.reLogin = false
if runeExplore := this.GetRoleRune(); runeExplore != nil {
runeExplore.RuneExploreEndAward()
}
util.InfoF("uuid=%v RoleOnline", this.uuid)
return ROLE_STATE_ONLINE
}
func (this *Role) RoleOffline() int32 {
////发送logout给客户端
//ntf := &serverproto.SCLogoutNtf{
// Error: int32(serverproto.ErrorCode_ERROR_OK),
//}
//this.ReplayGate(ntf, true)
//log.Println("[RoleOffline]SSUserKickNtf sessionID:",this.CliID().SessID)
if this.GetState() != ROLE_STATE_ONLINE {
return ROLE_STATE_ZOMBIE
}
//通知gate踢人并且不再反向通知logic服务器
kickNtf := &serverproto.SSUserKickNtf{
Error: int32(serverproto.ErrorCode_ERROR_OK),
ClientId: this.CliID().SessID,
}
this.ReplayGate(kickNtf, false)
this.GetRoleBase().OfflineOnlineTimeProcess()
//设置离线时间
onlineDuration := this.GetRoleBase().SetLastLoginTime()
//更新简介信息中的离线时间
this.GetRoleBase().UpdatePlayerBriefInfo(true)
//this.Save() 主update中会进行离线超时保存操作避免每次下线都进行数据库保存操作
this.saveTimer.Cancel()
//避免大批量离线操作
this.offlineTimer.Reset(util.GetTimeMilliseconds(), roleOfflineTimeout+time.Duration(rand.Int31n(500)), false)
///////////////////////////////
model.ElasticPutLogInfo(&model.ElasticLogST{
Uid: this.GetUUid(),
NickName: this.GetNickName(),
OpenId: this.GetOpenId(),
LogType: "RoleOffline",
LogDesc: "RoleOffline",
Param1: int(onlineDuration / 1000), //当前在线时间
})
this.MysqlLogNtf(serverproto.MysqlLogType_LType_Offline, []int32{int32(onlineDuration / 1000)}, 0)
//通知social玩家下线
this.playerSocialOffline()
//玩家离开世界boss
this.PlayerBattleBossOffline()
//离开aoi地图
//客户端没有发送离开协议,直接断开网络处理(下次重新进入还是说需要断线重连后也在AOI地图中)
this.playerMapOffline()
//下线公会处理
this.playerGuildOnline(2)
//注册到服务器列表(获取最近登录的服务器)
this.registerServerList(this.GetRoleBase().RoleData().HeadFrameId, this.GetRoleLevel())
//netease log
nLog := &NeteaseLogCreateRole{
OnlineTime: int(onlineDuration / 1000),
}
nLog.Log(this)
//log.Println("role offline uid:", this.GetUUid())
return ROLE_STATE_OFFLINE
}
func (this *Role) createRoleReward() {
//获取创建角色时的奖励
//新注册的系统邮件需求
if this.base.roleBase != nil && !this.base.roleBase.CreateReward {
this.base.roleBase.CreateReward = true
this.base.SetDirty(true)
this.GetRoleMail().AddMail(17, serverproto.MailType_MailType_System,
model.GlobalCreateRoleMailReward, nil, "", "")
}
}
func (this *Role) LoginAck(err serverproto.ErrorCode) {
ack := &serverproto.SCLoginAck{
ClientId: this.cliID.SessID,
Error: int32(err),
}
if err == serverproto.ErrorCode_ERROR_OK {
this.ReplayGate(ack, false) //gate需要做一些特殊处理
}
this.ReplayGate(ack, true)
}
func (this *Role) registerServerList(headFrameId, level int32) {
if headFrameId == 0 {
//注册日志添加到elasticsearch
model.ElasticPutLogInfo(&model.ElasticLogST{
Uid: this.GetUUid(),
NickName: this.GetNickName(),
OpenId: this.GetOpenId(),
LogType: "RoleRegister",
LogDesc: "RoleOnline",
})
}
jobCfgId := this.GetRoleBase().RoleData().HeroData.ConfigId
if headFrameId == 0 {
headFrameId = this.GetRoleBase().RoleData().HeadFrameId
}
zoneId := int32(service.GetServiceConfig().Node.Zone)
if this.GetSelectZone() > 0 {
zoneId = this.GetSelectZone()
}
gender := this.GetRoleBase().GetRoleSex() //1 female 2 male
nickName := this.GetNickName()
//tmpOpenId := model.ConvertPlatform(this.GetOpenId(), this.GetPlatform())
urlPath := "/serverlist/add?openid=" + this.GetOpenId()
uuid := this.GetUUid()
go func() {
defer func() {
//打印奔溃信息
if err := recover(); err != nil {
util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
}
}()
tmpRequest := &rocommon.HTTPRequest{}
tmpRequest.ReqCodecName = "httpform"
tmpRequest.ReqMsg = OpenIdServeNode{
ServerId: zoneId,
HeadFrameId: headFrameId,
Level: level, //默认1级
//RecordTime: uint32(util.GetTimeSeconds()),
JobCfgId: jobCfgId,
Gender: gender,
NickName: nickName,
}
parm := GetHttpNodeParam()
httpNode := baseserver.CreateHttpConnector(parm)
err := httpNode.(rocommon.HTTPConnector).Request("POST", urlPath, tmpRequest)
if err != nil {
util.InfoF("uid=%v http Request err=%v", uuid, err)
}
}()
}
// 礼包码获取奖励
func (this *Role) GetGiftReward(giftCode string) {
}