查看: 4866|回复: 1
打印 上一主题 下一主题

深度分析L1J的加速检测机制

[复制链接]

0

主题

0

好友

0

积分

哥布林

Rank: 1

UID
355
帖子
98
精华
1
积分
0 点
注册时间
2008-7-24
在线时间
39 小时
跳转到指定楼层
1#
发表于 2008-8-11 15:31:03 |显示全部楼层 |倒序浏览
配置文件server.properties中的设定
------------------------------------------------------------
是否检测移动、攻击、施法速度
CheckMoveInterval = false
CheckAttackInterval = false
CheckSpellInterval = false
不正常速度累计次数满多少次后断线
InjusticeCount = 10
正常速度累计次数满多少次后清空不正常速度计数
JusticeCount = 4
检测系数,容许的检测偏差,105以上是放宽,100以下是严格
CheckStrictness = 102
------------------------------------------------------------


代码端AcceleratorChecker类的检测

L1J检测加速原理是根据客户端封包的发送间隔来做的。

系数经计算调整为0.97
private static final double CHECK_STRICTNESS = (Config.CHECK_STRICTNESS - 5) / 100D;

获取封包发送间隔并乘以系数0.97
long now = System.currentTimeMillis();
long interval = now - _actTimers.get(type);
interval *= CHECK_STRICTNESS;

根据动作类型获取正常间隔,动作类型有MOVE(移动), ATTACK(攻击), SPELL_DIR(有向魔法), SPELL_NODIR(无向魔法)
int rightInterval = getRightInterval(type);

计算,间隔大于0并且小于正常间隔,则非正常计数器+1,满10次后断线,记录日志并显示在控制台上,如果中间有累计4次间隔正常的,则非正常计数器清0
if (0 < interval && interval < rightInterval) {
    _injusticeCount++;
    _justiceCount = 0;
    if (_injusticeCount >= INJUSTICE_COUNT_LIMIT) {
        doDisconnect();
        return R_DISCONNECTED;
    }
    result = R_DETECTED;
} else if (interval >= rightInterval) {
    _justiceCount++;
        if (_justiceCount >= JUSTICE_COUNT_LIMIT) {
        _injusticeCount = 0;
        _justiceCount = 0;
    }
}

这个是L1J服务器端的检测,网络卡以至于速度变慢,封包发送的间隔是大于正常间隔的,所以属于正常范围的。

有一点疑问,也就是网络卡得不动的时候,天堂的客户端是否会把封包累积起来一下子发很多?这个从客户端的设计角度来看是不可能的,因为当客户端发送一个封包后只有等待服务器返回一个封包后才会发送下一个,就好比打了个怪物,服务器要返回你打中了怪物没,伤了多少血后,你才能发送下一个攻击封包。这也是为什么一个可以在5秒内打死的怪物,在卡了20秒后突然网络通了,怪物依旧还是要打5秒才能死,而不是被一连串的攻击封包而秒杀。


