| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- #!/bin/bash
- # =====================================================
- # 一键开新区脚本 — 生成独立区服目录
- # 用法: ./create_zone.sh <区号> [选项]
- #
- # 生成目录结构:
- # dev/server<N>/
- # ├── _launch_server.xml # 该区独立配置
- # ├── start.sh # 启动
- # ├── stop.sh # 停止
- # ├── status.sh # 状态
- # └── restart.sh # 重启
- # =====================================================
- set -e
- # ======================== 默认配置 ========================
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
- BASE_OUTPUT="/data/CzServer/_output.server"
- DLL="$BASE_OUTPUT/OpenCards.Server.DotNetCore.dll"
- # 数据库密码(从现有配置读取)
- REDIS_PASSWORD="tmKjD1ENs3HfZ7adzLJO!"
- MYSQL_CONN="server=127.0.0.1;User ID=root;Password=CmASfW98lOKbFieqEQox;database=orm"
- NAMESERVER_ENDPOINT="127.0.0.1:17000"
- FIGHT_POST_URL="http://127.0.0.1:8088/fight/reqstartbattle"
- # 服务器公网IP
- SERVER_PUBLIC_IP="${SERVER_PUBLIC_IP:-127.0.0.1}"
- # ======================== 颜色 ========================
- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
- log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
- log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
- log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
- log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
- # ======================== 参数 ========================
- ZONE_ID=""
- ZONE_NAME=""
- CONNECTOR_PORT=""
- RPC_PORT=""
- REDIS_DB=""
- SERVER_ID=""
- REALM_ID="1"
- while [[ $# -gt 0 ]]; do
- case "$1" in
- --port) CONNECTOR_PORT="$2"; shift 2 ;;
- --rpc-port) RPC_PORT="$2"; shift 2 ;;
- --name) ZONE_NAME="$2"; shift 2 ;;
- --ip) SERVER_PUBLIC_IP="$2"; shift 2 ;;
- --redis-db) REDIS_DB="$2"; shift 2 ;;
- --realm) REALM_ID="$2"; shift 2 ;;
- --nameserver) NAMESERVER_ENDPOINT="$2"; shift 2 ;;
- -h|--help)
- echo "用法: $0 <区号> [选项]"
- echo ""
- echo "参数:"
- echo " 区号 第几区 (1, 2, 3...)"
- echo ""
- echo "选项:"
- echo " --port <端口> 客户端连接端口 (默认: 19820+区号)"
- echo " --rpc-port <端口> RPC端口 (默认: rpc=17019+区号)"
- echo " --name <名称> 区服显示名称 (默认: 测试服N区)"
- echo " --ip <IP地址> 服务器公网IP (用于serverlist)"
- echo " --redis-db <编号> Redis DB (默认: 同区号)"
- echo " --realm <ID> 大区ID (默认: 1)"
- echo " --nameserver <地址> NameServer地址 (默认: 127.0.0.1:17000)"
- echo ""
- echo "示例:"
- echo " $0 1 # 创建1区 (端口19821)"
- echo " $0 2 # 创建2区 (端口19822)"
- echo " $0 3 --port 19823 --name 正式3区"
- exit 0
- ;;
- *) ZONE_ID="$1"; shift ;;
- esac
- done
- if [ -z "$ZONE_ID" ]; then
- log_error "请指定区号,如: $0 2"
- exit 1
- fi
- # 自动计算默认值
- SERVER_ID="${ZONE_ID}"
- REDIS_DB="${REDIS_DB:-${ZONE_ID}}"
- CONNECTOR_PORT="${CONNECTOR_PORT:-$((19820 + ZONE_ID))}"
- RPC_PORT="${RPC_PORT:-$((17019 + ZONE_ID))}"
- ZONE_NAME="${ZONE_NAME:-测试服${ZONE_ID}区}"
- # ======================== 预检查 ========================
- log_step "检查环境..."
- ZONE_DIR="${SCRIPT_DIR}/server${ZONE_ID}"
- GAME_NODE="GameNode${ZONE_ID}"
- if [ -d "$ZONE_DIR" ]; then
- log_warn "目录 ${ZONE_DIR} 已存在"
- read -p "是否覆盖? (y/N): " confirm
- if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
- log_info "已取消"
- exit 0
- fi
- fi
- check_port() {
- local port=$1
- (ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null) | grep -q ":${port} " && return 0
- return 1
- }
- if check_port "$CONNECTOR_PORT"; then
- log_warn "端口 ${CONNECTOR_PORT} 已被占用,请检查"
- fi
- if check_port "$RPC_PORT"; then
- log_warn "RPC端口 ${RPC_PORT} 已被占用,请检查"
- fi
- # ======================== 创建目录 ========================
- log_step "创建目录: ${ZONE_DIR}"
- mkdir -p "${ZONE_DIR}"
- # ======================== 生成 _launch_server.xml ========================
- log_step "生成 _launch_server.xml ..."
- cat > "${ZONE_DIR}/_launch_server.xml" << XEOF
- <?xml version="1.0" encoding="utf-8"?>
- <doc>
- <!-- ================================================================ -->
- <!-- ${ZONE_NAME} 配置 (由 create_zone.sh 生成) -->
- <!-- 区号: ${ZONE_ID} 端口: ${CONNECTOR_PORT} RPC: ${RPC_PORT} -->
- <!-- Redis: db=${REDIS_DB} 生成时间: $(date '+%Y-%m-%d %H:%M:%S') -->
- <!-- ================================================================ -->
- <define name="GameNodeDefine" param1="" param2=""/>
- <GlobalConfig>
- <Env>dev</Env>
- <Realm>${REALM_ID}</Realm>
- <Mysql></Mysql>
- <AcceptClientVersion>0.0.0</AcceptClientVersion>
- <TemplateRoot>../../../data/ServerData/</TemplateRoot>
- <NoticeErrorUrl>https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=d9d262b8-17c8-4297-8b9f-bb1b7f72ac89</NoticeErrorUrl>
- <DebugPay>true</DebugPay>
- <BattleRecordURLPrefix>https://zqtfcn.oss-cn-shanghai.aliyuncs.com/apollo_dev/server/playback/</BattleRecordURLPrefix>
- </GlobalConfig>
- <NameServer>
- <RpcConfig>
- <LocalEndPoint>${NAMESERVER_ENDPOINT}</LocalEndPoint>
- <NetworkTimeoutMS>15000</NetworkTimeoutMS>
- <RpcCodec>OpenCards.Server.Core.Serializer</RpcCodec>
- </RpcConfig>
- </NameServer>
- <ServiceNodes>
- <${GAME_NODE}>
- <Redis>127.0.0.1,password=${REDIS_PASSWORD},allowAdmin=true,syncTimeout=30000,responseTimeout=30000,connectRetry=1000,connectTimeout=10000;db=${REDIS_DB}</Redis>
- <Mysql>${MYSQL_CONN}</Mysql>
- <Ip>127.0.0.1</Ip>
- <RpcConfig>
- <LocalNodeType>GameNode</LocalNodeType>
- <LocalNodeName>${GAME_NODE}</LocalNodeName>
- <LocalEndPoint>127.0.0.1:${RPC_PORT}</LocalEndPoint>
- <NameServerEndPoint>${NAMESERVER_ENDPOINT}</NameServerEndPoint>
- <RequestTickTimeMS>5000</RequestTickTimeMS>
- <NetworkTimeoutMS>30000</NetworkTimeoutMS>
- <DefaultTaskExecuteTimeout>60000</DefaultTaskExecuteTimeout>
- <RpcCodec>OpenCards.Server.Core.Serializer</RpcCodec>
- <AcceptTypeMappings>
- <CenterService>OpenCards.Service.Center.CenterService</CenterService>
- <AccountServer>OpenCards.Server.Account.AccountServer</AccountServer>
- <ConnectorService>OpenCards.Server.Connector.ConnectorService</ConnectorService>
- <ArenaManagerService>OpenCards.Server.Arena.ArenaManagerService</ArenaManagerService>
- <ArenaValorService>OpenCards.Server.Arena.ArenaValorService</ArenaValorService>
- <ArenaHighendService>OpenCards.Server.Arena.ArenaHighendService</ArenaHighendService>
- <SessionService>OpenCards.Server.Connector.SessionService</SessionService>
- <LogicService>OpenCards.Server.Logic.LogicService</LogicService>
- <LogicManagerService>OpenCards.Server.Logic.LogicManagerService</LogicManagerService>
- <StageRankService>OpenCards.Service.StageRank.StageRankService</StageRankService>
- <ArenaPinnacleGameService>OpenCards.Server.Arena.ArenaPinnacleGameService</ArenaPinnacleGameService>
- </AcceptTypeMappings>
- </RpcConfig>
- <StartService>
- <LogicManagerService>
- <ServiceName>LogicManagerService_${ZONE_ID}</ServiceName>
- <ServiceType>LogicManagerService</ServiceType>
- <Config>
- <FightPostURL>${FIGHT_POST_URL}</FightPostURL>
- <serverID>${SERVER_ID}</serverID>
- </Config>
- </LogicManagerService>
- <CenterService>
- <ServiceName>CenterService_${ZONE_ID}</ServiceName>
- <ServiceType>CenterService</ServiceType>
- <Config>
- <serverID>${SERVER_ID}</serverID>
- </Config>
- </CenterService>
- <StageRankService>
- <ServiceName>StageRankService_${ZONE_ID}</ServiceName>
- <ServiceType>StageRankService</ServiceType>
- <Config>
- <serverID>${SERVER_ID}</serverID>
- </Config>
- </StageRankService>
- <ArenaPinnacleGameService>
- <ServiceName>ArenaPinnacleGameService_${ZONE_ID}</ServiceName>
- <ServiceType>ArenaPinnacleGameService</ServiceType>
- <Config>
- <ServerID>${SERVER_ID}</ServerID>
- </Config>
- </ArenaPinnacleGameService>
- <ArenaManagerService>
- <ServiceName>ArenaManagerService_${ZONE_ID}</ServiceName>
- <ServiceType>ArenaManagerService</ServiceType>
- <Config>
- <ServerID>${SERVER_ID}</ServerID>
- </Config>
- </ArenaManagerService>
- <ArenaHighendService>
- <ServiceName>ArenaHighendService_${ZONE_ID}</ServiceName>
- <ServiceType>ArenaHighendService</ServiceType>
- <Config></Config>
- </ArenaHighendService>
- <ConnectorService>
- <ServiceName>ConnectorService_${ZONE_ID}</ServiceName>
- <ServiceType>ConnectorService</ServiceType>
- <Config>
- <ServerId>${SERVER_ID}</ServerId>
- <Host>0.0.0.0</Host>
- <Port>${CONNECTOR_PORT}</Port>
- <NetCodec>OpenCards.Core.Serializer</NetCodec>
- <KeepAlive>true</KeepAlive>
- <KeepAliveInterval>30000</KeepAliveInterval>
- <RecvBufferSize>16384</RecvBufferSize>
- <SendBufferSize>16384</SendBufferSize>
- <MaxConnections>300000</MaxConnections>
- </Config>
- </ConnectorService>
- </StartService>
- </${GAME_NODE}>
- </ServiceNodes>
- </doc>
- XEOF
- # ======================== 生成管理脚本 ========================
- log_step "生成管理脚本..."
- # --- 公共工具函数 ---
- write_script_header() {
- local file=$1
- cat > "$file" << 'SHEOF'
- #!/bin/bash
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
- BASE_OUTPUT="/data/CzServer/_output.server"
- DLL="$BASE_OUTPUT/OpenCards.Server.DotNetCore.dll"
- LOG_DIR="$BASE_OUTPUT/logfile"
- mkdir -p "$LOG_DIR"
- GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
- SHEOF
- }
- # --- start.sh ---
- write_script_header "${ZONE_DIR}/start.sh"
- cat >> "${ZONE_DIR}/start.sh" << XEOF
- # ${ZONE_NAME} 启动脚本
- PID=\$(pgrep -f "server${ZONE_ID}/_launch_server.xml ${GAME_NODE}" 2>/dev/null)
- if [ -n "\$PID" ]; then
- echo -e "\${YELLOW}[SKIP] ${ZONE_NAME} 已在运行 (PID: \$PID)\${NC}"
- exit 0
- fi
- echo -e "\${GREEN}[START] ${ZONE_NAME} (端口:${CONNECTOR_PORT}, RPC:${RPC_PORT}, Redis:db=${REDIS_DB}) ...\${NC}"
- nohup dotnet "\$DLL" "\$SCRIPT_DIR/_launch_server.xml" ${GAME_NODE} global.RealmID=${REALM_ID} global.ServerID=${SERVER_ID} \
- >> "\$LOG_DIR/server${ZONE_ID}.log" 2>&1 &
- sleep 3
- PID=\$(pgrep -f "server${ZONE_ID}/_launch_server.xml ${GAME_NODE}" 2>/dev/null)
- if [ -n "\$PID" ]; then
- echo -e "\${GREEN}[OK] ${ZONE_NAME} 启动成功 (PID: \$PID)\${NC}"
- else
- echo -e "\${RED}[FAIL] ${ZONE_NAME} 启动失败,查看日志:\${NC}"
- tail -20 "\$LOG_DIR/server${ZONE_ID}.log"
- exit 1
- fi
- XEOF
- # --- stop.sh ---
- write_script_header "${ZONE_DIR}/stop.sh"
- cat >> "${ZONE_DIR}/stop.sh" << XEOF
- # ${ZONE_NAME} 停止脚本
- PID=\$(pgrep -f "server${ZONE_ID}/_launch_server.xml ${GAME_NODE}" 2>/dev/null)
- if [ -n "\$PID" ]; then
- echo -e "\${YELLOW}[STOP] ${ZONE_NAME} (PID: \$PID)\${NC}"
- kill \$PID
- sleep 2
- if pgrep -f "server${ZONE_ID}/_launch_server.xml ${GAME_NODE}" > /dev/null 2>&1; then
- echo -e "\${RED}[KILL] 强制终止...\${NC}"
- kill -9 \$PID 2>/dev/null
- fi
- echo -e "\${GREEN}[OK] ${ZONE_NAME} 已停止\${NC}"
- else
- echo -e "\${YELLOW}[SKIP] ${ZONE_NAME} 未在运行\${NC}"
- fi
- XEOF
- # --- status.sh ---
- write_script_header "${ZONE_DIR}/status.sh"
- cat >> "${ZONE_DIR}/status.sh" << XEOF
- # ${ZONE_NAME} 状态查看
- PID=\$(pgrep -f "server${ZONE_ID}/_launch_server.xml ${GAME_NODE}" 2>/dev/null)
- if [ -n "\$PID" ]; then
- echo -e "\${GREEN}[UP] ${ZONE_NAME} 运行中"
- echo " PID: \$PID"
- echo " 端口: ${CONNECTOR_PORT}"
- echo " RPC: ${RPC_PORT}"
- echo " 日志: \$LOG_DIR/server${ZONE_ID}.log\${NC}"
- else
- echo -e "\${RED}[DOWN] ${ZONE_NAME} 未运行 (端口:${CONNECTOR_PORT})\${NC}"
- fi
- XEOF
- # --- restart.sh ---
- write_script_header "${ZONE_DIR}/restart.sh"
- cat >> "${ZONE_DIR}/restart.sh" << XEOF
- # ${ZONE_NAME} 重启脚本
- bash "\$SCRIPT_DIR/stop.sh"
- sleep 2
- bash "\$SCRIPT_DIR/start.sh"
- XEOF
- chmod +x "${ZONE_DIR}/start.sh" "${ZONE_DIR}/stop.sh" "${ZONE_DIR}/status.sh" "${ZONE_DIR}/restart.sh"
- # ======================== 输出 serverlist 条目 ========================
- cat << XEOF
- ${GREEN}============================================
- 请将以下条目添加到 OSS serverlist.json:
- ============================================${NC}
- {
- "id": ${ZONE_ID},
- "index": $((ZONE_ID - 1)),
- "name": "${ZONE_NAME}",
- "address": "${SERVER_PUBLIC_IP}:${CONNECTOR_PORT}",
- "state": 1,
- "is_open": true,
- "capacity": 2000,
- "serverid": ${SERVER_ID},
- "groupid": ${REALM_ID},
- "note": "测试服"
- }
- ${GREEN}============================================${NC}
- XEOF
- # ======================== 完成 ========================
- echo ""
- echo -e "${GREEN}============================================${NC}"
- echo -e "${GREEN} ${ZONE_NAME} 创建完成!${NC}"
- echo -e "${GREEN}============================================${NC}"
- echo ""
- echo -e " 目录: ${CYAN}${ZONE_DIR}${NC}"
- echo -e " 区号: ${CYAN}${SERVER_ID}${NC}"
- echo -e " 端口: ${CYAN}${CONNECTOR_PORT}${NC}"
- echo -e " RPC端口: ${CYAN}${RPC_PORT}${NC}"
- echo -e " Redis: ${CYAN}db=${REDIS_DB}${NC}"
- echo ""
- echo -e " 管理:"
- echo -e " ${CYAN}bash ${ZONE_DIR}/start.sh${NC} 启动"
- echo -e " ${CYAN}bash ${ZONE_DIR}/stop.sh${NC} 停止"
- echo -e " ${CYAN}bash ${ZONE_DIR}/status.sh${NC} 状态"
- echo -e " ${CYAN}bash ${ZONE_DIR}/restart.sh${NC} 重启"
- echo -e " ${CYAN}tail -f ${BASE_OUTPUT}/logfile/server${ZONE_ID}.log${NC} 日志"
- echo ""
- echo -e " ${YELLOW}⚠ 别忘了:${NC}"
- echo -e " 1. 更新 OSS serverlist.json(见上方)"
- echo -e " 2. 防火墙放行端口 ${CONNECTOR_PORT} 和 ${RPC_PORT}"
- echo ""
|