Merge branch 'main' of https://cnb.cool/blzing/blazing
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
昔念
2026-02-24 12:53:16 +08:00
11 changed files with 74 additions and 102 deletions

View File

@@ -86,7 +86,7 @@ func (s *Server) OnClose(c gnet.Conn, err error) (action gnet.Action) {
//logging.Infof("conn[%v] disconnected", c.RemoteAddr().String()) //logging.Infof("conn[%v] disconnected", c.RemoteAddr().String())
v, _ := c.Context().(*player.ClientData) v, _ := c.Context().(*player.ClientData)
v.LF.Close() //v.LF.Close()
if v.Player != nil { if v.Player != nil {
v.Player.Save() //保存玩家数据 v.Player.Save() //保存玩家数据
@@ -192,10 +192,7 @@ func (s *Server) handleTCP(conn gnet.Conn) (action gnet.Action) {
conn.Context().(*player.ClientData).IsCrossDomain.Do(func() { //跨域检测 conn.Context().(*player.ClientData).IsCrossDomain.Do(func() { //跨域检测
handle(conn) handle(conn)
}) })
// 1. 检查最小可读长度(避免无效 Peek
if conn.InboundBuffered() < 17 {
return gnet.None
}
// handle(c) // handle(c)
// 先读取4字节的包长度 // 先读取4字节的包长度
lenBuf, err := conn.Peek(4) lenBuf, err := conn.Peek(4)
@@ -284,10 +281,10 @@ func (s *Server) onevent(c gnet.Conn, v []byte) {
} else { } else {
header.Data = nil // 避免空切片分配 header.Data = nil // 避免空切片分配
} }
t.OnEvent(header)
s.workerPool.Submit(func() { // s.workerPool.Submit(func() {
t.LF.Producer().Write(header) // t.LF.Producer().Write(header)
}) // })
} }
} }

View File

@@ -21,7 +21,7 @@ func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *playe
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.ReadyFight(c) go c.FightC.ReadyFight(c)
return nil, -1 return nil, -1
} }
@@ -30,7 +30,7 @@ func (h Controller) UseSkill(data *fight.UseSkillInInfo, c *player.Player) (resu
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.UseSkill(c, data.SkillId) go c.FightC.UseSkill(c, data.SkillId)
return nil, 0 return nil, 0
} }
@@ -40,7 +40,7 @@ func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *player.Player)
return nil, err return nil, err
} }
defer c.FightC.Over(c, info.BattleOverReason.PlayerEscape) go c.FightC.Over(c, info.BattleOverReason.PlayerEscape)
return nil, 0 return nil, 0
} }
@@ -49,7 +49,7 @@ func (h Controller) ChangePet(data *fight.ChangePetInboundInfo, c *player.Player
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.ChangePet(c, data.CatchTime) go c.FightC.ChangePet(c, data.CatchTime)
return nil, -1 return nil, -1
} }
@@ -58,7 +58,12 @@ func (h Controller) Capture(data *fight.CatchMonsterInboundInfo, c *player.Playe
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.Capture(c, data.CapsuleId) if c.GetSpace().IsTime {
if data.CapsuleId < 300009 {
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
}
}
go c.FightC.Capture(c, data.CapsuleId)
return nil, -1 return nil, -1
} }
@@ -67,7 +72,7 @@ func (h Controller) LoadPercent(data *fight.LoadPercentInboundInfo, c *player.Pl
if c.FightC == nil { if c.FightC == nil {
return nil, -1 return nil, -1
} }
defer c.FightC.LoadPercent(c, int32(data.Percent)) go c.FightC.LoadPercent(c, int32(data.Percent))
return nil, -1 return nil, -1
} }
@@ -76,7 +81,12 @@ func (h Controller) UsePetItemInboundInfo(data *fight.UsePetItemInboundInfo, c *
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.UseItem(c, data.CatchTime, data.ItemId) if c.GetSpace().IsTime {
if data.ItemId < 300009 {
return nil, errorcode.ErrorCodes.ErrCannotPerformAction
}
}
go c.FightC.UseItem(c, data.CatchTime, data.ItemId)
return nil, -1 return nil, -1
} }
@@ -85,6 +95,6 @@ func (h Controller) FightChat(data *fight.ChatInfo, c *player.Player) (result *f
if err := h.checkFightStatus(c); err != 0 { if err := h.checkFightStatus(c); err != 0 {
return nil, err return nil, err
} }
defer c.FightC.Chat(c, data.Message) go c.FightC.Chat(c, data.Message)
return nil, -1 return nil, -1
} }

