aozhiwei 0905ea20d6 1
2024-04-15 20:16:20 +08:00

396 lines
10 KiB
Go

package player
import (
"cs"
"f5"
"fmt"
"github.com/golang/protobuf/proto"
"mt"
"q5"
"net"
"main/constant"
"main/common"
"math/rand"
. "main/global"
)
type SocketCloseEventHandle struct {
entry q5.ListHead
cb func()
deleted bool
}
type pendingLoginRequest struct {
hdr *f5.MsgHdr
msg *cs.CMLogin
addTick int64
reqId int64
}
type playerMgr struct {
cs.MsgHandlerImpl
accountIdHash map[string]*player
socketHash map[f5.WspCliConn]*player
pendingLoginHash map[string]*pendingLoginRequest
socketCloseEventHash map[f5.WspCliConn]*q5.ListHead
currReqId int64
recommendHumans []*player
lastRefreshRecommendTick int64
}
func (this *playerMgr) Init() {
this.accountIdHash = make(map[string]*player)
this.socketHash = make(map[f5.WspCliConn]*player)
this.pendingLoginHash = make(map[string]*pendingLoginRequest)
this.socketCloseEventHash = make(map[f5.WspCliConn]*q5.ListHead)
f5.GetTimer().SetInterval(
1000,
func(e int32, args *q5.Args) {
if e == q5.TIMER_EXEC_EVENT {
mt.Table.MasterCluster.Traverse(
func(meta *mt.MasterCluster) bool {
this.reportServerState(meta.GetIp(), meta.GetListenPort())
return true
})
}
})
f5.GetApp().RegisterIMMsgHandle(
constant.IM_WSP_CLOSE,
func(args q5.Args) {
conn := args[0].(net.Conn)
deletedPlayers := make(map[f5.WspCliConn]*player)
for socket, hum := range this.socketHash {
if conn == socket.Conn {
deletedPlayers[socket] = hum
}
}
for socket, _ := range deletedPlayers {
this.OnSocketClose(socket)
}
})
}
func (this *playerMgr) UnInit() {
}
func (this *playerMgr) CMLogin(hdr *f5.MsgHdr, msg *cs.CMLogin) {
{
oldHum := this.internalGetPlayerBySocket(hdr.GetSocket())
if oldHum != nil {
rspMsg := cs.SMLogin{}
rspMsg.Errcode = proto.Int32(0)
rspMsg.Errmsg = proto.String("")
rspMsg.ServerInfo = proto.String(mt.Table.IMCluster.GetServerInfo())
oldHum.reBind(hdr.GetSocket())
oldHum.SendMsg(&rspMsg)
return
}
}
{
oldHum := this.internalGetPlayerByAccountId(msg.GetAccountId())
if oldHum != nil {
rspMsg := cs.SMLogin{}
rspMsg.Errcode = proto.Int32(0)
rspMsg.Errmsg = proto.String("")
rspMsg.ServerInfo = proto.String(mt.Table.IMCluster.GetServerInfo())
oldHum.reBind(hdr.GetSocket())
oldHum.SendMsg(&rspMsg)
return
}
}
reqId := this.genSeqId()
pendingReq := this.getPendingRequest(msg.GetAccountId())
if pendingReq == nil {
this.pendingLoginHash[msg.GetAccountId()] = &pendingLoginRequest{
hdr: hdr,
msg: msg,
addTick: q5.GetTickCount(),
reqId: reqId,
}
} else {
if pendingReq.msg.GetAccountId() == msg.GetAccountId() &&
pendingReq.msg.GetSessionId() == msg.GetSessionId() {
pendingReq.hdr = hdr
pendingReq.msg = msg
return
} else {
pendingReq.hdr = hdr
pendingReq.msg = msg
pendingReq.reqId = reqId
}
}
params := map[string]string{
"c": "User",
"a": "detailInfo",
"account_id": msg.GetAccountId(),
"session_id": msg.GetSessionId(),
"target_id": msg.GetAccountId(),
}
url := fmt.Sprintf("%s/webapp/index.php", mt.Table.Config.GetById(0).GetGameapiUrl())
rspObj := new(common.LoginRsp)
var evHandle **SocketCloseEventHandle = new(*SocketCloseEventHandle)
handle := f5.GetHttpCliMgr().SendJsStyleJsonRspRequest(
url,
params,
&rspObj,
func(rsp f5.HttpCliResponse) {
this.RemoveSocketCloseEvent(*evHandle)
this.apiAuthCb(hdr, msg, reqId, rsp, rspObj)
})
*evHandle = this.AddSocketCloseEvent(hdr.GetSocket(), func() {
handle.Cancel()
})
}
func (this *playerMgr) apiAuthCb(hdr *f5.MsgHdr, msg *cs.CMLogin, reqId int64,
rsp f5.HttpCliResponse, rspObj *common.LoginRsp) {
pendingReq := this.getPendingRequest(msg.GetAccountId())
if pendingReq == nil || pendingReq.reqId != reqId {
return
}
delete(this.pendingLoginHash, msg.GetAccountId())
rspMsg := cs.SMLogin{}
if rsp.GetErr() != nil {
GetWspListener().SendProxyMsg(pendingReq.hdr.Conn, pendingReq.hdr.SocketHandle,
rspMsg.Err(
2,
"server internal error"))
f5.GetSysLog().Info("Api服务器JSON 解析错误1\n")
return
}
if !rsp.JsonParseOk() {
GetWspListener().SendProxyMsg(pendingReq.hdr.Conn, pendingReq.hdr.SocketHandle,
rspMsg.Err(
2,
"server internal error"))
return
}
if rspObj.Errcode != 0 {
GetWspListener().SendProxyMsg(pendingReq.hdr.Conn, pendingReq.hdr.SocketHandle,
rspMsg.Err(
2,
"invalid session_id"))
f5.GetSysLog().Error("Api服务器errcode:%d", rspObj.Errcode)
return
}
hum := newPlayer()
hum.init(pendingReq, rspObj)
this.accountIdHash[hum.GetAccountId()] = hum
this.socketHash[pendingReq.hdr.GetSocket()] = hum
rspMsg.AccountId = proto.String(rspObj.Info.AccountID)
rspMsg.ServerInfo = proto.String(mt.Table.IMCluster.GetServerInfo())
GetWspListener().SendProxyMsg(hdr.Conn, hdr.SocketHandle, &rspMsg)
/*
// Add player profile
playerProfile := &PlayerProfile{
AccountId: accountId,
Username: resObj.Info.Name,
Avatar: q5.ToInt32(resObj.Info.Avatar),
AvatarHead: q5.ToInt32(resObj.Info.AvatarHead),
Star: q5.ToInt32(resObj.Info.Star),
Rank: q5.ToInt32(resObj.Info.Rank),
OnlineStatus: constant.OnlineStatus,
LastLoginTime: q5.ToInt32(resObj.Info.LastLoginTime),
}
if len(resObj.Info.HistorySeasons) == 1 {
playerProfile.TotalKills = q5.ToInt32(resObj.Info.HistorySeasons[0].TotalKills)
playerProfile.TotalWinTimes = q5.ToInt32(resObj.Info.HistorySeasons[0].WinTimes)
} else {
playerProfile.TotalKills = 0
playerProfile.TotalWinTimes = 0
}
version := cacheMgr.getCacheVersion()
cacheMgr.AddPlayerProfile(version, playerProfile)
friendMgr.LoadUser(accountId)
*/
}
func (this *playerMgr) reportServerState(masterIp string, masterPort int32) {
params := map[string]string{
"node_id": q5.ToString(f5.GetApp().GetNodeId()),
"instance_id": q5.ToString(f5.GetApp().GetInstanceId()),
"ip": mt.Table.IMCluster.GetIp(),
"port": q5.ToString(mt.Table.IMCluster.GetListenPort()),
"online_num": q5.ToString(0),
"room_num": q5.ToString(0),
"channel": q5.ToString(0),
"alive_count": q5.ToString(0),
"servicing": q5.ToString(1),
}
f5.GetHttpCliMgr().SendQuickChannelJsStyleRequest(
fmt.Sprintf("http://%s:%d/webapp/index.php?c=GS&a=report&", masterIp, masterPort),
params,
func(rsp f5.HttpCliResponse) {
//f5.GetSysLog().Info(rsp.GetRawData())
})
}
func (this *playerMgr) getPendingRequest(accountId string) *pendingLoginRequest {
req, ok := this.pendingLoginHash[accountId]
if ok {
return req
}
return nil
}
func (this *playerMgr) genSeqId() int64 {
this.currReqId++
reqId := this.currReqId
return reqId
}
func (this *playerMgr) GetPlayerByAccountId(accountId string) common.Player {
hum := this.internalGetPlayerByAccountId(accountId)
if hum != nil {
return hum
} else {
return nil
}
}
func (this *playerMgr) GetPlayerBySocket(socket f5.WspCliConn) common.Player {
hum := this.internalGetPlayerBySocket(socket)
if hum != nil {
return hum
} else {
return nil
}
}
func (this *playerMgr) internalGetPlayerByAccountId(accountId string) *player {
hum, ok := this.accountIdHash[accountId]
if ok {
return hum
}
return nil
}
func (this *playerMgr) internalGetPlayerBySocket(socket f5.WspCliConn) *player {
hum, ok := this.socketHash[socket]
if ok {
return hum
}
return nil
}
func (this *playerMgr) CMReconnect(hdr *f5.MsgHdr, msg *cs.CMReconnect) {
hum := this.internalGetPlayerByAccountId(msg.GetAccountId())
rspMsg := &cs.SMReconnect{}
if hum == nil {
GetWspListener().SendProxyMsg(hdr.Conn, hdr.SocketHandle,
rspMsg.Err(
constant.ERR_CODE_RECONNECT_PLAYER_NO_EXISTS,
"player no exists"))
return
}
if hum.GetSessionId() != msg.GetSessionId() {
GetWspListener().SendProxyMsg(hdr.Conn, hdr.SocketHandle,
rspMsg.Err(
constant.ERR_CODE_RECONNECT_PLAYER_SESSION_ID_NO_VALID,
"session_id no valid"))
return
}
hum.reBind(hdr.GetSocket())
hum.SendMsg(rspMsg)
}
func (this *playerMgr) OnSocketClose(conn f5.WspCliConn) {
{
l, ok := this.socketCloseEventHash[conn]
if ok {
for !l.Empty() {
handle := l.FirstEntry().(*SocketCloseEventHandle)
handle.cb()
if !handle.deleted {
this.RemoveSocketCloseEvent(handle)
}
}
}
}
hum := this.internalGetPlayerBySocket(conn)
if hum == nil {
return
}
delete(this.socketHash, conn)
hum.onOffline()
}
func (this *playerMgr) AddSocketCloseEvent(conn f5.WspCliConn, cb func()) *SocketCloseEventHandle {
evHandle := &SocketCloseEventHandle{}
evHandle.entry.Init(evHandle)
evHandle.cb = cb
l, ok := this.socketCloseEventHash[conn]
if !ok {
l = q5.NewListHead()
this.socketCloseEventHash[conn] = l
}
l.AddTail(&evHandle.entry)
return evHandle
}
func (this *playerMgr) RemoveSocketCloseEvent(evHandle *SocketCloseEventHandle) {
if !evHandle.deleted {
evHandle.entry.DelInit()
evHandle.deleted = true
} else {
panic("RemoveSocketCloseEvent error")
}
}
func (this *playerMgr) ProcessCMMsg(handler *cs.CsNetMsgHandler, hdr *f5.MsgHdr) {
switch handler.HandlerId {
case constant.PLAYER_MGR_HANDLER_ID:
cs.DispatchMsg(handler, hdr, this)
case constant.PLAYER_HANDLER_ID:
hum := this.internalGetPlayerBySocket(hdr.GetSocket())
if hum != nil {
cs.DispatchMsg(handler, hdr, hum)
}
}
}
func (this *playerMgr) traverseHumans(cb func(*player) bool) {
for _, hum := range(this.accountIdHash) {
if !cb(hum) {
break
}
}
}
func (this *playerMgr) GetRecommendPlayers(excludeHums map[string]int32, outHums map[string]int32, num int32) {
if len(this.accountIdHash) < 50 ||
q5.GetTickCount() - this.lastRefreshRecommendTick > 1000 * 60 {
this.recommendHumans = []*player{}
this.traverseHumans(
func (hum *player) bool {
q5.AppendSlice(&this.recommendHumans, hum)
return true
})
rand.Shuffle(len(this.recommendHumans), func (i int, j int) {
this.recommendHumans[i], this.recommendHumans[j] = this.recommendHumans[j], this.recommendHumans[i]
})
}
if len(this.recommendHumans) > 0 {
rnd := rand.Int() % len(this.recommendHumans)
for i := rnd; i < len(this.recommendHumans); i++ {
if _, ok := excludeHums[this.recommendHumans[i].accountId]; !ok{
outHums[this.recommendHumans[i].accountId] = 1
}
}
for i := 0; i < len(this.recommendHumans); i++ {
if _, ok := excludeHums[this.recommendHumans[i].accountId]; !ok{
if len(outHums) > 5 {
break
}
if _, ok2 := outHums[this.recommendHumans[i].accountId]; !ok2 {
outHums[this.recommendHumans[i].accountId] = 1
}
}
}
}
}