Как выглядит bypass teleport go to village?

Ну почему же вынужденная? Можно ведь без этого всего teleport_goto##objectId# или npc_%objectId%_ в байпасах . Его еще и парсить надо.
не помню, правда. но была какая то проблема с выбором TeleportList правильного
 

не помню, правда. но была какая то проблема с выбором TeleportList правильного
Из того что я понимаю, L2J нужно было решить проблему привязки байпасов страницы к определенному npc. То есть таким образом можно сделать так что-бы когда байпас прилетит тут же и проверить во первых общялся ли игрок с нпц или нет, ну и дальше этот байпас отправить куда нужно.

Но это ведь можно все и на сервере делать, без участия модификаций байпасов. Сейчас L2J хранит список в памяти тех линков и байпасов (они не одно и то же) которые были отправленны игроку, и когда игрок посылает какой-то другой байпас это уже можно сразу же проверить (там немного сложнее, из-за определенных байпасов используемых например в community board). Но смысл то в том что можно отправлять игроку что угодно, главное то что сервер может это все понять.
 
Teleport request есть в первом сообщении. Он для другого.
ну на моей картинке три байпаса "teleport_request" "teleporttonpc_" "teleport_"
teleport_request "запрашивает" список телепортов (там запрос улетает в npc сервер)

teleport_ судя по логгерам "Teleport hack!!! char_name[%s]" "Teleport hack or something changed!!! char_name[%s]" и системным сообщениям "Недостаточно аден." "Недостаточно необходимых предметов." наверное и есть телепорт


по teleporttonpc_ затрудняюсь сказать что это но есть например в g_dimension_door_01.htm
HTML:
<html><head><body>
Dimensional Door:
<br>
An endless and mysterious vortex slowly spins before you.
<br>
<br>
<a action="bypass -h teleporttonpc_142">Jump in.</a>
<br>
</body></html>

других байпасов со словом teleport тут нет )
 
ну на моей картинке три байпаса "teleport_request" "teleporttonpc_" "teleport_"
teleport_request "запрашивает" список телепортов (там запрос улетает в npc сервер)

teleport_ судя по логгерам "Teleport hack!!! char_name[%s]" "Teleport hack or something changed!!! char_name[%s]" и системным сообщениям "Недостаточно аден." "Недостаточно необходимых предметов." наверное и есть телепорт


по teleporttonpc_ затрудняюсь сказать что это но есть например в g_dimension_door_01.htm
HTML:
<html><head><body>
Dimensional Door:
<br>
An endless and mysterious vortex slowly spins before you.
<br>
<br>
<a action="bypass -h teleporttonpc_142">Jump in.</a>
<br>
</body></html>

других байпасов со словом teleport тут нет )
Спасибо за помощь. На мысль натолкнули.
 
Так выглядит 1 строчка из списка
Код:
<button align=left icon=teleport action="bypass -h teleport_5077863200_0_57_1209033476_3" msg="811;F;1010004"><fstring>1010004</fstring></button>

Это сам байпас
Код:
bypass -h teleport_5077863200_0_57_1209033476_3

-h - закроет окно при отправке пакета
teleport - сам хендлер для обработки байпаса
5077863200 - это просто адрес списка позиций в кэше PosList L2Server.exe. По умолчанию кэш ПУСТ, поэтому этот адрес напрямую зависит от того, как рано L2NPC запрашивает конкретный PosList (обычно из-за взаимодействия игрока с NPC).
0 - индекс элемента в PosList
57 - тип / предмет платы за телепорт (что должно быть потреблено — PosList содержит только суммы)
1209033476 - smartId (в жаве objId нпц)
3 - тип телепортации, где 3 означает «новичок (бесплатно)», 1 — стандартный, 2 — ивент coretime

msg="811;F;1010004 - то что появляется при нажатии на строчку телепорта

811 - sysMsgId
F - Fstring = NpcString
1010004 - NpcStringId

Итог - Вы перемещаетесь в локацию (Глудин). Продолжить?
 
