### 一、问题核心与设计思路
用户反馈的"沙城主换人可重复领取"问题,本质在于传统脚本仅检测**角色名或行会名**,未绑定**行会唯一标识**与**时间戳验证**。根据中攻沙奖励逻辑,需实现以下核心功能:
1. **行会唯一性锁**:通过`GUILDUNIQUEID`绑定行会唯一标识,即使沙城易主,原行会已领取仍无法重复。
2. **全局时间戳检测**:利用`G变量`记录领取日期,实现每日仅一次领取限制。
3. **双重验证机制**:先校验是否为当前沙城主,再检测行会是否已领取。
---
### 二、完整防重复领取脚本
```lua
;-----------------------------------------
; 沙城领奖NPC脚本(Merchant.txt配置)
; 文件路径:Mir200\Envir\Market_Def\沙城奖励-3
;-----------------------------------------
[@main]
#IF
ISCASTLEMASTER ; 检测是否为沙城主
#ACT
MOV S0 <$GUILDUNIQUEID> ; 获取行会唯一ID
GetGlobalVar G99 S1 ; 读取全局变量G99(记录上次领取日期)
GetGlobalVar G100 S2 ; 读取全局变量G100(记录领取行会ID)
#IF
EQUAL S0 <$STR(S2)> ; 当前行会是否已领取
CHECKTEXTLIST ..\QuestDiary\沙城日志\已领奖日期.txt <$STR(S1)> ; 日期验证
#SAY
您所在行会今日已领取过攻沙奖励!\
<离开/@exit>
#ELSESAY
尊敬的沙城主【<$USERNAME>】,今日可领取攻沙奖励:\
<领取元宝奖励/@getreward>\
<查看领取记录/@checklog>\
<离开/@exit>
[@getreward]
#IF
HOUR 22 22 ; 限时22:00-23:00(根据时间规则)
ISCASTLEMASTER
SMALL <$STR(G99)> <$DATENUM> ; 日期是否更新
#ACT
CALCVAR G99 = <$DATENUM> ; 更新全局日期变量
SAVEVAR G99 ..\QuestDiary\沙城日志\全局变量.txt
CALCVAR G100 = <$GUILDUNIQUEID> ; 绑定行会唯一ID
SAVEVAR G100 ..\QuestDiary\沙城日志\全局变量.txt
AddTextListEx ..\QuestDiary\沙城日志\已领奖日期.txt <$STR(G99)> ; 记录日期
GAMEGOLD + 200000 ; 发放20万元宝(数值可调)
SENDMSG 6 【系统】沙城奖励已发放至行会【<$GUILDNAME>】金库!
#ELSESAY
领取失败!请检查:\
1. 当前时间非22:00-23:00\
2. 今日奖励已领取\
3. 非沙城主无法操作
```
---
### 三、关键技术解析
#### 1. **行会唯一ID绑定**
- **`<$GUILDUNIQUEID>`**:引擎生成的行会唯一标识码,即使行会更名或城主更换,ID不变。
- **全局变量G100**:记录最后一次领取奖励的行会ID,防止跨行会重复领取。
#### 2. **时间戳防跨天漏洞**
- **`<$DATENUM>`**:获取系统日期数字(如20240331),比传统`CHECKTIME`更精准。
- **双验证机制**:
- `CALCVAR G99 = <$DATENUM>` 更新领取日期
- `CHECKTEXTLIST`检测日期文件,避免变量被篡改。
#### 3. **日志追踪与防篡改**
- **文本记录**:在`QuestDiary\沙城日志`目录下生成:
- `已领奖日期.txt`:记录所有领取日期
- `全局变量.txt`:存储G99/G100变量值
- **SAVEVAR命令**:持久化存储变量,重启服务器不丢失。
---
### 四、进阶优化方案
#### 1. **行会金库替代个人领取**
```lua
#ACT
GUILDGAMEGOLD + 200000 ; 奖励发放至行会金库
SENDMSG 0 【全服公告】行会【<$GUILDNAME>】成功领取今日攻沙奖励20万元宝!
```
通过`GUILDGAMEGOLD`实现奖励归属行会,避免个人城主独占(需M2支持行会资金功能)。
#### 2. **多维度安全校验**
```lua
#IF
CHECKVARLIST ..\QuestDiary\沙城日志\封禁行会.txt <$GUILDUNIQUEID>
#SAY
您的行会因违规已被禁止领取奖励!
```
加入封禁名单检测,增强反作弊能力。
#### 3. **自动清理过期记录**
```lua
#CALL [\系统任务\定时清理.txt] @clearlog
; 定时清理脚本(每日0点执行)
[@clearlog]
#IF
EQUAL <$SERVERDAY> 1
#ACT
CLEARVAR G99 G100
DELTEXTLIST ..\QuestDiary\沙城日志\已领奖日期.txt *
```
避免日志文件无限膨胀。
---
### 五、常见问题排查
#### 1. **换城主仍能领取**
- **原因**:未使用`<$GUILDUNIQUEID>`,误用`<$GUILDNAME>`检测。
- **解决**:确保脚本中所有行会标识均采用唯一ID。
#### 2. **变量不保存**
- **检查**:`SAVEVAR`路径是否正确,`全局变量.txt`需有写入权限。
- **命令修正**:
```lua
SAVEVAR G99 ..\QuestDiary\沙城日志\全局变量.txt
```
#### 3. **时间检测失效**
- **校准**:在M2控制台输入`@DATE`查看服务器时间,时区需与脚本匹配。
- **备用方案**:
```lua
#IF
CHECKTIME 22:00-23:00
用户反馈的"沙城主换人可重复领取"问题,本质在于传统脚本仅检测**角色名或行会名**,未绑定**行会唯一标识**与**时间戳验证**。根据中攻沙奖励逻辑,需实现以下核心功能:
1. **行会唯一性锁**:通过`GUILDUNIQUEID`绑定行会唯一标识,即使沙城易主,原行会已领取仍无法重复。
2. **全局时间戳检测**:利用`G变量`记录领取日期,实现每日仅一次领取限制。
3. **双重验证机制**:先校验是否为当前沙城主,再检测行会是否已领取。
---
### 二、完整防重复领取脚本
```lua
;-----------------------------------------
; 沙城领奖NPC脚本(Merchant.txt配置)
; 文件路径:Mir200\Envir\Market_Def\沙城奖励-3
;-----------------------------------------
[@main]
#IF
ISCASTLEMASTER ; 检测是否为沙城主
#ACT
MOV S0 <$GUILDUNIQUEID> ; 获取行会唯一ID
GetGlobalVar G99 S1 ; 读取全局变量G99(记录上次领取日期)
GetGlobalVar G100 S2 ; 读取全局变量G100(记录领取行会ID)
#IF
EQUAL S0 <$STR(S2)> ; 当前行会是否已领取
CHECKTEXTLIST ..\QuestDiary\沙城日志\已领奖日期.txt <$STR(S1)> ; 日期验证
#SAY
您所在行会今日已领取过攻沙奖励!\
<离开/@exit>
#ELSESAY
尊敬的沙城主【<$USERNAME>】,今日可领取攻沙奖励:\
<领取元宝奖励/@getreward>\
<查看领取记录/@checklog>\
<离开/@exit>
[@getreward]
#IF
HOUR 22 22 ; 限时22:00-23:00(根据时间规则)
ISCASTLEMASTER
SMALL <$STR(G99)> <$DATENUM> ; 日期是否更新
#ACT
CALCVAR G99 = <$DATENUM> ; 更新全局日期变量
SAVEVAR G99 ..\QuestDiary\沙城日志\全局变量.txt
CALCVAR G100 = <$GUILDUNIQUEID> ; 绑定行会唯一ID
SAVEVAR G100 ..\QuestDiary\沙城日志\全局变量.txt
AddTextListEx ..\QuestDiary\沙城日志\已领奖日期.txt <$STR(G99)> ; 记录日期
GAMEGOLD + 200000 ; 发放20万元宝(数值可调)
SENDMSG 6 【系统】沙城奖励已发放至行会【<$GUILDNAME>】金库!
#ELSESAY
领取失败!请检查:\
1. 当前时间非22:00-23:00\
2. 今日奖励已领取\
3. 非沙城主无法操作
```
---
### 三、关键技术解析
#### 1. **行会唯一ID绑定**
- **`<$GUILDUNIQUEID>`**:引擎生成的行会唯一标识码,即使行会更名或城主更换,ID不变。
- **全局变量G100**:记录最后一次领取奖励的行会ID,防止跨行会重复领取。
#### 2. **时间戳防跨天漏洞**
- **`<$DATENUM>`**:获取系统日期数字(如20240331),比传统`CHECKTIME`更精准。
- **双验证机制**:
- `CALCVAR G99 = <$DATENUM>` 更新领取日期
- `CHECKTEXTLIST`检测日期文件,避免变量被篡改。
#### 3. **日志追踪与防篡改**
- **文本记录**:在`QuestDiary\沙城日志`目录下生成:
- `已领奖日期.txt`:记录所有领取日期
- `全局变量.txt`:存储G99/G100变量值
- **SAVEVAR命令**:持久化存储变量,重启服务器不丢失。
---
### 四、进阶优化方案
#### 1. **行会金库替代个人领取**
```lua
#ACT
GUILDGAMEGOLD + 200000 ; 奖励发放至行会金库
SENDMSG 0 【全服公告】行会【<$GUILDNAME>】成功领取今日攻沙奖励20万元宝!
```
通过`GUILDGAMEGOLD`实现奖励归属行会,避免个人城主独占(需M2支持行会资金功能)。
#### 2. **多维度安全校验**
```lua
#IF
CHECKVARLIST ..\QuestDiary\沙城日志\封禁行会.txt <$GUILDUNIQUEID>
#SAY
您的行会因违规已被禁止领取奖励!
```
加入封禁名单检测,增强反作弊能力。
#### 3. **自动清理过期记录**
```lua
#CALL [\系统任务\定时清理.txt] @clearlog
; 定时清理脚本(每日0点执行)
[@clearlog]
#IF
EQUAL <$SERVERDAY> 1
#ACT
CLEARVAR G99 G100
DELTEXTLIST ..\QuestDiary\沙城日志\已领奖日期.txt *
```
避免日志文件无限膨胀。
---
### 五、常见问题排查
#### 1. **换城主仍能领取**
- **原因**:未使用`<$GUILDUNIQUEID>`,误用`<$GUILDNAME>`检测。
- **解决**:确保脚本中所有行会标识均采用唯一ID。
#### 2. **变量不保存**
- **检查**:`SAVEVAR`路径是否正确,`全局变量.txt`需有写入权限。
- **命令修正**:
```lua
SAVEVAR G99 ..\QuestDiary\沙城日志\全局变量.txt
```
#### 3. **时间检测失效**
- **校准**:在M2控制台输入`@DATE`查看服务器时间,时区需与脚本匹配。
- **备用方案**:
```lua
#IF
CHECKTIME 22:00-23:00