---------------------------------------------------------------------
无限的服务器是这样写的
        public boolean isFastMovable() {
                return (hasSkillEffect(L1SkillId.HOLY_WALK)
                                || hasSkillEffect(L1SkillId.MOVING_ACCELERATION)
                                || hasSkillEffect(L1SkillId.WIND_WALK));
        }

        public boolean isBrave() {
                return hasSkillEffect(L1SkillId.STATUS_BEGIN);
        }

        private int invisDelayCounter = 0;

        public boolean isInvisDelay() {
                return (invisDelayCounter > 0);
        }

        private Object _invisTimerMonitor = new Object();

        public void addInvisDelayCounter(int counter) {
                synchronized (_invisTimerMonitor) {
                        invisDelayCounter += counter;
                }
        }

        private static final long DELAY_INVIS = 3000L;

        public void beginInvisTimer() {
                addInvisDelayCounter(1);
                GeneralThreadPool.getInstance().pcSchedule(new L1PcInvisDelay(getId()),
                                DELAY_INVIS);
        }

        private long _oldMoveTimeInMillis = 0L;
        private int _moveInjustice = 0;

        public void checkMoveInterval() {
                long nowMoveTimeInMillis = System.currentTimeMillis();

                long moveInterval = nowMoveTimeInMillis - _oldMoveTimeInMillis;
                int speedStage = 0;
                if (hasSkillEffect(L1SkillId.STATUS_HASTE)
                                || hasSkillEffect(L1SkillId.HASTE) // GP、ヘイスト
                                || hasSkillEffect(L1SkillId.GREATER_HASTE)
                                || getMoveSpeed() == 1) { // グレーターヘイスト、ヘイスト状態
                        speedStage++;
                }
                if (hasSkillEffect(L1SkillId.STATUS_BEGIN)
                                || hasSkillEffect(L1SkillId.HOLY_WALK)
                                || hasSkillEffect(L1SkillId.MOVING_ACCELERATION)
                                || hasSkillEffect(L1SkillId.WIND_WALK)) {
                        speedStage++;
                }
                if (getTempCharGfx() == 3863 // ドワーフ
                                || getTempCharGfx() == 1037 // ジャイアントアント
                                || getTempCharGfx() == 95 // ジャイアントスパイダー
                                || getTempCharGfx() == 146 // ドレッドスパイダー
                                || getTempCharGfx() == 3631 // グリフォン
                                || getTempCharGfx() == 3632 // コカトリス
                                || getTempCharGfx() == 3888 // バフォメット
                                || getTempCharGfx() == 3905 // ベレス
                                || getTempCharGfx() == 4003 // ブラックナイト
                                || getTempCharGfx() == 4133 // ハイラクーン
                                || getTempCharGfx() == 2501) { // ジャックオーランタン
                        speedStage++;
                }
                int minMoveInterval = 0;
                if (speedStage == 0) { // 加速なし
                        minMoveInterval = Config.MINIMUM_MOVE_INTERVAL0;
                } else if (speedStage == 1) { // 1段階加速
                        minMoveInterval = Config.MINIMUM_MOVE_INTERVAL1;
                } else if (speedStage == 2) { // 2段階加速
                        minMoveInterval = Config.MINIMUM_MOVE_INTERVAL2;
                } else if (speedStage == 3) { // 3段階加速
                        minMoveInterval = Config.MINIMUM_MOVE_INTERVAL3;
                }
                if (minMoveInterval >= moveInterval) { // 移動要求の間隔が短すぎる
                        _moveInjustice++;
                        if (_moveInjustice >= Config.MOVE_INJUSTICE_COUNT) { // 連続で不正な移動要求間隔
                                _log.info("系統檢測出不正常移動速度," + getName() + "系統強制斷線。");
                                sendPackets(new S_Disconnect());
                                _moveInjustice = 0;
                        }
                } else { // 移動要求間隔が正常
                        _moveInjustice = 0;
                }

                _oldMoveTimeInMillis = nowMoveTimeInMillis;
        }

        private long _oldAttackTimeInMillis = 0L;
        private int _attackInjustice = 0;

        public int getAttackInjustice() {
                return _attackInjustice;
        }

        public void checkAttackInterval() {
                long nowAttackTimeInMillis = System.currentTimeMillis();
                long attckInterval = nowAttackTimeInMillis - _oldAttackTimeInMillis;
                if (Config.MINIMUM_ATTACK_INTERVAL >= attckInterval) { // 攻撃要求の間隔が短すぎる
                        _attackInjustice++;
                        if (_attackInjustice >= Config.ATTACK_INJUSTICE_COUNT) { // 連続で不正な攻撃要求間隔
                                _log.info("系統檢測出不正常攻擊速度," + getName() + "系統強制斷線。");
                                sendPackets(new S_Disconnect());
                                _attackInjustice = 0;
                        }
                } else { // 攻撃要求間隔が正常
                        _attackInjustice = 0;
                }
                _oldAttackTimeInMillis = nowAttackTimeInMillis;
        }

原理是一样的.不过排除了各个变身的攻击速度差异.也就是说.你在有些服务器变身南瓜人或拿加速的大巴武器可能会判定为加速,而这里不会

0

主题

0

好友

0

积分

哥布林

Rank: 1

UID
355
帖子
98
精华
1
积分
0 点
注册时间
2008-7-24
在线时间
39 小时
2#
发表于 2008-8-11 16:12:15 |显示全部楼层
不会,在服务期端,你依旧是在线的,怪物依旧在打你,只是,你没法发送喝水、攻击、移动之类的封包给服务器了,所以即使你按住喝水,还是要等网络通后一个一个计算的,而不是一下子会喝很多,但是怪物的攻击在服务器端的,所以是持续的在打你,卡久了,你就死了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

Archiver|手机版|无限天堂 ( 黔ICP备18002592号-1 )

GMT+8, 2024-5-15 18:55 , Processed in 1.263824 second(s), 21 queries .

Powered by Discuz! X2.5 Licensed

© 2001-2012 Comsenz Inc.Design by Singcere.Net

回顶部