修改bug

This commit is contained in:
liuxiaobo 2025-06-16 00:50:42 +08:00
parent 5265c0a1e2
commit 19778fa3d4
22 changed files with 119 additions and 64 deletions

View File

@ -5,6 +5,7 @@
3. 修改完后清除调试日志。(已完成)
4. 客户端stop关闭连接触发服务端连接崩溃。(已修复)
5. 偶现网络关闭服务端此时传来数据网关会因为conn为nil触发协程崩溃不影响程序运行。(暂不处理)
6. 客户端反复关闭重连会触发gate退出无崩溃日志。
2. 编写db服
1. login服向db服请求数据及向log db服写入日志。测试rpc机制。(已验证)
@ -15,7 +16,9 @@
6. struct序列化到redis中时需要处理时间格式。(已修复)
7. 清理登陆相关调试日志。(已完成)
8. login服切换到其它地方启动后gate服会路由失败。(已修复etcd没有删除失效节点导致。)
9. login在创建帐号时还需要创建user。(已实现,待验证) todo
9. login在创建帐号时还需要创建user。(已实现,待验证)
10. 优化各服务的call,send将服务节点查询放到call,send方法内部调用者提供serviceTypeId即可。服务注册时需表明自己是有状态还是无状态或类似于db的有序服务。
11. 优化各服务的send方法除gate,login服其它服不需要传connId。
3. 编写color game玩法
1. 房间配置。(已实现,待测试)
@ -28,6 +31,7 @@
1. 开始游戏、通知下注、通知下注结束、开骰子、结算。(已实现,待测试)
2. 玩家下注、每秒更新投注区域信息。(已实现,待测试)
8. 机器人实现。(未开始)
9. 因业务触发崩溃会导致从etcd节点退出进而导致其它服务不会向它发消息。
4. 编写大厅lobby服
1. 玩家上线时通知玩家他所在的玩法。方便玩家重连进入该玩法服。(已实现,待测试)

View File