View File

@@ -78,7 +78,7 @@ func (f *FightC) ChangePet(c common.PlayerI, id uint32) {
case f.actionChan <- ret: case f.actionChan <- ret:
// 发送成功,可选记录日志 // 发送成功,可选记录日志
// log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id) // log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id)
case <-time.After(time.Second * 10): case <-time.After(time.Second * 60):
// 通道满时的降级处理 // 通道满时的降级处理
cool.Logger.Printf(context.Background(), "actionChan is full, failed to send skill, userID: %d, skillID: %d", cool.Logger.Printf(context.Background(), "actionChan is full, failed to send skill, userID: %d, skillID: %d",
c.GetInfo().UserID, id) c.GetInfo().UserID, id)
@@ -120,7 +120,7 @@ func (f *FightC) UseSkill(c common.PlayerI, id uint32) {
case f.actionChan <- ret: case f.actionChan <- ret:
// 发送成功,可选记录日志 // 发送成功,可选记录日志
// log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id) // log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id)
case <-time.After(time.Second * 10): case <-time.After(time.Second * 60):
// 通道满时的降级处理 // 通道满时的降级处理
cool.Logger.Printf(context.Background(), "actionChan is full, failed to send skill, userID: %d, skillID: %d", cool.Logger.Printf(context.Background(), "actionChan is full, failed to send skill, userID: %d, skillID: %d",
c.GetInfo().UserID, id) c.GetInfo().UserID, id)
@@ -137,7 +137,7 @@ func (f *FightC) Capture(c common.PlayerI, id uint32) {
case f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: id}: case f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: id}:
// 发送成功,可选记录日志 // 发送成功,可选记录日志
// log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id) // log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id)
case <-time.After(time.Second * 10): case <-time.After(time.Second * 60):
// 通道满时的降级处理 // 通道满时的降级处理
cool.Logger.Printf(context.Background(), "actionChan is full, failed to send Capture, userID: %d ", cool.Logger.Printf(context.Background(), "actionChan is full, failed to send Capture, userID: %d ",
c.GetInfo().UserID) c.GetInfo().UserID)
@@ -155,7 +155,7 @@ func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) {
case f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid}: case f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid}:
// 发送成功,可选记录日志 // 发送成功,可选记录日志
// log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id) // log.Printf("send skill success, userID: %d, skillID: %d", c.GetInfo().UserID, id)
case <-time.After(time.Second * 10): case <-time.After(time.Second * 60):
// 通道满时的降级处理 // 通道满时的降级处理
cool.Logger.Printf(context.Background(), "actionChan is full, failed to send UseItem, userID: %d, skillID: %d", cool.Logger.Printf(context.Background(), "actionChan is full, failed to send UseItem, userID: %d, skillID: %d",
c.GetInfo().UserID, cacthid) c.GetInfo().UserID, cacthid)

View File

