Introduction
While most modding is about changing game play, sometimes you want to give the player more power -- give them commands that allow them to "cheat".
In this tutorial I explain how create a custom command.
I use the example of a "conjure" command that acts like summon but for my custom entities.
The built in /summon command can call custom entities by pre-pending the mod id before the name of the entity, such as /summon wildanimals.Elephant.
However, for convenience and fun I don't like putting the modid in front so created my own equivalent command called "conjure" that spawns your named entity at the player's location. So this way I can just use /conjure Elephant.
In any case, it is useful to know how to create your own server command so here is an example for based on this conjure idea.
Create Custom Command Class Implementing ICommand
Follow these steps:
- Create a class that implements ICommand.
- Eclipse should warn you about unimplemented methods; accept the suggestion to implement the unimplemented methods.
- Then put your custom code inside those methods. For example:
public class CommandConjure implements ICommand { private final List aliases; protected String fullEntityName; protected Entity conjuredEntity; public CommandConjure() { aliases = new ArrayList();
aliases.add("conjure");
aliases.add("conj");
} @Override public int compareTo(Object o) { return 0;
} @Override public String getCommandName() { return "conjure";
} @Override public String getCommandUsage(ICommandSender var1) { return "conjure <text>";
} @Override public List getCommandAliases() { return this.aliases;
} @Override public void processCommand(ICommandSender sender, String[] argString) { World world = sender.getEntityWorld();
if (world.isRemote)
{
System.out.println("Not processing on Client side");
}
else
{
System.out.println("Processing on Server side");
if(argString.length == 0)
{
sender.addChatMessage(new ChatComponentText("Invalid argument"));
return;
}
sender.addChatMessage(new ChatComponentText("Conjuring: [" + argString[0]
+ "]"));
fullEntityName = WildAnimals.MODID+"."+argString[0];
if (EntityList.stringToClassMapping.containsKey(fullEntityName))
{
conjuredEntity = EntityList.createEntityByName(fullEntityName, world);
conjuredEntity.setPosition(sender.getPlayerCoordinates().posX,
sender.getPlayerCoordinates().posY,
sender.getPlayerCoordinates().posZ);
world.spawnEntityInWorld(conjuredEntity);
}
else
{
sender.addChatMessage(new ChatComponentText("Entity not found"));
}
}
} @Override public boolean canCommandSenderUseCommand(ICommandSender var1) { return true;
} @Override public List addTabCompletionOptions(ICommandSender var1, String[] var2) { // TODO Auto-generated method stub
return null;
} @Override public boolean isUsernameIndex(String[] var1, int var2) { // TODO Auto-generated method stub
return false;
}
}
There are a few things to note:
- The method names have changed a bit in recent versions of Minecraft The example above was for 1.8 but in 1.12 things have changed for example:
- getCommandName() is now just getName(),
- processCommand() is now execute().
- If you implement the ICommand interface Eclipse should tell you the current name of all the methods you need to implement.
- The actual command name is specified by the getCommandName() method, but you can also add aliases (other words that will also act to invoke the command).
- These aliases should be added in the command class constructor.
Tip: People often use aliases to allow for abbreviated command names.
The canCommandSenderUseCommand() method can be used to filter out which users are allowed to use the command. In my case I wanted all users to be allowed so I returned true.
The getCommandUsage() is important as it defines the format of the command. For example, in this case in addition to the command itself I wanted to pass an additional text argument (in my case the name of the entity).
The "real work" of the command happens in the processCommand() method. Here you can do anything you want. In my case I am using the additional text argument of the command and using it to look up registered entities. If I find that there is an entity registered with that name I will spawn it at the player location, otherwise I post an error message to the chat.
Tip: It is usually a good idea to send chat messages to indicate the success or failure of the command.
Register Command In FMLServerStartingEvent In Your Main Mod Class
Similar to how the preInit() and init() methods are put into the main class (or common proxy) of your mod, there is another "FML life cycle event" called the FMLServerStartingEvent that makes a good place to register the server commands. You just need to annotate the handling method with the @EventHandler annotation.
For example:
@EventHandler
public void serverLoad(FMLServerStartingEvent event)
{
// register server commands
event.registerServerCommand(new CommandConjure());
}
Conclusion
I hope this helps you have fun creating custom commands. Please feel free to contact me with any suggestions for corrections or clarifications!
This helped me greatly. Although in 1.8 there are different methods, but if you select add missing methods it becomes really to see what names have changed into what.
ReplyDeleteThis was a beautifully written tutorial - thank you.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteJust have one question. If I follow these instructions, will I be able to use the commands in single player as well? This is assuming I have my mod installed/active.
ReplyDeleteYes. In single player there is still both a server and client running. So it will operate in single player.
DeleteYou said to contact you about changes and suggestions, so here is one.
DeleteInclude stuff related to command block use, such as making it output a redstone signal through comparators when the command runs (like /testfor does)
I followed the instructions but I'm having a problem, whenever I use the command it tells me the entity I want to spawn can't be found (but still, I have 1 of the entities right in front of me, spawned naturally of course). May I get some help please?
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHow do you make command blocks have an analog output when the command runs, like /testfor in vanilla?
ReplyDeleteFigured it out, you throw a CommandException for a fail.
Delete