This commit is contained in:
1
2026-01-23 14:59:15 +00:00
parent 95055fe955
commit 53be2cb776
8 changed files with 129 additions and 121 deletions

View File

@@ -25,9 +25,8 @@ type Cmd struct {
//Res reflect.Value //返回体
}
var CmdCache = make(map[uint32]Cmd, 0)
var (
CmdCache = &utils.SyncMap[uint32, Cmd]{} //命令缓存
Logger = glog.New()
Cron = cronex.New() //时间轮

View File

@@ -8,7 +8,10 @@ import (
func TcpPing(address string) (n int64, err error) {
s := time.Now()
tcpConn, err := net.Dial("tcp", address)
n = time.Now().Sub(s).Nanoseconds()
n = time.Now().Sub(s).Milliseconds()
if n == 0 {
n = 1
}
if err != nil {
return
}

View File

@@ -47,7 +47,7 @@ func ParseCmd[T any](data []byte) T {
func Init(isGame bool) {
// 获取控制器实例的反射值
controllerValue := reflect.ValueOf(Maincontroller)
// 获取控制器类型
controllerType := controllerValue.Type()
@@ -86,11 +86,11 @@ func Init(isGame bool) {
Req: methodValue.Type().In(0).Elem(),
// Res: , // TODO 待实现对不同用户初始化方法以取消全局cmdcache
}
_, exists := cool.CmdCache.LoadOrStore(cmd, cmdInfo)
if exists { // 方法已存在
glog.Error(context.Background(), "命令处理方法已存在,跳过注册", cmd, method.Name)
}
cool.CmdCache[cmd] = cmdInfo
// if exists { // 方法已存在
// glog.Error(context.Background(), "命令处理方法已存在,跳过注册", cmd, method.Name)
// }
}
}
}

View File

@@ -58,7 +58,7 @@ func (h *ClientData) Recv(data common.TomeeHeader) {
}
}()
cmdlister, ok := cool.CmdCache.Load(data.CMD)
cmdlister, ok := cool.CmdCache[data.CMD]
if !ok {
glog.Debug(context.Background(), data.UserID, data.CMD, "cmd未注册")

View File

@@ -3,7 +3,6 @@ package player
import (
"blazing/common/data"
"blazing/common/socket/errorcode"
"blazing/common/utils"
"blazing/cool"
"blazing/logic/service/common"
"blazing/logic/service/fight/info"
@@ -20,6 +19,7 @@ import (
"github.com/antlabs/timer"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
csmap "github.com/mhmtszr/concurrent-swiss-map"
"github.com/panjf2000/gnet/v2"
)
@@ -34,7 +34,7 @@ func CountPlayer() int {
}
// Mainplayer 全局玩家数据存储映射
var Mainplayer = &utils.SyncMap[uint32, *Player]{}
var Mainplayer = csmap.New[uint32, *Player]()
type OgrePetInfo struct {
Id uint32
@@ -226,7 +226,7 @@ func (player1 *Player) Kick() {
//取成功,否则创建
//player1.Save() //先保存数据再返回
head := common.NewTomeeHeader(1001, player1.Info.UserID)
head.Result = uint32(errorcode.ErrorCodes.ErrAccountLoggedInElsewhere)
head.Result = uint32(errorcode.ErrorCodes.ErrXinPlanSleepMode)
//实际上这里有个问题,会造成重复保存问题
player1.SendPack(head.Pack(nil))

View File

@@ -38,6 +38,7 @@ func KickPlayer(userid uint32) error { //踢出玩家
}
//return player
return nil
}

View File

@@ -2,7 +2,6 @@ package space
import (
"blazing/common/data/xmlres"
"blazing/common/utils"
"blazing/cool"
"blazing/logic/service/common"
@@ -139,4 +138,4 @@ func GetSpace(id uint32) *Space {
return ret
}
var planetmap = &utils.SyncMap[uint32, *Space]{} //玩家数据
var planetmap = csmap.New[uint32, *Space]()

View File

@@ -196,29 +196,58 @@ else
command -v screen || { echo "❌ Screen安装失败"; exit 1; }
fi
#!/bin/bash
# ===== 优雅终止logic会话先等内部程序退出 → 再退screen=====
echo "===== 优雅终止logic会话 ====="
SCREEN_PID=""
# 你实际使用的screen名称从日志看是logic
SCREEN_NAME="%s{screen_name}"
# 替换为你实际的screen名称示例:logic
SCREEN_NAME="%s{screen_name}"
# 日志文件路径(可根据需要调整)
LOG_FILE="./screen_logic_exit.log"
# 调试开关如需详细日志取消set -x注释
set -o pipefail
export PS4='[DEBUG] ${BASH_SOURCE}:${LINENO} - ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
# set -x
# 定义检查PID是否存活的函数
# ========== 核心函数基于kill -0的等待进程退出函数 ==========
# 等待进程结束带60秒超时用kill -0检测存活输出进度点
wait_for_process_exit() {
local pidKilled=$1
local begin=$(date +%s) # 记录开始时间(秒)
local end
local timeout=60 # 最大等待时间(秒)
# 循环检测进程是否存活
while kill -0 $pidKilled > /dev/null 2>&1; do
echo -n "." # 输出进度点,直观显示等待过程
sleep 1;
# 检查是否超时
end=$(date +%s)
if [ $((end - begin)) -gt $timeout ]; then
echo -e "\n⚠ 等待进程$pidKilled退出超时已等${timeout}秒)"
break;
fi
done
# 最终状态提示
if ! kill -0 $pidKilled > /dev/null 2>&1; then
echo -e "\n✅ 进程$pidKilled已退出"
fi
}
# 定义检查PID是否存活的函数复用kill -0逻辑
pid_is_alive() {
local pid=$1
# 仅检查PID是否存在不发送信号最安全的方式
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
if [ -n "$pid" ] && kill -0 "$pid" > /dev/null 2>&1; then
return 0 # PID存活
else
return 1 # PID不存在
fi
}
# 定义安全的进程检测函数(带超时防卡)
# 定义获取screen会话下的所有子进程PID
get_inner_procs() {
local screen_pid=$1
# 5秒超时避免pstree卡住
@@ -230,113 +259,90 @@ get_inner_procs() {
echo "$procs"
}
# 1. 检查logic会话是否存在
if screen -ls "$SCREEN_NAME" 2>/dev/null | grep -q -E "[0-9]+\.$SCREEN_NAME"; then
echo "找到$SCREEN_NAME会话提取主PID..."
SCREEN_PID=$(screen -ls "$SCREEN_NAME" | grep -oE '[0-9]+\.'"$SCREEN_NAME" | head -1 | cut -d. -f1)
if [ -z "$SCREEN_PID" ]; then
echo "⚠️ 提取$SCREEN_NAME会话PID失败"
else
echo "✅ 提取到$SCREEN_NAME会话主PID$SCREEN_PID"
# ========== 步骤1给screen内所有子进程发优雅退出信号 ==========
echo "给$SCREEN_NAME内所有程序发送优雅退出信号(SIGTERM)..."
INNER_ALL_PROCS=$(get_inner_procs "$SCREEN_PID")
if [ -n "$INNER_ALL_PROCS" ]; then
echo "📌 检测到screen内进程列表$INNER_ALL_PROCS"
for pid in $INNER_ALL_PROCS; do
# 发送信号前检查子进程是否存活
if pid_is_alive "$pid"; then
if kill -15 "$pid" 2>/dev/null; then
echo "✅ 已给进程$pid发送SIGTERM信号"
else
echo "⚠️ 进程$pid发送信号失败"
fi
else
echo " 进程$pid已不存在跳过发送信号"
fi
done
else
echo " 未检测到$SCREEN_NAME内的子进程"
fi
# 第一步提取screen主PID并校验
SCREEN_PID=$(screen -ls "$SCREEN_NAME" | grep -oE '[0-9]+\.'"$SCREEN_NAME" | head -1 | cut -d. -f1)
if [ -z "$SCREEN_PID" ]; then
echo " 未找到$SCREEN_NAME会话对应的PID跳过终止流程"
# 去掉exit 1直接跳过后续逻辑不影响其他脚本执行
else
# ========== 仅当找到PID时才执行以下终止流程 ==========
echo "✅ 找到$SCREEN_NAME主PID$SCREEN_PID"
# 兜底给screen内Shell发送exit指令
echo "给screen内Shell发送exit指令兜底..."
screen -S "$SCREEN_NAME" -p 0 -X stuff $'exit\n' 2>/dev/null
sleep 1
# ========== 步骤2循环等待内部程序退出防卡优化 ==========
echo "开始循环等待$SCREEN_NAME内部所有程序退出最大60秒..."
WAIT_COUNT=0
MAX_WAIT_SECONDS=60
INNER_PROC_EXIST=true
while [ "$INNER_PROC_EXIST" = true ] && [ $WAIT_COUNT -lt $MAX_WAIT_SECONDS ]; do
INNER_PROCS=$(get_inner_procs "$SCREEN_PID")
# 强制退出条件:即使进程检测失败也不卡住
if [ -z "$INNER_PROCS" ]; then
INNER_PROC_EXIST=false
echo "✅ $SCREEN_NAME内部所有程序已退出或进程检测完成"
else
sleep 1
WAIT_COUNT=$((WAIT_COUNT + 1))
# 每5秒输出状态
if [ $((WAIT_COUNT % 5)) -eq 0 ]; then
ELAPSED=$WAIT_COUNT
echo "⏳ 等待中...残留进程:$INNER_PROCS已等$ELAPSED秒剩余$((MAX_WAIT_SECONDS - ELAPSED))秒)"
# 第二步:导出【退出前】的实时日志(终端+文件双输出)
echo -e "\n===== 【退出前】$SCREEN_NAME 内程序实时log ====="
screen -S "$SCREEN_NAME" -p 0 -X hardcopy -h "$LOG_FILE" 2>/dev/null
cat "$LOG_FILE"
# 第三步给所有子进程发SIGTERM信号并等待进程退出
echo -e "\n===== 开始给所有子进程发优雅退出信号(SIGTERM) ====="
INNER_PROCS=$(get_inner_procs "$SCREEN_PID")
if [ -z "$INNER_PROCS" ]; then
echo " 未检测到$SCREEN_NAME下的子进程"
else
echo "待处理子进程:$INNER_PROCS"
for pid in $INNER_PROCS; do
if pid_is_alive "$pid"; then
echo -n "📌 终止进程$pid并等待退出"
kill -15 "$pid" # 发送SIGTERM优雅退出信号
if [ $? -eq 0 ]; then
wait_for_process_exit "$pid" # 调用等待函数
else
echo "❌ 进程$pid发送SIGTERM失败"
fi
else
echo " 进程$pid已不存在跳过"
fi
done
# 超时提示
if [ "$INNER_PROC_EXIST" = true ]; then
echo "⚠️ 等待超时60秒$SCREEN_NAME内部程序仍未退出"
echo "📌 残留进程PID$INNER_PROCS"
fi
# ========== 步骤3退出screen会话核心修复避免kill卡住 ==========
if [ "$INNER_PROC_EXIST" = false ]; then
echo "内部程序已退出,开始退出$SCREEN_NAME会话..."
# 第一步尝试正常退出screen会话
if screen -S "$SCREEN_NAME" -X quit 2>/dev/null; then
echo "✅ $SCREEN_NAME会话已通过screen -X quit退出"
else
echo " screen -X quit执行失败会话可能已消失检查PID是否存活..."
# 第二步仅当PID存活时才执行kill且加超时
if pid_is_alive "$SCREEN_PID"; then
echo "📌 PID $SCREEN_PID 仍存活尝试kill终止5秒超时..."
timeout 5 kill -15 "$SCREEN_PID" 2>/dev/null
if [ $? -eq 0 ]; then
echo "✅ 已给screen主进程$SCREEN_PID发送SIGTERM信号"
else
echo "⚠️ kill $SCREEN_PID 失败(超时/进程不存在)"
fi
else
echo " PID $SCREEN_PID 已不存在跳过kill操作"
fi
fi
sleep 2
else
echo "⚠️ 内部程序未完全退出跳过退出screen会话"
fi
# 最终验证
if screen -ls "$SCREEN_NAME" 2>/dev/null | grep -q -E "[0-9]+\.$SCREEN_NAME"; then
echo "❌ $SCREEN_NAME会话最终仍未退出"
else
echo "✅ $SCREEN_NAME会话已完全退出"
fi
fi
else
echo "=== 未找到$SCREEN_NAME会话跳过终止 ==="
# 验证子进程是否全部退出
echo -e "\n===== 验证子进程退出状态 ====="
REMAIN_PROCS=$(get_inner_procs "$SCREEN_PID")
INNER_PROC_EXIST=true
if [ -z "$REMAIN_PROCS" ]; then
INNER_PROC_EXIST=false
echo "✅ $SCREEN_NAME内部所有程序已退出"
else
echo "⚠️ 仍有残留进程:$REMAIN_PROCS"
fi
# 退出screen会话
if [ "$INNER_PROC_EXIST" = false ]; then
echo "内部程序已退出,开始退出$SCREEN_NAME会话..."
# 尝试正常退出screen会话
if screen -S "$SCREEN_NAME" -X quit 2>/dev/null; then
echo "✅ $SCREEN_NAME会话已通过screen -X quit退出"
else
echo " screen -X quit执行失败检查PID是否存活..."
# 仅当PID存活时执行kill
if pid_is_alive "$SCREEN_PID"; then
echo "📌 PID $SCREEN_PID 仍存活尝试kill终止..."
timeout 5 kill -15 "$SCREEN_PID" 2>/dev/null
if [ $? -eq 0 ]; then
echo "✅ 已给screen主进程$SCREEN_PID发送SIGTERM信号"
else
echo "⚠️ kill $SCREEN_PID 失败"
fi
else
echo " PID $SCREEN_PID 已不存在跳过kill操作"
fi
fi
sleep 2
else
echo "⚠️ 内部程序未完全退出跳过退出screen会话"
fi
# 最终验证
echo -e "\n===== 最终验证 ====="
if screen -ls "$SCREEN_NAME" 2>/dev/null | grep -q -E "[0-9]+\.$SCREEN_NAME"; then
echo "❌ $SCREEN_NAME会话最终仍未退出"
else
echo "✅ $SCREEN_NAME会话已完全退出"
fi
fi
# 关闭调试
# set +x
# 后续脚本可以从这里继续执行,不受上述逻辑影响
echo -e "\n===== 终止logic会话流程结束继续执行后续脚本 ====="
# ===== 准备下载目录 =====
echo "创建工作目录:%s{work_dir}"