@@ -267,7 +267,7 @@ func (f *FightC) handleTimeout(ourID, oppID uint32, actions map[uint32]action.Ba
if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC { if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC {
// f.WinnerId = 0 // f.WinnerId = 0
go f.Our.GetAction() //boss出手后获取出招 go f.UseSkill(f.Our.Player, 0) //boss出手后获取出招
return false return false
} else { } else {
var pid uint32 var pid uint32
@@ -310,7 +310,7 @@ func (f *FightC) resolveRound(p1Action, p2Action action.BattleActionI) {
} }
// handleActiveSwitchAction 处理主动切换精灵动作 // handleActiveSwitchAction 处理主动切换精灵动作
func (f *FightC) handleActiveSwitchAction(switchAction *action.ActiveSwitchAction, otherAction action.BattleActionI) { func (f *FightC) handleActiveSwitchAction(_ *action.ActiveSwitchAction, otherAction action.BattleActionI) {
if skillAction, ok := otherAction.(*action.SelectSkillAction); ok { if skillAction, ok := otherAction.(*action.SelectSkillAction); ok {
if skillAction.SkillEntity != nil && skillAction.CD != nil { if skillAction.SkillEntity != nil && skillAction.CD != nil {

View File

@@ -5,8 +5,8 @@ import (
"blazing/cool" "blazing/cool"
"blazing/logic/service/common" "blazing/logic/service/common"
"encoding/binary" "encoding/binary"
"encoding/hex"
"sync" "sync"
"time"
"context" "context"
@@ -14,7 +14,6 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/bruceshao/lockfree"
"github.com/gobwas/ws" "github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil" "github.com/gobwas/ws/wsutil"
"github.com/gogf/gf/v2/os/glog" "github.com/gogf/gf/v2/os/glog"
@@ -90,23 +89,23 @@ func XORDecryptU(encryptedData []byte, key uint32) []byte {
// 遍历结构体方法并执行RECV_cmd // 遍历结构体方法并执行RECV_cmd
func (h *ClientData) OnEvent(data common.TomeeHeader) { func (h *ClientData) OnEvent(data common.TomeeHeader) {
defer func() { // defer func() {
if err := recover(); err != nil { // 恢复 panicerr 为 panic 错误值 // if err := recover(); err != nil { // 恢复 panicerr 为 panic 错误值
// 1. 打印错误信息 // // 1. 打印错误信息
if h.Player != nil { // if h.Player != nil {
if h.Player.Info != nil { // if h.Player.Info != nil {
cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, h.Player.Info.UserID, err) // cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, h.Player.Info.UserID, err)
} else { // } else {
cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, err) // cool.Logger.Error(context.TODO(), "panic 错误:", cool.Config.ServerInfo.OnlineID, err)
} // }
} else { // } else {
cool.Logger.Error(context.TODO(), "panic 错误:", err) // cool.Logger.Error(context.TODO(), "panic 错误:", err)
} // }
} // }
}() // }()
if data.CMD > 1001 { if data.CMD > 1001 {
if h.Player == nil { if h.Player == nil {
@@ -152,7 +151,7 @@ func (h *ClientData) OnEvent(data common.TomeeHeader) {
} }
if err != nil { if err != nil {
cool.Logger.Error(context.Background(), data.UserID, data.CMD, "解包失败,", err, data.Data) cool.Logger.Error(context.Background(), data.UserID, data.CMD, "解包失败,", err, hex.EncodeToString(data.Data))
//fmt.Println(data.UserID, data.CMD, "解包失败,", hex.EncodeToString(data.Data)) //fmt.Println(data.UserID, data.CMD, "解包失败,", hex.EncodeToString(data.Data))
data.Result = uint32(errorcode.ErrorCodes.ErrSystemProcessingError) data.Result = uint32(errorcode.ErrorCodes.ErrSystemProcessingError)
playerconn.SendPack(data.Pack(nil)) playerconn.SendPack(data.Pack(nil))
@@ -211,7 +210,7 @@ type ClientData struct {
ERROR_CONNUT int ERROR_CONNUT int
Wsmsg *WsCodec Wsmsg *WsCodec
Conn gnet.Conn Conn gnet.Conn
LF *lockfree.Lockfree[common.TomeeHeader] //LF *lockfree.Lockfree[common.TomeeHeader]
//SaveL sync.Once //保存锁 //SaveL sync.Once //保存锁
//SaveDone chan struct{} //SaveDone chan struct{}
@@ -226,19 +225,19 @@ func NewClientData(c gnet.Conn) *ClientData {
Conn: c, Conn: c,
Wsmsg: &WsCodec{}, Wsmsg: &WsCodec{},
} }
cd.LF = lockfree.NewLockfree( // cd.LF = lockfree.NewLockfree(
8, // 8,
cd, // cd,
lockfree.NewSleepBlockStrategy(time.Millisecond), // lockfree.NewSleepBlockStrategy(time.Millisecond),
) // )
// 启动Lockfree
if err := cd.LF.Start(); err != nil {
panic(err)
}
// // 启动Lockfree // // 启动Lockfree
// if err := cd.LF.Start(); err != nil { // if err := cd.LF.Start(); err != nil {
// panic(err) // panic(err)
// } // }
// // // 启动Lockfree
// // if err := cd.LF.Start(); err != nil {
// // panic(err)
// // }
return cd return cd
} }

View File

@@ -259,11 +259,12 @@ func (player1 *Player) Kick(isquit bool) {
// --- 新增超时机制核心代码 --- // --- 新增超时机制核心代码 ---
// 设定超时时间可根据业务需求调整这里以3秒为例 // 设定超时时间可根据业务需求调整这里以3秒为例
const kickTimeout = 3 * time.Second const kickTimeout = 10 * time.Second
select { select {
case <-CloseChan: case <-CloseChan:
// 正常流程连接关闭回调已执行CloseChan 被关闭 // 正常流程连接关闭回调已执行CloseChan 被关闭
case <-time.After(kickTimeout): case <-time.After(kickTimeout):
player1.Service.Info.Save(*player1.Info)
service.NewBaseSysLogService().RecordKick(uint32(player1.Info.UserID), fmt.Errorf("踢人操作超时(超时时间:%v", kickTimeout).Error()) service.NewBaseSysLogService().RecordKick(uint32(player1.Info.UserID), fmt.Errorf("踢人操作超时(超时时间:%v", kickTimeout).Error())
// 超时处理:避免永久阻塞,可添加日志便于排查问题 // 超时处理:避免永久阻塞,可添加日志便于排查问题
// 注意:这里不会中断 CloseWithCallback 的执行,仅解除当前协程的阻塞 // 注意:这里不会中断 CloseWithCallback 的执行,仅解除当前协程的阻塞

View File

@@ -33,6 +33,7 @@ type Space struct {
info.MapBossInfo info.MapBossInfo
TimeBoss info.S2C_2022 TimeBoss info.S2C_2022
Weather uint32 Weather uint32
IsTime bool
//CanWeather uint32 //CanWeather uint32
} }
@@ -40,36 +41,8 @@ type Space struct {
func NewSpace() *Space { func NewSpace() *Space {
ret := &Space{ ret := &Space{
User: csmap.New[uint32, common.PlayerI]( User: csmap.New[uint32, common.PlayerI](),
// set the number of map shards. the default value is 32. UserInfo: csmap.New[uint32, info.SimpleInfo](),
csmap.WithShardCount[uint32, common.PlayerI](32),
// // if don't set custom hasher, use the built-in maphash.
csmap.WithCustomHasher[uint32, common.PlayerI](func(key uint32) uint64 {
return uint64(key)
}),
// set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0.
// csmap.WithSize[string, int](1000),
),
UserInfo: csmap.New[uint32, info.SimpleInfo](
// set the number of map shards. the default value is 32.
csmap.WithShardCount[uint32, info.SimpleInfo](32),
csmap.WithCustomHasher[uint32, info.SimpleInfo](func(key uint32) uint64 {
return uint64(key)
}),
// // if don't set custom hasher, use the built-in maphash.
// csmap.WithCustomHasher[string, int](func(key string) uint64 {
// hash := fnv.New64a()
// hash.Write([]byte(key))
// return hash.Sum64()
// }),
// set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0.
// csmap.WithSize[string, int](1000),
),
} }
return ret return ret
@@ -111,6 +84,9 @@ func GetSpace(id uint32) *Space {
r := service.NewMapService().GetData(ret.ID) r := service.NewMapService().GetData(ret.ID)
if r != nil { if r != nil {
if r.IsTimeSpace != 0 {
ret.IsTime = true
}
if len(r.WeatherType) > 1 { if len(r.WeatherType) > 1 {
// ret.CanWeather = 1 // ret.CanWeather = 1
cool.Cron.CustomFunc(ret, func() { cool.Cron.CustomFunc(ret, func() {

View File

@@ -61,16 +61,16 @@ func (c *BaseSysUserController) GetSession(ctx context.Context, req *SessionReq)
} }
res = &SessionRes{} res = &SessionRes{}
t1 := service.NewBaseSysUserService().GetPerson(uint32(t.UserId)) t1 := service.NewBaseSysUserService().GetPerson(uint32(t.UserId))
res.UserID = int(t1.ID) res.UserID = int(t1.ID)
playerinfo := blazing.NewUserService(uint32(t1.ID)) playerinfo := blazing.NewUserService(uint32(t1.ID)).Info.Person(uint32(t1.ID))
if playerinfo.Info.IsReg() { if playerinfo != nil {
res.IsReg = 1 res.IsReg = 1
if t1.DepartmentID == 35 { ///抢先服玩家3天没登录衰退 if t1.DepartmentID == 35 { ///抢先服玩家3天没登录衰退
r := playerinfo.Info.Person(uint32(t1.ID))
if r.UpdateTime.AddDate(0, 0, 3).Before(gtime.Now()) { if playerinfo.UpdateTime.AddDate(0, 0, 3).Before(gtime.Now()) {
t1.DepartmentID = 1 t1.DepartmentID = 1
service.NewBaseSysUserService().SetdepartmentId(uint32(t1.ID), 1) service.NewBaseSysUserService().SetdepartmentId(uint32(t1.ID), 1)
} }

View File

@@ -14,11 +14,9 @@ const (
// -------------------------- 核心基类:所有塔配置的通用结构 -------------------------- // -------------------------- 核心基类:所有塔配置的通用结构 --------------------------
type BaseTowerConfig struct { type BaseTowerConfig struct {
*BaseConfig *BaseConfig
Name string `gorm:"size:32;default:'';comment:'塔层名称'" json:"name" description:"塔层名称"`
// ItemGift []ItemGift `orm:"with:item_id=id"`
// 核心必填字段(所有塔类型通用)
TowerLevel uint32 `gorm:"not null;default:0;uniqueIndex;comment:'塔层数(唯一标识每层配置)'" json:"tower_level" description:"塔层数"` TowerLevel uint32 `gorm:"not null;default:0;uniqueIndex;comment:'塔层数(唯一标识每层配置)'" json:"tower_level" description:"塔层数"`
BossIds []uint32 `gorm:"not null;type:json;default:'[]';comment:'绑定BOSS ID数组关联config_pet_boss表主键'" json:"boss_ids" description:"绑定BOSS数组"` BossIds []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'绑定BOSS ID数组关联config_pet_boss表主键'" json:"boss_ids" description:"绑定BOSS数组"`
} }
// NewBaseTowerConfig 创建基础塔配置实例(所有塔类型共用) // NewBaseTowerConfig 创建基础塔配置实例(所有塔类型共用)

View File

@@ -20,15 +20,6 @@ import (
csmap "github.com/mhmtszr/concurrent-swiss-map" csmap "github.com/mhmtszr/concurrent-swiss-map"
) )
func (s *InfoService) IsReg() bool {
m := s.dbm_fix(s.Model)
record, _ := m.Exist()
return record
}
// 是否注册,如果注册过,那么就会产生用户player信息 // 是否注册,如果注册过,那么就会产生用户player信息
// 实现注册,id+昵称+颜色 // 实现注册,id+昵称+颜色

View File

@@ -106,9 +106,9 @@ func (s *PetService) Pet_LEVEL_all() []model.Pet {
} }
// 精灵真正添加后的捕捉时间才是真正的时间 // 精灵真正添加后的捕捉时间才是真正的时间
func (s *PetService) PetAdd(y *model.PetInfo) { func (s *PetService) PetAdd(y *model.PetInfo) uint32 {
if y == nil { if y == nil {
return return 0
} }
sql := fmt.Sprintf(` sql := fmt.Sprintf(`
UPDATE %s UPDATE %s
@@ -136,7 +136,7 @@ RETURNING max_ts;
if err != nil { if err != nil {
panic(err) panic(err)
} }
return y.CatchTime
} }
// func (s *PetService) ModifyBefore(ctx context.Context, method string, param map[string]interface{}) (err error) { // func (s *PetService) ModifyBefore(ctx context.Context, method string, param map[string]interface{}) (err error) {