Валидация playable-персонажей

  • Автор темы Автор темы TheMads
  • Дата начала Дата начала

TheMads

Знаменитый
Участник
Сообщения
118
Розыгрыши
0
Репутация
5
Реакции
15
Баллы
1 270
Добрый вечер, решил переписать flytype-скилы (Rush Impact, Shadow Step, Warp и тд) и на последнем этапе столкнулся с проблемой некорректной обработки движения после использования Charge-скилов.

Баг актуален для всех сборок на базе l2p (Так же актуально для l2gw) даже если не трогать изначальный код.

В чем суть:
Если после окончания каста (после срабатывания clearCastVars() и finishFly()) начать отбегать то подключается nextAction.MOVE (обрабатывается в PlayableAI). По окончанию бега если персонаж на стороне клиента не добегает до точки то его возвращает в последние координаты после каста (в координаты, что находится в переменной _flyLoc и возвращается функцией getFlyLoc()).

Соответственно бежать можно бесконечно и по итогу персонаж все равно окажется на "левых" координатах. При этом после окончания бега сработает пакет validatePosition и переместит/портанет персонажа в зависимости от diff между клиентом и сервером.

Данного бага не было на лайве лостворлда (в шарных сурсах он остался)

Подробней как это проявляется:

Собственно вопрос - кто-то фиксил этот момент? Такое чувство что он зарыт где-то в мув-листе
 
А зачем в начале темы ты пишешь что используешь Finish fly

Если по сути этот метод не как не обрабатывает скилы с багом ?

Тут весь глюк в неверных расчетах или точнее заглушках,
вот зачем присваивать loc = applyOffset(target.getLoc(), (int) target.getColRadius()+40); с левым радиусом, от 8-20+40 ?
а потом снова присваивать Loc от цели , если она "чем то закрыта" , получается что присваивание Offset не как не влияет .

как по мне это та самая проблема, и она возможно глубжке( в самом canMoveToCoord) .

P.S.
Вот честно зачем делать отдельный метод SetLocOnFly , если все что он делает это перемещает по XYZ .И я бы глянул что из себя представляет этот XYZ у тебя!
Да и пихать в getFlyLocation проверки которые в большенстве дублируют те что в обычном getLocation, на мой взгляд не стоит .
И как вот это понимать ?

Ранее в FinishFly использовался setLocOnFly, в последствии я его оттуда вынес для теста что бы он отрабатывал раньше чем обнулятся все переменные связанные с кастом.

С радиусом поясню:
Если выставить просто getColRadius() - персонаж будет влетать в моба, если выставить просто 45 (мин радиус атаки) - персонаж будет влетать в мобов с большим радиусом, как универсальное решение - просто добавлять радиус атаки к текущему радиусу моба. Вообщем то больше не для чего.

Все что ниже applyOffset - рудемент от старых разработчиков, вроде бы даже от l2p 10тилетней давности.
По поводу canMoveToCoord - первая проверка соотв проверяет может ли персонаж дойти до точки, если не может - выставляем в локацию текущую координату таргета "без добавок" и проверяем еще раз и в случае если опять таки не может - отменяем каст, тут по факту ничего не логичного нет.

