Квестовые методы в ПТС ИИ

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

Aristo

Легендарный
Легенда Истоков
Победитель в номинации 2024
Победитель в номинации 2023
Сообщения
981
Розыгрыши
0
Решения
12
Репутация
762
Реакции
1 288
Баллы
1 733
Хроники
  1. Chaotic Throne: High Five
Сборка
Свое, на базе L2GW
Всем привет.
Сначала суть:
Сборка Java.
Портировал я как-то давно себе ПТС ИИ. Код перенесен на JAVA структурно без изменений из декомпила ХФ ai.obj
Сейчас провожу у себя ЗБТ и столкнулся с некоторой проблемой.
У корейцев, есть два основных вида проверки и переключения статуса квеста. Буду писать псевдокодом, чтобы было более понятно, в чем суть проблемы.
Пример: Для переключения квеста с 1 на 2 этап, нужно 10 итемов с ИД 9999. В рюкзаке 9 итемов, убиваем моба. У моба обработчик:
Вариант кода 1.
Код:
if (getItemCount(9999) == 9){
   giveItem(9999, 1);
   changeQuestState(2);
}
1679788928506.png
Вариант кода 2.
Код:
giveItem(9999, 1);
if(getItemCount(9999) >= 9){
  changeQuestState(2);
}
1679788882455.png
Оба варианта встречаются в ИИ примерно поровну. Первый вариант чаще в новых ИИ, от ГФ и выше, а второй преимущественно в старых.
Методы в коде вызываются одинаковые. Скорее всего, во втором варианте заложена задержка на передачу инфы туда обратно между NpcServer и Server,
но из-за этого, если я у себя на яве, обрабатываю вызов giveItem в том же потоке, то получаю ситуацию, когда у меня моб закрывает квест на 9 итемах, т.к условие выполняется. Если я выношу обработчик giveItem в отдельный поток, то иногда возникают ситуации, когда мобы выдают лишние итемы, т.е у чара получается 11/10 итемов, а т.к в тех же скриптах проверки в условиях по большей части не >=, а ==, то такие квесты не получится сдать.
Кто-то сталкивался с подобным? Править скрипты очень не хочу, т.к с датапаком ПТС работаю нативно и очень бы не хотелось его править.
Есть идеи, как это можно обойти?
 
Решение
это L2NPC.
похоже, что это Queue атомарных исполняемых операций, которая связана с CScriptEngine, которая затем вызывает функцию Process, которая выполняет операции в Queue.
Из-за того, что GiveItem должен запускаться таском RunNpcScript -> Process, он будет (почти?) всегда запускаться после OwnItemCount.

минус способа конечно в том что к примеру на париках мобов в итоге игроки не смогут быстро набивать предметы, т.е. условно с кучи одномоментно убитых мобов получат предметов столько же сколько с одного.
Сорян за некропостинг,но так и работает офф сервер. Есть такая цепочка квестов у леонель хантера "Узнай свой предел" апнуть уровень и набить 20-40-80-160к мобов и там очень заметно что на париках мобы не набиваются так как урон на мейне это почти всегда шотные мобы и дается 1 итем. По этому отрубают массухи и бьют в соло цель.
 
Сорян за некропостинг,но так и работает офф сервер. Есть такая цепочка квестов у леонель хантера "Узнай свой предел" апнуть уровень и набить 20-40-80-160к мобов и там очень заметно что на париках мобы не набиваются так как урон на мейне это почти всегда шотные мобы и дается 1 итем. По этому отрубают массухи и бьют в соло цель.
да, т.к квестовые события обрабатываются в атомарных очередях на тике HEARTBEAT(666мс). Т.е если условно упало 10 одинаковых задач на добавление итема по определенному квесту, то будет запущена только первая, а остальные будут дропнуты и могут быть запущены только по завершению текущей задачи такого типа и только на следующий тик. Там целый здоровенный enum, который содержит список типов AtomicJob.


Java:
package ru.nts.gameserver.system.enums;

import lombok.Getter;

