Плагин на баны, муты, кики в формах. [FormAPI v2.1.1]
Сброс лимитов каждые 24 часа
Настройка лимитов в конфиге
Настройка сообщений в message.yml
BanKickMuteUI.zip (8,1 КБ)
Плагин на баны, муты, кики в формах. [FormAPI v2.1.1]
Сброс лимитов каждые 24 часа
Настройка лимитов в конфиге
Настройка сообщений в message.yml
BanKickMuteUI.zip (8,1 КБ)
Оно хотя бы работает? И почему тема в Minecraft Pocket/Bedrock Edition > Вопросы/Обсуждения?
Хотя грок уделал? ChatGPT, так что шансы есть
<?php
namespace BanMuteKickUI;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\CommandExecutor;
use pocketmine\utils\Config;
class UnbanHandler implements CommandExecutor {
private $plugin;
private $banData;
private $muteData;
private $messages;
public function __construct(Main $plugin, Config $banData, Config $muteData, Config $messages) {
$this->plugin = $plugin;
$this->banData = $banData;
$this->muteData = $muteData;
$this->messages = $messages;
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
switch ($command->getName()) {
case "munban":
if (!$sender->hasPermission("banmutekickui.unban")) {
$sender->sendMessage($this->plugin->getMessage("no_permission"));
return true;
}
if (!isset($args[0])) {
$sender->sendMessage("Usage: /munban <player>");
return true;
}
$target = strtolower($args[0]);
if ($this->banData->exists($target)) {
$this->banData->remove($target);
$this->banData->save();
$placeholders = [
"player" => $sender->getName(),
"target" => $target
];
$sender->sendMessage($this->plugin->getMessage("player_unbanned", $placeholders));
$this->plugin->getServer()->broadcastMessage($this->plugin->getMessage("player_unbanned", $placeholders));
} else {
$sender->sendMessage($this->plugin->getMessage("player_not_banned", ["target" => $target]));
}
break;
case "munmute":
if (!$sender->hasPermission("banmutekickui.unmute")) {
$sender->sendMessage($this->plugin->getMessage("no_permission"));
return true;
}
if (!isset($args[0])) {
$sender->sendMessage("Usage: /munmute <player>");
return true;
}
$target = strtolower($args[0]);
if ($this->muteData->exists($target)) {
$this->muteData->remove($target);
$this->muteData->save();
$placeholders = [
"player" => $sender->getName(),
"target" => $target
];
$sender->sendMessage($this->plugin->getMessage("player_unmuted", $placeholders));
$this->plugin->getServer()->broadcastMessage($this->plugin->getMessage("player_unmuted", $placeholders));
} else {
$sender->sendMessage($this->plugin->getMessage("player_not_muted", ["target" => $target]));
}
break;
}
return true;
}
}
<?php
namespace BanMuteKickUI;
use pocketmine\plugin\PluginBase;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\player\Player;
use pocketmine\event\Listener;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\player\PlayerChatEvent;
use pocketmine\command\PluginCommand;
use jojoe77777\FormAPI\CustomForm;
use pocketmine\utils\Config;
use pocketmine\utils\TextFormat;
class Main extends PluginBase implements Listener {
private Config $banData;
private Config $muteData;
private Config $messages;
private Config $resetData;
private UnbanHandler $unbanHandler;
public function onEnable(): void {
$this->saveResource("message.yml");
$this->messages = new Config($this->getDataFolder() . "message.yml", Config::YAML);
$this->banData = new Config($this->getDataFolder() . "bans.yml", Config::YAML);
$this->muteData = new Config($this->getDataFolder() . "mutes.yml", Config::YAML);
$this->resetData = new Config($this->getDataFolder() . "reset.yml", Config::YAML);
if (!$this->resetData->exists("start_time")) {
$currentTime = time();
$this->resetData->set("start_time", $currentTime);
$this->resetData->set("last_reset", $currentTime);
$this->resetData->save();
$this->getLogger()->info("Установлено начальное время сброса: $currentTime");
}
if (!class_exists("jojoe77777\FormAPI\Form")) {
$this->getServer()->getPluginManager()->disablePlugin($this);
return;
}
$this->unbanHandler = new UnbanHandler($this, $this->banData, $this->muteData, $this->messages);
$this->getServer()->getPluginManager()->registerEvents($this, $this);
$commandMap = $this->getServer()->getCommandMap();
$commandsToUnregister = ["munban", "munmute", "mban", "mmute", "mkick", "banmutekickui:munban", "banmutekickui:munmute"];
foreach ($commandsToUnregister as $cmdName) {
$command = $commandMap->getCommand($cmdName);
if ($command instanceof Command) {
$commandMap->unregister($command);
}
}
$munban = new PluginCommand("munban", $this, $this->unbanHandler);
$munban->setPermission("banmutekickui.unban");
$munban->setDescription("Разбанивает игрока");
$munban->setUsage("/munban <игрок>");
$munmute = new PluginCommand("munmute", $this, $this->unbanHandler);
$munmute->setPermission("banmutekickui.unmute");
$munmute->setDescription("Размучивает игрока");
$munmute->setUsage("/munmute <игрок>");
$mkick = new PluginCommand("mkick", $this, $this);
$mkick->setPermission("banmutekickui.kick");
$mkick->setDescription("Кикает игрока");
$mkick->setUsage("/mkick <игрок> [причина]");
$mban = new PluginCommand("mban", $this, $this);
$mban->setPermission("banmutekickui.ban");
$mban->setDescription("Банит игрока");
$mban->setUsage("/mban");
$mmute = new PluginCommand("mmute", $this, $this);
$mmute->setPermission("banmutekickui.mute");
$mmute->setDescription("Мутит игрока");
$mmute->setUsage("/mmute");
$commandMap->register("", $munban);
$commandMap->register("", $munmute);
$commandMap->register("", $mkick);
$commandMap->register("", $mban);
$commandMap->register("", $mmute);
$this->getScheduler()->scheduleRepeatingTask(new \pocketmine\scheduler\ClosureTask(function() {
$this->resetLimitsIfNeeded();
}), 20 * 86400);
$this->getLogger()->info("Планировщик сброса лимитов запущен.");
}
public function getMessage(string $key, array $placeholders = []): string {
$message = $this->messages->get($key, "Сообщение не найдено: $key");
foreach ($placeholders as $placeholder => $value) {
$message = str_replace("\$$placeholder", $value, $message);
}
return TextFormat::colorize($message);
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
switch ($command->getName()) {
case "mban":
if (!$sender->hasPermission("banmutekickui.ban")) {
$sender->sendMessage($this->getMessage("no_permission"));
return true;
}
if ($sender instanceof Player) {
$this->openBanUI($sender);
} else {
$sender->sendMessage($this->getMessage("form_only_in_game"));
}
break;
case "mmute":
if (!$sender->hasPermission("banmutekickui.mute")) {
$sender->sendMessage($this->getMessage("no_permission"));
return true;
}
if ($sender instanceof Player) {
$this->openMuteUI($sender);
} else {
$sender->sendMessage($this->getMessage("form_only_in_game"));
}
break;
case "mkick":
if (!$sender->hasPermission("banmutekickui.kick")) {
$sender->sendMessage($this->getMessage("no_permission"));
return true;
}
if ($sender instanceof Player && empty($args)) {
$this->openKickUI($sender);
} else {
if (!isset($args[0])) {
$sender->sendMessage("Usage: /mkick <игрок> [причина]");
return true;
}
$target = strtolower($args[0]);
$reason = isset($args[1]) ? implode(" ", array_slice($args, 1)) : "Не указана";
if ($target === strtolower($sender->getName()) && $sender instanceof Player) {
$sender->sendMessage($this->getMessage("no_self_punishment"));
return true;
}
$player = $sender instanceof Player ? $sender : null;
if ($player === null || $this->checkKickLimits($player)) {
if ($this->kickPlayer($target, $reason, $sender)) {
$this->getServer()->broadcastMessage($this->getMessage("player_kick", [
"player" => $sender->getName(),
"target" => $target,
"reason" => $reason
]));
} else {
$sender->sendMessage($this->getMessage("player_not_online", ["target" => $target]));
}
} else {
$sender->sendMessage($this->getMessage("kick_limit_exceeded"));
}
}
break;
}
return true;
}
public function onPlayerLogin(PlayerLoginEvent $event): void {
$player = $event->getPlayer();
$name = strtolower($player->getName());
$ip = $player->getNetworkSession()->getIp();
if ($this->banData->exists($name)) {
$banInfo = $this->banData->get($name);
if (!is_array($banInfo) || !isset($banInfo["time"])) {
$this->banData->remove($name);
$this->banData->save();
return;
}
$banTime = $banInfo["time"];
if ($banTime !== -1 && time() >= $banTime) {
$this->banData->remove($name);
$this->banData->save();
} else {
$reason = $banInfo["reason"] ?? "Не указана";
$unbanTime = $banTime === -1 ? "Навсегда" : date("Y-m-d H:i", $banTime);
$event->setKickMessage($this->getMessage("ban_kick_message", [
"player" => $banInfo["issuer"] ?? "Сервер",
"reason" => $reason,
"unban_time" => $unbanTime
]));
$event->cancel();
}
}
$ipBans = $this->banData->get("ip_bans", []);
if (isset($ipBans[$ip])) {
$ipBanInfo = $ipBans[$ip];
if (!is_array($ipBanInfo) || !isset($ipBanInfo["time"])) {
$this->banData->remove("ip_bans.$ip");
$this->banData->save();
return;
}
$banTime = $ipBanInfo["time"];
if ($banTime !== -1 && time() >= $banTime) {
$this->banData->remove("ip_bans.$ip");
$this->banData->save();
} else {
$reason = $ipBanInfo["reason"] ?? "Не указана";
$unbanTime = $banTime === -1 ? "Навсегда" : date("Y-m-d H:i", $banTime);
$event->setKickMessage($this->getMessage("ban_kick_message", [
"player" => $ipBanInfo["issuer"] ?? "Сервер",
"reason" => $reason,
"unban_time" => $unbanTime
]));
$event->cancel();
}
}
}
public function onPlayerChat(PlayerChatEvent $event): void {
$player = $event->getPlayer();
$name = strtolower($player->getName());
if ($this->muteData->exists($name)) {
$muteInfo = $this->muteData->get($name);
if (!is_array($muteInfo) || !isset($muteInfo["time"])) {
$this->muteData->remove($name);
$this->muteData->save();
return;
}
$muteTime = $muteInfo["time"];
if ($muteTime !== -1 && time() >= $muteTime) {
$this->muteData->remove($name);
$this->muteData->save();
} else {
$reason = $muteInfo["reason"] ?? "Не указана";
$unmuteTime = $muteTime === -1 ? "Навсегда" : date("Y-m-d H:i", $muteTime);
$player->sendMessage($this->getMessage("mute_message", [
"player" => $muteInfo["issuer"] ?? "Сервер",
"reason" => $reason,
"unmute_time" => $unmuteTime
]));
$event->cancel();
}
}
}
private function openBanUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "ban");
$maxTime = $limits["max_time"] ?? "∞";
$maxCount = $limits["max_count"] ?? "∞";
$banCount = $this->banData->getNested(strtolower($player->getName()) . ".count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) {
$player->sendMessage("§cФорма закрыта без ввода данных.");
return;
}
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$time = isset($data[2]) && is_numeric($data[2]) ? (int)$data[2] : 0;
$reason = isset($data[3]) && is_string($data[3]) ? trim($data[3]) : '';
$ipBan = $player->hasPermission("banmutekickui.ban.op") && isset($data[4]) ? (bool)$data[4] : false;
$permBan = $player->hasPermission("banmutekickui.ban.op") && isset($data[5]) ? (bool)$data[5] : false;
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if ($reason === '') {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($time === 0 && !$permBan) {
$player->sendMessage($this->getMessage("no_empty_time"));
return;
}
if ($time === -1 && !$player->hasPermission("banmutekickui.ban.op")) {
$player->sendMessage("§cТолько операторы могут выдавать перманентные баны!");
return;
}
if ($permBan) {
$time = -1;
}
if ($this->checkBanLimits($player, $time)) {
$this->banPlayer($target, $time, $reason, $player, $ipBan);
} else {
$player->sendMessage($this->getMessage("ban_limit_exceeded"));
}
});
$form->setTitle("§c§lЗабанить игрока");
$form->addLabel("§eМакс. время: §r$maxTime §eмин. | §eОсталось попыток: §r" . ($maxCount === "∞" ? "∞" : ($maxCount - $banCount)));
$form->addInput("Имя игрока", "Введите имя игрока", "");
$form->addInput("Время бана (в минутах)", "Введите время в минутах", "");
$form->addInput("Причина", "Введите причину бана", "");
if ($player->hasPermission("banmutekickui.ban.op")) {
$form->addToggle("Бан по IP", false);
$form->addToggle("Перманентный бан", false);
}
$player->sendForm($form);
}
private function openMuteUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "mute");
$maxTime = $limits["max_time"] ?? "∞";
$maxCount = $limits["max_count"] ?? "∞";
$muteCount = $this->muteData->getNested(strtolower($player->getName()) . ".count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) {
$player->sendMessage("§cФорма закрыта без ввода данных.");
return;
}
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$time = isset($data[2]) && is_numeric($data[2]) ? (int)$data[2] : 0;
$reason = isset($data[3]) && is_string($data[3]) ? trim($data[3]) : '';
$permMute = $player->hasPermission("banmutekickui.ban.op") && isset($data[4]) ? (bool)$data[4] : false;
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if ($reason === '') {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($time === 0 && !$permMute) {
$player->sendMessage($this->getMessage("no_empty_time"));
return;
}
if ($time === -1 && !$player->hasPermission("banmutekickui.ban.op")) {
$player->sendMessage("§cТолько операторы могут выдавать перманентные муты!");
return;
}
if ($permMute) {
$time = -1;
}
if ($this->checkMuteLimits($player, $time)) {
$this->mutePlayer($target, $time, $reason, $player);
} else {
$player->sendMessage($this->getMessage("mute_limit_exceeded"));
}
});
$form->setTitle("§c§lЗамутить игрока");
$form->addLabel("§eМакс. время: §r$maxTime §eмин. | §eОсталось попыток: §r" . ($maxCount === "∞" ? "∞" : ($maxCount - $muteCount)));
$form->addInput("Имя игрока", "Введите имя игрока", "");
$form->addInput("Время мута (в минутах)", "Введите время в минутах", "");
$form->addInput("Причина", "Введите причину мута", "");
if ($player->hasPermission("banmutekickui.ban.op")) {
$form->addToggle("Перманентный мут", false);
}
$player->sendForm($form);
}
private function openKickUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "kick");
$maxCount = $limits["max_count"] ?? "∞";
$kickCount = $this->banData->getNested(strtolower($player->getName()) . ".kick_count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) {
$player->sendMessage("§cФорма закрыта без ввода данных.");
return;
}
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$reason = isset($data[2]) && is_string($data[2]) ? trim($data[2]) : '';
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if ($reason === '') {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($this->checkKickLimits($player)) {
$kickResult = $this->kickPlayer($target, $reason, $player);
if ($kickResult === true) {
$this->getServer()->broadcastMessage($this->getMessage("player_kick", [
"player" => $player->getName(),
"target" => $target,
"reason" => $reason
]));
} elseif ($kickResult === false) {
$player->sendMessage($this->getMessage("player_not_online", ["target" => $target]));
}
} else {
$player->sendMessage($this->getMessage("kick_limit_exceeded"));
}
});
$form->setTitle("§c§lКикнуть игрока");
$form->addLabel("§eОсталось попыток: §r" . ($maxCount === "∞" ? "∞" : ($maxCount - $kickCount)));
$form->addInput("Имя игрока", "Введите имя игрока", "");
$form->addInput("Причина", "Введите причину кика", "");
$player->sendForm($form);
}
private function getPlayerLimits(Player $player, string $type): array {
$config = $this->getConfig();
if ($player->hasPermission("banmutekickui.$type.op")) {
return ["max_time" => "∞", "max_count" => "∞"];
}
$limits = [];
foreach ($config->get($type, []) as $perm => $values) {
if ($player->hasPermission("banmutekickui.$type.$perm")) {
$limits = $values;
break;
}
}
return $limits;
}
private function checkBanLimits(Player $player, int $time): bool {
$config = $this->getConfig();
$issuerName = strtolower($player->getName());
$banInfo = $this->banData->get($issuerName, []);
$banCount = isset($banInfo["count"]) ? (int)$banInfo["count"] : 0;
if ($player->hasPermission("banmutekickui.ban.op")) return true;
foreach ($config->get("ban", []) as $perm => $limits) {
if ($player->hasPermission("banmutekickui.ban.$perm")) {
$maxTime = $limits["max_time"];
$maxCount = $limits["max_count"];
if ($time !== -1 && $time > $maxTime) return false;
if ($banCount >= $maxCount) return false;
return true;
}
}
return false;
}
private function checkMuteLimits(Player $player, int $time): bool {
$config = $this->getConfig();
$issuerName = strtolower($player->getName());
$muteInfo = $this->muteData->get($issuerName, []);
$muteCount = isset($muteInfo["count"]) ? (int)$muteInfo["count"] : 0;
if ($player->hasPermission("banmutekickui.ban.op")) return true;
foreach ($config->get("mute", []) as $perm => $limits) {
if ($player->hasPermission("banmutekickui.mute.$perm")) {
$maxTime = $limits["max_time"];
$maxCount = $limits["max_count"];
if ($time !== -1 && $time > $maxTime) return false;
if ($muteCount >= $maxCount) return false;
return true;
}
}
return false;
}
private function checkKickLimits(?Player $player): bool {
$config = $this->getConfig();
if ($player === null) return true;
$issuerName = strtolower($player->getName());
$kickInfo = $this->banData->get($issuerName, []);
$kickCount = isset($kickInfo["kick_count"]) ? (int)$kickInfo["kick_count"] : 0;
if ($this->getServer()->isOp($issuerName) || $player->hasPermission("banmutekickui.kick.op")) {
return true;
}
foreach ($config->get("kick", []) as $perm => $limits) {
if ($player->hasPermission("banmutekickui.kick.$perm")) {
$maxCount = $limits["max_count"];
return $kickCount < $maxCount;
}
}
return false;
}
private function banPlayer(string $target, int $time, string $reason, Player $issuer, bool $ipBan): void {
if (empty($reason)) return;
$target = strtolower($target);
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuer->getName()]));
return;
}
$banTime = $time === -1 ? -1 : time() + ($time * 60);
$issuerName = strtolower($issuer->getName());
$this->banData->set($target, ["time" => $banTime, "reason" => $reason, "issuer" => $issuerName, "ip_ban" => $ipBan]);
$banInfo = $this->banData->get($issuerName, []);
$banCount = isset($banInfo["count"]) ? (int)$banInfo["count"] : 0;
$this->banData->setNested($issuerName . ".count", $banCount + 1);
$this->banData->save();
$unbanTime = $time === -1 ? "Никогда" : date("Y-m-d H:i", $banTime);
if ($targetPlayer !== null) {
$targetPlayer->kick($this->getMessage("ban_kick_message", [
"player" => $issuerName,
"reason" => $reason,
"unban_time" => $unbanTime
]));
if ($ipBan) {
$ip = $targetPlayer->getNetworkSession()->getIp();
$this->banData->set("ip_bans.$ip", ["time" => $banTime, "reason" => $reason, "issuer" => $issuerName]);
$this->banData->save();
}
}
$this->getServer()->broadcastMessage($this->getMessage($ipBan ? "player_ip_ban" : "player_ban", [
"player" => $issuerName,
"target" => $target,
"reason" => $reason,
"unban_time" => $unbanTime
]));
}
private function mutePlayer(string $target, int $time, string $reason, Player $issuer): void {
if (empty($reason)) return;
$target = strtolower($target);
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuer->getName()]));
return;
}
$muteTime = $time === -1 ? -1 : time() + ($time * 60);
$issuerName = strtolower($issuer->getName());
$this->muteData->set($target, ["time" => $muteTime, "reason" => $reason, "issuer" => $issuerName]);
$muteInfo = $this->muteData->get($issuerName, []);
$muteCount = isset($muteInfo["count"]) ? (int)$muteInfo["count"] : 0;
$this->muteData->setNested($issuerName . ".count", $muteCount + 1);
$this->muteData->save();
$unmuteTime = $time === -1 ? "Никогда" : date("Y-m-d H:i", $muteTime);
if ($targetPlayer !== null) {
$targetPlayer->sendMessage($this->getMessage("mute_message", [
"player" => $issuerName,
"reason" => $reason,
"unmute_time" => $unmuteTime
]));
}
$this->getServer()->broadcastMessage($this->getMessage("player_mute", [
"player" => $issuerName,
"target" => $target,
"reason" => $reason,
"unmute_time" => $unmuteTime
]));
}
private function kickPlayer(string $target, string $reason, CommandSender $issuer): mixed {
$issuerName = strtolower($issuer->getName());
$target = strtolower($target);
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
if ($issuer instanceof Player) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuerName]));
}
return null;
}
$kickCount = $this->banData->getNested("$issuerName.kick_count", 0);
$this->banData->setNested("$issuerName.kick_count", $kickCount + 1);
$this->banData->save();
if ($targetPlayer instanceof Player && $targetPlayer->isOnline()) {
$kickMessage = $this->getMessage("kick_message", [
"player" => $issuerName,
"reason" => $reason
]);
$targetPlayer->kick($kickMessage);
return true;
}
return false;
}
private function resetLimitsIfNeeded(): void {
$config = $this->getConfig();
$resetInterval = $config->get("reset_interval", 86400);
$currentTime = time();
$startTime = $this->resetData->get("start_time", $currentTime);
$lastReset = $this->resetData->get("last_reset", $startTime);
$this->getLogger()->info("Проверка сброса лимитов: Current: $currentTime, Last Reset: $lastReset, Interval: $resetInterval");
$timeSinceLastReset = $currentTime - $lastReset;
if ($timeSinceLastReset >= $resetInterval) {
$this->getLogger()->info("Сброс лимитов: Прошло $timeSinceLastReset секунд с последнего сброса.");
$banData = $this->banData->getAll();
foreach ($banData as $name => $banInfo) {
if (!is_array($banInfo)) continue;
$name = strtolower($name);
$this->banData->setNested($name . ".count", 0);
$this->banData->setNested($name . ".kick_count", 0);
$player = $this->getServer()->getPlayerExact($name);
if ($player !== null) {
$player->sendMessage($this->getMessage("limits_reset"));
}
}
$this->banData->save();
$muteData = $this->muteData->getAll();
foreach ($muteData as $name => $muteInfo) {
if (!is_array($muteInfo)) continue;
$name = strtolower($name);
$this->muteData->setNested($name . ".count", 0);
$player = $this->getServer()->getPlayerExact($name);
if ($player !== null) {
$player->sendMessage($this->getMessage("limits_reset"));
}
}
$this->muteData->save();
$this->resetData->set("last_reset", $currentTime);
$this->resetData->save();
$this->getLogger()->info("Лимиты наказаний сброшены для всех игроков. Новый last_reset: $currentTime");
} else {
$this->getLogger()->info("Сброс лимитов не требуется: Прошло $timeSinceLastReset секунд, нужно $resetInterval.");
}
}
}
это ■■■■■■
Потому что обсуждение.
Для этого существует Беседка
шо ты там уже 4 минуты строчишь?
Command
и PluginOwned
уже не в моде. Теперь НУЖНО использовать интерфейс который вообще создан для главных классов.
Узнал себя 2 года назад xD
plugin.yml
на команду, если его не реализуют отдельным классом (-_-)testPermission()
если прав нет…Это указывать не обязательно кст, если только расширение не поменял
Так, погодите… Это типо сброс всех данные о банах и мутах?!
Очень сильно.
Извинитесь. Где он эти команды взял?
В исходном коде ядра, метод getCommand()
вернет либо Command
, либо null
, так что if (!$command) {}
в соло.
А в чём прикол?
А зачем тогда нужен был UnbanHandler
? (UPD: Только щяс понял что там разные команды)
Остальное лень комментировать, но понял то, что это стиль кода SkyPlugins, FactoryPlugins и прочих вк групп.
Плагин не надежный, плохо структурированный, захардкоденный
да там все меньше чем за 80 строк все сделать (событие, таск, команда т.д)
@MEFRREEX ты умеешь в рп?
Крч, я попросил его подумать, врубил ему глубокое мышление и попросил улучшить все что ты перечислил он выдал это:
Main.php :
<?php
namespace BanMuteKickUI;
use pocketmine\plugin\PluginBase;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\player\Player;
use pocketmine\event\Listener;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\player\PlayerChatEvent;
use pocketmine\command\PluginCommand;
use jojoe77777\FormAPI\CustomForm;
use pocketmine\utils\Config;
use pocketmine\utils\TextFormat;
class Main extends PluginBase implements Listener {
private Config $banData;
private Config $muteData;
private Config $messages;
private Config $resetData;
private UnbanHandler $unbanHandler;
public function onEnable(): void {
$this->saveResource("message.yml");
$this->messages = new Config($this->getDataFolder() . "message.yml", Config::YAML);
$this->banData = new Config($this->getDataFolder() . "bans.yml", Config::YAML);
$this->muteData = new Config($this->getDataFolder() . "mutes.yml", Config::YAML);
$this->resetData = new Config($this->getDataFolder() . "reset.yml", Config::YAML);
if (!$this->resetData->exists("start_time")) {
$currentTime = time();
$this->resetData->setAll(["start_time" => $currentTime, "last_reset" => $currentTime]);
$this->resetData->save();
}
if (!class_exists("jojoe77777\FormAPI\Form")) {
$this->getLogger()->error("FormAPI не найден. Плагин отключен.");
$this->getServer()->getPluginManager()->disablePlugin($this);
return;
}
$this->unbanHandler = new UnbanHandler($this, $this->banData, $this->muteData, $this->messages);
$this->getServer()->getPluginManager()->registerEvents($this, $this);
$this->registerCommands();
// Запуск задач
$this->getScheduler()->scheduleRepeatingTask(new \pocketmine\scheduler\ClosureTask(function() {
$this->resetLimitsIfNeeded();
}), 20 * 86400); // Каждые 24 часа
$this->getScheduler()->scheduleRepeatingTask(new \pocketmine\scheduler\ClosureTask(function() {
$this->cleanupExpiredPunishments();
}), 20 * 60 * 5); // Каждые 5 минут
$this->getLogger()->info("Плагин BanMuteKickUI успешно запущен.");
}
private function registerCommands(): void {
$commandMap = $this->getServer()->getCommandMap();
$commands = [
["munban", "banmutekickui.unban", "Разбанивает игрока", "/munban <игрок>", $this->unbanHandler],
["munmute", "banmutekickui.unmute", "Размучивает игрока", "/munmute <игрок>", $this->unbanHandler],
["mkick", "banmutekickui.kick", "Кикает игрока", "/mkick <игрок> [причина]", $this],
["mban", "banmutekickui.ban", "Банит игрока", "/mban", $this],
["mmute", "banmutekickui.mute", "Мутит игрока", "/mmute", $this]
];
foreach ($commands as [$name, $permission, $description, $usage, $executor]) {
$command = new PluginCommand($name, $this, $executor);
$command->setPermission($permission);
$command->setDescription($description);
$command->setUsage($usage);
$commandMap->register("banmutekickui", $command);
}
}
public function getMessage(string $key, array $placeholders = []): string {
$message = $this->messages->get($key, "Сообщение не найдено: $key");
foreach ($placeholders as $placeholder => $value) {
$message = str_replace("\$$placeholder", (string)$value, $message);
}
return TextFormat::colorize($message);
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
$cmd = $command->getName();
if (!$sender->hasPermission("banmutekickui.$cmd")) {
$sender->sendMessage($this->getMessage("no_permission"));
return true;
}
if ($cmd === "mkick") {
return $this->handleKickCommand($sender, $args);
}
if (!($sender instanceof Player)) {
$sender->sendMessage($this->getMessage("form_only_in_game"));
return true;
}
if ($cmd === "mban") {
$this->openBanUI($sender);
} elseif ($cmd === "mmute") {
$this->openMuteUI($sender);
}
return true;
}
private function handleKickCommand(CommandSender $sender, array $args): bool {
if ($sender instanceof Player && empty($args)) {
$this->openKickUI($sender);
return true;
}
if (!isset($args[0])) {
$sender->sendMessage("Usage: /mkick <игрок> [причина]");
return true;
}
$target = strtolower($args[0]);
$reason = isset($args[1]) ? implode(" ", array_slice($args, 1)) : "Не указана";
if ($sender instanceof Player && $target === strtolower($sender->getName())) {
$sender->sendMessage($this->getMessage("no_self_punishment"));
return true;
}
if (!$this->checkKickLimits($sender instanceof Player ? $sender : null)) {
$sender->sendMessage($this->getMessage("kick_limit_exceeded"));
return true;
}
$result = $this->kickPlayer($target, $reason, $sender);
if ($result === true) {
$this->getServer()->broadcastMessage($this->getMessage("player_kick", [
"player" => $sender->getName(),
"target" => $target,
"reason" => $reason
]));
} elseif ($result === false) {
$sender->sendMessage($this->getMessage("player_not_online", ["target" => $target]));
}
return true;
}
public function onPlayerLogin(PlayerLoginEvent $event): void {
$player = $event->getPlayer();
$name = strtolower($player->getName());
$ip = $player->getNetworkSession()->getIp();
if ($this->banData->exists("bans.$name")) {
$banInfo = $this->banData->get("bans.$name");
if (is_array($banInfo) && isset($banInfo["time"]) && ($banInfo["time"] === -1 || time() < $banInfo["time"])) {
$event->setKickMessage($this->getMessage("ban_kick_message", [
"player" => $banInfo["issuer"] ?? "Сервер",
"reason" => $banInfo["reason"] ?? "Не указана",
"unban_time" => $banInfo["time"] === -1 ? "Навсегда" : date("Y-m-d H:i", $banInfo["time"])
]));
$event->cancel();
return;
}
}
if ($this->banData->exists("ip_bans.$ip")) {
$ipBanInfo = $this->banData->get("ip_bans.$ip");
if (is_array($ipBanInfo) && isset($ipBanInfo["time"]) && ($ipBanInfo["time"] === -1 || time() < $ipBanInfo["time"])) {
$event->setKickMessage($this->getMessage("ban_kick_message", [
"player" => $ipBanInfo["issuer"] ?? "Сервер",
"reason" => $ipBanInfo["reason"] ?? "Не указана",
"unban_time" => $ipBanInfo["time"] === -1 ? "Навсегда" : date("Y-m-d H:i", $ipBanInfo["time"])
]));
$event->cancel();
}
}
}
public function onPlayerChat(PlayerChatEvent $event): void {
$player = $event->getPlayer();
$name = strtolower($player->getName());
if ($this->muteData->exists("mutes.$name")) {
$muteInfo = $this->muteData->get("mutes.$name");
if (is_array($muteInfo) && isset($muteInfo["time"]) && ($muteInfo["time"] === -1 || time() < $muteInfo["time"])) {
$player->sendMessage($this->getMessage("mute_message", [
"player" => $muteInfo["issuer"] ?? "Сервер",
"reason" => $muteInfo["reason"] ?? "Не указана",
"unmute_time" => $muteInfo["time"] === -1 ? "Навсегда" : date("Y-m-d H:i", $muteInfo["time"])
]));
$event->cancel();
}
}
}
private function openBanUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "ban");
$maxTime = $limits["max_time"] ?? "∞";
$maxCount = $limits["max_count"] ?? "∞";
$banCount = $this->banData->getNested("counts." . strtolower($player->getName()) . ".ban_count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) return;
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$time = is_numeric($data[2] ?? "") ? (int)$data[2] : 0;
$reason = trim($data[3] ?? "");
$ipBan = $player->hasPermission("banmutekickui.ban.op") && ($data[4] ?? false);
$permBan = $player->hasPermission("banmutekickui.ban.op") && ($data[5] ?? false);
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if (empty($reason)) {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($time <= 0 && !$permBan) {
$player->sendMessage($this->getMessage("no_empty_time"));
return;
}
if ($permBan) $time = -1;
if ($this->checkBanLimits($player, $time)) {
$this->banPlayer($target, $time, $reason, $player, $ipBan);
} else {
$player->sendMessage($this->getMessage("ban_limit_exceeded"));
}
});
$form->setTitle("§c§lЗабанить игрока");
$form->addLabel("§eМакс. время: $maxTime мин. | Осталось: " . ($maxCount === "∞" ? "∞" : $maxCount - $banCount));
$form->addInput("Имя игрока", "Введите имя игрока");
$form->addInput("Время бана (в минутах)", "Введите время");
$form->addInput("Причина", "Введите причину");
if ($player->hasPermission("banmutekickui.ban.op")) {
$form->addToggle("Бан по IP", false);
$form->addToggle("Перманентный бан", false);
}
$player->sendForm($form);
}
private function openMuteUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "mute");
$maxTime = $limits["max_time"] ?? "∞";
$maxCount = $limits["max_count"] ?? "∞";
$muteCount = $this->muteData->getNested("counts." . strtolower($player->getName()) . ".mute_count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) return;
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$time = is_numeric($data[2] ?? "") ? (int)$data[2] : 0;
$reason = trim($data[3] ?? "");
$permMute = $player->hasPermission("banmutekickui.ban.op") && ($data[4] ?? false);
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if (empty($reason)) {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($time <= 0 && !$permMute) {
$player->sendMessage($this->getMessage("no_empty_time"));
return;
}
if ($permMute) $time = -1;
if ($this->checkMuteLimits($player, $time)) {
$this->mutePlayer($target, $time, $reason, $player);
} else {
$player->sendMessage($this->getMessage("mute_limit_exceeded"));
}
});
$form->setTitle("§c§lЗамутить игрока");
$form->addLabel("§eМакс. время: $maxTime мин. | Осталось: " . ($maxCount === "∞" ? "∞" : $maxCount - $muteCount));
$form->addInput("Имя игрока", "Введите имя игрока");
$form->addInput("Время мута (в минутах)", "Введите время");
$form->addInput("Причина", "Введите причину");
if ($player->hasPermission("banmutekickui.ban.op")) {
$form->addToggle("Перманентный мут", false);
}
$player->sendForm($form);
}
private function openKickUI(Player $player): void {
$limits = $this->getPlayerLimits($player, "kick");
$maxCount = $limits["max_count"] ?? "∞";
$kickCount = $this->banData->getNested("counts." . strtolower($player->getName()) . ".kick_count", 0);
$form = new CustomForm(function (Player $player, $data) {
if ($data === null) return;
if (empty($data[1])) {
$player->sendMessage($this->getMessage("no_empty_target"));
return;
}
$target = strtolower(trim($data[1]));
$reason = trim($data[2] ?? "");
if ($target === strtolower($player->getName())) {
$player->sendMessage($this->getMessage("no_self_punishment"));
return;
}
if (empty($reason)) {
$player->sendMessage($this->getMessage("no_empty_reason"));
return;
}
if ($this->checkKickLimits($player)) {
$result = $this->kickPlayer($target, $reason, $player);
if ($result === true) {
$this->getServer()->broadcastMessage($this->getMessage("player_kick", [
"player" => $player->getName(),
"target" => $target,
"reason" => $reason
]));
} elseif ($result === false) {
$player->sendMessage($this->getMessage("player_not_online", ["target" => $target]));
}
} else {
$player->sendMessage($this->getMessage("kick_limit_exceeded"));
}
});
$form->setTitle("§c§lКикнуть игрока");
$form->addLabel("§eОсталось попыток: " . ($maxCount === "∞" ? "∞" : $maxCount - $kickCount));
$form->addInput("Имя игрока", "Введите имя игрока");
$form->addInput("Причина", "Введите причину");
$player->sendForm($form);
}
private function getPlayerLimits(Player $player, string $type): array {
if ($player->hasPermission("banmutekickui.$type.op")) {
return ["max_time" => "∞", "max_count" => "∞"];
}
$config = $this->getConfig()->get($type, []);
foreach ($config as $perm => $limits) {
if ($player->hasPermission("banmutekickui.$type.$perm")) {
return $limits;
}
}
return ["max_time" => 0, "max_count" => 0];
}
private function checkBanLimits(Player $player, int $time): bool {
if ($player->hasPermission("banmutekickui.ban.op")) return true;
$limits = $this->getPlayerLimits($player, "ban");
$maxTime = $limits["max_time"] ?? 0;
$maxCount = $limits["max_count"] ?? 0;
$banCount = $this->banData->getNested("counts." . strtolower($player->getName()) . ".ban_count", 0);
return ($time === -1 || $time <= $maxTime) && $banCount < $maxCount;
}
private function checkMuteLimits(Player $player, int $time): bool {
if ($player->hasPermission("banmutekickui.ban.op")) return true;
$limits = $this->getPlayerLimits($player, "mute");
$maxTime = $limits["max_time"] ?? 0;
$maxCount = $limits["max_count"] ?? 0;
$muteCount = $this->muteData->getNested("counts." . strtolower($player->getName()) . ".mute_count", 0);
return ($time === -1 || $time <= $maxTime) && $muteCount < $maxCount;
}
private function checkKickLimits(?Player $player): bool {
if ($player === null || $player->hasPermission("banmutekickui.kick.op")) return true;
$limits = $this->getPlayerLimits($player, "kick");
$maxCount = $limits["max_count"] ?? 0;
$kickCount = $this->banData->getNested("counts." . strtolower($player->getName()) . ".kick_count", 0);
return $kickCount < $maxCount;
}
private function banPlayer(string $target, int $time, string $reason, Player $issuer, bool $ipBan): void {
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuer->getName()]));
return;
}
$banTime = $time === -1 ? -1 : time() + ($time * 60);
$issuerName = strtolower($issuer->getName());
$this->banData->set("bans.$target", [
"time" => $banTime,
"reason" => $reason,
"issuer" => $issuerName,
"ip_ban" => $ipBan
]);
$banCount = $this->banData->getNested("counts.$issuerName.ban_count", 0);
$this->banData->setNested("counts.$issuerName.ban_count", $banCount + 1);
$this->banData->save();
$unbanTime = $banTime === -1 ? "Навсегда" : date("Y-m-d H:i", $banTime);
if ($targetPlayer !== null) {
$targetPlayer->kick($this->getMessage("ban_kick_message", [
"player" => $issuerName,
"reason" => $reason,
"unban_time" => $unbanTime
]));
if ($ipBan) {
$ip = $targetPlayer->getNetworkSession()->getIp();
$this->banData->set("ip_bans.$ip", [
"time" => $banTime,
"reason" => $reason,
"issuer" => $issuerName
]);
$this->banData->save();
}
}
$this->getServer()->broadcastMessage($this->getMessage($ipBan ? "player_ip_ban" : "player_ban", [
"player" => $issuerName,
"target" => $target,
"reason" => $reason,
"unban_time" => $unbanTime
]));
}
private function mutePlayer(string $target, int $time, string $reason, Player $issuer): void {
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuer->getName()]));
return;
}
$muteTime = $time === -1 ? -1 : time() + ($time * 60);
$issuerName = strtolower($issuer->getName());
$this->muteData->set("mutes.$target", [
"time" => $muteTime,
"reason" => $reason,
"issuer" => $issuerName
]);
$muteCount = $this->muteData->getNested("counts.$issuerName.mute_count", 0);
$this->muteData->setNested("counts.$issuerName.mute_count", $muteCount + 1);
$this->muteData->save();
$unmuteTime = $muteTime === -1 ? "Навсегда" : date("Y-m-d H:i", $muteTime);
if ($targetPlayer !== null) {
$targetPlayer->sendMessage($this->getMessage("mute_message", [
"player" => $issuerName,
"reason" => $reason,
"unmute_time" => $unmuteTime
]));
}
$this->getServer()->broadcastMessage($this->getMessage("player_mute", [
"player" => $issuerName,
"target" => $target,
"reason" => $reason,
"unmute_time" => $unmuteTime
]));
}
private function kickPlayer(string $target, string $reason, CommandSender $issuer): ?bool {
$targetPlayer = $this->getServer()->getPlayerExact($target);
if ($targetPlayer instanceof Player && $targetPlayer->hasPermission("nobad")) {
if ($issuer instanceof Player) {
$issuer->sendMessage($this->getMessage("player_no_bad"));
$targetPlayer->sendMessage($this->getMessage("player_givenot_bad", ["player" => $issuer->getName()]));
}
return null;
}
$issuerName = strtolower($issuer->getName());
$kickCount = $this->banData->getNested("counts.$issuerName.kick_count", 0);
$this->banData->setNested("counts.$issuerName.kick_count", $kickCount + 1);
$this->banData->save();
if ($targetPlayer instanceof Player && $targetPlayer->isOnline()) {
$targetPlayer->kick($this->getMessage("kick_message", [
"player" => $issuerName,
"reason" => $reason
]));
return true;
}
return false;
}
private function resetLimitsIfNeeded(): void {
$resetInterval = $this->getConfig()->get("reset_interval", 86400);
$currentTime = time();
$lastReset = $this->resetData->get("last_reset", $currentTime);
if ($currentTime - $lastReset < $resetInterval) return;
foreach ($this->banData->get("counts", []) as $name => $counts) {
$this->banData->setNested("counts.$name.ban_count", 0);
$this->banData->setNested("counts.$name.kick_count", 0);
}
$this->banData->save();
foreach ($this->muteData->get("counts", []) as $name => $counts) {
$this->muteData->setNested("counts.$name.mute_count", 0);
}
$this->muteData->save();
$this->resetData->set("last_reset", $currentTime);
$this->resetData->save();
foreach ($this->getServer()->getOnlinePlayers() as $player) {
$name = strtolower($player->getName());
if ($this->banData->exists("counts.$name") || $this->muteData->exists("counts.$name")) {
$player->sendMessage($this->getMessage("limits_reset"));
}
}
$this->getLogger()->info("Лимиты наказаний сброшены.");
}
private function cleanupExpiredPunishments(): void {
$currentTime = time();
foreach ($this->banData->get("bans", []) as $name => $banInfo) {
if (is_array($banInfo) && $banInfo["time"] !== -1 && $currentTime >= $banInfo["time"]) {
$this->banData->remove("bans.$name");
}
}
foreach ($this->banData->get("ip_bans", []) as $ip => $ipBanInfo) {
if (is_array($ipBanInfo) && $ipBanInfo["time"] !== -1 && $currentTime >= $ipBanInfo["time"]) {
$this->banData->remove("ip_bans.$ip");
}
}
$this->banData->save();
foreach ($this->muteData->get("mutes", []) as $name => $muteInfo) {
if (is_array($muteInfo) && $muteInfo["time"] !== -1 && $currentTime >= $muteInfo["time"]) {
$this->muteData->remove("mutes.$name");
}
}
$this->muteData->save();
}
}
UnbanHandler.php :
<?php
namespace BanMuteKickUI;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\command\CommandExecutor;
use pocketmine\utils\Config;
class UnbanHandler implements CommandExecutor {
private Main $plugin;
private Config $banData;
private Config $muteData;
private Config $messages;
public function __construct(Main $plugin, Config $banData, Config $muteData, Config $messages) {
$this->plugin = $plugin;
$this->banData = $banData;
$this->muteData = $muteData;
$this->messages = $messages;
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
$cmd = $command->getName();
if (!isset($args[0])) {
$sender->sendMessage("Usage: /$cmd <игрок>");
return true;
}
$target = strtolower($args[0]);
$placeholders = ["player" => $sender->getName(), "target" => $target];
if ($cmd === "munban") {
if ($this->banData->exists("bans.$target")) {
$this->banData->remove("bans.$target");
$this->banData->save();
$this->plugin->getServer()->broadcastMessage($this->plugin->getMessage("player_unbanned", $placeholders));
} else {
$sender->sendMessage($this->plugin->getMessage("player_not_banned", $placeholders));
}
} elseif ($cmd === "munmute") {
if ($this->muteData->exists("mutes.$target")) {
$this->muteData->remove("mutes.$target");
$this->muteData->save();
$this->plugin->getServer()->broadcastMessage($this->plugin->getMessage("player_unmuted", $placeholders));
} else {
$sender->sendMessage($this->plugin->getMessage("player_not_muted", $placeholders));
}
}
return true;
}
}
config.yml :
ban:
level1:
max_time: 60
max_count: 5
mute:
level1:
max_time: 30
max_count: 3
kick:
level1:
max_count: 10
reset_interval: 86400
UPD: Все равно х##ню выдал
фигня было, фигнёй осталось
застрели меня
Это ■■■■■■…
Он не разбирается с этим. Тебе может помочь @Koshak_Mine, еще @vezdehod разбирается
Да нет, не соло. При изучении любого языка, всегда стакливаешься с принципом KISS. И он здесь оправдан.
Цель не только выполнить задачу с максимальным сахаром php, а так -, чтобы это было ясно и понятно читать.
А чтобы узнать это, тебе либо нужно всегда держать что возвращает getcommand, либо обращаться к документации (если повезёт то у тебя подвязана IDE конечно проще)
Но в целом явное указание на логику работы в разы лучше, чем сахар.
Далбаеба в семье найдёшь кто тебя родил. Хотя ты максимум мог появится из протухшего говна, а не капусты.
Извините за мою грубость, просто таким людям надо лишь так отвечать)
Да нет, не соло. При изучении любого языка, всегда стакливаешься с принципом KISS. И он здесь оправдан.
Цель не только выполнить задачу с максимальным сахаром php, а так -, чтобы это было ясно и понятно читать.
Ну тогда $command !== null
или !is_null
норм промт сделай