添加lobby服

This commit is contained in:
liuxiaobo 2025-06-14 12:31:57 +08:00
parent e44d0a510e
commit 15a4b8256a
30 changed files with 516 additions and 236 deletions

View File

@ -25,7 +25,7 @@ const (
type BaseRoom[Seat ISeat] struct { type BaseRoom[Seat ISeat] struct {
id int id int
roomType int // 房间配置id 初级,中级,高级 roomType int // 房间配置id 初级,中级,高级
playType int // 玩法配置id color玩法id gameId int // 玩法配置id color玩法id
gameNo string gameNo string
seats []Seat seats []Seat
processor *processor.Processor processor *processor.Processor
@ -35,11 +35,11 @@ type BaseRoom[Seat ISeat] struct {
srv service.IService srv service.IService
} }
func NewBaseRoom[Seat ISeat](id, roomType, playType, seatNum int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) { func NewBaseRoom[Seat ISeat](id, roomType, gameId, seatNum int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) {
room := &BaseRoom[Seat]{ room := &BaseRoom[Seat]{
id: id, id: id,
roomType: roomType, roomType: roomType,
playType: playType, gameId: gameId,
gameNo: "", gameNo: "",
seats: make([]Seat, seatNum), seats: make([]Seat, seatNum),
timeTypes: make(map[timer.ITimeType]uint32), timeTypes: make(map[timer.ITimeType]uint32),
@ -59,8 +59,8 @@ func (r *BaseRoom[Seat]) RoomType() int {
return r.roomType return r.roomType
} }
func (r *BaseRoom[Seat]) PlayType() int { func (r *BaseRoom[Seat]) GameId() int {
return r.playType return r.gameId
} }
// 入座玩家数量 // 入座玩家数量
@ -257,10 +257,6 @@ func (r *BaseRoom[Seat]) RegisterMessages(metas processor.RegisterMetas) {
r.processor.RegisterMessages(metas) r.processor.RegisterMessages(metas)
} }
func (r *BaseRoom[Seat]) TimerDispatch(cmd timer.ITimeType, params ...any) error {
return r.timeProcessor.Dispatch(cmd, params...)
}
// 注册时间事件及处理 // 注册时间事件及处理
func (r *BaseRoom[Seat]) RegisterTimerMessages(metas processor.RegisterTimerMetas) { func (r *BaseRoom[Seat]) RegisterTimerMessages(metas processor.RegisterTimerMetas) {
r.timeProcessor.RegisterMessages(metas) r.timeProcessor.RegisterMessages(metas)

View File

@ -18,8 +18,8 @@ type HundredRoom struct {
users map[int64]IPlayer // 所有玩家 users map[int64]IPlayer // 所有玩家
} }
func NewHundredRoom(id, roomType, playType int, srv service.IService) (*HundredRoom, pb.ErrCode) { func NewHundredRoom(id, roomType, gameId int, srv service.IService) (*HundredRoom, pb.ErrCode) {
baseRoom, code := NewBaseRoom[*BaseSeat](id, roomType, playType, 0, srv) baseRoom, code := NewBaseRoom[*BaseSeat](id, roomType, gameId, 0, srv)
if code != pb.ErrCode_OK { if code != pb.ErrCode_OK {
return nil, code return nil, code
} }
@ -37,8 +37,8 @@ func (r *HundredRoom) RoomType() int {
return r.room.RoomType() return r.room.RoomType()
} }
func (r *HundredRoom) PlayType() int { func (r *HundredRoom) GameId() int {
return r.room.PlayType() return r.room.GameId()
} }
// 房间玩家数量 // 房间玩家数量
@ -169,10 +169,6 @@ func (r *HundredRoom) RegisterMessages(metas processor.RegisterMetas) {
r.room.RegisterMessages(metas) r.room.RegisterMessages(metas)
} }
func (r *HundredRoom) TimerDispatch(cmd timer.ITimeType, params ...any) error {
return r.room.TimerDispatch(cmd, params...)
}
// 注册时间事件及处理 // 注册时间事件及处理
func (r *HundredRoom) RegisterTimerMessages(metas processor.RegisterTimerMetas) { func (r *HundredRoom) RegisterTimerMessages(metas processor.RegisterTimerMetas) {
r.room.RegisterTimerMessages(metas) r.room.RegisterTimerMessages(metas)

View File

@ -8,7 +8,7 @@ import (
type IRoom interface { type IRoom interface {
Id() int Id() int
RoomType() int // 房间配置id RoomType() int // 房间配置id
PlayType() int GameId() int
OnInit() OnInit()
// SeatPlayerNum() int // SeatPlayerNum() int
// FindEmptySeat() bool // FindEmptySeat() bool

View File

@ -18,10 +18,10 @@ enum ChatType
// //
message ReqChat message ReqChat
{ {
ChatUser src_user = 1; // ChatUser srcUser = 1; //
ChatUser dst_user = 2; // ChatUser dstUser = 2; //
ChatType type = 3; // ChatType type = 3; //
ServiceTypeId game_id = 4; // id ServiceTypeId gameId = 4; // id
string content = 5; // string content = 5; //
} }

View File

@ -22,8 +22,8 @@ message ReqEnterRoom
message RspEnterRoom message RspEnterRoom
{ {
ErrCode code = 1; ErrCode code = 1;
int32 PlayType = 2; // id int32 gameId = 2; // id
int32 RoomType = 3; // , int32 roomType = 3; // ,
} }
// //

View File

@ -27,6 +27,12 @@ message NtfUserOnline
int64 user_id = 2; // id int64 user_id = 2; // id
} }
// 便使
message NtfUserInService
{
repeated string serviceNames = 3; //
}
// //
message ReqUserLogout message ReqUserLogout
{ {

View File

@ -8,8 +8,8 @@ import "user.proto";
// //
message ReqMatchRoom message ReqMatchRoom
{ {
int32 PlayType = 1; // id int32 gameId = 1; // id
int32 RoomType = 2; // , int32 roomType = 2; // ,
} }
// NotifyUserEnterRoom才是真房间 // NotifyUserEnterRoom才是真房间
@ -22,8 +22,8 @@ message RspMatchRoom
} }
ErrCode code = 1; ErrCode code = 1;
int32 PlayType = 2; // id int32 gameId = 2; // id
int32 RoomType = 3; // , int32 roomType = 3; // ,
GameUser User = 4; // GameUser User = 4; //
ColorInfo colorInfo = 20; // color玩法配置信息 ColorInfo colorInfo = 20; // color玩法配置信息

View File

@ -27,6 +27,7 @@ enum MsgId
ReqUserLoginId = 2100; // ReqUserLoginId = 2100; //
RspUserLoginId = 2101; RspUserLoginId = 2101;
NtfUserOnlineId = 2102; NtfUserOnlineId = 2102;
NtfUserInServiceId = 2103; // 便
ReqUserLogoutId = 2104; ReqUserLogoutId = 2104;
RspUserLogoutId = 2105; RspUserLogoutId = 2105;
NtfUserOfflineId = 2106; NtfUserOfflineId = 2106;

View File

@ -10,6 +10,7 @@ enum ServiceTypeId
STI_Chat = 102; // STI_Chat = 102; //
STI_DB = 103; // db服 STI_DB = 103; // db服
STI_Match = 104; // STI_Match = 104; //
STI_Lobby = 105; //
STI_ColorGame = 120; // color game STI_ColorGame = 120; // color game
} }

View File

@ -6,22 +6,22 @@ option go_package = "common/proto/pb";
// //
message ChatUser message ChatUser
{ {
int64 user_id = 1; int64 userId = 1;
string nickname = 2; // string nickname = 2; //
string avatar = 3; // string avatar = 3; //
string avatar_frame = 4; // string avatarFrame = 4; //
string vip_level = 5; // vip等级 string vipLevel = 5; // vip等级
} }
// //
message GameUser message GameUser
{ {
int64 user_id = 1; int64 userId = 1;
string nickname = 2; // string nickname = 2; //
string avatar = 3; // string avatar = 3; //
string avatar_frame = 4; // string avatarFrame = 4; //
int32 vip_level = 5; // vip等级 int32 vipLevel = 5; // vip等级
int32 vip_exp = 6; // vip经验 int32 vipExp = 6; // vip经验
int64 seat = 20; // int64 seat = 20; //
int64 gold = 25; // int64 gold = 25; //
} }

View File

@ -77,10 +77,10 @@ func (ChatType) EnumDescriptor() ([]byte, []int) {
// 聊天消息 // 聊天消息
type ReqChat struct { type ReqChat struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
SrcUser *ChatUser `protobuf:"bytes,1,opt,name=src_user,json=srcUser,proto3" json:"src_user,omitempty"` // 说话的人 SrcUser *ChatUser `protobuf:"bytes,1,opt,name=srcUser,proto3" json:"srcUser,omitempty"` // 说话的人
DstUser *ChatUser `protobuf:"bytes,2,opt,name=dst_user,json=dstUser,proto3" json:"dst_user,omitempty"` // 接收者 DstUser *ChatUser `protobuf:"bytes,2,opt,name=dstUser,proto3" json:"dstUser,omitempty"` // 接收者
Type ChatType `protobuf:"varint,3,opt,name=type,proto3,enum=pb.ChatType" json:"type,omitempty"` // 聊天类型 Type ChatType `protobuf:"varint,3,opt,name=type,proto3,enum=pb.ChatType" json:"type,omitempty"` // 聊天类型
GameId ServiceTypeId `protobuf:"varint,4,opt,name=game_id,json=gameId,proto3,enum=pb.ServiceTypeId" json:"game_id,omitempty"` // 游戏id只在本玩法中显示的聊天信息 GameId ServiceTypeId `protobuf:"varint,4,opt,name=gameId,proto3,enum=pb.ServiceTypeId" json:"gameId,omitempty"` // 游戏id只在本玩法中显示的聊天信息
Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` // 内容 Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` // 内容
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -157,12 +157,12 @@ const file_chat_proto_rawDesc = "" +
"\n" + "\n" +
"\n" + "\n" +
"chat.proto\x12\x02pb\x1a\n" + "chat.proto\x12\x02pb\x1a\n" +
"user.proto\x1a\rservice.proto\"\xc3\x01\n" + "user.proto\x1a\rservice.proto\"\xc0\x01\n" +
"\aReqChat\x12'\n" + "\aReqChat\x12&\n" +
"\bsrc_user\x18\x01 \x01(\v2\f.pb.ChatUserR\asrcUser\x12'\n" + "\asrcUser\x18\x01 \x01(\v2\f.pb.ChatUserR\asrcUser\x12&\n" +
"\bdst_user\x18\x02 \x01(\v2\f.pb.ChatUserR\adstUser\x12 \n" + "\adstUser\x18\x02 \x01(\v2\f.pb.ChatUserR\adstUser\x12 \n" +
"\x04type\x18\x03 \x01(\x0e2\f.pb.ChatTypeR\x04type\x12*\n" + "\x04type\x18\x03 \x01(\x0e2\f.pb.ChatTypeR\x04type\x12)\n" +
"\agame_id\x18\x04 \x01(\x0e2\x11.pb.ServiceTypeIdR\x06gameId\x12\x18\n" + "\x06gameId\x18\x04 \x01(\x0e2\x11.pb.ServiceTypeIdR\x06gameId\x12\x18\n" +
"\acontent\x18\x05 \x01(\tR\acontent*H\n" + "\acontent\x18\x05 \x01(\tR\acontent*H\n" +
"\bChatType\x12\x0e\n" + "\bChatType\x12\x0e\n" +
"\n" + "\n" +
@ -194,10 +194,10 @@ var file_chat_proto_goTypes = []any{
(ServiceTypeId)(0), // 3: pb.ServiceTypeId (ServiceTypeId)(0), // 3: pb.ServiceTypeId
} }
var file_chat_proto_depIdxs = []int32{ var file_chat_proto_depIdxs = []int32{
2, // 0: pb.ReqChat.src_user:type_name -> pb.ChatUser 2, // 0: pb.ReqChat.srcUser:type_name -> pb.ChatUser
2, // 1: pb.ReqChat.dst_user:type_name -> pb.ChatUser 2, // 1: pb.ReqChat.dstUser:type_name -> pb.ChatUser
0, // 2: pb.ReqChat.type:type_name -> pb.ChatType 0, // 2: pb.ReqChat.type:type_name -> pb.ChatType
3, // 3: pb.ReqChat.game_id:type_name -> pb.ServiceTypeId 3, // 3: pb.ReqChat.gameId:type_name -> pb.ServiceTypeId
4, // [4:4] is the sub-list for method output_type 4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type 4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension type_name

View File

@ -109,8 +109,8 @@ func (*ReqEnterRoom) Descriptor() ([]byte, []int) {
type RspEnterRoom struct { type RspEnterRoom struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Code ErrCode `protobuf:"varint,1,opt,name=code,proto3,enum=pb.ErrCode" json:"code,omitempty"` Code ErrCode `protobuf:"varint,1,opt,name=code,proto3,enum=pb.ErrCode" json:"code,omitempty"`
PlayType int32 `protobuf:"varint,2,opt,name=PlayType,proto3" json:"PlayType,omitempty"` // 玩法id GameId int32 `protobuf:"varint,2,opt,name=gameId,proto3" json:"gameId,omitempty"` // 玩法id
RoomType int32 `protobuf:"varint,3,opt,name=RoomType,proto3" json:"RoomType,omitempty"` // 房间类型,低级,中级,高级等 RoomType int32 `protobuf:"varint,3,opt,name=roomType,proto3" json:"roomType,omitempty"` // 房间类型,低级,中级,高级等
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -152,9 +152,9 @@ func (x *RspEnterRoom) GetCode() ErrCode {
return ErrCode_OK return ErrCode_OK
} }
func (x *RspEnterRoom) GetPlayType() int32 { func (x *RspEnterRoom) GetGameId() int32 {
if x != nil { if x != nil {
return x.PlayType return x.GameId
} }
return 0 return 0
} }
@ -255,11 +255,11 @@ const file_common_proto_rawDesc = "" +
"code.proto\"1\n" + "code.proto\"1\n" +
"\x0eNtfKickOutUser\x12\x1f\n" + "\x0eNtfKickOutUser\x12\x1f\n" +
"\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\"\x0e\n" + "\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\"\x0e\n" +
"\fReqEnterRoom\"g\n" + "\fReqEnterRoom\"c\n" +
"\fRspEnterRoom\x12\x1f\n" + "\fRspEnterRoom\x12\x1f\n" +
"\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\x12\x1a\n" + "\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\x12\x16\n" +
"\bPlayType\x18\x02 \x01(\x05R\bPlayType\x12\x1a\n" + "\x06gameId\x18\x02 \x01(\x05R\x06gameId\x12\x1a\n" +
"\bRoomType\x18\x03 \x01(\x05R\bRoomType\"\x0e\n" + "\broomType\x18\x03 \x01(\x05R\broomType\"\x0e\n" +
"\fReqLeaveRoom\"/\n" + "\fReqLeaveRoom\"/\n" +
"\fRspLeaveRoom\x12\x1f\n" + "\fRspLeaveRoom\x12\x1f\n" +
"\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04codeB\x11Z\x0fcommon/proto/pbb\x06proto3" "\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04codeB\x11Z\x0fcommon/proto/pbb\x06proto3"

View File

@ -203,6 +203,51 @@ func (x *NtfUserOnline) GetUserId() int64 {
return 0 return 0
} }
// 通知玩家在哪些服务里,方便玩家重进这些服务,重连使用
type NtfUserInService struct {
state protoimpl.MessageState `protogen:"open.v1"`
ServiceNames []string `protobuf:"bytes,3,rep,name=serviceNames,proto3" json:"serviceNames,omitempty"` // 玩家所在玩法的服务名
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NtfUserInService) Reset() {
*x = NtfUserInService{}
mi := &file_login_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NtfUserInService) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NtfUserInService) ProtoMessage() {}
func (x *NtfUserInService) ProtoReflect() protoreflect.Message {
mi := &file_login_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NtfUserInService.ProtoReflect.Descriptor instead.
func (*NtfUserInService) Descriptor() ([]byte, []int) {
return file_login_proto_rawDescGZIP(), []int{3}
}
func (x *NtfUserInService) GetServiceNames() []string {
if x != nil {
return x.ServiceNames
}
return nil
}
// 玩家登陆 // 玩家登陆
type ReqUserLogout struct { type ReqUserLogout struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@ -212,7 +257,7 @@ type ReqUserLogout struct {
func (x *ReqUserLogout) Reset() { func (x *ReqUserLogout) Reset() {
*x = ReqUserLogout{} *x = ReqUserLogout{}
mi := &file_login_proto_msgTypes[3] mi := &file_login_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -224,7 +269,7 @@ func (x *ReqUserLogout) String() string {
func (*ReqUserLogout) ProtoMessage() {} func (*ReqUserLogout) ProtoMessage() {}
func (x *ReqUserLogout) ProtoReflect() protoreflect.Message { func (x *ReqUserLogout) ProtoReflect() protoreflect.Message {
mi := &file_login_proto_msgTypes[3] mi := &file_login_proto_msgTypes[4]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -237,7 +282,7 @@ func (x *ReqUserLogout) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReqUserLogout.ProtoReflect.Descriptor instead. // Deprecated: Use ReqUserLogout.ProtoReflect.Descriptor instead.
func (*ReqUserLogout) Descriptor() ([]byte, []int) { func (*ReqUserLogout) Descriptor() ([]byte, []int) {
return file_login_proto_rawDescGZIP(), []int{3} return file_login_proto_rawDescGZIP(), []int{4}
} }
type RspUserLogout struct { type RspUserLogout struct {
@ -249,7 +294,7 @@ type RspUserLogout struct {
func (x *RspUserLogout) Reset() { func (x *RspUserLogout) Reset() {
*x = RspUserLogout{} *x = RspUserLogout{}
mi := &file_login_proto_msgTypes[4] mi := &file_login_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -261,7 +306,7 @@ func (x *RspUserLogout) String() string {
func (*RspUserLogout) ProtoMessage() {} func (*RspUserLogout) ProtoMessage() {}
func (x *RspUserLogout) ProtoReflect() protoreflect.Message { func (x *RspUserLogout) ProtoReflect() protoreflect.Message {
mi := &file_login_proto_msgTypes[4] mi := &file_login_proto_msgTypes[5]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -274,7 +319,7 @@ func (x *RspUserLogout) ProtoReflect() protoreflect.Message {
// Deprecated: Use RspUserLogout.ProtoReflect.Descriptor instead. // Deprecated: Use RspUserLogout.ProtoReflect.Descriptor instead.
func (*RspUserLogout) Descriptor() ([]byte, []int) { func (*RspUserLogout) Descriptor() ([]byte, []int) {
return file_login_proto_rawDescGZIP(), []int{4} return file_login_proto_rawDescGZIP(), []int{5}
} }
func (x *RspUserLogout) GetCode() ErrCode { func (x *RspUserLogout) GetCode() ErrCode {
@ -294,7 +339,7 @@ type NtfUserOffline struct {
func (x *NtfUserOffline) Reset() { func (x *NtfUserOffline) Reset() {
*x = NtfUserOffline{} *x = NtfUserOffline{}
mi := &file_login_proto_msgTypes[5] mi := &file_login_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -306,7 +351,7 @@ func (x *NtfUserOffline) String() string {
func (*NtfUserOffline) ProtoMessage() {} func (*NtfUserOffline) ProtoMessage() {}
func (x *NtfUserOffline) ProtoReflect() protoreflect.Message { func (x *NtfUserOffline) ProtoReflect() protoreflect.Message {
mi := &file_login_proto_msgTypes[5] mi := &file_login_proto_msgTypes[6]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -319,7 +364,7 @@ func (x *NtfUserOffline) ProtoReflect() protoreflect.Message {
// Deprecated: Use NtfUserOffline.ProtoReflect.Descriptor instead. // Deprecated: Use NtfUserOffline.ProtoReflect.Descriptor instead.
func (*NtfUserOffline) Descriptor() ([]byte, []int) { func (*NtfUserOffline) Descriptor() ([]byte, []int) {
return file_login_proto_rawDescGZIP(), []int{5} return file_login_proto_rawDescGZIP(), []int{6}
} }
func (x *NtfUserOffline) GetUserId() int64 { func (x *NtfUserOffline) GetUserId() int64 {
@ -347,7 +392,9 @@ const file_login_proto_rawDesc = "" +
"\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x14\n" + "\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x14\n" +
"\x05token\x18\x03 \x01(\tR\x05token\"(\n" + "\x05token\x18\x03 \x01(\tR\x05token\"(\n" +
"\rNtfUserOnline\x12\x17\n" + "\rNtfUserOnline\x12\x17\n" +
"\auser_id\x18\x02 \x01(\x03R\x06userId\"\x0f\n" + "\auser_id\x18\x02 \x01(\x03R\x06userId\"6\n" +
"\x10NtfUserInService\x12\"\n" +
"\fserviceNames\x18\x03 \x03(\tR\fserviceNames\"\x0f\n" +
"\rReqUserLogout\"0\n" + "\rReqUserLogout\"0\n" +
"\rRspUserLogout\x12\x1f\n" + "\rRspUserLogout\x12\x1f\n" +
"\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\")\n" + "\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\")\n" +
@ -366,19 +413,20 @@ func file_login_proto_rawDescGZIP() []byte {
return file_login_proto_rawDescData return file_login_proto_rawDescData
} }
var file_login_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_login_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_login_proto_goTypes = []any{ var file_login_proto_goTypes = []any{
(*ReqUserLogin)(nil), // 0: pb.ReqUserLogin (*ReqUserLogin)(nil), // 0: pb.ReqUserLogin
(*RspUserLogin)(nil), // 1: pb.RspUserLogin (*RspUserLogin)(nil), // 1: pb.RspUserLogin
(*NtfUserOnline)(nil), // 2: pb.NtfUserOnline (*NtfUserOnline)(nil), // 2: pb.NtfUserOnline
(*ReqUserLogout)(nil), // 3: pb.ReqUserLogout (*NtfUserInService)(nil), // 3: pb.NtfUserInService
(*RspUserLogout)(nil), // 4: pb.RspUserLogout (*ReqUserLogout)(nil), // 4: pb.ReqUserLogout
(*NtfUserOffline)(nil), // 5: pb.NtfUserOffline (*RspUserLogout)(nil), // 5: pb.RspUserLogout
(ErrCode)(0), // 6: pb.ErrCode (*NtfUserOffline)(nil), // 6: pb.NtfUserOffline
(ErrCode)(0), // 7: pb.ErrCode
} }
var file_login_proto_depIdxs = []int32{ var file_login_proto_depIdxs = []int32{
6, // 0: pb.RspUserLogin.code:type_name -> pb.ErrCode 7, // 0: pb.RspUserLogin.code:type_name -> pb.ErrCode
6, // 1: pb.RspUserLogout.code:type_name -> pb.ErrCode 7, // 1: pb.RspUserLogout.code:type_name -> pb.ErrCode
2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension type_name
@ -398,7 +446,7 @@ func file_login_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_login_proto_rawDesc), len(file_login_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_login_proto_rawDesc), len(file_login_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 6, NumMessages: 7,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -24,8 +24,8 @@ const (
// 房间匹配 // 房间匹配
type ReqMatchRoom struct { type ReqMatchRoom struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
PlayType int32 `protobuf:"varint,1,opt,name=PlayType,proto3" json:"PlayType,omitempty"` // 玩法id GameId int32 `protobuf:"varint,1,opt,name=gameId,proto3" json:"gameId,omitempty"` // 玩法id
RoomType int32 `protobuf:"varint,2,opt,name=RoomType,proto3" json:"RoomType,omitempty"` // 房间类型,低级,中级,高级等 RoomType int32 `protobuf:"varint,2,opt,name=roomType,proto3" json:"roomType,omitempty"` // 房间类型,低级,中级,高级等
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -60,9 +60,9 @@ func (*ReqMatchRoom) Descriptor() ([]byte, []int) {
return file_match_proto_rawDescGZIP(), []int{0} return file_match_proto_rawDescGZIP(), []int{0}
} }
func (x *ReqMatchRoom) GetPlayType() int32 { func (x *ReqMatchRoom) GetGameId() int32 {
if x != nil { if x != nil {
return x.PlayType return x.GameId
} }
return 0 return 0
} }
@ -78,8 +78,8 @@ func (x *ReqMatchRoom) GetRoomType() int32 {
type RspMatchRoom struct { type RspMatchRoom struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Code ErrCode `protobuf:"varint,1,opt,name=code,proto3,enum=pb.ErrCode" json:"code,omitempty"` Code ErrCode `protobuf:"varint,1,opt,name=code,proto3,enum=pb.ErrCode" json:"code,omitempty"`
PlayType int32 `protobuf:"varint,2,opt,name=PlayType,proto3" json:"PlayType,omitempty"` // 玩法id GameId int32 `protobuf:"varint,2,opt,name=gameId,proto3" json:"gameId,omitempty"` // 玩法id
RoomType int32 `protobuf:"varint,3,opt,name=RoomType,proto3" json:"RoomType,omitempty"` // 房间类型,低级,中级,高级等 RoomType int32 `protobuf:"varint,3,opt,name=roomType,proto3" json:"roomType,omitempty"` // 房间类型,低级,中级,高级等
User *GameUser `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"` // 玩家数据 User *GameUser `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"` // 玩家数据
ColorInfo *RspMatchRoom_ColorInfo `protobuf:"bytes,20,opt,name=colorInfo,proto3" json:"colorInfo,omitempty"` // color玩法配置信息 ColorInfo *RspMatchRoom_ColorInfo `protobuf:"bytes,20,opt,name=colorInfo,proto3" json:"colorInfo,omitempty"` // color玩法配置信息
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@ -123,9 +123,9 @@ func (x *RspMatchRoom) GetCode() ErrCode {
return ErrCode_OK return ErrCode_OK
} }
func (x *RspMatchRoom) GetPlayType() int32 { func (x *RspMatchRoom) GetGameId() int32 {
if x != nil { if x != nil {
return x.PlayType return x.GameId
} }
return 0 return 0
} }
@ -238,14 +238,14 @@ const file_match_proto_rawDesc = "" +
"\n" + "\n" +
"\vmatch.proto\x12\x02pb\x1a\n" + "\vmatch.proto\x12\x02pb\x1a\n" +
"code.proto\x1a\n" + "code.proto\x1a\n" +
"user.proto\"F\n" + "user.proto\"B\n" +
"\fReqMatchRoom\x12\x1a\n" + "\fReqMatchRoom\x12\x16\n" +
"\bPlayType\x18\x01 \x01(\x05R\bPlayType\x12\x1a\n" + "\x06gameId\x18\x01 \x01(\x05R\x06gameId\x12\x1a\n" +
"\bRoomType\x18\x02 \x01(\x05R\bRoomType\"\xd0\x01\n" + "\broomType\x18\x02 \x01(\x05R\broomType\"\xcc\x01\n" +
"\fRspMatchRoom\x12\x1f\n" + "\fRspMatchRoom\x12\x1f\n" +
"\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\x12\x1a\n" + "\x04code\x18\x01 \x01(\x0e2\v.pb.ErrCodeR\x04code\x12\x16\n" +
"\bPlayType\x18\x02 \x01(\x05R\bPlayType\x12\x1a\n" + "\x06gameId\x18\x02 \x01(\x05R\x06gameId\x12\x1a\n" +
"\bRoomType\x18\x03 \x01(\x05R\bRoomType\x12 \n" + "\broomType\x18\x03 \x01(\x05R\broomType\x12 \n" +
"\x04User\x18\x04 \x01(\v2\f.pb.GameUserR\x04User\x128\n" + "\x04User\x18\x04 \x01(\v2\f.pb.GameUserR\x04User\x128\n" +
"\tcolorInfo\x18\x14 \x01(\v2\x1a.pb.RspMatchRoom.ColorInfoR\tcolorInfo\x1a\v\n" + "\tcolorInfo\x18\x14 \x01(\v2\x1a.pb.RspMatchRoom.ColorInfoR\tcolorInfo\x1a\v\n" +
"\tColorInfo\"7\n" + "\tColorInfo\"7\n" +

View File

@ -42,6 +42,7 @@ const (
MsgId_ReqUserLoginId MsgId = 2100 // 玩家登陆 MsgId_ReqUserLoginId MsgId = 2100 // 玩家登陆
MsgId_RspUserLoginId MsgId = 2101 MsgId_RspUserLoginId MsgId = 2101
MsgId_NtfUserOnlineId MsgId = 2102 MsgId_NtfUserOnlineId MsgId = 2102
MsgId_NtfUserInServiceId MsgId = 2103 // 将玩家之前呆的服务同步给玩家,方便玩家重连进来
MsgId_ReqUserLogoutId MsgId = 2104 MsgId_ReqUserLogoutId MsgId = 2104
MsgId_RspUserLogoutId MsgId = 2105 MsgId_RspUserLogoutId MsgId = 2105
MsgId_NtfUserOfflineId MsgId = 2106 MsgId_NtfUserOfflineId MsgId = 2106
@ -78,6 +79,7 @@ var (
2100: "ReqUserLoginId", 2100: "ReqUserLoginId",
2101: "RspUserLoginId", 2101: "RspUserLoginId",
2102: "NtfUserOnlineId", 2102: "NtfUserOnlineId",
2103: "NtfUserInServiceId",
2104: "ReqUserLogoutId", 2104: "ReqUserLogoutId",
2105: "RspUserLogoutId", 2105: "RspUserLogoutId",
2106: "NtfUserOfflineId", 2106: "NtfUserOfflineId",
@ -109,6 +111,7 @@ var (
"ReqUserLoginId": 2100, "ReqUserLoginId": 2100,
"RspUserLoginId": 2101, "RspUserLoginId": 2101,
"NtfUserOnlineId": 2102, "NtfUserOnlineId": 2102,
"NtfUserInServiceId": 2103,
"ReqUserLogoutId": 2104, "ReqUserLogoutId": 2104,
"RspUserLogoutId": 2105, "RspUserLogoutId": 2105,
"NtfUserOfflineId": 2106, "NtfUserOfflineId": 2106,
@ -160,7 +163,7 @@ var File_msgId_proto protoreflect.FileDescriptor
const file_msgId_proto_rawDesc = "" + const file_msgId_proto_rawDesc = "" +
"\n" + "\n" +
"\vmsgId.proto\x12\x02pb*\x91\x05\n" + "\vmsgId.proto\x12\x02pb*\xaa\x05\n" +
"\x05MsgId\x12\x0e\n" + "\x05MsgId\x12\x0e\n" +
"\n" + "\n" +
"MI_Unknown\x10\x00\x12\x12\n" + "MI_Unknown\x10\x00\x12\x12\n" +
@ -174,7 +177,8 @@ const file_msgId_proto_rawDesc = "" +
"\tRspChatId\x10\xd1\x0f\x12\x13\n" + "\tRspChatId\x10\xd1\x0f\x12\x13\n" +
"\x0eReqUserLoginId\x10\xb4\x10\x12\x13\n" + "\x0eReqUserLoginId\x10\xb4\x10\x12\x13\n" +
"\x0eRspUserLoginId\x10\xb5\x10\x12\x14\n" + "\x0eRspUserLoginId\x10\xb5\x10\x12\x14\n" +
"\x0fNtfUserOnlineId\x10\xb6\x10\x12\x14\n" + "\x0fNtfUserOnlineId\x10\xb6\x10\x12\x17\n" +
"\x12NtfUserInServiceId\x10\xb7\x10\x12\x14\n" +
"\x0fReqUserLogoutId\x10\xb8\x10\x12\x14\n" + "\x0fReqUserLogoutId\x10\xb8\x10\x12\x14\n" +
"\x0fRspUserLogoutId\x10\xb9\x10\x12\x15\n" + "\x0fRspUserLogoutId\x10\xb9\x10\x12\x15\n" +
"\x10NtfUserOfflineId\x10\xba\x10\x12\x13\n" + "\x10NtfUserOfflineId\x10\xba\x10\x12\x13\n" +

View File

@ -30,6 +30,7 @@ const (
ServiceTypeId_STI_Chat ServiceTypeId = 102 // 聊天服 ServiceTypeId_STI_Chat ServiceTypeId = 102 // 聊天服
ServiceTypeId_STI_DB ServiceTypeId = 103 // db服 ServiceTypeId_STI_DB ServiceTypeId = 103 // db服
ServiceTypeId_STI_Match ServiceTypeId = 104 // 匹配服 ServiceTypeId_STI_Match ServiceTypeId = 104 // 匹配服
ServiceTypeId_STI_Lobby ServiceTypeId = 105 // 大厅服
ServiceTypeId_STI_ColorGame ServiceTypeId = 120 // color game ServiceTypeId_STI_ColorGame ServiceTypeId = 120 // color game
) )
@ -42,6 +43,7 @@ var (
102: "STI_Chat", 102: "STI_Chat",
103: "STI_DB", 103: "STI_DB",
104: "STI_Match", 104: "STI_Match",
105: "STI_Lobby",
120: "STI_ColorGame", 120: "STI_ColorGame",
} }
ServiceTypeId_value = map[string]int32{ ServiceTypeId_value = map[string]int32{
@ -51,6 +53,7 @@ var (
"STI_Chat": 102, "STI_Chat": 102,
"STI_DB": 103, "STI_DB": 103,
"STI_Match": 104, "STI_Match": 104,
"STI_Lobby": 105,
"STI_ColorGame": 120, "STI_ColorGame": 120,
} }
) )
@ -86,7 +89,7 @@ var File_service_proto protoreflect.FileDescriptor
const file_service_proto_rawDesc = "" + const file_service_proto_rawDesc = "" +
"\n" + "\n" +
"\rservice.proto\x12\x02pb*y\n" + "\rservice.proto\x12\x02pb*\x88\x01\n" +
"\rServiceTypeId\x12\x0f\n" + "\rServiceTypeId\x12\x0f\n" +
"\vSTI_Unknown\x10\x00\x12\f\n" + "\vSTI_Unknown\x10\x00\x12\f\n" +
"\bSTI_Gate\x10d\x12\r\n" + "\bSTI_Gate\x10d\x12\r\n" +
@ -94,7 +97,8 @@ const file_service_proto_rawDesc = "" +
"\bSTI_Chat\x10f\x12\n" + "\bSTI_Chat\x10f\x12\n" +
"\n" + "\n" +
"\x06STI_DB\x10g\x12\r\n" + "\x06STI_DB\x10g\x12\r\n" +
"\tSTI_Match\x10h\x12\x11\n" + "\tSTI_Match\x10h\x12\r\n" +
"\tSTI_Lobby\x10i\x12\x11\n" +
"\rSTI_ColorGame\x10xB\x11Z\x0fcommon/proto/pbb\x06proto3" "\rSTI_ColorGame\x10xB\x11Z\x0fcommon/proto/pbb\x06proto3"
var ( var (

View File

@ -24,11 +24,11 @@ const (
// 聊天中显示的玩家基础信息 // 聊天中显示的玩家基础信息
type ChatUser struct { type ChatUser struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` UserId int64 `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"`
Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称 Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称
Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像 Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像
AvatarFrame string `protobuf:"bytes,4,opt,name=avatar_frame,json=avatarFrame,proto3" json:"avatar_frame,omitempty"` // 头像框 AvatarFrame string `protobuf:"bytes,4,opt,name=avatarFrame,proto3" json:"avatarFrame,omitempty"` // 头像框
VipLevel string `protobuf:"bytes,5,opt,name=vip_level,json=vipLevel,proto3" json:"vip_level,omitempty"` // vip等级 VipLevel string `protobuf:"bytes,5,opt,name=vipLevel,proto3" json:"vipLevel,omitempty"` // vip等级
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -101,12 +101,12 @@ func (x *ChatUser) GetVipLevel() string {
// 房间内的玩家数据 // 房间内的玩家数据
type GameUser struct { type GameUser struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` UserId int64 `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"`
Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称 Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` // 昵称
Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像 Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` // 头像
AvatarFrame string `protobuf:"bytes,4,opt,name=avatar_frame,json=avatarFrame,proto3" json:"avatar_frame,omitempty"` // 头像框 AvatarFrame string `protobuf:"bytes,4,opt,name=avatarFrame,proto3" json:"avatarFrame,omitempty"` // 头像框
VipLevel int32 `protobuf:"varint,5,opt,name=vip_level,json=vipLevel,proto3" json:"vip_level,omitempty"` // vip等级 VipLevel int32 `protobuf:"varint,5,opt,name=vipLevel,proto3" json:"vipLevel,omitempty"` // vip等级
VipExp int32 `protobuf:"varint,6,opt,name=vip_exp,json=vipExp,proto3" json:"vip_exp,omitempty"` // vip经验 VipExp int32 `protobuf:"varint,6,opt,name=vipExp,proto3" json:"vipExp,omitempty"` // vip经验
Seat int64 `protobuf:"varint,20,opt,name=seat,proto3" json:"seat,omitempty"` // 座位 Seat int64 `protobuf:"varint,20,opt,name=seat,proto3" json:"seat,omitempty"` // 座位
Gold int64 `protobuf:"varint,25,opt,name=gold,proto3" json:"gold,omitempty"` // 金币 Gold int64 `protobuf:"varint,25,opt,name=gold,proto3" json:"gold,omitempty"` // 金币
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@ -204,20 +204,20 @@ var File_user_proto protoreflect.FileDescriptor
const file_user_proto_rawDesc = "" + const file_user_proto_rawDesc = "" +
"\n" + "\n" +
"\n" + "\n" +
"user.proto\x12\x02pb\"\x97\x01\n" + "user.proto\x12\x02pb\"\x94\x01\n" +
"\bChatUser\x12\x17\n" + "\bChatUser\x12\x16\n" +
"\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x1a\n" + "\x06userId\x18\x01 \x01(\x03R\x06userId\x12\x1a\n" +
"\bnickname\x18\x02 \x01(\tR\bnickname\x12\x16\n" + "\bnickname\x18\x02 \x01(\tR\bnickname\x12\x16\n" +
"\x06avatar\x18\x03 \x01(\tR\x06avatar\x12!\n" + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12 \n" +
"\favatar_frame\x18\x04 \x01(\tR\vavatarFrame\x12\x1b\n" + "\vavatarFrame\x18\x04 \x01(\tR\vavatarFrame\x12\x1a\n" +
"\tvip_level\x18\x05 \x01(\tR\bvipLevel\"\xd8\x01\n" + "\bvipLevel\x18\x05 \x01(\tR\bvipLevel\"\xd4\x01\n" +
"\bGameUser\x12\x17\n" + "\bGameUser\x12\x16\n" +
"\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x1a\n" + "\x06userId\x18\x01 \x01(\x03R\x06userId\x12\x1a\n" +
"\bnickname\x18\x02 \x01(\tR\bnickname\x12\x16\n" + "\bnickname\x18\x02 \x01(\tR\bnickname\x12\x16\n" +
"\x06avatar\x18\x03 \x01(\tR\x06avatar\x12!\n" + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12 \n" +
"\favatar_frame\x18\x04 \x01(\tR\vavatarFrame\x12\x1b\n" + "\vavatarFrame\x18\x04 \x01(\tR\vavatarFrame\x12\x1a\n" +
"\tvip_level\x18\x05 \x01(\x05R\bvipLevel\x12\x17\n" + "\bvipLevel\x18\x05 \x01(\x05R\bvipLevel\x12\x16\n" +
"\avip_exp\x18\x06 \x01(\x05R\x06vipExp\x12\x12\n" + "\x06vipExp\x18\x06 \x01(\x05R\x06vipExp\x12\x12\n" +
"\x04seat\x18\x14 \x01(\x03R\x04seat\x12\x12\n" + "\x04seat\x18\x14 \x01(\x03R\x04seat\x12\x12\n" +
"\x04gold\x18\x19 \x01(\x03R\x04goldB\x11Z\x0fcommon/proto/pbb\x06proto3" "\x04gold\x18\x19 \x01(\x03R\x04goldB\x11Z\x0fcommon/proto/pbb\x06proto3"

View File

@ -6,6 +6,7 @@ const (
Login = "login" Login = "login"
Db = "db" Db = "db"
Match = "match" Match = "match"
Lobby = "lobby"
// 下面是具体玩法服 // 下面是具体玩法服
ColorGame = "color_game" ColorGame = "color_game"

View File

@ -8,7 +8,6 @@ import (
"game/common/utils" "game/common/utils"
"github.com/fox/fox/etcd" "github.com/fox/fox/etcd"
"github.com/fox/fox/log" "github.com/fox/fox/log"
"github.com/fox/fox/service"
"github.com/fox/fox/xrand" "github.com/fox/fox/xrand"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"time" "time"
@ -24,6 +23,14 @@ const (
客户端没有指定路由节点则服务器从redis查找曾经的绑定节点并验证有效然后转发到对应的节点 客户端没有指定路由节点则服务器从redis查找曾经的绑定节点并验证有效然后转发到对应的节点
如果redis信息已经失效(服务有更新)则从etcd中获取该玩法下所有最新版本的节点(game1,game2)然后随机发送到其中一个节点并在redis中保存绑定关系 如果redis信息已经失效(服务有更新)则从etcd中获取该玩法下所有最新版本的节点(game1,game2)然后随机发送到其中一个节点并在redis中保存绑定关系
如果客户端所有消息都不指定具体的节点名则每次都需要从redis拉取绑定关系会影响路由速度 如果客户端所有消息都不指定具体的节点名则每次都需要从redis拉取绑定关系会影响路由速度
服务分为3种类型:
1.有状态服如各玩法服需要保存玩家在哪个状态服里
--1.1 这一类服务需要使用UserBindService.HashServiceNode来获取节点
2.无状态服如大厅服登陆服聊天服这些服务不持有任何状态包括玩家数据无需保存玩家在哪个服务直接通过group.topic随机路由即可
--2.1 这一类服务无需走UserBindService直接通过group.topic路由即可
3.有序hash服如db服需要根据玩家id hash到固定的db服以保证操作的一致性
--3.1 这一类服务需要使用UserBindService.HashServiceNode来获取节点
*/ */
type UserBindService struct { type UserBindService struct {
rdb *redis.Client rdb *redis.Client
@ -37,14 +44,18 @@ func NewUserBindService(rdb *redis.Client, etcdRegistry *etcd.Registry[etcd.Serv
} }
} }
func (m *UserBindService) makeRedisKey(userId int64, typeId pb.ServiceTypeId) string { func (m *UserBindService) makeRedisKey(userId int64) string {
return fmt.Sprintf("%s_%d:%d", prefix, userId, int(typeId)) return fmt.Sprintf("%s:%s", prefix, userId)
}
func (m *UserBindService) makeRedisSubKey(typeId pb.ServiceTypeId) string {
return typeId.String()
} }
// 从redis中加载玩家曾经访问过的服务节点名 // 从redis中加载玩家曾经访问过的服务节点名
func (m *UserBindService) LoadFromRedis(userId int64, typeId pb.ServiceTypeId) string { func (m *UserBindService) LoadFromRedis(userId int64, typeId pb.ServiceTypeId) string {
k := m.makeRedisKey(userId, typeId) key := m.makeRedisKey(userId)
if sName, err := m.rdb.Get(context.Background(), k).Result(); err != nil { subKey := m.makeRedisSubKey(typeId)
if sName, err := m.rdb.HGet(context.Background(), key, subKey).Result(); err != nil {
if !errors.Is(err, redis.Nil) { if !errors.Is(err, redis.Nil) {
log.Error(err.Error()) log.Error(err.Error())
} }
@ -56,24 +67,34 @@ func (m *UserBindService) LoadFromRedis(userId int64, typeId pb.ServiceTypeId) s
// 从redis中解除玩家与节点的绑定关系 // 从redis中解除玩家与节点的绑定关系
func (m *UserBindService) DelUserService(userId int64, typeId pb.ServiceTypeId) { func (m *UserBindService) DelUserService(userId int64, typeId pb.ServiceTypeId) {
k := m.makeRedisKey(userId, typeId) key := m.makeRedisKey(userId)
_, _ = m.rdb.Del(context.Background(), k).Result() subKey := m.makeRedisSubKey(typeId)
_, _ = m.rdb.HDel(context.Background(), key, subKey).Result()
}
// 保存玩家与节点的绑定关系至从redis
func (m *UserBindService) SaveUserService(userId int64, typeId pb.ServiceTypeId, serviceName string) {
key := m.makeRedisKey(userId)
subKey := m.makeRedisSubKey(typeId)
m.rdb.HSet(context.Background(), key, subKey, serviceName, 2*24*time.Hour)
} }
// 从etcd中检查节点是否有效如果有game1(旧服),game2(新服),都算有效,但是旧服会拒绝新玩家进入, // 从etcd中检查节点是否有效如果有game1(旧服),game2(新服),都算有效,但是旧服会拒绝新玩家进入,
// 此时旧服不止要拒绝新玩家还要删除redis中的绑定关系。方便客户端重新发消息时路由到新的服务。 // 此时旧服不止要拒绝新玩家还要删除redis中的绑定关系。方便客户端重新发消息时路由到新的服务。
func (m *UserBindService) serviceIsValid(serviceName string) bool { func (m *UserBindService) findServiceNodeByServiceName(serviceName string) (*etcd.ServiceNode, bool) {
var sNode *etcd.ServiceNode
valid := false valid := false
m.etcdRegistry.GetNodes().Range(func(k, v interface{}) bool { m.etcdRegistry.GetNodes().Range(func(k, v interface{}) bool {
if node, ok := v.(etcd.ServiceNode); ok { if node, ok := v.(etcd.ServiceNode); ok {
if node.Name == serviceName { if node.Name == serviceName {
valid = true valid = true
sNode = &node
return false return false
} }
} }
return true return true
}) })
return valid return sNode, valid
} }
func (m *UserBindService) stringAllServiceNode() string { func (m *UserBindService) stringAllServiceNode() string {
@ -86,7 +107,7 @@ func (m *UserBindService) stringAllServiceNode() string {
} }
// 从etcd中找可用服务节点随机选择一个 // 从etcd中找可用服务节点随机选择一个
func (m *UserBindService) RandServiceNode(typeId pb.ServiceTypeId) (*etcd.ServiceNode, error) { func (m *UserBindService) randServiceNode(typeId pb.ServiceTypeId) (*etcd.ServiceNode, error) {
var nodes []etcd.ServiceNode var nodes []etcd.ServiceNode
var version string var version string
m.etcdRegistry.GetNodes().Range(func(_, value any) bool { m.etcdRegistry.GetNodes().Range(func(_, value any) bool {
@ -109,47 +130,12 @@ func (m *UserBindService) RandServiceNode(typeId pb.ServiceTypeId) (*etcd.Servic
if len(nodes) == 0 { if len(nodes) == 0 {
return nil, fmt.Errorf("not found service node.type id:%v. all node:%v", typeId, m.stringAllServiceNode()) return nil, fmt.Errorf("not found service node.type id:%v. all node:%v", typeId, m.stringAllServiceNode())
} }
n := xrand.IntN(len(nodes)) n := xrand.RandN(len(nodes))
return &nodes[n], nil return &nodes[n], nil
} }
// 根据服务类型,路由到对应的服务节点 // 从etcd中hash一个服务节点。不需要保存玩家在哪个服务。
func (m *UserBindService) findServiceName(userId int64, typeId pb.ServiceTypeId) (string, error) { // 该服务是类似于db服这种有序操作的hash服
if userId > 0 {
// 向redis中查询。redis中保留的服务节点不一定是可用的还需要向etcd中验证
sName := m.LoadFromRedis(userId, typeId)
// log.DebugF("user:%v查找到服务节点:%s", userId, sName)
if sName != "" && m.serviceIsValid(sName) {
return sName, nil
}
}
// log.DebugF("user:%v查找到服务节点:%s为无效节点", userId, sName)
// redis也没有玩家的服务节点信息从etcd中找可用服务节点随机选择一个
node, err := m.RandServiceNode(typeId)
if err != nil {
log.ErrorF("etcd中随机一个服务节点时错误:%v", err)
return "", err
}
// log.DebugF("etcd中随机一个服务节点:%s", node.Name)
m.rdb.Set(context.Background(), m.makeRedisKey(userId, typeId), node.Name, 2*24*time.Hour)
return node.Name, nil
}
/*
查找topic,根据serviceTypeId以及玩家id查找玩家过往访问该服务的节点优先使用原节点
*/
func (m *UserBindService) FindTopic(userId int64, serviceTypeId pb.ServiceTypeId) (topic, sName string) {
var err error
if sName, err = m.findServiceName(userId, serviceTypeId); err == nil {
return service.TopicEx(sName), sName
} else {
log.Error(err.Error())
}
return "", sName
}
// 从etcd中hash一个服务节点
func (m *UserBindService) HashServiceNode(typeId pb.ServiceTypeId, uid int64) (*etcd.ServiceNode, error) { func (m *UserBindService) HashServiceNode(typeId pb.ServiceTypeId, uid int64) (*etcd.ServiceNode, error) {
var nodes []etcd.ServiceNode var nodes []etcd.ServiceNode
var version string var version string
@ -176,3 +162,51 @@ func (m *UserBindService) HashServiceNode(typeId pb.ServiceTypeId, uid int64) (*
n := uid % int64(len(nodes)) n := uid % int64(len(nodes))
return &nodes[n], nil return &nodes[n], nil
} }
// 要查找的服务必须是状态服,无状态服不需要查找指定服务。
// 如果玩家是首次使用该服务,则随机一个服务并保存玩家该服务节点。下次查找时返回该节点。
func (m *UserBindService) FindServiceNode(userId int64, typeId pb.ServiceTypeId) (*etcd.ServiceNode, error) {
if userId > 0 {
// 向redis中查询。redis中保留的服务节点不一定是可用的还需要向etcd中验证
sName := m.LoadFromRedis(userId, typeId)
// log.DebugF("user:%v查找到服务节点:%s", userId, sName)
if node, ok := m.findServiceNodeByServiceName(sName); ok {
return node, nil
}
}
// log.DebugF("user:%v查找到服务节点:%s为无效节点", userId, sName)
// redis也没有玩家的服务节点信息从etcd中找可用服务节点随机选择一个
node, err := m.randServiceNode(typeId)
if err != nil {
log.ErrorF("etcd中随机一个服务节点时错误:%v", err)
return nil, err
}
// log.DebugF("etcd中随机一个服务节点:%s", node.Name)
m.rdb.HSet(context.Background(), m.makeRedisKey(userId), node.Name, 2*24*time.Hour)
return node, nil
}
// 查找玩家所有的玩法节点
func (m *UserBindService) GetAllUserInGameServiceNode(userId int64) ([]*etcd.ServiceNode, error) {
if userId > 0 {
maps, err := m.rdb.HGetAll(context.Background(), m.makeRedisKey(userId)).Result()
if err != nil && err != redis.Nil {
log.ErrorF("user:%v get all service error:%v", err.Error())
return nil, err
}
if len(maps) > 0 {
inGames := make([]*etcd.ServiceNode, 0)
m.etcdRegistry.GetNodes().Range(func(k, v interface{}) bool {
if node, ok := v.(etcd.ServiceNode); ok {
if _, ok = maps[node.Name]; ok && node.TypeId != int(pb.ServiceTypeId_STI_Gate) {
inGames = append(inGames, &node)
}
}
return true
})
return inGames, nil
}
}
return nil, nil
}

View File

@ -2,6 +2,8 @@ package room
import ( import (
"game/common/proto/pb" "game/common/proto/pb"
"game/common/userBindService"
"game/server/colorgame/model"
"github.com/fox/fox/ipb" "github.com/fox/fox/ipb"
) )
@ -53,6 +55,9 @@ func (rm *ColorRoom) checkLeaveRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, re
func (rm *ColorRoom) leaveRoom(user *ColorPlayer) { func (rm *ColorRoom) leaveRoom(user *ColorPlayer) {
rm.DelPlayer(user.Id()) rm.DelPlayer(user.Id())
rm.userMgr.Del(user.ID) rm.userMgr.Del(user.ID)
// 移除redis中玩家与本服务绑定关系
userService := userBindService.NewUserBindService(model.UserBindServiceRedis, nil)
userService.DelUserService(user.ID, pb.ServiceTypeId_STI_ColorGame)
} }
func (rm *ColorRoom) onLeaveRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, req *pb.ReqLeaveRoom) { func (rm *ColorRoom) onLeaveRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, req *pb.ReqLeaveRoom) {

View File

@ -33,7 +33,7 @@ type ColorRoom struct {
} }
func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.PlayerMgr) (baseroom.IRoom, pb.ErrCode) { func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.PlayerMgr) (baseroom.IRoom, pb.ErrCode) {
playType := int(pb.ServiceTypeId_STI_ColorGame) gameId := int(pb.ServiceTypeId_STI_ColorGame)
rm := &ColorRoom{ rm := &ColorRoom{
HundredRoom: nil, HundredRoom: nil,
userMgr: userMgr, userMgr: userMgr,
@ -44,13 +44,13 @@ func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.Play
jackpotValue: 0, jackpotValue: 0,
endBetAreaMul: make([]*pb.ColorBetAreaMul, 0, len(pb.ColorBetArea_name)), endBetAreaMul: make([]*pb.ColorBetAreaMul, 0, len(pb.ColorBetArea_name)),
winBetAreaMul: nil, winBetAreaMul: nil,
jackpotMgr: jackpot.NewJackpotMgr(playType, model.UserRedis), jackpotMgr: jackpot.NewJackpotMgr(gameId, model.UserRedis),
} }
rm.trend = rm.initGameTrend() rm.trend = rm.initGameTrend()
rm.resetGameData() rm.resetGameData()
code := pb.ErrCode_OK code := pb.ErrCode_OK
rm.HundredRoom, code = baseroom.NewHundredRoom(id, roomType, playType, srv) rm.HundredRoom, code = baseroom.NewHundredRoom(id, roomType, gameId, srv)
if code != pb.ErrCode_OK { if code != pb.ErrCode_OK {
log.ErrorF("new color room err code:%v", code) log.ErrorF("new color room err code:%v", code)
return nil, code return nil, code

View File

@ -1,47 +0,0 @@
package cmd
import (
"fmt"
"github.com/fox/fox/log"
"os"
"os/signal"
"syscall"
)
// func initLog(command *config.Command) {
// log.Open(fmt.Sprintf("%v/%v/%v.log", command.LogPath, servername.Money, servername.Money), command.LogLevel)
// }
func initLog() {
log.Open("hilo.log", log.DebugL)
}
func initRepo() {
// model.InitUserDB(&config.Config.DBConfig)
// model.InitConfigDB(&config.Config.DBConfig)
// model.InitRedis(&config.Config.Redis)
// model.InitStub()
// RobotMgr.Load()
// ClubRobotMgr.Load()
// //log.Debug(fmt.Sprintf("%+v", stub.GGlobal))
}
func Run(version string) {
// command := config.ParseCommand()
// initLog(command)
initLog()
log.Info(fmt.Sprintf("版本信息.%v", version))
// err := config.Load(command.ConfigPath)
// if err != nil {
// log.Error(fmt.Sprintf("load config err: %v", err))
// }
// initRepo()
// handler.InitService()
// 截获 SIGINT 和 SIGTERM 信号
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
sig := <-c
// handler.StopService()
log.Info(fmt.Sprintf("received %s, initiating shutdown...", sig))
}

31
server/lobby/cmd/cmd.go Normal file
View File

@ -0,0 +1,31 @@
package cmd
import (
"fmt"
"game/server/lobby/config"
"game/server/lobby/model"
"game/server/lobby/server"
"github.com/fox/fox/log"
"os"
"os/signal"
"syscall"
)
func initRepo() {
model.InitRedis()
}
func Run(GitCommit, GitBranch, BuildDate string) {
config.InitLog()
config.LoadConfig(GitCommit, GitBranch, BuildDate)
log.Info(fmt.Sprintf("版本分支:%v,hash值:%v,编译时间:%v", GitBranch, GitCommit, BuildDate))
initRepo()
server.Init()
// 截获 SIGINT 和 SIGTERM 信号
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
sig := <-c
server.Stop()
log.Info(fmt.Sprintf("received %s, initiating shutdown...", sig))
}

View File

@ -0,0 +1,38 @@
package config
import (
"game/common/config"
"game/common/constant"
"github.com/fox/fox/db"
"github.com/fox/fox/log"
)
var Command *config.Command
var Cfg *config.Common
type LobbyConfig struct {
}
func InitLog() {
log.Open("./log/chat.log", log.DebugL)
log.Info("")
log.Info("")
log.Info("")
log.Info("-----init log success-----")
}
func LoadConfig(GitCommit, GitBranch, BuildDate string) {
Command = config.ParseCommand()
rdb, err := db.InitRedis(Command.RedisPassword, Command.RedisHost, Command.RedisPort, constant.Redis0Config)
if err != nil {
log.Error(err.Error())
return
}
defer func() { _ = rdb.Close() }()
Cfg, err = config.LoadCommonConfig[LobbyConfig](rdb, GitCommit, GitBranch, BuildDate)
if err != nil {
log.Error(err.Error())
return
}
log.DebugF("load common config success")
}

View File

@ -1,8 +1,7 @@
package main package main
import ( import (
"fmt" "game/server/lobby/cmd"
"game/server/hilo/cmd"
"github.com/fox/fox/ksync" "github.com/fox/fox/ksync"
"github.com/fox/fox/log" "github.com/fox/fox/log"
"time" "time"
@ -19,7 +18,8 @@ func main() {
if err == nil { if err == nil {
BuildDate = tm.Format("2006-01-02 15:04:05") BuildDate = tm.Format("2006-01-02 15:04:05")
} }
//BuildDate = "2025-05-31 09:56:06"
ksync.RunSafe(func() { ksync.RunSafe(func() {
cmd.Run(fmt.Sprintf("版本分支:%v,hash值:%v,编译时间:%v", GitBranch, GitCommit, BuildDate)) cmd.Run(GitBranch, GitCommit, BuildDate)
}, func() { log.Debug("reset run") }) }, func() { log.ErrorF("reset run") })
} }

20
server/lobby/model/db.go Normal file
View File

@ -0,0 +1,20 @@
package model
import (
"game/common/constant"
"game/server/lobby/config"
"github.com/fox/fox/db"
"github.com/fox/fox/log"
"github.com/go-redis/redis/v8"
)
var UserRedis *redis.Client
var err error
func InitRedis() {
UserRedis, err = db.InitRedis(config.Cfg.Redis.Password, config.Cfg.Redis.Host, config.Cfg.Redis.Port, constant.Redis1User)
if err != nil {
log.Fatal(err.Error())
return
}
}

View File

@ -0,0 +1,25 @@
package server
import (
"game/common/proto/pb"
"github.com/fox/fox/ipb"
"github.com/fox/fox/processor"
"github.com/fox/fox/service"
)
func (s *LobbyService) initProcessor() {
s.processor.RegisterMessages(processor.RegisterMetas{
pb.MsgId_NtfUserOnlineId: {pb.NtfUserOnline{}, s.onUserOnline},
})
}
// 玩家上线,告诉玩家在哪个玩法中
func (s *LobbyService) onUserOnline(iMsg *ipb.InternalMsg, msg *pb.NtfUserOnline) {
nodes, _ := s.bindService.GetAllUserInGameServiceNode(msg.UserId)
ntf := &pb.NtfUserInService{}
for _, node := range nodes {
ntf.ServiceNames = append(ntf.ServiceNames, node.Name)
}
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.UserId, int32(pb.MsgId_NtfUserInServiceId), ntf)
}

View File

@ -0,0 +1,116 @@
package server
import (
"fmt"
"game/common/proto/pb"
"game/common/serviceName"
"game/common/userBindService"
"game/server/lobby/config"
"game/server/lobby/model"
"github.com/fox/fox/ipb"
"github.com/fox/fox/log"
"github.com/fox/fox/processor"
"github.com/fox/fox/service"
"github.com/golang/protobuf/proto"
)
// 大厅服-无状态服,自身不持有任何状态包括玩家数据
var lobby []*LobbyService
type LobbyService struct {
*service.NatsService
processor *processor.Processor
bindService *userBindService.UserBindService
}
func Init() {
for i := 0; i < config.Command.ServiceNum; i++ {
sid := config.Command.ServiceId + i
if srv := newLobbyService(sid); srv != nil {
lobby = append(lobby, srv)
}
}
}
func Stop() {
for _, srv := range lobby {
srv.NotifyStop()
}
for _, srv := range lobby {
srv.WaitStop()
}
}
func newLobbyService(serviceId int) *LobbyService {
var err error
s := new(LobbyService)
sName := fmt.Sprintf("%v-%d", serviceName.Lobby, serviceId)
if s.NatsService, err = service.NewNatsService(&service.InitNatsServiceParams{
EtcdAddress: config.Cfg.Etcd.Address,
EtcdUsername: "",
EtcdPassword: "",
NatsAddress: config.Cfg.Nats.Address,
ServiceType: serviceName.Lobby,
ServiceName: sName,
OnFunc: s,
TypeId: int(pb.ServiceTypeId_STI_Lobby),
Version: config.Cfg.BuildDate,
}); err != nil {
log.Fatal(err.Error())
return nil
}
s.bindService = userBindService.NewUserBindService(model.UserRedis, s.ServiceEtcd())
s.processor = processor.NewProcessor()
s.initProcessor()
s.OnInit()
return s
}
func (s *LobbyService) OnInit() {
if err := s.NatsService.QueueSubscribe(service.GroupTopic(s), service.GroupQueue(s)); err != nil {
log.Error(err.Error())
}
s.NatsService.Run()
log.Debug("onInit")
}
func (s *LobbyService) CanStop() bool {
//log.Debug("chatService.CanStop")
return true
}
func (s *LobbyService) OnStop() {
s.NatsService.OnStop()
log.Debug("OnStop")
}
// 处理其它服发送过来的消息
func (s *LobbyService) OnMessage(data []byte) error {
var iMsg = &ipb.InternalMsg{}
var err error
if err = proto.Unmarshal(data, iMsg); err != nil {
log.Error(err.Error())
return err
}
if req, err := s.processor.Unmarshal(iMsg.MsgId, iMsg.Msg); err == nil {
err = s.processor.Dispatch(iMsg.MsgId, iMsg, req)
} else {
log.Error(err.Error())
}
//log.Debug(s.Log("received message:%v", iMsg.MsgId))
return nil
}
// 向内部服务发送消息
func (s *LobbyService) SendServiceData(topic string, userId int64, msgId int32, data []byte) {
iMsg := ipb.MakeMsg(s.Name(), 0, userId, msgId, data)
_ = s.Send(topic, iMsg)
}
// 向内部服务发送消息
func (s *LobbyService) SendServiceMsg(topic string, userId int64, msgId int32, msg proto.Message) {
data, _ := proto.Marshal(msg)
s.SendServiceData(topic, userId, msgId, data)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/fox/fox/log" "github.com/fox/fox/log"
"github.com/fox/fox/processor" "github.com/fox/fox/processor"
"github.com/fox/fox/service" "github.com/fox/fox/service"
"github.com/fox/fox/xrand"
"time" "time"
) )
@ -27,7 +28,7 @@ func (s *LoginService) initProcessor() {
func (s *LoginService) checkLoginOrRegister(req *pb.ReqUserLogin) (us *user.UserAccount, code pb.ErrCode, node *etcd.ServiceNode) { func (s *LoginService) checkLoginOrRegister(req *pb.ReqUserLogin) (us *user.UserAccount, code pb.ErrCode, node *etcd.ServiceNode) {
var err error var err error
node, err = s.bindService.RandServiceNode(pb.ServiceTypeId_STI_DB) node, err = s.bindService.HashServiceNode(pb.ServiceTypeId_STI_DB, xrand.RandN[int64](100))
if err != nil { if err != nil {
log.ErrorF(s.Log("not find db service.err:%s ", err.Error())) log.ErrorF(s.Log("not find db service.err:%s ", err.Error()))
return nil, pb.ErrCode_SystemErr, node return nil, pb.ErrCode_SystemErr, node

View File

@ -15,10 +15,10 @@ import (
func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom) { func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom) {
ksync.GoSafe(func() { ksync.GoSafe(func() {
// color game无需进入匹配队列 // color game无需进入匹配队列
playType := pb.ServiceTypeId(req.PlayType) gameId := pb.ServiceTypeId(req.GameId)
switch playType { switch gameId {
case pb.ServiceTypeId_STI_ColorGame: case pb.ServiceTypeId_STI_ColorGame:
node, err := s.bindService.RandServiceNode(playType) node, err := s.bindService.FindServiceNode(iMsg.UserId, gameId)
if err != nil { if err != nil {
log.ErrorF("db service node error:%v", err) log.ErrorF("db service node error:%v", err)
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId, s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId,
@ -47,9 +47,9 @@ func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom)
Seat: 0, Seat: 0,
Gold: us.Gold, Gold: us.Gold,
} }
rsp.PlayType = req.PlayType rsp.GameId = req.GameId
rsp.RoomType = req.RoomType rsp.RoomType = req.RoomType
switch pb.ServiceTypeId(rsp.PlayType) { switch pb.ServiceTypeId(rsp.GameId) {
case pb.ServiceTypeId_STI_ColorGame: case pb.ServiceTypeId_STI_ColorGame:
rsp.ColorInfo = &pb.RspMatchRoom_ColorInfo{} rsp.ColorInfo = &pb.RspMatchRoom_ColorInfo{}
} }