PC-HEWEI\hewei 4 months ago
parent
commit
b8162da97f
100 changed files with 4511 additions and 3310 deletions
  1. 0 1
      sr/AGENTS.md
  2. 2 2
      sr/Makefile
  3. 251 243
      sr/README.md
  4. 314 10
      sr/docs/0001-dev-debug.md
  5. 346 45
      sr/docs/0002-prod-env-deployment.md
  6. 712 0
      sr/docs/0003-profile-config.md
  7. 0 0
      sr/docs/drawio/match.drawio
  8. 0 3
      sr/docs/git-flow/README.md
  9. 0 154
      sr/docs/git-flow/git-flow.drawio
  10. 0 700
      sr/docs/git-flow/git-flow.md
  11. BIN
      sr/docs/git-flow/git-flow.pdf
  12. 0 0
      sr/docs/git-flow/xy3-git-cn.docx
  13. 744 0
      sr/docs/git-flow/版本流程.md
  14. 0 3
      sr/etc/cli/cli.sh
  15. 0 1
      sr/etc/data/area.json
  16. 0 1
      sr/etc/data/area_server.json
  17. 18 18
      sr/etc/data/arm_type.json
  18. 135 135
      sr/etc/data/equip_attr_extra.json
  19. 1 0
      sr/etc/data/item.json
  20. 50 50
      sr/etc/data/lord_level.json
  21. 0 0
      sr/etc/data/map_castle.json
  22. 35 5
      sr/etc/data/proto_route.json
  23. 0 1
      sr/etc/data_embed/area.json
  24. 0 1
      sr/etc/data_embed/area_server.json
  25. 1 0
      sr/etc/data_embed/game_debug.json
  26. 6 5
      sr/etc/inner_pb/actor.proto
  27. 3 28
      sr/etc/profile/azw.json
  28. 2 27
      sr/etc/profile/dev.json
  29. 2 27
      sr/etc/profile/dhc.json
  30. 0 9
      sr/etc/profile/include/dev_mongodb.json
  31. 2 27
      sr/etc/profile/lcs.json
  32. 2 27
      sr/etc/profile/lgy.json
  33. 2 18
      sr/etc/profile/lgy_dev.json
  34. 2 27
      sr/etc/profile/local.json
  35. 3 28
      sr/etc/profile/su.json
  36. 2 27
      sr/etc/profile/test.json
  37. 0 250
      sr/etc/profile/yanjian.json
  38. 31 0
      sr/internal/actor_remote/game_order.go
  39. 0 31
      sr/internal/actor_remote/pay_order.go
  40. 1 16
      sr/internal/actor_remote/remote.go
  41. 9 9
      sr/internal/algorithm/aoi_tower/aoi.go
  42. 8 0
      sr/internal/code/status_code.go
  43. 3 2
      sr/internal/constant/charge.go
  44. 0 1
      sr/internal/constant/node_type.go
  45. 14 13
      sr/internal/constant/test.go
  46. 2 2
      sr/internal/constant/time.go
  47. 8 0
      sr/internal/data/extend_const.go
  48. 5 3
      sr/internal/data/lord_level.go
  49. 7 6
      sr/internal/enum/charge.go
  50. 64 17
      sr/internal/enum/item.go
  51. 1 4
      sr/internal/name/actor/actor.go
  52. 8 1
      sr/internal/name/db/game.go
  53. 0 10
      sr/internal/name/db/pay.go
  54. 28 27
      sr/internal/name/local/map.go
  55. 11 8
      sr/internal/name/local/player.go
  56. 4 3
      sr/internal/name/remote/map.go
  57. 24 23
      sr/internal/name/route/map.go
  58. 10 6
      sr/internal/name/route/player.go
  59. 45 42
      sr/internal/name/route/push.go
  60. 23 12
      sr/internal/pb/actor.pb.go
  61. 151 35
      sr/internal/pb/charge.pb.go
  62. 270 191
      sr/internal/pb/map.pb.go
  63. 28 13
      sr/internal/pb/vip.pb.go
  64. 140 38
      sr/internal/types/currency_map.go
  65. 2 0
      sr/nodes/game/game.go
  66. 14 0
      sr/nodes/game/internal/db/cache.go
  67. 85 0
      sr/nodes/game/internal/db/charge_table.go
  68. 8 5
      sr/nodes/game/internal/db/data/chapter/chapter.go
  69. 73 0
      sr/nodes/game/internal/db/data/charge/data.go
  70. 0 5
      sr/nodes/game/internal/db/data/lineup/lineup.go
  71. 23 9
      sr/nodes/game/internal/db/data/player/vip.go
  72. 2 0
      sr/nodes/game/internal/db/db.go
  73. 3 4
      sr/nodes/game/internal/db/order_table.go
  74. 1 0
      sr/nodes/game/internal/facade/define.go
  75. 5 0
      sr/nodes/game/internal/facade/facade.go
  76. 3 0
      sr/nodes/game/internal/facade/init/init.go
  77. 3 5
      sr/nodes/game/order/actor.go
  78. 2 12
      sr/nodes/game/order/actor_deliver.go
  79. 2 0
      sr/nodes/game/player/actor_player.go
  80. 11 8
      sr/nodes/game/player/asset/origin/origin.go
  81. 4 8
      sr/nodes/game/player/asset/type/currency.go
  82. 132 27
      sr/nodes/game/player/chapter/service.go
  83. 26 0
      sr/nodes/game/player/charge/service.go
  84. 5 5
      sr/nodes/game/player/charge/service_type.go
  85. 86 66
      sr/nodes/game/player/charge/type/card.go
  86. 55 0
      sr/nodes/game/player/charge/type/gold.go
  87. 65 0
      sr/nodes/game/player/charge/type/vip.go
  88. 12 8
      sr/nodes/game/player/currency/service.go
  89. 89 0
      sr/nodes/game/player/lineup/service.go
  90. 129 28
      sr/nodes/game/player/player_chapter.go
  91. 63 8
      sr/nodes/game/player/player_charge.go
  92. 16 86
      sr/nodes/game/player/player_lineup.go
  93. 2 1
      sr/nodes/game/player/player_timer.go
  94. 54 14
      sr/nodes/game/player/player_vip.go
  95. 6 0
      sr/nodes/game/player/vip/service.go
  96. 0 228
      sr/nodes/logs/8_202603111900.log
  97. 0 259
      sr/nodes/logs/8_202603121100.log
  98. 0 81
      sr/nodes/logs/8_202603121200.log
  99. 0 40
      sr/nodes/logs/8_202603121300.log
  100. 0 17
      sr/nodes/logs/8_202603121400.log

+ 0 - 1
sr/AGENTS.md

@@ -182,7 +182,6 @@ if code.IsOK(errCode) {
 - **web**: HTTP API端点(可多实例)
 - **chat**: 聊天功能(可多实例)
 - **map**: 地图沙盘玩法(核心功能,可多实例)
-- **pay**: 支付处理(可多实例)
 - **record**: 游戏数据记录
 - **ops**: 运维接口(单节点部署)
 - **match**: 匹配功能

+ 2 - 2
sr/Makefile

@@ -7,7 +7,8 @@ P4 := $(word 4, $(MAKECMDGOALS))  # 第4个参数
 chmod:
 	chmod +x ./etc/script/*.sh
 	chmod +x ./etc/cli/*.sh
-	chmod +x ./excel/_ee/*
+	chmod +x ./_excel/bin/ee_darwin
+	chmod +x ./_excel/bin/ee_linux
 
 init:
 	@echo "[INIT] Install protoc-gen-go"
@@ -28,7 +29,6 @@ clean:
 	rm -rf nodes/master/__debug_bin* && \
 	rm -rf nodes/match/__debug_bin* && \
 	rm -rf nodes/ops/__debug_bin* && \
-	rm -rf nodes/pay/__debug_bin* && \
 	rm -rf nodes/record/__debug_bin* && \
 	rm -rf nodes/web/__debug_bin*
 

+ 251 - 243
sr/README.md

@@ -2,11 +2,38 @@
 
 基于Go语言和Cherry框架构建的SLG(策略类)游戏服务器,采用分布式架构和Actor模型。
 
+## 目录
+
+- [项目概述](#项目概述)
+  - [开始](#开始)
+  - [环境要求](#环境要求)
+- [技术特性](#技术特性)
+- [项目结构](#项目结构)
+- [核心功能](#核心功能)
+- [快速开始](#快速开始)
+- [服务器架构](#服务器架构)
+  - [术语定义](#术语定义)
+  - [配置文件说明](#配置文件说明)
+  - [节点类型](#节点类型)
+  - [调试&启动](#调试启动)
+- [构建和发布](#构建和发布)
+  - [常用命令](#常用命令)
+  - [测试命令](#测试命令)
+- [仓库管理](#仓库管理)
+  - [Proto仓库](#proto仓库)
+  - [版本发布](#版本发布)
+  - [部署](#部署)
+- [QA](#qa)
+- [贡献指南](#贡献指南)
+- [许可证](#许可证)
+
+---
+
 ## 项目概述
 
 F1游戏服务器是一个高性能、分布式的游戏服务端项目,核心玩法为地图沙盘系统。项目使用以下技术栈:
 
-- **语言**: Go 1.24
+- **语言**: Go 1.24+
 - **框架**: Cherry(基于Actor模型的分布式框架)
 - **通信**: Protocol Buffers + NATS集群
 - **存储**: MongoDB(持久化) + Redis(缓存)
@@ -15,241 +42,307 @@ F1游戏服务器是一个高性能、分布式的游戏服务端项目,核心
 ### 开始
 
 - `clone`本仓库,通过`bash`来执行初始化命令
-- 安装`protoc` (v3.17.3) 和 `protoc-gen-go` (v1.27.1)
+- 安装`protoc` (v3.17.3) 和 `protoc-gen-go` (v1.36.8)
 - 执行`make`查询相关指令,执行`make init`进行项目初始化
 - 执行`make chmod`设置脚本权限
 
-### 术语定义
+### 环境要求
 
-- `node` 节点,每个服务进程都称为一个`节点`,通过`节点类型`进行归类
-- `pid` 平台id
-- `uid` 游戏内用户唯一id
-- `playerID` 玩家id
-- `openID` 第三方的用户唯一id
+| 组件 | 版本要求 |
+|------|----------|
+| Go | 1.24+ |
+| protoc | v3.17.3 |
+| protoc-gen-go | v1.36.8 |
+| MongoDB | 7.0+ |
+| Redis | 8.0+ |
+| NATS | 2.x |
 
-### 服务器架构图
+> 注意:确保所有依赖版本满足要求,否则可能导致构建或运行问题。
 
-(**项目使用基于nats集群的架构**)
+---
 
-[基于nats集群的架构](tool/docs/images/architecture-nats.jpg)
-[架构图PNG](docs/architecture.png)
+## 技术特性
 
-### 节点类型
+- **Actor模型**: 基于Cherry框架的Actor模型,实现高并发处理
+- **分布式架构**: 支持多节点部署,可横向扩展
+- **NATS集群**: 节点间通过NATS进行通信
+- **Protocol Buffers**: 高效的消息序列化
+- **MongoDB + Redis**: 持久化存储和高速缓存
 
-- **game**: 游戏服节点,核心游戏逻辑和玩家会话,滚服部署
-- **gate**: 游戏网关节点,WebSocket/HTTP网关,处理客户端连接,可多节点部署
-- **center**: 游戏中心节点,账户管理和支付服务,单节点部署
-- **master**: 节点发现服务,仅在NATS模式下使用,实现简易的发现服务功能
-- **web**: web节点,主要处理对外的http业务
-- **chat**: 聊天节点,处理游戏内聊天功能
-- **map**: 地图节点,处理地图沙盘玩法(核心功能)
-- **pay**: 支付节点,处理游戏支付相关业务
-- **record**: 记录节点,处理游戏记录数据
-- **ops**: 运维节点,提供运维相关接口
+## 项目结构
 
-### 调试&启动
+```
+f1-server/
+├── nodes/              # 各个节点目录
+│   ├── center/         # 中心节点
+│   ├── game/           # 游戏节点
+│   ├── gate/           # 网关节点
+│   ├── master/         # 主节点
+│   ├── web/            # Web节点
+│   ├── chat/           # 聊天节点
+│   ├── map/            # 地图节点(核心功能)
+│   ├── record/         # 记录节点
+│   ├── match/          # 匹配节点
+│   └── ops/            # 运维节点
+├── internal/           # 内部共享代码
+│   ├── actor_remote/   # 远程调用
+│   ├── component/      # 组件
+│   ├── pb/             # 协议文件(自动生成)
+│   ├── types/          # 自定义类型
+│   └── ...
+├── etc/                # 配置文件
+│   ├── profile/        # 环境配置
+│   ├── data/           # Excel数据(JSON)
+│   └── script/         # 脚本文件
+├── tool/               # 工具目录
+├── docs/               # 文档目录
+└── AGENTS.md           # AI代理开发指南
+```
 
-- 每个节点的启动都通过`nodes/main.go`的`run`命令进行
-- 启动前先确认`etc/profile/`目录是否有您需要的profile配置
-- **内部已部署整套`dev环境`,开发人员仅需启动`game节点`即可进行本地调试**
+---
 
-#### 启动参数示例
+## 核心功能
 
-- `run -path=./etc/profile/su.json -node=master-1`  启动master类型的节点,环境为`dev`,节点id为`master-1`
-- `run -path=./etc/profile/su.json -node=center-1`  启动center类型的节点,环境为`dev`,节点id为`center-1`
-- `run -path=./etc/profile/su.json -node=gate-1`  启动gate类型的节点,环境为`dev`,节点id为`gate-1`
-- `run -path=./etc/profile/su.json -node=gate-1`  启动gate类型的节点,环境为`dev`,节点id为`gate-1`
-- `run -path=./etc/profile/su.json -node=web-1`     启动web类型的节点,环境为`dev`,节点id为`web-1`
-- `run -path=./etc/profile/su.json -node=map-1`      启动map类型的节点,环境为`dev`,节点id为`map-1`
-- `run -path=./etc/profile/su.json -node=3`         启动game类型的节点,环境为`dev`,节点id为`3`
+### 地图沙盘系统(nodes/map)
 
-#### 版本查看
-- `run version` 或 `run v` 或 `run ver` 查看节点版本信息
+地图沙盘是本项目的核心功能模块,包含以下特性:
 
-### 调试&启动
+- **AOI(Area of Interest)系统**: 分层管理不同类型的地图对象
+- **寻路系统**: 支持大地图分区域、分层寻路的A星算法
+- **行军系统**: 支持多种行军状态(空闲、停留、撤退、占领、采集、驻守、攻城等)
+- **碰撞系统**: 处理行军对象之间的碰撞和战斗逻辑
+- **城战系统**: 支持攻城大营、宣战、集结等城战玩法
+- **联盟地图**: 支持联盟在地图上的业务逻辑
 
-- 每个节点的启动都通过`nodes/{xxx}/{xxx}.go`的`Run`函数进行
-- 启动前先确认`etc/profile/`目录是否有您需要的profile配置
-- **内部已部署整套`dev环境`,开发人员仅需启动`game节点`即可进行本地调试**
+详细文档请参考 [README](nodes/map/README.md)。
 
-#### 启动参数示例
+### 游戏服务节点(nodes/game)
 
-- `run -path=./etc/profile/ryansu.json -node=master-1`  启动master类型的节点,环境为`ryansu`,节点id为`master-1`
-- `run -path=./etc/profile/ryansu.json -node=center-1`  启动center类型的节点,环境为`ryansu`,节点id为`center-1`
-- `run -path=./etc/profile/ryansu.json -node=gate-1`  启动gate类型的节点,环境为`ryansu`,节点id为`gate-1`
-- `run -path=./etc/profile/ryansu.json -node=web-1`     启动web类型的节点,环境为`ryansu`,节点id为`web-1`
-- `run -path=./etc/profile/ryansu.json -node=1`         启动game类型的节点,环境为`ryansu`,节点id为`1`
+游戏服务节点是核心游戏逻辑处理中心,承载玩家会话和游戏主流程:
 
+- **玩家管理**: 玩家Actor分片处理,支持高并发玩家同时在线
+- **登录系统**: 处理玩家登录流程,创建和管理玩家会话
+- **邮件系统**: 游戏内邮件的发送、接收和管理
+- **排行榜**: 各类游戏排行榜的计算和展示
+- **通用对象池**: GUID生成和对象池管理
 
-### 构建和发布
+### 网关节点(nodes/gate)
 
-#### 常用命令
-```bash
-# 查看所有可用命令
-make help
+网关节点是客户端统一接入层,负责连接管理和请求路由:
 
-# 初始化项目(安装protoc-gen-go)
-make init
+- **连接管理**: 维护长连接,处理心跳检测和连接状态
+- **登录鉴权**: Token验证、SDK配置校验、获取UID
+- **请求路由**: 根据Session中的节点信息路由到Game/Map等后端节点
+- **限速控制**: 基于UID和IP的请求频率限制
+- **推送服务**: 支持按玩家、节点维度批量推送消息
+- **踢人机制**: 支持重复登录踢出、强制下线等功能
 
-# 构建完整项目(交互模式)
-make build
+详细文档请参考 [README](nodes/gate/README.md)。
 
-# 非交互模式构建
-make build <env> <update_excel> <publish>
-# env: 1=dev, 2=test, 3=dev&test, 4=prod
-# update_excel: y/Y/1 表示更新并导出Excel数据
-# publish: y/Y/1 表示推送到发布仓库
+### 中心节点(nodes/center)
 
-# 仅构建源代码
-make code
+中心节点提供跨游戏服的中心数据与控制平面:
 
-# 构建Excel数据文件
-make excel
+- **账号绑定**: 统一UID与第三方平台OpenID的绑定管理
+- **开发者账号**: 开发者账号注册、认证和权限管理
+- **登录记录**: 聚合并缓存玩家最后登录记录(Redis+MongoDB)
+- **运维接口**: 健康探测、优雅关停、DB队列监控
+- **数据分片**: Actor分片设计提升并发处理能力
 
-# 构建protobuf文件
-make proto
+详细文档请参考 [README](nodes/center/README.md)。
 
-# 清理构建产物
-make clean
+### 主节点(nodes/master)
 
-# 清理数据库
-make clean_db
-```
+主节点是节点发现服务,仅在NATS模式下使用:
 
-#### 仓库管理
+- **服务发现**: 管理集群中各节点的注册与发现
+- **节点同步**: 维护节点状态,支持新节点加入时的信息同步
+- **轻量级设计**: 单节点部署,作为集群协调中心
+
+### Web节点(nodes/web)
+
+Web节点处理对外HTTP业务,提供RESTful API:
+
+- **HTTP服务**: 基于Gin框架的HTTP API服务
+- **跨域支持**: 内置CORS中间件
+- **接口控制器**: 首页、开发者、登录、支付、玩家、服务器等接口
+- **限速保护**: IP级别的请求频率限制
+
+### 聊天节点(nodes/chat)
+
+聊天节点处理游戏内聊天功能:
+
+- **私聊**: 玩家一对一私聊消息
+- **群聊**: 多人群组聊天功能
+- **联盟聊天**: 联盟频道内的成员聊天
+- **地图聊天**: 地图范围内的区域聊天
+
+### 记录节点(nodes/record)
+
+记录节点处理游戏数据记录和日志存储:
+
+- **数据记录**: 游戏行为数据的异步记录
+- **多模式存储**: 支持本地文件模式和云存储模式
+- **Actor分片**: 根据数据类型分片处理,提升写入性能
+
+### 运维节点(nodes/ops)
+
+运维节点提供运维相关接口和管理功能:
+
+- **运维接口**: 服务器状态查询、配置管理
+- **静态资源**: 运维后台静态文件服务
+- **管理后台**: 游戏运营管理界面
+
+---
+
+## 快速开始
+
+1. 克隆仓库并初始化:
 ```bash
-# 更新外部仓库
-make pull-excel    # 更新Excel配置
-make pull-proto   # 更新protobuf定义
-make pull-cherry  # 更新Cherry框架
+git clone <repository-url>
+cd f1-server
+make init
+```
 
-# 设置脚本权限
+2. 设置脚本权限:
+```bash
 make chmod
 ```
 
-#### Excel数据管理
+3. 更新外部仓库:
 ```bash
-# 更新Excel仓库并转换为JSON
-make pull-e        # 从f1/excel.git更新excel仓库
-make e            # 转换xlsx文件到etc/data/并生成go文件到internal/data/
+make pull-excel
+make pull-proto
 ```
 
-#### 测试命令
+4. 构建项目:
 ```bash
-# 运行所有测试
-go test ./...
-
-# 运行特定测试文件
-go test ./tool/test/slice/slice_test.go
+make build
+```
 
-# 运行测试并显示详细输出
-go test -v ./path/to/test
+5. 启动节点:
+```bash
+run -path=./etc/profile/dev.json -node=1
+```
 
-# 运行单个测试函数
-go test -run TestSpecificFunction ./path/to/test
+---
 
-# 运行基准测试
-go test -bench=. ./path/to/test
+## 服务器架构
 
-# 运行测试并生成覆盖率报告
-go test -cover ./path/to/package
-```
+### 术语定义
 
-### 版本发布
-- 执行 `make build`,根据提示选择对应的版本发布。
-- 详细的发布流程请参考 `docs/git-flow/` 目录下的git flow文档。
+- `node` 节点,每个服务进程都称为一个`节点`,通过`节点类型`进行归类
+- `pid` 平台id
+- `uid` 游戏内用户唯一id
+- `playerID` 玩家id
+- `openID` 第三方的用户唯一id
 
-### 模块简介
+### 服务器架构图
 
-#### excel
+(**项目使用基于nats集群的架构**)
 
-- 本目录为策划excel配表仓库
-- 通过`make e`导表
-- Excel数据导出到 `etc/data/` 目录
+[基于nats集群的架构](tool/docs/images/architecture-nats.jpg)
+[架构图PNG](docs/architecture.png)
 
-#### protocol
+### 配置文件说明
 
-- 本目录为protobuf通信协议仓库,[通信协议包头](tool/docs/images/protocol.jpg)
-- 协议文件位于 `internal/pb/` 目录,基于 `/f1/protocol.git` 仓库生成
-- 生成逻辑详见`etc/script/build_proto.sh`脚本
-- 使用 `make pull-p` 更新protocol.git仓库
-- 使用 `make proto` 生成最终的协议文件
-- protoc-gen-go v1.27.1
-- protoc v3.17.3
+#### profile 目录
 
-#### nodes/center
+`etc/profile/` 目录下存放各环境的配置文件:
 
-- 游戏中心节点,单节点部署,用于处理帐号、支付相关公共业务
-- 不做具体游戏内的业务
+详细配置说明请参考 [Profile配置文件说明](docs/0003-profile-config.md)。
 
-#### nodes/map
+### 节点类型
 
-- 地图节点,处理地图沙盘玩法(核心功能)
-- 包含AOI管理、寻路、联盟地图等功能
-- 详细文档请参考 `nodes/map/README.md`
+- **game**: 游戏服节点,核心游戏逻辑和玩家会话,滚服部署
+- **gate**: 游戏网关节点,WebSocket/HTTP网关,处理客户端连接,可多节点部署
+- **center**: 游戏中心节点,账户管理和支付服务,单节点部署
+- **master**: 节点发现服务,仅在NATS模式下使用,实现简易的发现服务功能
+- **web**: web节点,主要处理对外的http业务
+- **chat**: 聊天节点,处理游戏内聊天功能
+- **map**: 地图节点,处理地图沙盘玩法(核心功能)
+- **record**: 记录节点,处理游戏记录数据
+- **ops**: 运维节点,提供运维相关接口
 
-#### nodes/game
+### 调试&启动
 
-- 游戏服节点,滚服部署
+- 每个节点的启动都通过`nodes/main.go`的`run`命令进行
+- 启动前先确认`etc/profile/`目录是否有您需要的profile配置
+- **内部已部署整套`dev环境`,开发人员仅需启动`game节点`即可进行本地调试** 
+- 详细的文档请查阅[开发调试指南](docs/0001-dev-debug.md)。
 
-#### nodes/gate
+---
 
-- 游戏网关节点,可多节点部署,根据负载情况进行多节点部署
-- 可以给每个`区`设置一个网关地址。通过数据库`center.area.gate`字段进行设置
-- 可以自行架设反向代理进行多个gate节点集群
-- 可通过阿里/腾讯云的`SLB服务`进行多网关节负载部署
+## 构建和发布
 
-#### nodes/master
+#### 常用命令
 
-- 仅在`profile->cluster->discovery`模式为`nats`时使用该节点
-- 实现简易的发现服务功能,单节点部署,用于同步/广播节点信息
+```bash
+# 查看所有可用命令
+make help
 
-#### nodes/web
+```
 
-- web节点主要处理对外的http业务
+#### 测试命令
 
-#### nodes/chat
+```bash
+# 运行所有测试
+go test ./...
 
-- 聊天节点,处理游戏内聊天相关业务
+# 运行特定测试文件
+go test ./tool/test/slice/slice_test.go
 
-#### nodes/pay
+# 运行测试并显示详细输出
+go test -v ./path/to/test
 
-- 支付节点,处理游戏支付相关业务
+# 运行单个测试函数
+go test -run TestSpecificFunction ./path/to/test
 
-#### nodes/record
+# 运行基准测试
+go test -bench=. ./path/to/test
 
-- 记录节点,处理游戏记录数据相关业务
+# 运行测试并生成覆盖率报告
+go test -cover ./path/to/package
+```
 
-#### nodes/ops
+#### 仓库管理
 
-- 运维节点,提供运维相关接口
+```bash
+# 更新外部仓库
+make pull-excel   # 更新Excel配置
+make pull-proto   # 更新protobuf协议
+make pull-cherry  # 更新Cherry框架(go work方式开发则有必要拉取cherry框架)
+make chmod        # 设置脚本权限
+```
 
-#### nodes/match
+#### Excel数据管理
 
-- 匹配节点,处理游戏匹配相关业务
+```bash
+# 更新Excel仓库并转换为JSON
+make pull-e       # 拉取Excel仓库
+make e            # 转换xlsx文件到etc/data/并生成go文件到internal/data/
+```
 
-#### tool
+#### 版本发布
 
-- 工具目录,包含各种开发工具
-  - `client-cli`: 客户端命令行工具,用于测试
-  - `cleandb`: 数据库清理工具
-  - `proto-route`: 协议路由工具
-  - `test`: 各种测试工具
+- 执行 `make build`,根据提示选择对应的版本发布。
+- 详细的发布流程请参考 `docs/git-flow/` 目录下的git flow文档。
 
-#### 数据库
+#### 部署
 
-- 通过`gorm`的migrator功能管理数据库结构
+- 生产环境部署手册详见 [生产环境部署说明](docs/0002-prod-env-deployment.md)。
 
-### 部署
-- TODO (生产环境部署手册)
+---
 
-### QA
+## QA
 
 #### 1. 文本格式设置
+
 - clone代码前修改git的`Auto Crlf convert`参数。AutoCrlf:false, SafeCrlf:false
 - 修改Goland,找到`Settings -> Editor -> Code Style -> Line Separator`修改为`Unix and Macos`
 
 #### 2. 代码编写事项
+
 - XxxID 字段 ID 要大小如`HeroID`不能是小写如`Heroid`或者`HeroId`
 - 方法的接收体名称统一使用 p ,这样看到 p.xxx 就知道是当前方法的主体
 - 所有的 int 类型统一使用 int32 或者 int64
@@ -258,106 +351,21 @@ go test -cover ./path/to/package
 - 详细代码风格指南请参考 `AGENTS.md`
 
 #### 3. linux开发环境配置
+
 - 安装`go` https://go.dev/doc/install
 - 安装`protoc`  https://github.com/protocolbuffers/protobuf/releases
 - 执行`make`或`make help` 查看相关脚本指令
 - 执行`make chmod` 设置相关脚本的权限
 - 执行`make init` 初始化相关组件
 
-## 项目结构
-
-```
-f1-server/
-├── nodes/              # 各个节点目录
-│   ├── center/         # 中心节点
-│   ├── game/           # 游戏节点
-│   ├── gate/           # 网关节点
-│   ├── master/         # 主节点
-│   ├── web/            # Web节点
-│   ├── chat/           # 聊天节点
-│   ├── map/            # 地图节点(核心功能)
-│   ├── pay/            # 支付节点
-│   ├── record/         # 记录节点
-│   ├── match/          # 匹配节点
-│   └── ops/            # 运维节点
-├── internal/           # 内部共享代码
-│   ├── actor_remote/   # 远程调用
-│   ├── component/      # 组件
-│   ├── pb/             # 协议文件(自动生成)
-│   ├── types/          # 自定义类型
-│   └── ...
-├── etc/                # 配置文件
-│   ├── profile/        # 环境配置
-│   ├── data/           # Excel数据(JSON)
-│   └── script/         # 脚本文件
-├── tool/               # 工具目录
-├── docs/               # 文档目录
-└── AGENTS.md           # AI代理开发指南
-```
-
-## 核心功能
-
-### 地图沙盘系统(nodes/map)
-
-地图沙盘是本项目的核心功能模块,包含以下特性:
-
-- **AOI(Area of Interest)系统**: 分层管理不同类型的地图对象
-- **寻路系统**: 支持大地图分区域、分层寻路的A星算法
-- **行军系统**: 支持多种行军状态(空闲、停留、撤退、占领、采集、驻守、攻城等)
-- **碰撞系统**: 处理行军对象之间的碰撞和战斗逻辑
-- **城战系统**: 支持攻城大营、宣战、集结等城战玩法
-- **联盟地图**: 支持联盟在地图上的业务逻辑
-
-详细文档请参考 `nodes/map/README.md`。
-
-## 技术特性
-
-- **Actor模型**: 基于Cherry框架的Actor模型,实现高并发处理
-- **分布式架构**: 支持多节点部署,可横向扩展
-- **NATS集群**: 节点间通过NATS进行通信
-- **Protocol Buffers**: 高效的消息序列化
-- **MongoDB + Redis**: 持久化存储和高速缓存
-
-## 开发文档
-
-- 开发规范和指南:请参考 `AGENTS.md`
-- Git工作流:请参考 `docs/git-flow/`
-- 架构文档:请参考 `docs/` 目录
-
-## 快速开始
-
-1. 克隆仓库并初始化:
-```bash
-git clone <repository-url>
-cd f1-server
-make init
-```
-
-2. 设置脚本权限:
-```bash
-make chmod
-```
-
-3. 更新外部仓库:
-```bash
-make pull-excel
-make pull-proto
-```
-
-4. 构建项目:
-```bash
-make build
-```
-
-5. 启动节点:
-```bash
-run -path=./etc/profile/dev.json -node=10002
-```
+---
 
 ## 贡献指南
 
 请参考 `docs/git-flow/` 目录下的git flow文档了解开发流程。
 
+---
+
 ## 许可证
 
-[请在此处添加许可证信息]
+- Firerock Copyright

+ 314 - 10
sr/docs/0001-dev-debug.md

@@ -1,14 +1,318 @@
-## 开发&调试
+# 开发调试说明
 
-### 开发环境准备
-- go版本1.24+
-- goland 2023.2.5+
+本文档说明如何在当前仓库内完成本地开发、联调、单节点调试和 Docker 全套环境调试。
 
-### 调试
+## 调试方式选择
 
+仓库当前有两种常用开发方式:
 
-### 数据库环境说明
-- mongo:版本 `7.0+`
-- 基字符集 `utf8mb4`
-- 数据库排序规则 `utf8mb4_general_ci`
-- 帐号需需有表权限
+| 方式 | 适用场景 | 说明 |
+| --- | --- | --- |
+| dev 环境单节点调试 | 日常功能开发 | 内部已有完整 dev 环境,开发时通常只需要启动本地 `game` 节点 |
+| 本机 local 环境全套联调 | 排查节点交互、网关、会话、Docker 问题 | 依赖 `etc/docker/local_db.yaml` 与 `etc/docker/local.yaml` |
+
+优先建议:
+
+1. 业务开发先用 `dev.json` 启动本地 `game` 节点。
+2. 只有在需要验证完整链路时,再切到 `local.json` 加 Docker 全套节点。
+
+## 环境要求
+
+### 基础工具
+
+| 工具 | 版本要求 | 用途 |
+| --- | --- | --- |
+| Go | 1.24+ | 编译与运行 |
+| Docker Desktop | 最新稳定版 | 本地 Redis、MongoDB、NATS 与整套 local 节点 |
+| protoc | 3.17.3 | 生成协议代码 |
+| protoc-gen-go | 1.36.8 | 生成 Go 协议代码 |
+
+### Git 配置
+
+仓库要求关闭 AutoCRLF:
+
+```bash
+git config --global core.autocrlf false
+git config --global core.safecrlf false
+```
+
+## 项目初始化
+
+```bash
+git clone <repository-url>
+cd f1-server
+make init
+make chmod
+make code
+```
+
+如果需要同步外部配置:
+
+```bash
+make pull-excel
+make pull-proto
+make pull-cherry
+```
+
+## 方式一:dev 环境单节点调试
+
+这是仓库内最常用的开发方式。
+
+### 核心结论
+
+- 使用配置文件:`etc/profile/dev.json`
+- 默认依赖:dev 环境中的 Redis、MongoDB、NATS
+- 本地只启动一个 `game` 节点即可
+- 启动命令中的 `-node=1` 表示当前实例匹配 `game` 节点配置里的正则 `^\d+$`
+
+### 启动命令
+
+在仓库根目录先编译:
+
+```bash
+make code
+```
+
+然后进入任意节点目录启动,日常开发通常只启动 `game`:
+
+```bash
+cd nodes/game
+run -path=../../etc/profile/dev.json -node=1
+```
+
+如果需要调试其他节点,可以使用:
+
+```bash
+cd nodes/master && run -path=../../etc/profile/dev.json -node=master-1
+cd nodes/center && run -path=../../etc/profile/dev.json -node=center-1
+cd nodes/gate && run -path=../../etc/profile/dev.json -node=gate-1
+cd nodes/web && run -path=../../etc/profile/dev.json -node=web-1
+cd nodes/map && run -path=../../etc/profile/dev.json -node=map-1
+cd nodes/chat && run -path=../../etc/profile/dev.json -node=chat-1
+cd nodes/record && run -path=../../etc/profile/dev.json -node=record-1
+```
+
+### dev 环境关键依赖
+
+`dev.json` 当前直接写死了下列连接:
+
+| 组件 | 配置值 |
+| --- | --- |
+| NATS | `nats://nats:4222,nats://nats-1:4223,nats://nats-2:4224` |
+| Redis | `redis:6379` |
+| MongoDB | `mongodb://f1user:***@mongodb:27017` |
+| 数据目录 | `../data/` |
+
+如果当前机器不在内部网络,`dev.json` 模式无法正常联调。
+
+## 方式二:本机 local 环境全套联调
+
+`local.json` 配合 Docker Compose 可以在本机启动完整环境。
+
+### 1. 创建网络
+
+首次运行前创建 `f1` 网络:
+
+```bash
+docker network create --driver=bridge f1
+```
+
+查看网络:
+
+```bash
+docker network ls
+docker network inspect f1
+```
+
+### 2. 启动基础依赖
+
+```bash
+docker-compose -f etc/docker/local_db.yaml up -d
+```
+
+当前 `local_db` 实际启动内容:
+
+| 服务 | 容器名 | 宿主机端口 | 容器内地址 |
+| --- | --- | --- | --- |
+| Redis | `redis` | `46379` | `redis:6379` |
+| MongoDB | `mongodb` | `27017` | `mongodb:27017` |
+| NATS | `nats` | `4222`、`8222` | `nats:4222` |
+| NATS-1 | `nats-1` | `4223` | `nats-1:4222` |
+| NATS-2 | `nats-2` | `4224` | `nats-2:4222` |
+
+查看状态:
+
+```bash
+docker-compose -f etc/docker/local_db.yaml ps
+```
+
+### 3. 启动游戏节点
+
+```bash
+docker-compose -f etc/docker/local.yaml up -d
+```
+
+当前 `local.yaml` 实际启动的节点:
+
+| 节点 | 容器名 | 对外端口 |
+| --- | --- | --- |
+| master | `f1-master-1` | 无 |
+| center | `f1-center-1` | 无 |
+| game | `f1-game-1` | 无 |
+| map | `f1-map-1` | 无 |
+| chat | `f1-chat-1` | 无 |
+| record | `f1-record-1` | 无 |
+| gate | `f1-gate-1` | `30001` |
+| web | `f1-web-1` | `18080 -> 80` |
+| ops | `f1-ops-1` | `18081` |
+
+查看状态与日志:
+
+```bash
+docker-compose -f etc/docker/local.yaml ps
+docker logs -f f1-game-1
+docker logs -f f1-gate-1
+```
+
+### 4. 停止环境
+
+```bash
+docker-compose -f etc/docker/local.yaml down
+docker-compose -f etc/docker/local_db.yaml down
+```
+
+如需删除网络:
+
+```bash
+docker network rm f1
+```
+
+## local profile 关键参数
+
+`etc/profile/local.json` 的实际特征如下:
+
+| 配置项 | 当前值 | 说明 |
+| --- | --- | --- |
+| `env` | `local` | 本地私服环境 |
+| `cluster.discovery.mode` | `nats` | 节点发现依赖 NATS |
+| `cluster.nats.prefix` | `test` | local 环境也使用 `test` 集群前缀 |
+| `redis[0].address` | `redis:6379` | Docker 内部地址 |
+| `mongo.*.db_name` | `local-f1-*` | 本地数据库名带 `local-` 前缀 |
+| `logger.debug_file_log.enable_console` | `false` | 默认主要写文件 |
+
+## IDE 调试
+
+### VSCode
+
+可直接调试 `nodes/main.go`,通过参数决定环境与节点。
+
+最常用的两个配置如下:
+
+```json
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "dev-game-1",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "${workspaceFolder}/nodes/main.go",
+            "args": [
+                "run",
+                "-path=${workspaceFolder}/etc/profile/dev.json",
+                "-node=1"
+            ],
+            "console": "integratedTerminal"
+        },
+        {
+            "name": "local-gate-1",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "${workspaceFolder}/nodes/main.go",
+            "args": [
+                "run",
+                "-path=${workspaceFolder}/etc/profile/local.json",
+                "-node=gate-1"
+            ],
+            "console": "integratedTerminal"
+        }
+    ]
+}
+```
+
+### GoLand
+
+`Run/Debug Configurations` 中新增 `Go Build` 或 `Go Application`:
+
+- Run kind 选择 package/file 均可
+- 入口文件使用 `nodes/main.go`
+- Program arguments 使用 `run -path=... -node=...`
+- Working directory 使用仓库根目录
+
+## 快速排查
+
+### 查看版本
+
+```bash
+run version
+```
+
+### 只编译代码
+
+```bash
+make code
+```
+
+### 运行单测
+
+```bash
+go test ./...
+go test ./internal/algorithm/astar/
+go test -run TestAstar ./internal/algorithm/astar/
+```
+
+## 常见问题
+
+### 1. `run` 启动失败,提示节点不匹配
+
+优先检查:
+
+- `-node` 是否命中 profile 中的 `node_id`
+- `game` 节点通常是数字,如 `1`、`3`、`6`
+- `gate`、`web`、`master` 等节点通常是固定字符串
+
+### 2. 本地已启动 Docker,但节点仍连不上 Redis 或 MongoDB
+
+优先检查:
+
+```bash
+docker-compose -f etc/docker/local_db.yaml ps
+docker ps
+docker network inspect f1
+```
+
+然后确认 `local.json` 中使用的是容器内部地址 `redis:6379`、`mongodb:27017`,不是宿主机地址。
+
+### 3. 端口冲突
+
+本地默认暴露端口:
+
+- `30001`:gate
+- `18080`:web
+- `18081`:ops
+- `46379`:Redis
+- `27017`:MongoDB
+- `4222/4223/4224`:NATS
+- `8222`:NATS 监控
+
+如端口冲突,修改对应的 Docker Compose 映射端口。
+
+### 4. 为什么日常开发不建议启动全套节点
+
+因为仓库已经约定:
+
+- 开发期默认依赖现成 dev 环境
+- 本地仅启动 `game` 节点即可进入业务开发
+- 全套 local 环境更适合排查网关、会话同步、节点互调和容器问题

+ 346 - 45
sr/docs/0002-prod-env-deployment.md

@@ -1,48 +1,349 @@
-## 生产环境部署说明
-
-### 硬件环境要求
-- TODO
-
-### 安装中间件
-
-#### 安装redis
-- TODO
-
-#### 安装mysql
-- TODO
-
-#### 安装nat.io
-- https://docs.nats.io/running-a-nats-service/nats-kubernetes
-- docker compose
-```dockerfile
-version: "3.5"
-services:
-  nats:
-    image: nats
-    ports:
-      - "8222:8222"
-    command: "--cluster_name NATS --cluster nats://0.0.0.0:6222 --http_port 8222 "
-    networks: ["nats"]
-  nats-1:
-    image: nats
-    command: "--cluster_name NATS --cluster nats://0.0.0.0:6222 --routes=nats://ruser:T0pS3cr3t@nats:6222"
-    networks: ["nats"]
-    depends_on: ["nats"]
-  nats-2:
-    image: nats
-    command: "--cluster_name NATS --cluster nats://0.0.0.0:6222 --routes=nats://ruser:T0pS3cr3t@nats:6222"
-    networks: ["nats"]
-    depends_on: ["nats"]
-
-networks:
-  nats:
-    name: nats
+# 生产环境部署说明
+
+本文档说明当前仓库的环境组织方式、生产环境部署原则、节点部署建议和上线检查项。
+
+## 先说明一件事
+
+当前仓库 `etc/profile/` 目录下不存在 `prod.json`,现有环境文件是:
+
+- `test.json`
+- `su.json`
+- `lgy.json`
+- `dhc.json`
+- `azw.json`
+- 以及对应的 `_dev.json`
+
+这意味着当前项目的“生产部署”不是统一依赖一个固定 `prod.json`,而是按平台或环境拆成独立 profile。部署时应以目标环境对应的 profile 为准,而不是假设存在通用 `prod.json`。
+
+## 部署目标
+
+生产环境部署需要解决四类问题:
+
+1. 中间件可用,Redis、MongoDB、NATS 先就绪。
+2. profile 与目标环境一一对应,不能混用前缀、库名、Redis ID。
+3. 节点按职责拆分启动,尤其 `master`、`gate`、`game`、`map`、`center`、`web`。
+4. 上线前完成配置、端口、日志、数据写入和节点发现验证。
+
+## 环境文件组织
+
+### 当前已有环境
+
+| 文件 | 用途 |
+| --- | --- |
+| `test.json` | 测试环境 |
+| `su.json` | SU 环境 |
+| `lgy.json` | LGY 环境 |
+| `dhc.json` | DHC 环境 |
+| `azw.json` | AZW 环境 |
+| `*_dev.json` | 对应环境的开发联调版本 |
+
+### 环境隔离的关键字段
+
+实际隔离主要依赖以下配置:
+
+| 字段 | 作用 |
+| --- | --- |
+| `env` | 环境名 |
+| `cluster.nats.prefix` | 集群消息前缀,必须全环境唯一 |
+| `redis[].redis_id` | Redis 实例逻辑名 |
+| `mongo.*[].db_name` | MongoDB 数据库名 |
+| `node.*[].node_id` | 节点实例标识 |
+
+示例:
+
+- `su.json` 使用 `prefix: "su"`,数据库名形如 `su-f1-game`
+- `lgy.json` 使用 `prefix: "lgy"`,数据库名形如 `lgy-f1-game`
+- `azw.json` 使用 `prefix: "azw"`,数据库名形如 `azw-f1-game`
+
+## 部署前准备
+
+### 机器与系统要求
+
+仓库没有提供强制规格表,当前建议按节点职责拆分:
+
+| 节点 | 建议 |
+| --- | --- |
+| `master` | 单独部署,单实例 |
+| `center` | 单独部署,单实例或主备 |
+| `gate` | 可多实例,前置负载均衡 |
+| `game` | 可多实例,按滚服或区服扩容 |
+| `map` | 可多实例,视地图压力扩容 |
+| `web` | 可多实例 |
+| `chat` | 可多实例 |
+| `record` | 按战报写入压力部署 |
+| `ops` | 单独控制访问来源 |
+
+最低前提:
+
+- Go 1.24+
+- MongoDB 7.0+
+- Redis 可用
+- NATS 集群可用
+- 服务器时区统一为 `Asia/Shanghai`
+
+### 构建产物
+
+仓库实际启动入口是 `nodes/main.go`,命令形式统一为:
+
+```bash
+run -path=./etc/profile/<env>.json -node=<node-id>
+```
+
+生产发布前至少执行:
+
+```bash
+make init
+make chmod
+make code
 ```
 
-### 部署服务器版本
-- TODO
+如果涉及协议或配置更新,再执行:
+
+```bash
+make proto
+make excel
+```
+
+## 中间件部署
+
+### Redis
+
+用途:
+
+- 会话存储
+- 全局 ID 生成
+- 部分业务缓存
+
+部署要求:
+
+- 为目标环境分配独立实例或独立逻辑库
+- 与 profile 内 `redis_id` 和 `address` 保持一致
+- 密码必须与环境文件一致
+
+### MongoDB
+
+用途:
+
+- 游戏、中心、地图等持久化数据
+
+当前 profile 使用四组逻辑库:
+
+| 分组 | 典型用途 |
+| --- | --- |
+| `db_game_group` | game 数据 |
+| `db_center_group` | center 数据 |
+| `db_map_group` | map 数据 |
+
+要求:
+
+- 为每个环境使用独立 `db_name`
+- 用户名、密码和 URI 必须与 profile 一致
+- 部署前确认账号具有建表、读写权限
+
+### NATS
+
+用途:
+
+- 节点注册
+- 远程调用
+- 集群消息通信
+
+仓库现有配置均默认:
+
+- `cluster.discovery.mode = nats`
+- `cluster.nats.master_node_id = master-1`
+
+因此生产环境必须先保证:
+
+1. `master-1` 所在节点可启动。
+2. 其他节点能访问 NATS。
+3. `cluster.nats.prefix` 与其他环境不冲突。
+
+## profile 编写原则
+
+新增一个生产环境时,建议复制最接近的环境文件,例如:
+
+- 新平台服复制 `su.json` / `azw.json`
+- 新联运环境复制 `lgy.json` / `dhc.json`
+
+然后只改以下内容:
+
+1. `env`
+2. `cluster.nats.prefix`
+3. `cluster.nats.address`
+4. `redis`
+5. `mongo`
+6. `node`
+7. `logger`
+
+不要直接复用别的环境的:
+
+- Redis 库
+- Mongo 数据库名
+- NATS prefix
+- `game` 节点固定编号
+
+## 节点部署建议
+
+### 单实例节点
+
+这些节点通常只部署一个:
+
+| 节点类型 | 说明 |
+| --- | --- |
+| `master` | 服务发现核心节点 |
+| `center` | 账户与中心服务 |
+| `ops` | 运维入口,建议严格限制访问 |
+
+### 多实例节点
+
+这些节点通常根据压力扩容:
+
+| 节点类型 | 说明 |
+| --- | --- |
+| `gate` | 前置接入,可多实例 |
+| `game` | 玩家逻辑,可多实例 |
+| `map` | 沙盘地图,可多实例 |
+| `web` | HTTP 服务,可多实例 |
+| `chat` | 聊天服务,可多实例 |
+| `record` | 战报与记录,可多实例 |
+
+### 启动顺序
+
+建议按依赖顺序启动:
+
+1. Redis、MongoDB、NATS
+2. `master`
+3. `center`
+4. `game`
+5. `map`
+6. `chat`
+7. `record`
+8. `gate`
+9. `web`
+10. `ops`
+
+`gate` 和 `web` 可以放在后面启动,避免外部流量先进入。
+
+## 启动命令示例
+
+以下示例以 `su.json` 为例:
+
+```bash
+run -path=./etc/profile/su.json -node=master-1
+run -path=./etc/profile/su.json -node=center-1
+run -path=./etc/profile/su.json -node=gate-1
+run -path=./etc/profile/su.json -node=web-1
+run -path=./etc/profile/su.json -node=ops-1
+run -path=./etc/profile/su.json -node=3
+run -path=./etc/profile/su.json -node=map-1
+run -path=./etc/profile/su.json -node=chat-1
+run -path=./etc/profile/su.json -node=record-1
+```
+
+注意:
+
+- `game` 节点有的环境是固定数字,如 `3`、`6`
+- 有的环境使用正则 `^\d+$`,表示可多开多个 `game` 实例
+- `center`、`chat`、`map` 在部分环境中也用正则匹配多实例
+
+## 发布流程建议
+
+### 1. 发布前检查
+
+```bash
+make code
+go test ./...
+run version
+```
+
+重点检查:
+
+- profile 是否引用正确
+- 目标节点 `node_id` 是否存在
+- Redis、Mongo、NATS 地址是否可达
+- 日志目录是否可写
+- `etc/data/` 与 `internal/data/` 是否已同步
+
+### 2. 灰度发布
+
+建议:
+
+1. 先启动新版本 `master` 之外的非入口节点做验证。
+2. 确认节点注册成功后,再切换 `gate`、`web`。
+3. 最后再放量外部流量。
+
+如果是替换式发布,至少保证:
+
+- `master` 不先于依赖中间件下线
+- `gate` 切流前,`game`/`map`/`center` 已全部可用
+
+### 3. 回滚准备
+
+上线前保留:
+
+- 上一版本二进制
+- 上一版 profile
+- 数据库与 Redis 变更记录
+- 本次构建版本号
+
+如果本次包含协议、配置或数据结构变更,必须先评估是否可逆,不能把回滚建立在“应该没问题”上。
+
+## 上线核对清单
+
+### 中间件
+
+- Redis 可连接
+- MongoDB 可连接
+- NATS 集群正常
+- `master-1` 能连通 NATS
+
+### 配置
+
+- `env` 正确
+- `cluster.nats.prefix` 唯一
+- `mongo.db_name` 没有串环境
+- `redis_id_list`、`mongo_id_list` 与基础配置可对应
+- `ref_logger` 指向存在的 logger 配置
+
+### 节点
+
+- 每个启动命令的 `-node` 与 profile 匹配
+- `gate` 和 `web` 的对外端口未冲突
+- 多实例节点的实例 ID 不重复
+
+### 数据
+
+- `etc/data/` 为目标版本
+- `battle_record` 存储路径可写
+- `db_queue` 参数与环境负载匹配
+
+## 常见错误
+
+### 1. 不同环境共用了同一个 NATS prefix
+
+结果:
+
+- 节点发现串环境
+- 远程调用可能打到错误节点
+
+这是高危配置错误,必须先改 `cluster.nats.prefix`。
+
+### 2. `game` 节点编号写错
+
+例如 profile 里写死 `node_id = "3"`,启动时却用了 `-node=1`,会直接启动失败。
+
+### 3. Redis ID 存在,但节点 settings 没引用
+
+`redis` 配置本身正确不代表节点能用。真正生效的是 `__settings__.redis_id_list` 里的映射。
+
+### 4. Mongo 配置正确,但数据库名串环境
+
+例如把 `su` 环境写成 `lgy-f1-game`,服务能启动,但数据会写错库,这类问题比启动失败更危险。
+
+## 建议
+
+如果后续要补齐真正统一的生产部署能力,优先做两件事:
 
-#### 获取版本
-#### 配置参数
-#### 检查部署
-- TODO
+1. 新增标准化 `prod.json` 或明确的环境模板。
+2. 增加 systemd、Supervisor 或容器编排脚本,避免每个节点依赖手工命令启动。

+ 712 - 0
sr/docs/0003-profile-config.md

@@ -0,0 +1,712 @@
+# Profile 配置文件说明
+
+本文档说明 `etc/profile/` 目录下各环境配置文件的组织方式、字段含义和修改原则。
+
+## 目录说明
+
+### 环境文件
+
+当前仓库存在的顶层 profile 文件:
+
+| 文件 | 说明 |
+| --- | --- |
+| `local.json` | 本地 Docker 联调环境 |
+| `dev.json` | 开发环境 |
+| `test.json` | 测试环境 |
+| `su.json` | SU 环境 |
+| `su_dev.json` | SU 开发联调环境 |
+| `lgy.json` | LGY 环境 |
+| `lgy_dev.json` | LGY 开发联调环境 |
+| `dhc.json` | DHC 环境 |
+| `dhc_dev.json` | DHC 开发联调环境 |
+| `azw.json` | AZW 环境 |
+| `lcs.json` | 现有环境文件 |
+
+### include 文件
+
+`etc/profile/include/` 目录用于拆分公共片段,当前可见的公共配置包括:
+
+| 文件 | 用途 |
+| --- | --- |
+| `logger.json` | 日志模板 |
+| `dev_cluster.json` | 开发环境集群配置 |
+| `dev_data_config.json` | 开发环境数据配置 |
+| `dev_mongodb.json` | 开发环境 MongoDB 配置 |
+| `dev_redis.json` | 开发环境 Redis 配置 |
+| `dev_queue.json` | 数据库存盘队列配置 |
+| `dev_session.json` | 会话配置 |
+| `dev_genpool.json` | 全局 ID 池配置 |
+| `dev_game.json` | 开发环境节点配置 |
+| `dev_battle_record.json` | 战报配置 |
+
+## 配置加载方式
+
+节点启动入口在 `nodes/main.go`,执行流程是:
+
+1. 读取命令行参数中的 `-path`
+2. 读取命令行参数中的 `-node`
+3. 调用 Cherry 的 `profile.Init(path, nodeID)`
+4. 根据 `nodeID` 解析节点类型并启动对应节点
+
+实际启动命令:
+
+```bash
+run -path=./etc/profile/dev.json -node=1
+```
+
+因此 profile 的正确性,直接决定节点能否启动。
+
+## 整体结构
+
+一个完整 profile 的典型结构如下:
+
+```json
+{
+    "@desc": "环境描述",
+    "include": [],
+    "env": "dev",
+    "debug": true,
+    "print_level": "debug",
+    "cluster": {},
+    "data_config": {},
+    "node": {},
+    "db_queue": {},
+    "redis": [],
+    "mongo": {},
+    "rate_limiter": [],
+    "sessions": {},
+    "gen-pool": {},
+    "battle_record": {},
+    "logger": {}
+}
+```
+
+并不是所有环境都必须把所有字段写满。
+
+例如:
+
+- `su_dev.json` 主要通过 `include` 引入公共片段
+- `local.json` 与 `dev.json` 则直接写了完整结构
+
+## 基础字段
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| `@desc` | string | 环境描述 |
+| `include` | array | 需要合并的公共配置文件 |
+| `env` | string | 环境名 |
+| `debug` | bool | 是否开启调试模式 |
+| `print_level` | string | 全局日志级别 |
+
+### include
+
+用于配置复用。
+
+示例:
+
+```json
+{
+    "include": [
+        "include/logger.json",
+        "include/dev_mongodb.json",
+        "include/dev_redis.json"
+    ]
+}
+```
+
+适用场景:
+
+- 同一套 Redis、Mongo、logger 被多个环境共用
+- 平台环境只覆盖少量差异字段
+
+## cluster
+
+`cluster` 用于配置服务发现与节点通信。
+
+### 结构示例
+
+```json
+{
+    "cluster": {
+        "discovery": {
+            "mode": "nats"
+        },
+        "nats": {
+            "master_node_id": "master-1",
+            "prefix": "test",
+            "address": "nats://nats:4222,nats://nats-1:4223,nats://nats-2:4224",
+            "reconnect_delay": 1,
+            "max_reconnects": 0,
+            "request_timeout": 2,
+            "user": "",
+            "password": "",
+            "pool_size": 16,
+            "is_stats": false
+        }
+    }
+}
+```
+
+### discovery
+
+| 字段 | 说明 |
+| --- | --- |
+| `mode` | 服务发现模式,当前项目实际主要使用 `nats` |
+
+当前注释里还预留了:
+
+- `default`
+- `nats`
+- `etcd`
+
+但仓库现有环境基本都是 `nats`。
+
+### nats
+
+| 字段 | 说明 |
+| --- | --- |
+| `master_node_id` | 主节点 ID,当前固定为 `master-1` |
+| `prefix` | 环境隔离前缀 |
+| `address` | NATS 地址列表,逗号分隔 |
+| `reconnect_delay` | 重连等待时间,单位秒 |
+| `max_reconnects` | 最大重连次数,`0` 表示不限 |
+| `request_timeout` | 请求超时,单位秒 |
+| `user` | 认证用户 |
+| `password` | 认证密码 |
+| `pool_size` | 连接池大小 |
+| `is_stats` | 是否开启统计 |
+
+### 修改原则
+
+- `prefix` 必须按环境唯一
+- `master_node_id` 一般不要改
+- `address` 必须与实际 NATS 集群对应
+
+## data_config
+
+用于配置 Excel 导出的游戏数据加载方式。
+
+### 结构示例
+
+```json
+{
+    "data_config": {
+        "parser": "json",
+        "data_source": "file",
+        "file": {
+            "file_path": "../data/",
+            "ext_name": ".json",
+            "reload_time": 3000
+        },
+        "redis": {
+            "address": "redis:6379",
+            "password": "xxx",
+            "db": 0,
+            "prefix_key": "data_config",
+            "subscribe_key": "data_config_change"
+        }
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `parser` | 解析器类型,当前使用 `json` |
+| `data_source` | 数据来源,支持 `file` 或 `redis` |
+
+#### `file`
+
+| 字段 | 说明 |
+| --- | --- |
+| `file_path` | 数据目录 |
+| `ext_name` | 文件扩展名 |
+| `reload_time` | 热更新检查间隔,毫秒 |
+
+#### `redis`
+
+| 字段 | 说明 |
+| --- | --- |
+| `address` | Redis 地址 |
+| `password` | Redis 密码 |
+| `db` | DB 编号 |
+| `prefix_key` | 数据前缀 |
+| `subscribe_key` | 配置变更订阅键 |
+
+### 现状
+
+当前环境主要还是 `file` 模式,目录通常是 `../data/`。
+
+## node
+
+`node` 是最关键的一段,决定当前 profile 支持哪些节点、每个节点如何匹配以及节点私有配置。
+
+### 结构示例
+
+```json
+{
+    "node": {
+        "gate": [
+            {
+                "enable": true,
+                "node_id": "gate-1",
+                "address": ":30001",
+                "__settings__": {
+                    "heartbeat": 120,
+                    "ref_logger": "debug_file_log",
+                    "redis_id_list": {
+                        "guid_redis_id": "redis-global",
+                        "center_redis_id": "redis-global"
+                    }
+                }
+            }
+        ]
+    }
+}
+```
+
+### 通用字段
+
+| 字段 | 说明 |
+| --- | --- |
+| `enable` | 是否启用该实例 |
+| `node_id` | 节点 ID,可写固定值,也可写正则 |
+| `address` | 对外监听地址,部分节点需要 |
+| `__settings__` | 节点私有设置 |
+
+### `node_id` 规则
+
+常见写法:
+
+| 写法 | 含义 |
+| --- | --- |
+| `gate-1` | 固定实例 |
+| `master-1` | 固定实例 |
+| `^\d+$` | 匹配任意数字 game 节点 |
+| `^map-\d+$` | 匹配多个 map 节点 |
+| `^chat-\d+$` | 匹配多个 chat 节点 |
+
+### `__settings__` 常见字段
+
+| 字段 | 说明 |
+| --- | --- |
+| `ref_logger` | 引用 `logger` 中的日志配置名 |
+| `redis_id_list` | 当前节点依赖的 Redis 配置映射 |
+| `mongo_id_list` | 当前节点依赖的 Mongo 配置映射 |
+| `heartbeat` | gate 心跳时间 |
+| `battle_validation` | game 是否开启战斗校验 |
+| `allow_register` | web 是否允许注册 |
+
+### 节点类型
+
+仓库当前支持的节点类型可从 `nodes/main.go` 看出:
+
+- `master`
+- `center`
+- `game`
+- `gate`
+- `web`
+- `ops`
+- `chat`
+- `map`
+- `record`
+
+## db_queue
+
+`db_queue` 用于配置 MongoDB 批量落盘策略。
+
+相关代码在 `internal/component/db/queue/table_queue_config.go`。
+
+### 结构示例
+
+```json
+{
+    "db_queue": {
+        "save_ticker": 3,
+        "save_count": 1000,
+        "stop_save_count": 10000,
+        "print_save_log": false,
+        "tables": []
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `save_ticker` | 定时保存周期,秒 |
+| `save_count` | 每次批量保存条数 |
+| `stop_save_count` | 节点停止时一次处理条数 |
+| `print_save_log` | 是否打印保存日志 |
+| `tables` | 针对单表覆盖默认参数 |
+
+### 单表覆盖
+
+例如 `lgy.json` 与 `su.json` 中,会针对 `map_tile`、`map_res` 一类高频表做特殊配置。
+
+示例:
+
+```json
+{
+    "tables": [
+        {
+            "name": "map_tile",
+            "save_ticker": 120,
+            "save_count": 300
+        }
+    ]
+}
+```
+
+## redis
+
+`redis` 用于定义 Redis 实例列表,节点通过 `redis_id_list` 引用。
+
+### 结构示例
+
+```json
+{
+    "redis": [
+        {
+            "redis_id": "redis-global",
+            "address": "redis:6379",
+            "password": "xxx",
+            "db": 0,
+            "pool_size": 64,
+            "desc": "全局"
+        }
+    ]
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `redis_id` | 逻辑 ID |
+| `address` | 地址 |
+| `password` | 密码 |
+| `db` | Redis DB |
+| `pool_size` | 连接池大小 |
+| `desc` | 描述 |
+
+### 使用关系
+
+- 先在 `redis` 中声明实例
+- 再在 `node.*[].__settings__.redis_id_list` 中引用
+- 运行时由 Redis 组件读取 `redis_id_list`
+
+## mongo
+
+`mongo` 用于定义 MongoDB 分组配置,节点通过 `mongo_id_list` 引用。
+
+### 结构示例
+
+```json
+{
+    "mongo": {
+        "db_game_group": [
+            {
+                "enable": true,
+                "db_id": "mongo-f1-game",
+                "db_name": "f1-game",
+                "uri": "mongodb://user:pass@host:27017",
+                "timeout": 3000
+            }
+        ]
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `enable` | 是否启用 |
+| `db_id` | 逻辑 ID |
+| `db_name` | 数据库名 |
+| `uri` | Mongo 连接串 |
+| `timeout` | 超时,毫秒 |
+
+### 分组说明
+
+| 分组 | 用途 |
+| --- | --- |
+| `db_game_group` | game 数据 |
+| `db_center_group` | center 数据 |
+| `db_map_group` | map 数据 |
+
+### 使用关系
+
+- 先在 `mongo` 中定义 `db_id`
+- 再在节点 `mongo_id_list` 中引用
+- 数据库组件根据 `mongo_id_list` 取对应实例
+
+## rate_limiter
+
+用于限流配置。
+
+### 结构示例
+
+```json
+{
+    "rate_limiter": [
+        {
+            "enable": true,
+            "rate_id": "ip_rate",
+            "interval": 1,
+            "capacity": 60,
+            "quantum": 60,
+            "clean_ticker_interval": 10,
+            "clean_before_minute": 5,
+            "error_code": 205
+        }
+    ]
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `enable` | 是否启用 |
+| `rate_id` | 限流器 ID |
+| `interval` | 加令牌周期 |
+| `capacity` | 桶容量 |
+| `quantum` | 每次补充数量 |
+| `clean_ticker_interval` | 清理周期 |
+| `clean_before_minute` | 清理多久未使用的数据 |
+| `error_code` | 触发限流时返回码 |
+
+## sessions
+
+用于会话系统的 Redis 配置。
+
+相关代码在 `internal/sessions/actor.go`。
+
+### 结构示例
+
+```json
+{
+    "sessions": {
+        "redis_id": "redis-global"
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `redis_id` | 会话系统使用的 Redis 实例 ID |
+
+## gen-pool
+
+用于全局 ID 生成池配置。
+
+相关代码在 `internal/gen_pool/actor.go`。
+
+### 结构示例
+
+```json
+{
+    "gen-pool": {
+        "redis_id": "redis-global"
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `redis_id` | ID 池使用的 Redis 实例 ID |
+
+## battle_record
+
+用于战报记录存储配置。
+
+相关代码:
+
+- `nodes/record/mode_file.go`
+- `nodes/record/mode_cloud.go`
+
+### 结构示例
+
+```json
+{
+    "battle_record": {
+        "enable": true,
+        "mode": "file",
+        "file": {
+            "suffixKey": ".bin",
+            "succeedPathKey": "../battle_record/succeed",
+            "failedPathKey": "../battle_record/failed"
+        },
+        "cloud": {
+            "url": "",
+            "secretKey": ""
+        }
+    }
+}
+```
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `enable` | 是否启用 |
+| `mode` | 存储方式,`file` 或 `cloud` |
+
+#### `file`
+
+| 字段 | 说明 |
+| --- | --- |
+| `suffixKey` | 后缀名 |
+| `succeedPathKey` | 成功目录 |
+| `failedPathKey` | 失败目录 |
+
+#### `cloud`
+
+| 字段 | 说明 |
+| --- | --- |
+| `url` | 上传地址 |
+| `secretKey` | 上传鉴权 |
+
+## logger
+
+用于定义日志模板,节点通过 `ref_logger` 引用。
+
+### 结构示例
+
+```json
+{
+    "logger": {
+        "debug_file_log": {
+            "level": "debug",
+            "stack_level": "error",
+            "enable_write_file": true,
+            "enable_console": false,
+            "max_age": 7,
+            "time_format": "15:04:05.000",
+            "print_caller": true,
+            "rotation_time": 86400,
+            "file_link_path": "logs/%nodeid.log",
+            "file_path_format": "logs/%nodeid_%Y%m%d%H%M.log"
+        }
+    }
+}
+```
+
+### 当前常用日志模板
+
+从 `include/logger.json` 看,常见模板有:
+
+- `debug_console_log`
+- `debug_file_log`
+- `debug_log`
+- `info_console_log`
+- `info_file_log`
+- `info_log`
+
+### 字段说明
+
+| 字段 | 说明 |
+| --- | --- |
+| `level` | 日志级别 |
+| `stack_level` | 触发堆栈打印的级别 |
+| `enable_write_file` | 是否写文件 |
+| `enable_console` | 是否输出控制台 |
+| `max_age` | 保留天数 |
+| `time_format` | 时间格式 |
+| `print_caller` | 是否打印调用位置 |
+| `rotation_time` | 滚动周期,秒 |
+| `file_link_path` | 当前日志软链路径 |
+| `file_path_format` | 日志文件命名格式 |
+
+## 不同环境的典型差异
+
+### local.json
+
+- 本地 Docker 联调
+- Redis 地址是 `redis:6379`
+- Mongo 库名是 `local-f1-*`
+- 日志默认写文件
+
+### dev.json
+
+- 开发环境
+- Redis、Mongo、NATS 指向开发环境地址
+- `game` 节点通常使用数字 ID
+
+### `*_dev.json`
+
+- 通过 `include` 复用公共配置
+- 一般只覆盖少量差异,如 `env`、`cluster.nats.pool_size`
+
+### 平台环境文件
+
+例如 `su.json`、`lgy.json`、`azw.json`:
+
+- 通过不同 `env` 区分平台
+- 通过不同 `cluster.nats.prefix` 做集群隔离
+- 通过不同 `db_name` 做数据库隔离
+- `game` 节点编号可能固定,也可能允许多实例
+
+## 修改建议
+
+### 新增环境
+
+建议流程:
+
+1. 复制最接近的现有环境文件
+2. 修改 `env`
+3. 修改 `cluster.nats.prefix`
+4. 修改 Redis 与 Mongo 地址、密码、库名
+5. 修改节点 `node_id` 与端口
+6. 启动单节点验证
+
+### 修改已有环境
+
+优先检查四个高风险字段:
+
+1. `cluster.nats.prefix`
+2. `mongo.*.db_name`
+3. `node.*[].node_id`
+4. `node.*[].__settings__.redis_id_list` / `mongo_id_list`
+
+### 不建议直接改的内容
+
+- `master_node_id`
+- 节点类型名称
+- 已上线环境的 `db_name`
+- 已上线环境的 `game` 节点 ID 规则
+
+## 启动示例
+
+```bash
+run -path=./etc/profile/local.json -node=gate-1
+run -path=./etc/profile/dev.json -node=1
+run -path=./etc/profile/su.json -node=master-1
+run -path=./etc/profile/lgy.json -node=web-1
+```
+
+## 常见错误
+
+### 1. `-node` 与 `node_id` 不匹配
+
+例如 profile 里写的是 `node_id: "web-1"`,启动却用了 `-node=web`。
+
+### 2. 只改了 `redis`,没改 `redis_id_list`
+
+节点最终使用哪个 Redis,不是看你定义了多少个 `redis`,而是看节点 settings 引用了哪个 ID。
+
+### 3. `include` 引入了公共配置,但顶层又被错误覆盖
+
+这种问题最容易出现在 `*_dev.json`。改动前先确认最终覆盖顺序。
+
+### 4. NATS prefix 与其他环境重复
+
+节点会串环境,这是最危险的配置错误之一。

File diff suppressed because it is too large
+ 0 - 0
sr/docs/drawio/match.drawio


+ 0 - 3
sr/docs/git-flow/README.md

@@ -1,3 +0,0 @@
-# 安装vscode插件
-- Markdown Preview Enhanced
-- Draw.io Integration

+ 0 - 154
sr/docs/git-flow/git-flow.drawio

@@ -1,154 +0,0 @@
-<mxfile host="65bd71144e">
-    <diagram id="Nrt93d1KWjSaZXNd_6xh" name="Page-1">
-        <mxGraphModel dx="2426" dy="501" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
-            <root>
-                <mxCell id="0"/>
-                <mxCell id="1" parent="0"/>
-                <mxCell id="30" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-642" y="68" width="475" height="275" as="geometry"/>
-                </mxCell>
-                <mxCell id="28" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-65" y="82" width="223" height="98" as="geometry"/>
-                </mxCell>
-                <mxCell id="20" style="edgeStyle=none;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="17" target="18">
-                    <mxGeometry relative="1" as="geometry">
-                        <Array as="points">
-                            <mxPoint x="-458" y="140"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="24" style="edgeStyle=none;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="17" target="19">
-                    <mxGeometry relative="1" as="geometry">
-                        <Array as="points">
-                            <mxPoint x="-448" y="285"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="25" value="创建待发布分支" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="24">
-                    <mxGeometry x="-0.2002" relative="1" as="geometry">
-                        <mxPoint as="offset"/>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="17" value="dev&lt;div&gt;持续集成&lt;/div&gt;" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
-                    <mxGeometry x="-626" y="180" width="120" height="80" as="geometry"/>
-                </mxCell>
-                <mxCell id="18" value="feature/*&amp;nbsp; &lt;br&gt;新功能" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-351" y="122" width="139" height="40" as="geometry"/>
-                </mxCell>
-                <mxCell id="38" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="19" target="26">
-                    <mxGeometry relative="1" as="geometry">
-                        <Array as="points">
-                            <mxPoint x="-176" y="147"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="19" value="release/v X.X.X&amp;nbsp;&lt;br&gt;待发布/维护分支" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-353" y="278" width="141" height="40" as="geometry"/>
-                </mxCell>
-                <mxCell id="21" style="edgeStyle=none;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.967;entryY=0.388;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="18" target="17">
-                    <mxGeometry relative="1" as="geometry">
-                        <Array as="points">
-                            <mxPoint x="-414" y="202"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="23" value="PR合并" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="21">
-                    <mxGeometry x="0.1785" y="4" relative="1" as="geometry">
-                        <mxPoint as="offset"/>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="22" value="从dev切分支开发功能" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="-526" y="118" width="133" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="26" value="tag: vX.X.X" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-23" y="122" width="139" height="40" as="geometry"/>
-                </mxCell>
-                <mxCell id="29" value="&lt;b&gt;&lt;font color=&quot;#ff3333&quot;&gt;发布阶段&lt;/font&gt;&lt;/b&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=#FFFFFF;" vertex="1" parent="1">
-                    <mxGeometry x="11" y="82" width="66" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="31" value="&lt;b&gt;&lt;font color=&quot;#ff3333&quot;&gt;开发阶段&lt;/font&gt;&lt;/b&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=#FFFFFF;" vertex="1" parent="1">
-                    <mxGeometry x="-430" y="70" width="66" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="57" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="32" target="35">
-                    <mxGeometry relative="1" as="geometry"/>
-                </mxCell>
-                <mxCell id="32" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-67.5" y="252" width="223" height="98" as="geometry"/>
-                </mxCell>
-                <mxCell id="52" style="edgeStyle=none;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="33" target="19">
-                    <mxGeometry relative="1" as="geometry">
-                        <Array as="points">
-                            <mxPoint x="-72" y="365"/>
-                            <mxPoint x="-198" y="361"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="33" value="hotfix/*&lt;br&gt;接分支Bug修复" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="-25.5" y="292" width="139" height="40" as="geometry"/>
-                </mxCell>
-                <mxCell id="34" value="&lt;b&gt;&lt;font color=&quot;#ff3333&quot;&gt;测试阶段&lt;/font&gt;&lt;/b&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="8.5" y="252" width="66" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="35" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="297" y="159" width="223" height="98" as="geometry"/>
-                </mxCell>
-                <mxCell id="36" value="tag: vX.X.X" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
-                    <mxGeometry x="339" y="199" width="139" height="40" as="geometry"/>
-                </mxCell>
-                <mxCell id="37" value="&lt;b&gt;&lt;font color=&quot;#ff3333&quot;&gt;运维阶段&lt;/font&gt;&lt;/b&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="373" y="159" width="66" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="39" value="测试通过" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="-150" y="118" width="66" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="41" value="&lt;font color=&quot;#3333ff&quot;&gt;发现Bug&lt;/font&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="-159" y="223" width="63" height="26" as="geometry"/>
-                </mxCell>
-                <mxCell id="43" value="" style="endArrow=classic;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="19" target="33">
-                    <mxGeometry width="50" height="50" relative="1" as="geometry">
-                        <mxPoint x="-15" y="220" as="sourcePoint"/>
-                        <mxPoint x="35" y="170" as="targetPoint"/>
-                        <Array as="points">
-                            <mxPoint x="-152" y="245"/>
-                            <mxPoint x="-93" y="250"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="48" value="" style="endArrow=classic;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="33">
-                    <mxGeometry width="50" height="50" relative="1" as="geometry">
-                        <mxPoint x="-212" y="296" as="sourcePoint"/>
-                        <mxPoint x="-171" y="341" as="targetPoint"/>
-                        <Array as="points">
-                            <mxPoint x="-162" y="282"/>
-                            <mxPoint x="-94" y="285"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="51" value="&lt;font color=&quot;#3333ff&quot;&gt;线上Bug&lt;/font&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-                    <mxGeometry x="-167" y="257" width="60" height="30" as="geometry"/>
-                </mxCell>
-                <mxCell id="53" value="&lt;font color=&quot;#3333ff&quot;&gt;合并&lt;/font&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-                    <mxGeometry x="-156" y="330" width="60" height="30" as="geometry"/>
-                </mxCell>
-                <mxCell id="55" value="" style="endArrow=classic;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="33" target="17">
-                    <mxGeometry width="50" height="50" relative="1" as="geometry">
-                        <mxPoint x="93" y="396" as="sourcePoint"/>
-                        <mxPoint x="-552" y="411" as="targetPoint"/>
-                        <Array as="points">
-                            <mxPoint x="-39" y="381"/>
-                            <mxPoint x="-183" y="392"/>
-                            <mxPoint x="-420" y="363"/>
-                            <mxPoint x="-510" y="315"/>
-                        </Array>
-                    </mxGeometry>
-                </mxCell>
-                <mxCell id="56" value="&lt;font color=&quot;#3333ff&quot;&gt;合并&lt;/font&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
-                    <mxGeometry x="-302" y="350" width="60" height="30" as="geometry"/>
-                </mxCell>
-                <mxCell id="58" value="&lt;font color=&quot;#3333ff&quot;&gt;打新tag&lt;/font&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
-                    <mxGeometry x="188" y="223" width="59" height="26" as="geometry"/>
-                </mxCell>
-            </root>
-        </mxGraphModel>
-    </diagram>
-</mxfile>

+ 0 - 700
sr/docs/git-flow/git-flow.md

@@ -1,700 +0,0 @@
-# 游戏开发Git Flow方案
-
-**核心理念**:`dev` 持续集成,`release` 定期发布,`hotfix` 统一修复。所有修复由开发者主动合并到目标分支,减少分支类型。
-
----
-
-## 一、分支结构
-
-```
-dev(持续集成主干,保护分支)
-├── feature/skill-system(新功能开发1)
-├── feature/new-level(新功能开发1)
-├── release/v1.0.0(测试+发布分支,生命周期=发布周期)
-│   └── hotfix/crash-issue(从 release 切出的修复,合并回 release + dev)
-└── hotfix/v1.0.1-pay-bug(线上热修复,从 Tag 创建,合并回 dev + 新 Tag)
-└── tag:v1.0.1(线上运维的版本)
-```
-
-### 分支生命周期
-
-```mermaid
-graph LR
-    subgraph 开发阶段
-        dev(dev: 持续集成) --> feature[feature/*: 新功能]
-        feature --> |PR合并| dev
-        dev --> |创建| release[release/vX.X.X: 待发布/维护分支]
-    end
-
-    subgraph 测试阶段
-        release --> |发现Bug| hotfix[hotfix/*: Bug修复]
-        hotfix --> |合并| release
-        hotfix --> |合并| dev
-    end
-
-    subgraph 发布阶段
-        release --> |测试通过| tag[tag: vX.X.X]
-    end
-
-    subgraph 线上运维
-        release --> |线上Bug| hotfix
-        hotfix --> |打新Tag| tag2[Tag: vX.X.Y]
-    end
-
-    style dev fill:#f9f,stroke:#333,stroke-width:1px
-    style tag fill:#bbf,stroke:#333,stroke-width:1px
-    style tag2 fill:#bbf,stroke:#333,stroke-width:1px
-    style release fill:#bbf,stroke:#333,stroke-width:1px
-```
-
-## 二、完整工作流程
-
-### **阶段 1:日常开发**
-
-```bash
-# 1.1 同步最新主干
-git checkout dev
-git pull origin dev
-
-# 1.2 创建功能分支
-git checkout -b feature/player-combat
-
-# 1.3 开发并提交
-git add .
-git commit -m "feat: 实现三段连击系统
-- 添加跳跃状态机
-- 实现空中伤害判定
-- 关联任务:PROG-789"
-git push origin feature/player-combat
-
-# 1.4 提交 Pull Request 到 dev
-# Code Review 通过后合并
-
-# 1.5 合并后立即删除功能分支
-git checkout dev
-git pull origin dev
-git branch -d feature/player-combat
-git push origin --delete feature/player-combat
-```
-
-**原则**:`dev` 永不冻结,始终接收新功能,CI 自动构建供开发自测。
-
----
-
-### **阶段 2:发布准备**
-
-```bash
-# 2.1 发布负责人创建 release 分支
-git checkout dev
-git pull origin dev
-git checkout -b release/v1.0.0
-git push origin release/v1.0.0
-
-# 2.2 CI 自动触发测试包构建
-# GitLab/GitHub 检测到 release/v* 分支自动打包
-```
-
-**状态切换**:从这一刻起,`dev` 继续接收新功能,`release/v1.0.0` 只接收修复。
-
----
-
-### **阶段 3:测试与修复**
-
-```bash
-# 3.1 QA 在 release 上发现 Bug
-# 开发者从 release 切 hotfix 分支
-git checkout release/v1.0.0
-git checkout -b hotfix/crash-issue
-
-# 3.2 修复并提交
-git add .
-git commit -m "hotfix: 修复商城崩溃
-- 空数据保护
-- 发现阶段:QA测试
-- 影响版本:release/v1.0.0"
-git push origin hotfix/crash-issue
-
-# 3.3 提交 PR 到 release/v1.0.0
-# Reviewer:QA负责人 + 主程
-
-# 3.4 合并到 release(操作人:主程)
-git checkout release/v1.0.0
-git merge hotfix/crash-issue --no-ff
-git push origin release/v1.0.0
-
-# 3.5 主动合并回 dev(操作人:开发者自己)
-git checkout dev
-git pull origin dev
-git merge hotfix/crash-issue --no-ff
-git push origin dev
-
-# 3.6 删除 hotfix 分支
-git branch -d hotfix/crash-issue
-git push origin --delete hotfix/crash-issue
-```
-
-**关键点**:合并到 `dev` 是**开发者的责任**,不是自动的。如果冲突,需手动解决并保证代码兼容。
-
----
-
-### **阶段 4:正式发布**
-
-```bash
-# 4.1 QA 测试通过,批准发布
-git checkout release/v1.0.0
-git pull origin release/v1.0.0
-
-# 4.2 打正式版本 Tag(这就是线上版本的锚定点)
-git tag -a v1.0.0 -m "正式版本 v1.0.0 发布
-- 构建号:#12345
-- 发布日期:2024-12-08"
-git push origin v1.0.0
-
-# 4.3 删除 release 分支(保持整洁)
-git branch -d release/v1.0.0
-git push origin --delete release/v1.0.0
-```
-
-**原则**:发布后,`release/v1.0.0` 已完成使命,**Tag v1.0.0** 是唯一定位方式。
-
----
-
-### **阶段 5:线上热修复**
-
-```bash
-# 5.1 线上 v1.0.0 出现紧急 Bug
-# 必须从 Tag 创建 hotfix 分支
-git fetch origin tag v1.0.0
-git checkout -b hotfix/v1.0.1-pay-bug v1.0.0
-
-# 5.2 修复并提交
-git add .
-git commit -m "hotfix: 修复支付失败
-- 支付宝SDK版本回退
-- 发现阶段:线上监控
-- 紧急程度:P0"
-git push origin hotfix/v1.0.1-pay-bug
-
-# 5.3 打热修复版本 Tag
-git tag -a v1.0.1 -m "热修复版本 v1.0.1"
-git push origin v1.0.1
-
-# 5.4 合并回 dev(开发者的责任)
-git checkout dev
-git pull origin dev
-git merge hotfix/v1.0.1-pay-bug --no-ff
-git push origin dev
-
-# 5.5 删除 hotfix 分支
-git branch -d hotfix/v1.0.1-pay-bug
-git push origin --delete hotfix/v1.0.1-pay-bug
-```
-
-**注意**:如果 `dev` 已重构导致无法合并,需**手动移植**修复逻辑。
-
----
-
-## 三、提交信息规范
-
-```
-<type>: <简短描述(50字符内)>
-
-[正文]
-- 改动细节1
-- 改动细节2
-[发现阶段:QA测试/线上监控/开发自测]
-[影响范围:release/v1.0.0 / v1.0.0 / dev]
-[关联任务:TASK-123]
-```
-
-### 类型映射
-
-| 类型 | 说明 | 使用分支 |
-|------|------|----------|
-| `featture` | 新功能 | `feature/*` → `dev` |
-| `hotfix` | Bug修复/热修复 | `hotfix/*` → `release`/`dev`/Tag |
-| `refactor` | 重构 | `feature/*` → `dev` |
-| `art` | 美术资源 | `art/*` → `model1` |
-
-### 提交示例
-
-```bash
-# 功能开发
-feat: 新增联盟系统
-- 创建/加入/退出联盟
-- 联盟聊天功能
-- 关联任务:PROG-456
-
-# 测试阶段修复
-hotfix: 修复角色穿模
-- 调整碰撞盒大小
-- 发现阶段:QA测试
-- 影响版本:release/v1.0.0
-
-# 线上热修复
-hotfix: 修复支付回调失败
-- 回滚SDK到3.2.1
-- 发现阶段:线上监控
-- 紧急程度:P0
-- 影响版本:v1.0.0
-```
-
----
-
-## 四、自动化脚本
-
-### 1. 创建 release 分支
-
-```bash
-#!/bin/bash
-# scripts/create-release.sh
-
-if [ -z "$1" ]; then
-    echo "用法: ./create-release.sh v1.0.0"
-    exit 1
-fi
-
-VERSION=$1
-
-# 必须在 dev 分支
-current_branch=$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
-if [ "$current_branch" != "dev" ]; then
-    echo "❌ 必须在 dev 分支创建 release"
-    exit 1
-fi
-
-# 同步并创建
-git pull origin dev
-git checkout -b release/$VERSION
-git push origin release/$VERSION
-
-echo "✅ release/$VERSION 已创建"
-echo "请通知 QA 开始测试"
-```
-
----
-
-### 2. 创建 hotfix 分支(智能判断)
-
-```bash
-#!/bin/bash
-# scripts/create-hotfix.sh
-
-if [ -z "$1" ] || [ -z "$2" ]; then
-    echo "用法: ./create-hotfix.sh <版本> <问题描述>"
-    echo "  线上Bug: ./create-hotfix.sh v1.0.0 pay-crash"
-    echo "  测试Bug: ./create-hotfix.sh release/v1.0.0 ui-bug"
-    exit 1
-fi
-
-TARGET=$1
-NAME=$2
-
-# 判断是线上还是测试
-if [[ "$TARGET" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
-    # 从 Tag 创建(线上热修复)
-    git fetch origin tag $TARGET
-    git checkout -b hotfix/${TARGET}-${NAME} $TARGET
-    echo "✅ 线上热修复分支 hotfix/${TARGET}-${NAME} 已创建"
-else
-    # 从 release 创建(测试Bug修复)
-    git fetch origin $TARGET
-    git checkout -b hotfix/${TARGET#release/}-${NAME} $TARGET
-    echo "✅ 测试修复分支 hotfix/${TARGET#release/}-${NAME} 已创建"
-fi
-```
-
----
-
-### 3. 发布脚本
-
-```bash
-#!/bin/bash
-# scripts/publish.sh
-
-if [ -z "$1" ]; then
-    echo "用法: ./publish.sh release/v1.0.0"
-    exit 1
-fi
-
-RELEASE=$1
-VERSION=${RELEASE#release/}
-
-# 同步 release
-git checkout $RELEASE
-git pull origin $RELEASE
-
-# 打 Tag
-git tag -a $VERSION -m "正式发布 $VERSION"
-git push origin $VERSION
-
-# 删除 release 分支
-git branch -d $RELEASE
-git push origin --delete $RELEASE
-
-echo "🎉 发布完成!Tag: $VERSION"
-```
-
----
-
-## 五、GitLab CI/CD 配置
-
-```yaml
-# .gitlab-ci.yml
-stages:
-  - build
-  - test
-  - deploy
-
-variables:
-  UNITY_PATH: "/opt/Unity/Editor/Unity"
-
-# ==================== dev 快速构建 ====================
-build:dev:
-  stage: build
-  script:
-    - $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Dev/Game.exe
-  artifacts:
-    paths: [Build/Dev/]
-    expire_in: 2 days
-  only:
-    - dev
-  tags: [unity-builder]
-
-# ==================== release 测试包 ====================
-build:release:
-  stage: build
-  script:
-    - $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Release/Game.exe
-    - $UNITY_PATH -batchmode -projectPath . -buildAndroidPlayer Build/Release/Game.apk
-  artifacts:
-    paths: [Build/Release/]
-    expire_in: 1 week
-  only:
-    - /^release\/v.*$/
-  tags: [unity-builder]
-
-# ==================== hotfix 快速验证 ====================
-build:hotfix:
-  stage: build
-  script:
-    - $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Hotfix/Game.exe
-  artifacts:
-    paths: [Build/Hotfix/]
-    expire_in: 1 day
-  only:
-    - /^hotfix\/.*$/
-  tags: [unity-builder]
-
-# ==================== Tag 正式包 ====================
-build:production:
-  stage: build
-  script:
-    - echo "构建正式版本: $CI_COMMIT_TAG"
-    - $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Prod/Game_$CI_COMMIT_TAG.exe
-  artifacts:
-    paths: [Build/Prod/]
-    expire_in: 30 days
-  only:
-    - /^v\d+\.\d+\.\d+$/
-  tags: [unity-builder]
-
-# ==================== 部署到 Steam ====================
-deploy:steam:
-  stage: deploy
-  script:
-    - python scripts/upload_steam.py Build/Prod/Game_$CI_COMMIT_TAG.exe
-  only:
-    - /^v\d+\.\d+\.\d+$/
-  when: manual
-  tags: [deploy]
-```
-
----
-
-## 六、团队协作规范
-
-### 1. 分支操作权限矩阵
-
-| 操作 | 开发者 | QA | 主程 | 备注 |
-|------|--------|----|------|------|
-| 推送 `dev` | ❌ | ❌ | ❌ | 必须通过 PR |
-| 合并 PR 到 `dev` | ❌ | ❌ | ✅ | 需 1 名 reviewer |
-| 创建 `release/*` | ❌ | ❌ | ✅ | 由发布负责人操作 |
-| 推送 `hotfix/*` | ✅ | ❌ | ✅ | 开发者创建修复 |
-| 合并到 `release/*` | ❌ | ❌ | ✅ | 需 QA + 主程批准 |
-| 打版本 Tag | ❌ | ❌ | ✅ | 仅发布负责人 |
-| 删除远程分支 | ❌ | ❌ | ✅ | 每周清理 |
-
-### 2. Code Review 清单
-
-**feature → dev PR**:
-- [ ] 功能是否符合需求文档
-- [ ] 是否有单元测试
-- [ ] 性能影响评估(DrawCall、内存、GC)
-- [ ] 代码风格检查(SonarQube)
-
-**hotfix → release PR**:
-- [ ] QA 是否复现验证通过
-- [ ] 是否已同步 dev(截图证明无冲突)
-- [ ] 修复是否最小化(不引入新功能)
-
-**hotfix → dev PR**(线上热修复后):
-- [ ] 代码是否已适配 dev 最新架构
-- [ ] 是否影响未完成的功能
-
-### 3. 每日站会同步项
-
-```
-1. dev 分支状态:CI 是否通过 / 有多少待合并 PR
-2. release 状态:当前测试版本 /  blocking bug 数量
-3. hotfix 状态:是否在修复 / 预计合并时间
-4. 代码冻结通知:今天 18:00 冻结 dev,准备发布 v1.0.0
-```
-
----
-
-## 七、应急场景处理
-
-### 场景 1:hotfix 合并到 dev 时严重冲突
-
-```bash
-# 步骤 1:暂停合并,通知主程
-git checkout dev
-git merge hotfix/v1.0.1-crash
-
-# 步骤 2:主程评估冲突范围
-# 如果冲突文件 > 5 个或涉及核心模块:
-git merge --abort
-
-# 步骤 3:在 dev 上重新实现修复
-git checkout dev
-git checkout -b hotfix/v1.0.1-dev
-# 手动移植修复逻辑,适配新架构
-
-# 步骤 4:合并到 dev,关闭原 hotfix PR
-git checkout dev
-git merge hotfix/v1.0.1-dev --no-ff
-```
-
-### 场景 2:release 测试期间发现大量 Bug,发布延期
-
-```bash
-# 策略:release 分支继续保留,dev 继续开发
-# 但需要在 release 上合并 dev 的部分修复
-
-# 步骤 1:判断 dev 上的某个 commit 是否需要
-git checkout release/v1.0.0
-git cherry-pick <commit-hash>  # 只合并必要的修复
-
-# 步骤 2:通知团队,哪些 dev 的修复已合并到 release
-# 避免重复修复
-
-# 步骤 3:发布完成后,release 合并回 dev(一次性)
-git checkout dev
-git merge release/v1.0.0 --no-ff
-```
-
-### 场景 3:需要同时维护两个线上版本
-
-```bash
-# v1.0.0 国内版,v1.1.0 海外版,发现共用 Bug
-
-# 步骤 1:从 v1.0.0 切 hotfix
-git checkout -b hotfix/v1.0.1-bug v1.0.0
-# ...修复...
-
-# 步骤 2:从 v1.1.0 切 hotfix
-git checkout -b hotfix/v1.1.1-bug v1.1.0
-# cherry-pick 修复 commit
-git cherry-pick hotfix/v1.0.1-bug
-
-# 步骤 3:分别打 Tag 发布
-# v1.0.1 发国内渠道,v1.1.1 发海外渠道
-
-# 步骤 4:合并回 dev
-git checkout dev
-git merge hotfix/v1.1.1-bug --no-ff
-```
-
----
-
-## 八、配套工具配置
-
-### 1. Git 别名(~/.gitconfig)
-
-```ini
-[alias]
-    # 查看分支图
-    lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
-    
-    # 创建 hotfix(自动判断来源)
-    hf = "!f() { if [[ \"$1\" =~ ^v ]]; then git fetch origin tag $1 && git checkout -b hotfix/$2 $1; else git fetch origin $1 && git checkout -b hotfix/${1#release/}-$2 $1; fi; }; f"
-    
-    # 清理已合并分支
-    cleanup = "!git branch --merged | grep -vE '(^\\*|dev|release)' | xargs git branch -d"
-    
-    # 查看当前活跃分支
-    active = "!git branch -r | grep -E '(feature|hotfix)' | grep -v ' merged$'"
-
-[push]
-    default = simple
-    followTags = true
-```
-
-**使用示例**:
-```bash
-git hf release/v1.0.0 ui-bug      # 从 release 创建测试修复
-git hf v1.0.0 pay-crash           # 从 Tag 创建热修复
-git cleanup                       # 删除本地已合并分支
-git active                        # 查看团队活跃分支
-```
-
-### 2. Git Hook:禁止直接推送保护分支
-
-```bash
-# .git/hooks/pre-push(客户端)
-#!/bin/sh
-
-PROTECTED="dev release/"
-current=$(git symbolic-ref HEAD | sed 's!refs/heads/!!')
-
-if [[ "$current" =~ $PROTECTED ]]; then
-    echo "❌ 不能直接推送 $current 分支!"
-    echo "   请使用 Pull Request 流程"
-    exit 1
-fi
-```
-
-### 3. LFS 配置(.gitattributes)
-
-```
-# 代码文件(不使用 LFS)
-*.cs text diff=csharp
-*.cpp text diff=cpp
-*.h text diff=cpp
-*.lua text
-
-# 美术资源(使用 LFS)
-*.psd filter=lfs diff=lfs merge=lfs -text
-*.fbx filter=lfs diff=lfs merge=lfs -text
-*.png filter=lfs diff=lfs merge=lfs -text
-*.tga filter=lfs diff=lfs merge=lfs -text
-*.exr filter=lfs diff=lfs merge=lfs -text
-
-# 音频资源
-*.wav filter=lfs diff=lfs merge=lfs -text
-*.mp3 filter=lfs diff=lfs merge=lfs -text
-*.bank filter=lfs diff=lfs merge=lfs -text
-
-# 构建产物
-*.apk filter=lfs diff=lfs merge=lfs -text
-*.ipa filter=lfs diff=lfs merge=lfs -text
-*.dll filter=lfs diff=lfs merge=lfs -text
-```
-
----
-
-## 九、FAQ
-
-**Q1: 如何区分"测试修复"和"线上热修复"?**
-
-A: 通过提交信息和来源区分:
-- **测试修复**:`git log` 显示 `hotfix: xxx` 且父分支是 `release/*`
-- **线上热修复**:`git log` 显示 `hotfix: xxx` 且父分支是 Tag `vX.X.X`
-- 可使用 `git show --stat` 查看分支来源
-
-**Q2: 如果开发者忘记合并 hotfix 回 dev 怎么办?**
-
-A: 通过 CI 和每周检查防止:
-- CI 检测:`hotfix/*` 合并到 `release` 后,必须存在到 `dev` 的 PR
-- 每周例会:主程展示本周 hotfix 列表,确认都已同步
-
-**Q3: release 分支可以保留吗?**
-
-A: 可以,但有代价:
-- **保留理由**:渠道审核周期长,需保留构建环境
-- **保留方式**:发布后重命名为 `archive/v1.0.0`,并明确标注已发布
-- **推荐**:删除分支,所有信息通过 Tag 和提交记录追溯
-
----
-
-## 十、团队执行清单
-
-### 每日检查(自动化脚本)
-
-```bash
-#!/bin/bash
-# scripts/daily-check.sh
-
-echo "=== 每日分支健康检查 ==="
-
-# 1. dev 分支是否可构建
-curl -s "https://gitlab.example.com/api/v4/projects/123/pipelines?ref=dev" | 
-  grep -q "status.*success" && echo "✅ dev 构建正常" || echo "❌ dev 构建失败"
-
-# 2. release 分支数量
-release_count=$(git branch -r | grep -c "release/" || true)
-if [ $release_count -eq 0 ]; then
-    echo "✅ 无待发布版本"
-elif [ $release_count -eq 1 ]; then
-    echo "✅ 1 个待发布版本(正常)"
-else
-    echo "⚠️  $release_count 个待发布版本(需关注)"
-fi
-
-# 3. 未合并的 hotfix
-hotfix_count=$(git branch -r | grep "hotfix/" | wc -l)
-if [ $hotfix_count -gt 0 ]; then
-    echo "⚠️  有 $hotfix_count 个未删除的 hotfix 分支"
-    git branch -r | grep "hotfix/"
-fi
-
-# 4. 活跃 feature 分支
-echo "活跃功能分支:"
-git branch -r | grep "feature/" | head -5
-```
-
----
-
-### 发布日 Checklist
-
-- [ ] 确认 release/vX.X.X CI 构建成功
-- [ ] QA 签字确认测试通过(测试报告)
-- [ ] 主程确认所有 hotfix 已合并到 dev
-- [ ] 检查 release/vX.X.X 与 dev 的 diff(确认无遗漏修复)
-- [ ] 执行 `./scripts/publish.sh release/vX.X.X`
-- [ ] 在团队频道宣布:"vX.X.X 已发布,Tag 已创建"
-
----
-
-## 十一、流程图补充说明
-
-### 提交流向图
-
-```mermaid
-graph TD
-    subgraph "开发"
-        A[开发者] -->|创建| B(feature/*)
-        B -->|PR| C(dev)
-        C -->|CI| D[构建成功]
-    end
-
-    subgraph "发布"
-        D -->|定时| E[创建 release/vX.X.X]
-        E -->|QA测试| F{Bug?}
-        F -->|是| G[hotfix/*]
-        G -->|合并| E
-        G -->|合并| C
-        F -->|否| H[tag vX.X.X]
-    end
-
-    subgraph "运维"
-        H -->|线上Bug| I[hotfix/vX.X.Y]
-        I -->|合并| C
-        I -->|打tag| J[tag vX.X.Y]
-    end
-
-    style C fill:#f9f,stroke:#333,stroke-width:1px
-    style H fill:#bbf,stroke:#333,stroke-width:1px
-```

BIN
sr/docs/git-flow/git-flow.pdf


+ 0 - 0
sr/docs/git-flow/xy3-git.docx → sr/docs/git-flow/xy3-git-cn.docx


+ 744 - 0
sr/docs/git-flow/版本流程.md

@@ -0,0 +1,744 @@
+# 版本控制
+
+在游戏中,版本控制将按照以下规则进行格式化:
+
+## 命名规则 
+
+### UAT
+
+对游戏影响较大的**主要版本发布**。示例如下:
+
+#### Client
+
+更新无法通过热修复完成,必须经过 **Google Play Store / App Store
+审核流程** 的内容。
+
+#### Server
+
+更新涉及**不兼容的改动**,需要进行补丁或数据迁移。
+
+#### 其他
+
+-   大型新功能变更
+-   现有功能的完全重构
+-   架构级变更
+
+------------------------------------------------------------------------
+
+### Hotfix
+
+标准的**小版本更新**,仅包含较小的改动,例如:
+
+-   新的小功能
+-   对现有功能的修改
+-   Bug 修复
+-   每周维护更新
+
+------------------------------------------------------------------------
+
+### Urgent
+
+需要**尽快发布的紧急更新**,例如:
+
+-   修复游戏崩溃问题
+-   修复损坏的功能
+-   修复严重 Bug
+-   修复破坏游戏平衡的漏洞
+
+------------------------------------------------------------------------
+
+## 版本号格式 
+
+游戏版本号将根据游戏中的改动进行更新。
+版本号格式如下:
+
+    xx.yy.zz
+
+不同类型更新对版本号的影响如下:
+
+### UAT
+
+-   xx +1
+-   yy 和 zz 重置为 0
+
+示例:
+
+    2.5.2 → 3.0.0
+
+### Hotfix
+
+-   xx 不变
+-   yy +1
+-   zz 重置为 0
+
+示例:
+
+    2.5.2 → 2.6.0
+
+### Urgent
+
+-   xx 和 yy 不变
+-   zz +1
+
+示例:
+
+    2.5.2 → 2.5.3
+
+
+### 图示
+
+版本号升级规则:
+```mermaid
+flowchart LR
+  A["当前版本 xx.yy.zz"]
+
+  A -->|"UAT:xx + 1
+yy=0, zz=0"| B["新版本 (xx+1).0.0"]
+  A -->|"Hotfix:yy + 1
+zz=0"| C["新版本 xx.(yy+1).0"]
+  A -->|"Urgent:zz + 1"| D["新版本 xx.yy.(zz+1)"]
+```
+
+
+------------------------------------------------------------------------
+
+# Git 控制
+
+Git 访问需要严格规则,以确保项目稳定性。
+
+------------------------------------------------------------------------
+
+# 分支创建与规则
+
+在版本规划确认后,由**负责人(Project Manager)**创建一些标准分支。
+
+## Main / Master
+
+仓库中最重要的分支。
+
+该分支必须**完全对应当前对外发布的版本**。
+
+规则:
+
+-   只有负责人可以合并到该分支
+-   每个版本发布后进行合并
+-   **不允许直接提交 commit**
+-   只允许从以下分支合并:
+    -   Review
+    -   UAT
+    -   Hotfix
+    -   Urgent
+
+------------------------------------------------------------------------
+
+## Review
+
+用于存储**等待审核的最新主要版本**。
+
+目的:
+
+防止在应用仍处于审核状态时出现紧急问题。
+(如果审核期间合并到 master,将无法获取干净的公开版本)
+
+规则:
+
+-   只有负责人可以合并到此分支
+-   发布到 Play Store 和 App Store 后立即合并到 **Master**
+-   **不允许直接 commit**
+-   只允许从 **UAT 分支**合并
+
+如果审核失败:
+
+-   修改需要在对应的 **UAT 分支**完成
+-   再重新合并到 Review
+
+------------------------------------------------------------------------
+
+## UAT
+
+用于存储**即将发布的主要版本**。
+
+命名格式:
+
+    UAT/版本号
+    例如:UAT/2.0.0
+
+规则:
+
+-   不允许直接 commit
+-   所有修改必须通过 **Pull Request / Merge Request**
+-   必须获得负责人批准
+
+------------------------------------------------------------------------
+
+## Hotfix
+
+用于存储**即将发布的小版本更新**。
+
+命名格式:
+
+    Hotfix/版本号
+    例如:Hotfix/1.2.0
+
+规则:
+
+-   所有修改必须通过 **Pull Request / Merge Request**
+-   必须获得负责人批准
+
+------------------------------------------------------------------------
+
+## Urgent
+
+用于存储**紧急版本更新**。
+
+命名格式:
+
+    Urgent/版本号
+    例如:Urgent/1.1.2
+
+规则:
+
+-   所有修改必须通过 **Pull Request / Merge Request**
+-   必须获得负责人批准
+
+------------------------------------------------------------------------
+
+## Develop
+
+用于在功能本地开发完成后进行**集成测试**。
+
+规则:
+
+-   所有修改通过 **Pull Request / Merge Request**
+-   需要团队成员批准
+
+说明:
+
+由于该分支不是由负责人严格维护,如果仓库出现问题:
+
+负责人可以:
+
+-   从最新版本重新拉取
+    或
+-   手动修复
+
+------------------------------------------------------------------------
+
+## Local
+
+用于开发的**短生命周期分支**。
+
+命名方式:
+
+团队可自行决定,只要清晰易懂。
+
+规则:
+
+-   从对应的 **UAT / Hotfix / Urgent** 分支创建
+-   根据功能要进入的版本决定
+
+开发流程:
+
+-   所有 commit 在此分支完成
+-   功能完成后合并回对应版本分支
+-   需要定期从 UAT / Hotfix / Urgent 同步更新以避免冲突
+
+------------------------------------------------------------------------
+
+# 合并流程 
+
+每次发布新版本后,需要进行分支合并以避免改动被覆盖。
+
+一般规则:
+
+将改动合并到**所有更高版本的分支**
+
+例如:
+
+    1.1.2 < 1.2.0 < 2.0.0 < 3.0.0
+
+Master / Review / Develop 的规则略有不同。
+
+## Main / Master
+
+-   不会被合并到其他分支
+-   只接受其他分支的合并
+
+## Review
+
+当 Google Play Store 和 App Store 审核通过并正式发布后:
+
+    Review → Master
+
+## UAT
+
+测试通过后:
+
+如果不需要审核:
+
+    UAT → Master
+
+如果需要审核:
+
+    UAT → Review
+
+同时需要合并到**更高版本的 UAT 分支**
+
+示例:
+
+    UAT/2.0.0 → UAT/3.0.0
+
+## Hotfix
+
+测试通过后:
+
+    Hotfix → Master
+
+同时需要合并到:
+
+-   所有 **UAT 分支**
+-   所有更高版本 **Hotfix 分支**
+
+示例:
+
+    Hotfix/1.1.0 → Hotfix/1.2.0
+
+## Urgent
+
+测试通过后:
+
+    Urgent → Master
+
+同时需要合并到:
+
+-   所有 **UAT 分支**
+-   所有 **Hotfix 分支**
+-   所有更高版本 **Urgent 分支**
+
+示例:
+
+    Urgent/1.1.1 → Urgent/1.1.2
+
+## Develop
+
+-   不会合并到其他分支
+-   仅用于开发人员进行集成测试
+
+## Local
+
+短生命周期开发分支。
+
+流程:
+
+    Local → UAT / Hotfix / Urgent
+
+取决于该功能要进入哪个版本。
+
+维护建议:
+
+-   定期从对应版本分支同步更新
+-   避免冲突
+
+## 图示
+
+版本发布后的合并顺序
+
+```mermaid
+flowchart LR
+    A[Urgent/1.1.2] --> B[更高版本 Urgent 分支]
+    A --> C[所有 Hotfix 分支]
+    A --> D[所有 UAT 分支]
+    A --> E[Master]
+
+    F[Hotfix/1.2.0] --> G[更高版本 Hotfix 分支]
+    F --> H[所有 UAT 分支]
+    F --> I[Master]
+
+    J[UAT/2.0.0] --> K[更高版本 UAT 分支]
+    J --> L[Review(若需要审核)]
+    J --> M[Master(若无需审核)]
+```
+
+
+分支体系概览
+
+```mermaid
+flowchart TB
+  Master["Main / Master
+线上公开版本"]
+  Review["Review
+审核中的主要版本(可选)"]
+
+  subgraph ReleaseBranches["发布分支(按类型)"]
+    direction TB
+    UAT["UAT/x.y.z
+主要版本候选"]
+    Hotfix["Hotfix/x.y.z
+小版本候选"]
+    Urgent["Urgent/x.y.z
+紧急版本候选"]
+  end
+
+  Develop["Develop
+集成测试(可选)"]
+  Local["Local/*
+短生命周期开发分支"]
+
+  UAT -->|"拉出开发分支"| Local
+  Hotfix -->|"拉出开发分支"| Local
+  Urgent -->|"拉出开发分支"| Local
+
+  Local -->|"PR/MR 合并"| UAT
+  Local -->|"PR/MR 合并"| Hotfix
+  Local -->|"PR/MR 合并"| Urgent
+
+  Urgent -->|"同步版本"| Hotfix
+  Urgent -->|"同步版本"| UAT
+  Hotfix -->|"同步版本"| UAT
+  
+  UAT -->|"可选:同步/合并到"| Develop
+  Hotfix -->|"可选:同步/合并到"| Develop
+  Urgent -->|"可选:同步/合并到"| Develop
+
+  UAT -->|"无需审核:测试通过后合并"| Master
+  UAT -->|"需要审核:测试通过后合并"| Review
+  Review -->|"审核通过并发布后合并"| Master
+
+  Hotfix -->|"测试通过后合并"| Master
+  Urgent -->|"测试通过后合并"| Master
+```
+
+
+------------------------------------------------------------------------
+
+# 冲突解决
+
+当在合并过程中遇到冲突时:
+
+1.  通知相关人员:
+    -   冲突另一侧的作者
+    -   项目负责人
+2.  如果是小问题且有信心解决:
+    -   可以尝试自行解决
+    -   但仍需要通知相关人员
+3.  如果是复杂问题:
+    -   与另一侧作者协作解决
+    -   确保不会破坏任何一方的功能
+4.  如果无法找到解决方案:
+
+由 **负责人最终决定处理方式**
+
+### 图示
+
+冲突处理流程
+
+```mermaid
+flowchart TD
+    A[发生合并冲突] --> B[通知相关人员<br/>冲突另一侧作者 + 负责人]
+    B --> C{冲突是否简单<br/>且你有把握?}
+    C -->|是| D[自行解决冲突]
+    D --> E[通知相关人员:已解决方案与原因]
+    C -->|否| F[与另一侧作者协作解决]
+    F --> G{能否达成可行方案?}
+    G -->|是| E
+    G -->|否| H[由负责人最终决策解决方案]
+```
+
+
+------------------------------------------------------------------------
+
+# 潜在问题
+
+### 1. 本地开发环境版本不同步
+
+在使用 **Local 分支**进行开发时,开发者需要确保从各个仓库拉取的版本是**同步的**。
+
+例如:
+
+如果 **config 仓库**是在 **server 仓库之后一周才拉取**,则数据可能无法保持一致,从而导致一些**不可预期的错误**。
+
+为了确保本地测试不会出现问题:
+
+在进行测试之前,请确保**所有相关仓库都已经合并到最新版本**。
+
+---
+
+### 2. Git 无法自动解决的冲突
+
+对于 **Git 无法自动解决的冲突**,需要由**负责人**来处理冲突。
+
+如果在开发过程中遇到问题,可以将情况提出来讨论,以寻找**最合适的解决方案**。
+
+---
+
+# 不同仓库可能遇到的问题
+
+不同类型的仓库,遇到冲突的概率和类型可能不同。
+
+---
+
+## Art
+
+发生冲突的可能性**较低**。
+
+通常情况下不会遇到严重的合并问题。
+
+---
+
+## Config
+
+**问题 1 和问题 2 都比较容易出现。**
+
+需要注意:
+
+- **问题 1**:确保不同仓库之间的版本保持同步,以避免不必要的问题。
+    
+- **问题 2**:可以将一些在不同功能开发中**经常需要修改的公共配置文件**单独提取出来,并存放在**文件存储服务器**中统一管理。
+    
+
+当发生冲突时,负责人可以:
+
+- 从服务器拉取**最新版本的文件**
+    
+- 用该版本来解决冲突
+    
+
+这样可以确保**所有必要的修改仍然会保留在游戏中**,同时减少配置冲突带来的问题。
+
+如果这种方法在实际操作中存在困难,也可以再寻找其他方式来解决配置文件的冲突问题。
+
+---
+
+## Client
+
+**问题 1 和问题 2 都可能发生。**
+
+需要注意:
+
+- **问题 1**:确保仓库版本同步,避免不必要的问题
+    
+- **问题 2**:比较容易发生冲突的部分包括:
+    
+    - **Scenes**
+        
+    - **Effects**
+        
+
+这些问题可以通过**提前规划修改内容**来降低风险,避免多人同时修改相同内容。
+
+---
+
+## Server
+
+通常情况下:
+
+- **问题 1**(版本不同步)较容易发生,需要注意避免。
+    
+
+对于 **问题 2**:
+
+大多数情况下冲突可以通过以下方式解决:
+
+- Git 自动合并
+    
+- 或者在稍微复杂的情况下,由负责人进行少量干预即可解决。
+    
+
+---
+
+## Proto
+
+**问题 1 和问题 2 都比较容易出现。**
+
+需要注意:
+
+- **问题 1**:确保仓库版本同步,避免不必要的问题
+    
+- **问题 2**:大多数情况下冲突比较容易解决
+    
+
+但必须确保解决方式是正确的。
+
+例如:
+
+如果在 **Resource enum** 中:
+
+Silver = 3  
+Gold = 3
+
+那么相关开发人员需要**协商决定哪一个需要修改为 4**,以避免枚举值冲突。
+
+
+### 典型工作流程:从规划到发布
+
+#### 规划阶段
+
+1. 各负责人之间进行讨论
+    
+2. 规划项目时间线
+    
+3. 项目经理创建新的 **Milestone**
+    
+4. 项目经理将新的 **Ticket** 加入到该 Milestone 中
+    
+5. 项目经理尽可能详细地填写 Ticket 的描述内容
+    
+
+---
+
+#### 开发阶段
+
+1. 策划开始进行功能设计  
+    **更改 Ticket 状态为:Designer WIP**
+    
+2. 策划与开发人员和美术一起讨论该功能,以确认具体细节
+    
+3. 策划整理并最终确认设计文档,并发布设计文档  
+    **更改 Ticket 状态为:Designer Completed**
+    
+4. 美术根据设计文档开始制作相关资源  
+    **更改 Ticket 状态为:Artist WIP**
+    
+5. 美术完成该功能所需的所有美术资源  
+    **更改 Ticket 状态为:Artist Completed**
+    
+6. 开发人员根据设计文档和美术资源开始开发该功能  
+    **更改 Ticket 状态为:Dev WIP**
+    
+7. 开发人员完成该功能的全部开发,包括美术资源与配置  
+    **更改 Ticket 状态为:Dev Completed**
+    
+8. 策划确认该功能是否符合设计文档  
+    **更改 Ticket 状态为:Designer Verified**
+    
+9. 美术确认该功能是否符合提供的美术样例  
+    **更改 Ticket 状态为:Artist Verified**
+    
+10. 准备所有必要的 **Merge Request**,并等待所有相关仓库完成合并  
+    **更改 Ticket 状态为:Ready To Test**
+    
+11. QA 开始对该功能进行测试  
+    **更改 Ticket 状态为:Test In Progress**
+    
+12. QA 根据发现的问题创建新的 **Bug Ticket**  
+    **更改 Ticket 状态为:Test Failed**  
+    _(如果没有问题则跳过此步骤)_
+    
+13. QA 确认该功能已完全完成并符合要求  
+    **更改 Ticket 状态为:Test Completed**
+    
+14. 项目经理将改动部署到 **生产环境
+    **更改 Ticket 状态为:Deployed**
+
+
+### 图示
+
+功能生命周期概览
+
+```mermaid
+flowchart LR
+  A[规划阶段] --> B[设计阶段]
+  B --> C[制作阶段]
+  C --> D[集成阶段]
+  D --> E[测试阶段]
+  E --> F[发布阶段]
+
+  E -->|发现问题| C
+```
+
+
+按角色划分的详细工作流程
+
+```mermaid
+flowchart LR
+
+  subgraph PM[项目经理]
+    A[负责人讨论]
+    B[规划时间线]
+    C[创建 Milestone]
+    D[创建 Ticket 并填写描述]
+    Z[部署到生产环境 - 状态:Deployed]
+  end
+
+  subgraph Designer[策划]
+    E[开始功能设计 - 状态:Designer WIP]
+    F[与开发人员和美术讨论细节]
+    G[完成设计文档 - 状态:Designer Completed]
+    H[根据设计文档验证功能 - 状态:Designer Verified]
+  end
+
+  subgraph Artist[美术]
+    I[开始制作美术资源 - 状态:Artist WIP]
+    J[完成所有美术资源 - 状态:Artist Completed]
+    K[验证美术实现是否正确 - 状态:Artist Verified]
+  end
+
+  subgraph Developer[开发者]
+    L[开始功能开发 - 状态:Dev WIP]
+    M[完成包含美术与配置的功能 - 状态:Dev Completed]
+  end
+
+  subgraph QA[测试]
+    N[准备 Merge Requests - 状态:Ready To Test]
+    O[开始测试功能 - 状态:Test In Progress]
+    P{是否发现问题?}
+    Q[创建 Bug Ticket - 状态:Test Failed]
+    R[确认功能完成 - 状态:Test Completed]
+  end
+
+  A --> B
+  B --> C
+  C --> D
+  D --> E
+  E --> F
+  F --> G
+  G --> I
+  I --> J
+  J --> L
+  L --> M
+  M --> H
+  H --> K
+  K --> N
+  N --> O
+  O --> P
+  P -->|是| Q
+  Q --> L
+  P -->|否| R
+  R --> Z
+```
+
+典型工作流:从 Local 到发布
+
+```mermaid
+sequenceDiagram
+  participant Dev as 开发者(Dev)
+  participant Local as Local/*
+  participant Rel as UAT/Hotfix/Urgent
+  participant Review as Review(可选)
+  participant Master as Master
+
+  alt 开发
+    Dev->>Local: 开发 & 提交 commits(只在 Local)
+    Local->>Rel: 发起 PR/MR(Local -> 目标版本分支)
+    Rel-->>Dev: Code Review / 修改建议
+    Dev->>Local: 提交修复 commits(只在 Local)
+    Local->>Rel: 更新 PR/MR(Local -> 目标版本分支)
+  end
+
+  alt 测试
+    Rel-->>Rel: 测试
+    Rel-->>Dev: 反馈问题(测试未通过)
+    Dev->>Local: 回到 Local 修复并继续提交
+    Local->>Rel: 推送更新(更新同一个 PR/MR)
+    Rel->>Rel: 重新测试
+  end
+
+  alt 发布
+    Rel->>Review: 合并(UAT -> Review)
+    Review->>Master: 审核通过并发布后合并(Review -> Master)
+  else 不需要审核(或 Hotfix/Urgent)
+    Rel->>Master: 测试通过后合并(目标分支 -> Master)
+  end
+```
+
+

+ 0 - 3
sr/etc/cli/cli.sh

@@ -87,9 +87,6 @@ function do_run_all() {
     #echo "run cross node ..."
     #./node run -path=./etc/profile/$p2.json -node=cross-1 &
 
-    echo "run pay node ..."
-    ./node run -path=./etc/profile/$p2.json -node=pay-1 &
-
     echo "run game node ..."
     ./node run -path=./etc/profile/$p2.json -node=10001 &
 

+ 0 - 1
sr/etc/data/area.json

@@ -6,7 +6,6 @@
     {"Pid":2188005,"AreaID":5,"AreaName":"LCS测试服","Gate":"192.168.1.38:30001"},
     {"Pid":2188006,"AreaID":6,"AreaName":"AZW测试服","Gate":"192.168.1.41:30001"},
     {"Pid":2188007,"AreaID":7,"AreaName":"yanjian测试服","Gate":"192.168.1.48:30001"},
-    {"Pid":2188008,"AreaID":8,"AreaName":"hw测试服","Gate":"192.168.1.29:30001"},
     {"Pid":2188099,"AreaID":99,"AreaName":"local区","Gate":"127.0.0.1:30001"},
     {"Pid":2188100,"AreaID":100,"AreaName":"[CBT]1区","Gate":"47.238.143.20:30001"}
 ]

+ 0 - 1
sr/etc/data/area_server.json

@@ -10,7 +10,6 @@
     {"AreaID":5,"ServerID":5,"ServerName":"lcs","Status":1,"MergedServerID":0},
     {"AreaID":6,"ServerID":6,"ServerName":"azw","Status":1,"MergedServerID":0},
     {"AreaID":7,"ServerID":7,"ServerName":"yanjian","Status":1,"MergedServerID":0},
-    {"AreaID":8,"ServerID":8,"ServerName":"hw","Status":1,"MergedServerID":0},
     {"AreaID":99,"ServerID":1,"ServerName":"local","Status":1,"MergedServerID":0},
     {"AreaID":100,"ServerID":1,"ServerName":"1服","Status":1,"MergedServerID":0}
 ]

+ 18 - 18
sr/etc/data/arm_type.json

@@ -1,20 +1,20 @@
 [
-    {"ID":101,"Level":0,"Job":1,"Skills":[40101],"FightLevel":10,"Attack":76,"Def":80,"Hp":60,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":102,"Level":1,"Job":1,"Skills":[40101],"FightLevel":10,"Attack":228,"Def":240,"Hp":180,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":103,"Level":2,"Job":1,"Skills":[40101],"FightLevel":20,"Attack":456,"Def":480,"Hp":360,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":104,"Level":3,"Job":1,"Skills":[40101],"FightLevel":30,"Attack":836,"Def":880,"Hp":660,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":105,"Level":4,"Job":1,"Skills":[40101],"FightLevel":40,"Attack":1140,"Def":1200,"Hp":900,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":106,"Level":5,"Job":1,"Skills":[40101],"FightLevel":50,"Attack":1520,"Def":1600,"Hp":1200,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":201,"Level":0,"Job":2,"Skills":[40201],"FightLevel":10,"Attack":112,"Def":72,"Hp":56,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":202,"Level":1,"Job":2,"Skills":[40201],"FightLevel":10,"Attack":336,"Def":216,"Hp":168,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":203,"Level":2,"Job":2,"Skills":[40201],"FightLevel":20,"Attack":672,"Def":432,"Hp":336,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":204,"Level":3,"Job":2,"Skills":[40201],"FightLevel":30,"Attack":1232,"Def":792,"Hp":616,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":205,"Level":4,"Job":2,"Skills":[40201],"FightLevel":40,"Attack":1680,"Def":1080,"Hp":840,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":206,"Level":5,"Job":2,"Skills":[40201],"FightLevel":50,"Attack":2240,"Def":1440,"Hp":1120,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
-    {"ID":301,"Level":0,"Job":3,"Skills":[40301],"FightLevel":10,"Attack":88,"Def":56,"Hp":52,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":302,"Level":1,"Job":3,"Skills":[40301],"FightLevel":10,"Attack":264,"Def":168,"Hp":156,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":303,"Level":2,"Job":3,"Skills":[40301],"FightLevel":20,"Attack":528,"Def":336,"Hp":312,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":304,"Level":3,"Job":3,"Skills":[40301],"FightLevel":30,"Attack":968,"Def":616,"Hp":572,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":305,"Level":4,"Job":3,"Skills":[40301],"FightLevel":40,"Attack":1320,"Def":840,"Hp":780,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
-    {"ID":306,"Level":5,"Job":3,"Skills":[40301],"FightLevel":50,"Attack":1760,"Def":1120,"Hp":1040,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000}
+    {"ID":101,"Level":0,"Job":1,"Skills":[40101],"FightLevel":10,"Attack":72,"Def":100,"Hp":60,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":102,"Level":1,"Job":1,"Skills":[40101],"FightLevel":10,"Attack":216,"Def":300,"Hp":180,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":103,"Level":2,"Job":1,"Skills":[40101],"FightLevel":20,"Attack":432,"Def":600,"Hp":360,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":104,"Level":3,"Job":1,"Skills":[40101],"FightLevel":30,"Attack":792,"Def":1100,"Hp":660,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":105,"Level":4,"Job":1,"Skills":[40101],"FightLevel":40,"Attack":1080,"Def":1500,"Hp":900,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":106,"Level":5,"Job":1,"Skills":[40101],"FightLevel":50,"Attack":1440,"Def":2000,"Hp":1200,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":201,"Level":0,"Job":2,"Skills":[40201],"FightLevel":10,"Attack":112,"Def":90,"Hp":58,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":202,"Level":1,"Job":2,"Skills":[40201],"FightLevel":10,"Attack":336,"Def":270,"Hp":173,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":203,"Level":2,"Job":2,"Skills":[40201],"FightLevel":20,"Attack":672,"Def":540,"Hp":346,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":204,"Level":3,"Job":2,"Skills":[40201],"FightLevel":30,"Attack":1232,"Def":990,"Hp":634,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":205,"Level":4,"Job":2,"Skills":[40201],"FightLevel":40,"Attack":1680,"Def":1350,"Hp":864,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":206,"Level":5,"Job":2,"Skills":[40201],"FightLevel":50,"Attack":2240,"Def":1800,"Hp":1152,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":2000},
+    {"ID":301,"Level":0,"Job":3,"Skills":[40301],"FightLevel":10,"Attack":88,"Def":80,"Hp":54,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":302,"Level":1,"Job":3,"Skills":[40301],"FightLevel":10,"Attack":264,"Def":240,"Hp":162,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":303,"Level":2,"Job":3,"Skills":[40301],"FightLevel":20,"Attack":528,"Def":480,"Hp":324,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":304,"Level":3,"Job":3,"Skills":[40301],"FightLevel":30,"Attack":968,"Def":880,"Hp":594,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":305,"Level":4,"Job":3,"Skills":[40301],"FightLevel":40,"Attack":1320,"Def":1200,"Hp":810,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000},
+    {"ID":306,"Level":5,"Job":3,"Skills":[40301],"FightLevel":50,"Attack":1760,"Def":1600,"Hp":1080,"AttackSpeed":10000,"MoveSpeed":600,"Weight":10,"AggValue":1000}
 ]

+ 135 - 135
sr/etc/data/equip_attr_extra.json

@@ -1,137 +1,137 @@
 [
-    {"PoolID":1,"No":1,"Key":10031,"MinValue":48,"MaxValue":72,"Weight":1250},
-    {"PoolID":1,"No":2,"Key":10041,"MinValue":48,"MaxValue":72,"Weight":1250},
-    {"PoolID":1,"No":3,"Key":10021,"MinValue":103,"MaxValue":154,"Weight":2500},
-    {"PoolID":1,"No":4,"Key":10061,"MinValue":54,"MaxValue":80,"Weight":1250},
-    {"PoolID":1,"No":5,"Key":10071,"MinValue":54,"MaxValue":80,"Weight":1250},
-    {"PoolID":1,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":1,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":1,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":1,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":2,"No":1,"Key":10031,"MinValue":51,"MaxValue":77,"Weight":1250},
-    {"PoolID":2,"No":2,"Key":10041,"MinValue":51,"MaxValue":77,"Weight":1250},
-    {"PoolID":2,"No":3,"Key":10021,"MinValue":99,"MaxValue":148,"Weight":2500},
-    {"PoolID":2,"No":4,"Key":10061,"MinValue":48,"MaxValue":72,"Weight":1250},
-    {"PoolID":2,"No":5,"Key":10071,"MinValue":48,"MaxValue":72,"Weight":1250},
-    {"PoolID":2,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":2,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":2,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":2,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":3,"No":1,"Key":10031,"MinValue":54,"MaxValue":82,"Weight":1250},
-    {"PoolID":3,"No":2,"Key":10041,"MinValue":54,"MaxValue":82,"Weight":1250},
-    {"PoolID":3,"No":3,"Key":10021,"MinValue":93,"MaxValue":139,"Weight":2500},
-    {"PoolID":3,"No":4,"Key":10061,"MinValue":41,"MaxValue":62,"Weight":1250},
-    {"PoolID":3,"No":5,"Key":10071,"MinValue":41,"MaxValue":62,"Weight":1250},
-    {"PoolID":3,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":3,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":625},
-    {"PoolID":3,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":3,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":4,"No":1,"Key":10031,"MinValue":95,"MaxValue":143,"Weight":1250},
-    {"PoolID":4,"No":2,"Key":10041,"MinValue":95,"MaxValue":143,"Weight":1250},
-    {"PoolID":4,"No":3,"Key":10021,"MinValue":205,"MaxValue":308,"Weight":2500},
-    {"PoolID":4,"No":4,"Key":10061,"MinValue":107,"MaxValue":160,"Weight":1250},
-    {"PoolID":4,"No":5,"Key":10071,"MinValue":107,"MaxValue":160,"Weight":1250},
-    {"PoolID":4,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":4,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":4,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":4,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":5,"No":1,"Key":10031,"MinValue":102,"MaxValue":153,"Weight":1250},
-    {"PoolID":5,"No":2,"Key":10041,"MinValue":102,"MaxValue":153,"Weight":1250},
-    {"PoolID":5,"No":3,"Key":10021,"MinValue":197,"MaxValue":296,"Weight":2500},
-    {"PoolID":5,"No":4,"Key":10061,"MinValue":95,"MaxValue":143,"Weight":1250},
-    {"PoolID":5,"No":5,"Key":10071,"MinValue":95,"MaxValue":143,"Weight":1250},
-    {"PoolID":5,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":5,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":5,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":5,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":6,"No":1,"Key":10031,"MinValue":108,"MaxValue":163,"Weight":1250},
-    {"PoolID":6,"No":2,"Key":10041,"MinValue":108,"MaxValue":163,"Weight":1250},
-    {"PoolID":6,"No":3,"Key":10021,"MinValue":185,"MaxValue":277,"Weight":2500},
-    {"PoolID":6,"No":4,"Key":10061,"MinValue":82,"MaxValue":123,"Weight":1250},
-    {"PoolID":6,"No":5,"Key":10071,"MinValue":82,"MaxValue":123,"Weight":1250},
-    {"PoolID":6,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":6,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":6,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":6,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":7,"No":1,"Key":10031,"MinValue":190,"MaxValue":284,"Weight":1250},
-    {"PoolID":7,"No":2,"Key":10041,"MinValue":190,"MaxValue":284,"Weight":1250},
-    {"PoolID":7,"No":3,"Key":10021,"MinValue":409,"MaxValue":613,"Weight":2500},
-    {"PoolID":7,"No":4,"Key":10061,"MinValue":212,"MaxValue":319,"Weight":1250},
-    {"PoolID":7,"No":5,"Key":10071,"MinValue":212,"MaxValue":319,"Weight":1250},
-    {"PoolID":7,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":7,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":7,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":7,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":8,"No":1,"Key":10031,"MinValue":203,"MaxValue":304,"Weight":1250},
-    {"PoolID":8,"No":2,"Key":10041,"MinValue":203,"MaxValue":304,"Weight":1250},
-    {"PoolID":8,"No":3,"Key":10021,"MinValue":392,"MaxValue":588,"Weight":2500},
-    {"PoolID":8,"No":4,"Key":10061,"MinValue":190,"MaxValue":284,"Weight":1250},
-    {"PoolID":8,"No":5,"Key":10071,"MinValue":190,"MaxValue":284,"Weight":1250},
-    {"PoolID":8,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":8,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":8,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":8,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":9,"No":1,"Key":10031,"MinValue":216,"MaxValue":324,"Weight":1250},
-    {"PoolID":9,"No":2,"Key":10041,"MinValue":216,"MaxValue":324,"Weight":1250},
-    {"PoolID":9,"No":3,"Key":10021,"MinValue":368,"MaxValue":552,"Weight":2500},
-    {"PoolID":9,"No":4,"Key":10061,"MinValue":163,"MaxValue":245,"Weight":1250},
-    {"PoolID":9,"No":5,"Key":10071,"MinValue":163,"MaxValue":245,"Weight":1250},
-    {"PoolID":9,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":9,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":9,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":9,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":10,"No":1,"Key":10031,"MinValue":354,"MaxValue":530,"Weight":1250},
-    {"PoolID":10,"No":2,"Key":10041,"MinValue":354,"MaxValue":530,"Weight":1250},
-    {"PoolID":10,"No":3,"Key":10021,"MinValue":762,"MaxValue":1143,"Weight":2500},
-    {"PoolID":10,"No":4,"Key":10061,"MinValue":396,"MaxValue":594,"Weight":1250},
-    {"PoolID":10,"No":5,"Key":10071,"MinValue":396,"MaxValue":594,"Weight":1250},
-    {"PoolID":10,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":10,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":10,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":10,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":11,"No":1,"Key":10031,"MinValue":378,"MaxValue":567,"Weight":1250},
-    {"PoolID":11,"No":2,"Key":10041,"MinValue":378,"MaxValue":567,"Weight":1250},
-    {"PoolID":11,"No":3,"Key":10021,"MinValue":732,"MaxValue":1097,"Weight":2500},
-    {"PoolID":11,"No":4,"Key":10061,"MinValue":354,"MaxValue":530,"Weight":1250},
-    {"PoolID":11,"No":5,"Key":10071,"MinValue":354,"MaxValue":530,"Weight":1250},
-    {"PoolID":11,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":11,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":11,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":11,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":12,"No":1,"Key":10031,"MinValue":402,"MaxValue":604,"Weight":1250},
-    {"PoolID":12,"No":2,"Key":10041,"MinValue":402,"MaxValue":604,"Weight":1250},
-    {"PoolID":12,"No":3,"Key":10021,"MinValue":686,"MaxValue":1029,"Weight":2500},
-    {"PoolID":12,"No":4,"Key":10061,"MinValue":305,"MaxValue":457,"Weight":1250},
-    {"PoolID":12,"No":5,"Key":10071,"MinValue":305,"MaxValue":457,"Weight":1250},
-    {"PoolID":12,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":12,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":12,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":12,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":13,"No":1,"Key":10031,"MinValue":580,"MaxValue":870,"Weight":1250},
-    {"PoolID":13,"No":2,"Key":10041,"MinValue":580,"MaxValue":870,"Weight":1250},
-    {"PoolID":13,"No":3,"Key":10021,"MinValue":1250,"MaxValue":1875,"Weight":2500},
-    {"PoolID":13,"No":4,"Key":10061,"MinValue":650,"MaxValue":975,"Weight":1250},
-    {"PoolID":13,"No":5,"Key":10071,"MinValue":650,"MaxValue":975,"Weight":1250},
-    {"PoolID":13,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":13,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":13,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":13,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":14,"No":1,"Key":10031,"MinValue":620,"MaxValue":930,"Weight":1250},
-    {"PoolID":14,"No":2,"Key":10041,"MinValue":620,"MaxValue":930,"Weight":1250},
-    {"PoolID":14,"No":3,"Key":10021,"MinValue":1200,"MaxValue":1800,"Weight":2500},
-    {"PoolID":14,"No":4,"Key":10061,"MinValue":580,"MaxValue":870,"Weight":1250},
-    {"PoolID":14,"No":5,"Key":10071,"MinValue":580,"MaxValue":870,"Weight":1250},
-    {"PoolID":14,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":14,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":14,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":14,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":15,"No":1,"Key":10031,"MinValue":660,"MaxValue":990,"Weight":1250},
-    {"PoolID":15,"No":2,"Key":10041,"MinValue":660,"MaxValue":990,"Weight":1250},
-    {"PoolID":15,"No":3,"Key":10021,"MinValue":1125,"MaxValue":1688,"Weight":2500},
-    {"PoolID":15,"No":4,"Key":10061,"MinValue":500,"MaxValue":750,"Weight":1250},
-    {"PoolID":15,"No":5,"Key":10071,"MinValue":500,"MaxValue":750,"Weight":1250},
-    {"PoolID":15,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":15,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":625},
-    {"PoolID":15,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":625},
-    {"PoolID":15,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":625}
+    {"PoolID":1,"No":1,"Key":10031,"MinValue":19,"MaxValue":27,"Weight":1500},
+    {"PoolID":1,"No":2,"Key":10041,"MinValue":27,"MaxValue":41,"Weight":1500},
+    {"PoolID":1,"No":3,"Key":10021,"MinValue":103,"MaxValue":154,"Weight":2000},
+    {"PoolID":1,"No":4,"Key":10061,"MinValue":22,"MaxValue":32,"Weight":1500},
+    {"PoolID":1,"No":5,"Key":10071,"MinValue":32,"MaxValue":49,"Weight":1500},
+    {"PoolID":1,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":1,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":1,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":1,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":2,"No":1,"Key":10031,"MinValue":21,"MaxValue":30,"Weight":1500},
+    {"PoolID":2,"No":2,"Key":10041,"MinValue":31,"MaxValue":46,"Weight":1500},
+    {"PoolID":2,"No":3,"Key":10021,"MinValue":99,"MaxValue":148,"Weight":2000},
+    {"PoolID":2,"No":4,"Key":10061,"MinValue":20,"MaxValue":28,"Weight":1500},
+    {"PoolID":2,"No":5,"Key":10071,"MinValue":29,"MaxValue":43,"Weight":1500},
+    {"PoolID":2,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":2,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":2,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":2,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":3,"No":1,"Key":10031,"MinValue":22,"MaxValue":32,"Weight":1500},
+    {"PoolID":3,"No":2,"Key":10041,"MinValue":33,"MaxValue":49,"Weight":1500},
+    {"PoolID":3,"No":3,"Key":10021,"MinValue":93,"MaxValue":139,"Weight":2000},
+    {"PoolID":3,"No":4,"Key":10061,"MinValue":17,"MaxValue":24,"Weight":1500},
+    {"PoolID":3,"No":5,"Key":10071,"MinValue":25,"MaxValue":37,"Weight":1500},
+    {"PoolID":3,"No":6,"Key":10081,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":3,"No":7,"Key":10091,"MinValue":250,"MaxValue":375,"Weight":500},
+    {"PoolID":3,"No":8,"Key":10101,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":3,"No":9,"Key":10111,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":4,"No":1,"Key":10031,"MinValue":37,"MaxValue":53,"Weight":1500},
+    {"PoolID":4,"No":2,"Key":10041,"MinValue":54,"MaxValue":82,"Weight":1500},
+    {"PoolID":4,"No":3,"Key":10021,"MinValue":205,"MaxValue":308,"Weight":2000},
+    {"PoolID":4,"No":4,"Key":10061,"MinValue":43,"MaxValue":63,"Weight":1500},
+    {"PoolID":4,"No":5,"Key":10071,"MinValue":64,"MaxValue":97,"Weight":1500},
+    {"PoolID":4,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":4,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":4,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":4,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":5,"No":1,"Key":10031,"MinValue":41,"MaxValue":60,"Weight":1500},
+    {"PoolID":5,"No":2,"Key":10041,"MinValue":61,"MaxValue":92,"Weight":1500},
+    {"PoolID":5,"No":3,"Key":10021,"MinValue":197,"MaxValue":296,"Weight":2000},
+    {"PoolID":5,"No":4,"Key":10061,"MinValue":39,"MaxValue":56,"Weight":1500},
+    {"PoolID":5,"No":5,"Key":10071,"MinValue":57,"MaxValue":86,"Weight":1500},
+    {"PoolID":5,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":5,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":5,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":5,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":6,"No":1,"Key":10031,"MinValue":44,"MaxValue":63,"Weight":1500},
+    {"PoolID":6,"No":2,"Key":10041,"MinValue":65,"MaxValue":98,"Weight":1500},
+    {"PoolID":6,"No":3,"Key":10021,"MinValue":185,"MaxValue":277,"Weight":2000},
+    {"PoolID":6,"No":4,"Key":10061,"MinValue":33,"MaxValue":48,"Weight":1500},
+    {"PoolID":6,"No":5,"Key":10071,"MinValue":49,"MaxValue":74,"Weight":1500},
+    {"PoolID":6,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":6,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":6,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":6,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":7,"No":1,"Key":10031,"MinValue":81,"MaxValue":116,"Weight":1500},
+    {"PoolID":7,"No":2,"Key":10041,"MinValue":121,"MaxValue":182,"Weight":1500},
+    {"PoolID":7,"No":3,"Key":10021,"MinValue":454,"MaxValue":681,"Weight":2000},
+    {"PoolID":7,"No":4,"Key":10061,"MinValue":95,"MaxValue":137,"Weight":1500},
+    {"PoolID":7,"No":5,"Key":10071,"MinValue":143,"MaxValue":215,"Weight":1500},
+    {"PoolID":7,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":7,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":7,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":7,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":8,"No":1,"Key":10031,"MinValue":91,"MaxValue":131,"Weight":1500},
+    {"PoolID":8,"No":2,"Key":10041,"MinValue":137,"MaxValue":205,"Weight":1500},
+    {"PoolID":8,"No":3,"Key":10021,"MinValue":436,"MaxValue":654,"Weight":2000},
+    {"PoolID":8,"No":4,"Key":10061,"MinValue":85,"MaxValue":122,"Weight":1500},
+    {"PoolID":8,"No":5,"Key":10071,"MinValue":128,"MaxValue":192,"Weight":1500},
+    {"PoolID":8,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":8,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":8,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":8,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":9,"No":1,"Key":10031,"MinValue":97,"MaxValue":139,"Weight":1500},
+    {"PoolID":9,"No":2,"Key":10041,"MinValue":145,"MaxValue":218,"Weight":1500},
+    {"PoolID":9,"No":3,"Key":10021,"MinValue":409,"MaxValue":613,"Weight":2000},
+    {"PoolID":9,"No":4,"Key":10061,"MinValue":73,"MaxValue":105,"Weight":1500},
+    {"PoolID":9,"No":5,"Key":10071,"MinValue":110,"MaxValue":165,"Weight":1500},
+    {"PoolID":9,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":9,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":9,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":9,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":10,"No":1,"Key":10031,"MinValue":142,"MaxValue":204,"Weight":1500},
+    {"PoolID":10,"No":2,"Key":10041,"MinValue":215,"MaxValue":322,"Weight":1500},
+    {"PoolID":10,"No":3,"Key":10021,"MinValue":802,"MaxValue":1203,"Weight":2000},
+    {"PoolID":10,"No":4,"Key":10061,"MinValue":168,"MaxValue":241,"Weight":1500},
+    {"PoolID":10,"No":5,"Key":10071,"MinValue":254,"MaxValue":380,"Weight":1500},
+    {"PoolID":10,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":10,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":10,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":10,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":11,"No":1,"Key":10031,"MinValue":160,"MaxValue":230,"Weight":1500},
+    {"PoolID":11,"No":2,"Key":10041,"MinValue":242,"MaxValue":363,"Weight":1500},
+    {"PoolID":11,"No":3,"Key":10021,"MinValue":770,"MaxValue":1155,"Weight":2000},
+    {"PoolID":11,"No":4,"Key":10061,"MinValue":150,"MaxValue":215,"Weight":1500},
+    {"PoolID":11,"No":5,"Key":10071,"MinValue":226,"MaxValue":339,"Weight":1500},
+    {"PoolID":11,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":11,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":11,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":11,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":12,"No":1,"Key":10031,"MinValue":170,"MaxValue":245,"Weight":1500},
+    {"PoolID":12,"No":2,"Key":10041,"MinValue":257,"MaxValue":386,"Weight":1500},
+    {"PoolID":12,"No":3,"Key":10021,"MinValue":722,"MaxValue":1083,"Weight":2000},
+    {"PoolID":12,"No":4,"Key":10061,"MinValue":129,"MaxValue":186,"Weight":1500},
+    {"PoolID":12,"No":5,"Key":10071,"MinValue":195,"MaxValue":293,"Weight":1500},
+    {"PoolID":12,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":12,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":12,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":12,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":13,"No":1,"Key":10031,"MinValue":221,"MaxValue":318,"Weight":1500},
+    {"PoolID":13,"No":2,"Key":10041,"MinValue":335,"MaxValue":502,"Weight":1500},
+    {"PoolID":13,"No":3,"Key":10021,"MinValue":1250,"MaxValue":1875,"Weight":2000},
+    {"PoolID":13,"No":4,"Key":10061,"MinValue":261,"MaxValue":375,"Weight":1500},
+    {"PoolID":13,"No":5,"Key":10071,"MinValue":396,"MaxValue":593,"Weight":1500},
+    {"PoolID":13,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":13,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":13,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":13,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":14,"No":1,"Key":10031,"MinValue":249,"MaxValue":358,"Weight":1500},
+    {"PoolID":14,"No":2,"Key":10041,"MinValue":377,"MaxValue":566,"Weight":1500},
+    {"PoolID":14,"No":3,"Key":10021,"MinValue":1200,"MaxValue":1800,"Weight":2000},
+    {"PoolID":14,"No":4,"Key":10061,"MinValue":233,"MaxValue":335,"Weight":1500},
+    {"PoolID":14,"No":5,"Key":10071,"MinValue":353,"MaxValue":529,"Weight":1500},
+    {"PoolID":14,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":14,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":14,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":14,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":15,"No":1,"Key":10031,"MinValue":265,"MaxValue":381,"Weight":1500},
+    {"PoolID":15,"No":2,"Key":10041,"MinValue":402,"MaxValue":602,"Weight":1500},
+    {"PoolID":15,"No":3,"Key":10021,"MinValue":1125,"MaxValue":1688,"Weight":2000},
+    {"PoolID":15,"No":4,"Key":10061,"MinValue":201,"MaxValue":289,"Weight":1500},
+    {"PoolID":15,"No":5,"Key":10071,"MinValue":304,"MaxValue":456,"Weight":1500},
+    {"PoolID":15,"No":6,"Key":10081,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":15,"No":7,"Key":10091,"MinValue":500,"MaxValue":750,"Weight":500},
+    {"PoolID":15,"No":8,"Key":10101,"MinValue":1000,"MaxValue":1500,"Weight":500},
+    {"PoolID":15,"No":9,"Key":10111,"MinValue":1000,"MaxValue":1500,"Weight":500}
 ]

+ 1 - 0
sr/etc/data/item.json

@@ -5,6 +5,7 @@
     {"ID":4,"ParseType":0,"ItemSubType":0,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":4,"IsBind":false,"IsMarquee":false},
     {"ID":5,"ParseType":0,"ItemSubType":0,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":3,"IsBind":false,"IsMarquee":false},
     {"ID":6,"ParseType":0,"ItemSubType":0,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":3,"IsBind":false,"IsMarquee":false},
+    {"ID":7,"ParseType":0,"ItemSubType":0,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":3,"IsBind":false,"IsMarquee":false},
     {"ID":101,"ParseType":0,"ItemSubType":1,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":1,"IsBind":false,"IsMarquee":false},
     {"ID":102,"ParseType":0,"ItemSubType":2,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":1,"IsBind":false,"IsMarquee":false},
     {"ID":103,"ParseType":0,"ItemSubType":3,"CanUse":false,"CanSale":false,"SalePrice":[],"Quality":1,"IsBind":false,"IsMarquee":false},

+ 50 - 50
sr/etc/data/lord_level.json

@@ -1,52 +1,52 @@
 [
-    {"Level":1,"SeasonID":1,"Exp":100},
-    {"Level":2,"SeasonID":1,"Exp":120},
-    {"Level":3,"SeasonID":1,"Exp":140},
-    {"Level":4,"SeasonID":1,"Exp":160},
-    {"Level":5,"SeasonID":1,"Exp":180},
-    {"Level":6,"SeasonID":1,"Exp":220},
-    {"Level":7,"SeasonID":1,"Exp":250},
-    {"Level":8,"SeasonID":1,"Exp":300},
-    {"Level":9,"SeasonID":1,"Exp":320},
-    {"Level":10,"SeasonID":1,"Exp":350},
-    {"Level":11,"SeasonID":1,"Exp":370},
-    {"Level":12,"SeasonID":1,"Exp":400},
-    {"Level":13,"SeasonID":1,"Exp":430},
-    {"Level":14,"SeasonID":1,"Exp":450},
-    {"Level":15,"SeasonID":1,"Exp":470},
-    {"Level":16,"SeasonID":1,"Exp":500},
-    {"Level":17,"SeasonID":1,"Exp":520},
-    {"Level":18,"SeasonID":1,"Exp":540},
-    {"Level":19,"SeasonID":1,"Exp":600},
-    {"Level":20,"SeasonID":1,"Exp":800},
-    {"Level":21,"SeasonID":1,"Exp":1000},
-    {"Level":22,"SeasonID":1,"Exp":1100},
-    {"Level":23,"SeasonID":1,"Exp":1200},
-    {"Level":24,"SeasonID":1,"Exp":1300},
-    {"Level":25,"SeasonID":1,"Exp":1400},
-    {"Level":26,"SeasonID":1,"Exp":1500},
-    {"Level":27,"SeasonID":1,"Exp":1600},
-    {"Level":28,"SeasonID":1,"Exp":1800},
-    {"Level":29,"SeasonID":1,"Exp":2100},
-    {"Level":30,"SeasonID":1,"Exp":3100},
-    {"Level":31,"SeasonID":1,"Exp":3600},
-    {"Level":32,"SeasonID":1,"Exp":4100},
-    {"Level":33,"SeasonID":1,"Exp":4200},
-    {"Level":34,"SeasonID":1,"Exp":4300},
-    {"Level":35,"SeasonID":1,"Exp":6500},
-    {"Level":36,"SeasonID":1,"Exp":7000},
-    {"Level":37,"SeasonID":1,"Exp":8000},
-    {"Level":38,"SeasonID":1,"Exp":9000},
-    {"Level":39,"SeasonID":1,"Exp":9500},
-    {"Level":40,"SeasonID":1,"Exp":10000},
-    {"Level":41,"SeasonID":1,"Exp":10500},
-    {"Level":42,"SeasonID":1,"Exp":11000},
-    {"Level":43,"SeasonID":1,"Exp":11500},
-    {"Level":44,"SeasonID":1,"Exp":12000},
-    {"Level":45,"SeasonID":1,"Exp":12500},
-    {"Level":46,"SeasonID":1,"Exp":12500},
-    {"Level":47,"SeasonID":1,"Exp":13000},
-    {"Level":48,"SeasonID":1,"Exp":13500},
-    {"Level":49,"SeasonID":1,"Exp":14000},
-    {"Level":50,"SeasonID":1,"Exp":0}
+    {"Level":1,"SeasonID":1,"Exp":100,"StaminaPoolLimit":30,"LineupMemberLimit":1},
+    {"Level":2,"SeasonID":1,"Exp":120,"StaminaPoolLimit":31,"LineupMemberLimit":1},
+    {"Level":3,"SeasonID":1,"Exp":140,"StaminaPoolLimit":32,"LineupMemberLimit":1},
+    {"Level":4,"SeasonID":1,"Exp":160,"StaminaPoolLimit":33,"LineupMemberLimit":2},
+    {"Level":5,"SeasonID":1,"Exp":180,"StaminaPoolLimit":34,"LineupMemberLimit":2},
+    {"Level":6,"SeasonID":1,"Exp":220,"StaminaPoolLimit":35,"LineupMemberLimit":2},
+    {"Level":7,"SeasonID":1,"Exp":250,"StaminaPoolLimit":36,"LineupMemberLimit":3},
+    {"Level":8,"SeasonID":1,"Exp":300,"StaminaPoolLimit":37,"LineupMemberLimit":3},
+    {"Level":9,"SeasonID":1,"Exp":320,"StaminaPoolLimit":38,"LineupMemberLimit":3},
+    {"Level":10,"SeasonID":1,"Exp":350,"StaminaPoolLimit":39,"LineupMemberLimit":4},
+    {"Level":11,"SeasonID":1,"Exp":370,"StaminaPoolLimit":40,"LineupMemberLimit":4},
+    {"Level":12,"SeasonID":1,"Exp":400,"StaminaPoolLimit":41,"LineupMemberLimit":4},
+    {"Level":13,"SeasonID":1,"Exp":430,"StaminaPoolLimit":42,"LineupMemberLimit":4},
+    {"Level":14,"SeasonID":1,"Exp":450,"StaminaPoolLimit":43,"LineupMemberLimit":4},
+    {"Level":15,"SeasonID":1,"Exp":470,"StaminaPoolLimit":44,"LineupMemberLimit":4},
+    {"Level":16,"SeasonID":1,"Exp":500,"StaminaPoolLimit":45,"LineupMemberLimit":5},
+    {"Level":17,"SeasonID":1,"Exp":520,"StaminaPoolLimit":46,"LineupMemberLimit":5},
+    {"Level":18,"SeasonID":1,"Exp":540,"StaminaPoolLimit":47,"LineupMemberLimit":5},
+    {"Level":19,"SeasonID":1,"Exp":600,"StaminaPoolLimit":48,"LineupMemberLimit":5},
+    {"Level":20,"SeasonID":1,"Exp":800,"StaminaPoolLimit":49,"LineupMemberLimit":5},
+    {"Level":21,"SeasonID":1,"Exp":1000,"StaminaPoolLimit":50,"LineupMemberLimit":5},
+    {"Level":22,"SeasonID":1,"Exp":1100,"StaminaPoolLimit":51,"LineupMemberLimit":5},
+    {"Level":23,"SeasonID":1,"Exp":1200,"StaminaPoolLimit":52,"LineupMemberLimit":5},
+    {"Level":24,"SeasonID":1,"Exp":1300,"StaminaPoolLimit":53,"LineupMemberLimit":5},
+    {"Level":25,"SeasonID":1,"Exp":1400,"StaminaPoolLimit":54,"LineupMemberLimit":5},
+    {"Level":26,"SeasonID":1,"Exp":1500,"StaminaPoolLimit":55,"LineupMemberLimit":5},
+    {"Level":27,"SeasonID":1,"Exp":1600,"StaminaPoolLimit":56,"LineupMemberLimit":5},
+    {"Level":28,"SeasonID":1,"Exp":1800,"StaminaPoolLimit":57,"LineupMemberLimit":5},
+    {"Level":29,"SeasonID":1,"Exp":2100,"StaminaPoolLimit":58,"LineupMemberLimit":5},
+    {"Level":30,"SeasonID":1,"Exp":3100,"StaminaPoolLimit":59,"LineupMemberLimit":5},
+    {"Level":31,"SeasonID":1,"Exp":3600,"StaminaPoolLimit":60,"LineupMemberLimit":5},
+    {"Level":32,"SeasonID":1,"Exp":4100,"StaminaPoolLimit":61,"LineupMemberLimit":5},
+    {"Level":33,"SeasonID":1,"Exp":4200,"StaminaPoolLimit":62,"LineupMemberLimit":5},
+    {"Level":34,"SeasonID":1,"Exp":4300,"StaminaPoolLimit":63,"LineupMemberLimit":5},
+    {"Level":35,"SeasonID":1,"Exp":6500,"StaminaPoolLimit":64,"LineupMemberLimit":5},
+    {"Level":36,"SeasonID":1,"Exp":7000,"StaminaPoolLimit":65,"LineupMemberLimit":5},
+    {"Level":37,"SeasonID":1,"Exp":8000,"StaminaPoolLimit":66,"LineupMemberLimit":5},
+    {"Level":38,"SeasonID":1,"Exp":9000,"StaminaPoolLimit":67,"LineupMemberLimit":5},
+    {"Level":39,"SeasonID":1,"Exp":9500,"StaminaPoolLimit":68,"LineupMemberLimit":5},
+    {"Level":40,"SeasonID":1,"Exp":10000,"StaminaPoolLimit":69,"LineupMemberLimit":5},
+    {"Level":41,"SeasonID":1,"Exp":10500,"StaminaPoolLimit":70,"LineupMemberLimit":5},
+    {"Level":42,"SeasonID":1,"Exp":11000,"StaminaPoolLimit":71,"LineupMemberLimit":5},
+    {"Level":43,"SeasonID":1,"Exp":11500,"StaminaPoolLimit":72,"LineupMemberLimit":5},
+    {"Level":44,"SeasonID":1,"Exp":12000,"StaminaPoolLimit":73,"LineupMemberLimit":5},
+    {"Level":45,"SeasonID":1,"Exp":12500,"StaminaPoolLimit":74,"LineupMemberLimit":5},
+    {"Level":46,"SeasonID":1,"Exp":12500,"StaminaPoolLimit":75,"LineupMemberLimit":5},
+    {"Level":47,"SeasonID":1,"Exp":13000,"StaminaPoolLimit":76,"LineupMemberLimit":5},
+    {"Level":48,"SeasonID":1,"Exp":13500,"StaminaPoolLimit":77,"LineupMemberLimit":5},
+    {"Level":49,"SeasonID":1,"Exp":14000,"StaminaPoolLimit":78,"LineupMemberLimit":5},
+    {"Level":50,"SeasonID":1,"Exp":0,"StaminaPoolLimit":79,"LineupMemberLimit":5}
 ]

File diff suppressed because it is too large
+ 0 - 0
sr/etc/data/map_castle.json


+ 35 - 5
sr/etc/data/proto_route.json

@@ -129,6 +129,26 @@
         "notify": "",
         "desc": ""
     },
+    {
+        "enable": true,
+        "name": "[请求]获取上一次精力恢复时间戳",
+        "route": "game.player.chapterLastRecoverTime",
+        "request": "None",
+        "response": "I64",
+        "push": "",
+        "notify": "",
+        "desc": ""
+    },
+    {
+        "enable": true,
+        "name": "[请求]取出精力池精力",
+        "route": "game.player.chapterTakeOutStamina",
+        "request": "I64",
+        "response": "I64I64",
+        "push": "",
+        "notify": "",
+        "desc": ""
+    },
     {
         "enable": true,
         "name": "[推送]玩家充值数据",
@@ -2024,7 +2044,7 @@
         "name": "[请求]玩家进入地图",
         "route": "map.player.enter",
         "request": "None",
-        "response": "Point",
+        "response": "MapEnterResponse",
         "push": "",
         "notify": "",
         "desc": ""
@@ -2174,7 +2194,7 @@
         "name": "[请求]主城加固",
         "route": "map.player.reinforce",
         "request": "None",
-        "response": "I32",
+        "response": "I64List",
         "push": "",
         "notify": "",
         "desc": ""
@@ -3271,12 +3291,22 @@
     },
     {
         "enable": true,
-        "name": "[请求] 领取每日VIP奖励",
-        "route": "game.player.vipDailyReward",
-        "request": "I32",
+        "name": "[请求] 领取每日vip点数",
+        "route": "game.player.vipDailyExpReward",
+        "request": "None",
         "response": "I32",
         "push": "",
         "notify": "",
         "desc": ""
+    },
+    {
+        "enable": true,
+        "name": "[请求] 领取每日VIP宝箱奖励",
+        "route": "game.player.vipDailyBoxReward",
+        "request": "I32",
+        "response": "AssetList",
+        "push": "",
+        "notify": "",
+        "desc": ""
     }
 ]

+ 0 - 1
sr/etc/data_embed/area.json

@@ -6,7 +6,6 @@
     {"Pid":2188005,"AreaID":5,"AreaName":"LCS测试服","Gate":"192.168.1.38:30001"},
     {"Pid":2188006,"AreaID":6,"AreaName":"AZW测试服","Gate":"192.168.1.41:30001"},
     {"Pid":2188007,"AreaID":7,"AreaName":"yanjian测试服","Gate":"192.168.1.48:30001"},
-    {"Pid":2188008,"AreaID":8,"AreaName":"hw测试服","Gate":"192.168.1.29:30001"},
     {"Pid":2188099,"AreaID":99,"AreaName":"local区","Gate":"127.0.0.1:30001"},
     {"Pid":2188100,"AreaID":100,"AreaName":"[CBT]1区","Gate":"47.238.143.20:30001"}
 ]

+ 0 - 1
sr/etc/data_embed/area_server.json

@@ -10,7 +10,6 @@
     {"AreaID":5,"ServerID":5,"ServerName":"lcs","Status":1,"MergedServerID":0},
     {"AreaID":6,"ServerID":6,"ServerName":"azw","Status":1,"MergedServerID":0},
     {"AreaID":7,"ServerID":7,"ServerName":"yanjian","Status":1,"MergedServerID":0},
-    {"AreaID":8,"ServerID":8,"ServerName":"hw","Status":1,"MergedServerID":0},
     {"AreaID":99,"ServerID":1,"ServerName":"local","Status":1,"MergedServerID":0},
     {"AreaID":100,"ServerID":1,"ServerName":"1服","Status":1,"MergedServerID":0}
 ]

+ 1 - 0
sr/etc/data_embed/game_debug.json

@@ -7,6 +7,7 @@
             "MapBuildTime":10000,
             "MapCityBaseCooldown":10000,
             "MapComebackCooldown":10000,
+            "MapRechooseComebackCooldown":10000,
             "SiegeValue":600,
             "MapSiegeWaitTime":10000,
             "MapSnatchWaitTime":10000,

+ 6 - 5
sr/etc/inner_pb/actor.proto

@@ -28,11 +28,12 @@ message User {
 
 // 更新支付订单
 message UpdateOrder {
-  int64 orderID = 1; // 游戏内部订单id
-  string sdkOrderID = 2; // 第三方sdk平台订单id
-  int32 amount = 3; // 支付回调金额(单位分)
-  bool checkAmount = 4; // 是否检查金额
-  int32 origin = 5; // 订单来源
+  string gameNodeID = 1; // 游戏节点id
+  int64 orderID = 2; // 游戏内部订单id
+  string sdkOrderID = 3; // 第三方sdk平台订单id
+  int32 amount = 4; // 支付回调金额(单位分)
+  bool checkAmount = 5; // 是否检查金额
+  int32 origin = 6; // 订单来源
 }
 
 // 创建支付订单

+ 3 - 28
sr/etc/profile/azw.json

@@ -62,7 +62,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -97,23 +98,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "^pay-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-azw",
-                        "center_redis_id": "redis-azw"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -170,7 +154,7 @@
     "db_queue": {
         "save_ticker": 1,
         "save_count": 1000,
-        "stop_save_count":10000,
+        "stop_save_count": 10000,
         "print_save_log": false,
         "tables": [
             {
@@ -228,15 +212,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "azw-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/dev.json

@@ -72,7 +72,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -115,23 +116,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_file_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-global",
-                        "center_redis_id": "redis-global"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -226,15 +210,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@mongodb:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/dhc.json

@@ -76,7 +76,8 @@
                     },
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
-                    }
+                    },
+                    "auto_pay": true
                 }
             }
         ],
@@ -110,23 +111,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-dhc",
-                        "center_redis_id": "redis-dhc"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -220,15 +204,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "dhc-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 0 - 9
sr/etc/profile/include/dev_mongodb.json

@@ -18,15 +18,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/lcs.json

@@ -76,7 +76,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -110,23 +111,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-lcs",
-                        "center_redis_id": "redis-lcs"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -237,15 +221,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "lcs-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/lgy.json

@@ -61,7 +61,8 @@
                     },
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
-                    }
+                    },
+                    "auto_pay": true
                 }
             }
         ],
@@ -96,23 +97,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "^pay-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-lgy",
-                        "center_redis_id": "redis-lgy"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -226,15 +210,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "lgy-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 18
sr/etc/profile/lgy_dev.json

@@ -47,7 +47,8 @@
                     },
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
-                    }
+                    },
+                    "auto_pay": true
                 }
             }
         ],
@@ -90,23 +91,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-global",
-                        "center_redis_id": "redis-global"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/local.json

@@ -61,7 +61,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -104,23 +105,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_file_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-global",
-                        "center_redis_id": "redis-global"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -215,15 +199,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "local-f1-pay",
-                "uri": "mongodb://f1user:f1user#1357.com@mongodb:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 3 - 28
sr/etc/profile/su.json

@@ -62,7 +62,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -97,23 +98,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "^pay-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-su",
-                        "center_redis_id": "redis-su"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -170,7 +154,7 @@
     "db_queue": {
         "save_ticker": 3,
         "save_count": 1000,
-        "stop_save_count":10000,
+        "stop_save_count": 10000,
         "print_save_log": false,
         "tables": [
             {
@@ -228,15 +212,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "su-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 2 - 27
sr/etc/profile/test.json

@@ -72,7 +72,8 @@
                     "mongo_id_list": {
                         "mongo_id": "mongo-f1-game"
                     },
-                    "battle_validation": false
+                    "battle_validation": false,
+                    "auto_pay": true
                 }
             }
         ],
@@ -116,23 +117,6 @@
                 }
             }
         ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "pay-1",
-                "__settings__": {
-                    "ref_logger": "debug_file_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-global",
-                        "center_redis_id": "redis-global"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
         "ops": [
             {
                 "enable": true,
@@ -227,15 +211,6 @@
                 "timeout": 3000
             }
         ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@mongodb:27017",
-                "timeout": 3000
-            }
-        ],
         "db_map_group": [
             {
                 "enable": true,

+ 0 - 250
sr/etc/profile/yanjian.json

@@ -1,250 +0,0 @@
-{
-    "@desc": "yanjian 本机调试全套节点",
-    "include": [
-        "include/logger.json",
-        "include/dev_data_config.json"
-    ],
-    "env": "yanjian",
-    "debug": true,
-    "print_level": "debug",
-    "cluster": {
-        "discovery": {
-            "mode": "nats",
-            "@mode": "default|nats|etcd"
-        },
-        "nats": {
-            "master_node_id": "master-1",
-            "prefix": "yanjian",
-            "address": "nats://192.168.1.232:4222,nats://192.168.1.232:4223,nats://192.168.1.232:4224",
-            "reconnect_delay": 1,
-            "max_reconnects": 0,
-            "request_timeout": 2,
-            "user": "",
-            "password": ""
-        }
-    },
-    "node": {
-        "master": [
-            {
-                "enable": true,
-                "node_id": "master-1",
-                "__settings__": {
-                    "ref_logger": "debug_console_log"
-                }
-            }
-        ],
-        "gate": [
-            {
-                "enable": true,
-                "node_id": "gate-1",
-                "address": ":30001",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "center_redis_id": "redis-yanjian"
-                    }
-                }
-            }
-        ],
-        "game": [
-            {
-                "enable": true,
-                "node_id": "7",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "center_redis_id": "redis-yanjian",
-                        "game_redis_id": "redis-yanjian",
-                        "chat_redis_id": "redis-yanjian"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-game"
-                    },
-                    "battle_validation": false
-                }
-            }
-        ],
-        "web": [
-            {
-                "enable": true,
-                "node_id": "web-1",
-                "address": ":18080",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "center_redis_id": "redis-yanjian"
-                    },
-                    "allow_register": true
-                }
-            }
-        ],
-        "center": [
-            {
-                "enable": true,
-                "node_id": "^center-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-center"
-                    },
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "center_redis_id": "redis-yanjian"
-                    }
-                }
-            }
-        ],
-        "pay": [
-            {
-                "enable": true,
-                "node_id": "^pay-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "center_redis_id": "redis-yanjian"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-pay"
-                    },
-                    "auto_pay": true
-                }
-            }
-        ],
-        "ops": [
-            {
-                "enable": true,
-                "node_id": "ops-1",
-                "address": ":18081",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "game_redis_id": "redis-yanjian"
-                    }
-                }
-            }
-        ],
-        "chat": [
-            {
-                "enable": true,
-                "node_id": "^chat-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "chat_redis_id": "redis-yanjian",
-                        "game_redis_id": "redis-yanjian"
-                    }
-                }
-            }
-        ],
-        "map": [
-            {
-                "enable": true,
-                "node_id": "^map-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log",
-                    "redis_id_list": {
-                        "guid_redis_id": "redis-yanjian",
-                        "game_redis_id": "redis-yanjian"
-                    },
-                    "mongo_id_list": {
-                        "mongo_id": "mongo-f1-map"
-                    }
-                }
-            }
-        ],
-        "record": [
-            {
-                "enable": true,
-                "node_id": "^record-\\d+$",
-                "__settings__": {
-                    "ref_logger": "debug_console_log"
-                }
-            }
-        ]
-    },
-    "db_queue": {
-        "save_ticker": 1,
-        "save_count": 1000,
-        "stop_save_count":10000,
-        "print_save_log": false,
-        "tables": [
-            {
-                "name": "map_tile",
-                "save_ticker": 120,
-                "save_count": 300,
-                "save_chan_size": 10240,
-                "print_save_log": false,
-                "stop_save_ticker": 1,
-                "stop_save_count": 10000
-            },
-            {
-                "name": "map_res",
-                "save_ticker": 120,
-                "save_count": 300,
-                "save_chan_size": 10240,
-                "print_save_log": false,
-                "stop_save_ticker": 1,
-                "stop_save_count": 10000
-            }
-        ]
-    },
-    "redis": [
-        {
-            "redis_id": "redis-yanjian",
-            "address": "192.168.1.232:46379",
-            "password": "H+5QfwG0jE3C@Plvgikb",
-            "db": 0,
-            "pool_size": 32,
-            "desc": ""
-        }
-    ],
-    "sessions": {
-        "redis_id": "redis-yanjian"
-    },
-    "gen-pool": {
-        "redis_id": "redis-yanjian"
-    },
-    "mongo": {
-        "db_game_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-game",
-                "db_name": "yanjian-f1-game",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
-        "db_center_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-center",
-                "db_name": "yanjian-f1-center",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
-        "db_pay_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-pay",
-                "db_name": "yanjian-f1-pay",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ],
-        "db_map_group": [
-            {
-                "enable": true,
-                "db_id": "mongo-f1-map",
-                "db_name": "yanjian-f1-map",
-                "uri": "mongodb://f1user:3#GPU?MJcKbY2&fYbgplnckfU@192.168.1.232:27017",
-                "timeout": 3000
-            }
-        ]
-    }
-}

+ 31 - 0
sr/internal/actor_remote/game_order.go

@@ -0,0 +1,31 @@
+package actorRemote
+
+import (
+	cherryApp "f1-game/internal/cherry_app"
+	nameActor "f1-game/internal/name/actor"
+	nameRemote "f1-game/internal/name/remote"
+	"f1-game/internal/pb"
+
+	cfacade "github.com/cherry-game/cherry/facade"
+)
+
+type gameOrder struct {
+}
+
+func newGameOrder() *gameOrder {
+	return &gameOrder{}
+}
+
+func (p *gameOrder) Create(req *pb.CreateOrder) (int64, int32) {
+	rsp := &pb.I64{}
+	errCode := cherryApp.CallWait(p.target(req.GameNodeID), nameRemote.Order_Create, req, rsp)
+	return rsp.Value, errCode
+}
+
+func (p *gameOrder) Payment(req *pb.UpdateOrder) int32 {
+	return cherryApp.CallWait(p.target(req.GameNodeID), nameRemote.Order_Payment, req, nil)
+}
+
+func (*gameOrder) target(gameNodeID string) string {
+	return cfacade.NewPath(gameNodeID, nameActor.Order)
+}

+ 0 - 31
sr/internal/actor_remote/pay_order.go

@@ -1,31 +0,0 @@
-package actorRemote
-
-import (
-	cherryApp "f1-game/internal/cherry_app"
-	nameActor "f1-game/internal/name/actor"
-	nameRemote "f1-game/internal/name/remote"
-	"f1-game/internal/pb"
-
-	cfacade "github.com/cherry-game/cherry/facade"
-)
-
-type payOrder struct {
-}
-
-func newPayOrder() *payOrder {
-	return &payOrder{}
-}
-
-func (p *payOrder) Create(req *pb.CreateOrder) (int64, int32) {
-	rsp := &pb.I64{}
-	errCode := cherryApp.CallWait(p.target(), nameRemote.Order_Create, req, rsp)
-	return rsp.Value, errCode
-}
-
-func (p *payOrder) Payment(req *pb.UpdateOrder) int32 {
-	return cherryApp.CallWait(p.target(), nameRemote.Order_Payment, req, nil)
-}
-
-func (*payOrder) target() string {
-	return cfacade.NewPath(payNodeID(), nameActor.Order)
-}

+ 1 - 16
sr/internal/actor_remote/remote.go

@@ -3,7 +3,6 @@ package actorRemote
 import (
 	cherryApp "f1-game/internal/cherry_app"
 	"f1-game/internal/constant"
-	"math/rand"
 )
 
 var (
@@ -17,7 +16,7 @@ var (
 )
 
 var (
-	PayOrder = newPayOrder()
+	GameOrder = newGameOrder()
 )
 
 var (
@@ -38,20 +37,6 @@ var (
 	MapPlayer = newMapPlayer()
 )
 
-func payNodeID() string {
-	list := cherryApp.Discovery().ListByType(constant.NodePay)
-	listLen := len(list)
-	if listLen < 1 {
-		return ""
-	}
-
-	if listLen == 1 {
-		return list[0].GetNodeID()
-	}
-
-	return list[rand.Intn(listLen)].GetNodeID()
-}
-
 func centerNodeID() string {
 	member, found := cherryApp.Discovery().Random(constant.NodeCenter)
 	if !found {

+ 9 - 9
sr/internal/algorithm/aoi_tower/aoi.go

@@ -32,7 +32,7 @@ type (
 		OnMarkerEnter    OnMarkerEnterCallback      // 被观察者-[进入时]的回调
 		OnMarkerMove     OnMarkerMoveCallback       // 被观察者-[移动时]的回调
 		OnMarkerUpdate   OnMarkerUpdateCallback     // 被观察者-[更新时]的回调
-		OnMarkerExit     OnMarkerExitCallback       // 被观察者-[退出时]的回调
+		OnMarkerLeave    OnMarkerLeaveCallback      // 被观察者-[退出时]的回调
 		OnMarkerUpdateID OnMarkerUpdateIDCallback   // 被观察者-[更新时]的回调(带UpdateID)
 		OnTowerExpire    OnTowerExpireCallback      // 灯塔过期的回调
 	}
@@ -42,7 +42,7 @@ type (
 	OnMarkerEnterCallback    func(marker *Object, tower *Tower)
 	OnMarkerMoveCallback     func(marker *Object, newTowers *Tower, oldTowers *Tower)
 	OnMarkerUpdateCallback   func(marker *Object, tower *Tower)
-	OnMarkerExitCallback     func(marker *Object, tower *Tower)
+	OnMarkerLeaveCallback    func(marker *Object, tower *Tower)
 	OnMarkerUpdateIDCallback func(marker *Object, tower *Tower, updateID uint32, funcName string)
 	OnTowerExpireCallback    func(watcher *Object, tower *Tower)
 )
@@ -388,7 +388,7 @@ func (p *AOI) Move(objectID int64, x, y int32, now int64) bool {
 	return false
 }
 
-// Exit 对象退出 AOI 系统
+// Leave 对象离开 AOI 系统
 // 参数:
 //   - objectID: 对象的唯一标识符
 //
@@ -398,7 +398,7 @@ func (p *AOI) Move(objectID int64, x, y int32, now int64) bool {
 //  1. 查找并删除对象
 //  2. 离开观察者 - 从视野范围内的所有灯塔中删除 (忽略延迟,立即清理)
 //  3. 离开被观察者 - 直接通知
-func (p *AOI) Exit(objectID int64) {
+func (p *AOI) Leave(objectID int64) {
 	object := p.objects.Get(objectID)
 	if object == nil {
 		clog.Debugf("[Leave] objectID = %d not found.", objectID)
@@ -427,8 +427,8 @@ func (p *AOI) Exit(objectID int64) {
 
 	if object.IsMarker() {
 		// 触发回调:通知观察该灯塔的所有观察者有marker离开
-		if p.OnMarkerExit != nil {
-			p.OnMarkerExit(object, tower)
+		if p.OnMarkerLeave != nil {
+			p.OnMarkerLeave(object, tower)
 		}
 
 		tower.DelMarker(object)
@@ -893,8 +893,8 @@ func (p *AOI) SetOnMarkerUpdateID(callback OnMarkerUpdateIDCallback) {
 	p.OnMarkerUpdateID = callback
 }
 
-// SetOnMarkerExit 设置被观察者离开时的回调
+// SetOnMarkerLeave 设置被观察者离开时的回调
 // 参数:callback 为 func(marker *aoi.Object, tower *Tower) 形式
-func (p *AOI) SetOnMarkerExit(callback OnMarkerExitCallback) {
-	p.OnMarkerExit = callback
+func (p *AOI) SetOnMarkerLeave(callback OnMarkerLeaveCallback) {
+	p.OnMarkerLeave = callback
 }

+ 8 - 0
sr/internal/code/status_code.go

@@ -107,6 +107,8 @@ const (
 	ConfigNotFound_MapCastle        int32 = 10606 // 配置不存在:地图城池
 	ConfigNotFound_SeasonQuest      int32 = 12801 // 配置不存在:赛季霸业任务
 	ConfigNotFound_VipLevel         int32 = 11701 // VIP等级配置不存在
+	ConfigNotFound_ShopCard         int32 = 11702 // 周月卡商城配置不存在
+	ConfigNotFound_ShopGold         int32 = 11703 // 金币商城配置不存在
 )
 
 // 账号错误码
@@ -653,6 +655,7 @@ const (
 	ChapterLevelBuyTimesError      int32 = 119017 // 购买次数错误
 	ChapterBattleError             int32 = 119018 // 探险战斗异常
 	ChapterRewardIsEmpty           int32 = 119019 // 暂无可领取奖励
+	ChapterStaminaFull             int32 = 119020 // 当前精力已满
 )
 
 const (
@@ -730,6 +733,11 @@ const (
 
 const (
 	VipDailyRewardReceived int32 = 129001 // 今日已经领取
+	VipLevelBoxReceived    int32 = 129002 // 当前VIP等级的专属宝箱已经领取
+	VipLevelNotEnough      int32 = 129003 // VIP等级不足
+	VipCardExpired         int32 = 129004 // 领取失败,周月卡已经到期
+	VipCardAlreadyReceived int32 = 129005 // 周月卡奖励今日已领取
+	VipCardDayMaxLimit     int32 = 129006 // 周月卡日期已达最大上限
 )
 
 // 签到

+ 3 - 2
sr/internal/constant/charge.go

@@ -1,6 +1,7 @@
 package constant
 
 const (
-	ChargeKeyType   = "charge_type"   // 充值项类型
-	ChargeKeyParams = "charge_params" // 充值项参数
+	ChargeKeyType       = "charge_type"         // 充值项类型
+	ChargeKeyParams     = "charge_params"       // 充值项参数
+	ChargeKeyGameNodeID = "charge_game_node_id" // 充值玩家所在游戏节点ID
 )

+ 0 - 1
sr/internal/constant/node_type.go

@@ -5,7 +5,6 @@ const (
 	NodeGame   = "game"   // game节点类型   游戏主业务(多例,根据业务扩展)
 	NodeGate   = "gate"   // gate节点类型   网关(多例,根据压力扩展)
 	NodeMaster = "master" // master节点类型 发现服务(单例,有必要配置etcd模式配置多例)
-	NodePay    = "pay"    // pay节点类型    支付业务(多例,根据压力扩展)
 	NodeWeb    = "web"    // web节点类型    web业务(多例,根据压力扩展)
 	NodeOPS    = "ops"    // ops节点类型    对外API接口管理(单例)
 	NodeChat   = "chat"   // chat节点类型	聊天业务(多例,根据压力扩展)

+ 14 - 13
sr/internal/constant/test.go

@@ -1,17 +1,18 @@
 package constant
 
 const (
-	GameDebug_MapRelocateCooldown     = "MapRelocateCooldown"
-	GameDebug_MapBuildTime            = "MapBuildTime"
-	GameDebug_MapCityBaseCooldown     = "MapCityBaseCooldown"
-	GameDebug_MapComebackCooldown     = "MapComebackCooldown"
-	GameDebug_SiegeValue              = "SiegeValue"
-	GameDebug_MapSiegeWaitTime        = "MapSiegeWaitTime"
-	GameDebug_MapSnatchWaitTime       = "MapSnatchWaitTime"
-	GameDebug_MapDiscardWaitTime      = "MapDiscardWaitTime"
-	GameDebug_MapOccupyWaitTime       = "MapOccupyWaitTime"
-	GameDebug_MapMarchSpeedUp         = "MapMarchSpeedUp"
-	GameDebug_MapReinforcePrepareTime = "MapReinforcePrepareTime"
-	GameDebug_MapReinforceEffectTime  = "MapReinforceEffectTime"
-	GameDebug_MapReinforceCooldown    = "MapReinforceCooldown"
+	GameDebug_MapRelocateCooldown         = "MapRelocateCooldown"
+	GameDebug_MapBuildTime                = "MapBuildTime"
+	GameDebug_MapCityBaseCooldown         = "MapCityBaseCooldown"
+	GameDebug_MapComebackCooldown         = "MapComebackCooldown"
+	GameDebug_MapRechooseComebackCooldown = "MapRechooseComebackCooldown"
+	GameDebug_SiegeValue                  = "SiegeValue"
+	GameDebug_MapSiegeWaitTime            = "MapSiegeWaitTime"
+	GameDebug_MapSnatchWaitTime           = "MapSnatchWaitTime"
+	GameDebug_MapDiscardWaitTime          = "MapDiscardWaitTime"
+	GameDebug_MapOccupyWaitTime           = "MapOccupyWaitTime"
+	GameDebug_MapMarchSpeedUp             = "MapMarchSpeedUp"
+	GameDebug_MapReinforcePrepareTime     = "MapReinforcePrepareTime"
+	GameDebug_MapReinforceEffectTime      = "MapReinforceEffectTime"
+	GameDebug_MapReinforceCooldown        = "MapReinforceCooldown"
 )

+ 2 - 2
sr/internal/constant/time.go

@@ -13,6 +13,6 @@ const (
 )
 
 const (
-	TickOffset_March      = 500     // 行军定时器偏移
-	Aoi_WatcherLeaveDelay = 60 * 60 // aoi灯塔watcher离开延迟删除时间(单位秒)
+	TickOffset_March      = 500 // 行军定时器偏移
+	Aoi_WatcherLeaveDelay = 30  // aoi灯塔watcher离开延迟删除时间(单位秒)
 )

+ 8 - 0
sr/internal/data/extend_const.go

@@ -164,6 +164,14 @@ func (p *constConfig) GetMapComebackCoolDown() int64 {
 	return p.SelfStateComebackCoolDown * ctime.MillisecondsPerSecond
 }
 
+func (p *constConfig) GetMapRechooseComebackCoolDown() int64 {
+	if value, ok := GameDebug.GetDebugValue(constant.GameDebug_MapRechooseComebackCooldown); ok {
+		return value
+	}
+
+	return p.ChooseStateComebackCoolDown * ctime.MillisecondsPerSecond
+}
+
 // 通过联盟邮件类型获取邮件上限值
 func (p *constConfig) GetLeagueMailLimit(mailType int32) int32 {
 	switch mailType {

+ 5 - 3
sr/internal/data/lord_level.go

@@ -9,9 +9,11 @@ func init() {
 
 type (
 	LordLevelRow struct {
-		Level    int32 `json:"Level"`    // 等级
-		SeasonID int32 `json:"SeasonID"` // 赛季ID
-		Exp      int64 `json:"Exp"`      // 下级经验值
+		Level             int32 `json:"Level"`             // 等级
+		SeasonID          int32 `json:"SeasonID"`          // 赛季ID
+		Exp               int64 `json:"Exp"`               // 下级经验值
+		StaminaPoolLimit  int64 `json:"StaminaPoolLimit"`  // 精力池上限
+		LineupMemberLimit int   `json:"LineupMemberLimit"` // 阵容人数上限
 	}
 
 	lordLevelConfig struct {

+ 7 - 6
sr/internal/enum/charge.go

@@ -8,10 +8,11 @@ const (
 
 // ChargeType 充值类型
 const (
-	ChargeTypeNone          int32 = 0 // 未知
-	ChargeTypeShopGold      int32 = 1 // 金砖商店
-	ChargeTypeShopDailyDeal int32 = 2 // 每日特惠
-	ChargeTypeCard          int32 = 3 // 特权卡
-	ChargeTypeFund          int32 = 4 // 基金
-	ChargeTypeFirstCharge   int32 = 5 // 首充礼包
+	ChargeTypeNone        int32 = 0 // 未知
+	ChargeTypeShopGold    int32 = 1 // 金币商城
+	ChargeTypeCard        int32 = 2 // 周月卡
+	ChargeTypeGift        int32 = 3 // 超值礼包
+	ChargeTypeVip         int32 = 4 // vip专属宝箱
+	ChargeTypeFund        int32 = 5 // 基金 // 暂时没有
+	ChargeTypeFirstCharge int32 = 6 // 首充礼包 // 暂时没有
 )

+ 64 - 17
sr/internal/enum/item.go

@@ -1,6 +1,8 @@
 package enum
 
-import "slices"
+import (
+	"slices"
+)
 
 type ItemUseType int32 // 道具池使用类型
 const (
@@ -11,15 +13,21 @@ const (
 
 // 货币类型的id
 const (
-	ItemIDSilver      int32 = 1    // 银币
-	ItemIDGold        int32 = 2    // 金币
-	ItemIDF           int32 = 3    // F币
-	ItemIDStamina     int32 = 5    // 精力
-	ItemIDWood        int32 = 101  // 木材
-	ItemIDIron        int32 = 102  // 铁矿
-	ItemIDStone       int32 = 103  // 石料
-	ItemIDGrain       int32 = 104  // 粮食
-	ItemIDSeasonPoint int32 = 1001 // 赛季积分
+	ItemIDSilver       int32 = 1    // 银币
+	ItemIDGold         int32 = 2    // 金币
+	ItemIDF            int32 = 3    // F币
+	ItemIDStamina      int32 = 5    // 精力
+	ItemIDTempStamina  int32 = 7    // 存储精力
+	ItemIDWood         int32 = 101  // 木材(绑定)
+	ItemIDIron         int32 = 102  // 铁矿(绑定)
+	ItemIDStone        int32 = 103  // 石料(绑定)
+	ItemIDGrain        int32 = 104  // 粮食(绑定)
+	ItemIDWoodUnBound  int32 = 111  // 木材
+	ItemIDIronUnBound  int32 = 112  // 铁矿
+	ItemIDStoneUnBound int32 = 113  // 石料
+	ItemIDGrainUnBound int32 = 114  // 粮食
+	ItemIDSeasonPoint  int32 = 1001 // 赛季积分
+	ItemIDChargePoint  int32 = 1003 // 充值积分
 
 	ItemIDArm201 int32 = 201 // 民兵
 	ItemIDArm202 int32 = 202 // 精锐兵1
@@ -33,18 +41,29 @@ const (
 )
 
 var (
-	ItemMaxNumList = []int32{ // 有上限货币道具ID列表
+
+	// 有上限货币道具ID列表
+	ItemMaxNumList = []int32{
+		ItemIDWoodUnBound,
+		ItemIDIronUnBound,
+		ItemIDStoneUnBound,
+		ItemIDGrainUnBound,
 		ItemIDWood,
 		ItemIDIron,
 		ItemIDStone,
 		ItemIDGrain,
 	}
 
-	OpsItemInfoList = []int32{ // 后台需要展示的道具ID列表
+	// 后台需要展示的道具ID列表
+	OpsItemInfoList = []int32{
 		ItemIDSilver,
 		ItemIDGold,
 		ItemIDF,
 		ItemIDStamina,
+		ItemIDWoodUnBound,
+		ItemIDIronUnBound,
+		ItemIDStoneUnBound,
+		ItemIDGrainUnBound,
 		ItemIDWood,
 		ItemIDIron,
 		ItemIDStone,
@@ -57,6 +76,10 @@ var (
 		ItemIDIron,
 		ItemIDStone,
 		ItemIDGrain,
+		ItemIDWoodUnBound,
+		ItemIDIronUnBound,
+		ItemIDStoneUnBound,
+		ItemIDGrainUnBound,
 		ItemIDArm201,
 		ItemIDArm202,
 		ItemIDArm203,
@@ -78,14 +101,38 @@ var (
 
 	// 地图侦察资源列表
 	MapScoutItemIDList = []int32{
-		ItemIDWood,
-		ItemIDIron,
-		ItemIDStone,
-		ItemIDGrain,
+		ItemIDWoodUnBound,
+		ItemIDIronUnBound,
+		ItemIDStoneUnBound,
+		ItemIDGrainUnBound,
+	}
+
+	// 绑定资源和非绑定资源的映射
+	BindingResourceMap = map[int32]int32{
+		ItemIDWood:  ItemIDWoodUnBound,
+		ItemIDIron:  ItemIDIronUnBound,
+		ItemIDStone: ItemIDStoneUnBound,
+		ItemIDGrain: ItemIDGrainUnBound,
+	}
+
+	// 非绑定资源和绑定资源的映射
+	UnBindingResourceMap = map[int32]int32{
+		ItemIDWoodUnBound:  ItemIDWood,
+		ItemIDIronUnBound:  ItemIDIron,
+		ItemIDStoneUnBound: ItemIDStone,
+		ItemIDGrainUnBound: ItemIDGrain,
+	}
+
+	// 绑定资源产出的映射
+	MapItemAttrs = map[int32]int32{
+		ItemIDWood:  AttrWoodYield,
+		ItemIDIron:  AttrIronYield,
+		ItemIDStone: AttrStoneYield,
+		ItemIDGrain: AttrGrainYield,
 	}
 )
 
-var (
+const (
 	GenPoolTimeType_Hour  int32 = 1 // 每小时
 	GenPoolTimeType_Day   int32 = 2 // 每天
 	GenPoolTimeType_Week  int32 = 3 // 每周

+ 1 - 4
sr/internal/name/actor/actor.go

@@ -17,10 +17,7 @@ const (
 	GameOps    = "ops"     // 运维			path = {game}.ops
 	GamePlayer = "player"  // 玩家			path = {game}.player
 	Marquee    = "marquee" // 跑马灯		path = {game}.marquee
-)
-
-const (
-	Order = "order" // path = pay.order.
+	Order      = "order"   // 充值订单		path = {game}.order
 )
 
 const (

+ 8 - 1
sr/internal/name/db/game.go

@@ -16,8 +16,9 @@ const (
 	Table_Complaint = "complaint"
 	Table_Chapter   = "chapter"
 	Table_Marquee   = "marquee"
+	Table_Charge    = "charge"
+	Table_Order     = "order"
 )
-
 const (
 	Field_PlayerID   = "PlayerID"
 	Field_ActivityID = "ActivityID"
@@ -28,3 +29,9 @@ const (
 const (
 	Field_LordName = "Data.Lord.Name"
 )
+
+const (
+	Field_OrderID    = "OrderID"
+	Field_Status     = "Status"
+	Field_CreateTime = "CreateTime"
+)

+ 0 - 10
sr/internal/name/db/pay.go

@@ -1,10 +0,0 @@
-package nameDB
-
-const Table_Order = "order"
-
-const (
-	Field_OrderID    = "OrderID"
-	Field_PayNodeID  = "PayNodeID"
-	Field_Status     = "Status"
-	Field_CreateTime = "CreateTime"
-)

+ 28 - 27
sr/internal/name/local/map.go

@@ -84,33 +84,34 @@ const (
 )
 
 const (
-	MapPlayer_Login            = "login"            // 登录地图
-	MapPlayer_Enter            = "enter"            // 玩家进入地图
-	MapPlayer_SelectState      = "selectState"      // 选择出生州
-	MapPlayer_BornStateInfo    = "bornStateInfo"    // 获取出生州信息
-	MapPlayer_Join             = "join"             // 玩家观察者进入地图
-	MapPlayer_Quit             = "quit"             // 玩家观察者离开地图
-	MapPlayer_Slide            = "slide"            // 滑动屏幕
-	MapPlayer_March            = "march"            // 行军
-	MapPlayer_Retreat          = "retreat"          // 撤退
-	MapPlayer_MarchStop        = "marchStop"        // 行军中止
-	MapPlayer_Discard          = "discard"          // 丢弃
-	MapPlayer_DiscardCancel    = "discardCancel"    // 取消放弃
-	MapPlayer_Build            = "build"            // 建造
-	MapPlayer_BuildUpgrade     = "buildUpgrade"     // 玩家建筑升级
-	MapPlayer_Relocate         = "relocate"         // 迁城
-	MapPlayer_Comeback         = "comeback"         // 再起
-	MapPlayer_Reborn           = "reborn"           // 重新选择出生点
-	MapPlayer_MapMark          = "mapMark"          // 地图标记
-	MapPlayer_MapMarkDelete    = "mapMarkDelete"    // 地图标记删除
-	MapPlayer_SiegeAssemble    = "siegeAssemble"    // 攻城集结
-	MapPlayer_SiegeRank        = "siegeRank"        // 攻城首占排行
-	MapPlayer_FindPath         = "findPath"         // 查询寻路信息
-	MapPlayer_OccupyCastleList = "occupyCastleList" // 查询被攻占城池列表
-	MapPlayer_ScoutRequest     = "mapScoutRequest"  // 发起侦察
-	MapPlayer_Reinforce        = "reinforce"        // 主城加固
-	MapPlayer_ReinforceCancel  = "reinforceCancel"  // 主城加固取消
-	MapPlayer_ResArmies        = "resArmies"        // 资源守军
+	MapPlayer_Login             = "login"             // 登录地图
+	MapPlayer_Enter             = "enter"             // 玩家进入地图
+	MapPlayer_SelectState       = "selectState"       // 选择出生州
+	MapPlayer_BornStateInfo     = "bornStateInfo"     // 获取出生州信息
+	MapPlayer_Join              = "join"              // 玩家观察者进入地图
+	MapPlayer_Quit              = "quit"              // 玩家观察者离开地图
+	MapPlayer_Slide             = "slide"             // 滑动屏幕
+	MapPlayer_March             = "march"             // 行军
+	MapPlayer_Retreat           = "retreat"           // 撤退
+	MapPlayer_MarchStop         = "marchStop"         // 行军中止
+	MapPlayer_Discard           = "discard"           // 丢弃
+	MapPlayer_DiscardCancel     = "discardCancel"     // 取消放弃
+	MapPlayer_Build             = "build"             // 建造
+	MapPlayer_BuildUpgrade      = "buildUpgrade"      // 玩家建筑升级
+	MapPlayer_Relocate          = "relocate"          // 迁城
+	MapPlayer_Comeback          = "comeback"          // 再起
+	MapPlayer_Reborn            = "reborn"            // 重新选择出生点
+	MapPlayer_MapMark           = "mapMark"           // 地图标记
+	MapPlayer_MapMarkDelete     = "mapMarkDelete"     // 地图标记删除
+	MapPlayer_SiegeAssemble     = "siegeAssemble"     // 攻城集结
+	MapPlayer_SiegeRank         = "siegeRank"         // 攻城首占排行
+	MapPlayer_FindPath          = "findPath"          // 查询寻路信息
+	MapPlayer_OccupyCastleList  = "occupyCastleList"  // 查询被攻占城池列表
+	MapPlayer_ScoutRequest      = "mapScoutRequest"   // 发起侦察
+	MapPlayer_Reinforce         = "reinforce"         // 主城加固
+	MapPlayer_ReinforceCancel   = "reinforceCancel"   // 主城加固取消
+	MapPlayer_ResArmies         = "resArmies"         // 资源守军
+	MapPlayer_MapObjectPosition = "mapObjectPosition" // 获取地图对象位置
 )
 
 const (

+ 11 - 8
sr/internal/name/local/player.go

@@ -50,9 +50,9 @@ const (
 )
 
 const (
-	Player_ChargeCreate = "chargeCreate" // 创建支付订单
+	Player_ChargeCreate     = "chargeCreate" // 创建支付订单
+	Player_ChargeCardReward = "cardReward"   // 每日周月卡奖励领取
 )
-
 const (
 	Player_GMGetAsset   = "gmGetAsset"
 	Player_GMTimeOffset = "gmTimeOffset"
@@ -88,11 +88,13 @@ const (
 )
 
 const (
-	Player_ChapterBattle        = "chapterBattle"        // 探险发起关卡战斗
-	Player_ChapterVerify        = "chapterVerify"        // 探险关卡战斗验证
-	Player_ChapterLevelSweep    = "chapterLevelSweep"    // 探险关卡扫荡
-	Player_ChapterStarReward    = "chapterStarReward"    // 探险累计星级奖励领取
-	Player_ChapterLevelTimesBuy = "chapterLevelTimesBuy" // 探险关卡挑战次数购买
+	Player_ChapterBattle          = "chapterBattle"          // 探险发起关卡战斗
+	Player_ChapterVerify          = "chapterVerify"          // 探险关卡战斗验证
+	Player_ChapterLevelSweep      = "chapterLevelSweep"      // 探险关卡扫荡
+	Player_ChapterStarReward      = "chapterStarReward"      // 探险累计星级奖励领取
+	Player_ChapterLevelTimesBuy   = "chapterLevelTimesBuy"   // 探险关卡挑战次数购买
+	Player_ChapterLastRecoverTime = "chapterLastRecoverTime" // 获取上一次精力恢复时间戳
+	Player_ChapterTakeOutStamina  = "chapterTakeOutStamina"  // 取出精力池精力
 )
 
 const (
@@ -113,5 +115,6 @@ const (
 )
 
 const (
-	Player_VipDailyReward = "vipDailyReward" // 领取每日VIP奖励
+	Player_VipDailyExpReward = "vipDailyExpReward" // 领取每日VIP点数
+	Player_VipDailyBoxReward = "vipDailyBoxReward" // 领取每日VIP宝箱奖励
 )

+ 4 - 3
sr/internal/name/remote/map.go

@@ -3,7 +3,7 @@ package nameRemote
 const (
 	MapAOI_Enter  = "enter"
 	MapAOI_Move   = "move"
-	MapAOI_Exit   = "exit"
+	MapAOI_Leave  = "leave"
 	MapAOI_Update = "update"
 )
 
@@ -41,8 +41,9 @@ const (
 	MapLogic_AssembleStop            = "assembleStop"            // 集结取消
 	MapLogic_AssembleQuit            = "assembleKick"            // 集结踢人
 	MapLogic_AssembleDepart          = "assembleDepart"          // 集结出发
-	MapLogic_AOIMarkerEnter          = "aoiMarkerEnter"          // aoi marker进入视野回调
-	MapLogic_AOIMarkerLeave          = "aoiMarkerLeave"          // aoi marker移出视野回调
+	MapLogic_AOIMarkerEnterView      = "aoiMarkerEnterView"      // aoi marker进入视野回调
+	MapLogic_AOIMarkerLeaveView      = "aoiMarkerLeaveView"      // aoi marker移出视野回调
+	MapLogic_AOIMarkerDespawn        = "aoiMarkerDespawn"        // aoi marker移出aoi系统
 	MapLogic_AOIMarkerUpdate         = "aoiMarkerUpdate"         // aoi marker更新回调
 	MapLogic_AOIUpdateMarchState     = "aoiUpdateMarchState"     // aoi 更新回调 行军状态
 	MapLogic_AOIUpdateBattle         = "aoiUpdateBattle"         // aoi 更新回调 战斗

+ 24 - 23
sr/internal/name/route/map.go

@@ -1,29 +1,30 @@
 package nameRoute
 
 const (
-	MapPlayer_Login            = "map.player.login"
-	MapPlayer_Enter            = "map.player.enter"
-	MapPlayer_SelectState      = "map.player.selectState"
-	MapPlayer_BornStateInfo    = "map.player.bornStateInfo"
-	MapPlayer_Join             = "map.player.join"
-	MapPlayer_Quit             = "map.player.quit"
-	MapPlayer_Slide            = "map.player.slide"
-	MapPlayer_March            = "map.player.march"
-	MapPlayer_Retreat          = "map.player.retreat"
-	MapPlayer_MarchStop        = "map.player.stop"
-	MapPlayer_Discard          = "map.player.discard"
-	MapPlayer_DiscardCancel    = "map.player.discardCancel"    // 玩家取消放弃
-	MapPlayer_Build            = "map.player.build"            // 玩家建造
-	MapPlayer_BuildUpgrade     = "map.player.buildUpgrade"     // 玩家建筑升级
-	MapPlayer_SiegeRank        = "map.player.siegeRank"        // 玩家建筑攻城排名
-	MapPlayer_Relocate         = "map.player.relocate"         // 玩家迁城
-	MapPlayer_Comeback         = "map.player.comeback"         // 玩家再起
-	MapPlayer_RelocateBack     = "map.player.relocateBack"     // 玩家回迁
-	MapPlayer_SiegeAssemble    = "map.player.siegeAssemble"    // 攻城集结
-	MapPlayer_FindPath         = "map.player.findPath"         // 查询行军路线
-	MapPlayer_OccupyCastleList = "map.player.occupyCastleList" // 查询被攻占城池列表
-	MapPlayer_Reinforce        = "map.player.reinforce"        // 主城加固
-	MapPlayer_ReinforceCancel  = "map.player.reinforceCancel"  // 取消主城加固
+	MapPlayer_Login             = "map.player.login"
+	MapPlayer_Enter             = "map.player.enter"
+	MapPlayer_SelectState       = "map.player.selectState"
+	MapPlayer_BornStateInfo     = "map.player.bornStateInfo"
+	MapPlayer_Join              = "map.player.join"
+	MapPlayer_Quit              = "map.player.quit"
+	MapPlayer_Slide             = "map.player.slide"
+	MapPlayer_March             = "map.player.march"
+	MapPlayer_Retreat           = "map.player.retreat"
+	MapPlayer_MarchStop         = "map.player.stop"
+	MapPlayer_Discard           = "map.player.discard"
+	MapPlayer_DiscardCancel     = "map.player.discardCancel"     // 玩家取消放弃
+	MapPlayer_Build             = "map.player.build"             // 玩家建造
+	MapPlayer_BuildUpgrade      = "map.player.buildUpgrade"      // 玩家建筑升级
+	MapPlayer_SiegeRank         = "map.player.siegeRank"         // 玩家建筑攻城排名
+	MapPlayer_Relocate          = "map.player.relocate"          // 玩家迁城
+	MapPlayer_Comeback          = "map.player.comeback"          // 玩家再起
+	MapPlayer_RelocateBack      = "map.player.relocateBack"      // 玩家回迁
+	MapPlayer_SiegeAssemble     = "map.player.siegeAssemble"     // 攻城集结
+	MapPlayer_FindPath          = "map.player.findPath"          // 查询行军路线
+	MapPlayer_OccupyCastleList  = "map.player.occupyCastleList"  // 查询被攻占城池列表
+	MapPlayer_Reinforce         = "map.player.reinforce"         // 主城加固
+	MapPlayer_ReinforceCancel   = "map.player.reinforceCancel"   // 取消主城加固
+	MapPlayer_MapObjectPosition = "map.player.mapObjectPosition" // 获取地图对象位置
 )
 
 const (

+ 10 - 6
sr/internal/name/route/player.go

@@ -3,6 +3,7 @@ package nameRoute
 const (
 	GamePlayer_HeroStar           = "game.player.heroStar"
 	GamePlayer_ChargeCreate       = "game.player.chargeCreate" // 创建支付订单
+	GamePlayer_CardReward         = "game.player.cardReward"   // 每日周月卡奖励领取
 	GamePlayer_GMGetAsset         = "game.player.gmGetAsset"
 	GamePlayer_ItemUse            = "game.player.itemUse"
 	GamePlayer_ItemCraft          = "game.player.itemCraft"
@@ -63,11 +64,13 @@ const (
 
 // 探险
 const (
-	GamePlayer_ChapterBattle     = "game.player.chapterBattle"
-	GamePlayer_ChapterVerify     = "game.player.chapterVerify"
-	GamePlayer_ChapterLevelSweep = "game.player.chapterLevelSweep"
-	GamePlayer_ChapterStarReward = "game.player.chapterStarReward"
-	Player_ChapterLevelTimesBuy  = "game.player.chapterLevelTimesBuy"
+	GamePlayer_ChapterBattle      = "game.player.chapterBattle"
+	GamePlayer_ChapterVerify      = "game.player.chapterVerify"
+	GamePlayer_ChapterLevelSweep  = "game.player.chapterLevelSweep"
+	GamePlayer_ChapterStarReward  = "game.player.chapterStarReward"
+	Player_ChapterLevelTimesBuy   = "game.player.chapterLevelTimesBuy"
+	Player_ChapterLastRecoverTime = "game.player.chapterLastRecoverTime"
+	Player_ChapterTakeOutStamina  = "game.player.chapterTakeOutStamina"
 )
 
 // 商店
@@ -77,7 +80,8 @@ const (
 
 // vip
 const (
-	GamePlayer_VipDailyReward = "game.player.vipDailyReward" // 领取每日VIP奖励
+	GamePlayer_VipDailyExpReward = "game.player.vipDailyExpReward" // 领取每日vip点数
+	GamePlayer_VipDailyBoxReward = "game.player.vipDailyBoxReward" // 领取每日VIP宝箱奖励
 )
 
 // 领主个人信息

+ 45 - 42
sr/internal/name/route/push.go

@@ -41,53 +41,56 @@ const (
 	PushGamePlayer_ExchangeInfo    = "game.player.exchangeInfoPush"       // 推送 玩家交易所信息
 	PushGamePlayer_MainQuest       = "game.player.mainQuestsPush"         // 推送 游戏主线信息
 	PushGamePlayer_VipInfo         = "game.player.vipInfoPush"            // 推送 玩家vip信息
+	PushGamePlayer_ChargeData      = "game.player.chargeDataPush"         // 推送 玩家充值数据
 )
-
 const (
-	PushMapPusher_ObjectUpdate = "map.pusher.objectUpdate" // 推送 地图对象更新
-	PushMapPusher_ObjectDel    = "map.pusher.objectDel"    // 推送 地图对象删除
-	PushMapPusher_MarchState   = "map.pusher.marchState"   // 推送 行军状态更新
-	PushMapPusher_PlayerUpdate = "map.pusher.playerUpdate" // 推送 玩家信息更新
-	PushMapPusher_LeagueUpdate = "map.pusher.leagueUpdate" // 推送 联盟信息更新
-	PushMapPusher_Battle       = "map.pusher.battle"       // 推送 地图战斗信息
-	PushMapPusher_TowerUpdate  = "map.pusher.towerUpdate"  // 推送 灯塔全量更新
+	PushMapPusher_ObjectUpdate    = "map.pusher.objectUpdate"    // 推送 地图对象更新
+	PushMapPusher_ObjectDel       = "map.pusher.objectDel"       // 推送 地图对象删除
+	PushMapPusher_MarchState      = "map.pusher.marchState"      // 推送 行军状态更新
+	PushMapPusher_PlayerUpdate    = "map.pusher.playerUpdate"    // 推送 玩家信息更新
+	PushMapPusher_LeagueUpdate    = "map.pusher.leagueUpdate"    // 推送 联盟信息更新
+	PushMapPusher_Battle          = "map.pusher.battle"          // 推送 地图战斗信息
+	PushMapPusher_TowerUpdate     = "map.pusher.towerUpdate"     // 推送 灯塔全量更新
+	PushMapPusher_MapUIMarchState = "map.pusher.mapUIMarchState" // 推送 地图ui层-行军状态推送
 )
 
 const (
-	PushMapPlayer_Team               = "map.player.teamPush"               // 推送 英雄部队
-	PushMapPlayer_TeamChange         = "map.player.teamChangePush"         // 推送 英雄部队变更
-	PushMapPlayer_TeamTroopReturn    = "map.player.teamTroopReturnPush"    // 推送 部队兵力返还
-	PushMapPlayer_FacilityList       = "map.player.facilityListPush"       // 推送 建筑列表
-	PushMapPlayer_FacilityFinish     = "map.player.facilityFinishPush"     // 推送 建筑升级完成列表
-	PushMapPlayer_FacilityAttrChange = "map.player.facilityAttrChangePush" // 推送 城建属性变更
-	PushMapPlayer_ReportNew          = "map.player.reportNewPush"          // 推送新战报
-	PushMapPlayer_HeroList           = "map.player.heroListPush"           // 推送 英雄列表
-	PushMapPlayer_HeroChange         = "map.player.heroChangePush"         // 推送 英雄变更
-	PushMapPlayer_HeroState          = "map.player.heroStatePush"          // 推送 英雄状态
-	PushMapPlayer_Conscript          = "map.player.conscriptPush"          // 推送 征兵信息
-	PushMapPlayer_Quests             = "map.player.questsPush"             // 推送 任务列表
-	PushMapPlayer_QuestsLeague       = "map.player.questsLeaguePush"       // 推送 已领取联盟任务列表
-	PushMapPlayer_StorageList        = "map.player.storageListPush"        // 推送 背包列表
-	PushMapPlayer_StoragChange       = "map.player.storageChangePush"      // 推送 背包变更
-	PushMapPlayer_ResDefendRecover   = "map.player.resDefendRecoverPush"   // 推送 资源防守恢复
-	PushMapPlayer_MapMark            = "map.player.mapMarkPush"            // 推送 地图标记列表
-	PushMapPlayer_ShopList           = "map.player.shopPush"               // 推送 地图商店列表
-	PushMapPlayer_ShopChangeList     = "map.player.shopChangePush"         // 推送 更新地图商店列表
-	PushMapPlayer_LeagueQuit         = "map.player.leagueQuitPush"         // 推送 离开联盟通知
-	PushMapPlayer_PrestigeChange     = "map.player.prestigeChangePush"     // 推送 声望变更推送
-	PushMapPlayer_TeamOutsideTroops  = "map.player.teamOutsideTroopsPush"  // 推送 部队城外征兵变更
-	PushMapPlayer_SiegeResult        = "map.player.siegeResultPush"        // 推送 攻城结果
-	PushMapPlayer_MainQuest          = "map.player.mainQuestsPush"         // 推送 地图主线信息
-	PushMapPlayer_MainCityShow       = "map.player.mainCityShowPush"       // 推送 主城外观列表
-	PushMapPlayer_MainCityShowChange = "map.player.mainCityShowChangePush" // 推送 主城外观变更
-	PushMapPlayer_OwnerMapObjects    = "map.player.ownerMapObjectsPush"    // 推送 地图对象列表
-	PushMapPlayer_OwnerMapObjectAdd  = "map.player.ownerMapObjectAddPush"  // 推送 地图对象新增
-	PushMapPlayer_OwnerMapObjectDel  = "map.player.ownerMapObjectDelPush"  // 推送 地图对象删除
-	PushMapPlayer_MapUICastlesPush   = "map.player.mapUICastlesPush"       // 推送 地图对象删除
-	PushMapPlayer_SignIn             = "map.player.dailySignInPush"        // 推送 签到数据
-	PushMapPlayer_ScoutList          = "map.player.mapScoutListPush"       // 推送 侦察队列
-	PushMapPlayer_ScoutChange        = "map.player.mapScoutChangePush"     // 推送 侦察变更队列
-	PushMapPlayer_Reborn             = "map.player.rebornPush"             // 推送 重新出生(被击飞)
+	PushMapPlayer_Team                 = "map.player.teamPush"                 // 推送 英雄部队
+	PushMapPlayer_TeamChange           = "map.player.teamChangePush"           // 推送 英雄部队变更
+	PushMapPlayer_TeamTroopReturn      = "map.player.teamTroopReturnPush"      // 推送 部队兵力返还
+	PushMapPlayer_FacilityList         = "map.player.facilityListPush"         // 推送 建筑列表
+	PushMapPlayer_FacilityFinish       = "map.player.facilityFinishPush"       // 推送 建筑升级完成列表
+	PushMapPlayer_FacilityAttrChange   = "map.player.facilityAttrChangePush"   // 推送 城建属性变更
+	PushMapPlayer_ReportNew            = "map.player.reportNewPush"            // 推送新战报
+	PushMapPlayer_HeroList             = "map.player.heroListPush"             // 推送 英雄列表
+	PushMapPlayer_HeroChange           = "map.player.heroChangePush"           // 推送 英雄变更
+	PushMapPlayer_HeroState            = "map.player.heroStatePush"            // 推送 英雄状态
+	PushMapPlayer_Conscript            = "map.player.conscriptPush"            // 推送 征兵信息
+	PushMapPlayer_Quests               = "map.player.questsPush"               // 推送 任务列表
+	PushMapPlayer_QuestsLeague         = "map.player.questsLeaguePush"         // 推送 已领取联盟任务列表
+	PushMapPlayer_StorageList          = "map.player.storageListPush"          // 推送 背包列表
+	PushMapPlayer_StoragChange         = "map.player.storageChangePush"        // 推送 背包变更
+	PushMapPlayer_ResDefendRecover     = "map.player.resDefendRecoverPush"     // 推送 资源防守恢复
+	PushMapPlayer_MapMark              = "map.player.mapMarkPush"              // 推送 地图标记列表
+	PushMapPlayer_ShopList             = "map.player.shopPush"                 // 推送 地图商店列表
+	PushMapPlayer_ShopChangeList       = "map.player.shopChangePush"           // 推送 更新地图商店列表
+	PushMapPlayer_LeagueQuit           = "map.player.leagueQuitPush"           // 推送 离开联盟通知
+	PushMapPlayer_PrestigeChange       = "map.player.prestigeChangePush"       // 推送 声望变更推送
+	PushMapPlayer_TeamOutsideTroops    = "map.player.teamOutsideTroopsPush"    // 推送 部队城外征兵变更
+	PushMapPlayer_SiegeResult          = "map.player.siegeResultPush"          // 推送 攻城结果
+	PushMapPlayer_MainQuest            = "map.player.mainQuestsPush"           // 推送 地图主线信息
+	PushMapPlayer_MainCityShow         = "map.player.mainCityShowPush"         // 推送 主城外观列表
+	PushMapPlayer_MainCityShowChange   = "map.player.mainCityShowChangePush"   // 推送 主城外观变更
+	PushMapPlayer_OwnerMapObjects      = "map.player.ownerMapObjectsPush"      // 推送 地图对象列表
+	PushMapPlayer_OwnerMapObjectAdd    = "map.player.ownerMapObjectAddPush"    // 推送 地图对象新增
+	PushMapPlayer_OwnerMapObjectDel    = "map.player.ownerMapObjectDelPush"    // 推送 地图对象删除
+	PushMapPlayer_OwnerMapObjectUpdate = "map.player.ownerMapObjectUpdatePush" // 推送 地图对象更新
+	PushMapPlayer_SignIn               = "map.player.dailySignInPush"          // 推送 签到数据
+	PushMapPlayer_ScoutList            = "map.player.mapScoutListPush"         // 推送 侦察队列
+	PushMapPlayer_ScoutChange          = "map.player.mapScoutChangePush"       // 推送 侦察变更队列
+	PushMapPlayer_Reborn               = "map.player.rebornPush"               // 推送 重新出生(被击飞)
+	PushMapPlayer_MapUICastlesPush     = "map.player.mapUICastlesPush"         // 推送 地图ui层-系统城
+	PushMapPlayer_MapUIMarchsPush      = "map.player.mapUIMarchsPush"          // 推送 地图ui层-行军对象列表
 )
 
 const (

+ 23 - 12
sr/internal/pb/actor.pb.go

@@ -265,11 +265,12 @@ func (x *User) GetIp() string {
 // 更新支付订单
 type UpdateOrder struct {
 	state         protoimpl.MessageState `protogen:"open.v1"`
-	OrderID       int64                  `protobuf:"varint,1,opt,name=orderID,proto3" json:"orderID,omitempty"`         // 游戏内部订单id
-	SdkOrderID    string                 `protobuf:"bytes,2,opt,name=sdkOrderID,proto3" json:"sdkOrderID,omitempty"`    // 第三方sdk平台订单id
-	Amount        int32                  `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"`           // 支付回调金额(单位分)
-	CheckAmount   bool                   `protobuf:"varint,4,opt,name=checkAmount,proto3" json:"checkAmount,omitempty"` // 是否检查金额
-	Origin        int32                  `protobuf:"varint,5,opt,name=origin,proto3" json:"origin,omitempty"`           // 订单来源
+	GameNodeID    string                 `protobuf:"bytes,1,opt,name=gameNodeID,proto3" json:"gameNodeID,omitempty"`    // 游戏节点id
+	OrderID       int64                  `protobuf:"varint,2,opt,name=orderID,proto3" json:"orderID,omitempty"`         // 游戏内部订单id
+	SdkOrderID    string                 `protobuf:"bytes,3,opt,name=sdkOrderID,proto3" json:"sdkOrderID,omitempty"`    // 第三方sdk平台订单id
+	Amount        int32                  `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"`           // 支付回调金额(单位分)
+	CheckAmount   bool                   `protobuf:"varint,5,opt,name=checkAmount,proto3" json:"checkAmount,omitempty"` // 是否检查金额
+	Origin        int32                  `protobuf:"varint,6,opt,name=origin,proto3" json:"origin,omitempty"`           // 订单来源
 	unknownFields protoimpl.UnknownFields
 	sizeCache     protoimpl.SizeCache
 }
@@ -304,6 +305,13 @@ func (*UpdateOrder) Descriptor() ([]byte, []int) {
 	return file_actor_proto_rawDescGZIP(), []int{2}
 }
 
+func (x *UpdateOrder) GetGameNodeID() string {
+	if x != nil {
+		return x.GameNodeID
+	}
+	return ""
+}
+
 func (x *UpdateOrder) GetOrderID() int64 {
 	if x != nil {
 		return x.OrderID
@@ -7426,15 +7434,18 @@ const file_actor_proto_rawDesc = "" +
 	"\x03PID\x18\x02 \x01(\x05R\x03PID\x12\x16\n" +
 	"\x06openID\x18\x03 \x01(\tR\x06openID\x12\x10\n" +
 	"\x03uid\x18\x04 \x01(\x03R\x03uid\x12\x0e\n" +
-	"\x02ip\x18\x05 \x01(\tR\x02ip\"\x99\x01\n" +
-	"\vUpdateOrder\x12\x18\n" +
-	"\aorderID\x18\x01 \x01(\x03R\aorderID\x12\x1e\n" +
+	"\x02ip\x18\x05 \x01(\tR\x02ip\"\xb9\x01\n" +
+	"\vUpdateOrder\x12\x1e\n" +
 	"\n" +
-	"sdkOrderID\x18\x02 \x01(\tR\n" +
+	"gameNodeID\x18\x01 \x01(\tR\n" +
+	"gameNodeID\x12\x18\n" +
+	"\aorderID\x18\x02 \x01(\x03R\aorderID\x12\x1e\n" +
+	"\n" +
+	"sdkOrderID\x18\x03 \x01(\tR\n" +
 	"sdkOrderID\x12\x16\n" +
-	"\x06amount\x18\x03 \x01(\x05R\x06amount\x12 \n" +
-	"\vcheckAmount\x18\x04 \x01(\bR\vcheckAmount\x12\x16\n" +
-	"\x06origin\x18\x05 \x01(\x05R\x06origin\"\xb9\x02\n" +
+	"\x06amount\x18\x04 \x01(\x05R\x06amount\x12 \n" +
+	"\vcheckAmount\x18\x05 \x01(\bR\vcheckAmount\x12\x16\n" +
+	"\x06origin\x18\x06 \x01(\x05R\x06origin\"\xb9\x02\n" +
 	"\vCreateOrder\x12\x10\n" +
 	"\x03PID\x18\x01 \x01(\x05R\x03PID\x12\x10\n" +
 	"\x03UID\x18\x02 \x01(\x03R\x03UID\x12\x1e\n" +

+ 151 - 35
sr/internal/pb/charge.pb.go

@@ -23,22 +23,130 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+// 充值数据
+type ChargeData struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 周月卡信息 key: 充值项id value: 过期时间戳(毫秒)
+	Cards map[int32]*Card `protobuf:"bytes,1,rep,name=Cards,proto3" json:"Cards,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// 金币商城充值记录,用来判断首充
+	Golds         []int32 `protobuf:"varint,2,rep,packed,name=Golds,proto3" json:"Golds,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ChargeData) Reset() {
+	*x = ChargeData{}
+	mi := &file_charge_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ChargeData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChargeData) ProtoMessage() {}
+
+func (x *ChargeData) ProtoReflect() protoreflect.Message {
+	mi := &file_charge_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChargeData.ProtoReflect.Descriptor instead.
+func (*ChargeData) Descriptor() ([]byte, []int) {
+	return file_charge_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ChargeData) GetCards() map[int32]*Card {
+	if x != nil {
+		return x.Cards
+	}
+	return nil
+}
+
+func (x *ChargeData) GetGolds() []int32 {
+	if x != nil {
+		return x.Golds
+	}
+	return nil
+}
+
+// 周月卡信息
+type Card struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 过期时间戳(毫秒)
+	ExpireTime int64 `protobuf:"varint,1,opt,name=expireTime,proto3" json:"expireTime,omitempty"`
+	// 今日是否已领取
+	IsReceive     bool `protobuf:"varint,2,opt,name=isReceive,proto3" json:"isReceive,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Card) Reset() {
+	*x = Card{}
+	mi := &file_charge_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Card) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Card) ProtoMessage() {}
+
+func (x *Card) ProtoReflect() protoreflect.Message {
+	mi := &file_charge_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Card.ProtoReflect.Descriptor instead.
+func (*Card) Descriptor() ([]byte, []int) {
+	return file_charge_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Card) GetExpireTime() int64 {
+	if x != nil {
+		return x.ExpireTime
+	}
+	return 0
+}
+
+func (x *Card) GetIsReceive() bool {
+	if x != nil {
+		return x.IsReceive
+	}
+	return false
+}
+
 // 充值订单创建
 type ChargeCreate struct {
 	state protoimpl.MessageState `protogen:"open.v1"`
 	// 充值项id
 	ChargeID int32 `protobuf:"varint,1,opt,name=chargeID,proto3" json:"chargeID,omitempty"`
-	// 充值项类型
-	ChargeType int32 `protobuf:"varint,2,opt,name=chargeType,proto3" json:"chargeType,omitempty"`
 	// 充值项参数
-	ChargeParams  int32 `protobuf:"varint,3,opt,name=chargeParams,proto3" json:"chargeParams,omitempty"`
+	ChargeParams  int32 `protobuf:"varint,2,opt,name=chargeParams,proto3" json:"chargeParams,omitempty"`
 	unknownFields protoimpl.UnknownFields
 	sizeCache     protoimpl.SizeCache
 }
 
 func (x *ChargeCreate) Reset() {
 	*x = ChargeCreate{}
-	mi := &file_charge_proto_msgTypes[0]
+	mi := &file_charge_proto_msgTypes[2]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -50,7 +158,7 @@ func (x *ChargeCreate) String() string {
 func (*ChargeCreate) ProtoMessage() {}
 
 func (x *ChargeCreate) ProtoReflect() protoreflect.Message {
-	mi := &file_charge_proto_msgTypes[0]
+	mi := &file_charge_proto_msgTypes[2]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -63,7 +171,7 @@ func (x *ChargeCreate) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ChargeCreate.ProtoReflect.Descriptor instead.
 func (*ChargeCreate) Descriptor() ([]byte, []int) {
-	return file_charge_proto_rawDescGZIP(), []int{0}
+	return file_charge_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *ChargeCreate) GetChargeID() int32 {
@@ -73,13 +181,6 @@ func (x *ChargeCreate) GetChargeID() int32 {
 	return 0
 }
 
-func (x *ChargeCreate) GetChargeType() int32 {
-	if x != nil {
-		return x.ChargeType
-	}
-	return 0
-}
-
 func (x *ChargeCreate) GetChargeParams() int32 {
 	if x != nil {
 		return x.ChargeParams
@@ -95,14 +196,14 @@ type ChargeCreateResponse struct {
 	// 游戏订单id
 	OrderID int64 `protobuf:"varint,2,opt,name=orderID,proto3" json:"orderID,omitempty"`
 	// 返回参数
-	Params        map[string]string `protobuf:"bytes,4,rep,name=params,proto3" json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	Params        map[string]string `protobuf:"bytes,3,rep,name=params,proto3" json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	unknownFields protoimpl.UnknownFields
 	sizeCache     protoimpl.SizeCache
 }
 
 func (x *ChargeCreateResponse) Reset() {
 	*x = ChargeCreateResponse{}
-	mi := &file_charge_proto_msgTypes[1]
+	mi := &file_charge_proto_msgTypes[3]
 	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 	ms.StoreMessageInfo(mi)
 }
@@ -114,7 +215,7 @@ func (x *ChargeCreateResponse) String() string {
 func (*ChargeCreateResponse) ProtoMessage() {}
 
 func (x *ChargeCreateResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_charge_proto_msgTypes[1]
+	mi := &file_charge_proto_msgTypes[3]
 	if x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -127,7 +228,7 @@ func (x *ChargeCreateResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ChargeCreateResponse.ProtoReflect.Descriptor instead.
 func (*ChargeCreateResponse) Descriptor() ([]byte, []int) {
-	return file_charge_proto_rawDescGZIP(), []int{1}
+	return file_charge_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *ChargeCreateResponse) GetChargeID() int32 {
@@ -155,17 +256,27 @@ var File_charge_proto protoreflect.FileDescriptor
 
 const file_charge_proto_rawDesc = "" +
 	"\n" +
-	"\fcharge.proto\x12\x02pb\"n\n" +
-	"\fChargeCreate\x12\x1a\n" +
-	"\bchargeID\x18\x01 \x01(\x05R\bchargeID\x12\x1e\n" +
+	"\fcharge.proto\x12\x02pb\"\x97\x01\n" +
+	"\n" +
+	"ChargeData\x12/\n" +
+	"\x05Cards\x18\x01 \x03(\v2\x19.pb.ChargeData.CardsEntryR\x05Cards\x12\x14\n" +
+	"\x05Golds\x18\x02 \x03(\x05R\x05Golds\x1aB\n" +
 	"\n" +
-	"chargeType\x18\x02 \x01(\x05R\n" +
-	"chargeType\x12\"\n" +
-	"\fchargeParams\x18\x03 \x01(\x05R\fchargeParams\"\xc5\x01\n" +
+	"CardsEntry\x12\x10\n" +
+	"\x03key\x18\x01 \x01(\x05R\x03key\x12\x1e\n" +
+	"\x05value\x18\x02 \x01(\v2\b.pb.CardR\x05value:\x028\x01\"D\n" +
+	"\x04Card\x12\x1e\n" +
+	"\n" +
+	"expireTime\x18\x01 \x01(\x03R\n" +
+	"expireTime\x12\x1c\n" +
+	"\tisReceive\x18\x02 \x01(\bR\tisReceive\"N\n" +
+	"\fChargeCreate\x12\x1a\n" +
+	"\bchargeID\x18\x01 \x01(\x05R\bchargeID\x12\"\n" +
+	"\fchargeParams\x18\x02 \x01(\x05R\fchargeParams\"\xc5\x01\n" +
 	"\x14ChargeCreateResponse\x12\x1a\n" +
 	"\bchargeID\x18\x01 \x01(\x05R\bchargeID\x12\x18\n" +
 	"\aorderID\x18\x02 \x01(\x03R\aorderID\x12<\n" +
-	"\x06params\x18\x04 \x03(\v2$.pb.ChargeCreateResponse.ParamsEntryR\x06params\x1a9\n" +
+	"\x06params\x18\x03 \x03(\v2$.pb.ChargeCreateResponse.ParamsEntryR\x06params\x1a9\n" +
 	"\vParamsEntry\x12\x10\n" +
 	"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
 	"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x05Z\x03/pbb\x06proto3"
@@ -182,19 +293,24 @@ func file_charge_proto_rawDescGZIP() []byte {
 	return file_charge_proto_rawDescData
 }
 
-var file_charge_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_charge_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
 var file_charge_proto_goTypes = []any{
-	(*ChargeCreate)(nil),         // 0: pb.ChargeCreate
-	(*ChargeCreateResponse)(nil), // 1: pb.ChargeCreateResponse
-	nil,                          // 2: pb.ChargeCreateResponse.ParamsEntry
+	(*ChargeData)(nil),           // 0: pb.ChargeData
+	(*Card)(nil),                 // 1: pb.Card
+	(*ChargeCreate)(nil),         // 2: pb.ChargeCreate
+	(*ChargeCreateResponse)(nil), // 3: pb.ChargeCreateResponse
+	nil,                          // 4: pb.ChargeData.CardsEntry
+	nil,                          // 5: pb.ChargeCreateResponse.ParamsEntry
 }
 var file_charge_proto_depIdxs = []int32{
-	2, // 0: pb.ChargeCreateResponse.params:type_name -> pb.ChargeCreateResponse.ParamsEntry
-	1, // [1:1] is the sub-list for method output_type
-	1, // [1:1] is the sub-list for method input_type
-	1, // [1:1] is the sub-list for extension type_name
-	1, // [1:1] is the sub-list for extension extendee
-	0, // [0:1] is the sub-list for field type_name
+	4, // 0: pb.ChargeData.Cards:type_name -> pb.ChargeData.CardsEntry
+	5, // 1: pb.ChargeCreateResponse.params:type_name -> pb.ChargeCreateResponse.ParamsEntry
+	1, // 2: pb.ChargeData.CardsEntry.value:type_name -> pb.Card
+	3, // [3:3] is the sub-list for method output_type
+	3, // [3:3] is the sub-list for method input_type
+	3, // [3:3] is the sub-list for extension type_name
+	3, // [3:3] is the sub-list for extension extendee
+	0, // [0:3] is the sub-list for field type_name
 }
 
 func init() { file_charge_proto_init() }
@@ -208,7 +324,7 @@ func file_charge_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: unsafe.Slice(unsafe.StringData(file_charge_proto_rawDesc), len(file_charge_proto_rawDesc)),
 			NumEnums:      0,
-			NumMessages:   3,
+			NumMessages:   6,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

File diff suppressed because it is too large
+ 270 - 191
sr/internal/pb/map.pb.go


+ 28 - 13
sr/internal/pb/vip.pb.go

@@ -40,8 +40,10 @@ type VipInfo struct {
 	IsDailyExpReceived bool `protobuf:"varint,6,opt,name=isDailyExpReceived,proto3" json:"isDailyExpReceived,omitempty"`
 	// 连续登录天数
 	ContinuousLoginDays int32 `protobuf:"varint,7,opt,name=continuousLoginDays,proto3" json:"continuousLoginDays,omitempty"`
-	unknownFields       protoimpl.UnknownFields
-	sizeCache           protoimpl.SizeCache
+	// 专属宝箱充值状态 key:vip等级 value:是否已领取
+	SpecialBoxStates map[int32]bool `protobuf:"bytes,8,rep,name=specialBoxStates,proto3" json:"specialBoxStates,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
 }
 
 func (x *VipInfo) Reset() {
@@ -123,11 +125,18 @@ func (x *VipInfo) GetContinuousLoginDays() int32 {
 	return 0
 }
 
+func (x *VipInfo) GetSpecialBoxStates() map[int32]bool {
+	if x != nil {
+		return x.SpecialBoxStates
+	}
+	return nil
+}
+
 var File_vip_proto protoreflect.FileDescriptor
 
 const file_vip_proto_rawDesc = "" +
 	"\n" +
-	"\tvip.proto\x12\x02pb\x1a\x0fbase_type.proto\"\x84\x02\n" +
+	"\tvip.proto\x12\x02pb\x1a\x0fbase_type.proto\"\x98\x03\n" +
 	"\aVipInfo\x12\x14\n" +
 	"\x05level\x18\x01 \x01(\x05R\x05level\x12\x10\n" +
 	"\x03exp\x18\x02 \x01(\x03R\x03exp\x12\x1f\n" +
@@ -137,7 +146,11 @@ const file_vip_proto_rawDesc = "" +
 	"expireTime\x12.\n" +
 	"\x12isDailyBoxReceived\x18\x05 \x01(\bR\x12isDailyBoxReceived\x12.\n" +
 	"\x12isDailyExpReceived\x18\x06 \x01(\bR\x12isDailyExpReceived\x120\n" +
-	"\x13continuousLoginDays\x18\a \x01(\x05R\x13continuousLoginDaysB\x05Z\x03/pbb\x06proto3"
+	"\x13continuousLoginDays\x18\a \x01(\x05R\x13continuousLoginDays\x12M\n" +
+	"\x10specialBoxStates\x18\b \x03(\v2!.pb.VipInfo.SpecialBoxStatesEntryR\x10specialBoxStates\x1aC\n" +
+	"\x15SpecialBoxStatesEntry\x12\x10\n" +
+	"\x03key\x18\x01 \x01(\x05R\x03key\x12\x14\n" +
+	"\x05value\x18\x02 \x01(\bR\x05value:\x028\x01B\x05Z\x03/pbb\x06proto3"
 
 var (
 	file_vip_proto_rawDescOnce sync.Once
@@ -151,18 +164,20 @@ func file_vip_proto_rawDescGZIP() []byte {
 	return file_vip_proto_rawDescData
 }
 
-var file_vip_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_vip_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_vip_proto_goTypes = []any{
 	(*VipInfo)(nil), // 0: pb.VipInfo
-	(*Attrs)(nil),   // 1: pb.Attrs
+	nil,             // 1: pb.VipInfo.SpecialBoxStatesEntry
+	(*Attrs)(nil),   // 2: pb.Attrs
 }
 var file_vip_proto_depIdxs = []int32{
-	1, // 0: pb.VipInfo.attrs:type_name -> pb.Attrs
-	1, // [1:1] is the sub-list for method output_type
-	1, // [1:1] is the sub-list for method input_type
-	1, // [1:1] is the sub-list for extension type_name
-	1, // [1:1] is the sub-list for extension extendee
-	0, // [0:1] is the sub-list for field type_name
+	2, // 0: pb.VipInfo.attrs:type_name -> pb.Attrs
+	1, // 1: pb.VipInfo.specialBoxStates:type_name -> pb.VipInfo.SpecialBoxStatesEntry
+	2, // [2:2] is the sub-list for method output_type
+	2, // [2:2] is the sub-list for method input_type
+	2, // [2:2] is the sub-list for extension type_name
+	2, // [2:2] is the sub-list for extension extendee
+	0, // [0:2] is the sub-list for field type_name
 }
 
 func init() { file_vip_proto_init() }
@@ -177,7 +192,7 @@ func file_vip_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: unsafe.Slice(unsafe.StringData(file_vip_proto_rawDesc), len(file_vip_proto_rawDesc)),
 			NumEnums:      0,
-			NumMessages:   1,
+			NumMessages:   2,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

+ 140 - 38
sr/internal/types/currency_map.go

@@ -23,16 +23,30 @@ func NewCurrencyMap() CurrencyMap {
 	return CurrencyMap{}
 }
 
-func (p CurrencyMap) Get(id int32) *Currency {
+// 获取可用扣除的资源数量
+//
+// 绑定可用数量=绑定+非绑定
+//
+// 非绑定可用数量=非绑定
+func (p CurrencyMap) Get(id int32) int64 {
+	entity := p.GetEntity(id)
+	if unBindID, ok := enum.BindingResourceMap[id]; ok {
+		unBindEntity := p.GetEntity(unBindID)
+		return entity.Num + unBindEntity.Num
+	} else {
+		return entity.Num
+	}
+}
+
+func (p CurrencyMap) GetEntity(id int32) *Currency {
 	if value, found := p[id]; found {
 		return value
 	}
 
 	entity := &Currency{
-		ID:         id,
-		Num:        0,
-		MaxNum:     0,
-		UpdateTime: ctime.Now().ToSecond(),
+		ID:     id,
+		Num:    0,
+		MaxNum: 0,
 	}
 
 	p[id] = entity
@@ -49,44 +63,89 @@ func (p CurrencyMap) Increase(id int32, num int64) (*Currency, bool) {
 		return nil, false
 	}
 
-	entity := p.Get(id)
+	entity := p.GetEntity(id)
 	entity.Num += num
 
 	return entity, true
 }
 
-func (p CurrencyMap) Decrease(id int32, num int64) (*Currency, bool) {
+// Decrease 优先扣除绑定资源,再扣除非绑定资源
+//
+// 返回变更的资源列表
+//
+// 返回是否成功
+func (p CurrencyMap) Decrease(id int32, num int64) (Assets, bool) {
 	if id < 1 || num < 1 {
 		return nil, false
 	}
 
-	entity := p.Get(id)
+	// 返回变更的资源列表
+	changeRet := Assets{}
+
+	// 检查是否是绑定资源ID
+	if unBindID, ok := enum.BindingResourceMap[id]; ok {
+		// 是绑定资源,优先扣除绑定,再扣除非绑定
+		bindEntity := p.GetEntity(id)
+		unBindEntity := p.GetEntity(unBindID)
+
+		totalAvailable := bindEntity.Num + unBindEntity.Num
+		if totalAvailable < num {
+			return nil, false
+		}
+
+		remaining := num
+
+		// 先扣除绑定资源
+		if bindEntity.Num > 0 {
+			if bindEntity.Num >= remaining {
+				changeRet.Add(bindEntity.ID, remaining)
+				bindEntity.Num -= remaining
+				remaining = 0
+			} else {
+				changeRet.Add(bindEntity.ID, bindEntity.Num)
+				remaining -= bindEntity.Num
+				bindEntity.Num = 0
+			}
+
+			if p.IsFull(id) {
+				bindEntity.UpdateTime = ctime.Now().ToSecond()
+			}
+		}
+
+		// 再扣除非绑定资源
+		if remaining > 0 && unBindEntity.Num > 0 {
+			unBindEntity.Num -= remaining
+
+			changeRet.Add(unBindEntity.ID, remaining)
+
+			if p.IsFull(unBindID) {
+				unBindEntity.UpdateTime = ctime.Now().ToSecond()
+			}
+		}
+
+		return changeRet, true
+	}
+
+	// 非绑定资源或普通资源,直接扣除
+	entity := p.GetEntity(id)
 	if entity.Num < num {
 		return nil, false
 	}
 
-	// 在扣除的时候判断一下是否达到上限,刷新一下 UpdateTime,
-	// 避免达到上限后,一段时间内不更新这个时间导致下次进入自动产出会立即产出很多资源的问题
-	if entity.IsFull() {
+	entity.Num -= num
+
+	changeRet.Add(id, num)
+
+	if p.IsFull(id) {
 		entity.UpdateTime = ctime.Now().ToSecond()
 	}
 
-	entity.Num -= num
-
-	return entity, true
+	return changeRet, true
 }
 
 // Check 检查货币容量上限和是否有新增加的货币道具
-func (p CurrencyMap) Check(maxNum int64, isLeague bool) bool {
-	var (
-		isChange = false
-		itemList = enum.ItemMaxNumList
-	)
-
-	if isLeague {
-		itemList = enum.LeagueItemMaxNumList
-	}
-
+func (p CurrencyMap) Check(maxNum int64, itemList []int32) bool {
+	var isChange bool
 	for _, itemID := range itemList {
 		if p.CheckAdd(itemID, 0, maxNum) {
 			isChange = true
@@ -99,6 +158,10 @@ func (p CurrencyMap) Check(maxNum int64, isLeague bool) bool {
 func (p CurrencyMap) CheckAdd(id int32, num, maxNum int64) bool {
 	if c, found := p[id]; found {
 		if c.MaxNum < maxNum {
+			if p.IsFull(id) {
+				c.UpdateTime = ctime.Now().ToSecond()
+			}
+			// 更新上限
 			c.MaxNum = maxNum
 			return true
 		}
@@ -107,10 +170,10 @@ func (p CurrencyMap) CheckAdd(id int32, num, maxNum int64) bool {
 	}
 
 	p[id] = &Currency{
-		ID:         id,
-		Num:        num,
-		MaxNum:     maxNum,
-		UpdateTime: ctime.Now().ToSecond(),
+		ID:     id,
+		Num:    num,
+		MaxNum: maxNum,
+		// UpdateTime: ctime.Now().ToSecond(), // TODO 创建不赋值,有可能还没有产出
 	}
 
 	return true
@@ -137,13 +200,18 @@ func (p CurrencyMap) ToProto() map[int32]*pb.Currency {
 	return maps
 }
 
-func (p *Currency) IsFull() bool {
+func (p CurrencyMap) IsFull(id int32) bool {
+	currency := p.GetEntity(id)
 	// 没有上限
-	if p.MaxNum == 0 {
+	if currency.MaxNum == 0 {
 		return false
 	}
 
-	return p.Num >= p.MaxNum
+	// 总数量 对应非绑定或绑定的资源数量
+	num := p.getSumNum(id)
+
+	// 绑定和非绑定的资源共用当前的上限
+	return num >= currency.MaxNum
 }
 
 func (p *Currency) ToProto() pb.Currency {
@@ -155,15 +223,27 @@ func (p *Currency) ToProto() pb.Currency {
 	}
 }
 
+// 检查是否需要初始化更新时间(有产出的时候才需要初始化)
+func (p *CurrencyMap) CheckInitUpdateTime(id int32, nowSecond int64) bool {
+	currency := p.GetEntity(id)
+	if currency.UpdateTime == 0 {
+		currency.UpdateTime = nowSecond
+		return true
+	}
+	return false
+}
+
 // CheckAutoAdd 检测一段时间增加的货币道具
-func (p *Currency) CheckAutoAdd(nowSecond int64, addNumPerHour int64, itemAddSecond int64) bool {
+func (p *CurrencyMap) CheckAutoAdd(id int32, nowSecond int64, addNumPerHour int64, itemAddSecond int64) bool {
 	// 超过上限,忽略
-	if p.IsFull() {
+	if p.IsFull(id) {
 		return false
 	}
 
+	currency := p.GetEntity(id)
+
 	// 计算时差
-	diffSeconds := nowSecond - p.UpdateTime
+	diffSeconds := nowSecond - currency.UpdateTime
 	if diffSeconds < itemAddSecond {
 		return false
 	}
@@ -174,13 +254,35 @@ func (p *Currency) CheckAutoAdd(nowSecond int64, addNumPerHour int64, itemAddSec
 		return false
 	}
 
+	// 当前总数量
+	nowSumNum := p.getSumNum(id)
+
 	// 如果添加超出上限,则算出真实添加的点数
-	if p.MaxNum > 0 && (p.Num+addNum) >= p.MaxNum {
-		addNum = p.MaxNum - p.Num
+	if currency.MaxNum > 0 && (nowSumNum+addNum) >= currency.MaxNum {
+		addNum = currency.MaxNum - nowSumNum
 	}
 
-	p.UpdateTime = nowSecond
-	p.Num += max(0, addNum)
+	currency.UpdateTime = nowSecond
+	currency.Num += max(0, addNum)
 
 	return true
 }
+
+// 获取资源总数量,对应绑定或非绑定的数量
+func (p CurrencyMap) getSumNum(id int32) int64 {
+	// 总数量+=对应非绑定或绑定的资源数量
+	num := p.GetEntity(id).Num
+	// 判断是否有非绑定的ID
+	if unBindItemID, ok := enum.BindingResourceMap[id]; ok {
+		unBindCurrency := p.GetEntity(unBindItemID)
+		num += unBindCurrency.Num
+	}
+
+	// 判断是否有绑定ID
+	if bindItemID, ok := enum.UnBindingResourceMap[id]; ok {
+		bindCurrency := p.GetEntity(bindItemID)
+		num += bindCurrency.Num
+	}
+
+	return num
+}

+ 2 - 0
sr/nodes/game/game.go

@@ -18,6 +18,7 @@ import (
 	"f1-game/nodes/game/mail"
 	"f1-game/nodes/game/marquee"
 	"f1-game/nodes/game/ops"
+	"f1-game/nodes/game/order"
 	"f1-game/nodes/game/player"
 	"runtime"
 
@@ -55,6 +56,7 @@ func Run(node cfacade.INode) {
 		player.NewActor(),
 		login.NewActor(runtime.NumGoroutine()*2),
 		marquee.NewActor(),
+		order.NewActor(512),
 	)
 
 	app.ActorSystem().SetArrivalTimeout(50)

+ 14 - 0
sr/nodes/game/internal/db/cache.go

@@ -101,3 +101,17 @@ var (
 		cache.WithMaximumSize(-1),
 	)
 )
+
+var (
+	// 支付订单表 key:order_id, value:order
+	orderTableCache = cache.New(
+		cache.WithMaximumSize(-1),
+		cache.WithExpireAfterAccess(2*time.Minute),
+	)
+
+	// 充值表 key:playerID, value:*ChargeTable
+	chargeTableCache = cache.New(
+		cache.WithMaximumSize(-1),
+		cache.WithExpireAfterAccess(1*time.Hour),
+	)
+)

+ 85 - 0
sr/nodes/game/internal/db/charge_table.go

@@ -0,0 +1,85 @@
+package db
+
+import (
+	"errors"
+	capp "f1-game/internal/cherry_app"
+	dbFacade "f1-game/internal/component/db/facade"
+	nameDB "f1-game/internal/name/db"
+	dbCharge "f1-game/nodes/game/internal/db/data/charge"
+
+	"go.mongodb.org/mongo-driver/v2/bson"
+	"go.mongodb.org/mongo-driver/v2/mongo"
+
+	clog "github.com/cherry-game/cherry/logger"
+)
+
+// ChargeTable 玩家充值信息表
+type (
+	ChargeTable struct {
+		PlayerID           int64  `bson:"PlayerID,omitempty"`
+		NodeID             string `bson:"NodeID,omitempty"`
+		dbCharge.Data      `bson:"Data,omitempty"`
+		dbFacade.TableBase `bson:",inline"`
+	}
+)
+
+func (*ChargeTable) TableName() string {
+	return nameDB.Table_Charge
+}
+
+func (p *ChargeTable) PrimaryValue() any {
+	return p.PlayerID
+}
+
+func (p *ChargeTable) CheckField() {
+	p.Data.CheckField()
+}
+
+func (p *ChargeTable) Save2Queue() {
+	save2Queue(p)
+}
+
+func GetChargeTable(playerID int64) *ChargeTable {
+	if val, ok := chargeTableCache.GetIfPresent(playerID); ok {
+		return val.(*ChargeTable)
+	}
+
+	chargeTable, found := GetChargeTableFromDB(playerID)
+	if found {
+		chargeTableCache.Put(playerID, chargeTable)
+	}
+
+	return chargeTable
+}
+
+func GetChargeTableFromDB(playerID int64) (*ChargeTable, bool) {
+	chargeTable := newChargeTable(playerID)
+	filter := bson.M{
+		nameDB.Field_NodeID:   chargeTable.NodeID,
+		nameDB.Field_PlayerID: chargeTable.PlayerID,
+	}
+
+	err := dbComponent.FindOne(chargeTable, filter)
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			clog.Warnf("[playerID = %d] not found, create new one", playerID)
+			chargeTable.CheckField()
+			return chargeTable, true
+		}
+
+		clog.Errorf("[playerID = %d] db error = %v", playerID, err)
+		return chargeTable, false
+	}
+
+	chargeTable.CheckField()
+
+	return chargeTable, true
+}
+
+func newChargeTable(playerID int64) *ChargeTable {
+	return &ChargeTable{
+		PlayerID: playerID,
+		NodeID:   capp.NodeID(),
+		Data:     dbCharge.NewData(),
+	}
+}

+ 8 - 5
sr/nodes/game/internal/db/data/chapter/chapter.go

@@ -3,6 +3,8 @@ package dbChapter
 import (
 	"f1-game/internal/pb"
 	"f1-game/internal/types"
+
+	ctime "github.com/cherry-game/cherry/extend/time"
 )
 
 type (
@@ -11,7 +13,7 @@ type (
 		LevelID              int32                    `bson:"LevelID,omitempty"`         // 当前关卡ID T-探险-关卡表关卡ID
 		Levels               map[int32]*ChapterLevel  `bson:"Levels,omitempty"`          // 关卡列表 key 关卡ID T-探险-关卡表关卡ID value 关卡数据
 		ChapterRewards       map[int32]*ChapterReward `bson:"ChapterRewards,omitempty"`  // 已领取章节奖励列表 key 章节ID T-探险表章节ID value 章节奖励数据
-		LastRecoverTime      int64                    `bson:"LastRecoverTime,omitempty"` // 上一次精力恢复时间戳 单位秒
+		LastRecoverTime      int64                    `bson:"LastRecoverTime,omitempty"` // 上一次精力恢复时间戳 单位秒 为0则表示精力&精力池都满了
 		FinishChallengeCount int32                    `bson:"ChallengeCount,omitempty"`  // 累计通关次数
 		TotalSweepCount      int32                    `bson:"TotalSweepCount,omitempty"` // 累计扫荡次数
 		BattleLevelID        int32                    `bson:"BattleLevelID,omitempty"`   // 战斗的关卡ID
@@ -31,10 +33,11 @@ type (
 
 func newChapter() Chapter {
 	return Chapter{
-		ChapterID:      0,
-		LevelID:        0,
-		Levels:         map[int32]*ChapterLevel{},
-		ChapterRewards: map[int32]*ChapterReward{},
+		ChapterID:       0,
+		LevelID:         0,
+		Levels:          map[int32]*ChapterLevel{},
+		ChapterRewards:  map[int32]*ChapterReward{},
+		LastRecoverTime: ctime.Now().ToSecond(),
 	}
 }
 

+ 73 - 0
sr/nodes/game/internal/db/data/charge/data.go

@@ -0,0 +1,73 @@
+package dbCharge
+
+import (
+	"f1-game/internal/pb"
+	"f1-game/internal/types"
+)
+
+type (
+	Data struct {
+		TotalAmount int64                   `bson:"TotalAmount,omitempty"` // 累计充值金额
+		Cards       types.Map[int32, *Card] `bson:"Cards,omitempty"`       // 周月卡信息 key:chargeID value:card
+		Golds       types.List[int32]       `bson:"Golds,omitempty"`       // 金币商城充值记录,用来判断首充
+	}
+
+	Card struct {
+		ID         int32 `bson:"id"`         // ID
+		ExpireTime int64 `bson:"expireTime"` // 过期时间戳 单位毫秒
+		IsReceive  bool  `bson:"isReceive"`  // 今日是否已领取
+	}
+)
+
+func NewData() Data {
+	return Data{
+		Cards: types.NewMap[int32, *Card](),
+		Golds: types.NewList[int32](),
+	}
+}
+
+func (p *Data) CheckField() {
+	if p.Cards == nil {
+		p.Cards = types.NewMap[int32, *Card]()
+	}
+
+	if p.Golds == nil {
+		p.Golds = types.NewList[int32]()
+	}
+}
+func (p *Data) DailyReset() {
+	p.Cards.Range(func(_ int32, card *Card) bool {
+		card.IsReceive = false
+		return true
+	})
+}
+
+func NewCard(id int32) *Card {
+	return &Card{
+		ID: id,
+	}
+}
+
+func (p *Card) ToProto() *pb.Card {
+	return &pb.Card{
+		ExpireTime: p.ExpireTime,
+		IsReceive:  p.IsReceive,
+	}
+}
+func (p *Data) ToProto() *pb.ChargeData {
+	proto := &pb.ChargeData{
+		Cards: map[int32]*pb.Card{},
+		Golds: []int32{},
+	}
+
+	p.Cards.Range(func(_ int32, card *Card) bool {
+		proto.Cards[card.ID] = card.ToProto()
+		return true
+	})
+
+	p.Golds.ForEach(func(_ int, id int32) {
+		proto.Golds = append(proto.Golds, id)
+	})
+
+	return proto
+}

+ 0 - 5
sr/nodes/game/internal/db/data/lineup/lineup.go

@@ -1,7 +1,6 @@
 package dbLineup
 
 import (
-	"f1-game/internal/data"
 	"f1-game/internal/pb"
 	"f1-game/internal/types"
 
@@ -125,7 +124,3 @@ func (p Lineup) ToProto() pb.Lineup {
 func (p *Lineup) Clear() {
 	p.Members = []*LineupMember{}
 }
-
-func (p Lineup) IsLineupMemberLimit() bool {
-	return int32(len(p.Members)) >= data.Const.LineupMemberLimit
-}

+ 23 - 9
sr/nodes/game/internal/db/data/player/vip.go

@@ -8,19 +8,21 @@ import (
 
 type (
 	Vip struct {
-		Level              int32       `bson:"Level,omitempty"`              // vip等级
-		Exp                int64       `bson:"Exp,omitempty"`                // vip点数
-		Attrs              types.Attrs `bson:"Attrs,omitempty"`              // 属性
-		ExpireTime         int64       `bson:"ExpireTime,omitempty"`         // VIP过期时间
-		IsDailyBoxReceived bool        `bson:"IsDailyBoxReceived,omitempty"` // 每日免费宝箱是否已领取
-		IsDailyExpReceived bool        `bson:"IsDailyExpReceived,omitempty"` // 每日VIP点数是否已领取
-		IsExpired          bool        `bson:"IsExpired,omitempty"`          // 是否已经过期
+		Level              int32                  `bson:"Level,omitempty"`              // vip等级
+		Exp                int64                  `bson:"Exp,omitempty"`                // vip点数
+		Attrs              types.Attrs            `bson:"Attrs,omitempty"`              // 属性
+		ExpireTime         int64                  `bson:"ExpireTime,omitempty"`         // VIP过期时间
+		IsDailyBoxReceived bool                   `bson:"IsDailyBoxReceived,omitempty"` // 每日免费宝箱是否已领取
+		IsDailyExpReceived bool                   `bson:"IsDailyExpReceived,omitempty"` // 每日VIP点数是否已领取
+		IsExpired          bool                   `bson:"IsExpired,omitempty"`          // 是否已经过期
+		SpecialBoxStates   types.Map[int32, bool] `bson:"SpecialBoxStates,omitempty"`   // 专属宝箱充值状态 key:vip等级 value:是否已领取
 	}
 )
 
 func newVip() Vip {
 	return Vip{
-		Attrs: types.NewAttrs(),
+		Attrs:            types.NewAttrs(),
+		SpecialBoxStates: types.NewMap[int32, bool](),
 	}
 }
 
@@ -28,6 +30,10 @@ func (p *Vip) CheckField() {
 	if p.Attrs == nil {
 		p.Attrs = types.NewAttrs()
 	}
+
+	if p.SpecialBoxStates == nil {
+		p.SpecialBoxStates = types.NewMap[int32, bool]()
+	}
 }
 
 // 每日重置
@@ -38,14 +44,22 @@ func (p *Vip) DailyReset() {
 }
 
 func (p *Vip) ToProto() *pb.VipInfo {
-	return &pb.VipInfo{
+	proto := &pb.VipInfo{
 		Level:              p.Level,
 		Exp:                p.Exp,
 		Attrs:              p.Attrs.ToProto(),
 		ExpireTime:         p.ExpireTime,
 		IsDailyBoxReceived: p.IsDailyBoxReceived,
 		IsDailyExpReceived: p.IsDailyExpReceived,
+		SpecialBoxStates:   map[int32]bool{},
 	}
+
+	p.SpecialBoxStates.Range(func(key int32, value bool) bool {
+		proto.SpecialBoxStates[key] = value
+		return true
+	})
+
+	return proto
 }
 
 // 判断是否已经领取

+ 2 - 0
sr/nodes/game/internal/db/db.go

@@ -24,6 +24,8 @@ func NewGame() *db.Component {
 		&ComplaintTable{},
 		&ChapterTable{},
 		&ShopTable{},
+		&OrderTable{},
+		&ChargeTable{},
 	)
 
 	dbComponent.AddScript(

+ 3 - 4
sr/nodes/pay/internal/db/order_table.go → sr/nodes/game/internal/db/order_table.go

@@ -16,7 +16,6 @@ import (
 
 // OrderTable 充值订单表
 type OrderTable struct {
-	PayNodeID          string                    `bson:"PayNodeID,omitempty"`   // 创建订单的pay节点id
 	OrderID            int64                     `bson:"OrderID,omitempty"`     // 订单唯一id
 	SdkOrderID         string                    `bson:"SdkOrderID,omitempty"`  // sdk平台关联的订单id
 	PID                int32                     `bson:"PID,omitempty"`         // pid
@@ -101,7 +100,7 @@ func GetOrderWithID(orderID int64) *OrderTable {
 	return table
 }
 
-func PaymentOrderIDList(payNodeID string, beforeDay int) []int64 {
+func PaymentOrderIDList(gameNodeID string, beforeDay int) []int64 {
 	var (
 		ctx         = context.TODO()
 		now         = ctime.Now() // 当前时间
@@ -112,8 +111,8 @@ func PaymentOrderIDList(payNodeID string, beforeDay int) []int64 {
 	now.SubDays(beforeDay) // 获取x天以前的订单开始取
 
 	filter := bson.M{
-		nameDB.Field_PayNodeID: payNodeID,
-		nameDB.Field_Status:    enum.OrderStatusPayment,
+		nameDB.Field_NodeID: gameNodeID,
+		nameDB.Field_Status: enum.OrderStatusPayment,
 		nameDB.Field_CreateTime: bson.M{
 			"$gte": now.ToMillisecond(),
 		},

+ 1 - 0
sr/nodes/game/internal/facade/define.go

@@ -18,6 +18,7 @@ var (
 	Chat   chat   // 聊天
 	Lineup lineup // 部队
 	Vip    vip    // 会员
+	Charge charge // 充值
 )
 var (
 	playerServiceList []facade.IPlayerService[*db.PlayerTable]

+ 5 - 0
sr/nodes/game/internal/facade/facade.go

@@ -69,3 +69,8 @@ type vip interface {
 	AddExp(playerID int64, exp int64) int32
 	AddDay(playerID int64, day int32) int32
 }
+
+type charge interface {
+	facade.IPlayerService[*db.PlayerTable]
+	ChargePush(playerID int64)
+}

+ 3 - 0
sr/nodes/game/internal/facade/init/init.go

@@ -5,6 +5,7 @@ import (
 	"f1-game/nodes/game/player/achieve"
 	"f1-game/nodes/game/player/asset"
 	"f1-game/nodes/game/player/chapter"
+	"f1-game/nodes/game/player/charge"
 	"f1-game/nodes/game/player/chat"
 	"f1-game/nodes/game/player/currency"
 	"f1-game/nodes/game/player/equip"
@@ -36,6 +37,7 @@ func onLoad() {
 	gameFacade.Chat = chat.Service()
 	gameFacade.Lineup = lineup.Service()
 	gameFacade.Vip = vip.Service()
+	gameFacade.Charge = charge.Service()
 }
 
 func onRegister() {
@@ -54,6 +56,7 @@ func onRegister() {
 	gameFacade.ServiceRegister(marquee.Service())
 	gameFacade.ServiceRegister(mainQuest.Service())
 	gameFacade.ServiceRegister(vip.Service())
+	gameFacade.ServiceRegister(charge.Service())
 	gameFacade.ServiceRegister(online.Service()) // online 放最后
 	// 玩家登录完成后,才请求地图消息
 	gameFacade.ServiceRegister(gameMap.Service())

+ 3 - 5
sr/nodes/pay/order/actor.go → sr/nodes/game/order/actor.go

@@ -8,11 +8,10 @@ import (
 	nameActor "f1-game/internal/name/actor"
 	nameRemote "f1-game/internal/name/remote"
 	"f1-game/internal/pb"
-	"f1-game/nodes/pay/internal/db"
+	"f1-game/nodes/game/internal/db"
 	"sync/atomic"
 	"time"
 
-	cherryString "github.com/cherry-game/cherry/extend/string"
 	cstring "github.com/cherry-game/cherry/extend/string"
 	ctime "github.com/cherry-game/cherry/extend/time"
 	clog "github.com/cherry-game/cherry/logger"
@@ -67,7 +66,7 @@ func (p *actor) create(req *pb.CreateOrder) (*pb.I64, int32) {
 		return rsp, code.PIDError
 	}
 
-	if cherryString.ToInt32D(req.GameNodeID, 0) < 1 {
+	if cstring.ToInt32D(req.GameNodeID, 0) < 1 {
 		return rsp, code.PlayerOrderCreateFail
 	}
 
@@ -94,7 +93,6 @@ func (p *actor) create(req *pb.CreateOrder) (*pb.I64, int32) {
 		DayTotal:    ctime.Now().ToShortIntDateFormat(),
 		PaymentTime: 0,
 		DeliverTime: 0,
-		PayNodeID:   p.App().NodeID(), //记录当前节点id
 		Origin:      0,
 		Extra:       req.Extra,
 	}
@@ -109,7 +107,7 @@ func (p *actor) create(req *pb.CreateOrder) (*pb.I64, int32) {
 		p.deliver2Child(table)
 	}
 
-	clog.Infof("[create] orderID = %d, playerID = %d, gameNodeID = %d, status = %d, amount =%v, chargeID =%d, extra = %v",
+	clog.Infof("[create] orderID = %d, playerID = %d, gameNodeID = %s, status = %d, amount =%v, chargeID =%d, extra = %v",
 		table.OrderID,
 		table.PlayerID,
 		table.GameNodeID,

+ 2 - 12
sr/nodes/pay/order/actor_deliver.go → sr/nodes/game/order/actor_deliver.go

@@ -6,7 +6,7 @@ import (
 	nameActor "f1-game/internal/name/actor"
 	nameRemote "f1-game/internal/name/remote"
 	"f1-game/internal/pb"
-	"f1-game/nodes/pay/internal/db"
+	"f1-game/nodes/game/internal/db"
 
 	ctime "github.com/cherry-game/cherry/extend/time"
 	cfacade "github.com/cherry-game/cherry/facade"
@@ -63,10 +63,9 @@ func (p *actorDeliver) chargeDeliver(orderTable *db.OrderTable) bool {
 	}
 
 	// 发货到game节点
-	rsp := &pb.I32{}
 
 	targetPath := cfacade.NewChildPath(orderTable.GameNodeID, nameActor.GamePlayer, orderTable.PlayerID)
-	if errCode := p.CallWait(targetPath, nameRemote.Player_ChargeDeliver, req, rsp); code.IsFail(errCode) {
+	if errCode := p.CallWait(targetPath, nameRemote.Player_ChargeDeliver, req, nil); code.IsFail(errCode) {
 		clog.Warnf("[chargeDeliver] fail. [orderID = %d, errCode = %v, order = %+v]",
 			orderTable.OrderID,
 			errCode,
@@ -75,14 +74,5 @@ func (p *actorDeliver) chargeDeliver(orderTable *db.OrderTable) bool {
 		return false
 	}
 
-	if code.IsFail(rsp.Value) {
-		clog.Warnf("[chargeDeliver] fail. [orderID = %d, rspCode = %v, order = %+v]",
-			orderTable.OrderID,
-			rsp.Value,
-			orderTable,
-		)
-		return false
-	}
-
 	return true
 }

+ 2 - 0
sr/nodes/game/player/actor_player.go

@@ -235,6 +235,8 @@ func (p *actorPlayer) onReset(playerTable *db.PlayerTable, byLogin bool) {
 
 	// 发送跨天重置事件
 	p.PostEvent(event.NewPlayerReset(p.playerID))
+
+	p.Warn("daily reset finish. playerID=%d", p.playerID)
 }
 
 // onEnterEnd 推送各模块数据给客户端

+ 11 - 8
sr/nodes/game/player/asset/origin/origin.go

@@ -48,14 +48,17 @@ var (
 
 	TeamEnergyReoveryCost Origin = newOrigin(1101, "队伍体力恢复消耗")
 
-	ChapterStarRewardGet        Origin = newOrigin(1200, "探险累计星级奖励")
-	ChapterLevelSweepCost       Origin = newOrigin(1201, "探险关卡扫荡消耗")
-	ChapterLevelChallengeCost   Origin = newOrigin(1202, "探险关卡挑战消耗")
-	ChapterLevelFirstReward     Origin = newOrigin(1203, "探险关卡首胜奖励")
-	ChapterLevelChallengeReward Origin = newOrigin(1204, "探险关卡挑战奖励")
-	ChapterStaminaRecoverReward Origin = newOrigin(1205, "探险体力恢复获得")
-	ChapterLevelTimesBuyCost    Origin = newOrigin(1206, "探险挑战次数购买消耗")
-	ChapterLevelSweepReward     Origin = newOrigin(1207, "探险关卡扫荡奖励")
+	ChapterStarRewardGet            Origin = newOrigin(1200, "探险累计星级奖励")
+	ChapterLevelSweepCost           Origin = newOrigin(1201, "探险关卡扫荡消耗")
+	ChapterLevelChallengeCost       Origin = newOrigin(1202, "探险关卡挑战消耗")
+	ChapterLevelFirstReward         Origin = newOrigin(1203, "探险关卡首胜奖励")
+	ChapterLevelChallengeReward     Origin = newOrigin(1204, "探险关卡挑战奖励")
+	ChapterStaminaRecoverReward     Origin = newOrigin(1205, "探险精力恢复获得")
+	ChapterLevelTimesBuyCost        Origin = newOrigin(1206, "探险挑战次数购买消耗")
+	ChapterLevelSweepReward         Origin = newOrigin(1207, "探险关卡扫荡奖励")
+	ChapterStaminaPoolRecoverReward Origin = newOrigin(1208, "探险精力池恢复获得")
+	ChapterStaminaTakeOutCost       Origin = newOrigin(1209, "探险精力池取出消耗")
+	ChapterStaminaTakeOutReward     Origin = newOrigin(1210, "探险精力池取出获得")
 
 	QuestReward             Origin = newOrigin(1300, "任务奖励")
 	QuestChapterReward      Origin = newOrigin(1301, "任务章节奖励")

+ 4 - 8
sr/nodes/game/player/asset/type/currency.go

@@ -85,8 +85,8 @@ func (p *Currency) Sub(playerID int64, assets types.Assets, origin ao.Origin, re
 
 func (p *Currency) IsEnough(playerID int64, asset *types.Asset) int32 {
 	itemTable := db.GetItemTable(playerID)
-	currency := itemTable.CurrencyMap.Get(asset.ID)
-	if currency == nil || currency.Num < asset.Num {
+	currencyNum := itemTable.CurrencyMap.Get(asset.ID)
+	if currencyNum < 1 || currencyNum < asset.Num {
 		return code.CurrencyNotEnough
 	}
 
@@ -95,12 +95,8 @@ func (p *Currency) IsEnough(playerID int64, asset *types.Asset) int32 {
 
 func (p *Currency) Get(playerID int64, assetID int32) int64 {
 	itemTable := db.GetItemTable(playerID)
-	currency := itemTable.CurrencyMap.Get(assetID)
-	if currency == nil {
-		return 0
-	}
-
-	return currency.Num
+	currencyNum := itemTable.CurrencyMap.Get(assetID)
+	return currencyNum
 }
 
 func (p *Currency) Push(playerID int64, assets types.Assets) {

+ 132 - 27
sr/nodes/game/player/chapter/service.go

@@ -132,47 +132,91 @@ func (p *service) ChangePush(playerID int64, updateLevelIDs ...int32) {
 
 // 精力定时恢复
 func (p *service) StaminaRecoverTimer(playerID int64, nowSecond int64) {
+	chapterTable := db.GetChapterTable(playerID)
+	// 当前精力/精力池都已满
+	if chapterTable.Chapter.LastRecoverTime <= 0 {
+		return
+	}
+
 	var (
-		chapterTable       = db.GetChapterTable(playerID)
-		staminaID          = data.Const.ChapterStaminaAddValue.ID
-		staminaLimit       = data.Const.ChapterStaminaLimit
-		curStaminaNum      = asset.Service().Get(playerID, staminaID)
-		staminaAddInterval = data.Const.ChapterStaminaAddInterval
+		staminaAddInterval = p.GetStaminaAddInterval(playerID)                // 获取单次精力恢复时间间隔
+		diffSecond         = nowSecond - chapterTable.Chapter.LastRecoverTime // 获取精力恢复间隔
+		addStaminaTimes    = diffSecond / staminaAddInterval                  // 添加精力次数
 	)
 
-	// vip 精力上限加成
-	staminaLimit += vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaLimit)
-	// vip 精力恢复时间加成
-	staminaAddInterval = max(0, staminaAddInterval-vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaRecoverTime))
-	// 当前精力已满
-	if curStaminaNum >= staminaLimit {
+	// 需要恢复精力数量<=0 跳过
+	if addStaminaTimes <= 0 {
 		return
 	}
 
-	diffSecond := nowSecond - chapterTable.Chapter.LastRecoverTime
-	// 添加精力次数
-	addStaminaTimes := diffSecond / staminaAddInterval
-	if addStaminaTimes <= 0 {
-		return
+	var (
+		staminaID          = data.Const.ChapterStaminaAddValue.ID
+		staminaLimit       = p.GetStaminaLimit(playerID)
+		curStaminaNum      = asset.Service().Get(playerID, staminaID)
+		addStaminaNum      = addStaminaTimes * data.Const.ChapterStaminaAddValue.Num // 添加精力数量
+		finalAddStaminaNum = addStaminaNum                                           // 最终恢复精力数量
+		staminaFull        = curStaminaNum >= staminaLimit
+	)
+
+	// 当前精力未满 恢复精力
+	if !staminaFull {
+		// 恢复精力超出上限
+		if curStaminaNum+finalAddStaminaNum > staminaLimit {
+			finalAddStaminaNum = staminaLimit - curStaminaNum
+			staminaFull = true
+		}
+
+		_, errCode := asset.Service().Add(playerID, staminaID, finalAddStaminaNum, ao.ChapterStaminaRecoverReward, true)
+		if code.IsFail(errCode) {
+			clog.Warnf("[StaminaRecoverTimer] recover stamina fail, playerID = %d, errCode = %d", playerID, errCode)
+			return
+		}
+
+		addStaminaNum -= finalAddStaminaNum
 	}
 
-	// 添加精力数量
-	addStaminaNum := addStaminaTimes * data.Const.ChapterStaminaAddValue.Num
+	// 当前仍有精力需要恢复 恢复精力池精力
+	if addStaminaNum > 0 {
+		var (
+			curStaminaPoolValue = asset.Service().Get(playerID, enum.ItemIDTempStamina)
+			staminaPoolLimit    = p.GetStaminaPoolLimit(playerID)
+		)
+
+		// 当前精力池精力未满
+		if curStaminaPoolValue < staminaPoolLimit {
+			// 如果超出精力池上限 超出部分直接舍弃
+			if curStaminaPoolValue+addStaminaNum > staminaPoolLimit {
+				addStaminaNum = staminaPoolLimit - curStaminaPoolValue
+			}
+
+			_, errCode := asset.Service().Add(playerID, enum.ItemIDTempStamina, addStaminaNum, ao.ChapterStaminaRecoverReward, true)
+			if code.IsFail(errCode) {
+				clog.Warnf("[StaminaRecoverTimer] recover temp stamina fail, playerID = %d, errCode = %d", playerID, errCode)
+				return
+			}
+
+			finalAddStaminaNum += addStaminaNum
+		}
+	}
 
-	// 超出上限
-	if curStaminaNum+addStaminaNum > staminaLimit {
-		addStaminaNum = staminaLimit - curStaminaNum
+	update := false
+	// 发生精力池精力恢复
+	if finalAddStaminaNum > 0 {
+		// 更新最近一次恢复时间
+		chapterTable.Chapter.LastRecoverTime += addStaminaTimes * staminaAddInterval
+		update = true
 	}
 
-	_, errCode := asset.Service().Add(playerID, staminaID, addStaminaNum, ao.ChapterStaminaRecoverReward, true)
-	if code.IsFail(errCode) {
-		clog.Warnf("[StaminaRecoverTimer] recover stamina fail, playerID = %d, errCode = %d", playerID, errCode)
-		return
+	// 精力和精力池都到达上限 重置上一次恢复时间
+	if staminaFull && p.IsStaminaPoolFull(playerID) {
+		chapterTable.Chapter.LastRecoverTime = 0
+		update = true
 	}
 
-	chapterTable.Chapter.LastRecoverTime += addStaminaNum * data.Const.ChapterStaminaAddInterval
+	if update {
+		chapterTable.Save2Queue()
+	}
 
-	chapterTable.Save2Queue()
 }
 
 // 检测更新下一章节或者下一关
@@ -267,3 +311,64 @@ func (p *service) GetChapterBattleCampParam(playerID int64, lineupID int32) (*pb
 
 	return ret, code.OK
 }
+
+// 获取精力上限
+func (p *service) GetStaminaLimit(playerID int64) int64 {
+	staminalLimit := data.Const.ChapterStaminaLimit
+
+	// vip 精力上限加成
+	staminalLimit += vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaLimit)
+
+	return staminalLimit
+}
+
+// 获取精力池上限
+func (p *service) GetStaminaPoolLimit(playerID int64) int64 {
+	playerTable, found := db.GetPlayerTable(playerID)
+	if !found {
+		return 0
+	}
+
+	staminaPoolLimit := int64(0)
+	// 领主等级加成
+	lordLevelRow, found := data.LordLevel.GetByLevel(playerTable.Lord.Level)
+	if found {
+		staminaPoolLimit += lordLevelRow.StaminaPoolLimit
+	}
+
+	// vip 精力池上限加成
+	staminaPoolLimit += vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaLimit)
+
+	return staminaPoolLimit
+}
+
+// 获取精力恢复的时间间隔
+func (p *service) GetStaminaAddInterval(playerID int64) int64 {
+	staminalAddInterval := data.Const.ChapterStaminaAddInterval
+
+	// vip 精力恢复时间加成(减少时间间隔)
+	staminalAddInterval -= vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaRecoverTime)
+
+	return max(0, staminalAddInterval)
+}
+
+// 检测精力是否已达上限
+func (p *service) IsStaminaFull(playerID int64) bool {
+	// 1.检测当前精力是否是满的
+	var (
+		curStaminaNum = asset.Service().Get(playerID, data.Const.ChapterStaminaAddValue.ID)
+		staminaLimit  = p.GetStaminaLimit(playerID)
+	)
+
+	return curStaminaNum >= staminaLimit
+}
+
+// 检测精力池是否已达上限
+func (p *service) IsStaminaPoolFull(playerID int64) bool {
+	var (
+		curStaminaPoolValue = asset.Service().Get(playerID, enum.ItemIDTempStamina)
+		staminaPoolLimit    = p.GetStaminaPoolLimit(playerID)
+	)
+
+	return curStaminaPoolValue >= staminaPoolLimit
+}

+ 26 - 0
sr/nodes/game/player/charge/service.go

@@ -2,6 +2,13 @@ package charge
 
 import (
 	"f1-game/internal/code"
+	"f1-game/internal/facade"
+	nameRoute "f1-game/internal/name/route"
+	"f1-game/internal/sessions"
+	"f1-game/nodes/game/internal/db"
+
+	ctime "github.com/cherry-game/cherry/extend/time"
+	cproto "github.com/cherry-game/cherry/net/proto"
 )
 
 var srv = &service{
@@ -13,6 +20,7 @@ func Service() *service {
 }
 
 type service struct {
+	facade.PlayerServiceBase[*db.PlayerTable]
 	typ serviceType
 }
 
@@ -31,3 +39,21 @@ func (p *service) OnDeliver(playerID int64, chargeID, chargeType, chargeParams i
 
 	return code.PayChargeParamsError
 }
+
+func (p *service) OnReset(playerTable *db.PlayerTable, _ *ctime.CherryTime, _ bool) {
+	chargeTable := db.GetChargeTable(playerTable.PlayerID)
+	chargeTable.DailyReset()
+	chargeTable.Save2Queue()
+}
+
+func (p *service) Push(playerTable *db.PlayerTable, session *cproto.Session) {
+	chargeTable := db.GetChargeTable(playerTable.PlayerID)
+	sessions.PushWithSession(session, nameRoute.PushGamePlayer_ChargeData, chargeTable.Data.ToProto())
+}
+
+func (p *service) ChargePush(playerID int64) {
+	if session, found := sessions.GetSession(playerID); found {
+		playerTable, _ := db.GetPlayerTable(playerID)
+		p.Push(playerTable, session)
+	}
+}

+ 5 - 5
sr/nodes/game/player/charge/service_type.go

@@ -1,8 +1,6 @@
 package charge
 
-import (
-	chargeType "f1-game/nodes/game/player/charge/type"
-)
+import chargeType "f1-game/nodes/game/player/charge/type"
 
 // typeParser 充值类型解析器
 type (
@@ -33,7 +31,9 @@ func (p serviceType) get(chargeType int32) (typeParser, bool) {
 }
 
 func (p serviceType) load() {
-	//p.register(&chargeType.Card{})
+	p.register(&chargeType.Card{})
+	p.register(&chargeType.Gold{})
+	p.register(&chargeType.Vip{})
 	//p.register(&chargeType.Fund{})
-	p.register(&chargeType.FirstCharge{})
+	// p.register(&chargeType.FirstCharge{})
 }

+ 86 - 66
sr/nodes/game/player/charge/type/card.go

@@ -1,68 +1,88 @@
 package chargeType
 
-//// Card 特权卡
-//type Card struct {
-//}
-//
-//func (*Card) Type() int32 {
-//	return enum.ChargeTypeCard
-//}
-//
-//// OnCheck 创建支付订单时,验证支付项
-//func (*Card) OnCheck(playerID int64, chargeID, chargeParams int32) int32 {
-//	row, found := data.WelfareCard.Get(chargeParams)
-//	if !found {
-//		return code.PayChargeParamsError
-//	}
-//
-//	if row.ChargeID != chargeID {
-//		return code.PayChargeIDError
-//	}
-//
-//	if row.Day == -1 {
-//		welfareTable := db.GetWelfareTable(playerID)
-//		_, ok := welfareTable.Cards[row.ID]
-//		if ok {
-//			return code.PayChargeLimit
-//		}
-//	}
-//
-//	return code.OK
-//}
-//
-//// OnDeliver 订单发货时(可做奖劢返回)
-//func (*Card) OnDeliver(playerID int64, chargeID, chargeParams int32) int32 {
-//	row, found := data.WelfareCard.Get(chargeParams)
-//	if !found {
-//		return code.PayChargeParamsError
-//	}
-//
-//	if row.ChargeID != chargeID {
-//		return code.PayChargeIDError
-//	}
-//
-//	welfareTable := db.GetWelfareTable(playerID)
-//	card, ok := welfareTable.Cards[row.ID]
-//	if !ok {
-//		newCard := dbWelfare.NewCard(row.ID)
-//		card = &newCard
-//		welfareTable.Cards[row.ID] = card
-//	}
-//
-//	if row.Day == -1 {
-//		card.DayRemain = -1
-//	} else {
-//		card.DayRemain += row.Day
-//	}
-//
-//	welfareTable.Save2Queue()
-//
-//	//facade.Welfare.CardPush(playerID)
-//
-//	// 发邮件
-//	if len(row.Rewards) > 0 {
-//		gameFacade.Mail.SendTemplate(playerID, row.MailID, nil, row.Rewards.ToProto()...)
-//	}
-//
-//	return code.OK
-//}
+import (
+	"f1-game/internal/code"
+	"f1-game/internal/data"
+	"f1-game/internal/enum"
+	"f1-game/nodes/game/internal/db"
+	dbCharge "f1-game/nodes/game/internal/db/data/charge"
+	gameFacade "f1-game/nodes/game/internal/facade"
+	ao "f1-game/nodes/game/player/asset/origin"
+
+	ctime "github.com/cherry-game/cherry/extend/time"
+)
+
+// Card 周月卡
+type Card struct {
+}
+
+func (*Card) Type() int32 {
+	return enum.ChargeTypeCard
+}
+
+// OnCheck 创建支付订单时,验证支付项
+func (*Card) OnCheck(playerID int64, chargeID, chargeParams int32) int32 {
+	row, found := data.ShopCard.GetByID(chargeID)
+	if !found {
+		return code.ConfigNotFound_ShopCard
+	}
+
+	if row.DayLimit > 0 {
+		chargeTable := db.GetChargeTable(playerID)
+		if card, ok := chargeTable.Cards.Get(chargeID); ok {
+			var (
+				expireTime = ctime.NewMillisecond(card.ExpireTime)
+				now        = ctime.Now()
+			)
+
+			// 如果未过期,且已购买天数大于等于限制天数,则不允许购买
+			if card.ExpireTime > now.ToMillisecond() && now.DiffInDaysWithAbs(&expireTime) >= int64(row.DayLimit) {
+				return code.VipCardDayMaxLimit
+			}
+		}
+	}
+
+	return code.OK
+}
+
+// OnDeliver 订单发货时(可做奖劢返回)
+func (*Card) OnDeliver(playerID int64, chargeID, chargeParams int32) int32 {
+	row, found := data.ShopCard.GetByID(chargeID)
+	if !found {
+		return code.PayChargeParamsError
+	}
+
+	var (
+		chargeTable = db.GetChargeTable(playerID)
+		now         = ctime.Now()
+	)
+
+	card, ok := chargeTable.Cards.Get(chargeID)
+	if !ok {
+		card = dbCharge.NewCard(chargeID)
+		chargeTable.Cards.Put(chargeID, card)
+	}
+
+	// 如果未过期,延长有效期
+	if card.ExpireTime > now.ToMillisecond() {
+		expireTime := ctime.NewMillisecond(card.ExpireTime)
+		expireTime.AddDays(int(row.Day))
+		card.ExpireTime = expireTime.ToMillisecond()
+	} else {
+		// 如果已过期,则直接设置为当前时间加上天数-1
+		now.AddDays(int(row.Day - 1))
+		now = now.EndOfDay()
+		card.ExpireTime = now.ToMillisecond()
+	}
+
+	// 立即获得的奖励
+	if len(row.ChargeRewards) > 0 {
+		gameFacade.Asset.Adds(playerID, row.ChargeRewards, ao.None, true)
+	}
+
+	chargeTable.Save2Queue()
+
+	gameFacade.Charge.ChargePush(playerID)
+
+	return code.OK
+}

+ 55 - 0
sr/nodes/game/player/charge/type/gold.go

@@ -0,0 +1,55 @@
+package chargeType
+
+import (
+	"f1-game/internal/code"
+	"f1-game/internal/data"
+	"f1-game/internal/enum"
+	"f1-game/nodes/game/internal/db"
+	gameFacade "f1-game/nodes/game/internal/facade"
+	ao "f1-game/nodes/game/player/asset/origin"
+)
+
+// Gold 金币商城
+type Gold struct {
+}
+
+func (*Gold) Type() int32 {
+	return enum.ChargeTypeShopGold
+}
+
+// OnCheck 创建支付订单时,验证支付项
+func (*Gold) OnCheck(playerID int64, chargeID, chargeParams int32) int32 {
+	if !data.ShopGold.ContainID(chargeID) {
+		return code.ConfigNotFound_ShopGold
+	}
+
+	return code.OK
+}
+
+// OnDeliver 订单发货时(可做奖劢返回)
+func (*Gold) OnDeliver(playerID int64, chargeID, chargeParams int32) int32 {
+	row, found := data.ShopGold.GetByID(chargeID)
+	if !found {
+		return code.PayChargeParamsError
+	}
+
+	chargeTable := db.GetChargeTable(playerID)
+
+	// 获取的奖励
+	rewards := row.ChargeRewards
+	// 是否有双倍
+	if chargeTable.Golds.Contains(chargeID) {
+		rewards.AddAssets(row.NormalRewards)
+	} else {
+		rewards.AddAssets(row.FirstRewards)
+		// 记录首次状态
+		chargeTable.Golds.Add(chargeID)
+		chargeTable.Save2Queue()
+	}
+
+	gameFacade.Asset.Adds(playerID, rewards, ao.None, true)
+
+	gameFacade.Charge.ChargePush(playerID)
+
+	return code.OK
+}

+ 65 - 0
sr/nodes/game/player/charge/type/vip.go

@@ -0,0 +1,65 @@
+package chargeType
+
+import (
+	"f1-game/internal/code"
+	"f1-game/internal/data"
+	"f1-game/internal/enum"
+	"f1-game/nodes/game/internal/db"
+	gameFacade "f1-game/nodes/game/internal/facade"
+	ao "f1-game/nodes/game/player/asset/origin"
+	"f1-game/nodes/game/player/vip"
+)
+
+// Vip vip专属宝箱
+type Vip struct {
+}
+
+func (*Vip) Type() int32 {
+	return enum.ChargeTypeVip
+}
+
+// OnCheck 创建支付订单时,验证支付项
+func (*Vip) OnCheck(playerID int64, chargeID, chargeParams int32) int32 {
+	row, ok := data.Vip.GetBySpecialBoxChargeID(chargeID)
+	if !ok {
+		return code.ConfigNotFound_VipLevel
+	}
+
+	playerTable, _ := db.GetPlayerTable(playerID)
+	if playerTable.Vip.Level < row.Level {
+		return code.VipLevelNotEnough
+	}
+
+	if playerTable.Vip.SpecialBoxStates.Contains(row.Level) {
+		return code.VipLevelBoxReceived
+	}
+
+	return code.OK
+}
+
+// OnDeliver 订单发货时(可做奖劢返回)
+func (*Vip) OnDeliver(playerID int64, chargeID, chargeParams int32) int32 {
+	row, found := data.Vip.GetBySpecialBoxChargeID(chargeID)
+	if !found {
+		return code.PayChargeParamsError
+	}
+
+	playerTable, _ := db.GetPlayerTable(playerID)
+	if playerTable.Vip.Level < row.Level {
+		return code.VipLevelNotEnough
+	}
+
+	if playerTable.Vip.SpecialBoxStates.Contains(row.Level) {
+		return code.VipLevelBoxReceived
+	}
+
+	// 标记当前VIP等级宝箱为已领取
+	playerTable.Vip.SpecialBoxStates.Put(row.Level, true)
+	playerTable.Save2Queue()
+
+	gameFacade.Asset.Adds(playerID, row.SpecialBox, ao.None, true)
+
+	vip.Service().VipPush(playerTable)
+
+	return code.OK
+}

+ 12 - 8
sr/nodes/game/player/currency/service.go

@@ -69,7 +69,7 @@ func (p *service) ChangePush(playerID int64, idList ...int32) {
 			continue
 		}
 
-		entity := itemTable.CurrencyMap.Get(id)
+		entity := itemTable.CurrencyMap.GetEntity(id)
 		proto := entity.ToProto()
 		rsp.Currencies[entity.ID] = &proto
 	}
@@ -88,8 +88,7 @@ func (p *service) Contain(playerID int64, id int32) int32 {
 		return code.ConfigNotFound_Item
 	}
 
-	entity := itemTable.CurrencyMap.Get(id)
-	if entity.Num < 1 {
+	if itemTable.CurrencyMap.Get(id) < 1 {
 		return code.ItemNotEnough
 	}
 
@@ -98,9 +97,8 @@ func (p *service) Contain(playerID int64, id int32) int32 {
 
 func (p *service) Enough(playerID int64, id int32, num int64) bool {
 	itemTable := db.GetItemTable(playerID)
-
-	entity := itemTable.CurrencyMap.Get(id)
-	if entity.Num < 1 || entity.Num < num {
+	availableNum := itemTable.CurrencyMap.Get(id)
+	if availableNum < 1 || availableNum < num {
 		return false
 	}
 
@@ -156,7 +154,8 @@ func (p *service) Sub(playerID int64, id int32, num int64, origin ao.Origin, sav
 		return code.ConfigNotFound_Item
 	}
 
-	entity, ok := itemTable.CurrencyMap.Decrease(id, num)
+	// 优先扣除绑定资源,再扣除非绑定资源
+	changeAssets, ok := itemTable.CurrencyMap.Decrease(id, num)
 	if !ok {
 		return code.ItemNotEnough
 	}
@@ -165,8 +164,13 @@ func (p *service) Sub(playerID int64, id int32, num int64, origin ao.Origin, sav
 		itemTable.Save2Queue()
 	}
 
+	var changeIDList []int32
+	for _, asset := range changeAssets {
+		changeIDList = append(changeIDList, asset.ID)
+	}
+
 	if push {
-		p.ChangePush(playerID, entity.ID)
+		p.ChangePush(playerID, changeIDList...)
 	}
 
 	return code.OK

+ 89 - 0
sr/nodes/game/player/lineup/service.go

@@ -9,7 +9,9 @@ import (
 	"f1-game/internal/sessions"
 	"f1-game/internal/types"
 	"f1-game/nodes/game/internal/db"
+	dbLineup "f1-game/nodes/game/internal/db/data/lineup"
 
+	cslice "github.com/cherry-game/cherry/extend/slice"
 	clog "github.com/cherry-game/cherry/logger"
 	cproto "github.com/cherry-game/cherry/net/proto"
 )
@@ -132,3 +134,90 @@ func (p *service) GetFetterListByHeroList(playerID int64, heroIDList types.Set[i
 
 	return activeFetterIDs
 }
+
+// 检测同队伍是否存在相同英雄
+func (p *service) CheckLineupSameHero(heroTable *db.HeroTable, lineups dbLineup.Lineups, srcLineupID, srcLineupIndex, excludeLineupID, excludeIndex int32, heroIDs ...int32) bool {
+	if len(lineups) <= 0 {
+		return false
+	}
+
+	for _, lineup := range lineups {
+		// 如果排除的位置为0 且 排除的阵容ID相同 则排除整个阵容
+		if excludeIndex == 0 && lineup.LineupID == excludeLineupID {
+			continue
+		}
+
+		for _, member := range lineup.Members {
+			// 如果是不同阵容切换位置 则排除原位置
+			if lineup.LineupID == srcLineupID && member.Index == srcLineupIndex {
+				continue
+			}
+
+			// 排除上阵位置
+			if lineup.LineupID == excludeLineupID && member.Index == excludeIndex {
+				continue
+			}
+
+			hero, ok := heroTable.Heroes.Get(member.HeroGUID)
+			if !ok {
+				// 没找到返回true 防止上阵相同英雄
+				return true
+			}
+
+			if _, ok := cslice.Int32In(hero.HeroID, heroIDs); ok {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+// 更新队伍羁绊列表
+func (p *service) UpdateLineupFetterList(playerID int64, heroTable *db.HeroTable, updateTeams ...*dbLineup.Lineup) {
+	if len(updateTeams) < 1 {
+		return
+	}
+
+	for _, curTeam := range updateTeams {
+		if len(curTeam.Members) < 1 {
+			curTeam.FetterIDs.Clear()
+			continue
+		}
+
+		// 获取英雄列表
+		heroIDSet := types.Set[int32]{}
+		for _, member := range curTeam.Members {
+			curHeroEntity, found := heroTable.Heroes.Get(member.HeroGUID)
+			if found {
+				heroIDSet.Add(curHeroEntity.HeroID)
+			}
+		}
+
+		// 刷新队伍羁绊
+		fetterIDs := p.GetFetterListByHeroList(playerID, heroIDSet)
+		curTeam.FetterIDs = fetterIDs
+	}
+}
+
+// 检测阵容上阵人数是否已达上限
+// index 当前上阵位置
+func (p *service) CheckLineupMemberLimit(playerID int64, curLineup *dbLineup.Lineup, index int32) bool {
+	playerTable, _ := db.GetPlayerTable(playerID)
+
+	lordLevelRow, found := data.LordLevel.GetByLevel(playerTable.Lord.Level)
+	if !found {
+		clog.Warnf("[CheckLineupMemberLimit] lordLevelRow not found, playerID:%d, level:%d", playerID, playerTable.Lord.Level)
+		return true
+	}
+
+	// 判断当前上阵位置是否存在英雄 如果存在
+	memberCount := len(curLineup.Members)
+	_, found = curLineup.GetLineupMember(index)
+	// 上阵的位置不存在英雄 需要加上当前上阵英雄的数量
+	if !found {
+		memberCount++
+	}
+
+	return memberCount > lordLevelRow.LineupMemberLimit
+}

+ 129 - 28
sr/nodes/game/player/player_chapter.go

@@ -8,6 +8,8 @@ import (
 	"f1-game/internal/data"
 	"f1-game/internal/enum"
 	"f1-game/internal/event"
+	"f1-game/internal/extend/math"
+	nameEvent "f1-game/internal/name/event"
 	nameLocal "f1-game/internal/name/local"
 	"f1-game/internal/pb"
 	"f1-game/internal/types"
@@ -18,6 +20,7 @@ import (
 	"time"
 
 	ctime "github.com/cherry-game/cherry/extend/time"
+	cfacade "github.com/cherry-game/cherry/facade"
 	cproto "github.com/cherry-game/cherry/net/proto"
 )
 
@@ -27,6 +30,10 @@ func (p *actorPlayer) initChapter() {
 	p.Local().Register(nameLocal.Player_ChapterLevelSweep, p.chapterLevelSweep)
 	p.Local().Register(nameLocal.Player_ChapterStarReward, p.chapterReward)
 	p.Local().Register(nameLocal.Player_ChapterLevelTimesBuy, p.chapterLevelTimesBuy)
+	p.Local().Register(nameLocal.Player_ChapterLastRecoverTime, p.chapterLastRecoverTime)
+	p.Local().Register(nameLocal.Player_ChapterTakeOutStamina, p.chapterTakeOutStamina)
+
+	p.EventRegister(nameEvent.Vip_LevelUp, p.chapterRefreshEvent)
 }
 
 // 发起探险战斗
@@ -158,21 +165,23 @@ func (p *actorPlayer) chapterLevelSweep(session *cproto.Session, req *pb.I32I32)
 		return
 	}
 
-	// 总挑战次数
-	totalChallengeCount := chapterLevel.DayBuyChallengeCount + chapterLevelRow.DayChallengeCount
+	// 如果存在每日挑战次数上限
+	if chapterLevelRow.DayChallengeCount > 0 {
+		// 总挑战次数
+		totalChallengeCount := chapterLevel.DayBuyChallengeCount + chapterLevelRow.DayChallengeCount
 
-	// 判断条件次数是否满足
-	if !chapterLevel.CheckChallengeCount(sweepNum, totalChallengeCount) {
-		p.ResponseCode(session, code.ChapterLevelCountNotEnough)
-		return
+		// 判断条件次数是否满足
+		if !chapterLevel.CheckChallengeCount(sweepNum, totalChallengeCount) {
+			p.ResponseCode(session, code.ChapterLevelCountNotEnough)
+			return
+		}
 	}
 
 	var (
-		curStaminaValue = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
-		beforeIsFull    = curStaminaValue >= data.Const.ChapterStaminaLimit
+		beforeIsFull = chapterTable.Chapter.LastRecoverTime <= 0
+		costs        = chapterLevelRow.GetChapterLevelCost(sweepNum)
 	)
 
-	costs := chapterLevelRow.GetChapterLevelCost(sweepNum)
 	// 扣除精力
 	_, errCode := asset.Service().Subs(p.playerID, costs, ao.ChapterLevelSweepCost)
 	if code.IsFail(errCode) {
@@ -182,9 +191,8 @@ func (p *actorPlayer) chapterLevelSweep(session *cproto.Session, req *pb.I32I32)
 
 	// 原来是满精力 判断扣除精力后精力是否还满
 	if beforeIsFull {
-		curStaminaValue = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
-		// 体力不满 更新上次精力的恢复时间
-		if curStaminaValue < data.Const.ChapterStaminaLimit {
+		if full := chapter.Service().IsStaminaFull(p.playerID); !full {
+			// 体力不满 更新上次精力的恢复时间
 			chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
 		}
 	}
@@ -344,6 +352,99 @@ func (p *actorPlayer) chapterLevelTimesBuy(session *cproto.Session, req *pb.I32I
 	p.ResponseCode(session, code.OK)
 }
 
+// 精力池上一次恢复时间
+func (p *actorPlayer) chapterLastRecoverTime(session *cproto.Session, _ *pb.None) {
+	chapterTable := p.ChapterTable()
+
+	resp := &pb.I64{
+		Value: chapterTable.Chapter.LastRecoverTime,
+	}
+
+	p.Response(session, resp)
+}
+
+// 取出精力
+func (p *actorPlayer) chapterTakeOutStamina(session *cproto.Session, req *pb.I64) {
+	var (
+		chapterTable = p.ChapterTable()
+		takeOutNum   = req.Value
+	)
+
+	if takeOutNum <= 0 {
+		p.ResponseCode(session, code.IllegalArgument)
+		return
+	}
+
+	// 获取缺少的精力值
+	var (
+		curStaminaNum = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
+		staminaLimit  = chapter.Service().GetStaminaLimit(p.playerID)
+		diffStamina   = staminaLimit - curStaminaNum
+	)
+
+	// 当前精力已满
+	if diffStamina <= 0 {
+		p.ResponseCode(session, code.ChapterStaminaFull)
+		return
+	}
+
+	// 实际取出的精力值
+	takeOutNum = math.Min(takeOutNum, diffStamina)
+
+	// 判断消耗是否足够
+	_, errCode := asset.Service().Sub(p.playerID, enum.ItemIDTempStamina, takeOutNum, ao.ChapterStaminaTakeOutCost)
+	if code.IsFail(errCode) {
+		p.ResponseCode(session, errCode)
+		return
+	}
+
+	// 恢复精力值
+	_, errCode = asset.Service().Add(p.playerID, data.Const.ChapterStaminaAddValue.ID, takeOutNum, ao.ChapterStaminaTakeOutReward, true)
+	if code.IsFail(errCode) {
+		p.ResponseCode(session, errCode)
+		return
+	}
+
+	// 判断是否需要定时恢复精力
+	if chapterTable.Chapter.LastRecoverTime <= 0 {
+		chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
+
+		chapterTable.Save2Queue()
+	}
+
+	resp := &pb.I64I64{
+		Key:   takeOutNum,
+		Value: chapterTable.Chapter.LastRecoverTime,
+	}
+
+	p.Response(session, resp)
+}
+
+// vip升级触发精力恢复检测(vip提升精力&精力池上限)
+func (p *actorPlayer) chapterRefreshEvent(e cfacade.IEventData) {
+	if _, ok := e.(*event.VipLevelUp); !ok {
+		return
+	}
+
+	chapterTable := p.ChapterTable()
+	if chapterTable.Chapter.LastRecoverTime > 0 {
+		return
+	}
+
+	// 精力未满
+	if staminaFull := chapter.Service().IsStaminaFull(p.playerID); !staminaFull {
+		chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
+		chapterTable.Save2Queue()
+		return
+	}
+
+	// 精力池未满
+	if staminaPoolFull := chapter.Service().IsStaminaPoolFull(p.playerID); !staminaPoolFull {
+		chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
+		chapterTable.Save2Queue()
+	}
+}
+
 // 进入探险的检查
 func (p *actorPlayer) CheckChapterEnter(levelID int32) int32 {
 	chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
@@ -375,16 +476,19 @@ func (p *actorPlayer) CheckChapterEnter(levelID int32) int32 {
 		return code.ChapterLevelNotUnlocked
 	}
 
-	// 总挑战次数
-	totalChallengeCount := chapterLevelRow.DayChallengeCount
-	chapterLevel, found := chapterTable.Chapter.GetLevel(levelID)
-	if found {
-		totalChallengeCount += chapterLevel.DayBuyChallengeCount
-	}
+	// 如果存在每日挑战次数上限 判断每日挑战次数是否达到上限
+	if chapterLevelRow.DayChallengeCount > 0 {
+		// 总挑战次数
+		totalChallengeCount := chapterLevelRow.DayChallengeCount
+		chapterLevel, found := chapterTable.Chapter.GetLevel(levelID)
+		if found {
+			totalChallengeCount += chapterLevel.DayBuyChallengeCount
+		}
 
-	// 判断是否存在进入次数 首次挑战也会扣除次数
-	if !chapterTable.Chapter.CheckLevelChallengeCount(levelID, totalChallengeCount) {
-		return code.ChapterLevelCountNotEnough
+		// 判断是否存在进入次数 首次挑战也会扣除次数
+		if !chapterTable.Chapter.CheckLevelChallengeCount(levelID, totalChallengeCount) {
+			return code.ChapterLevelCountNotEnough
+		}
 	}
 
 	// 检测精力是否足够
@@ -413,10 +517,8 @@ func (p *actorPlayer) ChapterBattleResult(session *cproto.Session, result *pb.Ba
 		return nil, code.ConfigNotFound_Chapter
 	}
 
-	var (
-		curStaminaValue = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
-		beforeIsFull    = curStaminaValue >= data.Const.ChapterStaminaLimit
-	)
+	// 扣除体力前是否满体力
+	beforeIsFull := chapterTable.Chapter.LastRecoverTime <= 0
 
 	// 扣除精力
 	_, errCode := asset.Service().Subs(p.playerID, chapterLevelRow.CostStamina, ao.ChapterLevelChallengeCost)
@@ -426,9 +528,8 @@ func (p *actorPlayer) ChapterBattleResult(session *cproto.Session, result *pb.Ba
 
 	// 原来是满体力 判断扣除精力后精力是否还满
 	if beforeIsFull {
-		curStaminaValue = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
-		// 体力不满 更新上次精力的恢复时间
-		if curStaminaValue < data.Const.ChapterStaminaLimit {
+		if full := chapter.Service().IsStaminaFull(p.playerID); !full {
+			// 体力不满 更新上次精力的恢复时间
 			chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
 		}
 	}

+ 63 - 8
sr/nodes/game/player/player_charge.go

@@ -9,18 +9,24 @@ import (
 	sdkKey "f1-game/internal/component/sdk/define/key"
 	"f1-game/internal/constant"
 	"f1-game/internal/data"
+	"f1-game/internal/enum"
 	nameLocal "f1-game/internal/name/local"
 	nameRemote "f1-game/internal/name/remote"
 	"f1-game/internal/pb"
 	"f1-game/internal/sessions"
+	"f1-game/nodes/game/internal/db"
+	gameFacade "f1-game/nodes/game/internal/facade"
+	ao "f1-game/nodes/game/player/asset/origin"
 	"f1-game/nodes/game/player/charge"
 
 	cstring "github.com/cherry-game/cherry/extend/string"
+	ctime "github.com/cherry-game/cherry/extend/time"
 	cproto "github.com/cherry-game/cherry/net/proto"
 )
 
 func (p *actorPlayer) initCharge() {
 	p.Local().Register(nameLocal.Player_ChargeCreate, p.chargeCreate)
+	p.Local().Register(nameLocal.Player_ChargeCardReward, p.chargeCardReward)
 
 	p.Remote().Register(nameRemote.Player_ChargeDeliver, p.chargeDeliver)
 }
@@ -47,13 +53,13 @@ func (p *actorPlayer) chargeCreate(session *cproto.Session, req *pb.ChargeCreate
 	}
 
 	// 根据chargeID,检查充值项
-	errCode := charge.Service().OnCheck(p.playerID, req.ChargeID, req.ChargeType, req.ChargeParams)
+	errCode := charge.Service().OnCheck(p.playerID, req.ChargeID, chargeRow.ChargeType, req.ChargeParams)
 	if code.IsFail(errCode) {
 		p.ResponseCode(session, errCode)
 		return
 	}
 
-	// 通过pay节点创建订单,返回订单id
+	// 通过order actor 创建订单,返回订单id
 	orderID, errCode := p.createPayOrder(session, req, chargeRow)
 	if code.IsFail(errCode) {
 		p.ResponseCode(session, errCode)
@@ -96,18 +102,62 @@ func (p *actorPlayer) createPayOrder(session *cproto.Session, req *pb.ChargeCrea
 		ClientOS:   0, // 需要在玩家登录的时候带入到session里,然后直接读取
 		Ip:         session.Ip,
 		Extra: map[string]string{
-			constant.ChargeKeyType:   cstring.ToString(req.ChargeType),
-			constant.ChargeKeyParams: cstring.ToString(req.ChargeParams),
+			constant.ChargeKeyType:       cstring.ToString(chargeRow.ChargeType),
+			constant.ChargeKeyParams:     cstring.ToString(req.ChargeParams),
+			constant.ChargeKeyGameNodeID: cstring.ToString(playerTable.NodeID),
 		},
 	}
 
-	// 调用pay node创建订单ID信息,下发给客户端
-	return actorRemote.PayOrder.Create(createOrder)
+	// 调用order actor 创建订单ID信息,下发给客户端
+	return actorRemote.GameOrder.Create(createOrder)
+}
+
+// 每日周月卡奖励领取
+func (p *actorPlayer) chargeCardReward(session *cproto.Session, req *pb.I32) {
+	cardID := req.Value
+	if cardID < 1 {
+		p.ResponseCode(session, code.IllegalArgument)
+		return
+	}
+
+	row, ok := data.ShopCard.GetByID(cardID)
+	if !ok {
+		p.ResponseCode(session, code.ConfigNotFound_ShopCard)
+		return
+	}
+
+	chargeTable := db.GetChargeTable(p.playerID)
+
+	card, ok := chargeTable.Cards.Get(cardID)
+	if !ok {
+		p.ResponseCode(session, code.IllegalArgument)
+		return
+	}
+
+	if card.ExpireTime < ctime.Now().ToMillisecond() {
+		p.ResponseCode(session, code.VipCardExpired)
+		return
+	}
+
+	if card.IsReceive {
+		p.ResponseCode(session, code.VipCardAlreadyReceived)
+		return
+	}
+
+	// 先保存,再发放奖励
+	card.IsReceive = true
+	chargeTable.Save2Queue()
+
+	gameFacade.Asset.Adds(p.playerID, row.DayRewards, ao.None, true)
+
+	p.ResponseCode(session, code.OK)
+
+	p.Debug("[chargeCardReward] receive success. playerID = %d, cardID = %d", p.playerID, cardID)
 }
 
 // chargeDeliver 充值项订单发货 {server-id}.player.orderDeliver
 func (p *actorPlayer) chargeDeliver(req *pb.OrderDeliver) int32 {
-	_, found := data.Charge.GetByID(req.ChargeID)
+	chargeRow, found := data.Charge.GetByID(req.ChargeID)
 	if !found {
 		return code.PayChargeIDError
 	}
@@ -117,7 +167,7 @@ func (p *actorPlayer) chargeDeliver(req *pb.OrderDeliver) int32 {
 	}
 
 	chargeType, ok := req.GetExtraI32(constant.ChargeKeyType)
-	if !ok {
+	if !ok || chargeRow.ChargeType != chargeType {
 		return code.PayChargeTypeError
 	}
 
@@ -131,5 +181,10 @@ func (p *actorPlayer) chargeDeliver(req *pb.OrderDeliver) int32 {
 		p.Warn("[chargeDeliver] OnDeliver fail. req = %v, errCode = %d", req, errCode)
 	}
 
+	// 统一逻辑,加充值积分
+	if chargeRow.ChargePoints > 0 {
+		gameFacade.Asset.Add(p.playerID, enum.ItemIDChargePoint, int64(chargeRow.ChargePoints), ao.None, true)
+	}
+
 	return code.OK
 }

+ 16 - 86
sr/nodes/game/player/player_lineup.go

@@ -6,12 +6,8 @@ import (
 	"f1-game/internal/data"
 	nameLocal "f1-game/internal/name/local"
 	"f1-game/internal/pb"
-	"f1-game/internal/types"
-	"f1-game/nodes/game/internal/db"
-	dbLineup "f1-game/nodes/game/internal/db/data/lineup"
 	"f1-game/nodes/game/player/lineup"
 
-	cslice "github.com/cherry-game/cherry/extend/slice"
 	cproto "github.com/cherry-game/cherry/net/proto"
 )
 
@@ -69,28 +65,28 @@ func (p *actorPlayer) lineupUp(session *cproto.Session, req *pb.LineupUpRequest)
 	}
 
 	// 检测是否上阵相同英雄
-	if p.checkLineupSameHero(heroTable, lineups, 0, 0, lineupID, index, heroEntity.HeroID) {
+	if same := lineup.Service().CheckLineupSameHero(heroTable, lineups, 0, 0, lineupID, index, heroEntity.HeroID); same {
 		p.ResponseCode(session, code.TeamAlreadySameHero)
 		return
 	}
 
 	// 获取阵容数据
-	lineup, found := lineups.GetLineup(lineupID)
+	curLineup, found := lineups.GetLineup(lineupID)
 	if !found {
 		p.ResponseCode(session, code.TeamNotUnlock)
 		return
 	}
 
 	// 获取上阵英雄数据
-	lineupMember, found := lineup.GetLineupMember(index)
+	lineupMember, found := curLineup.GetLineupMember(index)
 	if !found {
 		// 上阵人数已达上限
-		if lineup.IsLineupMemberLimit() {
+		if lineup.Service().CheckLineupMemberLimit(p.playerID, curLineup, index) {
 			p.ResponseCode(session, code.TeamMemberLimit)
 			return
 		}
 
-		lineup.AddLineupMember(index, heroGUID)
+		curLineup.AddLineupMember(index, heroGUID)
 	} else {
 		lineupMember.HeroGUID = heroGUID
 	}
@@ -98,9 +94,9 @@ func (p *actorPlayer) lineupUp(session *cproto.Session, req *pb.LineupUpRequest)
 	teamTable.Save2Queue()
 
 	// 更新阵容羁绊列表
-	p.updateLineupFetterList(lineup)
+	lineup.Service().UpdateLineupFetterList(p.playerID, heroTable, curLineup)
 
-	proto := lineup.ToProto()
+	proto := curLineup.ToProto()
 	resp := &pb.LineupInfo{
 		LineupType: lineupType,
 		Lineup:     &proto,
@@ -124,13 +120,13 @@ func (p *actorPlayer) lineupLeave(session *cproto.Session, req *pb.LineupLeaveRe
 		return
 	}
 
-	lineup, found := lineups.GetLineup(lineupID)
+	curLineup, found := lineups.GetLineup(lineupID)
 	if !found {
 		p.ResponseCode(session, code.TeamNotUnlock)
 		return
 	}
 
-	if !lineup.DelLineupMember(index) {
+	if !curLineup.DelLineupMember(index) {
 		p.ResponseCode(session, code.HeroNotInTeam)
 		return
 	}
@@ -138,9 +134,9 @@ func (p *actorPlayer) lineupLeave(session *cproto.Session, req *pb.LineupLeaveRe
 	teamTable.Save2Queue()
 
 	// 更新阵容羁绊列表
-	p.updateLineupFetterList(lineup)
+	lineup.Service().UpdateLineupFetterList(p.playerID, p.HeroTable(), curLineup)
 
-	proto := lineup.ToProto()
+	proto := curLineup.ToProto()
 	resp := &pb.LineupInfo{
 		LineupType: lineupType,
 		Lineup:     &proto,
@@ -203,7 +199,8 @@ func (p *actorPlayer) lineupChange(session *cproto.Session, req *pb.LineupChange
 	}
 
 	//不同队伍 检测是否上阵相同英雄
-	if srcLineupID != dstLineupID && p.checkLineupSameHero(heroTable, lineups, srcLineupID, srcIndex, dstLineupID, dstIndex, srcHero.HeroID) {
+	if srcLineupID != dstLineupID &&
+		lineup.Service().CheckLineupSameHero(heroTable, lineups, srcLineupID, srcIndex, dstLineupID, dstIndex, srcHero.HeroID) {
 		p.ResponseCode(session, code.TeamAlreadySameHero)
 		return
 	}
@@ -213,8 +210,8 @@ func (p *actorPlayer) lineupChange(session *cproto.Session, req *pb.LineupChange
 	if found {
 		dstLineupMember.HeroGUID = srcLineupMember.HeroGUID
 	} else {
-		// 判断人数是否上限
-		if dstLineup.IsLineupMemberLimit() {
+		// 上阵人数已达上限
+		if lineup.Service().CheckLineupMemberLimit(p.playerID, dstLineup, dstIndex) {
 			p.ResponseCode(session, code.TeamMemberLimit)
 			return
 		}
@@ -228,7 +225,7 @@ func (p *actorPlayer) lineupChange(session *cproto.Session, req *pb.LineupChange
 	teamTable.Save2Queue()
 
 	// 更新阵容羁绊列表
-	p.updateLineupFetterList(srcLineup, dstLineup)
+	lineup.Service().UpdateLineupFetterList(p.playerID, heroTable, srcLineup, dstLineup)
 
 	// 同步给客户端
 	lineup.Service().LineupChangePush(p.playerID, lineupType, srcLineupID, dstLineupID)
@@ -294,70 +291,3 @@ func (p *actorPlayer) lineupAdjust(session *cproto.Session, req *pb.LineupAdjust
 
 	p.Response(session, resp)
 }
-
-// 检测同队伍是否存在相同英雄
-func (p *actorPlayer) checkLineupSameHero(heroTable *db.HeroTable, lineups dbLineup.Lineups, srcLineupID, srcLineupIndex, excludeLineupID, excludeIndex int32, heroIDs ...int32) bool {
-	if len(lineups) <= 0 {
-		return false
-	}
-
-	for _, lineup := range lineups {
-		// 如果排除的位置为0 且 排除的阵容ID相同 则排除整个阵容
-		if excludeIndex == 0 && lineup.LineupID == excludeLineupID {
-			continue
-		}
-
-		for _, member := range lineup.Members {
-			// 如果是不同阵容切换位置 则排除原位置
-			if lineup.LineupID == srcLineupID && member.Index == srcLineupIndex {
-				continue
-			}
-
-			// 排除上阵位置
-			if lineup.LineupID == excludeLineupID && member.Index == excludeIndex {
-				continue
-			}
-
-			hero, ok := heroTable.Heroes.Get(member.HeroGUID)
-			if !ok {
-				// 没找到返回true 防止上阵相同英雄
-				return true
-			}
-
-			if _, ok := cslice.Int32In(hero.HeroID, heroIDs); ok {
-				return true
-			}
-		}
-	}
-
-	return false
-}
-
-// 更新队伍羁绊列表
-func (p *actorPlayer) updateLineupFetterList(updateTeams ...*dbLineup.Lineup) {
-	if len(updateTeams) < 1 {
-		return
-	}
-
-	heroTable := p.HeroTable()
-
-	for _, curTeam := range updateTeams {
-		if len(curTeam.Members) < 1 {
-			curTeam.FetterIDs.Clear()
-			continue
-		}
-
-		// 获取英雄列表
-		heroIDSet := types.Set[int32]{}
-		for _, member := range curTeam.Members {
-			curHeroEntity, found := heroTable.Heroes.Get(member.HeroGUID)
-			if found {
-				heroIDSet.Add(curHeroEntity.HeroID)
-			}
-		}
-
-		// 刷新队伍羁绊
-		fetterIDs := lineup.Service().GetFetterListByHeroList(p.playerID, heroIDSet)
-		curTeam.FetterIDs = fetterIDs
-	}
-}

+ 2 - 1
sr/nodes/game/player/player_timer.go

@@ -1,6 +1,7 @@
 package player
 
 import (
+	"f1-game/internal/data"
 	"f1-game/nodes/game/player/chapter"
 	"f1-game/nodes/game/player/lord"
 	"f1-game/nodes/game/player/vip"
@@ -15,7 +16,7 @@ func (p *actorPlayer) startTimer() {
 	//移除所有定时器
 	p.Timer().RemoveAll()
 	// 添加跨天定时器
-	p.Timer().AddFixedHour(0, 0, 0, p.onCrossDayTimer)
+	p.Timer().AddFixedHour(int(data.Const.ResetTime), 0, 0, p.onCrossDayTimer)
 	// 添加每秒定时器
 	p.Timer().Add(1*time.Second, p.every1STimer)
 	// 资源定时器

+ 54 - 14
sr/nodes/game/player/player_vip.go

@@ -7,20 +7,21 @@ import (
 	nameLocal "f1-game/internal/name/local"
 	"f1-game/internal/pb"
 	gameFacade "f1-game/nodes/game/internal/facade"
-	assetOrigin "f1-game/nodes/game/player/asset/origin"
+	ao "f1-game/nodes/game/player/asset/origin"
 
 	cproto "github.com/cherry-game/cherry/net/proto"
 )
 
 func (p *actorPlayer) initVip() {
-	p.Local().Register(nameLocal.Player_VipDailyReward, p.vipDailyReward)
+	p.Local().Register(nameLocal.Player_VipDailyExpReward, p.vipDailyExpReward)
+	p.Local().Register(nameLocal.Player_VipDailyBoxReward, p.vipDailyBoxReward)
 }
 
-// 领取每日VIP奖励
-func (p *actorPlayer) vipDailyReward(session *cproto.Session, req *pb.I32) {
+// 领取每日VIP点数
+func (p *actorPlayer) vipDailyExpReward(session *cproto.Session, _ *pb.None) {
 	var (
 		playerTable = p.PlayerTable()
-		rewardType  = enum.VipDailyRewardType(req.Value)
+		rewardType  = enum.VipDailyRewardType_Exp
 	)
 
 	if !enum.IsVipDailyRewardType(rewardType) {
@@ -35,18 +36,57 @@ func (p *actorPlayer) vipDailyReward(session *cproto.Session, req *pb.I32) {
 
 	playerTable.Vip.SetReceived(rewardType)
 
-	switch rewardType {
-	case enum.VipDailyRewardType_Exp:
-		if addExp := data.VipDailyExp.GetExpByDay(playerTable.Stats.ContinueLoginDays); addExp > 0 {
-			gameFacade.Vip.AddExp(p.playerID, addExp)
-		}
-	case enum.VipDailyRewardType_Box:
-		if vipRow, found := data.Vip.GetByLevel(playerTable.Vip.Level); found {
-			gameFacade.Asset.Adds(p.playerID, vipRow.DailyBox, assetOrigin.None, true)
-		}
+	if addExp := data.VipDailyExp.GetExpByDay(playerTable.Stats.ContinueLoginDays); addExp > 0 {
+		gameFacade.Vip.AddExp(p.playerID, addExp)
 	}
 
 	playerTable.Save2Queue()
 
 	p.ResponseCode(session, code.OK)
+
+	p.Debug("[vipDailyExpReward] Received success.")
+}
+
+// 领取每日VIP宝箱奖励
+func (p *actorPlayer) vipDailyBoxReward(session *cproto.Session, req *pb.I32) {
+	var (
+		playerTable = p.PlayerTable()
+		level       = req.Value // VIP等级
+		rewardType  = enum.VipDailyRewardType_Box
+	)
+
+	if !enum.IsVipDailyRewardType(rewardType) {
+		p.ResponseCode(session, code.IllegalArgument)
+		return
+	}
+
+	if playerTable.Vip.IsReceived(rewardType) {
+		p.ResponseCode(session, code.VipDailyRewardReceived)
+		return
+	}
+
+	if level == 0 {
+		level = playerTable.Vip.Level
+	}
+
+	vipRow, found := data.Vip.GetByLevel(level)
+	if !found {
+		p.ResponseCode(session, code.ConfigNotFound_VipLevel)
+		return
+	}
+
+	playerTable.Vip.SetReceived(rewardType)
+
+	rewardAssets, errCode := gameFacade.Asset.Adds(p.playerID, vipRow.DailyBox, ao.None, true)
+	if code.IsFail(errCode) {
+		p.ResponseCode(session, errCode)
+		return
+	}
+
+	playerTable.Save2Queue()
+
+	rsp := rewardAssets.ToAssetListProto()
+	p.Response(session, &rsp)
+
+	p.Debug("[vipDailyBoxReward] Received success. level = %d", level)
 }

+ 6 - 0
sr/nodes/game/player/vip/service.go

@@ -50,6 +50,12 @@ func (p *service) Push(playerTable *db.PlayerTable, session *cproto.Session) {
 	sessions.PushWithSession(session, nameRoute.PushGamePlayer_VipInfo, proto)
 }
 
+func (p *service) VipPush(playerTable *db.PlayerTable) {
+	if session, found := sessions.GetSession(playerTable.PlayerID); found {
+		p.Push(playerTable, session)
+	}
+}
+
 func (p *service) AddExp(playerID int64, exp int64) int32 {
 	var (
 		playerTable, _ = db.GetPlayerTable(playerID)

+ 0 - 228
sr/nodes/logs/8_202603111900.log

@@ -1,228 +0,0 @@
-19:27:39.131	8  INFO 	cherry@v1.4.18/application.go:59	
-
-░█████╗░██╗░░██╗███████╗██████╗░██████╗░██╗░░░██╗
-██╔══██╗██║░░██║██╔════╝██╔══██╗██╔══██╗╚██╗░██╔╝
-██║░░╚═╝███████║█████╗░░██████╔╝██████╔╝░╚████╔╝░
-██║░░██╗██╔══██║██╔══╝░░██╔══██╗██╔══██╗░░╚██╔╝░░
-╚█████╔╝██║░░██║███████╗██║░░██║██║░░██║░░░██║░░░
-░╚════╝░╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚═╝░░░╚═╝░░░ 
-game sever framework @v1.4.18
-
-19:27:39.143	8  INFO 	cherry@v1.4.18/application.go:177	-------------------------------------------------
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:178	[nodeID      = 8] application is starting...
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:179	[nodeType    = game]
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:180	[pid         = 49780]
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:181	[startTime   = 2026-03-11 19:27:39]
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:182	[profilePath = D:\work\f1\server\etc\profile\]
-19:27:39.144	8  INFO 	cherry@v1.4.18/application.go:183	[profileName = hw.json]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:184	[env         = hw]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:185	[debug       = true]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:186	[printLevel  = debug]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:187	[logLevel    = debug]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:188	[stackLevel  = error]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:189	[writeFile   = true]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:190	[serializer  = protobuf]
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:191	-------------------------------------------------
-19:27:39.145	8  INFO 	cherry@v1.4.18/application.go:196	[component = cluster_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = discovery_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = initBeforeFunc] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = gops_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = data_config_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = redis_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = run_check_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = game_db_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = sdk_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:196	[component = actor_component] is added.
-19:27:39.146	8  INFO 	cherry@v1.4.18/application.go:198	-------------------------------------------------
-19:27:39.147	8  INFO 	cherry@v1.4.18/application.go:202	[component = cluster_component] -> OnInit().
-19:27:39.153	8  INFO 	nats/pool.go:50	Nats has connected! [poolSize = 1]
-19:27:39.154	8  INFO 	nats_cluster/cluster.go:59	Nats cluster execute OnInit().
-19:27:39.154	8  INFO 	cherry@v1.4.18/application.go:202	[component = discovery_component] -> OnInit().
-19:27:39.154	8  INFO 	discovery/component.go:45	Select discovery [mode = nats].
-19:27:39.154	8  INFO 	discovery/discovery_master.go:102	[init] Discovery = nats is running.
-19:27:39.154	8  INFO 	cherry@v1.4.18/application.go:202	[component = initBeforeFunc] -> OnInit().
-19:27:39.155	8  INFO 	snowflake/snowflake_default.go:34	[snowflake] nodeValue = 20756, nodeMax = 65535
-19:27:39.155	8  INFO 	cherry@v1.4.18/application.go:202	[component = gops_component] -> OnInit().
-19:27:39.155	8  INFO 	cherry@v1.4.18/application.go:202	[component = data_config_component] -> OnInit().
-19:27:39.156	8  WARN 	discovery/discovery_master.go:177	[sendRegister2Master] Fail. master = master-1, err = nats: no responders available for request
-19:27:39.160	8  INFO 	data-config@v1.4.1/component.go:114	[config = area] loaded. [size = 10]
-19:27:39.161	8  INFO 	data-config@v1.4.1/component.go:114	[config = area_server] loaded. [size = 14]
-19:27:39.163	8  INFO 	data-config@v1.4.1/component.go:114	[config = arm_level] loaded. [size = 6]
-19:27:39.166	8  INFO 	data-config@v1.4.1/component.go:114	[config = arm_type] loaded. [size = 18]
-19:27:39.167	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter] loaded. [size = 8]
-19:27:39.181	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_level] loaded. [size = 64]
-19:27:39.182	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_reward] loaded. [size = 16]
-19:27:39.183	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_star] loaded. [size = 3]
-19:27:39.185	8  INFO 	data-config@v1.4.1/component.go:114	[config = charge] loaded. [size = 10]
-19:27:39.187	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_emoji] loaded. [size = 48]
-19:27:39.187	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_msg_template] loaded. [size = 10]
-19:27:39.188	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_type] loaded. [size = 6]
-19:27:39.190	8  INFO 	data-config@v1.4.1/component.go:114	[config = const] loaded. [size = 1]
-19:27:39.242	8  INFO 	data-config@v1.4.1/component.go:114	[config = drop_pool] loaded. [size = 1742]
-19:27:39.272	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip] loaded. [size = 180]
-19:27:39.276	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip_level] loaded. [size = 42]
-19:27:39.278	8  INFO 	data-config@v1.4.1/component.go:114	[config = exchange_goods] loaded. [size = 4]
-19:27:39.278	8  INFO 	data-config@v1.4.1/component.go:114	[config = exchange_slot] loaded. [size = 4]
-19:27:39.294	8  INFO 	data-config@v1.4.1/component.go:114	[config = proto_route] loaded. [size = 328]
-19:27:39.294	8  INFO 	data-config@v1.4.1/component.go:114	[config = sdk] loaded. [size = 1]
-19:27:39.295	8  INFO 	data-config@v1.4.1/component.go:114	[config = lua] loaded. [size = 2]
-19:27:39.300	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip_attr_extra] loaded. [size = 135]
-19:27:39.301	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility] loaded. [size = 30]
-19:27:39.354	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility_level] loaded. [size = 599]
-19:27:39.354	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility_queue] loaded. [size = 3]
-19:27:39.355	8  INFO 	data-config@v1.4.1/component.go:114	[config = game_debug] loaded. [size = 5]
-19:27:39.355	8  INFO 	data-config@v1.4.1/component.go:114	[config = game_main_quest] loaded. [size = 3]
-19:27:39.356	8  INFO 	data-config@v1.4.1/component.go:114	[config = gen_pool] loaded. [size = 3]
-19:27:39.356	8  INFO 	data-config@v1.4.1/component.go:114	[config = gm] loaded. [size = 1]
-19:27:39.359	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero] loaded. [size = 30]
-19:27:39.359	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_arm_adaptation] loaded. [size = 3]
-19:27:39.362	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_fetter] loaded. [size = 17]
-19:27:39.363	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_level] loaded. [size = 50]
-19:27:39.364	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_star] loaded. [size = 6]
-19:27:39.369	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_star_attrs] loaded. [size = 150]
-19:27:39.369	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_team] loaded. [size = 5]
-19:27:39.397	8  INFO 	data-config@v1.4.1/component.go:114	[config = item] loaded. [size = 451]
-19:27:39.398	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_chest] loaded. [size = 37]
-19:27:39.398	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_craft] loaded. [size = 7]
-19:27:39.399	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_medicine] loaded. [size = 3]
-19:27:39.399	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_attr] loaded. [size = 25]
-19:27:39.400	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_flag] loaded. [size = 24]
-19:27:39.401	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_job] loaded. [size = 13]
-19:27:39.404	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_level] loaded. [size = 20]
-19:27:39.404	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_log] loaded. [size = 23]
-19:27:39.405	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_quest] loaded. [size = 9]
-19:27:39.405	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_storage] loaded. [size = 5]
-19:27:39.406	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_tech] loaded. [size = 13]
-19:27:39.410	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_tech_level] loaded. [size = 66]
-19:27:39.411	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_level] loaded. [size = 50]
-19:27:39.413	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_name] loaded. [size = 120]
-19:27:39.415	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_show] loaded. [size = 38]
-19:27:39.415	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_bulk] loaded. [size = 5]
-19:27:39.416	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_daily] loaded. [size = 7]
-19:27:39.418	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_template] loaded. [size = 54]
-19:27:39.419	8  INFO 	data-config@v1.4.1/component.go:114	[config = main_quest] loaded. [size = 9]
-19:27:39.420	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_county] loaded. [size = 96]
-19:27:39.421	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_province] loaded. [size = 30]
-19:27:39.422	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_state] loaded. [size = 10]
-19:27:39.433	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_build] loaded. [size = 14]
-19:27:39.438	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_build_upgrade] loaded. [size = 95]
-19:27:39.795	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773228458785  heartbeatTimeout:3000]
-19:27:40.165	8  INFO 	discovery/discovery_master.go:184	[sendRegister2Master] OK. master = master-1, member = nodeID:"8"  nodeType:"game"  lastAt:1773228459154  heartbeatTimeout:3000
-19:27:40.165	8  DEBUG	discovery/discovery_default.go:142	Add Duplicate Member. [member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773228459790  heartbeatTimeout:3000]
-19:27:40.166	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"master-1"  nodeType:"master"  lastAt:1773228459648  heartbeatTimeout:3000]
-19:27:40.166	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"8"  nodeType:"game"  lastAt:1773228460161  heartbeatTimeout:3000]
-19:27:40.246	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"web-1"  nodeType:"web"  lastAt:1773228459232  heartbeatTimeout:3000]
-19:27:40.345	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_castle] loaded. [size = 148]
-19:27:40.346	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_id] loaded. [size = 1]
-19:27:40.346	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_main_city_show] loaded. [size = 4]
-19:27:40.346	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_main_quest] loaded. [size = 7]
-19:27:40.347	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_march] loaded. [size = 12]
-19:27:40.348	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_march_state] loaded. [size = 34]
-19:27:40.352	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_monster] loaded. [size = 20]
-19:27:40.352	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_monster_area] loaded. [size = 20]
-19:27:40.354	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_object_type] loaded. [size = 6]
-19:27:40.355	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_redeploy] loaded. [size = 20]
-19:27:40.356	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_res] loaded. [size = 20]
-19:27:40.358	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_res_transport] loaded. [size = 101]
-19:27:40.358	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"map-1"  nodeType:"map"  lastAt:1773228459347  heartbeatTimeout:3000]
-19:27:40.358	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_tile] loaded. [size = 4]
-19:27:40.359	8  INFO 	data-config@v1.4.1/component.go:114	[config = mask_word] loaded. [size = 52]
-19:27:40.629	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"ops-1"  nodeType:"ops"  lastAt:1773228459615  heartbeatTimeout:3000]
-19:27:40.636	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"chat-1"  nodeType:"chat"  lastAt:1773228459624  heartbeatTimeout:3000]
-19:27:40.645	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster] loaded. [size = 2207]
-19:27:40.655	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"center-1"  nodeType:"center"  lastAt:1773228459642  heartbeatTimeout:3000]
-19:27:40.660	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster_group] loaded. [size = 461]
-19:27:40.661	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster_pool] loaded. [size = 58]
-19:27:40.661	8  INFO 	data-config@v1.4.1/component.go:114	[config = node] loaded. [size = 1]
-19:27:40.661	8  INFO 	data-config@v1.4.1/component.go:114	[config = node_state] loaded. [size = 1]
-19:27:40.674	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest] loaded. [size = 172]
-19:27:40.674	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_achieve_pool] loaded. [size = 7]
-19:27:40.674	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_achieve_type] loaded. [size = 2]
-19:27:40.677	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_group] loaded. [size = 54]
-19:27:40.677	8  INFO 	data-config@v1.4.1/component.go:114	[config = rank] loaded. [size = 5]
-19:27:40.678	8  INFO 	data-config@v1.4.1/component.go:114	[config = rate_limiter] loaded. [size = 6]
-19:27:40.678	8  INFO 	data-config@v1.4.1/component.go:114	[config = recruit] loaded. [size = 8]
-19:27:40.679	8  INFO 	data-config@v1.4.1/component.go:114	[config = season] loaded. [size = 5]
-19:27:40.680	8  INFO 	data-config@v1.4.1/component.go:114	[config = season_quest] loaded. [size = 10]
-19:27:40.680	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop] loaded. [size = 6]
-19:27:40.685	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop_goods] loaded. [size = 108]
-19:27:40.687	8  INFO 	data-config@v1.4.1/component.go:114	[config = sign_in] loaded. [size = 60]
-19:27:40.687	8  INFO 	data-config@v1.4.1/component.go:114	[config = sign_in_reward] loaded. [size = 6]
-19:27:40.694	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill] loaded. [size = 266]
-19:27:40.717	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill_level] loaded. [size = 746]
-19:27:40.718	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill_pool] loaded. [size = 13]
-19:27:40.722	8  INFO 	data-config@v1.4.1/component.go:114	[config = vip] loaded. [size = 18]
-19:27:40.723	8  INFO 	data-config@v1.4.1/component.go:114	[config = vip_daily_exp] loaded. [size = 8]
-19:27:40.748	8  INFO 	data/extend_monster_group.go:44	monsterGroupConfig load success, len: 126
-19:27:40.749	8  INFO 	cherry@v1.4.18/application.go:202	[component = redis_component] -> OnInit().
-19:27:40.749	8  INFO 	redis/component.go:78	New redis *client [configID = guid_redis_id, redisID = redis-hw]
-19:27:40.749	8  INFO 	redis/component.go:78	New redis *client [configID = center_redis_id, redisID = redis-hw]
-19:27:40.749	8  INFO 	redis/component.go:78	New redis *client [configID = game_redis_id, redisID = redis-hw]
-19:27:40.749	8  INFO 	redis/component.go:78	New redis *client [configID = chat_redis_id, redisID = redis-hw]
-19:27:40.756	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-19:27:40.759	8  INFO 	redis/guid.go:54	check guid. [current = 1049264]
-19:27:40.761	8  INFO 	redis/guid.go:57	check uid. [current = 1048578]
-19:27:40.766	8  INFO 	redis/guid.go:60	check chatid. [current = 1024]
-19:27:40.769	8  INFO 	redis/guid.go:63	check leagueid. [current = 1874]
-19:27:40.769	8  INFO 	redis/component.go:91	Load [type = *redis.guid, configID = guid_redis_id, redisID = redis-hw]
-19:27:40.769	8  INFO 	redis/component.go:91	Load [type = *redis.center, configID = center_redis_id, redisID = redis-hw]
-19:27:40.769	8  INFO 	redis/component.go:91	Load [type = *redis.chat, configID = chat_redis_id, redisID = redis-hw]
-19:27:40.769	8  INFO 	redis/component.go:91	Load [type = *redis.game, configID = game_redis_id, redisID = redis-hw]
-19:27:40.769	8  INFO 	cherry@v1.4.18/application.go:202	[component = run_check_component] -> OnInit().
-19:27:40.769	8  INFO 	cherry@v1.4.18/application.go:202	[component = game_db_component] -> OnInit().
-19:27:40.796	8  INFO 	mongo@v1.4.1/component.go:124	Ping DB is ok. [dbName = hw-f1-game, host = [192.168.1.232:27017]] 
-19:27:40.796	8  INFO 	mongo@v1.4.1/component.go:84	[dbGroup =db_game_group, dbName = mongo-f1-game] is connected.
-19:27:40.805	8  INFO 	migrator/migrator.go:32	[migrator] [version = 1] skip
-19:27:40.805	8  INFO 	migrator/migrator.go:32	[migrator] [version = 2] skip
-19:27:40.805	8  INFO 	migrator/migrator.go:32	[migrator] [version = 3] skip
-19:27:40.806	8  INFO 	migrator/migrator.go:32	[migrator] [version = 5] skip
-19:27:40.809	8  WARN 	migrator/migrator_table.go:57	mongo: no documents in result
-19:27:40.809	8  INFO 	migrator/migrator.go:134	[migrator] run finished. [executeCount = 0, lastVersion = 0]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = node, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = hero, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = item, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = mail, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = player, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = quest, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = lineup, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = equip, ticker = 1(sec), count = 100]
-19:27:40.810	8  INFO 	queue/table_queue.go:118	add [table = chat, ticker = 1(sec), count = 100]
-19:27:40.811	8  INFO 	queue/table_queue.go:118	add [table = complaint, ticker = 1(sec), count = 100]
-19:27:40.811	8  INFO 	queue/table_queue.go:118	add [table = chapter, ticker = 1(sec), count = 100]
-19:27:40.811	8  INFO 	queue/table_queue.go:118	add [table = shop, ticker = 1(sec), count = 100]
-19:27:40.811	8  INFO 	queue/table_queue.go:138	db queue starting...
-19:27:40.811	8  INFO 	db/component.go:51	[db_id = hw-f1-game] database is init.
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = lineup]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = complaint]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = mail]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = equip]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = node]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = hero]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = player]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = quest]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = item]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = shop]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = chapter]
-19:27:40.811	8  INFO 	queue/table_queue.go:241	run queue for [table = chat]
-19:27:40.821	8  INFO 	db/player_table.go:248	preload player info count = 1
-19:27:40.821	8  INFO 	cherry@v1.4.18/application.go:202	[component = sdk_component] -> OnInit().
-19:27:40.821	8  INFO 	cherry@v1.4.18/application.go:202	[component = actor_component] -> OnInit().
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:205	-------------------------------------------------
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:209	[component = cluster_component] -> OnAfterInit().
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:209	[component = discovery_component] -> OnAfterInit().
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:209	[component = initBeforeFunc] -> OnAfterInit().
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:209	[component = gops_component] -> OnAfterInit().
-19:27:40.822	8  INFO 	cherry@v1.4.18/application.go:209	[component = data_config_component] -> OnAfterInit().
-19:27:40.823	8  INFO 	cherry@v1.4.18/application.go:209	[component = redis_component] -> OnAfterInit().
-19:27:40.823	8  INFO 	cherry@v1.4.18/application.go:209	[component = run_check_component] -> OnAfterInit().
-19:27:40.830	8  INFO 	cherry@v1.4.18/application.go:209	[component = game_db_component] -> OnAfterInit().
-19:27:40.830	8  INFO 	cherry@v1.4.18/application.go:209	[component = sdk_component] -> OnAfterInit().
-19:27:40.830	8  INFO 	cherry@v1.4.18/application.go:209	[component = actor_component] -> OnAfterInit().
-19:27:40.831	8  INFO 	cherry@v1.4.18/application.go:221	-------------------------------------------------
-19:27:40.831	8  INFO 	sessions/actor.go:72	[sessions] actor init success. isSync = true
-19:27:40.831	8  INFO 	ops/actor.go:37	node default state [0]
-19:27:40.831	8  INFO 	cherry@v1.4.18/application.go:222	[spend time = 1688ms] application is running.
-19:27:40.831	8  INFO 	cherry@v1.4.18/application.go:223	-------------------------------------------------
-19:27:40.835	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-19:27:40.838	8  DEBUG	gen_pool/actor.go:168	load redis genPool items. count = 3
-19:27:41.016	8  DEBUG	queue/table_queue.go:296	[table = node, size = 1] queue bulk write.

+ 0 - 259
sr/nodes/logs/8_202603121100.log

@@ -1,259 +0,0 @@
-11:42:08.445	8  INFO 	cherry@v1.4.18/application.go:59	
-
-░█████╗░██╗░░██╗███████╗██████╗░██████╗░██╗░░░██╗
-██╔══██╗██║░░██║██╔════╝██╔══██╗██╔══██╗╚██╗░██╔╝
-██║░░╚═╝███████║█████╗░░██████╔╝██████╔╝░╚████╔╝░
-██║░░██╗██╔══██║██╔══╝░░██╔══██╗██╔══██╗░░╚██╔╝░░
-╚█████╔╝██║░░██║███████╗██║░░██║██║░░██║░░░██║░░░
-░╚════╝░╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚═╝░░░╚═╝░░░ 
-game sever framework @v1.4.18
-
-11:42:08.487	8  INFO 	cherry@v1.4.18/application.go:177	-------------------------------------------------
-11:42:08.487	8  INFO 	cherry@v1.4.18/application.go:178	[nodeID      = 8] application is starting...
-11:42:08.487	8  INFO 	cherry@v1.4.18/application.go:179	[nodeType    = game]
-11:42:08.487	8  INFO 	cherry@v1.4.18/application.go:180	[pid         = 55788]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:181	[startTime   = 2026-03-12 11:42:08]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:182	[profilePath = D:\work\f1\server\etc\profile\]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:183	[profileName = hw.json]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:184	[env         = hw]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:185	[debug       = true]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:186	[printLevel  = debug]
-11:42:08.488	8  INFO 	cherry@v1.4.18/application.go:187	[logLevel    = debug]
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:188	[stackLevel  = error]
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:189	[writeFile   = true]
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:190	[serializer  = protobuf]
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:191	-------------------------------------------------
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:196	[component = cluster_component] is added.
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:196	[component = discovery_component] is added.
-11:42:08.489	8  INFO 	cherry@v1.4.18/application.go:196	[component = initBeforeFunc] is added.
-11:42:08.490	8  INFO 	cherry@v1.4.18/application.go:196	[component = gops_component] is added.
-11:42:08.490	8  INFO 	cherry@v1.4.18/application.go:196	[component = data_config_component] is added.
-11:42:08.490	8  INFO 	cherry@v1.4.18/application.go:196	[component = redis_component] is added.
-11:42:08.491	8  INFO 	cherry@v1.4.18/application.go:196	[component = run_check_component] is added.
-11:42:08.491	8  INFO 	cherry@v1.4.18/application.go:196	[component = game_db_component] is added.
-11:42:08.491	8  INFO 	cherry@v1.4.18/application.go:196	[component = sdk_component] is added.
-11:42:08.491	8  INFO 	cherry@v1.4.18/application.go:196	[component = actor_component] is added.
-11:42:08.491	8  INFO 	cherry@v1.4.18/application.go:198	-------------------------------------------------
-11:42:08.492	8  INFO 	cherry@v1.4.18/application.go:202	[component = cluster_component] -> OnInit().
-11:42:08.506	8  INFO 	nats/pool.go:50	Nats has connected! [poolSize = 1]
-11:42:08.507	8  INFO 	nats_cluster/cluster.go:59	Nats cluster execute OnInit().
-11:42:08.507	8  INFO 	cherry@v1.4.18/application.go:202	[component = discovery_component] -> OnInit().
-11:42:08.507	8  INFO 	discovery/component.go:45	Select discovery [mode = nats].
-11:42:08.507	8  INFO 	discovery/discovery_master.go:102	[init] Discovery = nats is running.
-11:42:08.508	8  INFO 	cherry@v1.4.18/application.go:202	[component = initBeforeFunc] -> OnInit().
-11:42:08.508	8  INFO 	snowflake/snowflake_default.go:34	[snowflake] nodeValue = 20756, nodeMax = 65535
-11:42:08.508	8  INFO 	cherry@v1.4.18/application.go:202	[component = gops_component] -> OnInit().
-11:42:08.509	8  INFO 	cherry@v1.4.18/application.go:202	[component = data_config_component] -> OnInit().
-11:42:08.514	8  INFO 	data-config@v1.4.1/component.go:114	[config = area] loaded. [size = 10]
-11:42:08.515	8  INFO 	data-config@v1.4.1/component.go:114	[config = area_server] loaded. [size = 14]
-11:42:08.517	8  INFO 	data-config@v1.4.1/component.go:114	[config = arm_level] loaded. [size = 6]
-11:42:08.517	8  INFO 	discovery/discovery_master.go:184	[sendRegister2Master] OK. master = master-1, member = nodeID:"8"  nodeType:"game"  lastAt:1773286928507  heartbeatTimeout:3000
-11:42:08.517	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"map-1"  nodeType:"map"  lastAt:1773286928507  heartbeatTimeout:3000]
-11:42:08.517	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773286928470  heartbeatTimeout:3000]
-11:42:08.517	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"8"  nodeType:"game"  lastAt:1773286928512  heartbeatTimeout:3000]
-11:42:08.517	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"master-1"  nodeType:"master"  lastAt:1773286928297  heartbeatTimeout:3000]
-11:42:08.520	8  INFO 	data-config@v1.4.1/component.go:114	[config = arm_type] loaded. [size = 18]
-11:42:08.520	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter] loaded. [size = 8]
-11:42:08.524	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"ops-1"  nodeType:"ops"  lastAt:1773286928516  heartbeatTimeout:3000]
-11:42:08.525	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"chat-1"  nodeType:"chat"  lastAt:1773286928516  heartbeatTimeout:3000]
-11:42:08.540	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_level] loaded. [size = 64]
-11:42:08.543	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_reward] loaded. [size = 16]
-11:42:08.543	8  INFO 	data-config@v1.4.1/component.go:114	[config = chapter_star] loaded. [size = 3]
-11:42:08.545	8  INFO 	data-config@v1.4.1/component.go:114	[config = charge] loaded. [size = 32]
-11:42:08.547	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_emoji] loaded. [size = 48]
-11:42:08.547	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_msg_template] loaded. [size = 10]
-11:42:08.548	8  INFO 	data-config@v1.4.1/component.go:114	[config = chat_type] loaded. [size = 6]
-11:42:08.551	8  INFO 	data-config@v1.4.1/component.go:114	[config = const] loaded. [size = 1]
-11:42:08.619	8  INFO 	data-config@v1.4.1/component.go:114	[config = drop_pool] loaded. [size = 1742]
-11:42:08.653	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip] loaded. [size = 180]
-11:42:08.658	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip_level] loaded. [size = 42]
-11:42:08.660	8  INFO 	data-config@v1.4.1/component.go:114	[config = exchange_goods] loaded. [size = 4]
-11:42:08.661	8  INFO 	data-config@v1.4.1/component.go:114	[config = exchange_slot] loaded. [size = 4]
-11:42:08.689	8  INFO 	data-config@v1.4.1/component.go:114	[config = proto_route] loaded. [size = 328]
-11:42:08.690	8  INFO 	data-config@v1.4.1/component.go:114	[config = sdk] loaded. [size = 1]
-11:42:08.691	8  INFO 	data-config@v1.4.1/component.go:114	[config = lua] loaded. [size = 2]
-11:42:08.698	8  INFO 	data-config@v1.4.1/component.go:114	[config = equip_attr_extra] loaded. [size = 135]
-11:42:08.700	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility] loaded. [size = 30]
-11:42:08.776	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility_level] loaded. [size = 599]
-11:42:08.776	8  INFO 	data-config@v1.4.1/component.go:114	[config = facility_queue] loaded. [size = 3]
-11:42:08.778	8  INFO 	data-config@v1.4.1/component.go:114	[config = game_debug] loaded. [size = 5]
-11:42:08.778	8  INFO 	data-config@v1.4.1/component.go:114	[config = game_main_quest] loaded. [size = 3]
-11:42:08.779	8  INFO 	data-config@v1.4.1/component.go:114	[config = gen_pool] loaded. [size = 3]
-11:42:08.779	8  INFO 	data-config@v1.4.1/component.go:114	[config = gm] loaded. [size = 1]
-11:42:08.783	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero] loaded. [size = 30]
-11:42:08.784	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_arm_adaptation] loaded. [size = 3]
-11:42:08.787	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_fetter] loaded. [size = 17]
-11:42:08.789	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_level] loaded. [size = 50]
-11:42:08.789	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_star] loaded. [size = 6]
-11:42:08.797	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_star_attrs] loaded. [size = 150]
-11:42:08.798	8  INFO 	data-config@v1.4.1/component.go:114	[config = hero_team] loaded. [size = 5]
-11:42:08.837	8  INFO 	data-config@v1.4.1/component.go:114	[config = item] loaded. [size = 452]
-11:42:08.839	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_chest] loaded. [size = 37]
-11:42:08.840	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_craft] loaded. [size = 7]
-11:42:08.840	8  INFO 	data-config@v1.4.1/component.go:114	[config = item_medicine] loaded. [size = 3]
-11:42:08.841	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_attr] loaded. [size = 25]
-11:42:08.842	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_flag] loaded. [size = 24]
-11:42:08.843	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_job] loaded. [size = 13]
-11:42:08.847	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_level] loaded. [size = 20]
-11:42:08.848	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_log] loaded. [size = 23]
-11:42:08.849	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_quest] loaded. [size = 9]
-11:42:08.850	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_storage] loaded. [size = 5]
-11:42:08.850	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_tech] loaded. [size = 13]
-11:42:08.859	8  INFO 	data-config@v1.4.1/component.go:114	[config = league_tech_level] loaded. [size = 66]
-11:42:08.860	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_level] loaded. [size = 50]
-11:42:08.865	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_name] loaded. [size = 120]
-11:42:08.867	8  INFO 	data-config@v1.4.1/component.go:114	[config = lord_show] loaded. [size = 38]
-11:42:08.868	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_bulk] loaded. [size = 5]
-11:42:08.869	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_daily] loaded. [size = 7]
-11:42:08.871	8  INFO 	data-config@v1.4.1/component.go:114	[config = mail_template] loaded. [size = 54]
-11:42:08.872	8  INFO 	data-config@v1.4.1/component.go:114	[config = main_quest] loaded. [size = 9]
-11:42:08.874	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_county] loaded. [size = 96]
-11:42:08.875	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_province] loaded. [size = 30]
-11:42:08.877	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_area_state] loaded. [size = 10]
-11:42:08.893	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_build] loaded. [size = 14]
-11:42:08.899	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_build_upgrade] loaded. [size = 95]
-11:42:09.251	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"web-1"  nodeType:"web"  lastAt:1773286928235  heartbeatTimeout:3000]
-11:42:09.256	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"center-1"  nodeType:"center"  lastAt:1773286928241  heartbeatTimeout:3000]
-11:42:09.867	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_castle] loaded. [size = 148]
-11:42:09.867	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_id] loaded. [size = 1]
-11:42:09.868	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_main_city_show] loaded. [size = 4]
-11:42:09.868	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_main_quest] loaded. [size = 7]
-11:42:09.869	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_march] loaded. [size = 12]
-11:42:09.871	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_march_state] loaded. [size = 34]
-11:42:09.877	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_monster] loaded. [size = 20]
-11:42:09.878	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_monster_area] loaded. [size = 20]
-11:42:09.879	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_object_type] loaded. [size = 6]
-11:42:09.880	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_redeploy] loaded. [size = 20]
-11:42:09.881	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_res] loaded. [size = 20]
-11:42:09.884	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_res_transport] loaded. [size = 101]
-11:42:09.884	8  INFO 	data-config@v1.4.1/component.go:114	[config = map_tile] loaded. [size = 4]
-11:42:09.887	8  INFO 	data-config@v1.4.1/component.go:114	[config = mask_word] loaded. [size = 52]
-11:42:10.280	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster] loaded. [size = 2207]
-11:42:10.303	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster_group] loaded. [size = 461]
-11:42:10.306	8  INFO 	data-config@v1.4.1/component.go:114	[config = monster_pool] loaded. [size = 58]
-11:42:10.306	8  INFO 	data-config@v1.4.1/component.go:114	[config = node] loaded. [size = 1]
-11:42:10.307	8  INFO 	data-config@v1.4.1/component.go:114	[config = node_state] loaded. [size = 1]
-11:42:10.326	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest] loaded. [size = 172]
-11:42:10.327	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_achieve_pool] loaded. [size = 7]
-11:42:10.327	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_achieve_type] loaded. [size = 2]
-11:42:10.330	8  INFO 	data-config@v1.4.1/component.go:114	[config = quest_group] loaded. [size = 54]
-11:42:10.331	8  INFO 	data-config@v1.4.1/component.go:114	[config = rank] loaded. [size = 5]
-11:42:10.331	8  INFO 	data-config@v1.4.1/component.go:114	[config = rate_limiter] loaded. [size = 6]
-11:42:10.333	8  INFO 	data-config@v1.4.1/component.go:114	[config = recruit] loaded. [size = 8]
-11:42:10.333	8  INFO 	data-config@v1.4.1/component.go:114	[config = season] loaded. [size = 5]
-11:42:10.334	8  INFO 	data-config@v1.4.1/component.go:114	[config = season_quest] loaded. [size = 10]
-11:42:10.335	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop] loaded. [size = 6]
-11:42:10.336	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop_card] loaded. [size = 4]
-11:42:10.337	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop_gold] loaded. [size = 6]
-11:42:10.342	8  INFO 	data-config@v1.4.1/component.go:114	[config = shop_goods] loaded. [size = 108]
-11:42:10.345	8  INFO 	data-config@v1.4.1/component.go:114	[config = sign_in] loaded. [size = 60]
-11:42:10.345	8  INFO 	data-config@v1.4.1/component.go:114	[config = sign_in_reward] loaded. [size = 6]
-11:42:10.355	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill] loaded. [size = 266]
-11:42:10.385	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill_level] loaded. [size = 746]
-11:42:10.387	8  INFO 	data-config@v1.4.1/component.go:114	[config = skill_pool] loaded. [size = 13]
-11:42:10.394	8  INFO 	data-config@v1.4.1/component.go:114	[config = vip] loaded. [size = 18]
-11:42:10.395	8  INFO 	data-config@v1.4.1/component.go:114	[config = vip_daily_exp] loaded. [size = 8]
-11:42:10.427	8  INFO 	data/extend_monster_group.go:44	monsterGroupConfig load success, len: 126
-11:42:10.428	8  INFO 	cherry@v1.4.18/application.go:202	[component = redis_component] -> OnInit().
-11:42:10.428	8  INFO 	redis/component.go:78	New redis *client [configID = game_redis_id, redisID = redis-hw]
-11:42:10.428	8  INFO 	redis/component.go:78	New redis *client [configID = chat_redis_id, redisID = redis-hw]
-11:42:10.428	8  INFO 	redis/component.go:78	New redis *client [configID = guid_redis_id, redisID = redis-hw]
-11:42:10.428	8  INFO 	redis/component.go:78	New redis *client [configID = center_redis_id, redisID = redis-hw]
-11:42:10.439	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-11:42:10.445	8  INFO 	redis/guid.go:54	check guid. [current = 1049264]
-11:42:10.449	8  INFO 	redis/guid.go:57	check uid. [current = 1048578]
-11:42:10.459	8  INFO 	redis/guid.go:60	check chatid. [current = 1024]
-11:42:10.468	8  INFO 	redis/guid.go:63	check leagueid. [current = 1874]
-11:42:10.468	8  INFO 	redis/component.go:91	Load [type = *redis.guid, configID = guid_redis_id, redisID = redis-hw]
-11:42:10.468	8  INFO 	redis/component.go:91	Load [type = *redis.center, configID = center_redis_id, redisID = redis-hw]
-11:42:10.469	8  INFO 	redis/component.go:91	Load [type = *redis.chat, configID = chat_redis_id, redisID = redis-hw]
-11:42:10.469	8  INFO 	redis/component.go:91	Load [type = *redis.game, configID = game_redis_id, redisID = redis-hw]
-11:42:10.469	8  INFO 	cherry@v1.4.18/application.go:202	[component = run_check_component] -> OnInit().
-11:42:10.469	8  INFO 	cherry@v1.4.18/application.go:202	[component = game_db_component] -> OnInit().
-11:42:10.528	8  INFO 	mongo@v1.4.1/component.go:124	Ping DB is ok. [dbName = hw-f1-game, host = [192.168.1.232:27017]] 
-11:42:10.528	8  INFO 	mongo@v1.4.1/component.go:84	[dbGroup =db_game_group, dbName = mongo-f1-game] is connected.
-11:42:10.541	8  INFO 	migrator/migrator.go:32	[migrator] [version = 1] skip
-11:42:10.541	8  INFO 	migrator/migrator.go:32	[migrator] [version = 2] skip
-11:42:10.541	8  INFO 	migrator/migrator.go:32	[migrator] [version = 3] skip
-11:42:10.541	8  INFO 	migrator/migrator.go:32	[migrator] [version = 5] skip
-11:42:10.544	8  WARN 	migrator/migrator_table.go:57	mongo: no documents in result
-11:42:10.544	8  INFO 	migrator/migrator.go:134	[migrator] run finished. [executeCount = 0, lastVersion = 0]
-11:42:10.545	8  INFO 	queue/table_queue.go:118	add [table = node, ticker = 1(sec), count = 100]
-11:42:10.545	8  INFO 	queue/table_queue.go:118	add [table = hero, ticker = 1(sec), count = 100]
-11:42:10.545	8  INFO 	queue/table_queue.go:118	add [table = item, ticker = 1(sec), count = 100]
-11:42:10.545	8  INFO 	queue/table_queue.go:118	add [table = mail, ticker = 1(sec), count = 100]
-11:42:10.545	8  INFO 	queue/table_queue.go:118	add [table = player, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = quest, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = lineup, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = equip, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = chat, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = complaint, ticker = 1(sec), count = 100]
-11:42:10.546	8  INFO 	queue/table_queue.go:118	add [table = chapter, ticker = 1(sec), count = 100]
-11:42:10.547	8  INFO 	queue/table_queue.go:118	add [table = shop, ticker = 1(sec), count = 100]
-11:42:10.547	8  INFO 	queue/table_queue.go:138	db queue starting...
-11:42:10.547	8  INFO 	db/component.go:51	[db_id = hw-f1-game] database is init.
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = player]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = lineup]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = chapter]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = quest]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = equip]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = hero]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = node]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = item]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = shop]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = mail]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = chat]
-11:42:10.547	8  INFO 	queue/table_queue.go:241	run queue for [table = complaint]
-11:42:10.556	8  INFO 	db/player_table.go:248	preload player info count = 1
-11:42:10.556	8  INFO 	cherry@v1.4.18/application.go:202	[component = sdk_component] -> OnInit().
-11:42:10.556	8  INFO 	cherry@v1.4.18/application.go:202	[component = actor_component] -> OnInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:205	-------------------------------------------------
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = cluster_component] -> OnAfterInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = discovery_component] -> OnAfterInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = initBeforeFunc] -> OnAfterInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = gops_component] -> OnAfterInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = data_config_component] -> OnAfterInit().
-11:42:10.557	8  INFO 	cherry@v1.4.18/application.go:209	[component = redis_component] -> OnAfterInit().
-11:42:10.558	8  INFO 	cherry@v1.4.18/application.go:209	[component = run_check_component] -> OnAfterInit().
-11:42:10.564	8  INFO 	cherry@v1.4.18/application.go:209	[component = game_db_component] -> OnAfterInit().
-11:42:10.564	8  INFO 	cherry@v1.4.18/application.go:209	[component = sdk_component] -> OnAfterInit().
-11:42:10.565	8  INFO 	cherry@v1.4.18/application.go:209	[component = actor_component] -> OnAfterInit().
-11:42:10.565	8  INFO 	cherry@v1.4.18/application.go:221	-------------------------------------------------
-11:42:10.565	8  INFO 	ops/actor.go:37	node default state [0]
-11:42:10.565	8  INFO 	sessions/actor.go:72	[sessions] actor init success. isSync = true
-11:42:10.565	8  INFO 	cherry@v1.4.18/application.go:222	[spend time = 2078ms] application is running.
-11:42:10.565	8  INFO 	cherry@v1.4.18/application.go:223	-------------------------------------------------
-11:42:10.570	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-11:42:10.573	8  DEBUG	gen_pool/actor.go:168	load redis genPool items. count = 3
-11:42:11.057	8  DEBUG	queue/table_queue.go:296	[table = node, size = 1] queue bulk write.
-11:42:47.321	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"map-1"  nodeType:"map"  lastAt:1773286928507  heartbeatTimeout:3000]
-11:42:53.951	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"map-1"  nodeType:"map"  lastAt:1773286973944  heartbeatTimeout:3000]
-11:43:01.327	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773286928470  heartbeatTimeout:3000]
-11:43:38.981	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773287018971  heartbeatTimeout:3000]
-11:45:39.456	8  DEBUG	player/actor.go:85	[actor] create child. actorID = 1048577, targetPath = 8.player.1048577
-11:45:39.460	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = 75JyVvjFCl6UVqOhWyHybq, isNewPlayer = false
-11:45:39.461	8  DEBUG	player/actor_player.go:231	[playerID = 1048577] [onReset] playerID = 1048577
-11:45:39.495	8  DEBUG	lord/service.go:107	send daily mail finish. playerID:1048577, day:4
-11:45:39.499	8  WARN 	sessions/push_kick.go:23	[PushPlayer] Session not found. [playerID = 1048577, route = game.mail.newPush]
-11:45:39.499	8  DEBUG	mail/actor_mail.go:304	playerID = 1048577, mailNum = 2
-11:45:39.499	8  DEBUG	mail/actor_mail.go:305	delMailID = []
-11:45:39.502	8  WARN 	quest/service.go:113	[ChangePushWithPlayerID] session not found. [playerID = 1048577]
-11:45:39.513	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-11:45:39.522	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-11:45:39.529	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-11:45:39.529	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-11:45:39.920	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-11:45:39.921	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-11:45:39.921	8  WARN 	actor/actor.go:215	[remote] Invoke timeout.[source = 8.login.72, target = 8.player.1048577->onEnter, execution = 465ms]
-11:45:40.051	8  DEBUG	queue/table_queue.go:296	[table = quest, size = 1] queue bulk write.
-11:45:40.052	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-11:45:40.052	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-11:45:40.054	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-11:45:40.059	8  DEBUG	queue/table_queue.go:296	[table = hero, size = 1] queue bulk write.
-11:46:47.051	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-11:46:48.053	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-11:46:48.053	8  DEBUG	queue/table_queue.go:296	[table = item, size = 1] queue bulk write.
-11:46:48.054	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-11:48:03.814	8  DEBUG	mail/actor_mail.go:304	playerID = 1048577, mailNum = 2
-11:48:03.814	8  DEBUG	mail/actor_mail.go:305	delMailID = []
-11:48:04.054	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.

+ 0 - 81
sr/nodes/logs/8_202603121200.log

@@ -1,81 +0,0 @@
-12:17:59.639	8  WARN 	nats/connect.go:234	Disconnect error. [error = read tcp 192.168.1.29:62578->192.168.1.232:4222: wsarecv: An existing connection was forcibly closed by the remote host.]
-12:18:06.692	8  WARN 	nats/connect.go:239	Reconnected [nats://192.168.1.232:4222]
-12:18:06.751	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"web-1"  nodeType:"web"  lastAt:1773286928235  heartbeatTimeout:3000]
-12:18:06.751	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"center-1"  nodeType:"center"  lastAt:1773286928241  heartbeatTimeout:3000]
-12:18:06.751	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"map-1"  nodeType:"map"  lastAt:1773286973944  heartbeatTimeout:3000]
-12:18:06.752	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"ops-1"  nodeType:"ops"  lastAt:1773286928516  heartbeatTimeout:3000]
-12:18:06.752	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773287018971  heartbeatTimeout:3000]
-12:18:06.752	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"chat-1"  nodeType:"chat"  lastAt:1773286928516  heartbeatTimeout:3000]
-12:18:06.753	8  DEBUG	discovery/discovery_default.go:156	Remove member. [member = nodeID:"8"  nodeType:"game"  lastAt:1773286928512  heartbeatTimeout:3000]
-12:18:07.089	8  WARN 	actor/actor.go:199	[remote] Invoke timeout.[path = .system -> 8.ops -> checkNodeState, postTime = 1773289087089, buildTime = 1773289084580, arrival = 2509ms]
-12:18:07.102	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = 75JyVvjFCl6UVqOhWyHyjR, isNewPlayer = false
-12:18:07.103	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-12:18:07.112	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-12:18:07.121	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 180, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.121	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.125	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 44838, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.125	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.125	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-12:18:07.125	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 65, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.125	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.126	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-12:18:07.126	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 47, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.126	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.126	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 119, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.127	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.127	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 618, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.128	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.128	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 8994, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.129	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.129	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 1605, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.129	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.129	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 38, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.129	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.129	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 40, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.129	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.130	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 25, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.130	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.130	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 37, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.130	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.130	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 35, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.130	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.131	8  WARN 	nats_cluster/cluster.go:276	[RequestRemote] Get node type fail. [nodeID = gate-1, source = .system, target = gate-1.user.75JyVvjFCl6UVqOhWyHyjR, funcName = setSession, bytesLen = 63, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.131	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.player.1048577, target = gate-1.user, funcName = response, bytesLen = 46, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.131	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.player.1048577, target = gate-1.user, funcName = response, err = Discovery not found node]
-12:18:07.131	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-12:18:07.132	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-12:18:07.132	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatGame -> push]
-12:18:07.132	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatGame, funcName = push]
-12:18:07.132	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatMap -> push]
-12:18:07.131	8  WARN 	nats_cluster/cluster.go:202	[PublishRemote] Get node type fail. [nodeID = gate-1, source = 8.sessions, target = gate-1.user, funcName = push, bytesLen = 159, session = <nil>, err = nodeID = gate-1 not found.]
-12:18:07.132	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatMap, funcName = push]
-12:18:07.132	8  WARN 	actor/system.go:190	[Call] Publish remote fail. [source = 8.sessions, target = gate-1.user, funcName = push, err = Discovery not found node]
-12:18:07.135	8  WARN 	player/actor.go:64	player table not found. [playerID = 1048578, target = .player.1048578]
-12:18:07.654	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"center-1"  nodeType:"center"  lastAt:1773286928241  heartbeatTimeout:3000]
-12:18:07.654	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"web-1"  nodeType:"web"  lastAt:1773286928235  heartbeatTimeout:3000]
-12:18:07.655	8  INFO 	discovery/discovery_master.go:184	[sendRegister2Master] OK. master = master-1, member = nodeID:"8"  nodeType:"game"  lastAt:1773286928507  heartbeatTimeout:3000
-12:18:07.655	8  DEBUG	discovery/discovery_default.go:142	Add Duplicate Member. [member = nodeID:"web-1"  nodeType:"web"  lastAt:1773289087649  heartbeatTimeout:3000]
-12:18:07.656	8  DEBUG	discovery/discovery_default.go:142	Add Duplicate Member. [member = nodeID:"center-1"  nodeType:"center"  lastAt:1773289087648  heartbeatTimeout:3000]
-12:18:07.656	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"8"  nodeType:"game"  lastAt:1773289087652  heartbeatTimeout:3000]
-12:18:07.656	8  DEBUG	discovery/discovery_default.go:142	Add Duplicate Member. [member = nodeID:"master-1"  nodeType:"master"  lastAt:1773286928297  heartbeatTimeout:3000]
-12:18:08.051	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-12:18:08.060	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-12:23:23.653	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"map-1"  nodeType:"map"  lastAt:1773289403644  heartbeatTimeout:3000]
-12:24:20.750	8  DEBUG	discovery/discovery_default.go:144	Add Member. [ member = nodeID:"gate-1"  nodeType:"gate"  lastAt:1773289460745  heartbeatTimeout:3000]
-12:24:52.617	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = R32hqkkW0M3bN2MSt5JnyD, isNewPlayer = false
-12:24:52.618	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-12:24:52.625	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-12:24:52.634	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-12:24:52.634	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-12:24:52.675	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-12:24:52.675	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-12:24:52.675	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatGame -> push]
-12:24:52.676	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatGame, funcName = push]
-12:24:52.676	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatMap -> push]
-12:24:52.676	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatMap, funcName = push]
-12:24:52.676	8  WARN 	actor/actor.go:215	[remote] Invoke timeout.[source = 8.login.72, target = 8.player.1048577->onEnter, execution = 59ms]
-12:24:53.050	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-12:24:53.051	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-12:26:43.395	8  DEBUG	mail/actor_mail.go:304	playerID = 1048577, mailNum = 3
-12:26:43.395	8  DEBUG	mail/actor_mail.go:305	delMailID = []
-12:26:44.055	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.

+ 0 - 40
sr/nodes/logs/8_202603121300.log

@@ -1,40 +0,0 @@
-13:10:12.975	8  WARN 	nats/connect.go:234	Disconnect error. [error = read tcp 192.168.1.29:57392->192.168.1.232:4222: wsarecv: An existing connection was forcibly closed by the remote host.]
-13:10:20.053	8  WARN 	nats/connect.go:239	Reconnected [nats://192.168.1.232:4222]
-13:10:20.369	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = R32hqkkW0M3bN2MSt5JoAe, isNewPlayer = false
-13:10:20.370	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-13:10:20.391	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-13:10:20.406	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-13:10:20.406	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-13:10:20.426	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-13:10:20.426	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-13:10:20.426	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatGame -> push]
-13:10:20.426	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatGame, funcName = push]
-13:10:20.426	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatMap -> push]
-13:10:20.427	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatMap, funcName = push]
-13:10:20.427	8  WARN 	actor/actor.go:215	[remote] Invoke timeout.[source = 8.login.72, target = 8.player.1048577->onEnter, execution = 58ms]
-13:10:21.050	8  WARN 	queue/table_queue.go:291	[table = player] save error. [error = connection(192.168.1.232:27017[-6]) unable to write wire message to network: write tcp 192.168.1.29:62798->192.168.1.232:27017: wsasend: An existing connection was forcibly closed by the remote host.]
-13:10:21.054	8  WARN 	queue/table_queue.go:293	&{Collation:<nil> Upsert:0xc000b71d60 Filter:{"_id":{"$numberLong":"1048577"}} Update:{"$set":{"PlayerID":{"$numberLong":"1048577"},"PID":{"$numberInt":"2188008"},"OpenID":"1048577","UID":{"$numberLong":"1048578"},"NodeID":"8","OriginNodeID":"8","CreateTime":{"$numberLong":"1773038946928"},"CreateIP":"192.168.1.29","Data":{"Lord":{"Name":"EvansJudy","Level":{"$numberInt":"50"},"Exp":{"$numberLong":"70"},"IconID":{"$numberInt":"1"},"BgID":{"$numberInt":"301"},"SeasonID":{"$numberInt":"1"}},"Share":{},"Stats":{"LastDayResetTime":{"$numberLong":"1773287139456"},"LastWeekResetTime":{"$numberLong":"1773038946927"},"TotalOnlineSecond":{"$numberLong":"29099"},"TotalLoginDays":{"$numberInt":"4"},"ContinueLoginDays":{"$numberInt":"4"},"ContinueLoginMaxDays":{"$numberInt":"4"},"LastLoginTime":{"$numberLong":"1773292220369"},"LastLoginIP":"192.168.1.29","LogoutTime":{"$numberLong":"1773228629035"},"DailyMailDays":{"$numberInt":"4"}},"Settings":{"Language":"zh_CN"},"Map":{"MapNodeID":"map-1","Point":{"X":{"$numberInt":"0"},"Y":{"$numberInt":"0"}},"Builds":{}},"Shows":{"ShowMap":{"303":{"IsViewed":true},"115":{"IsViewed":true},"304":{"IsViewed":true},"108":{"IsViewed":true},"301":{"IsViewed":true},"126":{"IsViewed":true},"113":{"IsViewed":true},"114":{"IsViewed":true},"105":{"IsViewed":true},"112":{"IsViewed":true},"2":{"IsViewed":true},"102":{"IsViewed":true},"119":{"IsViewed":true},"1":{"IsViewed":true}}},"MainQuest":{"MainChapterID":{"$numberInt":"10101"}},"Vip":{"IsExpired":true}},"UpdateTime":{"$numberLong":"1773292220370"}}} ArrayFilters:[] Hint:<nil> Sort:<nil>}
-13:10:21.074	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-13:33:44.112	8  INFO 	player/actor_player.go:180	[playerID = 1048577] [onLogout] playerID = 1048577
-13:33:44.201	8  DEBUG	lord/service.go:71	[lord.OnLogout] PlayerID = 1048577, OnlineTime = 1404(s)
-13:33:44.204	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-13:33:44.207	8  INFO 	player/actor_player.go:198	[playerID = 1048577] [onLogout] finished! playerID = 1048577
-13:33:44.207	8  WARN 	actor/actor.go:215	[remote] Invoke timeout.[source = .system, target = .player.1048577->onSessionClosed, execution = 95ms]
-13:33:45.053	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-13:33:47.337	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = R32hqkkW0M3bN2MSt5JoIw, isNewPlayer = false
-13:33:47.337	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-13:33:47.343	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-13:33:47.343	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-13:33:47.353	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-13:33:47.353	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-13:33:47.354	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatGame -> push]
-13:33:47.354	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatGame, funcName = push]
-13:33:47.354	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatMap -> push]
-13:33:47.354	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatMap, funcName = push]
-13:33:48.053	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-13:33:48.058	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.
-13:51:58.052	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-13:52:02.055	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-13:52:05.050	8  DEBUG	queue/table_queue.go:296	[table = mail, size = 1] queue bulk write.
-13:52:05.050	8  DEBUG	queue/table_queue.go:296	[table = item, size = 1] queue bulk write.
-13:52:05.052	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.

+ 0 - 17
sr/nodes/logs/8_202603121400.log

@@ -1,17 +0,0 @@
-14:06:24.163	8  INFO 	player/actor_player.go:180	[playerID = 1048577] [onLogout] playerID = 1048577
-14:06:24.167	8  DEBUG	lord/service.go:71	[lord.OnLogout] PlayerID = 1048577, OnlineTime = 1957(s)
-14:06:24.175	8  INFO 	redis/component.go:129	[redisID = redis-hw] connected! [address = 192.168.1.232:46379]
-14:06:24.180	8  INFO 	player/actor_player.go:198	[playerID = 1048577] [onLogout] finished! playerID = 1048577
-14:06:25.050	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-14:06:48.205	8  DEBUG	player/actor_player.go:146	[playerID = 1048577] [onEnter] sid = R32hqkkW0M3bN2MSt5JoN5, isNewPlayer = false
-14:06:48.208	8  DEBUG	lord/service.go:49	[lord.OnLogin] PlayerID = 1048577, IP = 192.168.1.29
-14:06:48.216	8  DEBUG	hero/service.go:74	[playerID = 1048577] heroesCount = 487
-14:06:48.216	8  DEBUG	hero/service.go:85	[playerID = 1048577] heroBooksCount = 9
-14:06:48.224	8  DEBUG	player/actor_player.go:265	[playerID = 1048577] [onEnterResponse]
-14:06:48.224	8  DEBUG	actor_remote/center_player.go:48	[playerID = 1048577, gameNodeID = 8] update last player.
-14:06:48.225	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatGame -> push]
-14:06:48.225	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatGame, funcName = push]
-14:06:48.225	8  WARN 	actor/system.go:430	[PostRemote] actor not found. [source = .system, target = .chatMap -> push]
-14:06:48.225	8  WARN 	actor/system.go:206	[Call] Post remote fail. [source = .system, target = .chatMap, funcName = push]
-14:06:49.053	8  DEBUG	queue/table_queue.go:296	[table = player, size = 1] queue bulk write.
-14:06:49.054	8  DEBUG	queue/table_queue.go:296	[table = chat, size = 1] queue bulk write.

Some files were not shown because too many files changed in this diff