Сам canMoveToCoord вызывает метод canMove в геодвижке:
Код:
    /**
    * проверка проходимости по прямой
    */
    private static boolean canMove(int __x, int __y, int _z, int __tx, int __ty, int _tz, boolean withCollision, int geoIndex)
    {
        int _x = __x - World.MAP_MIN_X >> 4;
        int _y = __y - World.MAP_MIN_Y >> 4;
        int _tx = __tx - World.MAP_MIN_X >> 4;
        int _ty = __ty - World.MAP_MIN_Y >> 4;

        int diff_x = _tx - _x, diff_y = _ty - _y;
        int incx = sign(diff_x), incy = sign(diff_y);
        final boolean overRegionEdge = ((_x >> 11) != (_tx >> 11) || (_y >> 11) != (_ty >> 11));

        if(diff_x < 0)
            diff_x = -diff_x;
        if(diff_y < 0)
            diff_y = -diff_y;

        int pdx, pdy, es, el;

        if(diff_x > diff_y)
        {
            pdx = incx;
            pdy = 0;
            es = diff_y;
            el = diff_x;
        }
        else
        {
            pdx = 0;
            pdy = incy;
            es = diff_x;
            el = diff_y;
        }

        int err = el / 2;

        int curr_x = _x, curr_y = _y, curr_z = _z;
        int next_x = curr_x, next_y = curr_y, next_z = curr_z;

        short[] next_layers = new short[MAX_LAYERS + 1];
        short[] temp_layers = new short[MAX_LAYERS + 1];
        short[] curr_layers = new short[MAX_LAYERS + 1];

        NGetLayers(curr_x, curr_y, curr_layers, geoIndex);
        if(curr_layers[0] == 0)
            return true;

        for(int i = 0; i < el; i++)
        {
            err -= es;
            if(err < 0)
            {
                err += el;
                next_x += incx;
                next_y += incy;
            }
            else
            {
                next_x += pdx;
                next_y += pdy;
            }
            boolean regionEdge = overRegionEdge && ((next_x >> 11) != (curr_x >> 11) || (next_y >> 11) != (curr_y >> 11));

            NGetLayers(next_x, next_y, next_layers, geoIndex);
            if((next_z = NcanMoveNext(curr_x, curr_y, curr_z, curr_layers, next_x, next_y, next_layers, temp_layers, withCollision, regionEdge, geoIndex)) == Integer.MIN_VALUE)
                return false;

            short[] t = curr_layers;
            curr_layers = next_layers;
            next_layers = t;

            curr_x = next_x;
            curr_y = next_y;
            curr_z = next_z;
        }

        int diff_z = curr_z - _tz;
        if(Config.ALLOW_FALL_FROM_WALLS) // Разрешить падать со стен ?
            return diff_z < Config.MAX_Z_DIFF ? true : false;

        if(diff_z < 0)
            diff_z = -diff_z;
        return diff_z > Config.MAX_Z_DIFF ? false : true; // Проверка на максимальное отклонение по координате Z
    }


По породу setLocOnFLy - На данных сборках присутствует мувРекодер который по идее синхронизирует координаты между клиентом и сервером, поэтому SetLocOnFly создан с целью выставления координат в переменные хранящие клиент-серверные координаты. По хорошему нужно увеличить допуск рассинхрона, а еще лучше - избавиться от него и использовать пакет validatePosition. А так по факту полный аналог обычного setLoc.

Если перс в ФлайТрансформе/виверне то он не будет возвращать Null.
Первое условие содержит проверку на координату Z. На сколько известно чардж-скилы есть только у трансформы в птиц и финал трансформы полета и на сколько я помню континент грации задействует опредленные координаты, т.е от 0 до 6 тыс. Ниже и выше он будет возвращать null.

Вторая проверка - аналог canMoveToCoord но в полете, по факту меня не особо пока интересуют эти проверки т.к их удаление ничего не решает.

По setXYZ, он одинаковый для всех дочерних классов GameObject и просто записывает в переменные _x, _y, _z координаты (Заранее - addVisibleObject проверяет, сменился ли регион в котором находится обьект):
Код:
    public void setXYZ(int x, int y, int z)
    {
        _x = World.validCoordX(x);
        _y = World.validCoordY(y);
        _z = World.validCoordZ(z);

        World.addVisibleObject(this, null);
    }

Сами эти координаты позже используются в таске и функциях передвижения и прочей лабуде с помощью функций getX(), getY(), getZ().
 

Обратите внимание, что данный пользователь заблокирован! Не совершайте с ним никаких сделок! Перейдите в его профиль, чтобы узнать причину блокировки.
Желательно тебе это все в режиме дебага проследить . В качестве теста выпили offset из getflyloc и проверь как будет. Если так же выпиливай SetLocOnFly и FinishFly. И я так понял то что ты скидывал это не оригинал , а обрезаное ? Тебе тогда проще глянуть в лыжу где этого бага нету , или в декомпил л2сервера, а так это все пальцем в небо.
 
Желательно тебе это все в режиме дебага проследить . В качестве теста выпили offset из getflyloc и проверь как будет. Если так же выпиливай SetLocOnFly и FinishFly. И я так понял то что ты скидывал это не оригинал , а обрезаное ? Тебе тогда проще глянуть в лыжу где этого бага нету , или в декомпил л2сервера, а так это все пальцем в небо.

