93 private array $uniqueCommands = [];
97 public function __construct(
private Server $server){
99 $this->setDefaultCommands();
102 private function setDefaultCommands() :
void{
103 $pmPrefix =
"pocketmine";
104 $this->
register(
new BanCommand($pmPrefix,
"ban"));
110 $this->
register(
new DeopCommand($pmPrefix,
"deop"));
117 $this->
register(
new GiveCommand($pmPrefix,
"give"));
118 $this->
register(
new HelpCommand($pmPrefix,
"help"), [
"?"]);
119 $this->
register(
new KickCommand($pmPrefix,
"kick"));
120 $this->
register(
new KillCommand($pmPrefix,
"kill"), [
"suicide"]);
121 $this->
register(
new ListCommand($pmPrefix,
"list"));
122 $this->
register(
new MeCommand($pmPrefix,
"me"));
123 $this->
register(
new OpCommand($pmPrefix,
"op"));
124 $this->
register(
new PardonCommand($pmPrefix,
"pardon"), [
"unban"]);
125 $this->
register(
new PardonIpCommand($pmPrefix,
"pardon-ip"), [
"unban-ip"]);
127 $this->
register(
new PluginsCommand($pmPrefix,
"plugins"), [
"pl"]);
128 $this->
register(
new SaveCommand($pmPrefix,
"save-all"));
131 $this->
register(
new SayCommand($pmPrefix,
"say"));
132 $this->
register(
new SeedCommand($pmPrefix,
"seed"));
136 $this->
register(
new StopCommand($pmPrefix,
"stop"));
138 $this->
register(
new TellCommand($pmPrefix,
"tell"), [
"w",
"msg"]);
139 $this->
register(
new TimeCommand($pmPrefix,
"time"));
143 $this->
register(
new VersionCommand($pmPrefix,
"version"), [
"ver",
"about"]);
145 $this->
register(
new XpCommand($pmPrefix,
"xp"));
148 public function register(
Command $command, array $otherAliases = []) : void{
149 if(count($command->getPermissions()) === 0){
150 throw new \InvalidArgumentException(
"Commands must have a permission set");
153 $commandId = $command->getId();
154 if(isset($this->uniqueCommands[$commandId])){
155 throw new \InvalidArgumentException(
"A command with ID $commandId has already been registered");
158 $preferredAlias = trim($command->getName());
159 $this->aliasMap->bindAlias($commandId, $preferredAlias,
override:
false);
160 foreach($otherAliases as $alias){
161 $this->aliasMap->bindAlias($commandId, $alias,
override:
false);
164 $this->uniqueCommands[$commandId] = $command;
167 public function unregister(Command $command) : bool{
168 unset($this->uniqueCommands[$command->getId()]);
169 $this->aliasMap->unbindAliasesForCommand($command->getId());
174 public function dispatch(CommandSender $sender,
string $commandLine) : bool{
175 $args = CommandStringHelper::parseQuoteAware($commandLine);
177 $sentCommandLabel = array_shift($args);
178 if($sentCommandLabel !==
null && ($target = $this->getCommand($sentCommandLabel, $sender->getCommandAliasMap())) !==
null){
179 if(is_array($target)){
180 self::handleConflicted($sender, $sentCommandLabel, $target, $this->aliasMap);
183 $timings = Timings::getCommandDispatchTimings($target->getId());
184 $timings->startTiming();
187 if($target->testPermission($sentCommandLabel, $sender)){
188 $target->execute($sender, $sentCommandLabel, $args);
190 }
catch(InvalidCommandSyntaxException $e){
192 $sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage() ??
"/$sentCommandLabel")));
194 $timings->stopTiming();
200 $sender->sendMessage(KnownTranslationFactory::pocketmine_command_notFound(
201 $sentCommandLabel ??
"",
202 "/" . $sender->getCommandAliasMap()->getPreferredAlias(
"pocketmine:help", $this->aliasMap)
203 )->prefix(TextFormat::RED));
216 foreach($conflictedEntries as $c){
217 if($c->testPermissionSilent($sender)){
218 $candidates[] =
"/" . $c->getId();
221 if(count($candidates) > 0){
225 $candidateNames = implode(
", ", $candidates);
226 $sender->sendMessage(KnownTranslationFactory::pocketmine_command_error_aliasConflict(
"/$alias", $candidateNames)->prefix(TextFormat::RED));
228 $sender->sendMessage(KnownTranslationFactory::pocketmine_command_error_aliasConflictTip(
229 "/" . $userAliasMap->getPreferredAlias(
"pocketmine:cmdalias", $fallbackAliasMap)
230 )->prefix(TextFormat::RED));
232 $sender->sendMessage(KnownTranslationFactory::pocketmine_command_error_permission($alias)->prefix(TextFormat::RED));
236 public function clearCommands() : void{
237 $this->aliasMap = new CommandAliasMap();
238 $this->uniqueCommands = [];
239 $this->setDefaultCommands();
243 if(isset($this->uniqueCommands[$name])){
244 return $this->uniqueCommands[$name];
246 $commandId = $senderAliasMap?->resolveAlias($name) ?? $this->aliasMap->resolveAlias($name);
247 if(is_string($commandId)){
248 return $this->uniqueCommands[$commandId] ??
null;
250 if(is_array($commandId)){
256 return array_filter(array_map(
257 fn(
string $c) => $this->uniqueCommands[$c] ??
null,
269 return $this->uniqueCommands;
272 public function registerServerAliases() : void{
273 $values = $this->
server->getCommandAliases();
275 foreach(Utils::stringifyKeys($values) as $alias => $commandStrings){
276 if(str_contains($alias,
":")){
277 $this->
server->getLogger()->warning($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_command_alias_illegal($alias)));
285 foreach($commandStrings as $commandString){
286 $args = CommandStringHelper::parseQuoteAware($commandString);
287 $commandName = array_shift($args) ??
"";
288 $command = $this->getCommand($commandName);
290 if(!$command instanceof
Command){
291 $bad[] = $commandString;
292 }elseif(strcasecmp($commandName, $alias) === 0){
293 $recursive[] = $commandString;
295 $targets[] = $commandString;
299 if(count($recursive) > 0){
300 $this->
server->getLogger()->warning($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_command_alias_recursive($alias, implode(
", ", $recursive))));
305 $this->
server->getLogger()->warning($this->
server->getLanguage()->translate(KnownTranslationFactory::pocketmine_command_alias_notFound($alias, implode(
", ", $bad))));
310 $lowerAlias = strtolower($alias);
311 if(count($targets) > 0){
312 $aliasInstance =
new FormattedCommandAlias(
"pocketmine-config-defined", $lowerAlias, $targets);
313 $this->aliasMap->bindAlias($aliasInstance->getId(), $lowerAlias,
override:
true);
314 $this->uniqueCommands[$aliasInstance->getId()] = $aliasInstance;
317 $this->aliasMap->unbindAlias($lowerAlias);