Skip to content

A total rewrite of the minecraft command syntax, handling and parsing designed to be faster and more flexible

Notifications You must be signed in to change notification settings

Mathe172/NewCommands

Repository files navigation

NewCommands

##Contents

##Description The primary intention of this Minecraft modification was to improve the performance and flexibility of the command system. Although a lot of the commands are still not upgraded to support the new syntax, nearly all of the core functionality is here, of which we will list the most important ones (for examples see below):

###Installation If you want to give it a try, just download the installer-jar and launch it. Note that an unmodified 1.8 version of the client/server needs to be installed for this to work. For the client installation, create a new profile and select the latest NewCommands-version under 'Use version'.

###For end users

  • FULL backwards-compatibility (well almost... some things are interpreted that wouldn't have been before) - the syntax was just extended, not altered
  • Commands in command blocks are asynchronously precompiled to greatly improve the performance of high frequency command block contraptions
  • Everything can be used everywhere and more than once: Even inside selctors it is possible to write commands and the result can also be labeled for multiple usages later in the command
  • Tab completion works everywhere and automatically: Everything the engine understands can be completed (and additionaly abbreviations (see below for examples)), no matter how complex the command is, and all this with minimal to no effort. The completion engine even understands NBT-Tags and helps completing them.

###For developers Important note: Some files contain OBFID-variables generated by MCP. These files are mostly created by Mojang, we just modified some lines to tap into Minecraft. The other files are almost completely created by us. Also, the code for all commands that already exist in vanilla is mostly Mojang-code, we just ported it to our code-base.

  • The parsing is handled by a central unit to which arbitrary ways of parsing the command can be added - from simple Integers to fully customized parsers
  • Commands and selectors can easily be added using an intuitive chaining syntax, using predefined building blocks or completely new ones (as mentioned in the point above). It is also possible to register completely custom ones that would be too complex for this syntax, as it is the case with the Entity selector (since it requires dynamic parameter names for the score_<name> parameters)
  • Tab completion is also processed asynchronously (except some thread-critical sections acquiring data from the main thread)
  • Extremely modular: There is no difference between commands and other types (except that one is called by default) meaning they can be used everywhere interchangeably. It would for example be possible to parse the complete command (except the name) using a custom parser
  • Everything is loaded at runtime: Command-, selector-, type- (...) registration is always possible, even at runtime

##MCP and Minecraft version NewCommands is built on Minecraft 1.8 using MCP 9.10 and Java 7.

To compile, copy both Common/src/ and Client/src//Server/src/ into the source.

Note: As of now, MCP contains two bugs preventing direct use of the reobfuscated code (described here and here ) - direct execution using the startclient.bat files is still possible

To fix them the following steps are required:

  • Go to the conf-folder inside the mcp-folder and make the following changes (alternatively, you can use the conf-folder provided here
  • In exceptor.json, joined.exc and joined.srg, replace all occurences of MinecraftServer$1 to MinecraftServer$4 with MinecraftServer$inner1 to MinecraftServer$inner4
  • In joined.srg, append MD: net/minecraft/command/IPermission/a (Lae;)Z net/minecraft/command/IPermission/canCommandSenderUseCommand (Lnet/minecraft/command/ICommandSender;)Z as a new line at the end of the file

##Introduction to the syntax

##Commands A single command looks like this:

[<selector1> <selector2> ...] <command> [<argument1> ...]

The primary purpose of selectors preceding the command is to ensure the result is captured before anything is executed - consequently, they should be labeled for later access (further explanation below)

###Command chaining Commands of the form above can be chained and grouped, allowing for multiple commands inside one command block:

<command 1> [,|;] <command2> ...
//or even
(<command1>; <command2>), ((<command3>, <command4>); ...)

The difference between , and ; is quite simple: While the , prevents further execution (of the current scope) when encountering an error, the ; ignores any errors of the (one) preceeding command

Parentheses are used to group commands: The whole construct can be used anywhere a single command could be. For chaining purposes, the whole group counts as single command (especially for the , and ;)

Note: Most commands raise an error if nothing happened (e.g. no block/entity was changed, ...)

###List of commands Note: Every command that does not appear in the following lists has not yet been upgraded to work with the new syntax - it is however available (see also /legacy-command below): These commands work exactly like they do in vanilla, meaning only the old syntax is working. The only "new" thing is that you can terminate them with \0 (as with the /say-command) so that you can use them with the chaining syntax

The following commands are completely unchanged (compared to current implementation)

  • /blockdata
  • /deop
  • /entitydata
  • /gamemode
  • /gamerule
  • /kill
  • /op
  • /particle
  • /scoreboard
  • /setblock
  • /stats
  • /stop
  • /tellraw
  • /tp (Note: /tp <x> <y> <z> does not work if <x> can be interpreted as entity name (i.e. is a simple integer constant; there is no way to distinguish it from /tp <target-entity> <rx> <ry>) use /tp @s <x> <y> <z> instead

These commands have changed: (Only changes are listed)

  • /clone: optional fast flag (first parameter). If this flag is set, most safety mechanisms are deactivated, e.g. redstone may drop,... and block updates can be omitted sometimes. Should only be used for 'stable' structures made out of simple blocks. (As a benefit, it is faster)
  • /execute: Position can be omitted (/execute @e say ... is allowed), it defaults to ~ ~ ~. Note: If the preamble (selectors before command) is non-empty, parentheses should be used around the command (otherwise, the selectors might be interpreted as postions). Also, the detect part optionally accepts NBT-data to filter the block (while metadata can be omitted even with NBT-data, the should be specified when the NBT-data come from a selector)
  • /fill: Same fast-flag as for /clone
  • /help,/?: Same as before, but now also allows you to specify the 'command-path' (a list of keywords for the command without any other parameters): for example, /help scoreboard players would print the help information specific to that subcommand
  • /say: Nearly the same as before, but there are a few escape-sequences:
    \0: terminates the command, so that it can be chained with others
    \@: this selector won't get interpreted
    \$: this label won't get interpreted
    \\: backslashes that appear before 0,@,$,\ can be escaped this way to behave normally (this is only necessary before these sequences, in other places \\ is interpreted as \\)
    For example, /say Hello, \\ \\\@s\0, say Second message, \\@s would print Hello, \\ \@s and Second message, \<player-name>
  • /summon: Optional label <label-name> parameter (first parameter): If specified, the resulting entity is available in the label <label-name> (see labels-section for more information)

The commands listed below are completely new:

  • /activate:
    Syntax: /activate [<delay>] [<pos1>] [<pos2>]
    'Activates' all blocks specified (the positon of the sender, the block at <pos1> or the box specifed by <pos1> and <pos2>) after a delay of <delay> (defaulted to 1) ticks (minimum is one). This 'activation' triggers command-blocks, grows crops, ...
  • /break:
    No arguments. Raises an error to leave for-loops and similar constructs
  • /explain:
    Syntax: /explain [all|extended] [<position>]
    Gives further information about the errors that occured during parsing a command. If no position is specified, the last command of the player is analyzed (does not work on command-blocks or entities), otherwise the command stored in the command-block at position <position> is used. Without the all/extended-flag, only the error causing the command to fail is printed (with all its causes) With the flag specified, every error that occured during parsing is printed (even the ones that did not cause the command to fail), e.g. error caused by different possible interpretation of arguments. On hover, the output shows where the error occured.
  • /for:
    Syntax: /for [safe] <label-name> <start> <end> [step <step>] <command>
    Executes the command once for each value of <label-name> specified by <start>,<end> (and optionally <step>). Before each execution, the value of the label <label-name> is set appropriately (For more information on labels, see the labels-section). If the safe-flag is set, execution is cancelled when an error occurs, otherwise ignored (except for the '/break-error', this always cancels the loop)
  • /if:
    Syntax: /if <condition> <then-command> [else <else-command>]
    Self-explanatory. Note: <then-command> must be enclosed in parentheses if the else clause is present
  • /legacy
    Syntax: /legacy <command-name>
    Tells you wheter a command has already been upgraded to the new syntax or not
  • /move:
    Syntax: /move <entities> [<position>]
    Forces the entities to move to the specified position, resp. resets this behaviour (without the <position>-paramater). Note: For performance reasons, the path is rarely reevaluated.
  • /target:
    Syntax: /target <entities> [<target-entity>]
    Forces the entities to attack the specified target entity (even themselves), resp. resets this behaviour (without the <target-entity>-parameter).
  • /try:
    Syntax: /try <command> <command2>
    Executes <command2> if and only if <command> caused an error. Note: <command> must be enclosed in parentheses
  • /useitem:
    Syntax: /useitem <entities>
    Lets the specified entities perform the swing/attack animation

##Selectors While selectors are currently only used for selecting entities with specific properties, they can now be used to do a lot more: It's basically a way to input something in a different way than the default way: Instead of writing down the name of an entity/player, you can specify them using a selector. Now, you can also use things like the result of a calculation, the score of any player, ... (for a complete list, see below) ###Basic syntax The syntax for all selectors is basically the same as it is now: @<selector-name>, optionally followed by a list of parameters to further specify what you want. If a parameter is specified more than once, only the last occurence counts. For some selectors, the parameter names for some of the parameters can be left away:

@e[<x>,<y>,<z>,<r>]

instead of

@e[x=<x>,y=<y>,z=<z>,r=<r>]

For all selectors, there is a parameter that can always be specified: label=<label-name>. If specified, the result of the selector is stored in the label with name label-name. For more information on labels, see the labels-section. While selectors can be used almost anywhere, there is one important exception: For most commands, there are keywords that further specify what the command should do (the scoreboard command for example has the keywords players,objectives,...). For technical reasons, these keywords can't be replaced by selectors.

###List of selectors A complete list of selectors can be found in the table below. Parameter names in square bracked can be omitted and parameters in square brackets are optional. (note that the order of the unnamed parameters is important and can't be changed)

Name Parameter Parameter-description Selector-description
@s - - A reference to whatever is executing the command
@p @a @r @e all parameters from vanilla see the wiki Selects entities that have specific properties (as it is already the c[ase in vanilla)
[xyz=<postion>] Shorthand for x,y,z. If present, the others will be ignored
[dxyz=<size>] Shorthand for dx,dy,dz. If present, the others will be ignored. Only labels and selectors allowed (not things like dxyz=2 2 2)
[nbt=<tag>] Filters the entities using NBT-tags (like already present in scoreboard and some others
[team=[!]<team(s)>]
[name=[!]<name(s)>]
[type=[!]<type(s)>]
Unlike in vanilla, these parameters accept lists ((name1,name2,...)) instead of single names ('either..., or ...'). If prefixed by a !, the list is inverted (as in 'neither ..., nor ...')
@o <objective-name> The name of the objective to capture This is just for performance-reasons: Instead of searching the objective by name again and again, this allows you to label the result and use it elsewhere
@sc [o=]<objective-name> The objective of interest (by default the name) Used to query the score of an entity/variable from a scoreboard objective
[[t=]<entity/variable>] The entity/variable to read from. If omitted, the executor of the command is taken
@n <coords|entity|tag|string> Any source of nbt-data: Coordinates:the block is taken, entity: clear, tag: clear, string: the string is interpreted at runtime (can be used to store nbt inside a name/book/...) Reads nbt-data from the given source. Can also be used to read out parts of the tag
[<path>] The path inside the tag to read from (separated by .). For compounds, this is the key name. For lists, this is the index
@t [cmd=]<command> The command to be benchmarked Measures the execution time of a given command and returns the result in microseconds
@b <coordinates> The position of the block Used to query the block-state at a given position (the state contains type and metadata, but no tile-entities)
@c <operator> ... see Operators-section Used to perform calculations. For a complete list of available operators, see below

##Operators Due to technical limitations, the operators use prefix notation (this means that the operator is before its operands: + 1 2 instead of 1 + 2).

Important note: Since operator names can contain anything (except a whitespace), there has to be a whitespace after every operator. This is especially true for the constants defined below (even if they are the last thing in the selector)

There is a wide range of operators available:

Operator Description
+,-,*,/ The standard binary addition/... operators
-0 The unary sign inversion operator (shorthand for - 0 ...)
%/mod The modulo operator
<,<=,>,>=,!=,== Comparision operators
!/not,&/and,&&,` /or,
sq,sqrt The square and squareroot operator
rnd A random number between 0 and 1 (Note: Since this is a "constant", a space is always required afterwards)
rndI Returns a random integer between the two boundaries specified (inclusive)
sin,cos,exp,ln,^/pow The standard analytic functions. ^ is the power operator: ^ 2 3 =8. To stay with the rest of minecraft, sin and cos use degrees (not radians)
pi,e_ The mathematical constants
+v,-v Vector addition and subtraction
*v,/v Scalar multiplication and division. The scalar is the first argument
. The vector dot-product
v0 Normalizes the vector
abs Length of the vector
cv x and z are centered to the block-center, y is floored (1.35 0.7 2.5->1.5 0 2.5)
xv,yv,zv Reads the specified component from a vector
ex,ey,ez The vectors of unitiy
rxv,ryv The angles to describe the direction of the vector. The convention is the same as for the entity-selector (see the rx,ry parameters
pos,x,y,z The position / components of the position of an entity
rx,ry The angles describing the facing direction of an entity (like above, see entity-selector)
fv The normalized vector pointing in the direction the entity is facing
rd The entity ridden by another entity
slot The selected slot of a player (from 0 to 8)
items First operand: NBT-List contaning items. Second operand: An integer-list. This operator returns an NBT-List containing the items specified by the index-list in the correct order (The slot:-tag is used to find the items). Can be used to 'convert' the player equipment to entity-equipment
isAir Returns if the given block-state (not position) is air
meta Returns the metadata of a given block-state (not positon)
i,s,e,v Converts the argument into integer/string/entity/vector

##Labels Labels are a way of referencing results from earlier in the command (every selector can be labeled, and some commands provide ways to define labels). To reference a label, use $<label-name> anywhere where a selector would be allowed. Like everything else, labels have a type associated to them. Normally, the type is infered by the selector/command where the label is defined. If, for reasons as the ones below, you want to choose a different (but compatible) type, you can do so by specifying the type as <label-name>:<type>. Normally, a label can only be defined once. To use the same label multiple times, there are two possibilities:

  • Define the label with *<label-name>: In this case, label-name is just 'shared', the original place and this one both write their results into the same label (the * just signifies that you know that the label is already in use) Note that the type has to be exactly the same for the existing label and this declaration.
  • Define the label with ^<label-name>: Similar to above. However, it is possible that the value that is to be set to the label is converted appropriately to match the type of the label.

Note: Sometimes, the labels are not registered exactly where the label-name is in the command: The summon-commmand for example registers its label at its end (for obvious reasons). This means that the following is valid (note the places where the label is (re)defined)

summon label ^e Pig @c[pos @e[c=1,label=e]], say $e

For selectors, the registration happens right after the closing brackets, for the for-command it happens just before the command to be executed.

##Strings In most places where a string is required, you can place a composite string. The syntax is as follows:

"...\@<selector>...\$<label>..."

That is, the string is enclosed inside ". Inside the quotation marks, some things have to be escaped: (note however, that recursive selectors must not be escaped beyond the first @)

  • "\"
  • @<selector>\@<selector>
  • $<label>\$<label>

You may want to insert a label, but omit the whitespace that is required after it, ($l -text would be evaluated to label text assuming the label $l contains label; $l-text would fail since no label called l-text exists) you can do so by using \! as 'zero-width' character: $l\!-text will be evaluated to label-text (again assuming $l holds label)

##NBT The syntax to input NBT is nearly the same as it is in vanilla. For backwards-compatibility reasons, selectors and labels have to be escaped when they should be evaluated: {CustomName:\$name} instead of {CustomName:$name}. If you want to specify the type of a selector/label, you can do so by using the same literals as for numbers: b,s,i,l,f,d. These literal also work after a string enclosed in quotation marks (so you can 'build' your numbers/values from multiple selectors and labels)

##JSON As for NBT, the changes are only minimal - to evaluate selectors and labels, you also have to put a \ in front of them (see above)

##Examples Note: Since /give is still missing, you have to use other ways to get a command-block:

/setblock ~ ~ ~ command_block
OR
/summon Item ~  ~ ~ {Item:{id:command_block,Count:1}}

for x 1 5 summon Blaze ~ ~$x ~ {CustomName:"Blaze #\$x"}

Summons 5 Blazes on top of each other, named 'Blaze #1', ... (note that inside NBT-Tags, selectors and labels have to be escaped using \ to improve backwards-compatibility)


/say 1 + 2 + 3 equals @c[+ 1 + 2 3]

Calculates the sum of 1,2,3 and outputs the result. Note the prefix-notation: + 1 + 2 3 is interpreted as +(1, +(2, 3)) or 1 + (2 + 3)


/@s[label=s] execute @e[type=(Pig,Cow)] say @b[~ ~-1 ~], @c[i abs -v pos @s pos $s] 

Let's every Pig and Cow say what they're standing on and how far away they are from you. What it does step by step:

  • Store a reference to you in the label $s (@s[label=s])
  • Execute on all entities that are Pig or Cow (type=(Pig,Cow), note the new list format)
  • Output the block beneath them (@b[~ ~-1 ~])
  • Output the distance to the player labeled $s (you): i(abs(-v(pos(@s), pos($s))))
    • Get the postion of the Pig/Cow and you
    • Subtract them
    • Take the length
    • Convert it to an integer (otherwise the result contains ~10 digits)

activate, @p[label=p] @c[cos ry $p,label=fy] @c[-0 * $fy sin rx $p,label=dx] @c[* $fy cos rx $p,label=dz] @c[-0 sin ry $p,label=dy] execute $p (execute @e[type=Snowball,c=1,r=5] kill @s, for safe n 5 500 summon PrimedTnt ~@c[* $n $dx] ~@c[* $n $dy] ~@c[* $n $dz])

This command summons a ray of TNT in the direction the player is looking at when they throw a snowball. Without going in full detail, these are the main steps performed by the command:

  • activate triggers the command-block in the next tick (this replaces the setblock-clock)
  • calculate some things used to summon the ray in the correct direction
  • execute on the player and the on the nearest snowball
  • when a snowball is found, kill it and summon the ray using a for-loop. The safe-flag tells the for-command to stop when the first summon fails (we reached the top/bottom of the world

Note: To start the command, power the command-block once


activate, execute @p (tp @e[name=Mirror] ~ ~ ~ @c[-0 rx @s] @c[ry @s], @c[items @n[@s,Inventory] (@c[slot @s],100,101,102,103),label=i] entitydata @e[name=Mirror] {Equipment:\$i})

Lets every entity named Mirror mirror your head rotation and equipment (As can be seen, the currently selected slot as well as your armor are copied)

###Tab completion As mentioned, tab completion understands abbreviations: (| is the cursor)

/scr| -> /scoreboard|
/scr|brd -> /scoreboard|
/say @t| -> /say @t[|]
/summon PrimedTnt ~ ~ ~ {Custom|} -> /summon PrimentTnt ~ ~ ~ {CustomName:|} AND ... {CustomNameVisible:|}

As can be seen, even the cursor position is set appropriately after choosing a completion (also, neccessary characters like : are added). To iterate through the possible completions, TAB iterates forward, SHIFT+TAB backwards and holding down CTRL always starts a new completion (and finishes the current one by choosing the current item). Note that the first character (or nothing at all) has to be present for a completion to be proposed. So /crbrd| will not be completed (but /|crbrd will be, since nothing at all is before the cursor)

##Code model There are only a few basic structures:

  • CommandArg: The basic element that represents the result of one unit, most importantly they are passed to commands/selctors instead of plain Strings (it gets the ICommandSenderfor evaluation)
  • TypeID: Represents a type like Integer, String or EntityList, knows and handles the conversions of CommandArg's to CommandArg's returning data of other types (again described by a TypeID)
  • ArgWrapper: Combines the CommandArg and TypeID into one unit and allows for type-safe conversion
  • IDataType, IParse, IComplete, ...: Interfaces and classes that describe the capabilities of a parsing unit and handle necessary wrappers for completion
  • CommandDescriptor: As the name suggests, this describes a command. It knows a list of IDataType's (in some way, a IDataType is a TypeID with an associated parser and completion) as arguments and a list of subcommands (again CommandDescriptor's) identified by keywords. Also provides a construct-method that is called by the central parser once all the necessary data are acquired and provides usage description and an IPermisson instance to handle execution permissons
  • SelectorDescriptor: Similary to the CommandDescriptor knows a list of parameters (optionally identified by a name) that it can handle (as in the current syntax, unnamed parameters can be written before other parameters as shorthand notation) with the associated IDataType's.
  • Getter: A reference to the result of a CommandArg that is already evaluated. This mechanism is used for selectors: Selector arguments are preevaluated and passed as Getter's to ensure that the evaluation order matches their order in the command (these evaluations might have side-effects, e.g. label overrides,...)

Note: For commands (and operators), it is very important that the arguments are evaluated in the correct order. Also, parameter validations should only be done after everything is evaluated. This ensures that it is always clear what gets executed in which order. (For selectors, this is automatically done since it would be impossible otherwise, see above)

###Registration examples The following example registers the for-command and handles its construction. The necessary IDataType's are part of the default-set.

public final class Commands extends RegistrationHelper
{
	...
	
	public static final void init()
	{
		...
	
		register(command(CommandFor.ignoreErrorConstructable, IPermission.level2, usage("commands.for.usage"), "for")
			.optional(
				command(CommandFor.constructable, "safe"))
			.then(TypeLabelDeclaration.intNonInstant)
			.then(ParserInt.parser)
			.then(ParserInt.parser)
			.optional(
				command("step")
					.then(ParserInt.parser))
			.then(ProvideLastLabel.parser) //This makes the label visible. (for obvious reasons, the label should not be accessible for the limits of the loop)
			.then(TypeCommand.parserSingleCmd));
		
		...
	}
	
	...
	
// ###############################################################################
// ############################### CommandFor.java ###############################
// ###############################################################################
	
public class CommandFor extends CommandArg<Integer>
{
	public static final CommandConstructable constructable = new CommandConstructable()
	{
		@Override
		public CommandFor construct(final CParserData data)
		{
			return new CommandFor(data, false);
		}
	};
	
	public static final CommandConstructable ignoreErrorConstructable = new CommandConstructable()
	{
		@Override
		public CommandFor construct(final CParserData data)
		{
			return new CommandFor(data, true);
		}
	};
	
	private final Setter<Integer> label;
	private final CommandArg<Integer> start, end, step;
	private final CommandArg<Integer> command;
	private final boolean ignoreErrors;
	
	public CommandFor(final CParserData data, final boolean ignoreErrors)
	{
		this.label = data.getLabel(TypeIDs.Integer);
		this.start = data.get(TypeIDs.Integer);
		this.end = data.get(TypeIDs.Integer);
		this.step = data.path.size() == (ignoreErrors ? 0 : 1) ? null : data.get(TypeIDs.Integer);
		this.command = data.get(TypeIDs.Integer);
		this.ignoreErrors = ignoreErrors;
	}
	
	...
}

This example registers the score-selector:

public final class Selectors extends RegistrationHelper
{
	...

	public static final void init()
	{
		...
		
		register("o",
			selector(
				TypeScoreObjective.type,
				PrimitiveWrapper.constructable,
				IPermission.level2,
				TypeIDs.ScoreObjective));
		
		register("sc", selector(IPermission.level2, TypeIDs.Integer)
			.then("o", TypeScoreObjective.type)
			.then("t", Types.scoreHolder)
			.construct(SelectorScore.constructable));
		
		...
	}
	
	...
}

// ###############################################################################
// ############################## SelectorScore.java #############################
// ###############################################################################

public class SelectorScore extends CommandArg<Integer>
{
	public static final SelectorConstructable constructable = new SelectorConstructable()
	{
		@Override
		public ArgWrapper<?> construct(final DefaultParserData parserData) throws SyntaxErrorException
		{
			return TypeIDs.Integer.wrap(
				new SelectorScore(
					getRequiredParam(TypeIDs.ScoreObjective, 0, "o", parserData),
					getParam(TypeIDs.UUID, 1, "t", parserData)));
		}
	};
	
	private final Getter<ScoreObjective> objective;
	private final Getter<String> target;
	
	public SelectorScore(final Getter<ScoreObjective> objective, final Getter<String> target)
	{
		this.objective = objective;
		this.target = target;
	}
	
	@Override
	public Integer eval(final ICommandSender sender) throws CommandException
	{
		return MinecraftServer
			.getServer()
			.worldServerForDimension(0)
			.getScoreboard()
			.getValueFromObjective(
				this.target == null
					? ParsingUtilities.getEntityIdentifier(sender.getCommandSenderEntity())
					: this.target.get(),
				this.objective.get())
			.getScorePoints();
	}
}

About

A total rewrite of the minecraft command syntax, handling and parsing designed to be faster and more flexible

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages