-
Notifications
You must be signed in to change notification settings - Fork 4
/
route.go
134 lines (124 loc) · 3.86 KB
/
route.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package game
import (
"github.com/fish-tennis/gentity"
"github.com/fish-tennis/gentity/util"
. "github.com/fish-tennis/gnet"
"github.com/fish-tennis/gserver/cache"
"github.com/fish-tennis/gserver/db"
"github.com/fish-tennis/gserver/internal"
"github.com/fish-tennis/gserver/logger"
"github.com/fish-tennis/gserver/pb"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
)
// 路由参数
type RouteOptions struct {
// true:消息直接发给客户端
// false:放入玩家消息队列,消息将在玩家协程中被处理
DirectSendClient bool
// 路由到指定的服务器
ToServerId int32
// 先保存到数据库(player.pendingmessages),防止路由失败造成消息丢失
SaveDb bool
}
func NewRouteOptions() *RouteOptions {
return &RouteOptions{}
}
func DirectSendClientRouteOptions() *RouteOptions {
return &RouteOptions{
DirectSendClient: true,
}
}
func SaveDbRouteOptions() *RouteOptions {
return &RouteOptions{
SaveDb: true,
}
}
// set DirectSendClient
func (this *RouteOptions) SetDirectSendClient(directSendClient bool) *RouteOptions {
this.DirectSendClient = directSendClient
return this
}
// set ToServerId
func (this *RouteOptions) SetToServerId(toServerId int32) *RouteOptions {
this.ToServerId = toServerId
return this
}
// 路由玩家消息
// 如果目标玩家在本服务器,则直接路由到本服务器上的玩家
// 如果目标玩家在另一个服务器上,则转发到目标服务器 ServerA -> ServerB -> Player
//
// DirectSendClientRouteOptions():
// 消息直接转发给客户端,不做逻辑处理 ServerA -> ServerB -> Client
//
// 举例:
// 有人申请加入公会,公会广播该消息给公会成员,ServerB收到消息后,直接把消息发给客户端(Player.Send),而不需要放入玩家的逻辑消息队列(Player.OnRecvPacket)
//
// SaveDbRouteOptions(): 消息先保存数据库再转发,防止丢失
// 举例:
// 公会会长同意了玩家A的入会申请,此时玩家A可能不在线,就把该消息存入玩家的数据库,待玩家下次上线时,从数据库取出该消息,并进行相应的逻辑处理
func RoutePlayerPacket(playerId int64, cmd PacketCommand, message proto.Message, opts ...*RouteOptions) bool {
var (
directSendClient = false
toServerId = int32(0)
saveDb = false
)
for _,opt := range opts {
directSendClient = opt.DirectSendClient
//toServerId = opt.ToServerId
saveDb = opt.SaveDb
}
player := GetPlayer(playerId)
if player != nil {
if directSendClient {
return player.Send(cmd, message)
} else {
player.OnRecvPacket(NewProtoPacket(cmd, message))
}
return true
}
if saveDb {
any,err := anypb.New(message)
if err != nil {
logger.Error("RoutePlayerPacket %v err:%v", playerId, err)
return false
}
routePacket := &pb.RoutePlayerMessage{
ToPlayerId: playerId,
PacketCommand: int32(cmd),
DirectSendClient: false,
MessageId: util.GenUniqueId(), // 消息号生成唯一id
PacketData: any,
}
routePacketBytes,err := proto.Marshal(routePacket)
if err != nil {
logger.Error("RoutePlayerPacket %v err:%v", playerId, err)
return false
}
err = db.GetPlayerDb().SaveComponentField(playerId, "pendingmessages", util.Itoa(routePacket.MessageId), routePacketBytes)
if err != nil {
logger.Error("RoutePlayerPacket %v err:%v", playerId, err)
return false
}
}
if toServerId == 0 {
_,toServerId = cache.GetOnlinePlayer(playerId)
if toServerId == 0 {
return false
}
if toServerId == gentity.GetApplication().GetId() {
return false
}
}
any,err := anypb.New(message)
if err != nil {
logger.Error("RoutePlayerPacketWithServer %v err:%v", playerId, err)
return false
}
return internal.GetServerList().Send(toServerId, PacketCommand(pb.CmdRoute_Cmd_RoutePlayerMessage), &pb.RoutePlayerMessage{
ToPlayerId: playerId,
PacketCommand: int32(cmd),
DirectSendClient: directSendClient,
PacketData: any,
})
}