agent.go 3.13 KB
package main

import (
	"github.com/golang/protobuf/proto"
	"math"
	"pro2d/cmd/gameserver/action"
	"pro2d/common"
	"pro2d/common/components"
	"pro2d/common/logger"
	"pro2d/models"
	"pro2d/pb"
	"sync"
	"sync/atomic"
)

type Agent struct {
	components.IConnection
	Server components.IServer

	Role			*models.RoleModel
	nextCheckTime   	int64 //下一次检查的时间
	lastHeartCheckTime 	int64
	heartTimeoutCount  	int   //超时次数
}

var agentPool = sync.Pool{New: func() interface{} { return new(Agent)}}

func NewAgent(s components.IServer) *Agent {
	a := agentPool.Get().(*Agent)
	a.Server = s

	a.nextCheckTime =      0
	a.lastHeartCheckTime = common.Timex()
	a.heartTimeoutCount=  0
	return a
}

func (c *Agent) OnConnection(conn components.IConnection)  {
	c.IConnection = conn
}

func (c *Agent) OnLogin(msg components.IMessage)  {
	//第一次登录
	errCode, irole := action.LoginRpc(msg)
	if errCode != 0 {
		c.Send(errCode, msg.GetHeader().GetMsgID(), nil)
		return
	}

	role := irole.(*models.RoleModel)
	protoMsg := &pb.RoleRsp{
		Role:   role.Role,
		Hero:   role.GetAllHero(),
		Team:   role.GetAllTeam(),
	}
	rsp, err := proto.Marshal(protoMsg)
	if err != nil {
		c.Send(-100, msg.GetHeader().GetMsgID(), nil)
		return
	}
	c.Send(errCode, msg.GetHeader().GetMsgID(), rsp)
	//登录成功,存储agent role
	c.Role = role
}

func (c *Agent) OnMessage(msg components.IMessage)  {
	atomic.StoreInt64(&c.lastHeartCheckTime, common.Timex())

	if msg.GetHeader().GetMsgID() == uint32(pb.ProtoCode_LoginReq) {
		c.OnLogin(msg)
		return
	}

	md := c.Server.GetAction(msg.GetHeader().GetMsgID())
	if md == nil {
		logger.Debug("cmd: %d, handler is nil", msg.GetHeader().GetMsgID())
		return
	}
	logger.Debug("protocolID: %d", msg.GetHeader().GetMsgID())
	//fmt.Printf("errCode: %d, protoMsg:%v\n", errCode, protoMsg)

	f := md.(func (msg components.IMessage)  (int32, interface{}))
	errCode, protoMsg := f(msg)

	if protoMsg == nil {
		c.Send(errCode, msg.GetHeader().GetMsgID(), nil)
		return
	}

	rsp, err := proto.Marshal(protoMsg.(proto.Message))
	if err != nil {
		c.Send(-100, msg.GetHeader().GetMsgID(), nil)
		return
	}
	c.Send(errCode, msg.GetHeader().GetMsgID(), rsp)
}

func (c *Agent) OnTimer()  {
	nextCheckTime := atomic.LoadInt64(&c.nextCheckTime)
	now := common.Timex()
	if now >= nextCheckTime {
		//检查心跳
		c.checkHeartBeat(now)
		nextCheckTime = now + common.HeartTimerInterval
		atomic.StoreInt64(&c.nextCheckTime, nextCheckTime)
	}

	if c.Role != nil {
		//role 恢复数据
		c.Role.OnRecoverTimer(now)
	}
}

func (c *Agent) OnClose()  {
	c.Close()
}

func (c *Agent) Close()  {
	c.Role = nil
	agentPool.Put(c)

	if c.Role == nil {
		return
	}

	c.Role.OnOfflineEvent()
}

func (c *Agent) checkHeartBeat(now int64)  {
	lastHeartCheckTime := atomic.LoadInt64(&c.lastHeartCheckTime)
	//logger.Debug("checkHeartBeat ID: %d, last: %d, now: %d", c.GetID(), lastHeartCheckTime, now)
	if math.Abs(float64(lastHeartCheckTime - now)) > common.HeartTimerInterval {
		c.heartTimeoutCount++
		if c.heartTimeoutCount >= common.HeartTimeoutCountMax {
			c.Stop()
			return
		}
		logger.Debug("timeout count: %d", c.heartTimeoutCount)
	}else {
		c.heartTimeoutCount = 0
	}
}