├── .github
└── workflows
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
└── main
├── java
└── dev
│ └── xpple
│ └── clientarguments
│ ├── ClientArguments.java
│ └── arguments
│ ├── CAngleArgument.java
│ ├── CBlockInput.java
│ ├── CBlockPosArgument.java
│ ├── CBlockPredicateArgument.java
│ ├── CBlockStateArgument.java
│ ├── CColorArgument.java
│ ├── CColumnPosArgument.java
│ ├── CComponentArgument.java
│ ├── CCompoundTagArgument.java
│ ├── CCoordinates.java
│ ├── CDimensionArgument.java
│ ├── CEntityAnchorArgument.java
│ ├── CEntityArgument.java
│ ├── CEntitySelector.java
│ ├── CEntitySelectorOptions.java
│ ├── CEntitySelectorParser.java
│ ├── CEnumArgument.java
│ ├── CGameProfileArgument.java
│ ├── CItemArgument.java
│ ├── CItemPredicateArgument.java
│ ├── CLocalCoordinates.java
│ ├── CMessageArgument.java
│ ├── CNbtPathArgument.java
│ ├── CNbtTagArgument.java
│ ├── CObjectiveArgument.java
│ ├── CObjectiveCriteriaArgument.java
│ ├── COperationArgument.java
│ ├── CParticleArgument.java
│ ├── CRangeArgument.java
│ ├── CResourceArgument.java
│ ├── CResourceKeyArgument.java
│ ├── CResourceLocationArgument.java
│ ├── CResourceOrIdArgument.java
│ ├── CResourceOrTagArgument.java
│ ├── CResourceOrTagKeyArgument.java
│ ├── CResourceSelectorArgument.java
│ ├── CRotationArgument.java
│ ├── CScoreHolderArgument.java
│ ├── CScoreboardSlotArgument.java
│ ├── CSlotArgument.java
│ ├── CSlotsArgument.java
│ ├── CStyleArgument.java
│ ├── CSuggestionProviders.java
│ ├── CSwizzleArgument.java
│ ├── CTeamArgument.java
│ ├── CTimeArgument.java
│ ├── CUuidArgument.java
│ ├── CVec2Argument.java
│ ├── CVec3Argument.java
│ └── CWorldCoordinates.java
└── resources
├── clientarguments.aw
└── fabric.mod.json
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish package to GitHub Packages
2 | on:
3 | release:
4 | types: [created]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | contents: read
10 | packages: write
11 | steps:
12 | - uses: actions/checkout@v3
13 | - uses: actions/setup-java@v3
14 | with:
15 | java-version: '21'
16 | distribution: 'adopt'
17 | - name: Validate Gradle wrapper
18 | uses: gradle/wrapper-validation-action@v1
19 | - name: Publish package
20 | run: gradle publish
21 | env:
22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23 | MAVEN_USER: ${{ secrets.MAVEN_USER }}
24 | MAVEN_PASS: ${{ secrets.MAVEN_PASS }}
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific stuff
2 | .idea/
3 |
4 | *.iml
5 | *.ipr
6 | *.iws
7 |
8 | # IntelliJ
9 | out/
10 | # mpeltonen/sbt-idea plugin
11 | .idea_modules/
12 |
13 | # JIRA plugin
14 | atlassian-ide-plugin.xml
15 |
16 | # Compiled class file
17 | *.class
18 |
19 | # Log file
20 | *.log
21 |
22 | # BlueJ files
23 | *.ctxt
24 |
25 | # Package Files #
26 | *.jar
27 | *.war
28 | *.nar
29 | *.ear
30 | *.zip
31 | *.tar.gz
32 | *.rar
33 |
34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
35 | hs_err_pid*
36 |
37 | *~
38 |
39 | # temporary files which can be created if a process still has a handle open of a deleted file
40 | .fuse_hidden*
41 |
42 | # KDE directory preferences
43 | .directory
44 |
45 | # Linux trash folder which might appear on any partition or disk
46 | .Trash-*
47 |
48 | # .nfs files are created when an open file is removed but is still being accessed
49 | .nfs*
50 |
51 | # General
52 | .DS_Store
53 | .AppleDouble
54 | .LSOverride
55 |
56 | # Icon must end with two \r
57 | Icon
58 |
59 | # Thumbnails
60 | ._*
61 |
62 | # Files that might appear in the root of a volume
63 | .DocumentRevisions-V100
64 | .fseventsd
65 | .Spotlight-V100
66 | .TemporaryItems
67 | .Trashes
68 | .VolumeIcon.icns
69 | .com.apple.timemachine.donotpresent
70 |
71 | # Directories potentially created on remote AFP share
72 | .AppleDB
73 | .AppleDesktop
74 | Network Trash Folder
75 | Temporary Items
76 | .apdisk
77 |
78 | # Windows thumbnail cache files
79 | Thumbs.db
80 | Thumbs.db:encryptable
81 | ehthumbs.db
82 | ehthumbs_vista.db
83 |
84 | # Dump file
85 | *.stackdump
86 |
87 | # Folder config file
88 | [Dd]esktop.ini
89 |
90 | # Recycle Bin used on file shares
91 | $RECYCLE.BIN/
92 |
93 | # Windows Installer files
94 | *.cab
95 | *.msi
96 | *.msix
97 | *.msm
98 | *.msp
99 |
100 | # Windows shortcuts
101 | *.lnk
102 |
103 | .gradle
104 | build/
105 |
106 | # Ignore Gradle GUI config
107 | gradle-app.setting
108 |
109 | # Cache of project
110 | .gradletasknamecache
111 |
112 | **/build/
113 |
114 | # Common working directory
115 | run/
116 |
117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
118 | !gradle-wrapper.jar
119 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 xpple
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # clientarguments
2 | Quality of life library for client-sided Minecraft Fabric command building.
3 |
4 | ## Installation
5 | Replace `${version}` with the artifact version.
6 | ### Gradle
7 | You may choose between my own maven repository and GitHub's package repository.
8 | #### My own
9 | ```gradle
10 | repositories {
11 | maven {
12 | url 'https://maven.xpple.dev/maven2'
13 | }
14 | }
15 | ```
16 | #### GitHub packages
17 | ```gradle
18 | repositories {
19 | maven {
20 | url 'https://maven.pkg.github.com/xpple/clientarguments'
21 | credentials {
22 | username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
23 | password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
24 | }
25 | }
26 | }
27 | ```
28 | Import it:
29 | ```gradle
30 | dependencies {
31 | include modImplementation('dev.xpple:clientarguments:${version}')
32 | }
33 | ```
34 | Note: if you choose to use GitHub packages and get `Received status code 400 from server: Bad Request`, you need to
35 | configure your environment variables for GitHub.
36 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'fabric-loom' version '1.10-SNAPSHOT'
3 | id 'maven-publish'
4 | }
5 |
6 | version = project.mod_version
7 | group = project.maven_group
8 |
9 | repositories {
10 | maven {
11 | url = "https://maven.parchmentmc.org"
12 | }
13 | }
14 |
15 | loom {
16 | accessWidenerPath = file('src/main/resources/clientarguments.aw')
17 | }
18 |
19 | dependencies {
20 | // To change the versions see the gradle.properties file
21 | minecraft "com.mojang:minecraft:${project.minecraft_version}"
22 | mappings loom.layered {
23 | officialMojangMappings {
24 | nameSyntheticMembers = true
25 | }
26 | parchment("org.parchmentmc.data:parchment-1.21:2024.07.28@zip")
27 | }
28 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
29 |
30 | modImplementation fabricApi.module("fabric-command-api-v2", project.fabric_api_version)
31 |
32 | // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
33 | // You may need to force-disable transitiveness on them.
34 | }
35 |
36 | processResources {
37 | inputs.property "version", project.version
38 | filteringCharset "UTF-8"
39 |
40 | filesMatching("fabric.mod.json") {
41 | expand "version": project.version
42 | }
43 | }
44 |
45 | def targetJavaVersion = 21
46 | tasks.withType(JavaCompile).configureEach {
47 | // ensure that the encoding is set to UTF-8, no matter what the system default is
48 | // this fixes some edge cases with special characters not displaying correctly
49 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
50 | // If Javadoc is generated, this must be specified in that task too.
51 | it.options.encoding = "UTF-8"
52 | if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
53 | it.options.release = targetJavaVersion
54 | }
55 | }
56 |
57 | java {
58 | def javaVersion = JavaVersion.toVersion(targetJavaVersion)
59 | if (JavaVersion.current() < javaVersion) {
60 | toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
61 | }
62 | archivesBaseName = project.archives_base_name
63 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
64 | // if it is present.
65 | // If you remove this line, sources will not be generated.
66 | withSourcesJar()
67 | }
68 |
69 | jar {
70 | from("LICENSE") {
71 | rename { "${it}_${project.archivesBaseName}" }
72 | }
73 | }
74 |
75 | // configure the maven publication
76 | publishing {
77 | publications {
78 | mavenJava(MavenPublication) {
79 | from components.java
80 | }
81 | }
82 |
83 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
84 | repositories {
85 | // Add repositories to publish to here.
86 | // Notice: This block does NOT have the same function as the block in the top level.
87 | // The repositories here will be used for publishing your artifact, not for
88 | // retrieving dependencies.
89 | maven {
90 | name = "GitHubPackages"
91 | url = "https://maven.pkg.github.com/xpple/clientarguments"
92 | credentials {
93 | username = System.getenv("GITHUB_ACTOR")
94 | password = System.getenv("GITHUB_TOKEN")
95 | }
96 | }
97 | maven {
98 | name = "xpple"
99 | url = "sftp://xpple.dev:22/maven.xpple.dev/httpdocs/maven2"
100 | credentials {
101 | username = System.getenv("MAVEN_USER")
102 | password = System.getenv("MAVEN_PASS")
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Done to increase the memory available to gradle.
2 | org.gradle.jvmargs=-Xmx1G
3 | # Fabric Properties
4 | # check these on https://fabricmc.net/develop/
5 | minecraft_version=1.21.5-rc1
6 | loader_version=0.16.10
7 |
8 | # Mod Properties
9 | mod_version=1.11.1
10 | maven_group=dev.xpple
11 | archives_base_name=clientarguments
12 |
13 | # Dependencies
14 | fabric_api_version=0.119.2+1.21.5
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xpple/clientarguments/edcb311bfa19d6914ae070a553c6e56f95080fd9/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 | # SPDX-License-Identifier: Apache-2.0
19 | #
20 |
21 | ##############################################################################
22 | #
23 | # Gradle start up script for POSIX generated by Gradle.
24 | #
25 | # Important for running:
26 | #
27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
28 | # noncompliant, but you have some other compliant shell such as ksh or
29 | # bash, then to run this script, type that shell name before the whole
30 | # command line, like:
31 | #
32 | # ksh Gradle
33 | #
34 | # Busybox and similar reduced shells will NOT work, because this script
35 | # requires all of these POSIX shell features:
36 | # * functions;
37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
39 | # * compound commands having a testable exit status, especially «case»;
40 | # * various built-in commands including «command», «set», and «ulimit».
41 | #
42 | # Important for patching:
43 | #
44 | # (2) This script targets any POSIX shell, so it avoids extensions provided
45 | # by Bash, Ksh, etc; in particular arrays are avoided.
46 | #
47 | # The "traditional" practice of packing multiple parameters into a
48 | # space-separated string is a well documented source of bugs and security
49 | # problems, so this is (mostly) avoided, by progressively accumulating
50 | # options in "$@", and eventually passing that to Java.
51 | #
52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
54 | # see the in-line comments for details.
55 | #
56 | # There are tweaks for specific operating systems such as AIX, CygWin,
57 | # Darwin, MinGW, and NonStop.
58 | #
59 | # (3) This script is generated from the Groovy template
60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
61 | # within the Gradle project.
62 | #
63 | # You can find Gradle at https://github.com/gradle/gradle/.
64 | #
65 | ##############################################################################
66 |
67 | # Attempt to set APP_HOME
68 |
69 | # Resolve links: $0 may be a link
70 | app_path=$0
71 |
72 | # Need this for daisy-chained symlinks.
73 | while
74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
75 | [ -h "$app_path" ]
76 | do
77 | ls=$( ls -ld "$app_path" )
78 | link=${ls#*' -> '}
79 | case $link in #(
80 | /*) app_path=$link ;; #(
81 | *) app_path=$APP_HOME$link ;;
82 | esac
83 | done
84 |
85 | # This is normally unused
86 | # shellcheck disable=SC2034
87 | APP_BASE_NAME=${0##*/}
88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90 | ' "$PWD" ) || exit
91 |
92 | # Use the maximum available, or set MAX_FD != -1 to use that value.
93 | MAX_FD=maximum
94 |
95 | warn () {
96 | echo "$*"
97 | } >&2
98 |
99 | die () {
100 | echo
101 | echo "$*"
102 | echo
103 | exit 1
104 | } >&2
105 |
106 | # OS specific support (must be 'true' or 'false').
107 | cygwin=false
108 | msys=false
109 | darwin=false
110 | nonstop=false
111 | case "$( uname )" in #(
112 | CYGWIN* ) cygwin=true ;; #(
113 | Darwin* ) darwin=true ;; #(
114 | MSYS* | MINGW* ) msys=true ;; #(
115 | NONSTOP* ) nonstop=true ;;
116 | esac
117 |
118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
119 |
120 |
121 | # Determine the Java command to use to start the JVM.
122 | if [ -n "$JAVA_HOME" ] ; then
123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
124 | # IBM's JDK on AIX uses strange locations for the executables
125 | JAVACMD=$JAVA_HOME/jre/sh/java
126 | else
127 | JAVACMD=$JAVA_HOME/bin/java
128 | fi
129 | if [ ! -x "$JAVACMD" ] ; then
130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
131 |
132 | Please set the JAVA_HOME variable in your environment to match the
133 | location of your Java installation."
134 | fi
135 | else
136 | JAVACMD=java
137 | if ! command -v java >/dev/null 2>&1
138 | then
139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
140 |
141 | Please set the JAVA_HOME variable in your environment to match the
142 | location of your Java installation."
143 | fi
144 | fi
145 |
146 | # Increase the maximum file descriptors if we can.
147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
148 | case $MAX_FD in #(
149 | max*)
150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
151 | # shellcheck disable=SC2039,SC3045
152 | MAX_FD=$( ulimit -H -n ) ||
153 | warn "Could not query maximum file descriptor limit"
154 | esac
155 | case $MAX_FD in #(
156 | '' | soft) :;; #(
157 | *)
158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
159 | # shellcheck disable=SC2039,SC3045
160 | ulimit -n "$MAX_FD" ||
161 | warn "Could not set maximum file descriptor limit to $MAX_FD"
162 | esac
163 | fi
164 |
165 | # Collect all arguments for the java command, stacking in reverse order:
166 | # * args from the command line
167 | # * the main class name
168 | # * -classpath
169 | # * -D...appname settings
170 | # * --module-path (only if needed)
171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
172 |
173 | # For Cygwin or MSYS, switch paths to Windows format before running java
174 | if "$cygwin" || "$msys" ; then
175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
177 |
178 | JAVACMD=$( cygpath --unix "$JAVACMD" )
179 |
180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
181 | for arg do
182 | if
183 | case $arg in #(
184 | -*) false ;; # don't mess with options #(
185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
186 | [ -e "$t" ] ;; #(
187 | *) false ;;
188 | esac
189 | then
190 | arg=$( cygpath --path --ignore --mixed "$arg" )
191 | fi
192 | # Roll the args list around exactly as many times as the number of
193 | # args, so each arg winds up back in the position where it started, but
194 | # possibly modified.
195 | #
196 | # NB: a `for` loop captures its iteration list before it begins, so
197 | # changing the positional parameters here affects neither the number of
198 | # iterations, nor the values presented in `arg`.
199 | shift # remove old arg
200 | set -- "$@" "$arg" # push replacement arg
201 | done
202 | fi
203 |
204 |
205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
207 |
208 | # Collect all arguments for the java command:
209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
210 | # and any embedded shellness will be escaped.
211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
212 | # treated as '${Hostname}' itself on the command line.
213 |
214 | set -- \
215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
216 | -classpath "$CLASSPATH" \
217 | org.gradle.wrapper.GradleWrapperMain \
218 | "$@"
219 |
220 | # Stop when "xargs" is not available.
221 | if ! command -v xargs >/dev/null 2>&1
222 | then
223 | die "xargs is not available"
224 | fi
225 |
226 | # Use "xargs" to parse quoted args.
227 | #
228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
229 | #
230 | # In Bash we could simply go:
231 | #
232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
233 | # set -- "${ARGS[@]}" "$@"
234 | #
235 | # but POSIX shell has neither arrays nor command substitution, so instead we
236 | # post-process each arg (as a line of input to sed) to backslash-escape any
237 | # character that might be a shell metacharacter, then use eval to reverse
238 | # that process (while maintaining the separation between arguments), and wrap
239 | # the whole thing up as a single "set" statement.
240 | #
241 | # This will of course break if any of these variables contains a newline or
242 | # an unmatched quote.
243 | #
244 |
245 | eval "set -- $(
246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
247 | xargs -n1 |
248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
249 | tr '\n' ' '
250 | )" '"$@"'
251 |
252 | exec "$JAVACMD" "$@"
253 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven {
4 | name = 'Fabric'
5 | url = 'https://maven.fabricmc.net/'
6 | }
7 | gradlePluginPortal()
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/ClientArguments.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments;
2 |
3 | import com.mojang.brigadier.AmbiguityConsumer;
4 | import com.mojang.brigadier.Command;
5 | import com.mojang.brigadier.CommandDispatcher;
6 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
7 | import dev.xpple.clientarguments.arguments.CEntitySelectorOptions;
8 | import net.fabricmc.api.ClientModInitializer;
9 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
10 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
11 | import net.fabricmc.loader.api.FabricLoader;
12 | import net.minecraft.commands.CommandBuildContext;
13 | import net.minecraft.core.registries.Registries;
14 | import net.minecraft.network.chat.Component;
15 | import net.minecraft.world.level.GameType;
16 |
17 | import static dev.xpple.clientarguments.arguments.CAngleArgument.*;
18 | import static dev.xpple.clientarguments.arguments.CBlockPosArgument.*;
19 | import static dev.xpple.clientarguments.arguments.CBlockPredicateArgument.*;
20 | import static dev.xpple.clientarguments.arguments.CBlockStateArgument.*;
21 | import static dev.xpple.clientarguments.arguments.CColorArgument.*;
22 | import static dev.xpple.clientarguments.arguments.CColumnPosArgument.*;
23 | import static dev.xpple.clientarguments.arguments.CDimensionArgument.*;
24 | import static dev.xpple.clientarguments.arguments.CEntityAnchorArgument.*;
25 | import static dev.xpple.clientarguments.arguments.CEntityArgument.*;
26 | import static dev.xpple.clientarguments.arguments.CEnumArgument.*;
27 | import static dev.xpple.clientarguments.arguments.CGameProfileArgument.*;
28 | import static dev.xpple.clientarguments.arguments.CResourceLocationArgument.*;
29 | import static dev.xpple.clientarguments.arguments.CItemPredicateArgument.*;
30 | import static dev.xpple.clientarguments.arguments.CResourceSelectorArgument.*;
31 | import static dev.xpple.clientarguments.arguments.CSlotArgument.*;
32 | import static dev.xpple.clientarguments.arguments.CItemArgument.*;
33 | import static dev.xpple.clientarguments.arguments.CMessageArgument.*;
34 | import static dev.xpple.clientarguments.arguments.CCompoundTagArgument.*;
35 | import static dev.xpple.clientarguments.arguments.CNbtTagArgument.*;
36 | import static dev.xpple.clientarguments.arguments.CNbtPathArgument.*;
37 | import static dev.xpple.clientarguments.arguments.CRangeArgument.*;
38 | import static dev.xpple.clientarguments.arguments.COperationArgument.*;
39 | import static dev.xpple.clientarguments.arguments.CParticleArgument.*;
40 | import static dev.xpple.clientarguments.arguments.CResourceOrIdArgument.*;
41 | import static dev.xpple.clientarguments.arguments.CResourceOrTagArgument.*;
42 | import static dev.xpple.clientarguments.arguments.CResourceArgument.*;
43 | import static dev.xpple.clientarguments.arguments.CResourceKeyArgument.*;
44 | import static dev.xpple.clientarguments.arguments.CResourceOrTagKeyArgument.*;
45 | import static dev.xpple.clientarguments.arguments.CRotationArgument.*;
46 | import static dev.xpple.clientarguments.arguments.CScoreHolderArgument.*;
47 | import static dev.xpple.clientarguments.arguments.CObjectiveCriteriaArgument.*;
48 | import static dev.xpple.clientarguments.arguments.CObjectiveArgument.*;
49 | import static dev.xpple.clientarguments.arguments.CScoreboardSlotArgument.*;
50 | import static dev.xpple.clientarguments.arguments.CSlotsArgument.*;
51 | import static dev.xpple.clientarguments.arguments.CStyleArgument.*;
52 | import static dev.xpple.clientarguments.arguments.CSwizzleArgument.*;
53 | import static dev.xpple.clientarguments.arguments.CTeamArgument.*;
54 | import static dev.xpple.clientarguments.arguments.CComponentArgument.*;
55 | import static dev.xpple.clientarguments.arguments.CTimeArgument.*;
56 | import static dev.xpple.clientarguments.arguments.CUuidArgument.*;
57 | import static dev.xpple.clientarguments.arguments.CVec2Argument.*;
58 | import static dev.xpple.clientarguments.arguments.CVec3Argument.*;
59 | import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;
60 |
61 | public class ClientArguments implements ClientModInitializer {
62 | private static final DynamicCommandExceptionType STRUCTURE_INVALID_EXCEPTION = new DynamicCommandExceptionType(id -> Component.translatableEscape("commands.locate.structure.invalid", id));
63 |
64 | @Override
65 | public void onInitializeClient() {
66 | CEntitySelectorOptions.register();
67 |
68 | if (FabricLoader.getInstance().isDevelopmentEnvironment()) {
69 | ClientCommandRegistrationCallback.EVENT.register(ClientArguments::registerTestCommand);
70 | }
71 | }
72 |
73 | /**
74 | *
75 | * Registering this test command will trigger {@link com.mojang.brigadier.tree.CommandNode#findAmbiguities(AmbiguityConsumer)},
76 | * which checks the validity of the example inputs - and with that also the validity of the argument in question.
77 | */
78 | private static void registerTestCommand(CommandDispatcher dispatcher, CommandBuildContext registryAccess) {
79 | dispatcher.register(literal("clientarguments:test")
80 | .then(literal("angle").then(argument("angle", angle())
81 | .executes(ctx -> consume(getAngle(ctx, "angle")))))
82 | .then(literal("blockpos").then(argument("blockpos", blockPos())
83 | .executes(ctx -> consume(getBlockPos(ctx, "blockpos")))))
84 | .then(literal("blockpredicate").then(argument("blockpredicate", blockPredicate(registryAccess))
85 | .executes(ctx -> consume(getBlockPredicate(ctx, "blockpredicate")))))
86 | .then(literal("blockstate").then(argument("blockstate", blockState(registryAccess))
87 | .executes(ctx -> consume(getBlockState(ctx, "blockstate")))))
88 | .then(literal("color").then(argument("color", color())
89 | .executes(ctx -> consume(getColor(ctx, "color")))))
90 | .then(literal("columnpos").then(argument("columnpos", columnPos())
91 | .executes(ctx -> consume(getColumnPos(ctx, "columnpos")))))
92 | .then(literal("dimension").then(argument("dimension", dimension())
93 | .executes(ctx -> consume(getDimension(ctx, "dimension")))))
94 | .then(literal("entityanchor").then(argument("entityanchor", entityAnchor())
95 | .executes(ctx -> consume(getEntityAnchor(ctx, "entityanchor")))))
96 | .then(literal("entity").then(argument("entity", entity())
97 | .executes(ctx -> consume(getEntity(ctx, "entity")))))
98 | .then(literal("enum").then(argument("enum", enumArg(GameType.class))
99 | .executes(ctx -> consume(getEnum(ctx, "enum")))))
100 | .then(literal("gameprofile").then(argument("gameprofile", gameProfile())
101 | .executes(ctx -> consume(getProfileArgument(ctx, "gameprofile")))))
102 | .then(literal("identifier").then(argument("identifier", id())
103 | .executes(ctx -> consume(getId(ctx, "identifier")))))
104 | .then(literal("itempredicate").then(argument("itempredicate", itemPredicate(registryAccess))
105 | .executes(ctx -> consume(getItemStackPredicate(ctx, "itempredicate")))))
106 | .then(literal("itemslot").then(argument("itemslot", itemSlot())
107 | .executes(ctx -> consume(getItemSlot(ctx, "itemslot")))))
108 | .then(literal("itemstack").then(argument("itemstack", itemStack(registryAccess))
109 | .executes(ctx -> consume(getItemStackArgument(ctx, "itemstack")))))
110 | .then(literal("message").then(argument("message", message())
111 | .executes(ctx -> consume(getMessage(ctx, "message")))))
112 | .then(literal("nbtcompound").then(argument("nbtcompound", compoundTag())
113 | .executes(ctx -> consume(getCompoundTag(ctx, "nbtcompound")))))
114 | .then(literal("nbtelement").then(argument("nbtelement", nbtTag())
115 | .executes(ctx -> consume(getNbtTag(ctx, "nbtelement")))))
116 | .then(literal("nbtpath").then(argument("nbtpath", nbtPath())
117 | .executes(ctx -> consume(getNbtPath(ctx, "nbtpath")))))
118 | .then(literal("intrange").then(argument("intrange", intRange())
119 | .executes(ctx -> consume(Ints.getRangeArgument(ctx, "intrange")))))
120 | .then(literal("floatrange").then(argument("floatrange", floatRange())
121 | .executes(ctx -> consume(Floats.getRangeArgument(ctx, "floatrange")))))
122 | .then(literal("operation").then(argument("operation", operation())
123 | .executes(ctx -> consume(getOperation(ctx, "operation")))))
124 | .then(literal("particleeffect").then(argument("particleeffect", particle(registryAccess))
125 | .executes(ctx -> consume(getParticle(ctx, "particleeffect")))))
126 | .then(literal("registryentry").then(argument("registryentry", lootTable(registryAccess))
127 | .executes(ctx -> consume(getLootTable(ctx, "registryentry")))))
128 | .then(literal("registryentrypredicate").then(argument("registryentrypredicate", resourceOrTag(registryAccess, Registries.BIOME))
129 | .executes(ctx -> consume(getResourceOrTag(ctx, "registryentrypredicate", Registries.BIOME)))))
130 | .then(literal("registryentryreference").then(argument("registryentryreference", registryEntry(registryAccess, Registries.ENCHANTMENT))
131 | .executes(ctx -> consume(getEnchantment(ctx, "registryentryreference")))))
132 | .then(literal("registrykey").then(argument("registrykey", key(Registries.STRUCTURE))
133 | .executes(ctx -> consume(getKey(ctx, "registrykey", Registries.STRUCTURE, STRUCTURE_INVALID_EXCEPTION)))))
134 | .then(literal("registrypredicate").then(argument("registrypredicate", registryPredicate(Registries.STRUCTURE))
135 | .executes(ctx -> consume(getPredicate(ctx, "registrypredicate", Registries.STRUCTURE, STRUCTURE_INVALID_EXCEPTION)))))
136 | .then(literal("resourceselector").then(argument("resourceselector", resourceSelector(registryAccess, Registries.ITEM))
137 | .executes(ctx -> consume(getSelectedResources(ctx, "resourceselector", Registries.ITEM)))))
138 | .then(literal("rotation").then(argument("rotation", rotation())
139 | .executes(ctx -> consume(getRotation(ctx, "rotation")))))
140 | .then(literal("scoreboardcriterion").then(argument("scoreboardcriterion", criteria())
141 | .executes(ctx -> consume(getCriteria(ctx, "scoreboardcriterion")))))
142 | .then(literal("scoreboardobjective").then(argument("scoreboardobjective", objective())
143 | .executes(ctx -> consume(getObjective(ctx, "scoreboardobjective")))))
144 | .then(literal("scoreboardslot").then(argument("scoreboardslot", scoreboardSlot())
145 | .executes(ctx -> consume(getScoreboardSlot(ctx, "scoreboardslot")))))
146 | .then(literal("scoreholder").then(argument("scoreholder", scoreHolder())
147 | .executes(ctx -> consume(getScoreHolder(ctx, "scoreholder")))))
148 | .then(literal("slotrange").then(argument("slotrange", slots())
149 | .executes(ctx -> consume(getSlots(ctx, "slotrange")))))
150 | .then(literal("style").then(argument("style", style(registryAccess))
151 | .executes(ctx -> consume(getStyle(ctx, "style")))))
152 | .then(literal("swizzle").then(argument("swizzle", swizzle())
153 | .executes(ctx -> consume(getSwizzle(ctx, "swizzle")))))
154 | .then(literal("team").then(argument("team", team())
155 | .executes(ctx -> consume(getTeam(ctx, "team")))))
156 | .then(literal("text").then(argument("text", textComponent(registryAccess))
157 | .executes(ctx -> consume(getComponent(ctx, "text")))))
158 | .then(literal("time").then(argument("time", time())
159 | .executes(ctx -> consume(getTime(ctx, "time")))))
160 | .then(literal("uuid").then(argument("uuid", uuid())
161 | .executes(ctx -> consume(getUuid(ctx, "uuid")))))
162 | .then(literal("vec2").then(argument("vec2", vec2())
163 | .executes(ctx -> consume(getVec2(ctx, "vec2")))))
164 | .then(literal("vec3").then(argument("vec3", vec3())
165 | .executes(ctx -> consume(getVec3(ctx, "vec3")))))
166 | );
167 | }
168 |
169 | private static int consume(Object object) {
170 | return Command.SINGLE_SUCCESS;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CAngleArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
8 |
9 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
10 | import net.minecraft.commands.arguments.coordinates.WorldCoordinate;
11 | import net.minecraft.network.chat.Component;
12 | import net.minecraft.util.Mth;
13 |
14 | import java.util.Arrays;
15 | import java.util.Collection;
16 |
17 | public class CAngleArgument implements ArgumentType {
18 | private static final Collection EXAMPLES = Arrays.asList("0", "~", "~-5");
19 | public static final SimpleCommandExceptionType INCOMPLETE_ANGLE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.angle.incomplete"));
20 | public static final SimpleCommandExceptionType INVALID_ANGLE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.angle.invalid"));
21 |
22 | public static CAngleArgument angle() {
23 | return new CAngleArgument();
24 | }
25 |
26 | public static float getAngle(final CommandContext context, final String name) {
27 | return context.getArgument(name, Angle.class).getAngle(context.getSource());
28 | }
29 |
30 | @Override
31 | public Angle parse(final StringReader stringReader) throws CommandSyntaxException {
32 | if (!stringReader.canRead()) {
33 | throw INCOMPLETE_ANGLE_EXCEPTION.createWithContext(stringReader);
34 | }
35 | boolean relative = WorldCoordinate.isRelative(stringReader);
36 | float angle = stringReader.canRead() && stringReader.peek() != ' ' ? stringReader.readFloat() : 0.0F;
37 | if (Float.isNaN(angle) || Float.isInfinite(angle)) {
38 | throw INVALID_ANGLE_EXCEPTION.createWithContext(stringReader);
39 | }
40 | return new Angle(angle, relative);
41 | }
42 |
43 | @Override
44 | public Collection getExamples() {
45 | return EXAMPLES;
46 | }
47 |
48 | public static final class Angle {
49 | private final float angle;
50 | private final boolean relative;
51 |
52 | Angle(float angle, boolean relative) {
53 | this.angle = angle;
54 | this.relative = relative;
55 | }
56 |
57 | public float getAngle(FabricClientCommandSource source) {
58 | return Mth.wrapDegrees(this.relative ? this.angle + source.getRotation().y : this.angle);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CBlockInput.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import java.util.Set;
4 | import java.util.function.Predicate;
5 |
6 | import net.minecraft.world.level.block.state.BlockState;
7 | import net.minecraft.world.level.block.entity.BlockEntity;
8 | import net.minecraft.world.level.block.state.pattern.BlockInWorld;
9 | import net.minecraft.client.multiplayer.ClientLevel;
10 | import net.minecraft.nbt.CompoundTag;
11 | import net.minecraft.nbt.NbtUtils;
12 | import net.minecraft.world.level.block.state.properties.Property;
13 | import net.minecraft.core.BlockPos;
14 | import org.jetbrains.annotations.Nullable;
15 |
16 | public class CBlockInput implements Predicate {
17 | private final BlockState state;
18 | private final Set> properties;
19 | @Nullable
20 | private final CompoundTag data;
21 |
22 | public CBlockInput(BlockState state, Set> properties, @Nullable CompoundTag data) {
23 | this.state = state;
24 | this.properties = properties;
25 | this.data = data;
26 | }
27 |
28 | public BlockState getState() {
29 | return this.state;
30 | }
31 |
32 | public Set> getDefinedProperties() {
33 | return this.properties;
34 | }
35 |
36 | public boolean test(BlockInWorld blockInWorld) {
37 | BlockState blockState = blockInWorld.getState();
38 | if (!blockState.is(this.state.getBlock())) {
39 | return false;
40 | }
41 | for (Property> property : this.properties) {
42 | if (blockState.getValue(property) != this.state.getValue(property)) {
43 | return false;
44 | }
45 | }
46 |
47 | if (this.data == null) {
48 | return true;
49 | }
50 | BlockEntity blockEntity = blockInWorld.getEntity();
51 | return blockEntity != null && NbtUtils.compareNbt(this.data, blockEntity.saveWithFullMetadata(blockInWorld.getLevel().registryAccess()), true);
52 | }
53 |
54 | public boolean test(ClientLevel world, BlockPos pos) {
55 | return this.test(new BlockInWorld(world, pos, false));
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CBlockPosArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
11 | import net.minecraft.client.multiplayer.ClientLevel;
12 | import net.minecraft.commands.SharedSuggestionProvider;
13 | import net.minecraft.commands.Commands;
14 | import net.minecraft.network.chat.Component;
15 | import net.minecraft.core.BlockPos;
16 | import net.minecraft.world.level.ChunkPos;
17 | import net.minecraft.world.level.Level;
18 |
19 | import java.util.Arrays;
20 | import java.util.Collection;
21 | import java.util.Collections;
22 | import java.util.concurrent.CompletableFuture;
23 |
24 | public class CBlockPosArgument implements ArgumentType {
25 | private static final Collection EXAMPLES = Arrays.asList("0 0 0", "~ ~ ~", "^ ^ ^", "^1 ^ ^-5", "~0.5 ~1 ~-5");
26 | public static final SimpleCommandExceptionType UNLOADED_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.pos.unloaded"));
27 | public static final SimpleCommandExceptionType OUT_OF_WORLD_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.pos.outofworld"));
28 | public static final SimpleCommandExceptionType OUT_OF_BOUNDS_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.pos.outofbounds"));
29 |
30 | public static CBlockPosArgument blockPos() {
31 | return new CBlockPosArgument();
32 | }
33 |
34 | public static BlockPos getLoadedBlockPos(final CommandContext context, final String name) throws CommandSyntaxException {
35 | ClientLevel clientLevel = context.getSource().getWorld();
36 | return getLoadedBlockPos(context, clientLevel, name);
37 | }
38 |
39 | public static BlockPos getLoadedBlockPos(final CommandContext context, final ClientLevel level, final String name) throws CommandSyntaxException {
40 | BlockPos blockPos = getBlockPos(context, name);
41 | ChunkPos chunkPos = new ChunkPos(blockPos);
42 | if (!level.getChunkSource().hasChunk(chunkPos.x, chunkPos.z)) {
43 | throw UNLOADED_EXCEPTION.create();
44 | }
45 | if (!level.isInWorldBounds(blockPos)) {
46 | throw OUT_OF_WORLD_EXCEPTION.create();
47 | }
48 | return blockPos;
49 | }
50 |
51 | public static BlockPos getBlockPos(final CommandContext context, final String name) {
52 | return context.getArgument(name, CCoordinates.class).getBlockPos(context.getSource());
53 | }
54 |
55 | public static BlockPos getValidBlockPos(CommandContext context, String name) throws CommandSyntaxException {
56 | BlockPos blockPos = getBlockPos(context, name);
57 | if (!Level.isInSpawnableBounds(blockPos)) {
58 | throw OUT_OF_BOUNDS_EXCEPTION.create();
59 | }
60 | return blockPos;
61 | }
62 |
63 | @Override
64 | public CCoordinates parse(final StringReader stringReader) throws CommandSyntaxException {
65 | return stringReader.canRead() && stringReader.peek() == '^' ? CLocalCoordinates.parse(stringReader) : CWorldCoordinates.parse(stringReader);
66 | }
67 |
68 | @Override
69 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
70 | if (!(context.getSource() instanceof SharedSuggestionProvider)) {
71 | return Suggestions.empty();
72 | }
73 | String string = builder.getRemaining();
74 | Collection collection;
75 | if (!string.isEmpty() && string.charAt(0) == '^') {
76 | collection = Collections.singleton(SharedSuggestionProvider.TextCoordinates.DEFAULT_LOCAL);
77 | } else {
78 | collection = ((SharedSuggestionProvider) context.getSource()).getRelevantCoordinates();
79 | }
80 |
81 | return SharedSuggestionProvider.suggestCoordinates(string, collection, builder, Commands.createValidator(this::parse));
82 | }
83 |
84 | @Override
85 | public Collection getExamples() {
86 | return EXAMPLES;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CBlockPredicateArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.suggestion.Suggestions;
8 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
9 | import java.util.Arrays;
10 | import java.util.Collection;
11 | import java.util.Map;
12 | import java.util.Set;
13 | import java.util.Map.Entry;
14 | import java.util.concurrent.CompletableFuture;
15 | import java.util.function.Predicate;
16 | import net.minecraft.world.level.block.Block;
17 | import net.minecraft.world.level.block.state.BlockState;
18 | import net.minecraft.world.level.block.entity.BlockEntity;
19 | import net.minecraft.world.level.block.state.pattern.BlockInWorld;
20 | import net.minecraft.commands.CommandBuildContext;
21 | import net.minecraft.commands.arguments.blocks.BlockStateParser;
22 | import net.minecraft.nbt.CompoundTag;
23 | import net.minecraft.nbt.NbtUtils;
24 | import net.minecraft.core.registries.Registries;
25 | import net.minecraft.core.HolderLookup;
26 | import net.minecraft.core.HolderSet;
27 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
28 | import net.minecraft.world.level.block.state.properties.Property;
29 | import org.jetbrains.annotations.Nullable;
30 |
31 | public class CBlockPredicateArgument implements ArgumentType {
32 | private static final Collection EXAMPLES = Arrays.asList("stone", "minecraft:stone", "stone[foo=bar]", "#stone", "#stone[foo=bar]{baz=nbt}");
33 | private final HolderLookup holderLookup;
34 |
35 | public CBlockPredicateArgument(CommandBuildContext commandBuildContext) {
36 | this.holderLookup = commandBuildContext.lookupOrThrow(Registries.BLOCK);
37 | }
38 |
39 | public static CBlockPredicateArgument blockPredicate(CommandBuildContext commandBuildContext) {
40 | return new CBlockPredicateArgument(commandBuildContext);
41 | }
42 |
43 | @Override
44 | public CBlockPredicateArgument.BlockPredicate parse(final StringReader stringReader) throws CommandSyntaxException {
45 | return parse(this.holderLookup, stringReader);
46 | }
47 |
48 | public static CBlockPredicateArgument.BlockPredicate parse(HolderLookup holderLookup, StringReader reader) throws CommandSyntaxException {
49 | return BlockStateParser.parseForTesting(holderLookup, reader, true)
50 | .map(
51 | result -> new CBlockPredicateArgument.StatePredicate(result.blockState(), result.properties().keySet(), result.nbt()),
52 | result -> new CBlockPredicateArgument.TagPredicate(result.tag(), result.vagueProperties(), result.nbt())
53 | );
54 | }
55 |
56 | public static Predicate getBlockPredicate(final CommandContext context, final String name) {
57 | return context.getArgument(name, CBlockPredicateArgument.BlockPredicate.class);
58 | }
59 |
60 | @Override
61 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
62 | return BlockStateParser.fillSuggestions(this.holderLookup, builder, true, true);
63 | }
64 |
65 | @Override
66 | public Collection getExamples() {
67 | return EXAMPLES;
68 | }
69 |
70 | public interface BlockPredicate extends Predicate {
71 | boolean hasNbt();
72 | }
73 |
74 | static class StatePredicate implements CBlockPredicateArgument.BlockPredicate {
75 | private final BlockState state;
76 | private final Set> properties;
77 | @Nullable
78 | private final CompoundTag nbt;
79 |
80 | public StatePredicate(BlockState state, Set> properties, @Nullable CompoundTag nbt) {
81 | this.state = state;
82 | this.properties = properties;
83 | this.nbt = nbt;
84 | }
85 |
86 | public boolean test(BlockInWorld blockInWorld) {
87 | BlockState blockState = blockInWorld.getState();
88 | if (!blockState.is(this.state.getBlock())) {
89 | return false;
90 | }
91 | for (Property> property : this.properties) {
92 | if (blockState.getValue(property) != this.state.getValue(property)) {
93 | return false;
94 | }
95 | }
96 |
97 | if (this.nbt == null) {
98 | return true;
99 | }
100 | BlockEntity blockEntity = blockInWorld.getEntity();
101 | return blockEntity != null && NbtUtils.compareNbt(this.nbt, blockEntity.saveWithFullMetadata(blockInWorld.getLevel().registryAccess()), true);
102 | }
103 |
104 | @Override
105 | public boolean hasNbt() {
106 | return this.nbt != null;
107 | }
108 | }
109 |
110 | static class TagPredicate implements CBlockPredicateArgument.BlockPredicate {
111 | private final HolderSet tag;
112 | @Nullable
113 | private final CompoundTag nbt;
114 | private final Map properties;
115 |
116 | TagPredicate(HolderSet tag, Map properties, @Nullable CompoundTag nbt) {
117 | this.tag = tag;
118 | this.properties = properties;
119 | this.nbt = nbt;
120 | }
121 |
122 | public boolean test(BlockInWorld blockInWorld) {
123 | BlockState blockState = blockInWorld.getState();
124 | if (!blockState.is(this.tag)) {
125 | return false;
126 | }
127 | for (Entry entry : this.properties.entrySet()) {
128 | Property> property = blockState.getBlock().getStateDefinition().getProperty(entry.getKey());
129 | if (property == null) {
130 | return false;
131 | }
132 |
133 | Comparable> comparable = property.getValue(entry.getValue()).orElse(null);
134 | if (comparable == null) {
135 | return false;
136 | }
137 |
138 | if (blockState.getValue(property) != comparable) {
139 | return false;
140 | }
141 | }
142 |
143 | if (this.nbt == null) {
144 | return true;
145 | }
146 | BlockEntity blockEntity = blockInWorld.getEntity();
147 | return blockEntity != null && NbtUtils.compareNbt(this.nbt, blockEntity.saveWithFullMetadata(blockInWorld.getLevel().registryAccess()), true);
148 | }
149 |
150 | @Override
151 | public boolean hasNbt() {
152 | return this.nbt != null;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CBlockStateArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.suggestion.Suggestions;
8 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
9 | import java.util.Arrays;
10 | import java.util.Collection;
11 | import java.util.concurrent.CompletableFuture;
12 |
13 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
14 | import net.minecraft.commands.CommandBuildContext;
15 | import net.minecraft.commands.arguments.blocks.BlockStateParser;
16 | import net.minecraft.core.HolderLookup;
17 | import net.minecraft.core.registries.Registries;
18 | import net.minecraft.world.level.block.Block;
19 |
20 | public class CBlockStateArgument implements ArgumentType {
21 | private static final Collection EXAMPLES = Arrays.asList("stone", "minecraft:stone", "stone[foo=bar]", "foo{bar=baz}");
22 | private final HolderLookup registryWrapper;
23 |
24 | public CBlockStateArgument(CommandBuildContext buildContext) {
25 | this.registryWrapper = buildContext.lookupOrThrow(Registries.BLOCK);
26 | }
27 |
28 | public static CBlockStateArgument blockState(CommandBuildContext buildContext) {
29 | return new CBlockStateArgument(buildContext);
30 | }
31 |
32 | @Override
33 | public CBlockInput parse(final StringReader stringReader) throws CommandSyntaxException {
34 | BlockStateParser.BlockResult blockResult = BlockStateParser.parseForBlock(this.registryWrapper, stringReader, true);
35 | return new CBlockInput(blockResult.blockState(), blockResult.properties().keySet(), blockResult.nbt());
36 | }
37 |
38 | public static CBlockInput getBlockState(final CommandContext context, final String name) {
39 | return context.getArgument(name, CBlockInput.class);
40 | }
41 |
42 | @Override
43 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
44 | return BlockStateParser.fillSuggestions(this.registryWrapper, builder, false, true);
45 | }
46 |
47 | @Override
48 | public Collection getExamples() {
49 | return EXAMPLES;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CColorArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import java.util.Arrays;
11 | import java.util.Collection;
12 | import java.util.concurrent.CompletableFuture;
13 |
14 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
15 | import net.minecraft.commands.SharedSuggestionProvider;
16 | import net.minecraft.network.chat.Component;
17 | import net.minecraft.ChatFormatting;
18 |
19 | public class CColorArgument implements ArgumentType {
20 | private static final Collection EXAMPLES = Arrays.asList("red", "green");
21 | public static final DynamicCommandExceptionType INVALID_COLOR_EXCEPTION = new DynamicCommandExceptionType(color -> Component.translatableEscape("argument.color.invalid", color));
22 |
23 | private CColorArgument() {
24 | }
25 |
26 | public static CColorArgument color() {
27 | return new CColorArgument();
28 | }
29 |
30 | public static ChatFormatting getColor(final CommandContext context, final String name) {
31 | return context.getArgument(name, ChatFormatting.class);
32 | }
33 |
34 | @Override
35 | public ChatFormatting parse(final StringReader stringReader) throws CommandSyntaxException {
36 | String string = stringReader.readUnquotedString();
37 | ChatFormatting formatting = ChatFormatting.getByName(string);
38 | if (formatting == null || formatting.isFormat()) {
39 | throw INVALID_COLOR_EXCEPTION.createWithContext(stringReader, string);
40 | }
41 | return formatting;
42 | }
43 |
44 | @Override
45 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) {
46 | return SharedSuggestionProvider.suggest(ChatFormatting.getNames(true, false), builder);
47 | }
48 |
49 | @Override
50 | public Collection getExamples() {
51 | return EXAMPLES;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CColumnPosArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.minecraft.commands.SharedSuggestionProvider;
11 | import net.minecraft.commands.arguments.coordinates.WorldCoordinate;
12 | import net.minecraft.commands.Commands;
13 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
14 | import net.minecraft.network.chat.Component;
15 | import net.minecraft.core.BlockPos;
16 | import net.minecraft.server.level.ColumnPos;
17 |
18 | import java.util.Arrays;
19 | import java.util.Collection;
20 | import java.util.Collections;
21 | import java.util.concurrent.CompletableFuture;
22 |
23 | public class CColumnPosArgument implements ArgumentType {
24 | private static final Collection EXAMPLES = Arrays.asList("0 0", "~ ~", "~1 ~-2", "^ ^", "^-1 ^0");
25 | public static final SimpleCommandExceptionType INCOMPLETE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.pos2d.incomplete"));
26 |
27 | public static CColumnPosArgument columnPos() {
28 | return new CColumnPosArgument();
29 | }
30 |
31 | public static ColumnPos getColumnPos(final CommandContext context, final String name) {
32 | BlockPos blockPos = context.getArgument(name, CCoordinates.class).getBlockPos(context.getSource());
33 | return new ColumnPos(blockPos.getX(), blockPos.getZ());
34 | }
35 |
36 | @Override
37 | public CCoordinates parse(final StringReader stringReader) throws CommandSyntaxException {
38 | int cursor = stringReader.getCursor();
39 | if (!stringReader.canRead()) {
40 | throw INCOMPLETE_EXCEPTION.createWithContext(stringReader);
41 | }
42 | WorldCoordinate worldCoord = WorldCoordinate.parseInt(stringReader);
43 | if (!stringReader.canRead() || stringReader.peek() != ' ') {
44 | stringReader.setCursor(cursor);
45 | throw INCOMPLETE_EXCEPTION.createWithContext(stringReader);
46 | }
47 | stringReader.skip();
48 | WorldCoordinate worldCoord2 = WorldCoordinate.parseInt(stringReader);
49 | return new CWorldCoordinates(worldCoord, new WorldCoordinate(true, 0.0), worldCoord2);
50 | }
51 |
52 | @Override
53 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
54 | if (!(context.getSource() instanceof SharedSuggestionProvider)) {
55 | return Suggestions.empty();
56 | }
57 | String string = builder.getRemaining();
58 | Collection collection;
59 | if (!string.isEmpty() && string.charAt(0) == '^') {
60 | collection = Collections.singleton(SharedSuggestionProvider.TextCoordinates.DEFAULT_LOCAL);
61 | } else {
62 | collection = ((SharedSuggestionProvider)context.getSource()).getRelevantCoordinates();
63 | }
64 |
65 | return SharedSuggestionProvider.suggest2DCoordinates(string, collection, builder, Commands.createValidator(this::parse));
66 | }
67 |
68 | @Override
69 | public Collection getExamples() {
70 | return EXAMPLES;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CComponentArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.context.CommandContext;
4 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
5 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
6 | import net.minecraft.commands.CommandBuildContext;
7 | import net.minecraft.core.HolderLookup;
8 | import net.minecraft.nbt.NbtOps;
9 | import net.minecraft.nbt.SnbtGrammar;
10 | import net.minecraft.nbt.Tag;
11 | import net.minecraft.network.chat.Component;
12 | import net.minecraft.network.chat.ComponentSerialization;
13 | import net.minecraft.util.parsing.packrat.commands.CommandArgumentParser;
14 | import net.minecraft.util.parsing.packrat.commands.ParserBasedArgument;
15 |
16 | import java.util.Arrays;
17 | import java.util.Collection;
18 |
19 | public class CComponentArgument extends ParserBasedArgument {
20 | private static final Collection EXAMPLES = Arrays.asList("\"hello world\"", "\"\"", "\"{\"text\":\"hello world\"}", "[\"\"]");
21 | public static final DynamicCommandExceptionType INVALID_COMPONENT_EXCEPTION = new DynamicCommandExceptionType(text -> Component.translatableEscape("argument.component.invalid", text));
22 | private static final CommandArgumentParser TAG_PARSER = SnbtGrammar.createParser(NbtOps.INSTANCE);
23 |
24 | private CComponentArgument(HolderLookup.Provider registries) {
25 | super(TAG_PARSER.withCodec(registries.createSerializationContext(NbtOps.INSTANCE), TAG_PARSER, ComponentSerialization.CODEC, INVALID_COMPONENT_EXCEPTION));
26 | }
27 |
28 | public static CComponentArgument textComponent(CommandBuildContext buildContext) {
29 | return new CComponentArgument(buildContext);
30 | }
31 |
32 | public static Component getComponent(final CommandContext context, final String name) {
33 | return context.getArgument(name, Component.class);
34 | }
35 |
36 | @Override
37 | public Collection getExamples() {
38 | return EXAMPLES;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CCompoundTagArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import net.minecraft.nbt.CompoundTag;
8 | import net.minecraft.nbt.TagParser;
9 |
10 | import java.util.Arrays;
11 | import java.util.Collection;
12 |
13 | public class CCompoundTagArgument implements ArgumentType {
14 | private static final Collection EXAMPLES = Arrays.asList("{}", "{foo=bar}");
15 |
16 | private CCompoundTagArgument() {
17 | }
18 |
19 | public static CCompoundTagArgument compoundTag() {
20 | return new CCompoundTagArgument();
21 | }
22 |
23 | public static CompoundTag getCompoundTag(final CommandContext context, final String name) {
24 | return context.getArgument(name, CompoundTag.class);
25 | }
26 |
27 | @Override
28 | public CompoundTag parse(final StringReader stringReader) throws CommandSyntaxException {
29 | return TagParser.parseCompoundAsArgument(stringReader);
30 | }
31 |
32 | @Override
33 | public Collection getExamples() {
34 | return EXAMPLES;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CCoordinates.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
4 | import net.minecraft.core.BlockPos;
5 | import net.minecraft.world.phys.Vec2;
6 | import net.minecraft.world.phys.Vec3;
7 |
8 | public interface CCoordinates {
9 | Vec3 getPosition(FabricClientCommandSource source);
10 |
11 | Vec2 getRotation(FabricClientCommandSource source);
12 |
13 | default BlockPos getBlockPos(FabricClientCommandSource source) {
14 | return BlockPos.containing(this.getPosition(source));
15 | }
16 |
17 | boolean isXRelative();
18 |
19 | boolean isYRelative();
20 |
21 | boolean isZRelative();
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CDimensionArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
11 | import net.minecraft.commands.SharedSuggestionProvider;
12 | import net.minecraft.resources.ResourceKey;
13 | import net.minecraft.core.registries.Registries;
14 | import net.minecraft.network.chat.Component;
15 | import net.minecraft.resources.ResourceLocation;
16 | import net.minecraft.world.level.Level;
17 |
18 | import java.util.Collection;
19 | import java.util.concurrent.CompletableFuture;
20 | import java.util.stream.Collectors;
21 | import java.util.stream.Stream;
22 |
23 | public class CDimensionArgument implements ArgumentType {
24 | private static final Collection EXAMPLES = Stream.of(Level.OVERWORLD, Level.NETHER)
25 | .map(key -> key.location().toString())
26 | .collect(Collectors.toList());
27 | private static final DynamicCommandExceptionType INVALID_DIMENSION_EXCEPTION = new DynamicCommandExceptionType(id -> Component.translatableEscape("argument.dimension.invalid", id));
28 |
29 |
30 | public static CDimensionArgument dimension() {
31 | return new CDimensionArgument();
32 | }
33 |
34 | public static ResourceKey getDimension(final CommandContext context, final String name) throws CommandSyntaxException {
35 | ResourceLocation identifier = context.getArgument(name, ResourceLocation.class);
36 | ResourceKey resourceKey = ResourceKey.create(Registries.DIMENSION, identifier);
37 | return context.getSource().levels().stream()
38 | .filter(key -> key.registry().equals(resourceKey.registry()) && key.location().equals(resourceKey.location()))
39 | .findAny().orElseThrow(() -> INVALID_DIMENSION_EXCEPTION.create(identifier));
40 | }
41 |
42 | @Override
43 | public ResourceLocation parse(final StringReader stringReader) throws CommandSyntaxException {
44 | return ResourceLocation.read(stringReader);
45 | }
46 |
47 | @Override
48 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
49 | return context.getSource() instanceof SharedSuggestionProvider
50 | ? SharedSuggestionProvider.suggestResource(((SharedSuggestionProvider) context.getSource()).levels().stream().map(ResourceKey::location), builder)
51 | : Suggestions.empty();
52 | }
53 |
54 | @Override
55 | public Collection getExamples() {
56 | return EXAMPLES;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CEntityAnchorArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Maps;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.arguments.ArgumentType;
6 | import com.mojang.brigadier.context.CommandContext;
7 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
8 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
9 | import com.mojang.brigadier.suggestion.Suggestions;
10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
11 | import net.minecraft.commands.SharedSuggestionProvider;
12 | import net.minecraft.world.entity.Entity;
13 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
14 | import net.minecraft.network.chat.Component;
15 | import net.minecraft.Util;
16 | import net.minecraft.world.phys.Vec3;
17 | import org.jetbrains.annotations.Nullable;
18 |
19 | import java.util.Arrays;
20 | import java.util.Collection;
21 | import java.util.Map;
22 | import java.util.concurrent.CompletableFuture;
23 | import java.util.function.BiFunction;
24 |
25 | public class CEntityAnchorArgument implements ArgumentType {
26 | private static final Collection EXAMPLES = Arrays.asList("eyes", "feet");
27 | private static final DynamicCommandExceptionType INVALID_ANCHOR_EXCEPTION = new DynamicCommandExceptionType(name -> Component.translatableEscape("argument.anchor.invalid", name));
28 |
29 | public static CEntityAnchorArgument entityAnchor() {
30 | return new CEntityAnchorArgument();
31 | }
32 |
33 | public static EntityAnchor getEntityAnchor(final CommandContext context, final String name) {
34 | return context.getArgument(name, EntityAnchor.class);
35 | }
36 |
37 | @Override
38 | public EntityAnchor parse(final StringReader stringReader) throws CommandSyntaxException {
39 | int cursor = stringReader.getCursor();
40 | String string = stringReader.readUnquotedString();
41 | EntityAnchor entityAnchor = EntityAnchor.fromId(string);
42 | if (entityAnchor == null) {
43 | stringReader.setCursor(cursor);
44 | throw INVALID_ANCHOR_EXCEPTION.createWithContext(stringReader, string);
45 | }
46 | return entityAnchor;
47 | }
48 |
49 | @Override
50 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
51 | return SharedSuggestionProvider.suggest(EntityAnchor.ANCHORS.keySet(), builder);
52 | }
53 |
54 | @Override
55 | public Collection getExamples() {
56 | return EXAMPLES;
57 | }
58 |
59 | public enum EntityAnchor {
60 | FEET("feet", (pos, entity) -> pos),
61 | EYES("eyes", (pos, entity) -> new Vec3(pos.x, pos.y + (double) entity.getEyeHeight(), pos.z));
62 |
63 | static final Map ANCHORS = Util.make(Maps.newHashMap(), map -> {
64 | for (EntityAnchor entityAnchor : values()) {
65 | map.put(entityAnchor.id, entityAnchor);
66 | }
67 | });
68 | private final String id;
69 | private final BiFunction offset;
70 |
71 | EntityAnchor(final String id, final BiFunction offset) {
72 | this.id = id;
73 | this.offset = offset;
74 | }
75 |
76 | @Nullable
77 | public static CEntityAnchorArgument.EntityAnchor fromId(String id) {
78 | return ANCHORS.get(id);
79 | }
80 |
81 | public Vec3 positionAt(Entity entity) {
82 | return this.offset.apply(entity.position(), entity);
83 | }
84 |
85 | public Vec3 positionAt(FabricClientCommandSource source) {
86 | Entity entity = source.getEntity();
87 | return entity == null ? source.getPosition() : this.offset.apply(source.getPosition(), entity);
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CEntityArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Iterables;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.arguments.ArgumentType;
6 | import com.mojang.brigadier.context.CommandContext;
7 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
8 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
9 | import com.mojang.brigadier.suggestion.Suggestions;
10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
11 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
12 | import net.minecraft.client.player.AbstractClientPlayer;
13 | import net.minecraft.commands.SharedSuggestionProvider;
14 | import net.minecraft.world.entity.Entity;
15 | import net.minecraft.network.chat.Component;
16 |
17 | import java.util.Arrays;
18 | import java.util.Collection;
19 | import java.util.List;
20 | import java.util.concurrent.CompletableFuture;
21 |
22 | public class CEntityArgument implements ArgumentType {
23 | private static final Collection EXAMPLES = Arrays.asList("Player", "0123", "@e", "@e[type=foo]", "dd12be42-52a9-4a91-a8a1-11c01849e498");
24 | public static final SimpleCommandExceptionType TOO_MANY_ENTITIES_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.entity.toomany"));
25 | public static final SimpleCommandExceptionType TOO_MANY_PLAYERS_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.player.toomany"));
26 | public static final SimpleCommandExceptionType PLAYER_SELECTOR_HAS_ENTITIES_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.player.entities"));
27 | public static final SimpleCommandExceptionType ENTITY_NOT_FOUND_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.entity.notfound.entity"));
28 | public static final SimpleCommandExceptionType PLAYER_NOT_FOUND_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.entity.notfound.player"));
29 | public static final SimpleCommandExceptionType NOT_ALLOWED_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.entity.selector.not_allowed"));
30 | final boolean singleTarget;
31 | final boolean playersOnly;
32 |
33 | protected CEntityArgument(boolean singleTarget, boolean playersOnly) {
34 | this.singleTarget = singleTarget;
35 | this.playersOnly = playersOnly;
36 | }
37 |
38 | public static CEntityArgument entity() {
39 | return new CEntityArgument(true, false);
40 | }
41 |
42 | public static Entity getEntity(final CommandContext context, final String name) throws CommandSyntaxException {
43 | return context.getArgument(name, CEntitySelector.class).findSingleEntity(context.getSource());
44 | }
45 |
46 | public static CEntityArgument entities() {
47 | return new CEntityArgument(false, false);
48 | }
49 |
50 | public static Collection extends Entity> getEntities(final CommandContext context, final String name) throws CommandSyntaxException {
51 | Collection extends Entity> collection = getOptionalEntities(context, name);
52 | if (collection.isEmpty()) {
53 | throw ENTITY_NOT_FOUND_EXCEPTION.create();
54 | }
55 | return collection;
56 | }
57 |
58 | public static Collection extends Entity> getOptionalEntities(final CommandContext context, final String name) throws CommandSyntaxException {
59 | return context.getArgument(name, CEntitySelector.class).findEntities(context.getSource());
60 | }
61 |
62 | public static Collection getOptionalPlayers(final CommandContext context, final String name) throws CommandSyntaxException {
63 | return context.getArgument(name, CEntitySelector.class).findPlayers(context.getSource());
64 | }
65 |
66 | public static CEntityArgument player() {
67 | return new CEntityArgument(true, true);
68 | }
69 |
70 | public static AbstractClientPlayer getPlayer(final CommandContext context, final String name) throws CommandSyntaxException {
71 | return context.getArgument(name, CEntitySelector.class).findSinglePlayer(context.getSource());
72 | }
73 |
74 | public static CEntityArgument players() {
75 | return new CEntityArgument(false, true);
76 | }
77 |
78 | public static Collection getPlayers(final CommandContext context, final String name) throws CommandSyntaxException {
79 | List list = context.getArgument(name, CEntitySelector.class).findPlayers(context.getSource());
80 | if (list.isEmpty()) {
81 | throw PLAYER_NOT_FOUND_EXCEPTION.create();
82 | }
83 | return list;
84 | }
85 |
86 | @Override
87 | public CEntitySelector parse(final StringReader stringReader) throws CommandSyntaxException {
88 | return this.parse(stringReader, true);
89 | }
90 |
91 | public CEntitySelector parse(final StringReader stringReader, final S source) throws CommandSyntaxException {
92 | return this.parse(stringReader, CEntitySelectorParser.allowSelectors(source));
93 | }
94 |
95 | private CEntitySelector parse(StringReader stringReader, boolean allowSelectors) throws CommandSyntaxException {
96 | CEntitySelectorParser entitySelectorParser = new CEntitySelectorParser(stringReader, allowSelectors);
97 | CEntitySelector entitySelector = entitySelectorParser.parse();
98 | if (entitySelector.getMaxResults() > 1 && this.singleTarget) {
99 | if (this.playersOnly) {
100 | stringReader.setCursor(0);
101 | throw TOO_MANY_PLAYERS_EXCEPTION.createWithContext(stringReader);
102 | } else {
103 | stringReader.setCursor(0);
104 | throw TOO_MANY_ENTITIES_EXCEPTION.createWithContext(stringReader);
105 | }
106 | }
107 | if (entitySelector.includesEntities() && this.playersOnly && !entitySelector.isSelfSelector()) {
108 | stringReader.setCursor(0);
109 | throw PLAYER_SELECTOR_HAS_ENTITIES_EXCEPTION.createWithContext(stringReader);
110 | }
111 | return entitySelector;
112 | }
113 |
114 | @Override
115 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
116 | if (context.getSource() instanceof SharedSuggestionProvider commandSource) {
117 | StringReader stringReader = new StringReader(builder.getInput());
118 | stringReader.setCursor(builder.getStart());
119 | CEntitySelectorParser entitySelectorParser = new CEntitySelectorParser(stringReader, CEntitySelectorParser.allowSelectors(commandSource));
120 |
121 | try {
122 | entitySelectorParser.parse();
123 | } catch (CommandSyntaxException ignored) {
124 | }
125 |
126 | return entitySelectorParser.fillSuggestions(builder, builderx -> {
127 | Collection collection = commandSource.getOnlinePlayerNames();
128 | Iterable iterable = this.playersOnly ? collection : Iterables.concat(collection, commandSource.getSelectedEntities());
129 | SharedSuggestionProvider.suggest(iterable, builderx);
130 | });
131 | }
132 | return Suggestions.empty();
133 | }
134 |
135 | @Override
136 | public Collection getExamples() {
137 | return EXAMPLES;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CEntitySelector.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.google.common.collect.Streams;
5 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
6 | import it.unimi.dsi.fastutil.objects.ObjectArrayList;
7 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
8 | import net.minecraft.Util;
9 | import net.minecraft.client.multiplayer.ClientLevel;
10 | import net.minecraft.client.player.AbstractClientPlayer;
11 | import net.minecraft.util.AbortableIterationConsumer;
12 | import net.minecraft.world.entity.Entity;
13 | import net.minecraft.world.entity.EntityType;
14 | import net.minecraft.advancements.critereon.MinMaxBounds;
15 | import net.minecraft.network.chat.Component;
16 | import net.minecraft.network.chat.ComponentUtils;
17 | import net.minecraft.world.flag.FeatureFlagSet;
18 | import net.minecraft.world.level.entity.EntityTypeTest;
19 | import net.minecraft.world.phys.AABB;
20 | import net.minecraft.world.phys.Vec3;
21 | import org.jetbrains.annotations.Nullable;
22 |
23 | import java.util.Collections;
24 | import java.util.List;
25 | import java.util.UUID;
26 | import java.util.function.BiConsumer;
27 | import java.util.function.Function;
28 | import java.util.function.Predicate;
29 | import java.util.stream.Collectors;
30 |
31 | public class CEntitySelector {
32 | public static final int INFINITE = Integer.MAX_VALUE;
33 | public static final BiConsumer> ORDER_ARBITRARY = (center, entityList) -> {};
34 | private static final EntityTypeTest ANY_TYPE = new EntityTypeTest<>() {
35 | public Entity tryCast(Entity entity) {
36 | return entity;
37 | }
38 |
39 | @Override
40 | public Class extends Entity> getBaseClass() {
41 | return Entity.class;
42 | }
43 | };
44 | private final int maxResults;
45 | private final boolean includesEntities;
46 | private final boolean worldLimited;
47 | private final List> contextFreePredicates;
48 | private final MinMaxBounds.Doubles range;
49 | private final Function position;
50 | @Nullable
51 | private final AABB aabb;
52 | private final BiConsumer> order;
53 | private final boolean currentEntity;
54 | @Nullable
55 | private final String playerName;
56 | @Nullable
57 | private final UUID entityUUID;
58 | private final EntityTypeTest type;
59 | private final boolean usesSelector;
60 |
61 | public CEntitySelector(int maxResults, boolean includesEntities, boolean worldLimited, List> contextFreePredicates, MinMaxBounds.Doubles range, Function position, @Nullable AABB aabb, BiConsumer> order, boolean currentEntity, @Nullable String playerName, @Nullable UUID entityUUID, @Nullable EntityType> type, boolean usesSelector) {
62 | this.maxResults = maxResults;
63 | this.includesEntities = includesEntities;
64 | this.worldLimited = worldLimited;
65 | this.contextFreePredicates = contextFreePredicates;
66 | this.range = range;
67 | this.position = position;
68 | this.aabb = aabb;
69 | this.order = order;
70 | this.currentEntity = currentEntity;
71 | this.playerName = playerName;
72 | this.entityUUID = entityUUID;
73 | this.type = type == null ? ANY_TYPE : type;
74 | this.usesSelector = usesSelector;
75 | }
76 |
77 | public int getMaxResults() {
78 | return this.maxResults;
79 | }
80 |
81 | public boolean includesEntities() {
82 | return this.includesEntities;
83 | }
84 |
85 | public boolean isSelfSelector() {
86 | return this.currentEntity;
87 | }
88 |
89 | public boolean isWorldLimited() {
90 | return this.worldLimited;
91 | }
92 |
93 | public boolean usesSelector() {
94 | return this.usesSelector;
95 | }
96 |
97 | public Entity findSingleEntity(FabricClientCommandSource source) throws CommandSyntaxException {
98 | List extends Entity> list = this.findEntities(source);
99 | if (list.isEmpty()) {
100 | throw CEntityArgument.ENTITY_NOT_FOUND_EXCEPTION.create();
101 | }
102 | if (list.size() > 1) {
103 | throw CEntityArgument.TOO_MANY_ENTITIES_EXCEPTION.create();
104 | }
105 | return list.getFirst();
106 | }
107 |
108 | public List extends Entity> findEntities(FabricClientCommandSource source) throws CommandSyntaxException {
109 | if (!this.includesEntities) {
110 | return this.findPlayers(source);
111 | }
112 | if (this.playerName != null) {
113 | AbstractClientPlayer abstractClientPlayer = Streams.stream(source.getWorld().entitiesForRendering())
114 | .filter(entity -> entity instanceof AbstractClientPlayer)
115 | .map(entity -> (AbstractClientPlayer) entity)
116 | .filter(abstractPlayer -> abstractPlayer.getName().getString().equals(this.playerName))
117 | .findAny().orElse(null);
118 | return abstractClientPlayer == null ? Collections.emptyList() : Lists.newArrayList(abstractClientPlayer);
119 | }
120 | if (this.entityUUID != null) {
121 | Entity foundEntity = Streams.stream(source.getWorld().entitiesForRendering())
122 | .filter(entity -> entity.getUUID().equals(this.entityUUID))
123 | .findAny().orElse(null);
124 | return foundEntity == null ? Collections.emptyList() : Lists.newArrayList(foundEntity);
125 | }
126 |
127 | Vec3 vec3 = this.position.apply(source.getPosition());
128 | AABB aabb = this.getAbsoluteAabb(vec3);
129 | Predicate predicate = this.getPredicate(vec3, aabb, null);
130 | if (this.currentEntity) {
131 | return source.getEntity() != null && predicate.test(source.getEntity())
132 | ? Lists.newArrayList(source.getEntity())
133 | : Collections.emptyList();
134 | }
135 | List list = Lists.newArrayList();
136 | this.addEntities(list, source.getWorld(), aabb, predicate);
137 | return list;
138 | }
139 |
140 | private void addEntities(List entities, ClientLevel level, @Nullable AABB box, Predicate predicate) {
141 | int resultLimit = this.getResultLimit();
142 | if (entities.size() < resultLimit) {
143 | if (box != null) {
144 | level.getEntities(this.type, box, predicate, entities, resultLimit);
145 | } else {
146 | level.getEntities().get(this.type, entity -> {
147 | if (predicate.test(entity)) {
148 | entities.add(entity);
149 | if (entities.size() >= maxResults) {
150 | return AbortableIterationConsumer.Continuation.ABORT;
151 | }
152 | }
153 |
154 | return AbortableIterationConsumer.Continuation.CONTINUE;
155 | });
156 | }
157 | }
158 | }
159 |
160 | private int getResultLimit() {
161 | return this.order == ORDER_ARBITRARY ? this.maxResults : INFINITE;
162 | }
163 |
164 | public AbstractClientPlayer findSinglePlayer(FabricClientCommandSource source) throws CommandSyntaxException {
165 | List list = this.findPlayers(source);
166 | if (list.size() != 1) {
167 | throw CEntityArgument.PLAYER_NOT_FOUND_EXCEPTION.create();
168 | }
169 | return list.getFirst();
170 | }
171 |
172 | public List findPlayers(FabricClientCommandSource source) throws CommandSyntaxException {
173 | AbstractClientPlayer abstractClientPlayer;
174 | if (this.playerName != null) {
175 | abstractClientPlayer = Streams.stream(source.getWorld().entitiesForRendering())
176 | .filter(entity -> entity instanceof AbstractClientPlayer)
177 | .map(entity -> (AbstractClientPlayer) entity)
178 | .filter(abstractPlayer -> abstractPlayer.getName().getString().equals(this.playerName))
179 | .findAny().orElse(null);
180 | return abstractClientPlayer == null ? Collections.emptyList() : Lists.newArrayList(abstractClientPlayer);
181 | }
182 | if (this.entityUUID != null) {
183 | abstractClientPlayer = Streams.stream(source.getWorld().entitiesForRendering())
184 | .filter(entity -> entity instanceof AbstractClientPlayer)
185 | .map(entity -> (AbstractClientPlayer) entity)
186 | .filter(entity -> entity.getUUID().equals(this.entityUUID))
187 | .findAny().orElse(null);
188 | return abstractClientPlayer == null ? Collections.emptyList() : Lists.newArrayList(abstractClientPlayer);
189 | }
190 | Vec3 vec3d = this.position.apply(source.getPosition());
191 | Predicate predicate = this.getPredicate(vec3d, this.getAbsoluteAabb(vec3d), null);
192 | if (this.currentEntity) {
193 | if (source.getEntity() instanceof AbstractClientPlayer player && predicate.test(player)) {
194 | return Lists.newArrayList(player);
195 | }
196 |
197 | return Collections.emptyList();
198 | }
199 | List entities = source.getWorld().players().stream()
200 | .filter(predicate)
201 | .limit(this.getResultLimit())
202 | .collect(Collectors.toList());
203 |
204 | return this.sortAndLimit(vec3d, entities);
205 | }
206 |
207 | @Nullable
208 | private AABB getAbsoluteAabb(Vec3 pos) {
209 | return this.aabb != null ? this.aabb.move(pos) : null;
210 | }
211 |
212 | private Predicate getPredicate(Vec3 pos, @Nullable AABB box, @Nullable FeatureFlagSet enabledFeatures) {
213 | boolean bl = enabledFeatures != null;
214 | boolean bl2 = box != null;
215 | boolean bl3 = !this.range.isAny();
216 | int i = (bl ? 1 : 0) + (bl2 ? 1 : 0) + (bl3 ? 1 : 0);
217 | List> list;
218 | if (i == 0) {
219 | list = this.contextFreePredicates;
220 | } else {
221 | List> list2 = new ObjectArrayList<>(this.contextFreePredicates.size() + i);
222 | list2.addAll(this.contextFreePredicates);
223 | if (bl) {
224 | list2.add(entity -> entity.getType().isEnabled(enabledFeatures));
225 | }
226 |
227 | if (bl2) {
228 | list2.add(entity -> box.intersects(entity.getBoundingBox()));
229 | }
230 |
231 | if (bl3) {
232 | list2.add(entity -> this.range.matchesSqr(entity.distanceToSqr(pos)));
233 | }
234 |
235 | list = list2;
236 | }
237 |
238 | return Util.allOf(list);
239 | }
240 |
241 | private List sortAndLimit(Vec3 pos, List entities) {
242 | if (entities.size() > 1) {
243 | this.order.accept(pos, entities);
244 | }
245 |
246 | return entities.subList(0, Math.min(this.maxResults, entities.size()));
247 | }
248 |
249 | public static Component joinNames(List extends Entity> names) {
250 | return ComponentUtils.formatList(names, Entity::getDisplayName);
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CEnumArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.gson.JsonPrimitive;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.arguments.ArgumentType;
6 | import com.mojang.brigadier.context.CommandContext;
7 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
8 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
9 | import com.mojang.brigadier.suggestion.Suggestions;
10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
11 | import com.mojang.serialization.Codec;
12 | import com.mojang.serialization.JsonOps;
13 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
14 | import net.minecraft.commands.SharedSuggestionProvider;
15 | import net.minecraft.network.chat.Component;
16 | import net.minecraft.util.StringRepresentable;
17 |
18 | import java.util.Arrays;
19 | import java.util.Collection;
20 | import java.util.concurrent.CompletableFuture;
21 | import java.util.function.Supplier;
22 | import java.util.stream.Collectors;
23 |
24 | public class CEnumArgument & StringRepresentable> implements ArgumentType {
25 |
26 | private static final DynamicCommandExceptionType INVALID_ENUM_EXCEPTION = new DynamicCommandExceptionType((value) -> Component.translatable("argument.enum.invalid", value));
27 | private final Codec codec;
28 | private final Supplier valuesSupplier;
29 |
30 | private CEnumArgument(Codec codec, Supplier valuesSupplier) {
31 | this.codec = codec;
32 | this.valuesSupplier = valuesSupplier;
33 | }
34 |
35 | public static & StringRepresentable> CEnumArgument enumArg(Class enumClass) {
36 | return new CEnumArgument<>(StringRepresentable.fromEnum(enumClass::getEnumConstants), enumClass::getEnumConstants);
37 | }
38 |
39 | @SuppressWarnings("unchecked")
40 | public static & StringRepresentable> T getEnum(CommandContext context, String name) {
41 | return (T) context.getArgument(name, Enum.class);
42 | }
43 |
44 | public T parse(final StringReader stringReader) throws CommandSyntaxException {
45 | String string = stringReader.readUnquotedString();
46 | return this.codec.parse(JsonOps.INSTANCE, new JsonPrimitive(string)).result().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(string));
47 | }
48 |
49 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
50 | return SharedSuggestionProvider.suggest(Arrays.stream(this.valuesSupplier.get()).map(StringRepresentable::getSerializedName).map(this::transformValueName).collect(Collectors.toList()), builder);
51 | }
52 |
53 | public Collection getExamples() {
54 | return Arrays.stream(this.valuesSupplier.get()).map(StringRepresentable::getSerializedName).map(this::transformValueName).limit(2L).collect(Collectors.toList());
55 | }
56 |
57 | protected String transformValueName(String name) {
58 | return name;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CGameProfileArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.mojang.authlib.GameProfile;
5 | import com.mojang.brigadier.StringReader;
6 | import com.mojang.brigadier.arguments.ArgumentType;
7 | import com.mojang.brigadier.context.CommandContext;
8 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
9 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
10 | import com.mojang.brigadier.suggestion.Suggestions;
11 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
12 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
13 | import net.minecraft.client.Minecraft;
14 | import net.minecraft.client.multiplayer.PlayerInfo;
15 | import net.minecraft.client.player.AbstractClientPlayer;
16 | import net.minecraft.commands.SharedSuggestionProvider;
17 | import net.minecraft.network.chat.Component;
18 |
19 | import java.util.Collection;
20 | import java.util.Arrays;
21 | import java.util.Collections;
22 | import java.util.List;
23 | import java.util.concurrent.CompletableFuture;
24 |
25 | public class CGameProfileArgument implements ArgumentType {
26 | private static final Collection EXAMPLES = Arrays.asList("Player", "0123", "dd12be42-52a9-4a91-a8a1-11c01849e498", "@e");
27 | public static final SimpleCommandExceptionType UNKNOWN_PLAYER_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("argument.player.unknown"));
28 |
29 | private final boolean singleTarget;
30 |
31 | private CGameProfileArgument(boolean singleTarget) {
32 | this.singleTarget = singleTarget;
33 | }
34 |
35 | public static CGameProfileArgument gameProfile() {
36 | return new CGameProfileArgument(false);
37 | }
38 |
39 | public static CGameProfileArgument gameProfile(boolean singleTarget) {
40 | return new CGameProfileArgument(singleTarget);
41 | }
42 |
43 | public static Collection getProfileArgument(final CommandContext context, final String name) throws CommandSyntaxException {
44 | return context.getArgument(name, Result.class).getNames(context.getSource());
45 | }
46 |
47 | public static GameProfile getSingleProfileArgument(final CommandContext context, final String name) throws CommandSyntaxException {
48 | Collection profiles = context.getArgument(name, Result.class).getNames(context.getSource());
49 | if (profiles.size() > 1) {
50 | throw CEntityArgument.TOO_MANY_PLAYERS_EXCEPTION.create();
51 | }
52 | return profiles.iterator().next();
53 | }
54 |
55 | public CGameProfileArgument.Result parse(final StringReader stringReader, final S source) throws CommandSyntaxException {
56 | return parse(stringReader, CEntitySelectorParser.allowSelectors(source));
57 | }
58 |
59 | @Override
60 | public Result parse(final StringReader stringReader) throws CommandSyntaxException {
61 | return parse(stringReader, true);
62 | }
63 |
64 | private CGameProfileArgument.Result parse(StringReader stringReader, boolean allowSelectors) throws CommandSyntaxException {
65 | if (stringReader.canRead() && stringReader.peek() == CEntitySelectorParser.SYNTAX_SELECTOR_START) {
66 | CEntitySelectorParser entitySelectorParser = new CEntitySelectorParser(stringReader, allowSelectors);
67 | CEntitySelector entitySelector = entitySelectorParser.parse();
68 | if (entitySelector.includesEntities()) {
69 | throw CEntityArgument.PLAYER_SELECTOR_HAS_ENTITIES_EXCEPTION.createWithContext(stringReader);
70 | }
71 | if (this.singleTarget && entitySelector.getMaxResults() > 1) {
72 | throw CEntityArgument.TOO_MANY_PLAYERS_EXCEPTION.create();
73 | }
74 | return new SelectorResult(entitySelector);
75 | }
76 |
77 | int cursor = stringReader.getCursor();
78 | while (stringReader.canRead() && stringReader.peek() != ' ') {
79 | stringReader.skip();
80 | }
81 |
82 | String playerName = stringReader.getString().substring(cursor, stringReader.getCursor());
83 | return source -> Collections.singleton(Minecraft.getInstance().getConnection().getOnlinePlayers().stream()
84 | .map(PlayerInfo::getProfile)
85 | .filter(profile -> profile.getName().equals(playerName))
86 | .findFirst().orElseThrow(UNKNOWN_PLAYER_EXCEPTION::create));
87 | }
88 |
89 | @Override
90 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
91 | if (context.getSource() instanceof SharedSuggestionProvider sharedSuggestionProvider) {
92 | StringReader stringReader = new StringReader(builder.getInput());
93 | stringReader.setCursor(builder.getStart());
94 | CEntitySelectorParser entitySelectorParser = new CEntitySelectorParser(stringReader, CEntitySelectorParser.allowSelectors(sharedSuggestionProvider));
95 |
96 | try {
97 | entitySelectorParser.parse();
98 | } catch (CommandSyntaxException ignored) {
99 | }
100 |
101 | return entitySelectorParser.fillSuggestions(builder, builderx -> SharedSuggestionProvider.suggest(((SharedSuggestionProvider) context.getSource()).getOnlinePlayerNames(), builderx));
102 | }
103 | return Suggestions.empty();
104 | }
105 |
106 | @Override
107 | public Collection getExamples() {
108 | return EXAMPLES;
109 | }
110 |
111 | @FunctionalInterface
112 | public interface Result {
113 | Collection getNames(FabricClientCommandSource source) throws CommandSyntaxException;
114 | }
115 |
116 | public static class SelectorResult implements Result {
117 | private final CEntitySelector selector;
118 |
119 | public SelectorResult(CEntitySelector selector) {
120 | this.selector = selector;
121 | }
122 |
123 | @Override
124 | public Collection getNames(FabricClientCommandSource fabricClientCommandSource) throws CommandSyntaxException {
125 | List list = this.selector.findPlayers(fabricClientCommandSource);
126 | if (list.isEmpty()) {
127 | throw CEntityArgument.PLAYER_NOT_FOUND_EXCEPTION.create();
128 | }
129 | List list2 = Lists.newArrayList();
130 |
131 | for (AbstractClientPlayer abstractClientPlayer : list) {
132 | list2.add(abstractClientPlayer.getGameProfile());
133 | }
134 |
135 | return list2;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CItemArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.suggestion.Suggestions;
8 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
9 | import net.minecraft.commands.CommandBuildContext;
10 | import net.minecraft.commands.arguments.item.ItemInput;
11 | import net.minecraft.commands.arguments.item.ItemParser;
12 |
13 | import java.util.Arrays;
14 | import java.util.Collection;
15 | import java.util.concurrent.CompletableFuture;
16 |
17 | public class CItemArgument implements ArgumentType {
18 | private static final Collection EXAMPLES = Arrays.asList("stick", "minecraft:stick", "stick{foo=bar}");
19 | private final ItemParser reader;
20 |
21 | public CItemArgument(CommandBuildContext commandBuildContext) {
22 | this.reader = new ItemParser(commandBuildContext);
23 | }
24 |
25 | public static CItemArgument itemStack(CommandBuildContext commandBuildContext) {
26 | return new CItemArgument(commandBuildContext);
27 | }
28 |
29 | public static ItemInput getItemStackArgument(final CommandContext context, final String name) {
30 | return context.getArgument(name, ItemInput.class);
31 | }
32 |
33 | @Override
34 | public ItemInput parse(final StringReader stringReader) throws CommandSyntaxException {
35 | ItemParser.ItemResult itemResult = this.reader.parse(stringReader);
36 | return new ItemInput(itemResult.item(), itemResult.components());
37 | }
38 |
39 | @Override
40 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
41 | return this.reader.fillSuggestions(builder);
42 | }
43 |
44 | @Override
45 | public Collection getExamples() {
46 | return EXAMPLES;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CItemPredicateArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.ImmutableStringReader;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.arguments.ArgumentType;
6 | import com.mojang.brigadier.context.CommandContext;
7 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
8 | import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
9 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
10 | import com.mojang.brigadier.suggestion.Suggestions;
11 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
12 | import com.mojang.serialization.Codec;
13 | import com.mojang.serialization.DataResult;
14 | import com.mojang.serialization.Decoder;
15 | import java.util.Arrays;
16 | import java.util.Collection;
17 | import java.util.List;
18 | import java.util.Map;
19 | import java.util.Objects;
20 | import java.util.concurrent.CompletableFuture;
21 | import java.util.function.Predicate;
22 | import java.util.stream.Collectors;
23 | import java.util.stream.Stream;
24 |
25 | import com.mojang.serialization.Dynamic;
26 | import net.minecraft.commands.CommandBuildContext;
27 | import net.minecraft.core.component.predicates.DataComponentPredicate;
28 | import net.minecraft.util.parsing.packrat.commands.Grammar;
29 | import net.minecraft.commands.arguments.item.ComponentPredicateParser;
30 | import net.minecraft.core.component.DataComponentType;
31 | import net.minecraft.world.item.Item;
32 | import net.minecraft.world.item.ItemStack;
33 | import net.minecraft.advancements.critereon.MinMaxBounds;
34 | import net.minecraft.resources.ResourceKey;
35 | import net.minecraft.core.registries.Registries;
36 | import net.minecraft.resources.RegistryOps;
37 | import net.minecraft.core.HolderLookup;
38 | import net.minecraft.core.Holder;
39 | import net.minecraft.core.HolderSet;
40 | import net.minecraft.tags.TagKey;
41 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
42 | import net.minecraft.network.chat.Component;
43 | import net.minecraft.resources.ResourceLocation;
44 | import net.minecraft.Util;
45 |
46 | public class CItemPredicateArgument implements ArgumentType {
47 | private static final Collection EXAMPLES = Arrays.asList("stick", "minecraft:stick", "#stick", "#stick{foo:'bar'}");
48 | static final DynamicCommandExceptionType INVALID_ITEM_ID_EXCEPTION = new DynamicCommandExceptionType(object -> Component.translatableEscape("argument.item.id.invalid", object));
49 | static final DynamicCommandExceptionType UNKNOWN_ITEM_TAG_EXCEPTION = new DynamicCommandExceptionType(object -> Component.translatableEscape("arguments.item.tag.unknown", object));
50 | static final DynamicCommandExceptionType UNKNOWN_ITEM_COMPONENT_EXCEPTION = new DynamicCommandExceptionType(object -> Component.translatableEscape("arguments.item.component.unknown", object));
51 | static final Dynamic2CommandExceptionType MALFORMED_ITEM_COMPONENT_EXCEPTION = new Dynamic2CommandExceptionType((object, object2) -> Component.translatableEscape("arguments.item.component.malformed", object, object2));
52 | static final DynamicCommandExceptionType UNKNOWN_ITEM_PREDICATE_EXCEPTION = new DynamicCommandExceptionType(object -> Component.translatableEscape("arguments.item.predicate.unknown", object));
53 | static final Dynamic2CommandExceptionType MALFORMED_ITEM_PREDICATE_EXCEPTION = new Dynamic2CommandExceptionType((object, object2) -> Component.translatableEscape("arguments.item.predicate.malformed", object, object2));
54 | private static final ResourceLocation COUNT_ID = ResourceLocation.withDefaultNamespace("count");
55 | static final Map SPECIAL_COMPONENT_CHECKS = Stream.of(new ComponentWrapper(COUNT_ID, stack -> true, MinMaxBounds.Ints.CODEC.map(range -> stack -> range.matches(stack.getCount())))).collect(Collectors.toUnmodifiableMap(ComponentWrapper::id, check -> check));
56 | static final Map SPECIAL_SUB_PREDICATE_CHECKS = Stream.of(new PredicateWrapper(COUNT_ID, MinMaxBounds.Ints.CODEC.map(range -> stack -> range.matches(stack.getCount())))).collect(Collectors.toUnmodifiableMap(PredicateWrapper::id, check -> check));
57 | private final Grammar>> parser;
58 |
59 | public CItemPredicateArgument(CommandBuildContext commandBuildContext) {
60 | Context context = new Context(commandBuildContext);
61 | this.parser = ComponentPredicateParser.createGrammar(context);
62 | }
63 |
64 | public static CItemPredicateArgument itemPredicate(CommandBuildContext commandRegistryAccess) {
65 | return new CItemPredicateArgument(commandRegistryAccess);
66 | }
67 |
68 | @Override
69 | public CItemStackPredicateArgument parse(final StringReader stringReader) throws CommandSyntaxException {
70 | return Util.allOf(this.parser.parseForCommands(stringReader))::test;
71 | }
72 |
73 | public static CItemStackPredicateArgument getItemStackPredicate(final CommandContext context, String name) {
74 | return context.getArgument(name, CItemStackPredicateArgument.class);
75 | }
76 |
77 | @Override
78 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
79 | return this.parser.parseForSuggestions(builder);
80 | }
81 |
82 | @Override
83 | public Collection getExamples() {
84 | return EXAMPLES;
85 | }
86 |
87 | record ComponentWrapper(ResourceLocation id, Predicate presenceChecker, Decoder extends Predicate> valueChecker) {
88 | public static ComponentWrapper read(ImmutableStringReader reader, ResourceLocation id, DataComponentType type) throws CommandSyntaxException {
89 | Codec codec = type.codec();
90 | if (codec == null) {
91 | throw UNKNOWN_ITEM_COMPONENT_EXCEPTION.createWithContext(reader, id);
92 | }
93 | return new ComponentWrapper(id, stack -> stack.has(type), codec.map(expected -> stack -> {
94 | T object2 = stack.get(type);
95 | return Objects.equals(expected, object2);
96 | }));
97 | }
98 |
99 | public Predicate createPredicate(ImmutableStringReader reader, Dynamic> nbt) throws CommandSyntaxException {
100 | DataResult extends Predicate> dataResult = this.valueChecker.parse(nbt);
101 | return dataResult.getOrThrow(error -> MALFORMED_ITEM_COMPONENT_EXCEPTION.createWithContext(reader, this.id.toString(), error));
102 | }
103 | }
104 |
105 | public interface CItemStackPredicateArgument extends Predicate {
106 | }
107 |
108 | record PredicateWrapper(ResourceLocation id, Decoder extends Predicate> type) {
109 | public PredicateWrapper(Holder.Reference> type) {
110 | this(type.key().location(), type.value().codec().map(predicate -> predicate::matches));
111 | }
112 |
113 | public Predicate createPredicate(ImmutableStringReader reader, Dynamic> nbt) throws CommandSyntaxException {
114 | DataResult extends Predicate> dataResult = this.type.parse(nbt);
115 | return dataResult.getOrThrow(error -> MALFORMED_ITEM_PREDICATE_EXCEPTION.createWithContext(reader, this.id.toString(), error));
116 | }
117 | }
118 |
119 | static class Context implements ComponentPredicateParser.Context, ComponentWrapper, PredicateWrapper> {
120 | private final HolderLookup.Provider registries;
121 | private final HolderLookup.RegistryLookup- itemHolderLookup;
122 | private final HolderLookup.RegistryLookup> dataComponentTypeHolderLookup;
123 | private final HolderLookup.RegistryLookup> itemSubPredicateTypeHolderLookup;
124 |
125 | Context(HolderLookup.Provider registries) {
126 | this.registries = registries;
127 | this.itemHolderLookup = registries.lookupOrThrow(Registries.ITEM);
128 | this.dataComponentTypeHolderLookup = registries.lookupOrThrow(Registries.DATA_COMPONENT_TYPE);
129 | this.itemSubPredicateTypeHolderLookup = registries.lookupOrThrow(Registries.DATA_COMPONENT_PREDICATE_TYPE);
130 | }
131 |
132 | @Override
133 | public Predicate forElementType(ImmutableStringReader immutableStringReader, ResourceLocation id) throws CommandSyntaxException {
134 | Holder.Reference
- reference = this.itemHolderLookup
135 | .get(ResourceKey.create(Registries.ITEM, id))
136 | .orElseThrow(() -> INVALID_ITEM_ID_EXCEPTION.createWithContext(immutableStringReader, id));
137 | return stack -> stack.is(reference);
138 | }
139 |
140 | @Override
141 | public Predicate forTagType(ImmutableStringReader immutableStringReader, ResourceLocation id) throws CommandSyntaxException {
142 | HolderSet
- registryEntryList = this.itemHolderLookup
143 | .get(TagKey.create(Registries.ITEM, id))
144 | .orElseThrow(() -> UNKNOWN_ITEM_TAG_EXCEPTION.createWithContext(immutableStringReader, id));
145 | return stack -> stack.is(registryEntryList);
146 | }
147 |
148 | @Override
149 | public ComponentWrapper lookupComponentType(ImmutableStringReader immutableStringReader, ResourceLocation id) throws CommandSyntaxException {
150 | ComponentWrapper componentWrapper = SPECIAL_COMPONENT_CHECKS.get(id);
151 | if (componentWrapper != null) {
152 | return componentWrapper;
153 | }
154 | DataComponentType> dataComponentType = this.dataComponentTypeHolderLookup
155 | .get(ResourceKey.create(Registries.DATA_COMPONENT_TYPE, id))
156 | .map(Holder::value)
157 | .orElseThrow(() -> UNKNOWN_ITEM_COMPONENT_EXCEPTION.createWithContext(immutableStringReader, id));
158 | return ComponentWrapper.read(immutableStringReader, id, dataComponentType);
159 | }
160 |
161 | @Override
162 | public Predicate createComponentTest(ImmutableStringReader immutableStringReader, ComponentWrapper componentWrapper, Dynamic> nbtElement) throws CommandSyntaxException {
163 | return componentWrapper.createPredicate(immutableStringReader, RegistryOps.injectRegistryContext(nbtElement, registries));
164 | }
165 |
166 | @Override
167 | public Predicate createComponentTest(ImmutableStringReader immutableStringReader, ComponentWrapper componentWrapper) {
168 | return componentWrapper.presenceChecker;
169 | }
170 |
171 | @Override
172 | public PredicateWrapper lookupPredicateType(ImmutableStringReader immutableStringReader, ResourceLocation id) throws CommandSyntaxException {
173 | PredicateWrapper predicateWrapper = SPECIAL_SUB_PREDICATE_CHECKS.get(id);
174 | return predicateWrapper != null ? predicateWrapper : this.itemSubPredicateTypeHolderLookup
175 | .get(ResourceKey.create(Registries.DATA_COMPONENT_PREDICATE_TYPE, id))
176 | .map(PredicateWrapper::new)
177 | .orElseThrow(() -> UNKNOWN_ITEM_PREDICATE_EXCEPTION.createWithContext(immutableStringReader, id));
178 | }
179 |
180 | @Override
181 | public Predicate createPredicateTest(ImmutableStringReader immutableStringReader, PredicateWrapper predicateWrapper, Dynamic> nbtElement) throws CommandSyntaxException {
182 | return predicateWrapper.createPredicate(immutableStringReader, RegistryOps.injectRegistryContext(nbtElement, registries));
183 | }
184 |
185 | @Override
186 | public Stream listElementTypes() {
187 | return this.itemHolderLookup.listElementIds().map(ResourceKey::location);
188 | }
189 |
190 | @Override
191 | public Stream listTagTypes() {
192 | return this.itemHolderLookup.listTagIds().map(TagKey::location);
193 | }
194 |
195 | @Override
196 | public Stream listComponentTypes() {
197 | return Stream.concat(
198 | SPECIAL_COMPONENT_CHECKS.keySet().stream(),
199 | this.dataComponentTypeHolderLookup
200 | .listElements()
201 | .filter(entry -> !entry.value().isTransient())
202 | .map(entry -> entry.key().location())
203 | );
204 | }
205 |
206 | @Override
207 | public Stream listPredicateTypes() {
208 | return Stream.concat(SPECIAL_SUB_PREDICATE_CHECKS.keySet().stream(), this.itemSubPredicateTypeHolderLookup.listElementIds().map(ResourceKey::location));
209 | }
210 |
211 | @Override
212 | public Predicate negate(Predicate predicate) {
213 | return predicate.negate();
214 | }
215 |
216 | @Override
217 | public Predicate anyOf(List> list) {
218 | return Util.anyOf(list);
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CLocalCoordinates.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
5 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
6 | import net.minecraft.commands.arguments.coordinates.WorldCoordinate;
7 | import net.minecraft.util.Mth;
8 | import net.minecraft.world.phys.Vec2;
9 | import net.minecraft.world.phys.Vec3;
10 |
11 | import java.util.Objects;
12 |
13 | public class CLocalCoordinates implements CCoordinates {
14 | private final double x;
15 | private final double y;
16 | private final double z;
17 |
18 | public CLocalCoordinates(double x, double y, double z) {
19 | this.x = x;
20 | this.y = y;
21 | this.z = z;
22 | }
23 |
24 | @Override
25 | public Vec3 getPosition(FabricClientCommandSource source) {
26 | Vec2 vec2 = source.getRotation();
27 | Vec3 vec3 = CEntityAnchorArgument.EntityAnchor.FEET.positionAt(source);
28 | float f = Mth.cos((vec2.y + 90.0F) * (float) (Math.PI / 180.0));
29 | float g = Mth.sin((vec2.y + 90.0F) * (float) (Math.PI / 180.0));
30 | float h = Mth.cos(-vec2.x * (float) (Math.PI / 180.0));
31 | float i = Mth.sin(-vec2.x * (float) (Math.PI / 180.0));
32 | float j = Mth.cos((-vec2.x + 90.0F) * (float) (Math.PI / 180.0));
33 | float k = Mth.sin((-vec2.x + 90.0F) * (float) (Math.PI / 180.0));
34 | Vec3 vec32 = new Vec3(f * h, i, g * h);
35 | Vec3 vec33 = new Vec3(f * j, k, g * j);
36 | Vec3 vec34 = vec32.cross(vec33).scale(-1.0);
37 | double d = vec32.x * this.z + vec33.x * this.y + vec34.x * this.x;
38 | double e = vec32.y * this.z + vec33.y * this.y + vec34.y * this.x;
39 | double l = vec32.z * this.z + vec33.z * this.y + vec34.z * this.x;
40 | return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l);
41 | }
42 |
43 | @Override
44 | public Vec2 getRotation(FabricClientCommandSource source) {
45 | return Vec2.ZERO;
46 | }
47 |
48 | @Override
49 | public boolean isXRelative() {
50 | return true;
51 | }
52 |
53 | @Override
54 | public boolean isYRelative() {
55 | return true;
56 | }
57 |
58 | @Override
59 | public boolean isZRelative() {
60 | return true;
61 | }
62 |
63 | public static CLocalCoordinates parse(StringReader reader) throws CommandSyntaxException {
64 | int cursor = reader.getCursor();
65 | double d = readCoordinate(reader, cursor);
66 | if (!reader.canRead() || reader.peek() != ' ') {
67 | reader.setCursor(cursor);
68 | throw CVec3Argument.INCOMPLETE_EXCEPTION.createWithContext(reader);
69 | }
70 | reader.skip();
71 | double e = readCoordinate(reader, cursor);
72 | if (!reader.canRead() || reader.peek() != ' ') {
73 | reader.setCursor(cursor);
74 | throw CVec3Argument.INCOMPLETE_EXCEPTION.createWithContext(reader);
75 | }
76 | reader.skip();
77 | double f = readCoordinate(reader, cursor);
78 | return new CLocalCoordinates(d, e, f);
79 | }
80 |
81 | private static double readCoordinate(StringReader reader, int startingCursorPos) throws CommandSyntaxException {
82 | if (!reader.canRead()) {
83 | throw WorldCoordinate.ERROR_EXPECTED_DOUBLE.createWithContext(reader);
84 | }
85 | if (reader.peek() != '^') {
86 | reader.setCursor(startingCursorPos);
87 | throw CVec3Argument.MIXED_COORDINATE_EXCEPTION.createWithContext(reader);
88 | }
89 | reader.skip();
90 | return reader.canRead() && reader.peek() != ' ' ? reader.readDouble() : 0.0;
91 | }
92 |
93 | public boolean equals(Object o) {
94 | if (this == o) {
95 | return true;
96 | }
97 | if (!(o instanceof CLocalCoordinates localCoordinates)) {
98 | return false;
99 | }
100 | return this.x == localCoordinates.x && this.y == localCoordinates.y && this.z == localCoordinates.z;
101 | }
102 |
103 | public int hashCode() {
104 | return Objects.hash(this.x, this.y, this.z);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CMessageArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
8 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
9 | import net.minecraft.commands.arguments.SignedArgument;
10 | import net.minecraft.network.chat.MutableComponent;
11 | import net.minecraft.network.chat.Component;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.util.Arrays;
15 | import java.util.Collection;
16 | import java.util.List;
17 |
18 | public class CMessageArgument implements SignedArgument {
19 | private static final Collection EXAMPLES = Arrays.asList("Hello world!", "foo", "@e", "Hello @p :)");
20 | static final Dynamic2CommandExceptionType TOO_LONG = new Dynamic2CommandExceptionType((length, maxLength) -> Component.translatableEscape("argument.message.too_long", length, maxLength));
21 |
22 | public static CMessageArgument message() {
23 | return new CMessageArgument();
24 | }
25 |
26 | public static Component getMessage(final CommandContext context, final String name) throws CommandSyntaxException {
27 | CMessageArgument.Message message = context.getArgument(name, Message.class);
28 | return message.resolveComponent(context.getSource());
29 | }
30 |
31 | public CMessageArgument.Message parse(final StringReader stringReader) throws CommandSyntaxException {
32 | return CMessageArgument.Message.parseText(stringReader, true);
33 | }
34 |
35 | public
CMessageArgument.Message parse(final StringReader stringReader, final @Nullable S source) throws CommandSyntaxException {
36 | return CMessageArgument.Message.parseText(stringReader, CEntitySelectorParser.allowSelectors(source));
37 | }
38 |
39 | public Collection getExamples() {
40 | return EXAMPLES;
41 | }
42 |
43 | public record Message(String text, CMessageArgument.Part[] parts) {
44 |
45 | Component resolveComponent(FabricClientCommandSource fabricClientCommandSource) throws CommandSyntaxException {
46 | return this.toComponent(fabricClientCommandSource, CEntitySelectorParser.allowSelectors(fabricClientCommandSource));
47 | }
48 |
49 | public Component toComponent(FabricClientCommandSource fabricClientCommandSource, boolean allowSelectors) throws CommandSyntaxException {
50 | if (this.parts.length == 0 || !allowSelectors) {
51 | return Component.literal(this.text);
52 | }
53 |
54 | MutableComponent mutableComponent = Component.literal(this.text.substring(0, this.parts[0].start()));
55 | int i = this.parts[0].start();
56 | for (Part part : this.parts) {
57 | Component component = part.toComponent(fabricClientCommandSource);
58 | if (i < part.start()) {
59 | mutableComponent.append(this.text.substring(i, part.start()));
60 | }
61 | mutableComponent.append(component);
62 | i = part.end();
63 | }
64 |
65 | if (i < this.text.length()) {
66 | mutableComponent.append(this.text.substring(i));
67 | }
68 |
69 | return mutableComponent;
70 | }
71 |
72 | public static CMessageArgument.Message parseText(StringReader stringReader, boolean allowSelectors) throws CommandSyntaxException {
73 | if (stringReader.getRemainingLength() > 256) {
74 | throw CMessageArgument.TOO_LONG.create(stringReader.getRemainingLength(), 256);
75 | }
76 | String string = stringReader.getRemaining();
77 | if (!allowSelectors) {
78 | stringReader.setCursor(stringReader.getTotalLength());
79 | return new CMessageArgument.Message(string, new CMessageArgument.Part[0]);
80 | }
81 | List list = Lists.newArrayList();
82 | int cursor = stringReader.getCursor();
83 | while (true) {
84 | int j;
85 | CEntitySelector entitySelector;
86 | while (true) {
87 | if (!stringReader.canRead()) {
88 | return new CMessageArgument.Message(string, list.toArray(new CMessageArgument.Part[0]));
89 | }
90 | if (stringReader.peek() == CEntitySelectorParser.SYNTAX_SELECTOR_START) {
91 | j = stringReader.getCursor();
92 |
93 | try {
94 | CEntitySelectorParser entitySelectorParser = new CEntitySelectorParser(stringReader, true);
95 | entitySelector = entitySelectorParser.parse();
96 | break;
97 | } catch (CommandSyntaxException var8) {
98 | if (var8.getType() != CEntitySelectorParser.ERROR_MISSING_SELECTOR_TYPE
99 | && var8.getType() != CEntitySelectorParser.ERROR_UNKNOWN_SELECTOR_TYPE) {
100 | throw var8;
101 | }
102 | stringReader.setCursor(j + 1);
103 | }
104 | } else {
105 | stringReader.skip();
106 | }
107 | }
108 | list.add(new CMessageArgument.Part(j - cursor, stringReader.getCursor() - cursor, entitySelector));
109 | }
110 | }
111 | }
112 |
113 | public record Part(int start, int end, CEntitySelector selector) {
114 | public Component toComponent(FabricClientCommandSource fabricClientCommandSource) throws CommandSyntaxException {
115 | return CEntitySelector.joinNames(this.selector.findEntities(fabricClientCommandSource));
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CNbtTagArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.context.CommandContext;
4 | import net.minecraft.nbt.NbtOps;
5 | import net.minecraft.nbt.SnbtGrammar;
6 | import net.minecraft.nbt.Tag;
7 | import net.minecraft.util.parsing.packrat.commands.CommandArgumentParser;
8 | import net.minecraft.util.parsing.packrat.commands.ParserBasedArgument;
9 |
10 | import java.util.Arrays;
11 | import java.util.Collection;
12 |
13 | public class CNbtTagArgument extends ParserBasedArgument {
14 | private static final Collection EXAMPLES = Arrays.asList("0", "0b", "0l", "0.0", "\"foo\"", "{foo=bar}", "[0]");
15 | private static final CommandArgumentParser TAG_PARSER = SnbtGrammar.createParser(NbtOps.INSTANCE);
16 |
17 | private CNbtTagArgument() {
18 | super(TAG_PARSER);
19 | }
20 |
21 | public static CNbtTagArgument nbtTag() {
22 | return new CNbtTagArgument();
23 | }
24 |
25 | public static Tag getNbtTag(final CommandContext context, final String name) {
26 | return context.getArgument(name, Tag.class);
27 | }
28 |
29 | @Override
30 | public Collection getExamples() {
31 | return EXAMPLES;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CObjectiveArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
11 | import net.minecraft.commands.SharedSuggestionProvider;
12 | import net.minecraft.world.scores.Scoreboard;
13 | import net.minecraft.world.scores.Objective;
14 | import net.minecraft.network.chat.Component;
15 |
16 | import java.util.Arrays;
17 | import java.util.Collection;
18 | import java.util.concurrent.CompletableFuture;
19 |
20 | public class CObjectiveArgument implements ArgumentType {
21 | private static final Collection EXAMPLES = Arrays.asList("foo", "*", "012");
22 | private static final DynamicCommandExceptionType UNKNOWN_OBJECTIVE_EXCEPTION = new DynamicCommandExceptionType(name -> Component.translatableEscape("arguments.objective.notFound", name));
23 | private static final DynamicCommandExceptionType READONLY_OBJECTIVE_EXCEPTION = new DynamicCommandExceptionType(name -> Component.translatableEscape("arguments.objective.readonly", name));
24 |
25 | public static CObjectiveArgument objective() {
26 | return new CObjectiveArgument();
27 | }
28 |
29 | public static Objective getObjective(final CommandContext context, final String name) throws CommandSyntaxException {
30 | String string = context.getArgument(name, String.class);
31 | Scoreboard scoreboard = context.getSource().getWorld().getScoreboard();
32 | Objective objective = scoreboard.getObjective(string);
33 | if (objective == null) {
34 | throw UNKNOWN_OBJECTIVE_EXCEPTION.create(string);
35 | }
36 | return objective;
37 | }
38 |
39 | public static Objective getWritableObjective(final CommandContext context, final String name) throws CommandSyntaxException {
40 | Objective scoreboardObjective = getObjective(context, name);
41 | if (scoreboardObjective.getCriteria().isReadOnly()) {
42 | throw READONLY_OBJECTIVE_EXCEPTION.create(scoreboardObjective.getName());
43 | }
44 | return scoreboardObjective;
45 | }
46 |
47 | @Override
48 | public String parse(final StringReader stringReader) throws CommandSyntaxException {
49 | return stringReader.readUnquotedString();
50 | }
51 |
52 | @Override
53 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
54 | if (context.getSource() instanceof FabricClientCommandSource fabricClientCommandSource) {
55 | return SharedSuggestionProvider.suggest(fabricClientCommandSource.getWorld().getScoreboard().getObjectiveNames(), builder);
56 | } else {
57 | return context.getSource() instanceof SharedSuggestionProvider commandSource ? commandSource.customSuggestion(context) : Suggestions.empty();
58 | }
59 | }
60 |
61 | @Override
62 | public Collection getExamples() {
63 | return EXAMPLES;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CObjectiveCriteriaArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.mojang.brigadier.StringReader;
5 | import com.mojang.brigadier.arguments.ArgumentType;
6 | import com.mojang.brigadier.context.CommandContext;
7 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
8 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
9 | import com.mojang.brigadier.suggestion.Suggestions;
10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
11 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
12 | import net.minecraft.commands.SharedSuggestionProvider;
13 | import net.minecraft.core.registries.BuiltInRegistries;
14 | import net.minecraft.world.scores.criteria.ObjectiveCriteria;
15 | import net.minecraft.stats.Stat;
16 | import net.minecraft.stats.StatType;
17 | import net.minecraft.network.chat.Component;
18 |
19 | import java.util.Arrays;
20 | import java.util.Collection;
21 | import java.util.List;
22 | import java.util.concurrent.CompletableFuture;
23 |
24 | public class CObjectiveCriteriaArgument implements ArgumentType {
25 | private static final Collection EXAMPLES = Arrays.asList("foo", "foo.bar.baz", "minecraft:foo");
26 | public static final DynamicCommandExceptionType INVALID_CRITERION_EXCEPTION = new DynamicCommandExceptionType(name -> Component.translatableEscape("argument.criteria.invalid", name));
27 |
28 | private CObjectiveCriteriaArgument() {
29 | }
30 |
31 | public static CObjectiveCriteriaArgument criteria() {
32 | return new CObjectiveCriteriaArgument();
33 | }
34 |
35 | public static ObjectiveCriteria getCriteria(final CommandContext context, final String name) {
36 | return context.getArgument(name, ObjectiveCriteria.class);
37 | }
38 |
39 | @Override
40 | public ObjectiveCriteria parse(final StringReader stringReader) throws CommandSyntaxException {
41 | int cursor = stringReader.getCursor();
42 |
43 | while (stringReader.canRead() && stringReader.peek() != ' ') {
44 | stringReader.skip();
45 | }
46 |
47 | String string = stringReader.getString().substring(cursor, stringReader.getCursor());
48 | return ObjectiveCriteria.byName(string).orElseThrow(() -> {
49 | stringReader.setCursor(cursor);
50 | return INVALID_CRITERION_EXCEPTION.createWithContext(stringReader, string);
51 | });
52 | }
53 |
54 | @Override
55 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
56 | List list = Lists.newArrayList(ObjectiveCriteria.getCustomCriteriaNames());
57 |
58 | for (StatType> statType : BuiltInRegistries.STAT_TYPE) {
59 | for (var object : statType.getRegistry()) {
60 | String string = this.getStatName(statType, object);
61 | list.add(string);
62 | }
63 | }
64 |
65 | return SharedSuggestionProvider.suggest(list, builder);
66 | }
67 |
68 | public String getStatName(StatType stat, Object value) {
69 | return Stat.buildName(stat, (T) value);
70 | }
71 |
72 | @Override
73 | public Collection getExamples() {
74 | return EXAMPLES;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/COperationArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
11 | import net.minecraft.commands.SharedSuggestionProvider;
12 | import net.minecraft.world.scores.ScoreAccess;
13 | import net.minecraft.network.chat.Component;
14 | import net.minecraft.util.Mth;
15 |
16 | import java.util.Arrays;
17 | import java.util.Collection;
18 | import java.util.concurrent.CompletableFuture;
19 |
20 | public class COperationArgument implements ArgumentType {
21 | private static final Collection EXAMPLES = Arrays.asList("=", ">", "<");
22 | private static final SimpleCommandExceptionType INVALID_OPERATION = new SimpleCommandExceptionType(Component.translatable("arguments.operation.invalid"));
23 | private static final SimpleCommandExceptionType DIVISION_ZERO_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("arguments.operation.div0"));
24 |
25 | public static COperationArgument operation() {
26 | return new COperationArgument();
27 | }
28 |
29 | public static COperationArgument.Operation getOperation(final CommandContext context, final String name) {
30 | return context.getArgument(name, COperationArgument.Operation.class);
31 | }
32 |
33 | @Override
34 | public COperationArgument.Operation parse(final StringReader stringReader) throws CommandSyntaxException {
35 | if (!stringReader.canRead()) {
36 | throw INVALID_OPERATION.createWithContext(stringReader);
37 | }
38 | int i = stringReader.getCursor();
39 |
40 | while (stringReader.canRead() && stringReader.peek() != ' ') {
41 | stringReader.skip();
42 | }
43 |
44 | return getOperator(stringReader.getString().substring(i, stringReader.getCursor()));
45 | }
46 |
47 | @Override
48 | public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) {
49 | return SharedSuggestionProvider.suggest(new String[]{"=", "+=", "-=", "*=", "/=", "%=", "<", ">", "><"}, builder);
50 | }
51 |
52 | @Override
53 | public Collection getExamples() {
54 | return EXAMPLES;
55 | }
56 |
57 | private static COperationArgument.Operation getOperator(String operator) throws CommandSyntaxException {
58 | return operator.equals("><") ? (a, b) -> {
59 | int i = a.get();
60 | a.set(b.get());
61 | b.set(i);
62 | } : getIntOperator(operator);
63 | }
64 |
65 | private static COperationArgument.IntOperator getIntOperator(String operator) throws CommandSyntaxException {
66 | return switch(operator) {
67 | case "=" -> (a, b) -> b;
68 | case "+=" -> Integer::sum;
69 | case "-=" -> (a, b) -> a - b;
70 | case "*=" -> (a, b) -> a * b;
71 | case "/=" -> (a, b) -> {
72 | if (b == 0) {
73 | throw DIVISION_ZERO_EXCEPTION.create();
74 | }
75 | return Mth.floorDiv(a, b);
76 | };
77 | case "%=" -> (a, b) -> {
78 | if (b == 0) {
79 | throw DIVISION_ZERO_EXCEPTION.create();
80 | }
81 | return Mth.positiveModulo(a, b);
82 | };
83 | case "<" -> Math::min;
84 | case ">" -> Math::max;
85 | default -> throw INVALID_OPERATION.create();
86 | };
87 | }
88 |
89 | @FunctionalInterface
90 | interface IntOperator extends COperationArgument.Operation {
91 | int apply(int a, int b) throws CommandSyntaxException;
92 |
93 | @Override
94 | default void apply(ScoreAccess scoreAccess, ScoreAccess scoreAccess2) throws CommandSyntaxException {
95 | scoreAccess.set(this.apply(scoreAccess.get(), scoreAccess2.get()));
96 | }
97 | }
98 |
99 | @FunctionalInterface
100 | public interface Operation {
101 | void apply(ScoreAccess a, ScoreAccess b) throws CommandSyntaxException;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/dev/xpple/clientarguments/arguments/CParticleArgument.java:
--------------------------------------------------------------------------------
1 | package dev.xpple.clientarguments.arguments;
2 |
3 | import com.mojang.brigadier.StringReader;
4 | import com.mojang.brigadier.arguments.ArgumentType;
5 | import com.mojang.brigadier.context.CommandContext;
6 | import com.mojang.brigadier.exceptions.CommandSyntaxException;
7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
8 | import com.mojang.brigadier.suggestion.Suggestions;
9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10 | import net.minecraft.commands.CommandBuildContext;
11 | import net.minecraft.commands.SharedSuggestionProvider;
12 | import net.minecraft.nbt.NbtOps;
13 | import net.minecraft.nbt.TagParser;
14 | import net.minecraft.core.particles.ParticleOptions;
15 | import net.minecraft.core.particles.ParticleType;
16 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
17 | import net.minecraft.resources.RegistryOps;
18 | import net.minecraft.resources.ResourceKey;
19 | import net.minecraft.core.registries.Registries;
20 | import net.minecraft.core.HolderLookup;
21 | import net.minecraft.network.chat.Component;
22 | import net.minecraft.resources.ResourceLocation;
23 |
24 | import java.util.Arrays;
25 | import java.util.Collection;
26 | import java.util.concurrent.CompletableFuture;
27 |
28 | public class CParticleArgument implements ArgumentType {
29 | private static final Collection EXAMPLES = Arrays.asList("foo", "foo:bar", "particle{foo:bar}");
30 | public static final DynamicCommandExceptionType UNKNOWN_PARTICLE_EXCEPTION = new DynamicCommandExceptionType(id -> Component.translatableEscape("particle.notFound", id));
31 | public static final DynamicCommandExceptionType INVALID_OPTIONS_EXCEPTION = new DynamicCommandExceptionType(error -> Component.translatableEscape("particle.invalidOptions", error));
32 | private final HolderLookup.Provider holderLookupProvider;
33 | private static final TagParser> VALUE_PARSER = TagParser.create(NbtOps.INSTANCE);
34 |
35 | public CParticleArgument(CommandBuildContext buildContext) {
36 | this.holderLookupProvider = buildContext;
37 | }
38 |
39 | public static CParticleArgument particle(CommandBuildContext buildContext) {
40 | return new CParticleArgument(buildContext);
41 | }
42 |
43 | public static ParticleOptions getParticle(final CommandContext context, final String name) {
44 | return context.getArgument(name, ParticleOptions.class);
45 | }
46 |
47 | @Override
48 | public ParticleOptions parse(final StringReader stringReader) throws CommandSyntaxException {
49 | return readParameters(stringReader, this.holderLookupProvider);
50 | }
51 |
52 | @Override
53 | public Collection getExamples() {
54 | return EXAMPLES;
55 | }
56 |
57 | public static ParticleOptions readParameters(StringReader reader, HolderLookup.Provider holderLookupProvider) throws CommandSyntaxException {
58 | ParticleType> particleType = getType(reader, holderLookupProvider.lookupOrThrow(Registries.PARTICLE_TYPE));
59 | return readParameters(VALUE_PARSER, reader, particleType, holderLookupProvider);
60 | }
61 |
62 | private static ParticleType> getType(StringReader reader, HolderLookup> holderLookup) throws CommandSyntaxException {
63 | ResourceLocation id = ResourceLocation.read(reader);
64 | ResourceKey