Последние рецензии

плагин балдёжный, но есть баг с тем что если курсором передвинуть ключ в инвентаре, то тайники перестают его видеть.

(после действия курсора с ключом в инвентаре, ключ становится обычным крюком из майнкрафта)
Конфликтует с packetevents, изза чего кикает с сервера с ошибкой подключения к каналу.

org.bukkit.command.CommandException: Unhandled exception executing command 'clan' in plugin FunnyClans v3.9
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:47) ~[purpur-api-1.21.11-R0.1-SNAPSHOT.jar:?]
at io.papermc.paper.command.brigadier.bukkit.BukkitCommandNode$BukkitBrigCommand.run(BukkitCommandNode.java:83) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at com.mojang.brigadier.context.ContextChain.runExecutable(ContextChain.java:73) ~[brigadier-1.3.10.jar:?]
at net.minecraft.commands.execution.tasks.ExecuteCommand.execute(ExecuteCommand.java:30) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.execution.tasks.ExecuteCommand.execute(ExecuteCommand.java:13) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.execution.UnboundEntryAction.lambda$bind$0(UnboundEntryAction.java:8) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.execution.CommandQueueEntry.execute(CommandQueueEntry.java:5) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.execution.ExecutionContext.runCommandQueue(ExecutionContext.java:104) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.Commands.executeCommandInContext(Commands.java:477) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.Commands.performCommand(Commands.java:382) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.commands.Commands.performCommand(Commands.java:370) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.network.ServerGamePacketListenerImpl.performUnsignedChatCommand(ServerGamePacketListenerImpl.java:2456) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.network.ServerGamePacketListenerImpl.lambda$handleChatCommand$15(ServerGamePacketListenerImpl.java:2429) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.TickTask.run(TickTask.java:18) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:177) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:24) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:1561) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:188) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:151) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.pollTaskInternal(MinecraftServer.java:1541) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.pollTask(MinecraftServer.java:1535) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.recordTaskExecutionTimeWhileWaiting(MinecraftServer.java:1240) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1377) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at net.minecraft.server.MinecraftServer.lambda$spin$2(MinecraftServer.java:392) ~[purpur-1.21.11.jar:1.21.11-2568-f57bd86]
at java.base/java.lang.Thread.run(Thread.java:1474) ~[?:?]
Caused by: java.lang.LinkageError: loader constraint violation: loader 'FunnyClans-3.9.jar' @21003af0 wants to load interface com.github.retrooper.packetevents.manager.player.PlayerManager. A different interface with the same name was previously loaded by 'packetevents-spigot-2.13.0.jar' @635d6286. (com.github.retrooper.packetevents.manager.player.PlayerManager is in unnamed module of loader 'packetevents-spigot-2.13.0.jar' @635d6286, parent loader java.net.URLClassLoader @433c675d)
at FunnyClans-3.9.jar//me.funnyclans.glow.armor.ArmorPacketSender.sendRealArmorPacket(ArmorPacketSender.java:56) ~[?:?]
at FunnyClans-3.9.jar//me.funnyclans.glow.GlowManager.sendRealArmorPacket(GlowManager.java:41) ~[?:?]
at FunnyClans-3.9.jar//me.funnyclans.data.ClanDeleter.deleteClan(ClanDeleter.java:31) ~[?:?]
at FunnyClans-3.9.jar//me.funnyclans.data.ClanManager.deleteClan(ClanManager.java:74) ~[?:?]
at FunnyClans-3.9.jar//me.funnyclans.commands.subcommands.DeleteCommand.execute(DeleteCommand.java:35) ~[?:?]
at FunnyClans-3.9.jar//me.funnyclans.commands.ClanCommand.onCommand(ClanCommand.java:123) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[purpur-api-1.21.11-R0.1-SNAPSHOT.jar:?]
... 24 more
Плагин хороший но есть один минус на версии 1.21.11 он просто не хочет переплавлять
unkn
unkn
Спасибо за отзыв!
отличный плагин, пользуюсь проблем пока не видал, спасибо за такое удобное взаймодействия с крафтами
Плагин хороший, но почему то, когда я ставлю трапку, она появляется в другом месте.
CrazyX
CrazyX
Надо скопировать в центре схематики
у вас всегда хорошие плагины этот не исключение меня сильно порадовало что плагин можно настроить в игре а не в конфиге
CrazyX
CrazyX
Спасибо большое
*(и мне всё равно, что тут нет Markdown)*

# Мишань, всё херня, давай по-новой.

У статьи две проблемы: большой упор на производительность и очень неудачные примеры, которые реального новичка могут привести совсем не в ту сторону. По себе знаю, потому что программировать начинал именно с написания плагинов.

При этом советы из статьи не то, что бы плохие. Но подача очень хромает.