На лыже все немного проще:

Изначально установка локации работает посредством таска с 50 мс задержкой (Почему и зачем до конца не понятно):
Код:
        // Before start AI Cast Broadcast Fly Effect is Need
        if (skill.getFlyType() != null)
        {
            ThreadPoolManager.getInstance().scheduleEffect(new FlyToLocationTask(this, target, skill), 50);
        }

Сам таск немного интересен - локацией является просто текущая локация без каких либо просчетов:
Код:
        if (_character != null)
        {
            _character.broadcastPacket(new FlyToLocation(_character, _target, _skill.getFlyType()));
            _character.setXYZ(_target.getX(), _target.getY(), _target.getZ());
        }

Перенес код с лыжи.
Если цель во время раша не умирает - он работает как надо, если умирает - идет резкий обрыв и баг проявляется снова, видимо нужно копать еще грубже даже не в мувинг
 
Обратите внимание, что данный пользователь заблокирован! Не совершайте с ним никаких сделок! Перейдите в его профиль, чтобы узнать причину блокировки.
Всмысле копать глубже ? Тебе же раз в 50мс кастует пакет( с локой моба), моб дохнет и отправляет null , сделай if target null, finishMovement( остановись там где надо)
 
Всмысле копать глубже ? Тебе же раз в 50мс кастует пакет( с локой моба), моб дохнет и отправляет null , сделай if target null, finishMovement( остановись там где надо)

scheduleEffect проигрывается один раз грубо говоря, поставил на всякий условие на null, но дело опять же не в нем, null он не возвращает (это бы сразу вылезло в консоль сервера)
Можно попробовать обернуть бродкаст пакета в try {} catch {}.

Мне кажется нужно смотреть в сторону пакета Die, возможно фукнции по типу onDeath и смежные выставляют лишние переменные или опять же содержат заглушки


Исправленный вариант.
Можно заметить что иногда персонажа кидает обратно даже если моб просто идет (при этом он не мертвый) и в любом случае если он мертв

Передумал копать в сторону onDeath, возможно что-то с локацией таргета при setXYZ (изначально в холдер передаются косячные и getX, getY и getZ возвращают испорченные координаты)
 
Последнее редактирование модератором:
Обратите внимание, что данный пользователь заблокирован! Не совершайте с ним никаких сделок! Перейдите в его профиль, чтобы узнать причину блокировки.
scheduleEffect проигрывается один раз грубо говоря, поставил на всякий условие на null, но дело опять же не в нем, null он не возвращает (это бы сразу вылезло в консоль сервера)
Можно попробовать обернуть бродкаст пакета в try {} catch {}.

Мне кажется нужно смотреть в сторону пакета Die, возможно фукнции по типу onDeath и смежные выставляют лишние переменные или опять же содержат заглушки
Посмотри что у тебя за значения в локе , когда моб здох, они скорее всего левые, а те 50 мс похоже не на задержку , а на повторное в потоке раз в 50 мс , но опять же я не вижу всего кода ! И брейк ты должен ставить в пул менеджер
 
Посмотри что у тебя за значения в локе , когда моб здох, они скорее всего левые, а те 50 мс похоже не на задержку , а на повторное в потоке раз в 50 мс , но опять же я не вижу всего кода ! И брейк ты должен ставить в пул менеджер

Наврятли это поток раз в 50 мс, для теста попробую как раз сделать такой поток с брейком, отпишусь что из этого получится

Ну как я и думал) Персонаж просто начинает дрыгаться как эпилептик)

Вообщем полный код текущего варианта:

Код:
            case CHARGE:
                //_flyLoc = getFlyLocation(target, skill);
                if(_flyLoc != null) {
                        //broadcastPacket(new FlyToLocation(this, _flyLoc, skill.getFlyType()));
                        setPrevLoc(getLoc());
                        _newFlyTask = ThreadPoolManager.getInstance().scheduleEffect(new NewRushTask(this, target, skill), 50);
                }
                else
                {
                    sendPacket(SystemMsg.CANNOT_SEE_TARGET);
                    return;
                }

