Pārlūkot izejas kodu

feat(GameItem): 设计物品冻结功能

- 新增物品冻结功能设计文档
- 扩展ItemUser表增加冻结状态字段
- 新增冻结/解冻操作逻辑和验证机制
- 创建冻结记录表追踪冻结操作
- 定义冻结操作和原因类型枚举
- 扩展ItemUser模型和ItemFreeze逻辑类
- 更新ItemService添加冻结相关方法- 设计与交易系统和其他验证的集成方案
notfff 7 mēneši atpakaļ
vecāks
revīzija
bb88d5061f

+ 178 - 0
AiWork/2025年06月/12日1111-GameItem模块物品冻结功能设计文档.md

@@ -0,0 +1,178 @@
+# GameItem模块物品冻结功能设计文档
+
+**任务时间:** 2025年06月12日 11:11  
+**任务类型:** 功能设计  
+**模块:** GameItems  
+
+## 任务背景
+
+在实现匹配交易的过程中,当用户发起卖出物品订单时,需要冻结该物品,防止用户在订单处理期间使用、交易或消耗这些物品。目前GameItem模块缺少物品冻结机制,需要设计并实现完整的物品冻结功能。
+
+## 现状分析
+
+### 当前物品状态管理
+- **ItemUser表**:记录用户物品关联,包含数量、过期时间等基本信息
+- **ItemInstance表**:单独属性物品实例,包含绑定状态(`is_bound`)、交易状态(`tradable`)
+- **交易日志**:通过`ItemTransactionLog`记录所有物品流转
+- **状态枚举**:已有`TRANSACTION_TYPE`、`ITEM_BIND_TYPE`等状态管理
+
+### 缺失的功能
+- 缺少物品冻结状态字段
+- 缺少冻结/解冻操作逻辑
+- 缺少冻结状态验证机制
+- 缺少冻结记录追踪
+
+## 设计方案
+
+### 数据库设计
+
+#### ItemUser表扩展(拆堆模式)
+在`item_users`表中新增冻结相关字段:
+- `is_frozen` - 是否冻结状态(布尔值)
+- `freeze_log_id` - 冻结日志ID,关联冻结记录表
+
+**拆堆机制**:冻结时将原堆叠拆分为冻结部分和可用部分两个独立记录,例如1000个物品冻结200个时,拆分为200个(冻结)+ 800个(可用)。
+
+**重要修正**:ItemInstance表不需要扩展冻结字段,因为ItemInstance是物品实例表,记录的是物品的基本信息和属性,而不涉及物品归属关系。冻结功能是针对用户拥有的物品进行的操作,应该在ItemUser表中实现。
+
+#### 冻结记录表
+创建专门的冻结记录表`item_freeze_logs`用于追踪所有冻结操作,使用`source_id`和`source_type`记录操作方信息。
+
+### 枚举定义
+
+#### 冻结操作类型
+```php
+class FREEZE_ACTION_TYPE
+{
+    const FREEZE = 1;    // 冻结
+    const UNFREEZE = 2;  // 解冻
+}
+```
+
+#### 冻结原因类型
+```php
+class FREEZE_REASON_TYPE
+{
+    const TRADE_ORDER = 'trade_order';      // 交易订单
+    const ADMIN_FREEZE = 'admin_freeze';    // 管理员冻结
+    const SYSTEM_FREEZE = 'system_freeze';  // 系统冻结
+    const AUCTION = 'auction';              // 拍卖
+    const MAIL_ATTACHMENT = 'mail_attachment'; // 邮件附件
+}
+```
+
+### 模型扩展
+
+#### ItemUser模型扩展
+- 新增冻结相关字段:`is_frozen`和`freeze_log_id`
+- 添加`isFrozen()`检查是否为冻结状态
+- 添加`isAvailable()`检查是否可用
+- 添加`getAvailableQuantity()`静态方法获取用户可用物品总数
+- 添加`freezeLog()`关联冻结日志记录
+
+**修正**:ItemInstance模型不需要扩展冻结相关字段和方法,冻结状态在ItemUser表中管理。
+
+### 逻辑层实现
+
+#### ItemFreeze逻辑类(拆堆模式)
+核心方法包括:
+- `freezeNormalItem()` - 冻结统一属性物品,拆堆实现,创建冻结记录
+- `freezeUniqueItem()` - 冻结单独属性物品,直接标记is_frozen=true
+- `unfreezeByLogId()` - 根据冻结日志ID解冻物品,可选择合并或保持独立
+- `getAvailableQuantity()` - 获取用户可用物品数量(排除冻结堆叠)
+- `checkAvailableQuantity()` - 验证用户是否有足够的可用物品
+
+### 服务层扩展
+
+#### ItemService扩展
+- `freezeItem()` - 冻结物品
+- `unfreezeItem()` - 解冻物品
+- `getAvailableQuantity()` - 获取可用数量
+- `getFrozenItems()` - 获取冻结物品列表
+
+## 集成方案
+
+### 与交易系统集成
+- **创建卖出订单时**:自动冻结对应数量的物品
+- **订单完成时**:解冻物品并执行消耗操作
+- **订单取消时**:解冻物品恢复可用状态
+- **订单失败时**:解冻物品并记录失败原因
+
+### 与现有验证集成
+- **消耗物品前**:检查可用数量(总数量-冻结数量)
+- **交易物品前**:验证物品未被冻结
+- **使用物品前**:确认物品处于可用状态
+
+### 解冻机制
+- **主动解冻**:由冻结发起方(如交易系统、管理员等)主动调用解冻方法
+- **日志追踪**:通过freeze_log_id关联冻结记录,确保解冻操作的准确性
+
+## 实现优先级
+
+### 第一阶段(核心功能)
+1. 数据库表结构修改
+2. 模型字段和基础方法扩展
+3. 冻结/解冻核心逻辑实现
+4. 基础验证机制
+
+### 第二阶段(集成功能)
+1. 与交易系统集成
+2. 服务层方法完善
+3. 管理后台界面
+4. 冻结记录查询
+
+### 第三阶段(优化功能)
+1. 批量操作优化
+2. 性能监控和优化
+3. 异常情况处理
+4. 冻结记录清理机制
+
+## 注意事项
+
+### 数据一致性
+- 冻结操作必须在事务中执行
+- 确保冻结数量不超过实际拥有数量
+- 解冻时验证冻结记录的有效性
+
+### 性能考虑
+- 冻结状态查询需要适当的索引支持
+- 大量物品冻结时考虑批量操作
+- 定时任务的执行频率和性能影响
+
+### 业务规则
+- 冻结的堆叠(is_frozen=true)不能被消耗、交易或使用
+- 解冻操作由冻结发起方负责处理,通过freeze_log_id定位
+- 拆堆时需要保证数量守恒:原堆叠数量 = 冻结堆叠数量 + 剩余可用堆叠数量
+- 交易日志不记录冻结相关信息,冻结信息由冻结记录表单独管理
+- 不同冻结原因(source_type)可能有不同的处理逻辑
+
+## 任务成果
+
+1. **完整的设计文档**:创建了详细的物品冻结功能设计文档
+2. **数据库设计**:设计了完整的数据库表结构扩展方案
+3. **架构设计**:提供了完整的枚举、模型、逻辑层、服务层设计
+4. **集成方案**:明确了与交易系统的集成方式
+5. **实现计划**:制定了三阶段的实现优先级
+
+## 文件清单
+
+- `app/Module/GameItems/Docs/冻结实现.md` - 物品冻结功能实现思路文档
+
+## 总结
+
+本次任务成功为GameItem模块设计了完整的物品冻结功能架构,解决了匹配交易中卖出物品需要冻结的核心问题。设计方案涵盖了数据库设计、代码架构、集成方案和实现计划,为后续的代码开发提供了详细的技术指导。
+
+设计方案具有以下特点:
+- **完整性**:覆盖了冻结功能的所有方面
+- **可扩展性**:支持多种冻结原因和场景
+- **一致性**:与现有代码架构保持一致
+- **实用性**:提供了具体的实现指导
+
+该设计文档将作为GameItem模块物品冻结功能开发的重要参考资料。
+
+## 重要修正
+
+**版本修正内容**:
+- **v1.1**:移除了ItemInstance表的冻结扩展设计,因为ItemInstance是物品实例表,记录的是物品的基本信息和属性,而不涉及物品归属关系。
+- **v1.2**:简化设计,移除自动解冻逻辑,解冻由发起方处理;冻结记录表使用source_id/source_type替代order_id;简化ItemUser表字段。
+- **v1.3**:采用冻结即拆"堆"的模式,使用is_frozen字段标识冻结状态;交易日志不记录冻结信息,冻结信息由冻结记录表单独管理。

