Точка входа
Интерфейс FlectonePulse, внедрение зависимостей через Google Guice, жизненный цикл проекта и обработка ошибок
Работа с API начинается с двух классов
| Класс | Зачем нужен |
|---|---|
net.flectone.pulse.FlectonePulseAPI | Хранит запущенный экземпляр и управляет его жизненным циклом |
net.flectone.pulse.FlectonePulse | Даёт внедрение зависимостей, перезагрузку и доступ к платформе |
import net.flectone.pulse.FlectonePulse;
import net.flectone.pulse.FlectonePulseAPI;
FlectonePulse flectonePulse = FlectonePulseAPI.getInstance();FlectonePulseAPI
| Метод | Возвращает | Что делает |
|---|---|---|
getInstance() | FlectonePulse | Отдаёт запущенный экземпляр или null, если проект ещё не загрузился |
isDisabling() | boolean | Отдаёт true, пока идёт выключение проекта |
Пока isDisabling() отдаёт true, не создавай новые задачи и не трогай базу данных. Проект в этот момент уже сворачивается
FlectonePulse
| Метод | Возвращает | Что делает |
|---|---|---|
get(Class<T>) | T | Отдаёт компонент из Guice |
isReady() | boolean | Проверяет готовность инжектора |
reload() | void | Перечитывает конфигурацию и бросает ReloadException при ошибке |
getLoader() | Object | Отдаёт нативный объект плагина или мода платформы |
hook(HookType, Object...) | void | Вызывает платформенную точку расширения |
onLoad(), onEnable(), onDisable() | void | Внутренний жизненный цикл, вызывается платформой |
throwInitException(Exception) | void | Заворачивает ошибку в InitException |
get(Class<T> type)
Отдаёт компонент из инжектора. Почти все компоненты объявлены интерфейсами, а их реализации помечены @Singleton, поэтому повторные вызовы отдают один и тот же объект
import net.flectone.pulse.dispatcher.MessageDispatcher;
import net.flectone.pulse.logging.FLogger;
import net.flectone.pulse.platform.registry.ListenerRegistry;
import net.flectone.pulse.service.FPlayerService;
FLogger fLogger = flectonePulse.get(FLogger.class);
FPlayerService fPlayerService = flectonePulse.get(FPlayerService.class);
MessageDispatcher messageDispatcher = flectonePulse.get(MessageDispatcher.class);
ListenerRegistry listenerRegistry = flectonePulse.get(ListenerRegistry.class);Перед вызовом get() проверяй готовность через isReady(), иначе получишь InjectorNotInitializedException
Запрашивай интерфейс, а не реализацию. Реализации лежат в закрытых модулях и отличаются на разных платформах
// правильно
FPlayerService service = flectonePulse.get(FPlayerService.class);
// неправильно, класса FPlayerServiceImpl нет в артефакте api
FPlayerServiceImpl service = flectonePulse.get(FPlayerServiceImpl.class);isReady()
Проверяет, поднялся ли инжектор зависимостей
if (flectonePulse.isReady()) {
FLogger fLogger = flectonePulse.get(FLogger.class);
fLogger.info("API готов к работе");
}reload()
Перезагружает конфигурацию, то же самое делает команда /flectonepulse reload
import net.flectone.pulse.exception.ReloadException;
try {
flectonePulse.reload();
getLogger().info("FlectonePulse перезагружен");
} catch (ReloadException e) {
getLogger().severe("Ошибка перезагрузки " + e.getMessage());
}Перезагрузка удаляет все слушатели, кроме добавленных через registerPermanent(). Подробности на странице системы событий
getLoader()
Отдаёт нативный объект загрузчика текущей платформы. Пригодится, когда нужен платформенный API, которого нет в абстракциях FlectonePulse
| Платформа | Тип объекта |
|---|---|
| Bukkit и Paper | org.bukkit.plugin.java.JavaPlugin |
| BungeeCord | net.md_5.bungee.api.plugin.Plugin |
| Velocity | объект плагина Velocity |
| Fabric и NeoForge | контейнер мода |
| Hytale | загрузчик мода Hytale |
JavaPlugin pulsePlugin = (JavaPlugin) flectonePulse.getLoader();hook(HookType type, Object... args)
Точки расширения, через которые ядро дёргает платформенный слой. Проект вызывает их сам, вручную они нужны только для низкоуровневой интеграции
HookType | Когда срабатывает |
|---|---|
CONFIGURE_SERIALIZATION | Настройка сериализации платформы |
PRE_NEW_PLAYER_PLACE | Перед размещением нового игрока в мире |
ON_PLAYER_PRE_LOGIN | Проверка игрока до входа |
ON_PLAYER_LOGIN | Вход игрока |
POST_RESPAWN | После возрождения игрока |
INIT_PACKET_ADAPTER | Запуск пакетного адаптера |
TERMINATE_PACKET_ADAPTER | Штатная остановка пакетного адаптера |
TERMINATE_FAILED_PACKET_ADAPTER | Остановка адаптера после ошибки запуска |
CLOSE_UIS | Закрытие всех открытых интерфейсов |
SIMPLEVOICE_ENTITY_SOUND_PACKET | Пакет звука сущности Simple Voice Chat |
SIMPLEVOICE_MICROPHONE_PACKET | Пакет микрофона Simple Voice Chat |
import net.flectone.pulse.constant.HookType;
// закрыть все открытые интерфейсы FlectonePulse
flectonePulse.hook(HookType.CLOSE_UIS);throwInitException(Exception e)
Заворачивает ошибку в InitException. В обычном режиме сообщение обрезается до 25 строк, а в debug режиме сохраняется целиком
try {
// опасная операция при запуске
} catch (Exception e) {
flectonePulse.throwInitException(e); // всегда бросает InitException
}Отладка
Debug режим включается системным свойством при запуске сервера
java -Dflectonepulse.debug=true -jar server.jarВ нём FlectonePulse не обрезает сообщения об ошибках и пишет подробные логи при старте
Исключения
Все исключения лежат в пакете net.flectone.pulse.exception
| Исключение | Когда прилетает |
|---|---|
InjectorNotInitializedException | get() вызван до готовности инжектора |
InitException | Ошибка при запуске проекта |
ReloadException | Ошибка при вызове reload() |
LoadingException | Ошибка загрузки проекта |
LibraryLoadException | Не получилось скачать или подключить библиотеку |
FileLoadException | Ошибка чтения конфигурации |
FileWriteException | Ошибка записи конфигурации |
ListenerRegistrationException | Кривой слушатель или метод @Pulse |
CacheRegistrationException | Ошибка регистрации кэша |
DatabaseNotInitializedException | Обращение к базе до её подключения |
UnsupportedDatabaseOperationException | Операция не поддерживается выбранной базой |
ProxyMessageCreateException | Ошибка при сборке прокси сообщения |
SchedulerTaskException | Ошибка внутри задачи планировщика |
ReflectionException | Ошибка рефлексии в платформенном слое |
ReloadException и SchedulerTaskException наследуют Exception, поэтому их придётся обработать или пробросить. Все остальные наследуют RuntimeException