Сам таск:
Код:
    public static class NewRushTask extends RunnableImpl
    {
        public Creature _character;
        public GameObject _target;
        public Skill _skill;

        public NewRushTask(Creature character, GameObject target, Skill skill)
        {
            _character = character;
            _target = target;
            _skill = skill;
        }

        @Override
        public void runImpl()
        {          
            if(_target == null)
                return;
          
            if(_character.isPlayer())
                _character.getPlayer().sendMessage("Target log: "+_target.getLoc());

            if(!_character.isCastingNow()){
                _character.clearFlyTask();
                return;
            }

            _character.broadcastPacket(new FlyToLocation(_character, _target.getLoc(), _skill.getFlyType()));
            _character.setXYZ(_target.getX(), _target.getY(), _target.getZ());
        }
    }

clearFlyTas() просто обнуляет текущий таск
Код:
    public void clearFlyTask() {
        _newFlyTask = null;
    }
 
Последнее редактирование модератором:

    ツsmile10ツ

    Баллов: 0
    Спасибо за вклад в развитие форума
@TheMads, т.е хочешь сказать ты за день переписал весь мувинг? А то и меньше
 
@TheMads, т.е хочешь сказать ты за день переписал весь мувинг? А то и меньше
Мувинг не трогал за исключением глупых заглушек, в самом мувинге никаких явных проблем не заметил по дебагу, весь путь корректно просчитывается. Смысл его трогать? Мне нужно найти причину отброса к позиции FlyToLocation-пакета. Дело в том что перемещает даже не SetLoc а что-то иное.
 
Мувинг не трогал за исключением глупых заглушек, в самом мувинге никаких явных проблем не заметил по дебагу, весь путь корректно просчитывается. Смысл его трогать? Мне нужно найти причину отброса к позиции FlyToLocation-пакета. Дело в том что перемещает даже не SetLoc а что-то иное.
Не читал с начала, но все равно напишу:
После отправки пакета FlyToLocation всегда серверу шлется пакет ValidatePosition. Вы уверены, что вас кидает не этот пакет?
И еще: для правильной работы полетных скиллов необходимо сначала установить координаты, а потом только отправить пакет FlyToLocation.
 
Не читал с начала, но все равно напишу:
После отправки пакета FlyToLocation всегда серверу шлется пакет ValidatePosition. Вы уверены, что вас кидает не этот пакет?
И еще: для правильной работы полетных скиллов необходимо сначала установить координаты, а потом только отправить пакет FlyToLocation.

ValidatePosition - первое о чем я подумал вообще, комментил все содержимое пакета оставляя базовую структуру, никакого результата от этого нет.

При этом в пакетнике у пакетов ValidatePosition, MoveToLocation и ValidateLocation корректные локации.
В дебаге передвижения и отдельно функции SetLoc тоже никаких проблем.

Добавил установку координат до начала бродкаста FlyToLocation - в корне ничего не изменилось. (Старую установку соотв удалил)

Отбрасывает только если цель двигается или умирает, при этом в конце каста осуществляется какой-то резкий рывок (не всегда).

Плюсом - это не может быть validatePosition тк он отправляется во время бега, вся уникальность ситуации в том, что отбрасывает когда персонаж добегает до курсора со стороны сервера, т.е можно использовать раш и бегать минут 5 без остановки, но после тебя все равно откинет на ту точку.

На ПТСе кстати validatePosition не отправляется если после юза никуда не бежишь:
9rNb5yezTm8.webp

Точней не на ПТСе а вообще, по крайней мере на ХФ

Решил отключить полностью пакет ValidatePositon и убрал из кода FlyToLocation оставив единственный setXYZ, персонажа вообще не кидает при любых условиях и при этом четко меняются координаты, могут ли быть дополнительные условия для FlyToLocation?

P.S: Если выполнить setLoc до бродкаста пакета в хлапе бродкаст выполняется сразу из установленных координат (т.е из локации таргета в локацию таргета), на птске идет бродкаст текущей позиции в позицию таргета

Есть идея сначала сохранять в переменную текущие координаты, выставлять локацию а после бродкастить пакет из сохраненных координат в необходимые
 
Последнее редактирование модератором:
кидает из-за пакета ValidateLocation который приходит после использования скила
 
кидает из-за пакета ValidateLocation который приходит после использования скила