+ 95 - 47
app/Module/GameItems/Docs/冻结实现.md

@@ -23,16 +23,35 @@
 ### 3.1 数据库设计
 
 #### 3.1.1 ItemUser表扩展
-在`item_users`表中新增冻结相关字段:
+在`item_users`表中新增冻结状态字段:
 
 ```sql
 ALTER TABLE `kku_item_users`
-ADD COLUMN `frozen_quantity` int NOT NULL DEFAULT 0 COMMENT '冻结数量',
+ADD COLUMN `is_frozen` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否冻结(0:未冻结, 1:已冻结)',
 ADD COLUMN `freeze_log_id` int DEFAULT NULL COMMENT '冻结日志ID,关联kku_item_freeze_logs表',
-ADD INDEX `idx_frozen_status` (`user_id`, `frozen_quantity`),
+ADD INDEX `idx_frozen_status` (`user_id`, `is_frozen`),
 ADD INDEX `idx_freeze_log` (`freeze_log_id`);
 ```
 
+**冻结拆堆机制说明**:
+- 冻结时采用拆"堆"模式:将原有堆叠拆分为冻结部分和可用部分两个独立的ItemUser记录
+- 例如:1000个物品堆叠,冻结200个时,拆分为:200个(is_frozen=1)+ 800个(is_frozen=0)
+- 冻结的堆叠不能使用、消耗或交易
+
+**拆堆示例**:
+```
+原始状态:
+ItemUser: user_id=1, item_id=100, quantity=1000, is_frozen=0
+
+冻结200个后:
+ItemUser: user_id=1, item_id=100, quantity=200, is_frozen=1, freeze_log_id=123
+ItemUser: user_id=1, item_id=100, quantity=800, is_frozen=0
+
+解冻后(可选择合并或保持独立):
+选择1 - 合并:ItemUser: user_id=1, item_id=100, quantity=1000, is_frozen=0
+选择2 - 独立:两条记录都保持is_frozen=0
+```
+
 **说明**:ItemInstance表不需要扩展冻结字段,因为ItemInstance是物品实例表,记录的是物品的基本信息和属性,而不涉及物品归属关系。冻结功能是针对用户拥有的物品进行的操作,应该在ItemUser表中实现。
 
 #### 3.1.2 冻结记录表
