Набор вспомогательных инструментов для Bukkit API.
Основан на версии Bukkit API 1.12.
- Перед использованием
- GhastTools
- AssetsManager
- BuildHelper
- CommandManager
- EffectsHelper
- EventContext
- JdbcTemplate
- ScheduleManager
- ScheduleTask
- Messages
- XLog
- Подключение
Перед началом использования, необходимо в вашем Bukkit-плагине прописать подобный код:
void onLoad() {
GhastTools.setPlugin(this);
}
Это необходимо сделать, т.к. весь инструментарий основан на статических (static) методах.
Все методы данного набора инструментов объеденены в классы, выполняющие роль группировщиков.
Методы общего назначения или без определённой группировки.
Загрузка файла настроек плагина - config.yml
.
YamlConfiguration config = GhastTools.loadConfig();
По-умолчанию "гаст" пытается файл найти в папке плагина - getDataFolder()
.
Если файла там нет, то выгружает встроенный (имеющийся в .jar
файле плагина) в эту папку и загружает его.
YamlConfiguration config = GhastTools.loadConfig(false);
Если передать параметр false
, то при отсутствии файла config.yml
в папке плагина,
будет загруден исключительно встроенный файл настроек.
Копирования объекта Location
Location location = ...;
Location copyLoc = GhastTools.copyLocation(location);
Методы по работе с файлами плагина ("ассетами").
У каждой группы методов один и тот же набор входных параметров:
resourceName
- наименование и путь к файлу в папке плагинаdefaultResourceName
- наименование и путь к файлу в плагине.
Опционально. По-умолчанию равненresourceName
saveDefault
- необходимость скопировать содержимое файла изdefaultResourceName
в файлresourceName
.
Опционально. По-умолчанию равенtrue
Правила поиска файлов так же одинаков для каждой группы:
- В начале файл ищется в папке плагина
- Если файл отсутствует в папке плагина, то...
- если
defaultResourceName
не равенnull
...- если
saveDefault
равенtrue
, то файл из плагина будет выгружен в папку плагина и от туда загружен в память. - если
saveDefault
равенfalse
, то данные будут взяты из файлв в плагине.
- если
- если
defaultResourceName
равенnull
, то будет брошено исключениеAssetsException
с описанием ошибки вида "Файл X не найден".
- если
InputStream inputStream = AssetsManager.getAsInputStream("translate.ru.yml", "translate.yml", false);
Reader reader = AssetsManager.getAsReader("translate.ru.yml", "translate.yml", false);
String string = AssetsManager.getAsString("readme.txt", "readme.txt", StandardCharsets.UTF_8, false);
У этой группы есть дополнительный опциональный параметр - charset
- в котором указывается кодиривка получаемой строки.
По-умолчанию равен StandardCharsets.UTF_8
Набор методов облегчающих размецение объектов на карте.
Установка черепа.
Location location = ...;
Skull skull = BuildHelper.placeSkull(location, BlockFace.NORTH);
skull.update(true); // иначе изменения на карте не применятся и череп будет висеть в воздухе
Установка головы игрока.
Location location = ...;
Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH);
playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе
Если третьим параметром передать URL текстуры, то голова будет текстурирована.
Location location = ...;
BuildHelper.placePlayerHead(location, BlockFace.NORTH, "http://...");
Установка текстуры для головы игрока.
Location location = ...;
Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH);
playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе
setPlayerHeadSkin(playerHead);
Порядок выполнения методов в приведённом выше примере важен. Если playerHead.update(true)
вызвать после
установки текстуры, она собъётся на стандартную.
Location location = ...;
Sign signWall = BuildHelper.placeSignWall(location, BlockFace.NORTH)
Регистрация команд.
Имеется два варианта использования: упрощённый
CommandManager.register("start", (sender, args) -> sender.sendMessage("hello!"));
и подробный:
CommandManager.create("start")
.useOnlyPlayer()
.executer((sender, args) -> sender.sendMessage("hello!"))
.register();
Упрощенная регистрация команды. Указывается лишь название команды и исполнитель.
CommandManager.register("start", (sender, args) -> sender.sendMessage("hello!"));
Конструктор для подробного варианта регистрации команды.
CommandManager.Builder builder = CommandManager.create("start");
Указание исполнителя для команды
CommandManager.Builder builder = CommandManager.create("start")
.executer((sender, args) -> sender.sendMessage("hello!"));
Обработчик исключений
CommandManager.Builder builder = CommandManager.create("start")
.onError((sender, commandName, args, exception) -> {
sender.sendMessage(ChatColor.RED + "Произошла ошибка при выполнении команды '" + commandName + "'.");
exception.printStackTrace();
});
Указание, что данную команду могут использовать только Игроки.
Опционально можно указать сообщение, которое будет выводиться в консоль.
Отменяет действие указателя useOnlyConsole
CommandManager.Builder builder = CommandManager.create("start")
.useOnlyPlayer("Команду могут использовать только игроки");
Указание, что данную команду можно использовать только в консоле.
Опционально можно указать сообщение, которое будет выводиться Игроку.
Отменяет действие указателя useOnlyPlayer
CommandManager.Builder builder = CommandManager.create("start")
.useOnlyConsole(ChatColor.RED + "Команду можно использовать только в консоли");
Регистрация описанной в Конструкторе команды.
CommandManager.create("start")
.useOnlyPlayer()
.executer((sender, args) -> sender.sendMessage("hello!"))
.register();
Набор методов для работы с эффектами.
Воспроизвести звук.
Location location = ...;
EffectsHelper.playSound(location, Sound.AMBIENT_CAVE, 1.0f);
Создание частиц.
Location location = ...;
EffectsHelper.particle(location, Particle.REDSTONE, 1.0d, 1.0d, 1.0d, 1.0d, 5);
Регистрация группы обработчиков событий, объединённых общим условием выполнения.
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
.onEvent(PlayerJoinEvent.class, event -> { event.getPlayer().kickPlayer("Max players"); });
Создание контекста событий.
EventContext eventContext = EventContext.create();
Условие, при котором будут срабатывать обработчики событий в данном контексте.
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
Указание события и его обработчика.
Обработчик события регистрируется сразу же.
EventContext.create()
.filter(() -> Bukkit.getOnlinePlayers().size() > 10)
.onEvent(PlayerJoinEvent.class, event -> event.getPlayer().kickPlayer("Max players"));
Отменить событие.
Обработчик события регистрируется сразу же.
EventContext.create()
.cancelEvent(BlockPlaceEvent.class);
эквивалентен коду:
EventContext.create()
.onEvent(BlockPlaceEvent.class, event -> event.setCancelled(true))
Инструмент для упрощения работы с SQL базами данных, работающими через JDBC.
Для начала потребуется создать объект DataSource
// На примере MySQL
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerName("localhost");
dataSource.setPort(3306);
dataSource.setCharacterEncoding(StandardCharsets.UTF_8.name());
dataSource.setDatabaseName("MyDataBase");
dataSource.setUser("root");
dataSource.setPassword("secret");
После чего создать JdbcTemplate
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
Выполнение SQL запроса без последующей обработки результатов выполнения.
jdbcTemplate.execute("CREATE TABLE my_table (id int, name varchar(16));");
Выполнение SQL запроса и обработка его результатов.
Может возвращать любой тип объектов.
String name = jdbcTemplate.query("SELECT name FROM my_table LIMIT 0,1", resultSet -> {
if (resultSet.next()) {
return resultSet.getString("name");
} else {
return null;
}
});
List<String> names = jdbcTemplate.query("SELECT name FROM my_table", resultSet -> {
if (resultSet.next()) {
List<String> list = new ArrayList<>();
do {
list.add(resultSet.getString("name"));
} while (resultSet.next());
return list;
} else {
return Collections.emptyList();
}
});
Выполнение SQL запроса с расчетом, что результат будет единичным либо не будет вовсе.
Возвращает Optional
.
Optional<String> optName = jdbcTemplate.queryOne("SELECT name FROM my_table WHERE name LIKE 'dmitriymx'", rs -> rs.getString("name"));
Выполнение SQL запроса и обработка результата как списка данных.
Возвращает List
.
List<String> names = jdbcTemplate.queryList("SELECT name FROM my_table", (resultSet, rowNum) -> resultSet.getString("name"));
Выполнение SQL запроса с расчетом, что результат будет единичным либо не будет вовсе.
Возвращает Map<String, Object>
, где ключ — это наименование колонок таблицы, а значения — это значения в ячейках таблицы.
Map<String, Object> map = jdbcTemplate.queryForMap("SELECT * FROM my_table LIMIT 0,1;");
Выполнение SQL запроса и обработка результата как списка данных.
Возвращает List<Map<String, Object>>
, где ключ — это наименование колонок таблицы, а значения — это значения в ячейках таблицы.
List<Map<String, Object>> mapList = jdbcTemplate.queryForMapList("SELECT * FROM my_table");
Выполнение SQL запроса где будет происходить обновление данных в таблице.
Под "обновлением" подразумеваются любые изменения в таблице: UPDATE
, DELETE
, INSERT
.
Возвращает число строк, которые были по факту обновлены в таблице.
int rows = jdbcTemplate.update("DELETE FROM my_table WHERE name LIKE 'dmitriymx';");
Набор методов для создания параллельных задач, выполняющихся один раз или по рассписанию.
Создание конструктора задачи.
ScheduleManager.Builder builder = ScheduleManager.createTask();
Если задача будет взаимодействоватьс Bukkit API или необходима привязка задачи к тикам, то необходимо использовать данный указатель.
В ином случае, указатель не нужен.
ScheduleManager.Builder builder = ScheduleManager.createTask()
.useBukkitScheduler();
Указание, что задачу нужно выполнить не сразу, а с некоторой задержкой перед запуском.
ScheduleManager.Builder builder = ScheduleManager.createTask()
.after(5, TimeUnit.MINUTES);
Указание, что задачу нужно повторять через указанное время.
ScheduleManager.Builder builder = ScheduleManager.createTask()
.every(5, TimeUnit.MINUTES);
Создание описанной задачи.
ScheduleTask scheduleTask = ScheduleManager.createTask()
.every(1, TimeUnit.SECONDS)
.create(() -> Bukkit.getServer().getLogger().info("TimeMS: " + System.currentTimeMillis()));
Задача будет только создана. Для её выполнения нужно вызвать scheduleTask.start()
.
Создание и выполнение описанной задачи.
ScheduleTask scheduleTask = ScheduleManager.createTask()
.every(1, TimeUnit.SECONDS)
.execute(() -> Bukkit.getServer().getLogger().info("TimeMS: " + System.currentTimeMillis()));
Вспомогательный объект, созданный через ScheduleManager
. Позволяет управлять созданной задачей.
Запускает задачу, если она еще не запущена.
ScheduleTask scheduleTask = ...;
scheduleTask.start();
Возвращает состояние задачи. Если true
, значит задача была или отменена/остоновлена или была завершена.
ScheduleTask scheduleTask = ...;
boolean status = scheduleTask.isCanceled();
Отменяет/Остонавливает выполнение задачи.
ScheduleTask scheduleTask = ...;
scheduleTask.cancel();
Инструмент для работы с параметизированными сообщениями или просто сообщениями, которые храняться в отдельном файле.
Параметизированные сообщения имеют следующий вид: Привет, {player}!
.
Загрузка сообщений в инструмент.
Есть три варианта: через Properties
Properties properties = ...;
Messages.load(properties);
через Map<String, String>
Map<String, String> map = ...;
Messages.load(map);
через Reader
Reader reader = ...;
Messages.load(reader);
Следует учесть, про при работе через Reader
, Messages ожидает там обнаружить список строк в формате key=value
.
Получение обычноего или параметизированного сообщения.
Для примера, пусть у нас будут такие сообщения:
simple=Простое сообщение
welcome=Приветствуем, {player}!
Для получения простого сообщения, просто указываем его ключ:
String message = Messages.get("simple");
// Простое сообщение
Для получения параметизированного сообщения, нужно помимо ключа передать параметры.
Есть два способа: через Map<String, Object>
Map<String, Object> = map = new HashMap<>(1);
map.put("player", "David");
String message = Messages.get("welcome", map);
// Приветствуем, David!
через попарное перечисление параметров
String message = Messages.get("welcome", "player", "David");
// Приветствуем, David!
Если по указанному ключу сообщение отсутствует, то Messages вернёт значение самого ключа
String message = Messages.get("not_exists_key");
// not_exists_key
message = Messages.get("not_exists_key", "player", "David");
// not_exists_key
Если параметр, который указан в шаблоне не был указан/определён, то параметр останется как есть
String message = Messages.get("welcome");
// Приветствуем, {player}!
message = Messages.get("welcome", "unknown_param_key", 123);
// Приветствуем, {player}!
Messages можно использовать и просто для форматирования параметизированных шаблонов:
Map<String, Object> = map = new HashMap<>(1);
map.put("player", "David");
String message = Messages.format("Приветствуем, {player}!", map);
// Приветствуем, David!
String message = Messages.foramt("Приветствуем, {player}!", "player", "David");
// Приветствуем, David!
Замена стандартному getLogger()
, который использует java.utils.Logger
и не всегда удобен для логирования.
Имеет 4 уровня логирования: debug
, info
, warning
, error
.
Сообщения могут быть шаблонизированными. Синтаксис шаблонов — java.text.MessageFormat
.
Примеры:
XLog.info("Hello");
XLog.info("Player {0} join game", event.getPlayer().getName());
XLog.error("ERROR!", exception);
XLog.error("ERROR: {0}", exception.getMessage());
// Для экранирования "{" нужно перед ней поставить "'".
// А для использования "'" нужно их дублировать.
XLog.error("ERROR ''{0}'' in Event '{{1}'}: {2}", exception.getClass(), event.getClass(), exception.getMessage());
XLog.error("ERROR: {0}", exception.getMessage(), exception);
repositories {
maven { url 'https://dmx-mc-project.gitlab.io/maven-repository/' }
}
implementation group: 'ghast', name: 'ghast-tools', version: '1.12.1'
<repositories>
<repository>
<id>dmx-mc-project</id>
<url>https://dmx-mc-project.gitlab.io/maven-repository/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>ghast</groupId>
<artifactId>ghast-tools</artifactId>
<version>1.12.1</version>
</dependency>
</dependencies>