Спорный момент, я переписал мувинг на основе текущего более оффлайк, т.е ValidateLocation используется только при выделении на таргет, при слишком большой разнице клиент-серверных координат и еще паре моментов.

Сам пакет после юза прописывался в finishFly(), он для чардж скилов у меня не используется (только для DUMMY и других типов полетов)

При этом после использования скила ValidateLocation не приходит, приходит ValidatePosition, но пакет ValidatePosition в моем случае не обрабатывает ничего во время юза и после юза скила в течении некоторого времени разницы в координатах

При этом сам баг не число клиентский, персонажа так же кидает и для игроков со стороны, при первом же передвижении ValidatePosition отрабатывает и возвращает большой diff что либо с помощью пакета ValidateLocation резко переместит персонажа или даже телепортирует в локацию где он по идее должен быть
 
Спорный момент, я переписал мувинг на основе текущего более оффлайк, т.е ValidateLocation используется только при выделении на таргет, при слишком большой разнице клиент-серверных координат и еще паре моментов.

Сам пакет после юза прописывался в finishFly(), он для чардж скилов у меня не используется (только для DUMMY и других типов полетов)

При этом после использования скила ValidateLocation не приходит, приходит ValidatePosition, но пакет ValidatePosition в моем случае не обрабатывает ничего во время юза и после юза скила в течении некоторого времени разницы в координатах

При этом сам баг не число клиентский, персонажа так же кидает и для игроков со стороны, при первом же передвижении ValidatePosition отрабатывает и возвращает большой diff что либо с помощью пакета ValidateLocation резко переместит персонажа или даже телепортирует в локацию где он по идее должен быть
Давно этим не занимался, но валидейтПозишн отправляется только от клиента, если я правильно помню, валидейтЛокейшн отправляется при определенном не совпадении координат и каждый определенный промежуток времени конкретно клиенту, в птс валидейЛокейшн не отправляется клиенту после чаржа, тут же отправляется, что и является проблемой, поправьте если я не прав

п.с. Кстати, сам чарж работает не правильно, он с любой позиции перемещает игрока за спину противнику, но это не блинк ножа, это чарж, этот скил должен приближать к врагу на минимальное расстояние, а не за спину

и да, этот баг актуален для всех сборок, от забугорных до наших, из-за скорости бега и каста он не так заметен, если тестить под фул бафом, но он все равно есть
 
Последнее редактирование модератором:
п.с. Кстати, сам чарж работает не правильно, он с любой позиции перемещает игрока за спину противнику, но это не блинк ножа, это чарж, этот скил должен приближать к врагу на минимальное расстояние, а не за спину
Все верно, на данный момент (у меня) чардж скил перемещает к противнику (ближайшей точке) а не за спину. На ПТС валидейтлокейшен отправляется вообще в редких случаях (не знаю почему в яве он на каждом шагу). На данный момент после скила он не отправляется (отправляется только клиентский пакет). Более того - для теста я вообще вырезал полностью функционал ValidatePosition и комментил все отправки ValidateLocation. Это не помогает.

По видео что ранее я выкладывал (даже в первом сообщении) можно понять что возвращает на позицию flyLoc только после окончания передвижения, т.е при StopMove. При этом StopMove на данный момент у меня не возвращает ValidateLocation.

Все это давно поправлено, и нормально работает если таргет стоит на месте. Как только таргет умирает или передвигается - появляется данный баг.
Что странно для меня - в пакетнике все координаты во всех пакетах отправляются корректно но клиент почему-то решает что нужно вернуть персонажа в позицию flyLoc.

Как вариант - заглушка на каст спид чардж скилов, т.е выставить мин каст в 540 (на тестах при 540 бага нет но его юз далек от оффлайка)
 
Сурсы какие? Лосты? Потому что я заблокировав в пакетнике ValidateLocation избавился от данного бага, потому и думаю что нужно копать в эту же сторону
 
Сурсы какие? Лосты? Потому что я заблокировав в пакетнике ValidateLocation избавился от данного бага, потому и думаю что нужно копать в эту же сторону

На основе ребы, форкнутая с лостом
 
Не, такое г***о я бы в жизни за основу не взял)
хезе, судя по видосикам с лайва и вообще отзывам, не такое и говно, хотя вообще хз, не смотрел что они из себя представляют
 
Назад
Сверху Снизу