@@ -109,24 +128,29 @@ class FREEZE_REASON_TYPE
 // 在ItemUser模型中添加字段和方法
 protected $fillable = [
     // ... 现有字段
-    'frozen_quantity',
+    'is_frozen',
     'freeze_log_id',
 ];
 
+protected $casts = [
+    // ... 现有字段
+    'is_frozen' => 'boolean',
+];
+
 /**
- * 获取可用数量(总数量 - 冻结数量)
+ * 检查是否为冻结状态
  */
-public function getAvailableQuantityAttribute(): int
+public function isFrozen(): bool
 {
-    return max(0, $this->quantity - $this->frozen_quantity);
+    return $this->is_frozen;
 }
 
 /**
- * 检查是否有冻结物品
+ * 检查是否可用(未冻结)
  */
-public function hasFrozenItems(): bool
+public function isAvailable(): bool
 {
-    return $this->frozen_quantity > 0;
+    return !$this->is_frozen;
 }
 
 /**
@@ -136,6 +160,24 @@ public function freezeLog(): BelongsTo
 {
     return $this->belongsTo(ItemFreezeLog::class, 'freeze_log_id');
 }
+
+/**
+ * 获取用户指定物品的可用数量(排除冻结的堆叠)
+ */
+public static function getAvailableQuantity(int $userId, int $itemId, ?int $instanceId = null): int
+{
+    $query = static::where('user_id', $userId)
+        ->where('item_id', $itemId)
+        ->where('is_frozen', false);
+
+    if ($instanceId) {
+        $query->where('instance_id', $instanceId);
+    } else {
+        $query->whereNull('instance_id');
+    }
+
+    return $query->sum('quantity');
+}
 ```
 
 **说明**:ItemInstance模型不需要扩展冻结相关字段和方法,因为ItemInstance表记录的是物品实例的基本信息,冻结状态应该在ItemUser表中管理。
@@ -148,7 +190,13 @@ public function freezeLog(): BelongsTo
 class ItemFreeze
 {
     /**
-     * 冻结统一属性物品
+     * 冻结统一属性物品(拆堆模式)
+     *
+     * 实现逻辑:
+     * 1. 查找用户可用的物品堆叠(is_frozen=false)
+     * 2. 从可用堆叠中扣除冻结数量
+     * 3. 创建新的冻结堆叠记录(is_frozen=true)
+     * 4. 记录冻结日志
      */
     public static function freezeNormalItem(
         int $userId,
@@ -160,8 +208,8 @@ class ItemFreeze
     ): Res;
 
     /**
-     * 冻结单独属性物品
-     * 注:单独属性物品的冻结状态仍然记录在ItemUser表中,通过instance_id关联
+     * 冻结单独属性物品(拆堆模式)
+     * 注:单独属性物品数量始终为1,冻结时直接标记is_frozen=true
      */
     public static function freezeUniqueItem(
         int $userId,
@@ -173,40 +221,34 @@ class ItemFreeze
     ): Res;
 
     /**
-     * 解冻统一属性物品
-     * 注:解冻由冻结发起方处理,通过freeze_log_id定位冻结记录
+     * 解冻统一属性物品(合堆模式)
+     *
+     * 实现逻辑:
+     * 1. 通过freeze_log_id找到冻结的堆叠记录
+     * 2. 将冻结堆叠标记为可用(is_frozen=false)或删除
+     * 3. 尝试与现有可用堆叠合并
+     * 4. 记录解冻日志
      */
-    public static function unfreezeNormalItem(
-        int $userId,
-        int $itemId,
-        int $quantity,
-        int $freezeLogId
-    ): Res;
+    public static function unfreezeByLogId(int $freezeLogId): Res;
 
     /**
-     * 解冻单独属性物品
-     * 注:解冻由冻结发起方处理,通过freeze_log_id定位冻结记录
+     * 检查用户可用物品数量(排除冻结堆叠)
      */
-    public static function unfreezeUniqueItem(
+    public static function getAvailableQuantity(
         int $userId,
         int $itemId,
-        int $instanceId,
-        int $freezeLogId
-    ): Res;
+        ?int $instanceId = null
+    ): int;
 
     /**
-     * 检查用户可用物品数量
+     * 验证用户是否有足够的可用物品
      */
     public static function checkAvailableQuantity(
         int $userId,
         int $itemId,
-        int $requiredQuantity
+        int $requiredQuantity,
+        ?int $instanceId = null
     ): bool;
-
-    /**
-     * 根据冻结日志ID解冻物品
-     */
-    public static function unfreezeByLogId(int $freezeLogId): Res;
 }
 ```
 