по teleporttonpc_ затрудняюсь сказать что это но есть например в g_dimension_door_01.htm
это очередное извращение от корейцев - телепорт к нпс с заданным ид
просто разбирался как раз с этим, когда выяснял нафига нужен эффект i_summon_unique_npc, который имеется в 2 скиллах и спавнит вот как раз нпс с ид 141 и 142.
суть оного - заспавнить на сервере 2 нпс которые могут быть только в одном экземпляре - если есть предыдущий спавн, то он удаляется.
ну и потом тупо через их диалоги перемещаться между этими нпс.
 
Последнее редактирование:
Вам важно понять, что те ИИ, которые вы смотрите, это СКРИПТЫ. Обработка логики этих скриптов проходит в NASC-интерпретаторе, который содержит саму логику внутренних функций скрипта. Т.е всякие ShowPage(talker, fnYouAreChaotic);, Teleport(talker, Position, ShopName, "", "", ""); и еще полторы тысячи функций для НПЦ и мейкеров. Не разобрав логику этих функций, вы не сможете ее воспроизвести.
Как выглядит структура и bypass динамично формирующегося html для телепорта?
На примере ПТС скриптов обычного телепортера. Как выглядит цепочка телепорта.
1) НПЦ при инициализации NASC скрипта, регается в холдер как телепортер, предоставляя список допустимых видов ТП.
2) После разговора с этим НПЦ, отсылается стартовая страница, которая обычно содержит байпасс teleport_request
3) Когда в клиенте тыкается этот байпасс, обработчик байпассов на стороне сервера триггерит NASC хендлер TELEPORT_REQUESTED в скрипте этого НПЦ, передавая туда определенные аргументы.
4) В большинстве случаев, в хендлере TELEPORT_REQUESTED у телепортеров вызывается функция TeleportFStr, которая формирует страницу телепорта и отсылает ее в клиент в качестве HTML сообщения.
5) Ну и дальше при клике на ТП, клиент шлет байпасс teleport с параметрами, которые интерпретируются на сервере и обрабатываются уже не в наске.


Сначала, когда проходит загрузка NASC-скриптов, актор наска регается как телепортер:
Java:
default void RegisterTeleporterType(int type, int level) {
        switch (getNASCActor()) {
            case Npc npc_actor -> NpcTeleportTypeManager.getInstance().registerTeleporterType(npc_actor, ETeleporterType.list.get(type), level);
            case null, default -> Loggers.STATIC.error("Unsupported actor type!", new IllegalArgumentException());
        }

    }