@Getter
public enum EAJ_JOBID_TYPE {
AJ_PARAM_CHANGE(0x0),
AJ_CREATE_PET(0x1),
AJ_EVOLVE_PET(0x2),
AJ_DESTROY_PET(0x3),
AJ_BUY_LOTTO(0x4),
AJ_MEMO_CONTROL(0x5),
AJ_SHOW_PAGE(0x6),
AJ_SHOW_FHTML(0x7),
AJ_DROP_ITEM(0x8),
AJ_RIDE_WYVERN(0x9),
AJ_PLEDGE_LEVELUP(0xA),
AJ_ADD_SSQ_MEMBER(0xB),
AJ_DELETE_DEPOSITED_SSQ_ITEM(0xC),
AJ_ADD_TIMEATTACK_RECORD(0xD),
AJ_TELEPORT_PARTY(0xE),
AJ_SET_AGIT_DECO(0xF),
AJ_RESET_AGIT_DECO(0x10),
AJ_SET_FORTRESS_FACILITY(0x11),
AJ_RESET_FORTRESS_FACILITY(0x12),
AJ_ADD_TIMER(0x13),
AJ_START_OBSERVER(0x14),
AJ_SET_TICKET_BUY_COUNT(0x15),
AJ_TELEPORT(0x16),
AJ_ADD_TIME_ATTACK_FEE(0x17),
AJ_TIME_ATTACK_REWARD(0x18),
AJ_DEPOSIT_SSQ_ITEM_EX(0x19),
AJ_DROP_ITEM2(0x1A),
AJ_SET_NOBLESS(0x1B),
AJ_SET_HERO(0x1C),
AJ_CAST_BUFF(0x1D),
AJ_AQUIRE_PLEDGE_SKILL(0x1E),
AJ_CHANGE_PET_NAME(0x1F),
AJ_RESET_PET_NAME(0x20),
AJ_CREATE_ACADEMY(0x21),
AJ_CREATE_SUBPLEDGE(0x22),
AJ_CAST_BUFF_WITH_MP_CONSUMPTION(0x23),
AJ_EVOLVE_PET_WITH_EXP(0x24),
AJ_UPDATE_PCCAFE_POINT(0x25),
AJ_EVENT_RIDE(0x26),
AJ_DELETE_ACQUIRE_SKILL(0x27),
AJ_DELETE_ACQUIRE_SKILLS(0x28),
AJ_UPDATE_PVP_POINT(0x29),
AJ_MANIPULATE_PVP_POINT_WITH_ITEM(0x2A),
AJ_NRMEMO_CONTROL(0x2B),
AJ_SHOW_QUEST_PAGE(0x2C),
AJ_SHOW_QUEST_FHTML(0x2D),
AJ_SUMMON_AIRSHIP(0x2E),
AJ_BUY_AIRSHIP(0x2F),
AJ_GETON_AIRSHIP(0x30),
AJ_ITEM_DELETE(0x31),
AJ_CHANGE_TALK_TARGET(0x32),
AJ_CHANGE_CLASS_AND_SET_SKILL(0x33),
AJ_REWARD_SKILL_ENCHANT(0x34),
AJ_SET_SKILL(0x35),
AJ_CHANGE_CLASS(0x36),
AJ_SET_DAILY_QUEST_FLAG(0x37),
AJ_NPC_SET_SKILL_ALL(0x38),
AJ_UPDATE_USER_POINT(0x39),
AJ_SHOW_CARDCOLLECTSYSTEM(0x3A),
AJ_CAST_BUFF_FOR_EVENT_MAKER(0x3B),
AJ_ADD_WORLDCHAT_BONUS_POINT(0x3C),
AJ_ADD_FACTION_POINT(0x3D),
AJ_SET_FACTION_POINT(0x3E),
AJ_OPEN_DECO_NPC(0x3F),
AJ_CONTENT_UI_EVENT(0x40),
AJ_ACCEPT_USER_QUEST(0x41),
AJ_MAX(0x42);

private final int value;

EAJ_JOBID_TYPE(int value) {
this.value = value;
    }

}
 
я у себя кстати в критичных местах выдачу квестовых предметов сделал тоже раз в тик (666мс), т.к. на послдних тестах подобная проблема с лишними выдачами и т.п. очень явно вылезла из-за того что на тесте был комп с малым количеством памяти (да и сам по себе достаточно слабенький) и сервер периодически ощутимо подбуксовывал, и в итоге при убийстве мобов массовухами возникали ситуации что с тем что умудрялось залетать в ветки переключения этапов квеста по несколько раз подряд.
Так что вот пришлось на всякий случай все же сделать так сказать защиту от подобных случаев, чтобы к примеру игрокам не давало лишних SoE например при переключениях этапов квеста.
Java:
    @Override
    public String onKill(NpcInstance npc, Player player, QuestState st)
    {
        if (st.getCond() == 3 && st.getMemo(1) == 0)
        {
            if (giveItem(player, UndeadBlood[0], 1, 10) >= UndeadBlood[1])
            {
                st.setMemo(1, 1);

                if (player.getLevel() >= ReqLevel)
                {
                    if (!st.checkLastRewardTick())
                        return null;

                    st.setLastRewardTick();
                    st.setCond(4);
                    giveItem(player, ScrollOfEscapeHerphah, 1L);
                    showScreenMessage(player, 558950, 5000); // Используйте имеющийся в инвентаре Свиток Телепорта: Герпа.
                    playSound(player, SOUND_MIDDLE);
                    return null;
                }
                else
                    playSound(player, SOUND_ITEMGET);
            }
            else
                playSound(player, SOUND_ITEMGET);
        }

        return null;
    }
Если что, до этого код выдачи и т.п. в основном оставался все тот же что и в оригинальном овере, так что думаю подобной проблеме подвержены все сборки на базе оного при работе на достаточно слабом железе и тормозах сервера из-за этого.
Если конечно там никто тоже подобной проблемой не озадачивался и тоже не исправлял у себя каким либо образом.
 
Последнее редактирование:
Назад
Сверху