Кто-то там в курилке говорил, что пора выкладывать всякую хрень в честь дня рождения зоны? Так получайте
Небольшая хук-система для нектгена. Умеет хукать большинство хандлеров (от байпассов до бгомерзких админ-команд). Писалось некоторое время назад для себя, т.к. сейчас есть немного работы под этот эмуль.
Примеры использования:
Свернуть ↑
Код:
/**
* @author PointerRage
*
*/
public class CtF extends L2Event implements ScriptFile {
private class BypassHook extends ABypassHook {
@Override public boolean useBypass(String command, L2Player player, L2Character target) {
if(command.startsWith("Chat") && target != null && isInTeam(player, teams) && _status > 1 &&
(target.getNpcId() == 35426 || target.getNpcId() == 35423 || target.getNpcId() == 35425)) {
capture(player, target);
}
return super.useBypass(command, player, target);
}
}
@Override
public void onLoad()
{
Hooks.getInstance().enableLogging(false);
Hooks.getInstance().addHook(new BypassHook(BypassHandler.getInstance().getHandler( "Chat"));
}
Свернуть ↑Развернуть ↓
Свернуть ↑
Код:
import l2n.extensions.scripts.ScriptFile;
import l2n.game.communitybbs.CommunityBoardHandlers;
import l2n.game.model.actor.L2Player;
import rage.ng.hook.Hooks;
import rage.ng.hook.type.ACommunityHook;
/**
* @author PointerRage
*
*/
public class BBSMultisell implements ScriptFile {
private class Pass extends ACommunityHook {
@Override
public boolean execute(final L2Player activeChar, final String command, final String[] params, final String source) {
if(command.equalsIgnoreCase("_bbsmultisell")) {
if(activeChar.isParalyzed() || activeChar.isFakeDeath() || activeChar.isBlocked())
return true;
}
return super.execute(activeChar, command, params, source);
}
}
@Override
public void onLoad() {
Hooks.getInstance().addHook(new Pass(CommunityBoardHandlers.getInstance().getHandl er("_bbsmultisell")), false);
}
@Override
public void onReload() {}
@Override
public void onShutdown() {}
}
Свернуть ↑Развернуть ↓
В чем же соль спросите вы?
Все просто - к сожалению мы не можем модифицировать существующие байпассы (возьмем для конкретики именно их), хотя время от времени это становится нужным. Логика библиотеки проста: берем хранилище хандлеров, ищем фиелд с их хранением, берем его и изменяем хандлер на наш, чтобы запрос шел на наш обработчик. При этом сохраняется обратный вызов хукнутого хандлера, с помощью super-вызова (представлено выше).
Немного документации:
Свернуть ↑
package rage.ng.hook;
Свернуть ↑
Используется для создания кастомных хуков, которые не относятся к уже созданным пресетам.
Для работы требуется указать:
setOldObject - ссылка на стандартный обработчик
setStorage - ссылка на хранилище хандлеров (например BypassHandlers)
setAssign - ссылка на тип обработчика (обычно наследуемый интерфейс, например: IBypassHandler)
Свернуть ↑Развернуть ↓
package rage.ng.hook.type;
Включает в себя готовые пресеты:
AAdminHook - админ хандлеры, доступно для перегрузки: useAdminCommand, getDescription
ABypassHook - байпасс хандлеры, доступно для перегрузки: useBypass
ACommunityHook - коммунити хандлеры, доступно для перегрузки: checkCondition, execute, onWriteCommand
AItemHook - айтем хандлеры, доступно для перегрузки: useItem
AUserHook - юзер хандлеры, доступно для перегрузки: useUserCommand
AVoiceHook - войс хандлеры, доступно для перегрузки: useVoicedCommand
IHook - унифицирующий интерфейс, используется для кастома
Свернуть ↑Развернуть ↓
Tick:
Подмену можно делать только всего подмножества команд, которые реализует стандартный обработчик. Так же не поддерживается расширение этого подмножества, для этого лучше создать отдельный обработчик.
Tick 2:
Для написания кастомных версий требуется соблюдать некоторые правила:
1. Хук-классы. Необходимо наличие глобальной переменной oldHandler с
любыми флагами поля и
любым типом, т.е. другими словами: делайте хоть private final Object oldHandler. Эта переменная не должна быть null, она должна указывать на стандартный обработчик, который заменяет хук.
2. Хранилище. Сканинг направлен только на TIntObjectHashMap типы фиелдов. Если тип фиелда, где хранятся обработчики другой - поле для инжекта не будет найдено, соответственно хук просто не будет работать.
Либа:
mediafire
Сорц либы (содержит проект eclipse со всеми зависимостями):
mediafire
*для людей, которые думают: "ололо, щас заберу ядро НГ" - хренушки, ибо я вырезал все классы, кроме зависимых.*
Послесловие:
Как я уже говорил, алгоритмика проверена и используется мной. Абстракцию и уровень библиотеки написал только что, для зиги, поэтому возможны ошибки
Послесловие 2:
Чует мое сердце, что такими темпами дойду до модернизации байткода на лету, ибо не хватает очень многих вещей в Script-API некстгена