@@ -253,9 +295,10 @@ public static function getFrozenItems(
 - **订单失败时**:解冻物品并记录失败原因
 
 ### 4.2 与现有验证集成
-- **消耗物品前**:检查可用数量(总数量-冻结数量)
-- **交易物品前**:验证物品未被冻结
-- **使用物品前**:确认物品处于可用状态
+- **消耗物品前**:只查询is_frozen=false的堆叠,确保不消耗冻结物品
+- **交易物品前**:验证物品堆叠未被冻结(is_frozen=false)
+- **使用物品前**:确认物品堆叠处于可用状态(is_frozen=false)
+- **物品查询**:默认只显示可用物品,冻结物品需要特殊查询
 
 ### 4.3 解冻机制
 - **主动解冻**:由冻结发起方(如交易系统、管理员等)主动调用解冻方法
@@ -284,26 +327,31 @@ public static function getFrozenItems(
 ## 6. 注意事项
 
 ### 6.1 数据一致性
-- 冻结操作必须在事务中执行
-- 确保冻结数量不超过实际拥有数量
-- 解冻时验证冻结记录的有效性
+- 冻结操作必须在事务中执行,确保拆堆操作的原子性
+- 确保冻结数量不超过实际可用数量(is_frozen=false的堆叠总和)
+- 解冻时验证冻结记录的有效性,防止重复解冻
+- 拆堆和合堆操作需要保证数量的准确性
 
 ### 6.2 性能考虑
-- 冻结状态查询需要适当的索引支持
-- 大量物品冻结时考虑批量操作
-- 定时任务的执行频率和性能影响
+- 冻结状态查询需要适当的索引支持(user_id, is_frozen)
+- 拆堆操作会增加ItemUser记录数量,需要考虑存储空间
+- 可用数量查询需要聚合计算,建议添加缓存机制
+- 大量物品冻结时考虑批量操作优化
 
 ### 6.3 业务规则
-- 冻结物品不能被消耗、交易或使用
-- 解冻操作由冻结发起方负责处理
-- 通过freeze_log_id确保冻结和解冻操作的对应关系
+- 冻结的堆叠(is_frozen=true)不能被消耗、交易或使用
+- 解冻操作由冻结发起方负责处理,通过freeze_log_id定位
+- 拆堆时需要保证原堆叠数量 = 冻结堆叠数量 + 剩余可用堆叠数量
+- 解冻时可以选择与现有可用堆叠合并或保持独立
 - 不同冻结原因(source_type)可能有不同的处理逻辑
+- 交易日志不记录冻结相关信息,冻结信息由冻结记录表单独管理
 
 ---
 
 *文档创建时间:2025年06月12日*
-*版本:v1.2*
+*版本:v1.3*
 *状态:设计阶段*
 *修正说明:*
 - *v1.1:移除ItemInstance表的冻结扩展,因为ItemInstance是物品实例表,不涉及物品归属关系*
 - *v1.2:简化设计,移除自动解冻逻辑,解冻由发起方处理;冻结记录表使用source_id/source_type;简化ItemUser表字段*
+- *v1.3:采用冻结即拆"堆"的模式,使用is_frozen字段标识冻结状态;交易日志不记录冻结信息*

+ 7 - 6
config/proto_route.php

@@ -66,11 +66,12 @@ return array (
       0 => 'check_code',
       1 => 'device_info',
       2 => 'login',
-      3 => 'player_data',
-      4 => 'register',
-      5 => 'reset_password',
-      6 => 'send_sms',
-      7 => 'token',
+      3 => 'login4u',
+      4 => 'player_data',
+      5 => 'register',
+      6 => 'reset_password',
+      7 => 'send_sms',
+      8 => 'token',
     ),
     'shop' => 
     array (
@@ -98,7 +99,7 @@ return array (
       7 => 'query_data',
     ),
   ),
-  'generated_at' => '+08:00 2025-06-11 11:11:11',
+  'generated_at' => '+08:00 2025-06-12 11:50:50',
   'conventions' => 
   array (
     'handler_namespace' => 'App\\Module\\AppGame\\Handler',

+ 19 - 9
protophp/GPBMetadata/Proto/Game.php

@@ -16,8 +16,8 @@ class Game
         }
         $pool->internalAddGeneratedFile(
             '
-»³
-proto/game.proto	uraus.kku"ó:
+†¶
+proto/game.proto	uraus.kku"ß;
 Request
 request_unid (	;
 public_tokend (2%.uraus.kku.Request.RequestPublicToken;
@@ -27,7 +27,8 @@ class Game
 public_sendsmsh (2\'.uraus.kku.Request.RequestPublicSendSmsC
 public_checkcodei (2).uraus.kku.Request.RequestPublicCheckCodeK
 public_resetpasswordj (2-.uraus.kku.Request.RequestPublicResetPasswordE
-public_deviceinfok (2*.uraus.kku.Request.RequestPublicDeviceInfoB
+public_deviceinfok (2*.uraus.kku.Request.RequestPublicDeviceInfo@
+public_login4uÇ (2\'.uraus.kku.Request.RequestPublicLogin4uB
 land_fertilizerÈ (2(.uraus.kku.Request.RequestLandFertilizer>
 
land_wateringÉ (2&.uraus.kku.Request.RequestLandWatering@
 land_pesticideÊ (2\'.uraus.kku.Request.RequestLandPesticide@
@@ -89,7 +90,9 @@ shop_query
 times (6
 RequestPublicLogin
 mobile (	
-password (	\\
+password (	(
+RequestPublicLogin4u
+keylogin (	\\
 RequestPublicRegister
 mobile (	
 password (	
@@ -260,7 +263,7 @@ select_ids (.
 RequestMatchexchangeMy
 item_id (2
 	direction (2.uraus.kku.Common.MEX_DIRECTION+
-page (2.uraus.kku.Common.RequestPage"¦H
+page (2.uraus.kku.Common.RequestPage"ãI
 Response
 run_unid (	
 run_ms (-
@@ -279,7 +282,8 @@ select_ids (.
 public_sendsmsh (2).uraus.kku.Response.ResponsePublicSendSmsE
 public_checkcodei (2+.uraus.kku.Response.ResponsePublicCheckCodeM
 public_resetpasswordj (2/.uraus.kku.Response.ResponsePublicResetPasswordG
-public_deviceinfok (2,.uraus.kku.Response.ResponsePublicDeviceInfoD
+public_deviceinfok (2,.uraus.kku.Response.ResponsePublicDeviceInfoB
+public_login4uÇ (2).uraus.kku.Response.ResponsePublicLogin4uD
 land_fertilizerÈ (2*.uraus.kku.Response.ResponseLandFertilizer@
 
land_wateringÉ (2(.uraus.kku.Response.ResponseLandWateringB
 land_pesticideÊ (2).uraus.kku.Response.ResponseLandPesticideB
@@ -342,6 +346,10 @@ shop_query
 ResponsePublicLogin
 token (	
 is_prohibit (:
+last_login_info (2!.uraus.kku.Response.LastLoginInfow
+ResponsePublicLogin4u
+token (	
+is_prohibit (:
 last_login_info (2!.uraus.kku.Response.LastLoginInfo-
 ResponsePublicRegister
 is_register (¶
@@ -546,7 +554,7 @@ last_times (
 APPLYING	
 AGREE
 
-REFUSE"ô/
+REFUSE"–0
 Common)
 KeyValue
 kname (	
@@ -637,12 +645,14 @@ pet_simple (2.uraus.kku.Common.DataPetSimple-
 task	 (2.uraus.kku.Common.DataPetSimple*
 DataCoin
 type (
-quantity (W
+quantity (y
 DataItem
 item_id (
 instance_id (
 quantity (
-expire_time (É
+expire_time (
+	is_frozen (
+iu_id (É
 DataLand
 
 id (

+ 68 - 0
protophp/Uraus/Kku/Common/DataItem.php

@@ -39,6 +39,18 @@ class DataItem extends \Google\Protobuf\Internal\Message
      * Generated from protobuf field <code>int64 expire_time = 4;</code>
      */
     protected $expire_time = 0;
+    /**
+     * 是否冻结
+     *
+     * Generated from protobuf field <code>bool is_frozen = 5;</code>
+     */
+    protected $is_frozen = false;
+    /**
+     * 堆id(堆叠物品)
+     *
+     * Generated from protobuf field <code>int64 iu_id = 6;</code>
+     */
+    protected $iu_id = 0;
 
     /**
      * Constructor.
@@ -54,6 +66,10 @@ class DataItem extends \Google\Protobuf\Internal\Message
      *           数量
      *     @type int|string $expire_time
      *           过期时间
+     *     @type bool $is_frozen
+     *           是否冻结
+     *     @type int|string $iu_id
+     *           堆id(堆叠物品)
      * }
      */
     public function __construct($data = NULL) {
@@ -165,6 +181,58 @@ class DataItem extends \Google\Protobuf\Internal\Message
         return $this;
     }
 
+    /**
+     * 是否冻结
+     *
+     * Generated from protobuf field <code>bool is_frozen = 5;</code>
+     * @return bool
+     */
+    public function getIsFrozen()
+    {
+        return $this->is_frozen;
+    }
+
+    /**
+     * 是否冻结
+     *
+     * Generated from protobuf field <code>bool is_frozen = 5;</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setIsFrozen($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->is_frozen = $var;
+
+        return $this;
+    }
+
+    /**
+     * 堆id(堆叠物品)
+     *
+     * Generated from protobuf field <code>int64 iu_id = 6;</code>
+     * @return int|string
+     */
+    public function getIuId()
+    {
+        return $this->iu_id;
+    }
+
+    /**
+     * 堆id(堆叠物品)
+     *
+     * Generated from protobuf field <code>int64 iu_id = 6;</code>
+     * @param int|string $var
+     * @return $this
+     */
+    public function setIuId($var)
+    {
+        GPBUtil::checkInt64($var);
+        $this->iu_id = $var;
+
+        return $this;
+    }
+
 }
 
 // Adding a class alias for backwards compatibility with the previous class name.

+ 44 - 0
protophp/Uraus/Kku/Request.php

@@ -71,6 +71,12 @@ class Request extends \Google\Protobuf\Internal\Message
      * Generated from protobuf field <code>.uraus.kku.Request.RequestPublicDeviceInfo public_deviceinfo = 107;</code>
      */
     protected $public_deviceinfo = null;
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Request.RequestPublicLogin4u public_login4u = 199;</code>
+     */
+    protected $public_login4u = null;
     /**
      * 施肥操作请求
      *
@@ -422,6 +428,8 @@ class Request extends \Google\Protobuf\Internal\Message
      *           重置密码
      *     @type \Uraus\Kku\Request\RequestPublicDeviceInfo $public_deviceinfo
      *           设备信息 上报
+     *     @type \Uraus\Kku\Request\RequestPublicLogin4u $public_login4u
+     *           登陆
      *     @type \Uraus\Kku\Request\RequestLandFertilizer $land_fertilizer
      *           施肥操作请求
      *     @type \Uraus\Kku\Request\RequestLandWatering $land_watering
@@ -857,6 +865,42 @@ class Request extends \Google\Protobuf\Internal\Message
         return $this;
     }
 
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Request.RequestPublicLogin4u public_login4u = 199;</code>
+     * @return \Uraus\Kku\Request\RequestPublicLogin4u
+     */
+    public function getPublicLogin4U()
+    {
+        return isset($this->public_login4u) ? $this->public_login4u : null;
+    }
+
+    public function hasPublicLogin4U()
+    {
+        return isset($this->public_login4u);
+    }
+
+    public function clearPublicLogin4U()
+    {
+        unset($this->public_login4u);
+    }
+
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Request.RequestPublicLogin4u public_login4u = 199;</code>
+     * @param \Uraus\Kku\Request\RequestPublicLogin4u $var
+     * @return $this
+     */
+    public function setPublicLogin4U($var)
+    {
+        GPBUtil::checkMessage($var, \Uraus\Kku\Request\RequestPublicLogin4u::class);
+        $this->public_login4u = $var;
+
+        return $this;
+    }
+
     /**
      * 施肥操作请求
      *

+ 70 - 0
protophp/Uraus/Kku/Request/RequestPublicLogin4u.php

@@ -0,0 +1,70 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku\Request;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * 登陆操作
+ *
+ * Generated from protobuf message <code>uraus.kku.Request.RequestPublicLogin4u</code>
+ */
+class RequestPublicLogin4u extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * 登陆密钥
+     *
+     * Generated from protobuf field <code>string keylogin = 1;</code>
+     */
+    protected $keylogin = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $keylogin
+     *           登陆密钥
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Proto\Game::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * 登陆密钥
+     *
+     * Generated from protobuf field <code>string keylogin = 1;</code>
+     * @return string
+     */
+    public function getKeylogin()
+    {
+        return $this->keylogin;
+    }
+
+    /**
+     * 登陆密钥
+     *
+     * Generated from protobuf field <code>string keylogin = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setKeylogin($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->keylogin = $var;
+
+        return $this;
+    }
+
+}
+
+// Adding a class alias for backwards compatibility with the previous class name.
+class_alias(RequestPublicLogin4u::class, \Uraus\Kku\Request_RequestPublicLogin4u::class);
+

+ 16 - 0
protophp/Uraus/Kku/Request_RequestPublicLogin4u.php

@@ -0,0 +1,16 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku;
+
+if (false) {
+    /**
+     * This class is deprecated. Use Uraus\Kku\Request\RequestPublicLogin4u instead.
+     * @deprecated
+     */
+    class Request_RequestPublicLogin4u {}
+}
+class_exists(Request\RequestPublicLogin4u::class);
+@trigger_error('Uraus\Kku\Request_RequestPublicLogin4u is deprecated and will be removed in the next major release. Use Uraus\Kku\Request\RequestPublicLogin4u instead', E_USER_DEPRECATED);
+

+ 44 - 0
protophp/Uraus/Kku/Response.php

@@ -130,6 +130,12 @@ class Response extends \Google\Protobuf\Internal\Message
      * Generated from protobuf field <code>.uraus.kku.Response.ResponsePublicDeviceInfo public_deviceinfo = 107;</code>
      */
     protected $public_deviceinfo = null;
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.ResponsePublicLogin4u public_login4u = 199;</code>
+     */
+    protected $public_login4u = null;
     /**
      * land 200+
      *     import "land_response.proto";
@@ -526,6 +532,8 @@ class Response extends \Google\Protobuf\Internal\Message
      *           重置密码
      *     @type \Uraus\Kku\Response\ResponsePublicDeviceInfo $public_deviceinfo
      *           设备信息上报
+     *     @type \Uraus\Kku\Response\ResponsePublicLogin4u $public_login4u
+     *           登陆
      *     @type \Uraus\Kku\Response\ResponseLandFertilizer $land_fertilizer
      *           land 200+
      *               import "land_response.proto";
@@ -1258,6 +1266,42 @@ class Response extends \Google\Protobuf\Internal\Message
         return $this;
     }
 
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.ResponsePublicLogin4u public_login4u = 199;</code>
+     * @return \Uraus\Kku\Response\ResponsePublicLogin4u
+     */
+    public function getPublicLogin4U()
+    {
+        return isset($this->public_login4u) ? $this->public_login4u : null;
+    }
+
+    public function hasPublicLogin4U()
+    {
+        return isset($this->public_login4u);
+    }
+
+    public function clearPublicLogin4U()
+    {
+        unset($this->public_login4u);
+    }
+
+    /**
+     * 登陆
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.ResponsePublicLogin4u public_login4u = 199;</code>
+     * @param \Uraus\Kku\Response\ResponsePublicLogin4u $var
+     * @return $this
+     */
+    public function setPublicLogin4U($var)
+    {
+        GPBUtil::checkMessage($var, \Uraus\Kku\Response\ResponsePublicLogin4u::class);
+        $this->public_login4u = $var;
+
+        return $this;
+    }
+
     /**
      * land 200+
      *     import "land_response.proto";

+ 148 - 0
protophp/Uraus/Kku/Response/ResponsePublicLogin4u.php

@@ -0,0 +1,148 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku\Response;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * 登陆返回信息 4u
+ *
+ * Generated from protobuf message <code>uraus.kku.Response.ResponsePublicLogin4u</code>
+ */
+class ResponsePublicLogin4u extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * token
+     *
+     * Generated from protobuf field <code>string token = 1;</code>
+     */
+    protected $token = '';
+    /**
+     * 是否封禁
+     *
+     * Generated from protobuf field <code>bool is_prohibit = 2;</code>
+     */
+    protected $is_prohibit = false;
+    /**
+     * 上一次登陆信息
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.LastLoginInfo last_login_info = 3;</code>
+     */
+    protected $last_login_info = null;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $token
+     *           token
+     *     @type bool $is_prohibit
+     *           是否封禁
+     *     @type \Uraus\Kku\Response\LastLoginInfo $last_login_info
+     *           上一次登陆信息
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Proto\Game::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * token
+     *
+     * Generated from protobuf field <code>string token = 1;</code>
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->token;
+    }
+
+    /**
+     * token
+     *
+     * Generated from protobuf field <code>string token = 1;</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setToken($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->token = $var;
+
+        return $this;
+    }
+
+    /**
+     * 是否封禁
+     *
+     * Generated from protobuf field <code>bool is_prohibit = 2;</code>
+     * @return bool
+     */
+    public function getIsProhibit()
+    {
+        return $this->is_prohibit;
+    }
+
+    /**
+     * 是否封禁
+     *
+     * Generated from protobuf field <code>bool is_prohibit = 2;</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setIsProhibit($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->is_prohibit = $var;
+
+        return $this;
+    }
+
+    /**
+     * 上一次登陆信息
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.LastLoginInfo last_login_info = 3;</code>
+     * @return \Uraus\Kku\Response\LastLoginInfo
+     */
+    public function getLastLoginInfo()
+    {
+        return isset($this->last_login_info) ? $this->last_login_info : null;
+    }
+
+    public function hasLastLoginInfo()
+    {
+        return isset($this->last_login_info);
+    }
+
+    public function clearLastLoginInfo()
+    {
+        unset($this->last_login_info);
+    }
+
+    /**
+     * 上一次登陆信息
+     *
+     * Generated from protobuf field <code>.uraus.kku.Response.LastLoginInfo last_login_info = 3;</code>
+     * @param \Uraus\Kku\Response\LastLoginInfo $var
+     * @return $this
+     */
+    public function setLastLoginInfo($var)
+    {
+        GPBUtil::checkMessage($var, \Uraus\Kku\Response\LastLoginInfo::class);
+        $this->last_login_info = $var;
+
+        return $this;
+    }
+
+}
+
+// Adding a class alias for backwards compatibility with the previous class name.
+class_alias(ResponsePublicLogin4u::class, \Uraus\Kku\Response_ResponsePublicLogin4u::class);
+

+ 16 - 0
protophp/Uraus/Kku/Response_ResponsePublicLogin4u.php

@@ -0,0 +1,16 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/game.proto
+
+namespace Uraus\Kku;
+
+if (false) {
+    /**
+     * This class is deprecated. Use Uraus\Kku\Response\ResponsePublicLogin4u instead.
+     * @deprecated
+     */
+    class Response_ResponsePublicLogin4u {}
+}
+class_exists(Response\ResponsePublicLogin4u::class);
+@trigger_error('Uraus\Kku\Response_ResponsePublicLogin4u is deprecated and will be removed in the next major release. Use Uraus\Kku\Response\ResponsePublicLogin4u instead', E_USER_DEPRECATED);
+