@ -251,7 +251,7 @@ func (r *BaseRoom[Seat]) Unmarshal(cmd int32, data []byte) (any, error) {
}
func (r *BaseRoom[Seat]) Dispatch(user IPlayer, cmd int32, params ...any) error {
inp := make([]any, len(params)+1)
inp := make([]any, 0, len(params)+1)
inp = append(inp, user)
inp = append(inp, params...)
return r.processor.Dispatch(cmd, inp...)

View File

@ -25,6 +25,7 @@ func NewHundredRoom(id, roomType, gameId int, srv service.IService) (*HundredRoo
}
room := &HundredRoom{
room: baseRoom,
users: make(map[int64]IPlayer),
}
return room, pb.ErrCode_OK
}
@ -72,7 +73,7 @@ func (r *HundredRoom) FindPlayer(uid int64) (IPlayer, bool) {
return u, ok
}
// 站起时player为nil坐下时player非nil
// 添加玩家如果已存在返回false
func (r *HundredRoom) AddPayer(user IPlayer) bool {
if _, ok := r.users[user.Id()]; ok {
return false

View File

@ -137,18 +137,18 @@ func (s *TableOp[T]) Find(id int64) (*T, pb.ErrCode) {
}
// 根据条件查询只在mysql中查询无法在redis中查询
func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, error) {
var result utils.TValue[T]
err := s.db.Where(condition).First(&result.V).Error
func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, pb.ErrCode) {
us := new(T)
err := s.db.Where(condition).First(us).Error
if err != nil {
log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err)
return nil, err
return nil, pb.ErrCode_SystemErr
}
// 查看redis中是否存在该键不存在则写入数据
if !s.existRedis(&result.V) {
s.writeRedis(result.V.GetId(), &result.V)
if !s.existRedis(us) {
s.writeRedis((*us).GetId(), us)
}
return &result.V, nil
return us, pb.ErrCode_OK
}
func (s *TableOp[T]) Update(id int64, updates map[string]any) (*T, pb.ErrCode) {

View File

@ -2,7 +2,7 @@ package user
// 玩家账户表
type UserResources struct {
UID int64 `gorm:"uniqueIndex" json:"id"`
UID int64 `gorm:"uniqueIndex" json:"uid"`
Gold int64 `gorm:"default:0" json:"gold"` // 金币
Diamond int64 `gorm:"default:0" json:"diamond"` // 钻石
}
@ -16,7 +16,7 @@ func (u UserResources) TableName() string {
}
type UserResourcesLog struct {
UID int64 `gorm:"uniqueIndex" json:"id"`
UID int64 `gorm:"uniqueIndex" json:"uid"`
ResName string `gorm:"default:0" json:"res_name"` // 资源名
ResAddValue int64 `gorm:"default:0" json:"res_value"` // 资源增加值
ResAfterValue int64 `gorm:"default:0" json:"res_after_value"` // 资源增加后的值

View File

@ -40,5 +40,5 @@ func RpcGetGameUser(bindService *userBindService.UserBindService, s service.ISer
_ = json.Unmarshal(rspMsg.Msg, us)
return us, pb.ErrCode_OK
}
return nil, pb.ErrCode_OK
return nil, pb.ErrCode(rspMsg.RpcCode)
}

View File

@ -35,6 +35,8 @@ sudo docker run -d \
-p 3306:3306 \
mysql:8.0
sudo docker exec -it mysql-server mysql -ugame -pfox379@@zyxi
docker run -d \
--name clickhouse-server \
-p 8123:8123 \

View File

@ -8,7 +8,7 @@ import (
)
var Command *config.Command
var Cfg *config.Common[ChatConfig]
var Cfg *config.Common
type ChatConfig struct {
}
@ -29,7 +29,7 @@ func LoadConfig(GitCommit, GitBranch, BuildDate string) {
return
}
defer func() { _ = rdb.Close() }()
Cfg, err = config.LoadCommonConfig[ChatConfig](rdb, GitCommit, GitBranch, BuildDate)
Cfg, err = config.LoadCommonConfig(rdb, GitCommit, GitBranch, BuildDate)
if err != nil {
log.Error(err.Error())
return

View File

@ -18,13 +18,13 @@ func (s *ChatService) initProcessor() {
func (s *ChatService) onChat(uid int64, msg *pb.ReqChat) {
switch msg.Type {
case pb.ChatType_CT_Private:
tName, _ := s.bindService.FindTopic(msg.DstUser.UserId, pb.ServiceTypeId_STI_Gate)
if tName == "" {
log.DebugF("user:%v find gate failed", uid)
node, err := s.bindService.FindServiceNode(pb.ServiceTypeId_STI_Gate, msg.DstUser.UserId)
if node == nil {
log.ErrorF("user:%v find gate failed.err:%v", uid, err)
return
}
s.SendServiceMsg(service.TopicEx(tName), msg.DstUser.UserId, int32(pb.MsgId_RspChatId), msg)
s.SendServiceMsg(service.TopicEx(node.Name), msg.DstUser.UserId, int32(pb.MsgId_RspChatId), msg)
default:
s.SendServiceMsg(service.TopicEx(topicName.WorldMessage), uid, int32(pb.MsgId_RspChatId), msg)
}
}

View File

@ -8,8 +8,10 @@ import (
)
const (
gateAddress1 = "114.132.124.145:5100"
gateAddress2 = "114.132.124.145:5101"
//gateAddress1 = "114.132.124.145:5100"
//gateAddress2 = "114.132.124.145:5101"
gateAddress1 = "127.0.0.1:5100"
gateAddress2 = "127.0.0.1:5101"
)
var Command *config.Command

View File

@ -19,13 +19,14 @@ func (s *ClientService) reqLogin() {
// 收到登陆成功消息,判断是否顶号
func (s *ClientService) onLogin(cMsg *pb.ClientMsg, msg *pb.RspUserLogin) {
if msg.Code != pb.ErrCode_OK {
log.ErrorF("reqLogin error:%v :%v", msg.Code, msg.Code.String())
log.ErrorF("onLogin error:%v :%v", msg.Code, msg.Code.String())
return
}
_ = cMsg
s.userId = msg.UserId
s.client.SetUid(msg.UserId)
log.DebugF("user:%v id:%v reqLogin success", s.username, msg.UserId)
s.reqMatchRoom()
}
func (s *ClientService) reqMatchRoom() {
@ -35,3 +36,21 @@ func (s *ClientService) reqMatchRoom() {
RoomType: 0,
})
}
func (s *ClientService) onMatchRoom(cMsg *pb.ClientMsg, msg *pb.RspMatchRoom) {
if msg.Code != pb.ErrCode_OK {
log.ErrorF("onMatch error:%v :%v", msg.Code, msg.Code.String())
return
}
log.DebugF("user:%v onMatch success", s.userId)
_ = cMsg
}
func (s *ClientService) onEnterRoom(cMsg *pb.ClientMsg, msg *pb.RspEnterRoom) {
if msg.Code != pb.ErrCode_OK {
log.ErrorF("onEnterRoom error:%v :%v", msg.Code, msg.Code.String())
return
}
log.DebugF("user:%v onEnterRoom success", s.userId)
_ = cMsg
}

View File

@ -8,5 +8,7 @@ import (
func (s *ClientService) initProcessor() {
s.processor.RegisterMessages(processor.RegisterMetas{
pb.MsgId_RspUserLoginId: {pb.RspUserLogin{}, s.onLogin},
pb.MsgId_RspMatchRoomId: {pb.RspMatchRoom{}, s.onMatchRoom},
pb.MsgId_RspEnterRoomId: {pb.RspEnterRoom{}, s.onEnterRoom},
})
}

View File

@ -24,7 +24,9 @@ func (rm *ColorRoom) onMatchRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, req *
}
func (rm *ColorRoom) enterRoom(user *ColorPlayer) {
_ = rm.AddPayer(user)
if rm.AddPayer(user) {
user.resetData()
}
rm.notifyColorRoomInfo(user)
}

View File

@ -16,17 +16,18 @@ const (
func (s *ColorService) initProcessor() {
s.processor.RegisterMessages(processor.RegisterMetas{
pb.MsgId_ReqMatchRoomId: {pb.ReqMatchRoom{}, s.onEnterRoom},
pb.MsgId_ReqEnterRoomId: {pb.ReqEnterRoom{}, s.onEnterRoom},
})
}
// 进房间
func (s *ColorService) onEnterRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom) {
func (s *ColorService) onEnterRoom(iMsg *ipb.InternalMsg, req *pb.ReqEnterRoom) {
ksync.GoSafe(func() {
us, code := rpc.RpcGetGameUser(s.bindService, s, iMsg.UserId)
if code != pb.ErrCode_OK {
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId,
int32(pb.MsgId_RspMatchRoomId), &pb.RspMatchRoom{Code: pb.ErrCode_SystemErr})
int32(pb.MsgId_RspEnterRoomId), &pb.RspEnterRoom{Code: pb.ErrCode_SystemErr})
return
}
// 切回服务协程处理业务逻辑
s.RunOnce(func() {

View File

@ -151,7 +151,7 @@ func (s *ColorService) OnMessage(data []byte) error {
log.Error(err.Error())
}
}
log.Debug(s.Log("received message:%v", iMsg.MsgId))
log.Debug(s.Log("received message:%v", pb.MsgId(iMsg.MsgId)))
return nil
}
@ -163,6 +163,10 @@ func (s *ColorService) SendServiceData(topic string, connId uint32, userId int64
// 向内部服务发送消息
func (s *ColorService) SendServiceMsg(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) {
if msgId == int32(pb.MsgId_RspMatchRoomId) {
_ = connId
}
log.DebugF("send to:%v msg id:%v, msg:%v", topic, pb.MsgId(msgId), msg.String())
data, _ := proto.Marshal(msg)
s.SendServiceData(topic, connId, userId, msgId, data)
}

View File

@ -7,7 +7,6 @@ import (
"game/common/model"
"game/common/model/user"
"game/common/proto/pb"
"game/common/serialization"
"game/common/utils"
"github.com/fox/fox/log"
"github.com/fox/fox/xrand"
@ -40,19 +39,16 @@ func (s *UserOp) GetUserByAccountId(accountId int64) (*user.User, pb.ErrCode) {
sUid, err := s.userRedis.Get(context.Background(), s.redisKey(accountId)).Result()
if err != nil {
if errors.Is(err, redis.Nil) {
us := &user.User{}
err = s.db.Where("account_id = ?", accountId).First(us).Error
if err != nil {
log.DebugF("find user by account id:%v err:%v", accountId, err)
us, code := s.FindCondition(map[string]any{"account_id": accountId})
if code != pb.ErrCode_OK {
// db中没有则创建玩家
if us, code = s.createUserAccountId(accountId); code == pb.ErrCode_OK {
_, _ = NewUserResourcesOp().Create(&user.UserResources{UID: us.ID})
return us, pb.ErrCode_OK
} else {
log.DebugF("create user by account id:%v", accountId)
return nil, pb.ErrCode_SystemErr
}
// 从db中查到后写入redis并建立索引
if us.ID > 0 {
_, _ = s.Update(us.ID, serialization.StructToMap(us))
_ = s.userRedis.Set(context.Background(), s.redisKey(accountId), us.ID, model.TableExpire).Err()
} else {
// db中没有则创建玩家
return s.createUserAccountId(accountId)
}
return us, pb.ErrCode_OK
} else {

View File

@ -68,15 +68,22 @@ func (s *DbService) onLogUserAccountLogin(iMsg *ipb.InternalMsg) *ipb.InternalMs
return iMsg
}
// 获取用户数据,没有则创建
// 获取用户数据,没有则创建用户数据及用户资源
func (s *DbService) onGetUserByAccountId(iMsg *ipb.InternalMsg) *ipb.InternalMsg {
operationDb[user.User](iMsg, func(us *user.User) (*user.User, pb.ErrCode) {
return operation.NewUserOp().GetUserByAccountId(us.AccountId)
userOp := operation.NewUserOp()
us2, code := userOp.GetUserByAccountId(us.AccountId)
if code != pb.ErrCode_OK {
if us2, code = userOp.Create(us); code == pb.ErrCode_OK {
operation.NewUserResourcesOp().Create(&user.UserResources{UID: us2.ID})
}
}
return us2, pb.ErrCode_OK
})
return iMsg
}
// 获取用户数据,没有则创建
// 获取用户数据
func (s *DbService) onGetUserByUid(iMsg *ipb.InternalMsg) *ipb.InternalMsg {
operationDb[user.User](iMsg, func(us *user.User) (*user.User, pb.ErrCode) {
return operation.NewUserOp().Find(us.ID)
@ -87,8 +94,9 @@ func (s *DbService) onGetUserByUid(iMsg *ipb.InternalMsg) *ipb.InternalMsg {
// 获取用户资源数据,没有则创建
func (s *DbService) onGetUserResources(iMsg *ipb.InternalMsg) *ipb.InternalMsg {
operationDb[user.UserResources](iMsg, func(res *user.UserResources) (*user.UserResources, pb.ErrCode) {
if us1, code := operation.NewUserResourcesOp().Find(res.UID); code != pb.ErrCode_OK {
return operation.NewUserResourcesOp().Create(res)
resOp := operation.NewUserResourcesOp()
if us1, code := resOp.Find(res.UID); code != pb.ErrCode_OK {
return resOp.Create(res)
} else {
return us1, code
}

View File

@ -183,7 +183,7 @@ func (s *GateService) WsOnMessage(conn ws.IConn, data []byte) {
} else {
log.Error(s.Log("topic:%v not exist.user:%v", topic, conn.UserId()))
}
log.Debug(s.Log("received conn:%d user:%v message:%v", conn.Id(), conn.UserId(), msg.MsgId))
log.Debug(s.Log("received conn:%d user:%v message:%v", conn.Id(), conn.UserId(), pb.MsgId(msg.MsgId)))
}
// 向内部服务发送消息
@ -194,6 +194,7 @@ func (s *GateService) SendServiceData(topic string, conn ws.IConn, msgId int32,
// 向内部服务发送消息
func (s *GateService) SendServiceMsg(topic string, conn ws.IConn, msgId int32, msg proto.Message) {
log.DebugF("user:%v send to service:%v msg id:%v, msg:%v", conn.UserId(), topic, pb.MsgId(msgId), msg.String())
data, _ := proto.Marshal(msg)
s.SendServiceData(topic, conn, msgId, data)
}
@ -207,6 +208,7 @@ func (s *GateService) SendClientData(conn ws.IConn, serviceName string, msgId in
// 向玩家发送消息
func (s *GateService) SendClientMsg(conn ws.IConn, serviceName string, msgId int32, msg proto.Message) {
log.DebugF("send to user:%v msg id:%v, msg:%v", conn.UserId(), pb.MsgId(msgId), msg.String())
data, _ := proto.Marshal(msg)
s.SendClientData(conn, serviceName, msgId, data)
}

View File

@ -83,7 +83,7 @@ func (s *LoginService) checkLoginOrRegister(req *pb.ReqUserLogin) (us *user.User
log.DebugF("收到rcp:%v返回数据:%v", rpc.CreateUserAccount, string(rspMsg.Msg))
}
if !utils.CheckPassword(req.Password, us.Password) {
log.ErrorF(s.Log("用户密码:%v 数据库中密码:%v", req.Password, us.Password))
log.ErrorF(s.Log("用户密码错误"))
return nil, pb.ErrCode_LoginUserOrPwdErr, node
}
switch us.Status {
@ -106,14 +106,19 @@ func generateToken(userID int64, username string) (string, error) {
}
// 获取用户数据,如果没有则创建
func (s *LoginService) getUser(accountId int64, tName string) (*user.User, pb.ErrCode) {
func (s *LoginService) getUser(accountId int64) (*user.User, pb.ErrCode) {
node, err := s.bindService.HashServiceNode(pb.ServiceTypeId_STI_DB, xrand.RandN[int64](100))
if err != nil {
log.ErrorF(s.Log("not find db service.err:%s ", err.Error()))
return nil, pb.ErrCode_SystemErr
}
us := &user.User{
AccountId: accountId,
}
rpcMsg := ipb.MakeRpcMsg(rpc.GetUserByAccountId, 0, us)
rsp, err := s.Call(service.RpcTopicEx(tName), timeout, rpcMsg)
rsp, err := s.Call(service.RpcTopicEx(node.Name), timeout, rpcMsg)
if err != nil {
log.ErrorF(s.Log("call rpc:%v err:%s", rpcMsg.RpcMsgId, err.Error()))
log.ErrorF(s.Log("call src:%v rpc:%v err:%s", node.Name, rpcMsg.RpcMsgId, err.Error()))
return nil, pb.ErrCode_SystemErr
}
if rsp.RpcCode != 0 {
@ -137,11 +142,13 @@ func (s *LoginService) onLoginOrRegister(iMsg *ipb.InternalMsg, req *pb.ReqUserL
if account != nil && code == pb.ErrCode_OK {
// 拉取用户数据
us := &user.User{}
us, code = s.getUser(userId, req.Username)
us, code = s.getUser(account.ID)
if code == pb.ErrCode_OK {
rsp.UserId = us.ID
rsp.Token, _ = generateToken(account.ID, account.Username)
userId = rsp.UserId
} else {
rsp.Code = code
}
}
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, userId, int32(pb.MsgId_RspUserLoginId), rsp)

View File

@ -99,7 +99,7 @@ func (s *LoginService) OnMessage(data []byte) error {
} else {
log.Error(err.Error())
}
log.Debug(s.Log("received message:%v", iMsg.MsgId))
log.Debug(s.Log("received message:%v", pb.MsgId(iMsg.MsgId)))
return nil
}
@ -111,6 +111,7 @@ func (s *LoginService) SendServiceData(topic string, connId uint32, userId int64
// 向内部服务发送消息
func (s *LoginService) SendServiceMsg(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) {
log.DebugF("send to:%v msg id:%v, msg:%v", topic, msgId, msg.String())
data, _ := proto.Marshal(msg)
s.SendServiceData(topic, connId, userId, msgId, data)
}

View File

@ -15,17 +15,20 @@ import (
func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom) {
ksync.GoSafe(func() {
// color game无需进入匹配队列
gameId := pb.ServiceTypeId(req.GameId)
gameId := req.GameId
switch gameId {
case pb.ServiceTypeId_STI_ColorGame:
node, err := s.bindService.FindServiceNode(gameId, iMsg.UserId)
if err != nil {
log.ErrorF("db service node error:%v", err)
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId,
s.SendServiceMsg(iMsg.ServiceName, service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId,
int32(pb.MsgId_RspMatchRoomId), &pb.RspMatchRoom{Code: pb.ErrCode_SystemErr})
return
}
s.SendServiceMsg(service.TopicEx(node.Name), iMsg.ConnId, iMsg.UserId, int32(pb.MsgId_ReqMatchRoomId), req)
s.SendServiceMsg(iMsg.ServiceName, service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId,
int32(pb.MsgId_RspMatchRoomId), &pb.RspMatchRoom{})
s.SendServiceMsg(iMsg.ServiceName, service.TopicEx(node.Name), iMsg.ConnId, iMsg.UserId,
int32(pb.MsgId_ReqEnterRoomId), &pb.ReqEnterRoom{})
return
}
@ -33,7 +36,7 @@ func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom)
rsp := &pb.RspMatchRoom{}
us, rsp.Code = rpc.RpcGetGameUser(s.bindService, s, iMsg.UserId)
if rsp.Code != pb.ErrCode_OK {
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId, int32(pb.MsgId_RspMatchRoomId), rsp)
s.SendServiceMsg(iMsg.ServiceName, service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId, int32(pb.MsgId_RspMatchRoomId), rsp)
return
}
vipLv, vipExp := utils.VipLevel(us.VipExp)
@ -54,6 +57,6 @@ func (s *MatchService) onMatchRoom(iMsg *ipb.InternalMsg, req *pb.ReqMatchRoom)
rsp.ColorInfo = &pb.RspMatchRoom_ColorInfo{}
}
s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId, int32(pb.MsgId_RspMatchRoomId), rsp)
s.SendServiceMsg(iMsg.ServiceName, service.TopicEx(iMsg.ServiceName), iMsg.ConnId, iMsg.UserId, int32(pb.MsgId_RspMatchRoomId), rsp)
}, nil)
}

View File

@ -102,18 +102,19 @@ func (s *MatchService) OnMessage(data []byte) error {
} else {
log.Error(err.Error())
}
log.Debug(s.Log("received message:%v", iMsg.MsgId))
log.Debug(s.Log("received message:%v", pb.MsgId(iMsg.MsgId)))
return nil
}
// 向内部服务发送消息
func (s *MatchService) SendServiceData(topic string, connId uint32, userId int64, msgId int32, data []byte) {
iMsg := ipb.MakeMsg(s.Name(), connId, userId, msgId, data)
func (s *MatchService) SendServiceData(gateName, topic string, connId uint32, userId int64, msgId int32, data []byte) {
iMsg := ipb.MakeMsg(gateName, connId, userId, msgId, data)
_ = s.Send(topic, iMsg)
}
// 向内部服务发送消息
func (s *MatchService) SendServiceMsg(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) {
func (s *MatchService) SendServiceMsg(gateName, topic string, connId uint32, userId int64, msgId int32, msg proto.Message) {
log.DebugF("send to:%v msg id:%v, msg:%v", topic, pb.MsgId(msgId), msg.String())
data, _ := proto.Marshal(msg)
s.SendServiceData(topic, connId, userId, msgId, data)
s.SendServiceData(gateName, topic, connId, userId, msgId, data)
}