не помню, правда. но была какая то проблема с выбором TeleportList правильногоНу почему же вынужденная? Можно ведь без этого всего teleport_goto##objectId# или npc_%objectId%_ в байпасах . Его еще и парсить надо.
Посмотрите видео ниже, чтобы узнать, как установить наш сайт в виде веб-приложения на главном экране.
Примечание: Эта функция может быть недоступна в некоторых браузерах.
не помню, правда. но была какая то проблема с выбором TeleportList правильногоНу почему же вынужденная? Можно ведь без этого всего teleport_goto##objectId# или npc_%objectId%_ в байпасах . Его еще и парсить надо.
Из того что я понимаю, L2J нужно было решить проблему привязки байпасов страницы к определенному npc. То есть таким образом можно сделать так что-бы когда байпас прилетит тут же и проверить во первых общялся ли игрок с нпц или нет, ну и дальше этот байпас отправить куда нужно.не помню, правда. но была какая то проблема с выбором TeleportList правильного
Teleport request есть в первом сообщении. Он для другого.я извиняюсь, там да все же скорее не верный bypass в тех исходах.
вот c pts hf "teleport_request" там должен быть в html
Посмотреть вложение 88536
ну на моей картинке три байпаса "teleport_request" "teleporttonpc_" "teleport_"Teleport request есть в первом сообщении. Он для другого.
<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_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 тут нет )
<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
это очередное извращение от корейцев - телепорт к нпс с заданным идпо teleporttonpc_ затрудняюсь сказать что это но есть например в g_dimension_door_01.htm
На примере ПТС скриптов обычного телепортера. Как выглядит цепочка телепорта.Как выглядит структура и bypass динамично формирующегося html для телепорта?
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());
}
}
@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, "", "", "", "", "");
}
}
@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);
}
}
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 нпс которые могут быть только в одном экземпляре - если есть предыдущий спавн, то он удаляется.
ну и потом тупо через их диалоги перемещаться между этими нпс.
Спасибо. Вот такой ответ и ждал. А откуда источник? Или сами исследовали?Так выглядит 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, "", "", "", "", ""); } }
Посмотреть вложение 88539Java:@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); } }
И вот такая реализация. Тут ты сможешь найти и структуру 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