После этого, когда проходит вызов функции телепорта, триггерится хендлер телепорта:
Java:
@Override
    public void TELEPORT_REQUESTED(ISharedCreature talker) {
        if (talker.transformID() == 111 || talker.transformID() == 112 || talker.transformID() == 124) {
            ShowPage(talker, "q194_noteleport.htm");
        } else {
            TeleportFStr(talker, "Position", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
        }
    }

Java:
    @Override
    public void TELEPORT_REQUESTED(ISharedCreature talker) {
        if (IsMyLord(talker) || HavePledgePower(talker, ppSetGate) && Castle_GetPledgeId() == talker.pledge_id() && talker.pledge_id() != 0) {
            if (talker.transformID() == 111 || talker.transformID() == 112 || talker.transformID() == 124) {
                ShowPage(talker, "q194_noteleport.htm");
            } else if (Agit_GetDecoLevel(decotype_teleport) == 11) {
                TeleportFStr(talker, "Position1", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
            } else if (Agit_GetDecoLevel(decotype_teleport) == 12) {
                TeleportFStr(talker, "Position2", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
            } else {
                ShowPage(talker, fnFuncDisabled);
            }
        } else {
            ShowPage(talker, fnNoAuthority);
        }
    }
1756348550211.webp
И вот такая реализация. Тут ты сможешь найти и структуру html и примерную логику:
Java:
default void TeleportFStr(ISharedCreature sCreature, String telposlist, String shopname, String byePage, String clsMissMatchPage, String underAdenaPage, int nItemClassID, int fstrItemIndex, String p1, String p2, String p3, String p4, String p5) {
        switch (getNASCActor()) {
            case Npc npc -> {
                if (sCreature instanceof Player talker) {
                    if (telposlist == null || telposlist.isEmpty()) {
                        return;
                    }

                    int[][] position = TelPosListHolder.getInstance().getTelPosList(npc, telposlist);

                    Int2ObjectOpenHashMap<String> tpls;
                    String base_html = """
                    <html><body>&$556;<br><br><?teleport_list?><br></body></html>
                    <!--TEMPLET1
                    <a action="bypass -h teleport_<?list_id?>_<?list_pos?>_<?item_id?>_<?npc_index?>" msg="811;F;<?location?>"><?pos_index?><fstring><?location?></fstring></a><br1>
                    TEMPLET-->
                    <!--TEMPLET2
                    <a action="bypass -h teleport_<?list_id?>_<?list_pos?>_<?item_id?>_<?npc_index?>" msg="811;F;<?location?>"><?pos_index?><fstring><?location?></fstring> - <?count?> <fstring p1="<?p1?>" p2="<?p2?>" p3="<?p3?>" p4="<?p4?>" p5="<?p5?>"><?item_name?></fstring></a><br1>
                    TEMPLET-->
                    """;
                    tpls = LocalFiles.parseTemplate(base_html);
                    try (var f = talker.openFHTML()) {
                        f.set(tpls.get(0));
                        StringBuilder list = new StringBuilder();

                        final var ldt = LocalDateTime.now();

                        int day = ldt.getDayOfWeek().getValue();
                        int hour = ldt.getHour();

                        boolean lowPrice = nItemClassID == adena && day != 1 && day != 7 && (hour <= 12 || hour >= 22);

                        int common_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_COMMON);
                        int coretime_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_CORETIME);
                        int free_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_FREE);

                        if (free_level >= 0 && (free_level == 0 || talker.getLevel() <= free_level)) {
                            String tpl = tpls.get(1);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", "0").replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        } else if (nItemClassID == olympiad_token && coretime_level >= 0 && (coretime_level == 0 || talker.getLevel() <= coretime_level)) {
                            String tpl = tpls.get(2);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", String.valueOf(nItemClassID)).replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?count?>", String.valueOf(position[c][4])).replace("<?item_name?>", String.valueOf(fstrItemIndex)).replace("<?p1?>", p1).replace("<?p2?>", p2).replace("<?p3?>", p3).replace("<?p4?>", p4).replace("<?p5?>", p5).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        } else if (common_level >= 0 && (common_level == 0 || talker.getLevel() <= common_level)) {
                            String tpl = tpls.get(2);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", String.valueOf(nItemClassID)).replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?count?>", String.valueOf(position[c][4] / (lowPrice ? 2 : 1))).replace("<?item_name?>", String.valueOf(fstrItemIndex)).replace("<?p1?>", p1).replace("<?p2?>", p2).replace("<?p3?>", p3).replace("<?p4?>", p4).replace("<?p5?>", p5).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        }

                        f.replace("<?teleport_list?>", list.toString());
                        f.showNpc(npc);
                    }
                }
            }
            case null, default -> Loggers.STATIC.error("Unsupported actor type!", new IllegalArgumentException());
        }

    }

Это реализация для ХФ.

суть оного - заспавнить на сервере 2 нпс которые могут быть только в одном экземпляре - если есть предыдущий спавн, то он удаляется.
ну и потом тупо через их диалоги перемещаться между этими нпс.
Ага, это для ГМской трансформы скиллы. Ну и unique npc в целом так работает. Не только на ворота. Есть NPC определенные, которые могут быть только в одном экземпляре призваны, т.к повторный вызов ломает NASC. Т.е второй экземпляр тупо не заспавится, если существует первый. Их не много, но они есть.
Посмотреть вложение Запись экрана 2025-08-28 064910.mp4
 
Последнее редактирование:
Так выглядит 1 строчка из списка
Код:
<button align=left icon=teleport action="bypass -h teleport_5077863200_0_57_1209033476_3" msg="811;F;1010004"><fstring>1010004</fstring></button>

Это сам байпас
Код:
bypass -h teleport_5077863200_0_57_1209033476_3

-h - закроет окно при отправке пакета
teleport - сам хендлер для обработки байпаса
5077863200 - это просто адрес списка позиций в кэше PosList L2Server.exe. По умолчанию кэш ПУСТ, поэтому этот адрес напрямую зависит от того, как рано L2NPC запрашивает конкретный PosList (обычно из-за взаимодействия игрока с NPC).
0 - индекс элемента в PosList
57 - тип / предмет платы за телепорт (что должно быть потреблено — PosList содержит только суммы)
1209033476 - smartId (в жаве objId нпц)
3 - тип телепортации, где 3 означает «новичок (бесплатно)», 1 — стандартный, 2 — ивент coretime