## 1. Некорректная работа с конфигурацией
### а) Код из примера не идентичен по функционалу
Переменная `message` из "правильного" кода будет взята единожды и переиспользоваться даже после выполнения перезагрузки конфига `plugin.reloadConfig()` - то есть игрок будет всё время видеть одно и то же сообщение. Если действительно хотим показать что-то правильное, нужно расширять скоуп. Что-нибудь вроде:
```java
public class MyClass {
private String message;

public MyClass(Plugin plugin) {
reload(plugin);
Bukkit.getScheduller().runTaskTimer(plugin, () -> {
Player player = Bukkit.getPlayer(nickname);
player.sendMessage(message);
}, 200L, 200L);
}

public void reload(Plugin plugin) {
this.message = plugin.getConfig().getString("message");
}
}
```
В следствии, при вызове `MyClass#reload` у нас наконец будет обновляться соответствующее сообщение.

Причём, далее есть примеры с переменными класса, но комментарии к ним дают совершенно другой контекст, внезапно заговаривая про рекорды. Будто бы тут больше подошёл поэтапный формат "проблема > решение > проблема решения > новое решение"

### б) Неэффективность преувеличена
Когда как для часто-вызываемых блоков кода рассказ про производительность имеет смысл, здесь его уже почти нет. Единоразовая перезагрузка конфига не может уронить ТПС сервера, если только происходит что-то совсем не так.

Тем не менее, использование секций - хорошая практика, и я бы заострил внимание именно на этом. Да даже просто из-за риска очепяток.

Единственный случай, когда здесь производительность может иметь какое-то значение - если какие-то данные активно подхватываются с конфигов. Какая-нибудь там валюта игрока. Однако даже в таком случае основной проблемой будет скорей работа с файловой системой (можно было бы плавно перейти к асинхрону), нежели какой-то просчёт хэша строк.

## 2. Страх перед локальными переменными/константами и прочим
Тут уже получше...
### Ситуация 1) ...но у новичка нет контекста, что должно быть константой
Например, есть потоко-зависимые классы, которые таковыми не кажутся. Пускай какой-нибудь `SimpleDateFormat` уже считается крайне устаревшим, но вот какой-нибудь `new DecimalFormat("#.##")` выглядит как хороший кандидат... а потом оказывается, что у него есть внутренний буфер, который может упороться при выполнении в потоках.

Также можно предположить, что при работе с SQL какой-нибудь `PreparedStatement` можно сохранить - ведь даже название на это будто намекает - но пойдёшь лесом на втором же прогоне.

Сложно придумать, как получше это всё уместить - возможно, просто написать популярные кейсы, и в остальном посоветовать обращаться к JavaDoc'ам и гуглить.

### Ситуация 2) ...но пример слишком конкретный
Как и в первом, рассматривается очень определённый кейс, из чего можно только подчеркнуть, что общие операция со строками следует делать сразу. По факту же, стоит расширить описание - мол, это касается всех подобных кейсов. Собственно, у таких значений даже название есть - инвариант цикла - т.е. то, что не меняется из итерации в итерацию. Тут же следует сделать оговорку про мутабельность:
```java
List<String> bestPeople = new ArrayList<>(getAdminNames());
for (Player player : Bukkit.getOnlinePlayers()) {
bestPeople.add(player.getName());
player.sendMessage("В список лучших людей на сервере входят: " + bestPeople); // С каждой итерацией будут добавляться новые игроки
}
```

## 3. Проблемы с коллекциями
Тоже неплохо...
### А) ...но стоит подправить пример
Тут чем-то похоже на проблему из самого первого пункта. Я *очень* часто видел, как люди создают новый `HashSet` прямо перед работой с ним. Следует помнить, что создание такого объекта, как `HashSet`, тоже небесплатно, и, по возможности, это следует делать заранее.
### Б) ...но стоит, по-моему, расширить
Хранение `Player` - далеко не единственная причина утечек. Одна из самых популярных у новичков - хранение мутабельных объектов в `HashSet` и в ключах `HashMap`. Коллекция запоминает старый хэш, а поиск/удаление идёт изменённому - объект становится недоступен, но остаётся в памяти. Такое часто видел с объектами типа `Location`.

Конечно, если всё делать аккуратно, как и в случае в `Player`, проблем можно избежать. Но лучше просто избегать таких ситуаций. Например, с локацией можно оформить свой рекорд:
```java
public record MyLocation(String world, int x, int y, int z) {
public MyLocation(Location loc) {
this(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
}
```
### В) ...и всё
Могу лишь придраться, что для `ImmutableList`/`ImmutableSet` в ванильной джаве уже есть свои аналоги.

## 4. Асинхрон/конкурентность и что там должно и не должно быть
Очень странные примеры. Из них кажется, будто для работы с `ConcurrentHashMap` нужно обязательно работать в асинхроне - в реальности же, в однопоточном режиме производительность `CHM` сопоставима со стандартным `HashMap`. Лучше уж сделать по примеру про использование `HashMap` vs `CHM`, и по примеру для вызова долгих или тяжёлых операций, вроде обращения по сети, нормальная компутация, или работа с файловой системой.

