Skip to content
lovexyn0827 edited this page Aug 27, 2025 · 8 revisions

Accessing Path

As one of the most powerful and possibly the most difficult part of this Mod, the accessing path will be discussed in such a separate section.

I. Overview

An accessing path is a sequence of code, written within a single line, describing how some values like contents of fields are obtained from a given object step by step and ultimately give you a final result. Working with the accessing path, many complex reading (writing is also partly supported) operations are possible to be performed via commands, without any modification to the source code of the game.

Here are some simple examples:

  • The first element in field pistonMovementDelta
    • !pistonMovementDelta.[0]
  • The velocity on the x-axis of the second passenger of the given entity
    • !passenger.[1].velocity.x
    • or !passenger.[1].velocity.getX()
    • or !passenger.[1].velocity.!x
  • The distance from the origin to the entity
    • !pos.length()
  • **[DANGEROUS]**Stop the server
    • !world.!server.stop()
  • The value associated with the key net.minecraft.tag.FluidTags.LAVA in the Map stored in the fieldfluidHeight of the vehicle of the given entity
    • !vehicle.!fluidHeight.<S+net/minecraft/tag/FluidTags#LAVA>
  • Set the velocity of the owner of the given entity to zero
    • getOwner().setVelocity<3>(0,0,0)
    • or getOwner().setVelocity<(DDD)V>(0,0,0)
    • or getOwner().setVelocity<1>(S+net/minecraft/util/math/Vec3d#ZERO)
    • or getOwner().setVelocity<1>((0,0,0))

II. Nodes

Probably, you have noticed that the accessing path in these examples above are composed of several smaller parts, joined by some dots. Yes, you are right, and actually, nearly all accessing paths are composed this way, and these parts are called "nodes" here.

Currently, there are 13 types of nodes available in accessing paths, as described below:

Notation Description
!fieldName The value of the field with the given name. If a mapping is loaded, the name is deobfuscated before it is used.
method<descriptor>(args) or method<argNum>(args) or method(args) The returned value of a method. To tell the game which method you want it to invoke and how the method is invoked, you can specify its name, its descriptor (like (Ljava/lang/String;IDZZ)V) or the number of the parameters, and the arguments. If there is only one method with the given name, the descriptor and the number of parameters can be omitted. Some arguments should be wrapped by "'". If a mapping is loaded, the name and the descriptor are deobfuscated before used.
[n] The nth element in an array, a Collection or a Map.
<key> The value associated with the given key in a Map
size The size of an array, a String, a Collection or a Map.
hash The hash code of the given object, generated by its hashcode() method
identityHash The identity hash code of the given object, generated in the manner used in Object.hashcode(), which should be distinct for different instances.
x, y, or z A component of the given Vector (including Vec3d, Vec3i, BlockPos, and ChunkPos), or the coordination of the given entity or block entity.
class The class of the last input.
(package/Class) Cast the input as package/Class.
>package/Class::method、 >package/Class::method<argNum>(args) or >package/Class::method<desc>(args) The return value of a method, but the method needn't be one of the last input's methods. If the first format is used, a method with the given name and a single parameter will be selected; when the method is invoked, the input will serve as the argument, and if the method is not static, the method will be invoked on the input. The meaning of the other two formats is similar to the method node, but special literal _ representing the input itself is allowed in the argument list.
nodeName The output of a custom node. Custom node is per se a named accessing path, which can be defined with /accessingpath。
*literalNotation The value of a literal. Note that if we use literal nodes somewhere, the output of nodes followed by it will be ignored completely.

During running, nodes in paths are processed from left to right, that is, the output of a node is the input of its neighbor on its right (if any).

Each node has an output type and a set of requirements on the input, so based on them, there is a simple validation system. With this system, accessing paths which are likely to fail can fail fast in the parsing phase. However, the system is buggy and rejects some actually valid paths by now, so it is disabled by default. To enable it, please set the option strictAccessingPathParsing to true.

III. Literals

Literals are string representations of objects used as the key of Maps or the argument of methods.

Parsed to Format
String "content", some quoted characters
Enumeration constant E+ENUM_NAME, like E+MAIN_HAND
Static field S+Class#Field, like S+net/minecraft/util/math/Vec3d#ZERO
Vec3d (x,y,z)
Boolean true or false
BlockPos [x,y,z], where x, y and z should be integers.
null null
Integer 123, -2022, etc.
Long (64 bit integer) 123L or -20230820L
Float -123F, 2023.0820F, +Infinity or NaN
Double -123D, 2023.0820D, +Infinity or NaN
Class C+ClassName, like C+java/lang/Object
The value of a variable V+VaribleName, likeV+TACS
Array A+ClassName[dim1][dim2]..., like A+int[16]

IV. Initialization

A newly created accessing path has to be initialized before it is ready to be used. Usually, initialization involves resolving the names of fields and methods into concrete Member instances, parsing or capturing literals, and determining the exact output type of each node.

There are three initializing strategies available:

  • Legacy strategy: Accessing paths are only initialized once for its first input, then the result, including the resolved Member instances and so on, will be used to access all subsequent inputs.
  • Standard strategy: Accessing paths are parsed for every different inputs , and the parsed copies are cached until the inputs are discarded by the garbage collector.
  • Strict Strategy: Accessing paths are reinitialized each time they are used.

As you may expect, from the first one to the last one, the reliability, flexibility and consistency of the behaviors of accessing paths are increasing, while the performance drops. Depending on the need, you can switch between these strategies via the option accessingPathInitStrategy.

V. Exception & Errors

All exceptions arising from using accessing paths are finally wrapped with an AccessingFailureException, along with which node it is from and its cause (if referable).

If the exception has arose from using commands like /entityfield, you will see a descriptive message like this:

The value associated with the given key is not found! (in node #3, "<E+NEGATIVE>")

But for obvious reasons, the messages are shortened in HUDs and entity logs, in the form of CAUSE@NODE_NUM, like NULL@1, indicating a NullPointException was thrown from the second node, possibly because the output of the first node is null.

Abbreviation Cause
NO_FIELD, NO_METHOD The specified member couldn't be found
NO_KEY No value has been associated with the given key
OUT_OF_BOUND The index is out of bound
NULL Null pointer exception
INVOKE_FAIL The method invocation failed, possibly because it threw an Exception
INV_LAST The output of the last node is not suitable
UNCERTAIN_CLASS The declaring class of a field or method couldn't be known
NO_CLASS A class is not found
NOT_MAP The result of the previous node is not a Map!
BAD_ARG Some arguments are illegal.
MULTI_TARGET Multiple targets (methods or fields) were found.
INV_STATIC The string of static field is incorrect in syntax.
CAST Type casting failed.
NOT_WRITTABLE Writing is not available.
ERROR Unexpected error

Clone this wiki locally