msg="811;F;1010004 - то что появляется при нажатии на строчку телепорта

811 - sysMsgId
F - Fstring = NpcString
1010004 - NpcStringId

Итог - Вы перемещаетесь в локацию (Глудин). Продолжить?
Спасибо. Вот такой ответ и ждал. А откуда источник? Или сами исследовали?

Вам важно понять, что те ИИ, которые вы смотрите, это СКРИПТЫ. Обработка логики этих скриптов проходит в NASC-интерпретаторе, который содержит саму логику внутренних функций скрипта. Т.е всякие ShowPage(talker, fnYouAreChaotic);, Teleport(talker, Position, ShopName, "", "", ""); и еще полторы тысячи функций для НПЦ и мейкеров. Не разобрав логику этих функций, вы не сможете ее воспроизвести.

На примере ПТС скриптов обычного телепортера. Как выглядит цепочка телепорта.
1) НПЦ при инициализации NASC скрипта, регается в холдер как телепортер, предоставляя список допустимых видов ТП.
2) После разговора с этим НПЦ, отсылается стартовая страница, которая обычно содержит байпасс teleport_request
3) Когда в клиенте тыкается этот байпасс, обработчик байпассов на стороне сервера триггерит NASC хендлер TELEPORT_REQUESTED в скрипте этого НПЦ, передавая туда определенные аргументы.
4) В большинстве случаев, в хендлере TELEPORT_REQUESTED у телепортеров вызывается функция TeleportFStr, которая формирует страницу телепорта и отсылает ее в клиент в качестве HTML сообщения.
5) Ну и дальше при клике на ТП, клиент шлет байпасс teleport с параметрами, которые интерпретируются на сервере и обрабатываются уже не в наске.


Сначала, когда проходит загрузка NASC-скриптов, актор наска регается как телепортер:
Java:
default void RegisterTeleporterType(int type, int level) {
        switch (getNASCActor()) {
            case Npc npc_actor -> NpcTeleportTypeManager.getInstance().registerTeleporterType(npc_actor, ETeleporterType.list.get(type), level);
            case null, default -> Loggers.STATIC.error("Unsupported actor type!", new IllegalArgumentException());
        }

    }