## 5. Принцип DRY и ради бога - следуйте ему.
Ну тут правда. Хотелось бы только блоки логики побольше, чтоб реально показать разницу.

## 6. Мелкие придирки к бесящим вещам
Тут просто оставлю пару комментариев.
### А) Dependency Injection - круто
Единственное - про громоздкость можно поспорить. При правильной архитектуре и это решаемо, но это уже совсем другая история.
### Б) Хе-хе-хе, мой старый код
Наверно, один из лучших вариантов для баланса между производительностью и поддерживаемостью кода. Но примерно на том же уровне можно сделать всё и без регулярок, и одним методом.

# Моё заключение
1. Самое важное - нужны правки примеров (а ещё `getScheduler()` с одной `l`).
2. Некоторые темы плохо раскрыты.
3. Слишком большой упор на производительность - пишешь верно, но новичка так можно довести до того, что тот постоянно будет заниматься преждевременной ~~эяк~~оптимизацией.
4. Если реально заниматься оптимизацией - без тестов многое подтвердить просто невозможно, хорошо бы чего про проверки через JMH и spark тогда.
5. Как финальный совет, можно было бы попросить новичков забить на Spigot API и перейти на Paper API. Потихоньку оно будет становиться всё более несовместимым, а фич там намного больше.
В целом, сборка хорошая, но есть пару нюансов, ниже чуть более подробно:

Плюсы: Продавец ответил быстро, Цена небольшая, Способов оплаты предложили несколько, Сама по себе сборка работает отлично, На все вопросы ответили, Помогли настроить веб-карту мира.

Минусов только 2: 1. Высокий пинг - подобнее, у меня есть VDS машина, на ней запущено 3 режима, один из которых - ванилла этой сборки. ресурсы всем серверам выданы одни, сервера запущены через докер. Пинг на анархии 80, в то же время, когда я захожу на ваниллу, поднимается до 120, при этом соединение никак не меняется, тот же IP с которого захожу, та же машина, вероятнее всего проблема в сборке. 2. Много упоминаний MrDrag0nXYT, в целом, что это прям минус, сказать не могу, скорее что-то неприятное, исправляется не очень сложно
Приобрел сборку лобби, хотел обновить старое лобби текущего проекта. С продавцом списался, ответ получил довольно быстро. После оплаты сборку выдали быстро, сборка была качественно реализована. После покупки все вопросы были быстро решены, я обновил сборку под свой проект и поставил на прод. Сборка сейчас работает хорошо, у игроков и у меня вопросов к ней нет. Спасибо❤️
очень хорошая сборка, для ванилы. Разраб помог разобраться с плагинами, помог все настроить +rep
Lorex
Lorex
спасибо за оценку ресурса!
отличный плагин, после того как разработчик внесет те обновления которые я предложил, станет еще лучше
Kronose0
Kronose0
Большое спасибо за рецензию!
спасибо большое автору сборки, сборка ПОТРЯСАЮЩА, не смотря на свои баги, честно, сборка на уровне платной, и не как иначе, буду ждать последующих обновлений. Рекомендую!!)
jxesi
jxesi
ухты! спасибки за рецензию) последующие обновления будут, пусть и не очень часто. сфокусируюсь как раз на исправлении ошибок и полировке. спасибо за поддержку! 🤗
Один из ЛУЧШИХ плагинов на скупщика, разнообразие видов скупщика ГЛАВНЫЙ ПЛЮС. Если в других плагинах только один вид, то тут их 3 и это просто ИМБА
StupidCoder
StupidCoder
Спасибо за отзыв!
Отличная студия! Администрация всегда на связи, отвечает быстро и помогает с любыми вопросами. Купленные карты полностью оправдали ожидания — качественные, красивые и отлично проработанные. Остался очень доволен сервисом и отношением к клиентам. Смело рекомендую Lunacy Studio всем, кто ищет качественные проекты и услуги!
Отличная студия! Администрация всегда на связи, отвечает быстро и помогает с любыми вопросами. Купленные карты полностью оправдали ожидания — качественные, красивые и отлично проработанные. Остался очень доволен сервисом и отношением к клиентам. Смело рекомендую Lunacy Studio всем, кто ищет качественные проекты и услуги!
Плагин так по себе хороший, но есть одно НО, добавь чтобы можно было ограничивать за какую максимальную и минимальную цену игрок может выставлять предмет. Буду очень благодарен, а так плагин огонь!
Отличный плагин. Всем советую. 2фа и так далее просто пушка
Купил у него сборку дуелей, кинул в чс, и обманул на деньги, удалил переписку.
Плагин нормальный, но хотелось бы, чтобы можно было сделать выдачу награды только за подписку на какие-то тг каналы
Назад
Сверху Снизу