From 2f756c77bb8b8d263e49b365b830ff496ce90463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <12574910+72wo@users.noreply.github.com> Date: Thu, 12 Feb 2026 12:43:28 +0800 Subject: [PATCH] 1 --- common/socket/ServerEvent.go | 6 ++-- help/三主宠查询.sql | 45 +++++++++++++++++++++++++ help/查询多余精灵.sql | 61 ++++++++++++++++++++++++++++------ logic/controller/pet_info.go | 2 +- logic/controller/pet_繁殖.go | 3 ++ logic/controller/user_info.go | 3 ++ logic/service/player/pack.go | 4 +-- logic/service/player/save.go | 21 +++++++++++- modules/player/service/info.go | 1 + 9 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 help/三主宠查询.sql diff --git a/common/socket/ServerEvent.go b/common/socket/ServerEvent.go index 01753e45a..a55a85736 100644 --- a/common/socket/ServerEvent.go +++ b/common/socket/ServerEvent.go @@ -58,14 +58,14 @@ func (s *Server) OnClose(c gnet.Conn, err error) (action gnet.Action) { if t, ok := c.Context().(*player.ClientData); ok { if t.Player != nil { if t.Player.Info != nil { - cool.Logger.Error(context.TODO(), "OnClose 错误:", t.Player.Info.UserID, err) + cool.Logger.Error(context.TODO(), "OnClose 错误:", cool.Config.ServerInfo.OnlineID, t.Player.Info.UserID, err) t.Player.Service.Info.Save(*t.Player.Info) } } } else { - cool.Logger.Error(context.TODO(), "OnClose 错误:", err) + cool.Logger.Error(context.TODO(), "OnClose 错误:", cool.Config.ServerInfo.OnlineID, err) } @@ -132,7 +132,7 @@ func (s *Server) OnTraffic(c gnet.Conn) (action gnet.Action) { if t, ok := c.Context().(*player.ClientData); ok { if t.Player != nil { if t.Player.Info != nil { - cool.Logger.Error(context.TODO(), "OnTraffic 错误:", t.Player.Info.UserID, err) + cool.Logger.Error(context.TODO(), "OnTraffic 错误:", cool.Config.ServerInfo.OnlineID, t.Player.Info.UserID, err) t.Player.Service.Info.Save(*t.Player.Info) } diff --git a/help/三主宠查询.sql b/help/三主宠查询.sql new file mode 100644 index 000000000..3bb6516bd --- /dev/null +++ b/help/三主宠查询.sql @@ -0,0 +1,45 @@ +-- 删除:每个多余精灵组中除了最早创建的其余记录 +WITH pet_group_mapping AS ( +SELECT +id, +player_id, +-- 核心修正:PARTITION BY中直接写分组逻辑 +ROW_NUMBER() OVER ( +PARTITION BY +player_id, +CASE -- 3个一组的分组逻辑 +WHEN (data->>'ID')::INT BETWEEN 1 AND 3 THEN 'group_1_3' +WHEN (data->>'ID')::INT BETWEEN 4 AND 6 THEN 'group_4_6' +WHEN (data->>'ID')::INT BETWEEN 7 AND 9 THEN 'group_7_9' +WHEN (data->>'ID')::INT BETWEEN 301 AND 303 THEN 'group_301_303' +WHEN (data->>'ID')::INT BETWEEN 304 AND 306 THEN 'group_304_306' +WHEN (data->>'ID')::INT BETWEEN 307 AND 309 THEN 'group_307_309' +END +ORDER BY "createTime" ASC +) AS rn, +-- 定义pet_group用于筛选多余组 +CASE +WHEN (data->>'ID')::INT BETWEEN 1 AND 3 THEN 'group_1_3' +WHEN (data->>'ID')::INT BETWEEN 4 AND 6 THEN 'group_4_6' +WHEN (data->>'ID')::INT BETWEEN 7 AND 9 THEN 'group_7_9' +WHEN (data->>'ID')::INT BETWEEN 301 AND 303 THEN 'group_301_303' +WHEN (data->>'ID')::INT BETWEEN 304 AND 306 THEN 'group_304_306' +WHEN (data->>'ID')::INT BETWEEN 307 AND 309 THEN 'group_307_309' +END AS pet_group +FROM "player_pet" +WHERE deleted_at IS NULL +), +excess_groups AS ( +SELECT player_id, pet_group +FROM pet_group_mapping +WHERE pet_group IS NOT NULL +GROUP BY player_id, pet_group +HAVING COUNT(*) > 1 +) +DELETE FROM "player_pet" +WHERE id IN ( +SELECT pgm.id +FROM pet_group_mapping pgm +INNER JOIN excess_groups eg ON pgm.player_id = eg.player_id AND pgm.pet_group = eg.pet_group +WHERE pgm.rn > 1 +); \ No newline at end of file diff --git a/help/查询多余精灵.sql b/help/查询多余精灵.sql index 5fd2befd4..a39aa8d92 100644 --- a/help/查询多余精灵.sql +++ b/help/查询多余精灵.sql @@ -1,11 +1,50 @@ -SELECT - player_id, - COUNT(*) AS pet_count -FROM - "player_pet" -WHERE - (data->>'ID')::INT IN (273, 274) -- 适配JSONB的data字段取id并转整型 -GROUP BY - player_id -HAVING - COUNT(*) >= 2; -- 筛选出拥有273/274宠物的玩家,可根据需求调整为>=2(同时拥有两者) \ No newline at end of file +-- 验证:查询宠物ID为273/274、玩家拥有≥2条且非最早创建的记录(只查不删) +WITH player_pet_ranked AS ( + SELECT + id, -- 记录主键ID + player_id, + (data->>'ID')::INT AS pet_id, -- 便于核对宠物ID + "createTime", + ROW_NUMBER() OVER ( + PARTITION BY player_id + ORDER BY "createTime" ASC + ) AS rn + FROM "player_pet" + WHERE (data->>'ID')::INT IN (273, 274) -- 改为273或274 +) +SELECT * +FROM player_pet_ranked +WHERE rn > 1 -- rn>1是要删除的记录 +AND player_id IN ( + SELECT player_id + FROM player_pet_ranked + GROUP BY player_id + HAVING COUNT(*) >= 2 +); + + + +-- 核心删除:保留每个玩家下273/274宠物中createTime最早的那条,删除其余 +WITH player_pet_ranked AS ( + SELECT + id, -- 必须取主键ID用于精准删除 + player_id, + ROW_NUMBER() OVER ( + PARTITION BY player_id + ORDER BY "createTime" ASC + ) AS rn + FROM "player_pet" + WHERE (data->>'ID')::INT IN (273, 274) -- 关键修改:70→273,274 +) +DELETE FROM "player_pet" +WHERE id IN ( + SELECT id + FROM player_pet_ranked + WHERE rn > 1 -- 删除非最早的记录 + AND player_id IN ( + SELECT player_id + FROM player_pet_ranked + GROUP BY player_id + HAVING COUNT(*) >= 2 -- 仅处理拥有≥2条273/274宠物的玩家 + ) +); \ No newline at end of file diff --git a/logic/controller/pet_info.go b/logic/controller/pet_info.go index d03a45c18..ee0f27870 100644 --- a/logic/controller/pet_info.go +++ b/logic/controller/pet_info.go @@ -31,7 +31,7 @@ func (h Controller) GetPetInfo( return nil, errorcode.ErrorCodes.ErrPokemonNotExists } result = &pet.OutInfo{ - PetInfo: player.Service.Pet.PetInfo_One(data.CatchTime).Data, + PetInfo: ret.Data, } return result, 0 } diff --git a/logic/controller/pet_繁殖.go b/logic/controller/pet_繁殖.go index 282dcd23b..935f22728 100644 --- a/logic/controller/pet_繁殖.go +++ b/logic/controller/pet_繁殖.go @@ -182,6 +182,9 @@ func (ctl Controller) GetHatchPet( // TODO: 实现获得孵化精灵的具体逻辑,这里暂时返回默认值 r := playerObj.Service.Egg.GetEgg() + if r == nil { + return nil, errorcode.ErrorCodes.ErrSystemError + } playerObj.Service.Pet.PetAdd(r) result.PetID = r.ID diff --git a/logic/controller/user_info.go b/logic/controller/user_info.go index cf44aa607..8026b4284 100644 --- a/logic/controller/user_info.go +++ b/logic/controller/user_info.go @@ -27,6 +27,9 @@ func (h Controller) GetUserSimInfo(data *user.SimUserInfoInboundInfo, player *pl func (h Controller) GetUserMoreInfo(data *user.MoreUserInfoInboundInfo, player *player.Player) (result *user.MoreUserInfoOutboundInfo, err errorcode.ErrorCode) { result = &user.MoreUserInfoOutboundInfo{} info := player.Service.Info.Person(data.UserId) + if info == nil { + return nil, errorcode.ErrorCode(errorcode.ErrorCodes.ErrSystemError) + } copier.CopyWithOption(result, info.Data, copier.Option{IgnoreEmpty: true, DeepCopy: true}) //todo 待实现 diff --git a/logic/service/player/pack.go b/logic/service/player/pack.go index b580c275f..5ccc5d76a 100644 --- a/logic/service/player/pack.go +++ b/logic/service/player/pack.go @@ -52,9 +52,9 @@ func (h *ClientData) OnEvent(data common.TomeeHeader) { // 1. 打印错误信息 if h.Player != nil { if h.Player.Info != nil { - cool.Logger.Error(context.TODO(), "panic 错误:", h.Player.Info.UserID, err) + cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, h.Player.Info.UserID, err) } else { - cool.Logger.Error(context.TODO(), "panic 错误:", err) + cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, err) } diff --git a/logic/service/player/save.go b/logic/service/player/save.go index f402e0d6c..60675bc74 100644 --- a/logic/service/player/save.go +++ b/logic/service/player/save.go @@ -29,7 +29,26 @@ func (p *Player) Save() { p.Info.OnlineTime = p.Info.OnlineTime + (newtime-int64(p.Logintime))/60 //每次退出时候保存已经在线的分钟数 if p.FightC != nil { - defer p.FightC.Over(p, info.BattleOverReason.PlayerOffline) //玩家逃跑,但是不能锁线程 + //ov := make(chan struct{}) + go func() { + + defer func() { + if err := recover(); err != nil { // 恢复 panic,err 为 panic 错误值 + // 1. 打印错误信息 + + cool.Logger.Error(context.TODO(), "panic 错误:", err) + + } + }() + p.FightC.Over(p, info.BattleOverReason.PlayerOffline) //玩家逃跑,但是不能锁线程 + }() + //<-ov + select { + case <-p.FightC.GetOverChan(): //等待结束 + case <-time.After(time.Second * 5): //等待5秒 + cool.Logger.Error(context.TODO(), "战斗崩溃", p.Info.UserID) + + } } p.IsLogin = false diff --git a/modules/player/service/info.go b/modules/player/service/info.go index e0e335971..0c9b76cb7 100644 --- a/modules/player/service/info.go +++ b/modules/player/service/info.go @@ -191,6 +191,7 @@ func (s *InfoService) Save(data model.PlayerInfo) { tt.Data = data _, err := m.Save(tt) if err != nil { + //todo 待实现兜底保存,现在有可能出错 panic(err) }