После этого, когда проходит вызов функции телепорта, триггерится хендлер телепорта:
Java:
@Override
    public void TELEPORT_REQUESTED(ISharedCreature talker) {
        if (talker.transformID() == 111 || talker.transformID() == 112 || talker.transformID() == 124) {
            ShowPage(talker, "q194_noteleport.htm");
        } else {
            TeleportFStr(talker, "Position", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
        }
    }

Java:
    @Override
    public void TELEPORT_REQUESTED(ISharedCreature talker) {
        if (IsMyLord(talker) || HavePledgePower(talker, ppSetGate) && Castle_GetPledgeId() == talker.pledge_id() && talker.pledge_id() != 0) {
            if (talker.transformID() == 111 || talker.transformID() == 112 || talker.transformID() == 124) {
                ShowPage(talker, "q194_noteleport.htm");
            } else if (Agit_GetDecoLevel(decotype_teleport) == 11) {
                TeleportFStr(talker, "Position1", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
            } else if (Agit_GetDecoLevel(decotype_teleport) == 12) {
                TeleportFStr(talker, "Position2", ShopName, "", "", "", 57, 1000308, "", "", "", "", "");
            } else {
                ShowPage(talker, fnFuncDisabled);
            }
        } else {
            ShowPage(talker, fnNoAuthority);
        }
    }
Посмотреть вложение 88539
И вот такая реализация. Тут ты сможешь найти и структуру html и примерную логику:
Java:
default void TeleportFStr(ISharedCreature sCreature, String telposlist, String shopname, String byePage, String clsMissMatchPage, String underAdenaPage, int nItemClassID, int fstrItemIndex, String p1, String p2, String p3, String p4, String p5) {
        switch (getNASCActor()) {
            case Npc npc -> {
                if (sCreature instanceof Player talker) {
                    if (telposlist == null || telposlist.isEmpty()) {
                        return;
                    }

                    int[][] position = TelPosListHolder.getInstance().getTelPosList(npc, telposlist);

                    Int2ObjectOpenHashMap<String> tpls;
                    String base_html = """
                    <html><body>&$556;<br><br><?teleport_list?><br></body></html>
                    <!--TEMPLET1
                    <a action="bypass -h teleport_<?list_id?>_<?list_pos?>_<?item_id?>_<?npc_index?>" msg="811;F;<?location?>"><?pos_index?><fstring><?location?></fstring></a><br1>
                    TEMPLET-->
                    <!--TEMPLET2
                    <a action="bypass -h teleport_<?list_id?>_<?list_pos?>_<?item_id?>_<?npc_index?>" msg="811;F;<?location?>"><?pos_index?><fstring><?location?></fstring> - <?count?> <fstring p1="<?p1?>" p2="<?p2?>" p3="<?p3?>" p4="<?p4?>" p5="<?p5?>"><?item_name?></fstring></a><br1>
                    TEMPLET-->
                    """;
                    tpls = LocalFiles.parseTemplate(base_html);
                    try (var f = talker.openFHTML()) {
                        f.set(tpls.get(0));
                        StringBuilder list = new StringBuilder();

                        final var ldt = LocalDateTime.now();

                        int day = ldt.getDayOfWeek().getValue();
                        int hour = ldt.getHour();

                        boolean lowPrice = nItemClassID == adena && day != 1 && day != 7 && (hour <= 12 || hour >= 22);

                        int common_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_COMMON);
                        int coretime_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_CORETIME);
                        int free_level = NpcTeleportTypeManager.getInstance().getTeleporterLevel(npc, ETeleporterType.TELEPORTER_FREE);

                        if (free_level >= 0 && (free_level == 0 || talker.getLevel() <= free_level)) {
                            String tpl = tpls.get(1);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", "0").replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        } else if (nItemClassID == olympiad_token && coretime_level >= 0 && (coretime_level == 0 || talker.getLevel() <= coretime_level)) {
                            String tpl = tpls.get(2);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", String.valueOf(nItemClassID)).replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?count?>", String.valueOf(position[c][4])).replace("<?item_name?>", String.valueOf(fstrItemIndex)).replace("<?p1?>", p1).replace("<?p2?>", p2).replace("<?p3?>", p3).replace("<?p4?>", p4).replace("<?p5?>", p5).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        } else if (common_level >= 0 && (common_level == 0 || talker.getLevel() <= common_level)) {
                            String tpl = tpls.get(2);
                            for (int c = 0; c < position.length; c++) {
                                list.append(tpl.replace("<?list_id?>", String.valueOf(position.hashCode())).replace("<?list_pos?>", String.valueOf(c)).replace("<?item_id?>", String.valueOf(nItemClassID)).replace("<?npc_index?>", String.valueOf(npc.getObjectId())).replace("<?location?>", String.valueOf(position[c][0])).replace("<?count?>", String.valueOf(position[c][4] / (lowPrice ? 2 : 1))).replace("<?item_name?>", String.valueOf(fstrItemIndex)).replace("<?p1?>", p1).replace("<?p2?>", p2).replace("<?p3?>", p3).replace("<?p4?>", p4).replace("<?p5?>", p5).replace("<?pos_index?>", (c + 1) + ". "));
                            }
                        }

                        f.replace("<?teleport_list?>", list.toString());
                        f.showNpc(npc);
                    }
                }
            }
            case null, default -> Loggers.STATIC.error("Unsupported actor type!", new IllegalArgumentException());
        }

    }

Это реализация для ХФ.


Ага, это для ГМской трансформы скиллы. Ну и unique npc в целом так работает. Не только на ворота. Есть NPC определенные, которые могут быть только в одном экземпляре призваны, т.к повторный вызов ломает NASC. Т.е второй экземпляр тупо не заспавится, если существует первый. Их не много, но они есть.
Посмотреть вложение 88540
Спасибо за развернутый ответ.
Про то что нужно хорошее понимание NASC вы правы все так. Но вопрос был про html файл. И вы и ChaosPaladin дали ответ на него за что огромное спасибо. Это именно то что нужно.
P.S. почему-то не могу увеличить вам репутацию в плюс. Запрет какой-то)
 
Последнее редактирование модератором:
Назад
Сверху