Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
579aecf
First step in restructuring command alias handling
dktapps May 4, 2025
084774e
Don't allow registering the same command instance twice
dktapps May 4, 2025
7eff658
Add ability to register & unregister specific command aliases for exi…
dktapps May 4, 2025
91dad0a
Merge branch 'major-next' into command-alias-handling
dktapps May 4, 2025
8035d66
Merge branch 'major-next' into command-alias-handling
dktapps May 4, 2025
bc54380
CS
dktapps May 4, 2025
de15737
Merge branch 'major-next' into command-alias-handling
dktapps May 24, 2025
9a7d94c
Merge branch 'major-next' into command-alias-handling
dktapps Aug 3, 2025
743e6c8
Merge branch 'major-next' into command-alias-handling
dktapps Oct 4, 2025
9e93c40
Don't register prefixed non-primary aliases
dktapps Oct 4, 2025
02712d0
Revert changes to command name
dktapps Oct 5, 2025
b4c5576
Make alias conflicts more sane
dktapps Oct 8, 2025
7eeb436
Fix PHPStan
dktapps Oct 8, 2025
a8b6a42
Fixed PluginCommand usage messages
dktapps Oct 8, 2025
bdb962b
First look at user-local alias maps and /cmdalias
dktapps Oct 8, 2025
5510e62
Suppress error
dktapps Oct 8, 2025
5ac6f01
Merge branch 'major-next' into command-alias-handling
dktapps Oct 8, 2025
1ba86fc
Put namespace inside Command
dktapps Oct 8, 2025
846bd99
Tidy namespace & name handling & validation
dktapps Oct 8, 2025
84af5df
Merge branch 'major-next' into command-alias-handling
dktapps Oct 10, 2025
5bbd179
UX improvements & localisations
dktapps Oct 10, 2025
c41f316
stfu
dktapps Oct 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,8 @@ public function getConfigGroup() : ServerConfigGroup{
* @phpstan-return (Command&PluginOwned)|null
*/
public function getPluginCommand(string $name){
if(($command = $this->commandMap->getCommand($name)) instanceof PluginOwned){
return $command;
}else{
return null;
}
$command = $this->commandMap->getCommand($name);
return $command instanceof PluginOwned ? $command : null;
}

public function getNameBans() : BanList{
Expand Down
4 changes: 2 additions & 2 deletions src/command/ClosureCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ final class ClosureCommand extends Command{
* @phpstan-param Execute $execute
*/
public function __construct(
string $namespace,
string $name,
\Closure $execute,
array $permissions,
Translatable|string $description = "",
Translatable|string|null $usageMessage = null,
array $aliases = []
){
Utils::validateCallableSignature(
fn(CommandSender $sender, Command $command, string $commandLabel, array $args) : mixed => 1,
$execute,
);
$this->execute = $execute;
parent::__construct($name, $description, $usageMessage, $aliases);
parent::__construct($namespace, $name, $description, $usageMessage);
$this->setPermissions($permissions);
}

Expand Down
144 changes: 31 additions & 113 deletions src/command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,52 +33,22 @@
use pocketmine\Server;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\TextFormat;
use function array_values;
use function explode;
use function implode;
use function str_replace;
use const PHP_INT_MAX;

abstract class Command{

private string $name;

private string $nextLabel;
private string $label;

/**
* @var string[]
* @phpstan-var list<string>
*/
private array $aliases = [];

/**
* @var string[]
* @phpstan-var list<string>
*/
private array $activeAliases = [];

private ?CommandMap $commandMap = null;

protected Translatable|string $description = "";

protected Translatable|string $usageMessage;

/** @var string[] */
private array $permission = [];
private Translatable|string|null $permissionMessage = null;

/**
* @param string[] $aliases
* @phpstan-param list<string> $aliases
*/
public function __construct(string $name, Translatable|string $description = "", Translatable|string|null $usageMessage = null, array $aliases = []){
$this->name = $name;
$this->setLabel($name);
$this->setDescription($description);
$this->usageMessage = $usageMessage ?? ("/" . $name);
$this->setAliases($aliases);
}
public function __construct(
private string $namespace,
private string $name,
private Translatable|string $description = "",
private Translatable|string|null $usageMessage = null
){}

/**
* @param string[] $args
Expand All @@ -89,10 +59,25 @@ public function __construct(string $name, Translatable|string $description = "",
*/
abstract public function execute(CommandSender $sender, string $commandLabel, array $args);

public function getName() : string{
final public function getNamespace() : string{
return $this->namespace;
}

/**
* Returns the local identifier of the command (without namespace or leading slash).
* This cannot be changed after creation.
*/
final public function getName() : string{
return $this->name;
}

/**
* Returns the globally unique ID for the command. This typically looks like namespace:name
*/
final public function getId() : string{
return "$this->namespace:$this->name";
}

/**
* @return string[]
*/
Expand All @@ -117,12 +102,17 @@ public function setPermission(?string $permission) : void{
$this->setPermissions($permission === null ? [] : explode(";", $permission, limit: PHP_INT_MAX));
}

public function testPermission(CommandSender $target, ?string $permission = null) : bool{
/**
* @param string $context usually the command name, but may include extra args if useful (e.g. for subcommands)
* @param CommandSender $target the target to check the permission for
* @param string|null $permission the permission to check, if null, will check if the target has any of the command's permissions
*/
public function testPermission(string $context, CommandSender $target, ?string $permission = null) : bool{
if($this->testPermissionSilent($target, $permission)){
return true;
}

$message = $this->permissionMessage ?? KnownTranslationFactory::pocketmine_command_error_permission($this->name);
$message = $this->permissionMessage ?? KnownTranslationFactory::pocketmine_command_error_permission($context);
if($message instanceof Translatable){
$target->sendMessage($message->prefix(TextFormat::RED));
}elseif($message !== ""){
Expand All @@ -143,62 +133,6 @@ public function testPermissionSilent(CommandSender $target, ?string $permission
return false;
}

public function getLabel() : string{
return $this->label;
}

public function setLabel(string $name) : bool{
$this->nextLabel = $name;
if(!$this->isRegistered()){
$this->label = $name;

return true;
}

return false;
}

/**
* Registers the command into a Command map
*/
public function register(CommandMap $commandMap) : bool{
if($this->allowChangesFrom($commandMap)){
$this->commandMap = $commandMap;

return true;
}

return false;
}

public function unregister(CommandMap $commandMap) : bool{
if($this->allowChangesFrom($commandMap)){
$this->commandMap = null;
$this->activeAliases = $this->aliases;
$this->label = $this->nextLabel;

return true;
}

return false;
}

private function allowChangesFrom(CommandMap $commandMap) : bool{
return $this->commandMap === null || $this->commandMap === $commandMap;
}

public function isRegistered() : bool{
return $this->commandMap !== null;
}

/**
* @return string[]
* @phpstan-return list<string>
*/
public function getAliases() : array{
return $this->activeAliases;
}

public function getPermissionMessage() : Translatable|string|null{
return $this->permissionMessage;
}
Expand All @@ -207,22 +141,10 @@ public function getDescription() : Translatable|string{
return $this->description;
}

public function getUsage() : Translatable|string{
public function getUsage() : Translatable|string|null{
return $this->usageMessage;
}

/**
* @param string[] $aliases
* @phpstan-param list<string> $aliases
*/
public function setAliases(array $aliases) : void{
$aliases = array_values($aliases); //because plugins can and will pass crap
$this->aliases = $aliases;
if(!$this->isRegistered()){
$this->activeAliases = $aliases;
}
}

public function setDescription(Translatable|string $description) : void{
$this->description = $description;
}
Expand All @@ -231,7 +153,7 @@ public function setPermissionMessage(Translatable|string $permissionMessage) : v
$this->permissionMessage = $permissionMessage;
}

public function setUsage(Translatable|string $usage) : void{
public function setUsage(Translatable|string|null $usage) : void{
$this->usageMessage = $usage;
}

Expand All @@ -252,8 +174,4 @@ public static function broadcastCommandMessage(CommandSender $source, Translatab
}
}
}

public function __toString() : string{
return $this->name;
}
}
Loading