2022-01-16 21:09:53 +00:00
/ *
* Copyright ( c ) 2019 - 2022 GeyserMC . http : //geysermc.org
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
* /
package org.geysermc.geyser.command ;
2022-07-11 00:58:48 +00:00
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap ;
2022-01-16 21:09:53 +00:00
import lombok.Getter ;
import lombok.RequiredArgsConstructor ;
import org.checkerframework.checker.nullness.qual.NonNull ;
2023-12-05 23:54:42 +00:00
import org.checkerframework.checker.nullness.qual.Nullable ;
2023-06-17 01:56:50 +00:00
import org.geysermc.geyser.api.util.PlatformType ;
2022-01-16 21:09:53 +00:00
import org.geysermc.geyser.GeyserImpl ;
import org.geysermc.geyser.api.command.Command ;
import org.geysermc.geyser.api.command.CommandExecutor ;
import org.geysermc.geyser.api.command.CommandSource ;
2022-09-04 18:08:17 +00:00
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent ;
import org.geysermc.geyser.api.extension.Extension ;
import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand ;
import org.geysermc.geyser.command.defaults.AdvancementsCommand ;
import org.geysermc.geyser.command.defaults.ConnectionTestCommand ;
import org.geysermc.geyser.command.defaults.DumpCommand ;
import org.geysermc.geyser.command.defaults.ExtensionsCommand ;
import org.geysermc.geyser.command.defaults.HelpCommand ;
import org.geysermc.geyser.command.defaults.ListCommand ;
import org.geysermc.geyser.command.defaults.OffhandCommand ;
2023-09-18 13:31:39 +00:00
import org.geysermc.geyser.command.defaults.PingCommand ;
2022-09-04 18:08:17 +00:00
import org.geysermc.geyser.command.defaults.ReloadCommand ;
import org.geysermc.geyser.command.defaults.SettingsCommand ;
import org.geysermc.geyser.command.defaults.StatisticsCommand ;
import org.geysermc.geyser.command.defaults.StopCommand ;
import org.geysermc.geyser.command.defaults.VersionCommand ;
import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl ;
import org.geysermc.geyser.extension.command.GeyserExtensionCommand ;
2022-01-16 21:09:53 +00:00
import org.geysermc.geyser.session.GeyserSession ;
import org.geysermc.geyser.text.GeyserLocale ;
2022-06-08 12:09:14 +00:00
import java.util.Collections ;
2022-09-04 18:08:17 +00:00
import java.util.HashMap ;
2022-06-08 12:09:14 +00:00
import java.util.List ;
2022-07-11 00:58:48 +00:00
import java.util.Locale ;
2022-06-08 12:09:14 +00:00
import java.util.Map ;
2022-01-16 21:09:53 +00:00
@RequiredArgsConstructor
2022-10-18 20:05:55 +00:00
public class GeyserCommandManager {
2022-01-16 21:09:53 +00:00
@Getter
2023-09-18 13:31:39 +00:00
private final Map < String , Command > commands = new Object2ObjectOpenHashMap < > ( 13 ) ;
2022-09-04 18:08:17 +00:00
private final Map < Extension , Map < String , Command > > extensionCommands = new Object2ObjectOpenHashMap < > ( 0 ) ;
2022-01-16 21:09:53 +00:00
private final GeyserImpl geyser ;
public void init ( ) {
2022-09-04 18:08:17 +00:00
registerBuiltInCommand ( new HelpCommand ( geyser , " help " , " geyser.commands.help.desc " , " geyser.command.help " , " geyser " , this . commands ) ) ;
2022-07-11 00:58:48 +00:00
registerBuiltInCommand ( new ListCommand ( geyser , " list " , " geyser.commands.list.desc " , " geyser.command.list " ) ) ;
registerBuiltInCommand ( new ReloadCommand ( geyser , " reload " , " geyser.commands.reload.desc " , " geyser.command.reload " ) ) ;
registerBuiltInCommand ( new OffhandCommand ( geyser , " offhand " , " geyser.commands.offhand.desc " , " geyser.command.offhand " ) ) ;
registerBuiltInCommand ( new DumpCommand ( geyser , " dump " , " geyser.commands.dump.desc " , " geyser.command.dump " ) ) ;
registerBuiltInCommand ( new VersionCommand ( geyser , " version " , " geyser.commands.version.desc " , " geyser.command.version " ) ) ;
registerBuiltInCommand ( new SettingsCommand ( geyser , " settings " , " geyser.commands.settings.desc " , " geyser.command.settings " ) ) ;
registerBuiltInCommand ( new StatisticsCommand ( geyser , " statistics " , " geyser.commands.statistics.desc " , " geyser.command.statistics " ) ) ;
registerBuiltInCommand ( new AdvancementsCommand ( " advancements " , " geyser.commands.advancements.desc " , " geyser.command.advancements " ) ) ;
registerBuiltInCommand ( new AdvancedTooltipsCommand ( " tooltips " , " geyser.commands.advancedtooltips.desc " , " geyser.command.tooltips " ) ) ;
2022-08-02 04:25:07 +00:00
registerBuiltInCommand ( new ConnectionTestCommand ( geyser , " connectiontest " , " geyser.commands.connectiontest.desc " , " geyser.command.connectiontest " ) ) ;
2023-09-18 13:31:39 +00:00
registerBuiltInCommand ( new PingCommand ( " ping " , " geyser.commands.ping.desc " , " geyser.command.ping " ) ) ;
2022-09-04 18:08:17 +00:00
if ( this . geyser . getPlatformType ( ) = = PlatformType . STANDALONE ) {
2022-07-11 00:58:48 +00:00
registerBuiltInCommand ( new StopCommand ( geyser , " stop " , " geyser.commands.stop.desc " , " geyser.command.stop " ) ) ;
2022-01-16 21:09:53 +00:00
}
2024-02-14 11:50:50 +00:00
if ( ! this . geyser . extensionManager ( ) . extensions ( ) . isEmpty ( ) ) {
2022-09-04 18:08:17 +00:00
registerBuiltInCommand ( new ExtensionsCommand ( this . geyser , " extensions " , " geyser.commands.extensions.desc " , " geyser.command.extensions " ) ) ;
}
GeyserDefineCommandsEvent defineCommandsEvent = new GeyserDefineCommandsEventImpl ( this . commands ) {
@Override
public void register ( @NonNull Command command ) {
if ( ! ( command instanceof GeyserExtensionCommand extensionCommand ) ) {
throw new IllegalArgumentException ( " Expected GeyserExtensionCommand as part of command registration but got " + command + " ! Did you use the Command builder properly? " ) ;
}
registerExtensionCommand ( extensionCommand . extension ( ) , extensionCommand ) ;
}
} ;
this . geyser . eventBus ( ) . fire ( defineCommandsEvent ) ;
// Register help commands for all extensions with commands
for ( Map . Entry < Extension , Map < String , Command > > entry : this . extensionCommands . entrySet ( ) ) {
2023-08-27 12:48:14 +00:00
String id = entry . getKey ( ) . description ( ) . id ( ) ;
registerExtensionCommand ( entry . getKey ( ) , new HelpCommand ( this . geyser , " help " , " geyser.commands.exthelp.desc " , " geyser.command.exthelp. " + id , id , entry . getValue ( ) ) ) ;
2022-09-04 18:08:17 +00:00
}
2022-07-11 00:58:48 +00:00
}
/ * *
* For internal Geyser commands
* /
public void registerBuiltInCommand ( GeyserCommand command ) {
register ( command , this . commands ) ;
2022-01-16 21:09:53 +00:00
}
2022-09-04 18:08:17 +00:00
public void registerExtensionCommand ( @NonNull Extension extension , @NonNull Command command ) {
register ( command , this . extensionCommands . computeIfAbsent ( extension , e - > new HashMap < > ( ) ) ) ;
2022-07-11 00:58:48 +00:00
}
private void register ( Command command , Map < String , Command > commands ) {
commands . put ( command . name ( ) , command ) ;
geyser . getLogger ( ) . debug ( GeyserLocale . getLocaleStringLog ( " geyser.commands.registered " , command . name ( ) ) ) ;
2022-01-16 21:09:53 +00:00
if ( command . aliases ( ) . isEmpty ( ) ) {
return ;
}
for ( String alias : command . aliases ( ) ) {
2022-07-11 00:58:48 +00:00
commands . put ( alias , command ) ;
2022-01-16 21:09:53 +00:00
}
}
2023-12-05 23:54:42 +00:00
@NonNull
2022-09-04 18:08:17 +00:00
public Map < String , Command > commands ( ) {
return Collections . unmodifiableMap ( this . commands ) ;
2022-01-16 21:09:53 +00:00
}
2023-12-05 23:54:42 +00:00
@NonNull
2022-09-04 18:08:17 +00:00
public Map < Extension , Map < String , Command > > extensionCommands ( ) {
2022-07-11 00:58:48 +00:00
return Collections . unmodifiableMap ( this . extensionCommands ) ;
2022-01-16 21:09:53 +00:00
}
2022-07-11 00:58:48 +00:00
public boolean runCommand ( GeyserCommandSource sender , String command ) {
2022-09-04 18:08:17 +00:00
Extension extension = null ;
for ( Extension loopedExtension : this . extensionCommands . keySet ( ) ) {
if ( command . startsWith ( loopedExtension . description ( ) . id ( ) + " " ) ) {
extension = loopedExtension ;
break ;
}
}
if ( ! command . startsWith ( " geyser " ) & & extension = = null ) {
2022-07-11 00:58:48 +00:00
return false ;
}
2022-01-16 21:09:53 +00:00
2022-09-04 18:08:17 +00:00
command = command . trim ( ) . replace ( extension ! = null ? extension . description ( ) . id ( ) + " " : " geyser " , " " ) ;
2022-01-16 21:09:53 +00:00
String label ;
String [ ] args ;
if ( ! command . contains ( " " ) ) {
2022-07-11 00:58:48 +00:00
label = command . toLowerCase ( Locale . ROOT ) ;
2022-01-16 21:09:53 +00:00
args = new String [ 0 ] ;
} else {
2022-07-11 00:58:48 +00:00
label = command . substring ( 0 , command . indexOf ( " " ) ) . toLowerCase ( Locale . ROOT ) ;
2022-01-16 21:09:53 +00:00
String argLine = command . substring ( command . indexOf ( " " ) + 1 ) ;
args = argLine . contains ( " " ) ? argLine . split ( " " ) : new String [ ] { argLine } ;
}
2022-09-04 18:08:17 +00:00
Command cmd = ( extension ! = null ? this . extensionCommands . getOrDefault ( extension , Collections . emptyMap ( ) ) : this . commands ) . get ( label ) ;
2022-01-16 21:09:53 +00:00
if ( cmd = = null ) {
2022-09-04 18:08:17 +00:00
sender . sendMessage ( GeyserLocale . getLocaleStringLog ( " geyser.commands.invalid " ) ) ;
2022-07-11 00:58:48 +00:00
return false ;
2022-01-16 21:09:53 +00:00
}
if ( cmd instanceof GeyserCommand ) {
if ( sender instanceof GeyserSession ) {
( ( GeyserCommand ) cmd ) . execute ( ( GeyserSession ) sender , sender , args ) ;
} else {
if ( ! cmd . isBedrockOnly ( ) ) {
( ( GeyserCommand ) cmd ) . execute ( null , sender , args ) ;
} else {
geyser . getLogger ( ) . error ( GeyserLocale . getLocaleStringLog ( " geyser.bootstrap.command.bedrock_only " ) ) ;
}
}
}
2022-07-11 00:58:48 +00:00
return true ;
2022-01-16 21:09:53 +00:00
}
/ * *
* Returns the description of the given command
*
* @param command Command to get the description for
* @return Command description
* /
2022-10-18 20:05:55 +00:00
public String description ( String command ) {
return " " ;
}
2022-01-16 21:09:53 +00:00
@RequiredArgsConstructor
public static class CommandBuilder < T extends CommandSource > implements Command . Builder < T > {
2022-09-04 18:08:17 +00:00
private final Extension extension ;
private Class < ? extends T > sourceType ;
2022-01-16 21:09:53 +00:00
private String name ;
private String description = " " ;
private String permission = " " ;
private List < String > aliases ;
2022-06-08 12:09:14 +00:00
private boolean suggestedOpOnly = false ;
2022-01-16 21:09:53 +00:00
private boolean executableOnConsole = true ;
private List < String > subCommands ;
private boolean bedrockOnly ;
private CommandExecutor < T > executor ;
2022-09-04 18:08:17 +00:00
@Override
public Command . Builder < T > source ( @NonNull Class < ? extends T > sourceType ) {
this . sourceType = sourceType ;
return this ;
}
public CommandBuilder < T > name ( @NonNull String name ) {
2022-01-16 21:09:53 +00:00
this . name = name ;
return this ;
}
2022-09-04 18:08:17 +00:00
public CommandBuilder < T > description ( @NonNull String description ) {
2022-01-16 21:09:53 +00:00
this . description = description ;
return this ;
}
2022-09-04 18:08:17 +00:00
public CommandBuilder < T > permission ( @NonNull String permission ) {
2022-01-16 21:09:53 +00:00
this . permission = permission ;
return this ;
}
2022-09-04 18:08:17 +00:00
public CommandBuilder < T > aliases ( @NonNull List < String > aliases ) {
2022-01-16 21:09:53 +00:00
this . aliases = aliases ;
return this ;
}
2022-06-08 12:09:14 +00:00
@Override
public Command . Builder < T > suggestedOpOnly ( boolean suggestedOpOnly ) {
this . suggestedOpOnly = suggestedOpOnly ;
return this ;
}
2022-01-16 21:09:53 +00:00
public CommandBuilder < T > executableOnConsole ( boolean executableOnConsole ) {
this . executableOnConsole = executableOnConsole ;
return this ;
}
2022-09-04 18:08:17 +00:00
public CommandBuilder < T > subCommands ( @NonNull List < String > subCommands ) {
2022-01-16 21:09:53 +00:00
this . subCommands = subCommands ;
return this ;
}
public CommandBuilder < T > bedrockOnly ( boolean bedrockOnly ) {
this . bedrockOnly = bedrockOnly ;
return this ;
}
2022-09-04 18:08:17 +00:00
public CommandBuilder < T > executor ( @NonNull CommandExecutor < T > executor ) {
2022-01-16 21:09:53 +00:00
this . executor = executor ;
return this ;
}
2022-09-04 18:08:17 +00:00
@NonNull
public GeyserExtensionCommand build ( ) {
2022-01-16 21:09:53 +00:00
if ( this . name = = null | | this . name . isBlank ( ) ) {
throw new IllegalArgumentException ( " Command cannot be null or blank! " ) ;
}
2022-09-04 18:08:17 +00:00
if ( this . sourceType = = null ) {
throw new IllegalArgumentException ( " Source type was not defined for command " + this . name + " in extension " + this . extension . name ( ) ) ;
}
return new GeyserExtensionCommand ( this . extension , this . name , this . description , this . permission ) {
2022-01-16 21:09:53 +00:00
@SuppressWarnings ( " unchecked " )
@Override
public void execute ( @Nullable GeyserSession session , GeyserCommandSource sender , String [ ] args ) {
2022-09-04 18:08:17 +00:00
Class < ? extends T > sourceType = CommandBuilder . this . sourceType ;
2022-01-16 21:09:53 +00:00
CommandExecutor < T > executor = CommandBuilder . this . executor ;
if ( sourceType . isInstance ( session ) ) {
executor . execute ( ( T ) session , this , args ) ;
return ;
}
if ( sourceType . isInstance ( sender ) ) {
executor . execute ( ( T ) sender , this , args ) ;
return ;
}
GeyserImpl . getInstance ( ) . getLogger ( ) . debug ( " Ignoring command " + this . name + " due to no suitable sender. " ) ;
}
@NonNull
@Override
public List < String > aliases ( ) {
return CommandBuilder . this . aliases = = null ? Collections . emptyList ( ) : CommandBuilder . this . aliases ;
}
2022-06-08 12:09:14 +00:00
@Override
public boolean isSuggestedOpOnly ( ) {
return CommandBuilder . this . suggestedOpOnly ;
}
2022-01-16 21:09:53 +00:00
@NonNull
@Override
public List < String > subCommands ( ) {
return CommandBuilder . this . subCommands = = null ? Collections . emptyList ( ) : CommandBuilder . this . subCommands ;
}
@Override
public boolean isBedrockOnly ( ) {
return CommandBuilder . this . bedrockOnly ;
}
@Override
public boolean isExecutableOnConsole ( ) {
return CommandBuilder . this . executableOnConsole ;
}
} ;
}
}
}