ecs/servers/game/handler/message.go
2025-07-16 10:05:22 +08:00

362 lines
9.8 KiB
Go

package handler
import (
"ecs/proto"
"ecs/proto/pb"
"ecs/servers/game/data"
"ecs/servers/game/logic"
"github.com/oylshe1314/framework/client/rpc"
"github.com/oylshe1314/framework/net"
"github.com/oylshe1314/framework/server"
"github.com/oylshe1314/framework/util"
)
type userAuthContext struct {
newId uint64
players []*logic.Player
verifyAck *proto.MsgUserTokenVerifyAck
}
type MessageHandler struct {
Handler
}
func NewMessageHandler(svr server.Server, httpRpcClient rpc.HttpRpcClient, tables *data.Tables, eventManager *logic.EventManager, serverManager *logic.ServerManager, playerManager *logic.PlayerManager) *MessageHandler {
return &MessageHandler{
Handler: Handler{
server: svr,
httpRpcClient: httpRpcClient,
tables: tables,
eventManager: eventManager,
serverManager: serverManager,
playerManager: playerManager},
}
}
func (this *MessageHandler) TipNotice(conn *net.Conn, err error) error {
//return conn.Send(uint16(pb.ModId_ModuleCommon), uint16(pb.MsgId_ModCommonTipNotice), &proto.MsgTipNoticeAck{Message: this.tables.TipNotice.GetLang(err.Error(), int(proto.LanguageSimpleChinese))})
return conn.Send(uint16(pb.ModId_ModuleCommon), uint16(pb.MsgId_ModCommonTipNotice), &pb.TipNoticeAck{Message: err.Error()})
}
func (this *MessageHandler) HandleConnect(conn *net.Conn) {
conn.Beating(uint16(pb.ModId_ModuleCommon), uint16(pb.MsgId_ModCommonHeartbeat), 60)
}
func (this *MessageHandler) HandleDisconnect(conn *net.Conn) {
var object = conn.Object()
if object == nil {
return
}
player, ok := object.(*logic.Player)
if !ok {
return
}
this.playerManager.Lost(player)
this.eventManager.PlayerLogin(player, logic.LogTypePlayerLost, 0, conn.RemoteAddr())
}
func (this *MessageHandler) Heartbeat(msg *net.Message) {
var req = new(pb.HeartbeatReq)
var err = msg.Read(req)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrMessageError)
return
}
var now = util.NowUnix()
msg.Conn.Beat(now)
var ack = &pb.HeartbeatAck{Index: req.Index, ServerTime: now}
_ = msg.Reply(ack)
}
func (this *MessageHandler) UserAuth(msg *net.Message) {
var req = new(pb.UserAuthReq)
var err = msg.Read(req)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrMessageError)
return
}
if len(req.Token) == 0 {
this.Logger().Error("User auth token is empty")
_ = this.TipNotice(msg.Conn, proto.ErrInvalidToken)
return
}
var verifyReq = &proto.MsgUserTokenVerifyReq{Token: req.GetToken(), ServerId: this.serverManager.Config().AreaConfig.Id}
if this.Logger().IsDebugEnabled() {
this.Logger().Debugf("[user:/verify/token] -> verifyReq: %s", util.ToJsonString(verifyReq))
}
var verifyAck = new(proto.MsgUserTokenVerifyAck)
reply, err := this.httpRpcClient.RandPost("user", "/verify/token", nil, verifyReq, verifyAck)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
if err = reply.Error(); err != nil {
this.Logger().Error(reply.Message)
_ = this.TipNotice(msg.Conn, err)
return
}
if reply.Data == nil {
this.Logger().Error("User auth token verify error, reply.Data == nil")
_ = this.TipNotice(msg.Conn, proto.ErrInvalidToken)
return
}
if this.Logger().IsDebugEnabled() {
this.Logger().Debugf("[user:/verify/token] <- verifyAck: %s", util.ToJsonString(verifyAck))
}
if !proto.CheckPlatform(verifyAck.Platform) {
this.Logger().Error("User auth token verify ack platform error, platfrom: ", verifyAck.Platform)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
if !proto.CheckChannel(verifyAck.Channel) {
this.Logger().Error("User auth token verify ack channel error, channel: ", verifyAck.Channel)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
players, err := this.playerManager.QueryPlayers(verifyAck.UserId) //query player from database
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
var roleList []*pb.Role
for i := range players {
if players[i].BanningTime < 0 || players[i].BanningTime > util.NowUnix() {
this.Logger().Error("Player role banned, roleId: %d, banTime: %d", players[i].RoleId, players[i].BanningTime)
continue
}
var player = this.playerManager.GetPlayer(players[i].RoleId) //get player from memory
if player != nil {
this.playerManager.Kick(player, proto.ErrLoginOtherPlace.Error())
this.eventManager.PlayerLogin(player, logic.LogTypePlayerKickOut, 0, player.Temp.Address)
player = nil
}
roleList = append(roleList, &pb.Role{Id: players[i].RoleId, Name: players[i].RoleName, Gender: players[i].RoleGender})
}
msg.Conn.BindObject(&userAuthContext{players: players, verifyAck: verifyAck})
var ack = &pb.UserAuthAck{UserId: verifyAck.UserId, RoleList: roleList}
_ = msg.Reply(ack)
}
func (this *MessageHandler) RoleCreate(msg *net.Message) {
var object = msg.Conn.Object()
if object == nil {
_ = this.TipNotice(msg.Conn, proto.ErrUserNotLogin)
return
}
authCtx, ok := object.(*userAuthContext)
if !ok {
_ = this.TipNotice(msg.Conn, proto.ErrBadRequest)
return
}
if len(authCtx.players) >= this.serverManager.Config().MaxRoles {
_ = this.TipNotice(msg.Conn, proto.ErrRolesAlreadyMax)
return
}
var req = new(pb.RoleCreateReq)
var err = msg.Read(req)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrMessageError)
return
}
if len(req.Name) == 0 {
this.Logger().Error("Parameter error, req.Name can not be empty")
_ = this.TipNotice(msg.Conn, proto.ErrParameterError)
return
}
if req.Gender != 0 && req.Gender != 1 {
this.Logger().Error("Parameter error, req.Gender: ", req.Gender)
_ = this.TipNotice(msg.Conn, proto.ErrParameterError)
return
}
roleId, err := this.playerManager.NewRoleId()
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
var areaConfig = this.serverManager.Config().AreaConfig
var player = this.playerManager.NewPlayer()
player.RoleId = roleId
player.Platform = authCtx.verifyAck.Platform
player.Channel = authCtx.verifyAck.Channel
player.UserId = authCtx.verifyAck.UserId
player.ServerId = areaConfig.Id
player.Username = authCtx.verifyAck.Username
player.CreateTime = util.NowUnix()
player.Language = 0
player.RoleName = req.Name
player.RoleGender = req.Gender
err = this.playerManager.SavePlayer(player)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
authCtx.newId = player.RoleId
authCtx.players = append(authCtx.players, player)
_ = msg.Reply(&pb.RoleCreateAck{Role: &pb.Role{Id: player.RoleId, Name: player.RoleName, Gender: player.RoleGender}})
this.eventManager.PlayerCreate(player, logic.LogTypePlayerRoleCreate)
}
func (this *MessageHandler) RoleLogin(msg *net.Message) {
var object = msg.Conn.Object()
if object == nil {
_ = this.TipNotice(msg.Conn, proto.ErrUserNotLogin)
return
}
authCtx, ok := object.(*userAuthContext)
if !ok {
_ = this.TipNotice(msg.Conn, proto.ErrBadRequest)
return
}
if len(authCtx.players) == 0 {
_ = this.TipNotice(msg.Conn, proto.ErrRoleNotCreated)
return
}
var req = new(pb.RoleLoginReq)
var err = msg.Read(req)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrMessageError)
return
}
if req.RoleId == 0 {
this.Logger().Error("Parameter error, req.RoleId: ", req.RoleId)
_ = this.TipNotice(msg.Conn, proto.ErrParameterError)
return
}
var player *logic.Player
for i := range authCtx.players {
if authCtx.players[i].RoleId == req.RoleId {
player = authCtx.players[i]
if player.RoleId != authCtx.newId {
player, err = this.playerManager.QueryPlayer(req.RoleId)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrInternalError)
return
}
}
break
}
}
if player == nil {
this.Logger().Error("Parameter error, req.RoleId: ", req.RoleId)
_ = this.TipNotice(msg.Conn, proto.ErrRoleNotFound)
return
}
player.Temp.Address = msg.Conn.RemoteAddr()
msg.Conn.BindObject(player)
this.playerManager.Enter(player, msg.Conn)
this.eventManager.PlayerLogin(player, logic.LogTypePlayerRoleLogin, 0, msg.Conn.RemoteAddr())
}
func (this *MessageHandler) RoleLogout(msg *net.Message) {
var object = msg.Conn.Object()
if object == nil {
return
}
msg.Conn.ClearObject()
player, ok := object.(*logic.Player)
if !ok {
return
}
this.playerManager.Exit(player)
this.eventManager.PlayerLogin(player, logic.LogTypePlayerRoleLogout, 0, msg.Conn.RemoteAddr())
}
func (this *MessageHandler) Reconnect(msg *net.Message) {
var req = new(pb.ReconnectReq)
var err = msg.Read(req)
if err != nil {
this.Logger().Error(err)
_ = this.TipNotice(msg.Conn, proto.ErrMessageError)
_ = msg.Conn.Send(uint16(pb.ModId_ModuleLevel), uint16(pb.MsgId_ModLevelSceneEnter), &pb.SceneEnterAck{SceneId: 2})
return
}
var player = this.playerManager.GetPlayer(req.RoleId)
if player == nil {
_ = this.TipNotice(msg.Conn, proto.ErrUserNotLogin)
_ = msg.Conn.Send(uint16(pb.ModId_ModuleLevel), uint16(pb.MsgId_ModLevelSceneEnter), &pb.SceneEnterAck{SceneId: 2})
return
}
player.Temp.Address = msg.Conn.RemoteAddr()
msg.Conn.BindObject(player)
this.playerManager.Reenter(player, msg.Conn)
this.eventManager.PlayerLogin(player, logic.LogTypePlayerReconnect, 0, msg.Conn.RemoteAddr())
}
func (this *MessageHandler) Message(msg *net.Message) {
var object = msg.Conn.Object()
if object == nil {
_ = this.TipNotice(msg.Conn, proto.ErrUserNotLogin)
return
}
player, ok := object.(*logic.Player)
if !ok {
_ = this.TipNotice(msg.Conn, proto.ErrRoleNotLogged)
return
}
//player = this.playerManager.GetPlayer(player.UserId)
//if player == nil {
// _ = this.TipNotice(msg.Conn, proto.ErrRoleNotLogged)
// return
//}
this.playerManager.Handle(player, msg)
}