DFU Codecs for various libraries
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: initial commit

+1985
+113
.checkstyle/checkstyle.xml
··· 1 + <?xml version="1.0"?> 2 + <!DOCTYPE module PUBLIC 3 + "-//Puppy Crawl//DTD Check Configuration 1.3//EN" 4 + "https://checkstyle.org/dtds/configuration_1_3.dtd"> 5 + 6 + <module name="Checker"> 7 + 8 + <property name="charset" value="UTF-8"/> 9 + <property name="fileExtensions" value="java, properties, xml"/> 10 + <property name="severity" value="error"/> 11 + 12 + <!-- https://checkstyle.org/filefilters/beforeexecutionexclusionfilefilter.html --> 13 + <module name="BeforeExecutionExclusionFileFilter"> 14 + <property name="fileNamePattern" value="module\-info\.java$"/> 15 + </module> 16 + 17 + <!-- https://checkstyle.org/checks/whitespace/filetabcharacter.html --> 18 + <module name="FileTabCharacter"> 19 + <property name="eachLine" value="true"/> 20 + </module> 21 + 22 + <!-- https://checkstyle.org/checks/misc/newlineatendoffile.html --> 23 + <module name="NewlineAtEndOfFile"/> 24 + 25 + <!-- https://checkstyle.org/filters/suppressionfilter.html --> 26 + <module name="SuppressionFilter"> 27 + <property name="file" value="${configDirectory}/suppressions.xml"/> 28 + </module> 29 + 30 + <!-- https://checkstyle.org/filters/suppresswarningsfilter.html --> 31 + <module name="SuppressWarningsFilter"/> 32 + 33 + <module name="TreeWalker"> 34 + 35 + <!-- https://checkstyle.org/checks/misc/arraytypestyle.html --> 36 + <module name="ArrayTypeStyle"/> 37 + 38 + <!-- https://checkstyle.org/checks/imports/avoidstarimport.html --> 39 + <module name="AvoidStarImport"/> 40 + 41 + <!-- https://checkstyle.org/checks/design/finalclass.html --> 42 + <module name="FinalClass"/> 43 + 44 + <!-- https://checkstyle.org/checks/coding/finallocalvariable.html --> 45 + <module name="FinalLocalVariable"> 46 + <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF"/> 47 + <property name="validateEnhancedForLoopVariable" value="true"/> 48 + </module> 49 + 50 + <!-- https://checkstyle.org/checks/imports/illegalimport.html --> 51 + <module name="IllegalImport"> 52 + <property name="illegalPkgs" 53 + value="sun, jdk, com.sun, org.jetbrains.annotations.Nullable, org.jetbrains.annotations.NotNull"/> 54 + </module> 55 + 56 + <!-- https://checkstyle.org/checks/javadoc/invalidjavadocposition.html --> 57 + <module name="InvalidJavadocPosition"/> 58 + 59 + <!-- https://checkstyle.org/checks/javadoc/javadoccontentlocation.html --> 60 + <module name="JavadocContentLocation"/> 61 + 62 + <!-- https://checkstyle.org/checks/javadoc/javadocmethod.html --> 63 + <module name="JavadocMethod"/> 64 + 65 + <!-- https://checkstyle.org/checks/javadoc/javadocmissingwhitespaceafterasterisk.html --> 66 + <module name="JavadocMissingWhitespaceAfterAsterisk"/> 67 + 68 + <!-- https://checkstyle.org/checks/javadoc/javadocparagraph.html --> 69 + <module name="JavadocParagraph"/> 70 + 71 + <!-- https://checkstyle.org/checks/javadoc/javadoctagcontinuationindentation.html --> 72 + <module name="JavadocTagContinuationIndentation"/> 73 + 74 + <!-- https://checkstyle.org/checks/blocks/leftcurly.html --> 75 + <module name="LeftCurly"/> 76 + 77 + <!-- https://checkstyle.org/checks/coding/matchxpath.html --> 78 + <module name="MatchXpath"> 79 + <property name="query" value="//ANNOTATION[./IDENT[@text='NotNull']]"/> 80 + <message key="matchxpath.match" 81 + value="Avoid using @NotNull annotation. Use @NonNull instead."/> 82 + </module> 83 + 84 + <!-- https://checkstyle.org/checks/naming/methodname.html --> 85 + <module name="MethodName"> 86 + <property name="format" 87 + value="^(?:(?:.{1,3})|(?:[gs]et[^A-Z].*)|(?:(?:[^gsA-Z]..|.[^e].|..[^t]).+))$"/> 88 + </module> 89 + 90 + <!-- https://checkstyle.org/checks/javadoc/missingjavadoctype.html --> 91 + <module name="MissingJavadocType"/> 92 + 93 + <!-- https://checkstyle.org/checks/javadoc/missingjavadocmethod.html --> 94 + <module name="MissingJavadocMethod"/> 95 + 96 + <!-- https://checkstyle.org/checks/javadoc/missingjavadocpackage.html --> 97 + <module name="MissingJavadocPackage"/> 98 + 99 + <!-- https://tangled.org/nayrid.com/checks/blob/main/src/main/java/com/nayrid/checks/RequireSinceCheck.java --> 100 + <module name="com.nayrid.checks.RequireSinceCheck"/> 101 + 102 + <!-- https://checkstyle.org/checks/coding/requirethis.html --> 103 + <module name="RequireThis"/> 104 + 105 + <!-- https://checkstyle.org/filters/suppresswarningsfilter.html --> 106 + <module name="SuppressWarningsHolder"/> 107 + 108 + <!-- https://checkstyle.org/filters/suppressioncommentfilter.html --> 109 + <module name="SuppressionCommentFilter"/> 110 + 111 + </module> 112 + 113 + </module>
+6
.checkstyle/suppressions.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" 3 + "http://checkstyle.org/dtds/suppressions_1_2.dtd"> 4 + <suppressions> 5 + 6 + </suppressions>
+13
.editorconfig
··· 1 + [*] 2 + charset = utf-8 3 + end_of_line = lf 4 + indent_size = 4 5 + indent_style = space 6 + insert_final_newline = true 7 + max_line_length = 100 8 + tab_width = 4 9 + ij_continuation_indent_size = 4 10 + ij_smart_tabs = false 11 + ij_java_blank_lines_before_class_end = 1 12 + ij_any_blank_lines_after_class_header = 1 13 + ij_any_blank_lines_around_field = 1
+2
.gitattributes
··· 1 + * text=auto 2 + *.java text eol=lf
+6
.gitignore
··· 1 + **/build 2 + **/.gradle 3 + **/.idea 4 + **/.iml 5 + **/run 6 + **/.kotlin
+4
README.md
··· 1 + # grimoire 2 + 3 + [DFU](https://github.com/Mojang/DataFixerUpper) Codecs for various libraries. Builds are published 4 + to [repo.nayrid.com](https://repo.nayrid.com/#).
+16
build-logic/build.gradle.kts
··· 1 + plugins { 2 + `kotlin-dsl` 3 + } 4 + 5 + repositories { 6 + gradlePluginPortal() 7 + } 8 + 9 + dependencies { 10 + implementation(libs.shadow) 11 + implementation(libs.indra.common) 12 + implementation(libs.indra.licenseHeader) 13 + 14 + // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 15 + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) 16 + }
+7
build-logic/settings.gradle.kts
··· 1 + dependencyResolutionManagement { 2 + versionCatalogs { 3 + create("libs") { 4 + from(files("../gradle/libs.versions.toml")) 5 + } 6 + } 7 + }
+43
build-logic/src/main/kotlin/base-conventions.gradle.kts
··· 1 + plugins { 2 + idea 3 + id("net.kyori.indra") 4 + id("net.kyori.indra.checkstyle") 5 + id("net.kyori.indra.licenser.spotless") 6 + } 7 + 8 + version = rootProject.version 9 + 10 + indra { 11 + mitLicense() 12 + 13 + javaVersions { 14 + target(25) 15 + } 16 + } 17 + 18 + indraSpotlessLicenser { 19 + licenseHeaderFile(rootProject.file("license_header.txt")) 20 + } 21 + 22 + dependencies { 23 + checkstyle(libs.checkstyle) 24 + checkstyle(libs.checks) 25 + testImplementation(libs.junit.jupiter) 26 + testRuntimeOnly(libs.junit.platform.launcher) 27 + } 28 + 29 + tasks { 30 + jar { 31 + dependsOn(check) 32 + } 33 + test { 34 + useJUnitPlatform() 35 + } 36 + } 37 + 38 + idea { 39 + module { 40 + isDownloadJavadoc = true 41 + isDownloadSources = true 42 + } 43 + }
+17
build-logic/src/main/kotlin/extensions.kt
··· 1 + import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 + import org.gradle.accessors.dm.LibrariesForLibs 3 + import org.gradle.api.Project 4 + import org.gradle.kotlin.dsl.the 5 + 6 + // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 7 + val Project.libs: LibrariesForLibs 8 + get() = the() 9 + 10 + /** 11 + * Relocate a package into a project-scoped namespace. 12 + */ 13 + fun ShadowJar.relocateDependency(pkg: String) { 14 + val groupId = project.group.toString().ifBlank { "com.nayrid" } 15 + val projectId = project.name.ifBlank { "grimoire" } 16 + relocate(pkg, "$groupId.$projectId.libs.$pkg") 17 + }
+28
build-logic/src/main/kotlin/publishing-conventions.gradle.kts
··· 1 + plugins { 2 + id("base-conventions") 3 + id("net.kyori.indra.publishing") 4 + } 5 + 6 + indra { 7 + publishSnapshotsTo("nayrid", "https://repo.nayrid.com/snapshots") 8 + publishReleasesTo("nayrid", "https://repo.nayrid.com/releases") 9 + } 10 + 11 + tasks { 12 + javadoc { 13 + dependsOn(check) 14 + options { 15 + (this as StandardJavadocDocletOptions).apply { 16 + encoding = Charsets.UTF_8.name() 17 + links( 18 + "https://docs.oracle.com/en/java/javase/25/docs/api/", 19 + "https://jspecify.dev/docs/api/", 20 + "https://joml-ci.github.io/JOML/apidocs", 21 + "https://kvverti.github.io/Documented-DataFixerUpper/snapshot", 22 + "https://jd.advntr.dev/key/${libs.versions.adventure.get()}/", 23 + "https://jd.papermc.io/paper/${libs.versions.paper.get().replace("-R0.1-SNAPSHOT", "")}/" 24 + ) 25 + } 26 + } 27 + } 28 + }
+2
build.gradle.kts
··· 1 + group = "com.nayrid" 2 + version = "1.0.0-SNAPSHOT"
+33
gradle/libs.versions.toml
··· 1 + [versions] 2 + indra = "4.0.0" 3 + checkstyle = "13.2.0" 4 + checks = "1.0.0" 5 + shadow = "9.3.1" 6 + junit = "6.0.2" 7 + jspecify = "1.0.0" 8 + 9 + dfu = "8.0.16" 10 + adventure = "4.26.1" 11 + joml = "1.10.8" 12 + paper = "1.21.11-R0.1-SNAPSHOT" 13 + 14 + [libraries] 15 + # build logic 16 + indra-common = { group = "net.kyori", name = "indra-common", version.ref = "indra" } 17 + indra-licenseHeader = { group = "net.kyori", name = "indra-licenser-spotless", version.ref = "indra" } 18 + shadow = { group = "com.gradleup.shadow", name = "shadow-gradle-plugin", version.ref = "shadow" } 19 + 20 + # development tools (code quality, annotations) 21 + checkstyle = { group = "com.puppycrawl.tools", name = "checkstyle", version.ref = "checkstyle" } 22 + checks = { group = "com.nayrid", name = "checks", version.ref = "checks" } 23 + jspecify = { group = "org.jspecify", name = "jspecify", version.ref = "jspecify" } 24 + 25 + # testing 26 + junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } 27 + junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" } 28 + 29 + # libraries 30 + dfu = { group = "com.mojang", name = "datafixerupper", version.ref = "dfu" } 31 + adventure-key = { group = "net.kyori", name = "adventure-key", version.ref = "adventure" } 32 + joml = { group = "org.joml", name = "joml", version.ref = "joml" } 33 + paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
gradle/wrapper/gradle-wrapper.jar

This is a binary file and will not be displayed.

+7
gradle/wrapper/gradle-wrapper.properties
··· 1 + distributionBase=GRADLE_USER_HOME 2 + distributionPath=wrapper/dists 3 + distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip 4 + networkTimeout=10000 5 + validateDistributionUrl=true 6 + zipStoreBase=GRADLE_USER_HOME 7 + zipStorePath=wrapper/dists
+248
gradlew
··· 1 + #!/bin/sh 2 + 3 + # 4 + # Copyright © 2015 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\n' "$PWD" ) || exit 90 + 91 + # Use the maximum available, or set MAX_FD != -1 to use that value. 92 + MAX_FD=maximum 93 + 94 + warn () { 95 + echo "$*" 96 + } >&2 97 + 98 + die () { 99 + echo 100 + echo "$*" 101 + echo 102 + exit 1 103 + } >&2 104 + 105 + # OS specific support (must be 'true' or 'false'). 106 + cygwin=false 107 + msys=false 108 + darwin=false 109 + nonstop=false 110 + case "$( uname )" in #( 111 + CYGWIN* ) cygwin=true ;; #( 112 + Darwin* ) darwin=true ;; #( 113 + MSYS* | MINGW* ) msys=true ;; #( 114 + NONSTOP* ) nonstop=true ;; 115 + esac 116 + 117 + 118 + 119 + # Determine the Java command to use to start the JVM. 120 + if [ -n "$JAVA_HOME" ] ; then 121 + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 122 + # IBM's JDK on AIX uses strange locations for the executables 123 + JAVACMD=$JAVA_HOME/jre/sh/java 124 + else 125 + JAVACMD=$JAVA_HOME/bin/java 126 + fi 127 + if [ ! -x "$JAVACMD" ] ; then 128 + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 129 + 130 + Please set the JAVA_HOME variable in your environment to match the 131 + location of your Java installation." 132 + fi 133 + else 134 + JAVACMD=java 135 + if ! command -v java >/dev/null 2>&1 136 + then 137 + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 138 + 139 + Please set the JAVA_HOME variable in your environment to match the 140 + location of your Java installation." 141 + fi 142 + fi 143 + 144 + # Increase the maximum file descriptors if we can. 145 + if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 146 + case $MAX_FD in #( 147 + max*) 148 + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 149 + # shellcheck disable=SC2039,SC3045 150 + MAX_FD=$( ulimit -H -n ) || 151 + warn "Could not query maximum file descriptor limit" 152 + esac 153 + case $MAX_FD in #( 154 + '' | soft) :;; #( 155 + *) 156 + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 157 + # shellcheck disable=SC2039,SC3045 158 + ulimit -n "$MAX_FD" || 159 + warn "Could not set maximum file descriptor limit to $MAX_FD" 160 + esac 161 + fi 162 + 163 + # Collect all arguments for the java command, stacking in reverse order: 164 + # * args from the command line 165 + # * the main class name 166 + # * -classpath 167 + # * -D...appname settings 168 + # * --module-path (only if needed) 169 + # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 170 + 171 + # For Cygwin or MSYS, switch paths to Windows format before running java 172 + if "$cygwin" || "$msys" ; then 173 + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 174 + 175 + JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 + 177 + # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 + for arg do 179 + if 180 + case $arg in #( 181 + -*) false ;; # don't mess with options #( 182 + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 + [ -e "$t" ] ;; #( 184 + *) false ;; 185 + esac 186 + then 187 + arg=$( cygpath --path --ignore --mixed "$arg" ) 188 + fi 189 + # Roll the args list around exactly as many times as the number of 190 + # args, so each arg winds up back in the position where it started, but 191 + # possibly modified. 192 + # 193 + # NB: a `for` loop captures its iteration list before it begins, so 194 + # changing the positional parameters here affects neither the number of 195 + # iterations, nor the values presented in `arg`. 196 + shift # remove old arg 197 + set -- "$@" "$arg" # push replacement arg 198 + done 199 + fi 200 + 201 + 202 + # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 + DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 + 205 + # Collect all arguments for the java command: 206 + # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 + # and any embedded shellness will be escaped. 208 + # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 + # treated as '${Hostname}' itself on the command line. 210 + 211 + set -- \ 212 + "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 214 + "$@" 215 + 216 + # Stop when "xargs" is not available. 217 + if ! command -v xargs >/dev/null 2>&1 218 + then 219 + die "xargs is not available" 220 + fi 221 + 222 + # Use "xargs" to parse quoted args. 223 + # 224 + # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 + # 226 + # In Bash we could simply go: 227 + # 228 + # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 + # set -- "${ARGS[@]}" "$@" 230 + # 231 + # but POSIX shell has neither arrays nor command substitution, so instead we 232 + # post-process each arg (as a line of input to sed) to backslash-escape any 233 + # character that might be a shell metacharacter, then use eval to reverse 234 + # that process (while maintaining the separation between arguments), and wrap 235 + # the whole thing up as a single "set" statement. 236 + # 237 + # This will of course break if any of these variables contains a newline or 238 + # an unmatched quote. 239 + # 240 + 241 + eval "set -- $( 242 + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 + xargs -n1 | 244 + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 + tr '\n' ' ' 246 + )" '"$@"' 247 + 248 + exec "$JAVACMD" "$@"
+93
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 + 74 + 75 + @rem Execute Gradle 76 + "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 + 78 + :end 79 + @rem End local scope for the variables with windows NT shell 80 + if %ERRORLEVEL% equ 0 goto mainEnd 81 + 82 + :fail 83 + rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 + rem the _cmd.exe /c_ return code! 85 + set EXIT_CODE=%ERRORLEVEL% 86 + if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 + if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 + exit /b %EXIT_CODE% 89 + 90 + :mainEnd 91 + if "%OS%"=="Windows_NT" endlocal 92 + 93 + :omega
+10
grimoire-adventure-key/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + api(libs.jspecify) 7 + api(projects.grimoireCommon) 8 + compileOnlyApi(libs.dfu) 9 + compileOnlyApi(libs.adventure.key) 10 + }
+51
grimoire-adventure-key/src/main/java/com/nayrid/grimoire/adventure/KeyCodecs.java
··· 1 + /* 2 + * This file is part of grimoire, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.nayrid.grimoire.adventure; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.nayrid.grimoire.common.Grimoire; 28 + import net.kyori.adventure.key.Key; 29 + 30 + /** 31 + * Codecs for adventure-key types. 32 + * 33 + * @since 1.0.0 34 + */ 35 + public final class KeyCodecs { 36 + 37 + /** 38 + * Stores a {@link Key} as its minimal string representation. 39 + * 40 + * @since 1.0.0 41 + */ 42 + @SuppressWarnings("PatternValidation") 43 + public static final Codec<Key> KEY = 44 + Codec.STRING.comapFlatMap(string -> Grimoire.safeDataResult(() -> Key.key( 45 + string)), Key::asMinimalString); 46 + 47 + private KeyCodecs() { 48 + throw new IllegalStateException("Utility class"); 49 + } 50 + 51 + }
+7
grimoire-adventure-key/src/main/java/com/nayrid/grimoire/adventure/package-info.java
··· 1 + /** 2 + * Codecs for adventure-key. 3 + */ 4 + @NullMarked 5 + package com.nayrid.grimoire.adventure; 6 + 7 + import org.jspecify.annotations.NullMarked;
+9
grimoire-common/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + api(libs.jspecify) 7 + compileOnlyApi(libs.dfu) 8 + compileOnlyApi(libs.joml) 9 + }
+119
grimoire-common/src/main/java/com/nayrid/grimoire/common/Grimoire.java
··· 1 + /* 2 + * This file is part of grimoire, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.nayrid.grimoire.common; 25 + 26 + import com.mojang.serialization.DataResult; 27 + import org.jspecify.annotations.Nullable; 28 + 29 + import java.util.Arrays; 30 + import java.util.List; 31 + import java.util.function.Supplier; 32 + import java.util.stream.IntStream; 33 + 34 + /** 35 + * Utilities for writing codecs. 36 + * 37 + * @since 1.0.0 38 + */ 39 + public final class Grimoire { 40 + 41 + private Grimoire() { 42 + throw new IllegalStateException("Utility class"); 43 + } 44 + 45 + /** 46 + * Ensures a list's length is equal to `length`. 47 + * 48 + * @param list the list 49 + * @param length the length 50 + * @param <T> list type 51 + * @return data result 52 + * @since 1.0.0 53 + */ 54 + public static <T> DataResult<List<T>> fixedLength(final List<T> list, final int length) { 55 + if (list.size() != length) { 56 + final Supplier<String> messageSupplier = 57 + () -> "Input is not a list of %d elements".formatted(length); 58 + return list.size() >= length ? DataResult.error(messageSupplier, 59 + list.subList(0, length) 60 + ) : DataResult.error(messageSupplier); 61 + } else { 62 + return DataResult.success(list); 63 + } 64 + } 65 + 66 + /** 67 + * Ensures an {@link IntStream}'s length is equal to `length`. 68 + * 69 + * @param stream the stream 70 + * @param length the length 71 + * @return data result 72 + * @since 1.0.0 73 + */ 74 + public static DataResult<int[]> fixedLength(final IntStream stream, final int length) { 75 + final int[] ints = stream.limit(length + 1).toArray(); 76 + if (ints.length != length) { 77 + final Supplier<String> messageSupplier = 78 + () -> "Input is not a list of %d integers".formatted(length); 79 + return ints.length >= length ? DataResult.error(messageSupplier, Arrays.copyOf(ints, 80 + length)) : DataResult.error(messageSupplier); 81 + } else { 82 + return DataResult.success(ints); 83 + } 84 + } 85 + 86 + /** 87 + * Resolves a {@link Supplier} and wraps the result inside a {@link DataResult}. 88 + * 89 + * @param supplier the supplier 90 + * @param <T> result type 91 + * @return data result 92 + * @since 1.0.0 93 + */ 94 + public static <T> DataResult<T> safeDataResult(final Supplier<T> supplier) { 95 + try { 96 + final T t = supplier.get(); 97 + return DataResult.success(t); 98 + } catch (final Exception exception) { 99 + return DataResult.error(exception::getMessage); 100 + } 101 + } 102 + 103 + /** 104 + * Returns a {@link DataResult} for a nullable value ensuring it's non-null. 105 + * 106 + * @param t the nullable thing 107 + * @param <T> result type 108 + * @return data result 109 + * @since 1.0.0 110 + */ 111 + public static <T> DataResult<T> nonNullResult(final @Nullable T t) { 112 + if (t == null) { 113 + return DataResult.error(() -> "Cannot be null"); 114 + } 115 + //noinspection NullableProblems - no better way of doing this :( 116 + return DataResult.success(t); 117 + } 118 + 119 + }
+75
grimoire-common/src/main/java/com/nayrid/grimoire/common/JavaCodecs.java
··· 1 + /* 2 + * This file is part of grimoire, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.nayrid.grimoire.common; 25 + 26 + import com.mojang.serialization.Codec; 27 + 28 + import java.util.Arrays; 29 + import java.util.UUID; 30 + 31 + /** 32 + * Codecs for Java standard library types. 33 + * 34 + * @since 1.0.0 35 + */ 36 + public final class JavaCodecs { 37 + 38 + /** 39 + * Stores a {@link UUID} as a string. 40 + * 41 + * @since 1.0.0 42 + */ 43 + public static final Codec<UUID> UUID_STRING = 44 + Codec.STRING.comapFlatMap(string -> Grimoire.safeDataResult(() -> java.util.UUID.fromString( 45 + string)), java.util.UUID::toString); 46 + 47 + /** 48 + * Stores a {@link UUID} as a list of 4 integers. 49 + * 50 + * @since 1.0.0 51 + */ 52 + public static final Codec<UUID> UUID_INTS = Codec.INT_STREAM 53 + .comapFlatMap(list -> Grimoire.fixedLength(list, 4).map(JavaCodecs::uuidFromIntArray), 54 + uuid -> Arrays.stream(uuidToIntArray(uuid))); 55 + 56 + private JavaCodecs() { 57 + throw new IllegalStateException("Utility class"); 58 + } 59 + 60 + private static UUID uuidFromIntArray(final int[] intArray) { 61 + return new UUID((long) intArray[0] << 32 | intArray[1] & 4294967295L, 62 + (long) intArray[2] << 32 | intArray[3] & 4294967295L); 63 + } 64 + 65 + private static int[] uuidToIntArray(final UUID uuid) { 66 + return mostLeastAsIntArray(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); 67 + } 68 + 69 + private static int[] mostLeastAsIntArray(final long mostSignificantBits, 70 + final long leastSignificantBits) { 71 + return new int[]{(int) (mostSignificantBits >> 32), (int) mostSignificantBits, 72 + (int) (leastSignificantBits >> 32), (int) leastSignificantBits}; 73 + } 74 + 75 + }
+7
grimoire-common/src/main/java/com/nayrid/grimoire/common/package-info.java
··· 1 + /** 2 + * Utilities and Java codecs. 3 + */ 4 + @NullMarked 5 + package com.nayrid.grimoire.common; 6 + 7 + import org.jspecify.annotations.NullMarked;
+10
grimoire-joml/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + api(libs.jspecify) 7 + api(projects.grimoireCommon) 8 + compileOnlyApi(libs.dfu) 9 + compileOnlyApi(libs.joml) 10 + }
+396
grimoire-joml/src/main/java/com/nayrid/grimoire/joml/JomlCodecs.java
··· 1 + /* 2 + * This file is part of grimoire, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.nayrid.grimoire.joml; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.codecs.RecordCodecBuilder; 28 + import com.nayrid.grimoire.common.Grimoire; 29 + import org.joml.AxisAngle4d; 30 + import org.joml.AxisAngle4f; 31 + import org.joml.Matrix2d; 32 + import org.joml.Matrix2f; 33 + import org.joml.Matrix3d; 34 + import org.joml.Matrix3f; 35 + import org.joml.Matrix4d; 36 + import org.joml.Matrix4f; 37 + import org.joml.Quaterniond; 38 + import org.joml.Quaternionf; 39 + import org.joml.Vector2L; 40 + import org.joml.Vector2d; 41 + import org.joml.Vector2f; 42 + import org.joml.Vector2i; 43 + import org.joml.Vector3L; 44 + import org.joml.Vector3d; 45 + import org.joml.Vector3f; 46 + import org.joml.Vector3i; 47 + 48 + import java.util.List; 49 + 50 + /** 51 + * Codecs for JOML types. 52 + * 53 + * @since 1.0.0 54 + */ 55 + public final class JomlCodecs { 56 + 57 + /** 58 + * Stores a {@link Vector2d} as a list of 2 doubles. 59 + * 60 + * @since 1.0.0 61 + */ 62 + public static final Codec<Vector2d> VECTOR2D = Codec.DOUBLE.listOf() 63 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 2) 64 + .map(list -> new Vector2d(list.getFirst(), list.getLast())), 65 + vector2d -> List.of(vector2d.x(), vector2d.y())); 66 + 67 + /** 68 + * Stores a {@link Vector2f} as a list of 2 doubles. 69 + * 70 + * @since 1.0.0 71 + */ 72 + public static final Codec<Vector2f> VECTOR2F = VECTOR2D.xmap(Vector2f::new, Vector2d::new); 73 + 74 + /** 75 + * Stores a {@link Vector2L} as a list of 2 longs. 76 + * 77 + * @since 1.0.0 78 + */ 79 + public static final Codec<Vector2L> VECTOR2L = Codec.LONG.listOf() 80 + .comapFlatMap(longs -> Grimoire.fixedLength(longs, 2) 81 + .map(list -> new Vector2L(list.getFirst(), list.getLast())), 82 + vector2l -> List.of(vector2l.x(), vector2l.y())); 83 + 84 + /** 85 + * Stores a {@link Vector2i} as a list of 2 integers. 86 + * 87 + * @since 1.0.0 88 + */ 89 + public static final Codec<Vector2i> VECTOR2I = Codec.INT.listOf() 90 + .comapFlatMap(ints -> Grimoire.fixedLength(ints, 2) 91 + .map(list -> new Vector2i(list.getFirst(), list.getLast())), 92 + vector2i -> List.of(vector2i.x(), vector2i.y())); 93 + 94 + /** 95 + * Stores a {@link Vector3d} as a list of 3 doubles. 96 + * 97 + * @since 1.0.0 98 + */ 99 + public static final Codec<Vector3d> VECTOR3D = Codec.DOUBLE.listOf() 100 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 3) 101 + .map(list -> new Vector3d(list.getFirst(), list.get(1), list.getLast())), 102 + vector3d -> List.of(vector3d.x(), vector3d.y(), vector3d.z())); 103 + 104 + /** 105 + * Stores a {@link Vector3f} as a list of 3 doubles. 106 + * 107 + * @since 1.0.0 108 + */ 109 + public static final Codec<Vector3f> VECTOR3F = VECTOR3D.xmap(Vector3f::new, Vector3d::new); 110 + 111 + /** 112 + * Stores a {@link Vector3L} as a list of 3 longs. 113 + * 114 + * @since 1.0.0 115 + */ 116 + public static final Codec<Vector3L> VECTOR3L = Codec.LONG.listOf() 117 + .comapFlatMap(longs -> Grimoire.fixedLength(longs, 3) 118 + .map(list -> new Vector3L().set(list.getFirst(), list.get(1), list.getLast())), 119 + vector3l -> List.of(vector3l.x(), vector3l.y(), vector3l.z())); 120 + 121 + /** 122 + * Stores a {@link Vector3i} as a list of 3 integers. 123 + * 124 + * @since 1.0.0 125 + */ 126 + public static final Codec<Vector3i> VECTOR3I = Codec.INT.listOf() 127 + .comapFlatMap(ints -> Grimoire.fixedLength(ints, 3) 128 + .map(list -> new Vector3i(list.getFirst(), list.get(1), list.getLast())), 129 + vector3i -> List.of(vector3i.x(), vector3i.y(), vector3i.z())); 130 + 131 + /** 132 + * Stores an {@link AxisAngle4d} as an object with {@code angle} and {@code axis} fields. 133 + * 134 + * @since 1.0.0 135 + */ 136 + public static final Codec<AxisAngle4d> AXISANGLE4D = 137 + RecordCodecBuilder.create(instance -> instance.group( 138 + Codec.DOUBLE.fieldOf("angle").forGetter(axisangle4d -> axisangle4d.angle), 139 + VECTOR3D.fieldOf("axis") 140 + .forGetter(axisAngle4d -> new Vector3d(axisAngle4d.x, axisAngle4d.y, axisAngle4d.z)) 141 + ).apply(instance, AxisAngle4d::new)); 142 + 143 + /** 144 + * Stores an {@link AxisAngle4f} as an object with {@code angle} and {@code axis} fields. 145 + * 146 + * @since 1.0.0 147 + */ 148 + public static final Codec<AxisAngle4f> AXISANGLE4F = 149 + AXISANGLE4D.xmap(axisAngle4d -> new AxisAngle4f( 150 + (float) axisAngle4d.angle, 151 + (float) axisAngle4d.x, 152 + (float) axisAngle4d.y, 153 + (float) axisAngle4d.z 154 + ), 155 + axisAngle4f -> new AxisAngle4d(axisAngle4f.angle, 156 + axisAngle4f.x, 157 + axisAngle4f.y, 158 + axisAngle4f.z 159 + ) 160 + ); 161 + 162 + /** 163 + * Stores a {@link Matrix2d} as a list of 4 doubles in m00, m01, m10, m11 order. 164 + * 165 + * @since 1.0.0 166 + */ 167 + public static final Codec<Matrix2d> MATRIX2D = Codec.DOUBLE.listOf() 168 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 4).map(list -> { 169 + final Matrix2d result = new Matrix2d(); 170 + result.set(list.getFirst(), list.get(1), list.get(2), list.get(3)); 171 + return result; 172 + }), matrix2d -> List.of(matrix2d.m00, matrix2d.m01, matrix2d.m10, matrix2d.m11)); 173 + 174 + /** 175 + * Stores a {@link Matrix3d} as a list of 9 doubles in row-major order. 176 + * 177 + * @since 1.0.0 178 + */ 179 + public static final Codec<Matrix3d> MATRIX3D = Codec.DOUBLE.listOf() 180 + .comapFlatMap(list -> Grimoire.fixedLength(list, 9).map(list1 -> { 181 + final Matrix3d result = new Matrix3d(); 182 + result.set(list1.get(0), 183 + list1.get(1), 184 + list1.get(2), 185 + list1.get(3), 186 + list1.get(4), 187 + list1.get(5), 188 + list1.get(6), 189 + list1.get(7), 190 + list1.get(8) 191 + ); 192 + return result; 193 + }), 194 + matrix -> List.of(matrix.m00, 195 + matrix.m01, 196 + matrix.m02, 197 + matrix.m10, 198 + matrix.m11, 199 + matrix.m12, 200 + matrix.m20, 201 + matrix.m21, 202 + matrix.m22 203 + ) 204 + ); 205 + 206 + /** 207 + * Stores a {@link Matrix4d} as a list of 16 doubles in row-major order. 208 + * 209 + * @since 1.0.0 210 + */ 211 + public static final Codec<Matrix4d> MATRIX4D = Codec.DOUBLE.listOf() 212 + .comapFlatMap(list -> Grimoire.fixedLength(list, 16).map(list1 -> { 213 + final Matrix4d result = new Matrix4d(); 214 + result.set(list1.get(0), 215 + list1.get(1), 216 + list1.get(2), 217 + list1.get(3), 218 + list1.get(4), 219 + list1.get(5), 220 + list1.get(6), 221 + list1.get(7), 222 + list1.get(8), 223 + list1.get(9), 224 + list1.get(10), 225 + list1.get(11), 226 + list1.get(12), 227 + list1.get(13), 228 + list1.get(14), 229 + list1.get(15) 230 + ); 231 + return result; 232 + }), 233 + matrix -> List.of(matrix.m00(), 234 + matrix.m01(), 235 + matrix.m02(), 236 + matrix.m03(), 237 + matrix.m10(), 238 + matrix.m11(), 239 + matrix.m12(), 240 + matrix.m13(), 241 + matrix.m20(), 242 + matrix.m21(), 243 + matrix.m22(), 244 + matrix.m23(), 245 + matrix.m30(), 246 + matrix.m31(), 247 + matrix.m32(), 248 + matrix.m33() 249 + ) 250 + ); 251 + 252 + /** 253 + * Stores a {@link Matrix2f} as a list of 4 doubles in m00, m01, m10, m11 order. 254 + * 255 + * @since 1.0.0 256 + */ 257 + public static final Codec<Matrix2f> MATRIX2F = 258 + MATRIX2D.xmap(matrix2d -> new Matrix2f((float) matrix2d.m00, 259 + (float) matrix2d.m01, 260 + (float) matrix2d.m10, 261 + (float) matrix2d.m11 262 + ), matrix2f -> new Matrix2d(matrix2f.m00, matrix2f.m01, matrix2f.m10, matrix2f.m11)); 263 + 264 + /** 265 + * Stores a {@link Matrix3f} as a list of 9 doubles in row-major order. 266 + * 267 + * @since 1.0.0 268 + */ 269 + public static final Codec<Matrix3f> MATRIX3F = 270 + MATRIX3D.xmap(matrix3d -> new Matrix3f((float) matrix3d.m00, 271 + (float) matrix3d.m01, 272 + (float) matrix3d.m02, 273 + (float) matrix3d.m10, 274 + (float) matrix3d.m11, 275 + (float) matrix3d.m12, 276 + (float) matrix3d.m20, 277 + (float) matrix3d.m21, 278 + (float) matrix3d.m22 279 + ), 280 + matrix3f -> new Matrix3d(matrix3f.m00, 281 + matrix3f.m01, 282 + matrix3f.m02, 283 + matrix3f.m10, 284 + matrix3f.m11, 285 + matrix3f.m12, 286 + matrix3f.m20, 287 + matrix3f.m21, 288 + matrix3f.m22 289 + ) 290 + ); 291 + 292 + /** 293 + * Stores a {@link Matrix4f} as a list of 16 doubles in row-major order. 294 + * 295 + * @since 1.0.0 296 + */ 297 + public static final Codec<Matrix4f> MATRIX4F = 298 + MATRIX4D.xmap(matrix4d -> new Matrix4f((float) matrix4d.m00(), 299 + (float) matrix4d.m01(), 300 + (float) matrix4d.m02(), 301 + (float) matrix4d.m03(), 302 + (float) matrix4d.m10(), 303 + (float) matrix4d.m11(), 304 + (float) matrix4d.m12(), 305 + (float) matrix4d.m13(), 306 + (float) matrix4d.m20(), 307 + (float) matrix4d.m21(), 308 + (float) matrix4d.m22(), 309 + (float) matrix4d.m23(), 310 + (float) matrix4d.m30(), 311 + (float) matrix4d.m31(), 312 + (float) matrix4d.m32(), 313 + (float) matrix4d.m33() 314 + ), 315 + matrix4f -> new Matrix4d(matrix4f.m00(), 316 + matrix4f.m01(), 317 + matrix4f.m02(), 318 + matrix4f.m03(), 319 + matrix4f.m10(), 320 + matrix4f.m11(), 321 + matrix4f.m12(), 322 + matrix4f.m13(), 323 + matrix4f.m20(), 324 + matrix4f.m21(), 325 + matrix4f.m22(), 326 + matrix4f.m23(), 327 + matrix4f.m30(), 328 + matrix4f.m31(), 329 + matrix4f.m32(), 330 + matrix4f.m33() 331 + ) 332 + ); 333 + 334 + /** 335 + * Stores a normalized {@link Quaterniond} as a list of 4 doubles in x, y, z, w order. 336 + * 337 + * @since 1.0.0 338 + */ 339 + public static final Codec<Quaterniond> QUATERNIOND_NORMALIZED = Codec.DOUBLE.listOf() 340 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 4) 341 + .map(list -> new Quaterniond(list.getFirst(), 342 + list.get(1), 343 + list.get(2), 344 + list.get(3) 345 + ).normalize()), 346 + quaterniond -> List.of(quaterniond.x(), 347 + quaterniond.y(), 348 + quaterniond.z(), 349 + quaterniond.w() 350 + ) 351 + ); 352 + 353 + /** 354 + * Stores a normalized {@link Quaternionf} as a list of 4 floats in x, y, z, w order. 355 + * 356 + * @since 1.0.0 357 + */ 358 + public static final Codec<Quaternionf> QUATERNIONF_NORMALIZED = Codec.FLOAT.listOf() 359 + .comapFlatMap(floats -> Grimoire.fixedLength(floats, 4) 360 + .map(list -> new Quaternionf(list.getFirst(), 361 + list.get(1), 362 + list.get(2), 363 + list.get(3) 364 + ).normalize()), 365 + quaternionf -> List.of(quaternionf.x(), 366 + quaternionf.y(), 367 + quaternionf.z(), 368 + quaternionf.w() 369 + ) 370 + ); 371 + 372 + /** 373 + * Stores a {@link Quaternionf} as either a normalized quaternion list or an axis-angle object. 374 + * 375 + * @since 1.0.0 376 + */ 377 + public static final Codec<Quaternionf> QUATERNIONF = Codec.withAlternative( 378 + QUATERNIONF_NORMALIZED, 379 + AXISANGLE4F.xmap(Quaternionf::new, AxisAngle4f::new) 380 + ); 381 + 382 + /** 383 + * Stores a {@link Quaterniond} as either a normalized quaternion list or an axis-angle object. 384 + * 385 + * @since 1.0.0 386 + */ 387 + public static final Codec<Quaterniond> QUATERNIOND = Codec.withAlternative( 388 + QUATERNIOND_NORMALIZED, 389 + AXISANGLE4D.xmap(Quaterniond::new, AxisAngle4d::new) 390 + ); 391 + 392 + private JomlCodecs() { 393 + throw new IllegalStateException("Utility class"); 394 + } 395 + 396 + }
+7
grimoire-joml/src/main/java/com/nayrid/grimoire/joml/package-info.java
··· 1 + /** 2 + * Codecs for JOML types. 3 + */ 4 + @NullMarked 5 + package com.nayrid.grimoire.joml; 6 + 7 + import org.jspecify.annotations.NullMarked;
+12
grimoire-paper/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + api(libs.jspecify) 7 + api(projects.grimoireCommon) 8 + api(projects.grimoireJoml) 9 + api(projects.grimoireAdventureKey) 10 + compileOnlyApi(libs.dfu) 11 + compileOnlyApi(libs.paper) 12 + }
+561
grimoire-paper/src/main/java/com/nayrid/grimoire/paper/PaperCodecs.java
··· 1 + /* 2 + * This file is part of grimoire, licensed under the MIT License. 3 + * 4 + * Copyright (c) 2026 nayrid 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in all 14 + * copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + * SOFTWARE. 23 + */ 24 + package com.nayrid.grimoire.paper; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.DataResult; 28 + import com.mojang.serialization.codecs.RecordCodecBuilder; 29 + import com.nayrid.grimoire.adventure.KeyCodecs; 30 + import com.nayrid.grimoire.common.Grimoire; 31 + import com.nayrid.grimoire.joml.JomlCodecs; 32 + import io.papermc.paper.datacomponent.DataComponentType; 33 + import io.papermc.paper.dialog.Dialog; 34 + import io.papermc.paper.registry.RegistryAccess; 35 + import io.papermc.paper.registry.RegistryKey; 36 + import org.bukkit.Art; 37 + import org.bukkit.Axis; 38 + import org.bukkit.Bukkit; 39 + import org.bukkit.Color; 40 + import org.bukkit.DyeColor; 41 + import org.bukkit.Fluid; 42 + import org.bukkit.GameEvent; 43 + import org.bukkit.GameRule; 44 + import org.bukkit.JukeboxSong; 45 + import org.bukkit.Keyed; 46 + import org.bukkit.Location; 47 + import org.bukkit.MusicInstrument; 48 + import org.bukkit.NamespacedKey; 49 + import org.bukkit.Particle; 50 + import org.bukkit.Rotation; 51 + import org.bukkit.Sound; 52 + import org.bukkit.World; 53 + import org.bukkit.attribute.Attribute; 54 + import org.bukkit.block.Biome; 55 + import org.bukkit.block.BlockFace; 56 + import org.bukkit.block.BlockType; 57 + import org.bukkit.block.banner.PatternType; 58 + import org.bukkit.damage.DamageType; 59 + import org.bukkit.enchantments.Enchantment; 60 + import org.bukkit.entity.Cat; 61 + import org.bukkit.entity.Chicken; 62 + import org.bukkit.entity.Cow; 63 + import org.bukkit.entity.EntityType; 64 + import org.bukkit.entity.Frog; 65 + import org.bukkit.entity.Pig; 66 + import org.bukkit.entity.Villager; 67 + import org.bukkit.entity.Wolf; 68 + import org.bukkit.entity.ZombieNautilus; 69 + import org.bukkit.entity.memory.MemoryKey; 70 + import org.bukkit.generator.structure.Structure; 71 + import org.bukkit.generator.structure.StructureType; 72 + import org.bukkit.inventory.ItemType; 73 + import org.bukkit.inventory.MenuType; 74 + import org.bukkit.inventory.meta.trim.TrimMaterial; 75 + import org.bukkit.inventory.meta.trim.TrimPattern; 76 + import org.bukkit.map.MapCursor; 77 + import org.bukkit.potion.PotionEffectType; 78 + import org.bukkit.potion.PotionType; 79 + import org.bukkit.util.BoundingBox; 80 + import org.bukkit.util.EulerAngle; 81 + import org.bukkit.util.Transformation; 82 + import org.bukkit.util.Vector; 83 + 84 + import java.util.List; 85 + import java.util.Locale; 86 + import java.util.function.Function; 87 + import java.util.regex.Pattern; 88 + 89 + /** 90 + * Codecs for paper types. 91 + * 92 + * @since 1.0.0 93 + */ 94 + public final class PaperCodecs { 95 + 96 + /** 97 + * Stores a {@link NamespacedKey} using its key representation. 98 + * 99 + * @since 1.0.0 100 + */ 101 + public static final Codec<NamespacedKey> NAMESPACED_KEY = 102 + KeyCodecs.KEY.xmap(key -> new NamespacedKey(key.namespace(), key.value()), 103 + NamespacedKey::key); 104 + 105 + /** 106 + * Stores a {@link World} by its key. 107 + * 108 + * @since 1.0.0 109 + */ 110 + @SuppressWarnings("DataFlowIssue") // false positive: success path is non-null 111 + public static final Codec<World> WORLD = 112 + KeyCodecs.KEY.comapFlatMap(key -> Grimoire.nonNullResult(Bukkit.getWorld(key)), World::key); 113 + 114 + /** 115 + * @since 1.0.0 116 + */ 117 + public static final Codec<BlockFace> BLOCKFACE = enumCodec(BlockFace::valueOf); 118 + 119 + /** 120 + * @since 1.0.0 121 + */ 122 + public static final Codec<Axis> AXIS = enumCodec(Axis::valueOf); 123 + 124 + /** 125 + * @since 1.0.0 126 + */ 127 + public static final Codec<DyeColor> DYE_COLOR = enumCodec(DyeColor::valueOf); 128 + 129 + /** 130 + * @since 1.0.0 131 + */ 132 + public static final Codec<Rotation> ROTATION = enumCodec(Rotation::valueOf); 133 + 134 + /** 135 + * @since 1.0.0 136 + */ 137 + public static final Codec<Vector> VECTOR = JomlCodecs.VECTOR3D.xmap(Vector::fromJOML, 138 + Vector::toVector3d); 139 + 140 + /** 141 + * Stores a {@link EulerAngle} as a vector of x, y, z values. 142 + * 143 + * @since 1.0.0 144 + */ 145 + public static final Codec<EulerAngle> EULER_ANGLE = 146 + VECTOR.xmap(vector -> new EulerAngle(vector.getX(), vector.getY(), vector.getZ()), 147 + eulerAngle -> new Vector(eulerAngle.getX(), eulerAngle.getY(), eulerAngle.getZ())); 148 + 149 + /** 150 + * @since 1.0.0 151 + */ 152 + public static final Codec<BoundingBox> BOUNDING_BOX = 153 + RecordCodecBuilder.create(instance -> instance.group( 154 + VECTOR.fieldOf("min").forGetter(BoundingBox::getMin), 155 + VECTOR.fieldOf("max").forGetter(BoundingBox::getMax) 156 + ).apply(instance, BoundingBox::of)); 157 + 158 + /** 159 + * @since 1.0.0 160 + */ 161 + public static final Codec<Transformation> TRANSFORMATION = 162 + RecordCodecBuilder.create(instance -> instance.group( 163 + JomlCodecs.VECTOR3F.fieldOf("translation").forGetter(Transformation::getTranslation), 164 + JomlCodecs.QUATERNIONF.fieldOf("left_rotation").forGetter(Transformation::getLeftRotation), 165 + JomlCodecs.VECTOR3F.fieldOf("scale").forGetter(Transformation::getScale), 166 + JomlCodecs.QUATERNIONF.fieldOf("right_rotation").forGetter(Transformation::getRightRotation) 167 + ).apply(instance, Transformation::new)); 168 + 169 + /** 170 + * @since 1.0.0 171 + */ 172 + public static final Codec<Location> LOCATION = 173 + RecordCodecBuilder.create(instance -> instance.group( 174 + WORLD.fieldOf("world").forGetter(Location::getWorld), 175 + VECTOR.fieldOf("position").forGetter(Location::toVector), 176 + Codec.FLOAT.fieldOf("yaw").forGetter(Location::getYaw), 177 + Codec.FLOAT.fieldOf("pitch").forGetter(Location::getPitch)) 178 + .apply(instance, 179 + ((world, vector, yaw, pitch) -> new Location(world, 180 + vector.getX(), 181 + vector.getY(), 182 + vector.getZ(), 183 + yaw, 184 + pitch)))); 185 + 186 + /** 187 + * Stores a {@link Color} as an ARGB integer. 188 + * 189 + * @since 1.0.0 190 + */ 191 + public static final Codec<Color> COLOR_ARGB_INT = 192 + Codec.INT.comapFlatMap(integer -> Grimoire.safeDataResult( 193 + () -> Color.fromARGB(integer)), Color::asARGB); 194 + 195 + /** 196 + * Stores a {@link Color} as an RGB integer. 197 + * 198 + * @since 1.0.0 199 + */ 200 + public static final Codec<Color> COLOR_RGB_INT = 201 + Codec.INT.comapFlatMap(integer -> Grimoire.safeDataResult( 202 + () -> Color.fromRGB(integer)), Color::asRGB); 203 + 204 + /** 205 + * Stores a {@link Color} as a list of 3 integers in red, green, blue order. 206 + * 207 + * @since 1.0.0 208 + */ 209 + public static final Codec<Color> COLOR_RGB_INT_LIST = Codec.INT.listOf() 210 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 3) 211 + .map(list -> Color.fromRGB(list.getFirst(), list.get(1), list.getLast())), 212 + color -> List.of(color.getRed(), color.getGreen(), color.getBlue())); 213 + 214 + /** 215 + * Stores a {@link Color} as a list of 4 integers in alpha, red, green, blue order. 216 + * 217 + * @since 1.0.0 218 + */ 219 + public static final Codec<Color> COLOR_ARGB_INT_LIST = Codec.INT.listOf() 220 + .comapFlatMap(doubles -> Grimoire.fixedLength(doubles, 4) 221 + .map(list -> Color.fromARGB(list.getFirst(), list.get(1), list.get(2), 222 + list.getLast())), 223 + color -> List.of(color.getAlpha(), 224 + color.getRed(), 225 + color.getGreen(), 226 + color.getBlue())); 227 + 228 + /** 229 + * Stores an {@link Attribute} by its registry key. 230 + * 231 + * @since 1.0.0 232 + */ 233 + public static final Codec<Attribute> ATTRIBUTE = 234 + registryCodec(RegistryKey.ATTRIBUTE); 235 + 236 + /** 237 + * Stores a {@link PatternType} by its registry key. 238 + * 239 + * @since 1.0.0 240 + */ 241 + public static final Codec<PatternType> BANNER_PATTERN = 242 + registryCodec(RegistryKey.BANNER_PATTERN); 243 + 244 + /** 245 + * Stores a {@link Biome} by its registry key. 246 + * 247 + * @since 1.0.0 248 + */ 249 + public static final Codec<Biome> BIOME = 250 + registryCodec(RegistryKey.BIOME); 251 + 252 + /** 253 + * Stores a {@link BlockType} by its registry key. 254 + * 255 + * @since 1.0.0 256 + */ 257 + public static final Codec<BlockType> BLOCK = 258 + registryCodec(RegistryKey.BLOCK); 259 + 260 + /** 261 + * Stores a {@link Cat.Type} by its registry key. 262 + * 263 + * @since 1.0.0 264 + */ 265 + public static final Codec<Cat.Type> CAT_VARIANT = 266 + registryCodec(RegistryKey.CAT_VARIANT); 267 + 268 + /** 269 + * Stores a {@link Chicken.Variant} by its registry key. 270 + * 271 + * @since 1.0.0 272 + */ 273 + public static final Codec<Chicken.Variant> CHICKEN_VARIANT = 274 + registryCodec(RegistryKey.CHICKEN_VARIANT); 275 + 276 + /** 277 + * Stores a {@link Cow.Variant} by its registry key. 278 + * 279 + * @since 1.0.0 280 + */ 281 + public static final Codec<Cow.Variant> COW_VARIANT = 282 + registryCodec(RegistryKey.COW_VARIANT); 283 + 284 + /** 285 + * Stores a {@link DamageType} by its registry key. 286 + * 287 + * @since 1.0.0 288 + */ 289 + public static final Codec<DamageType> DAMAGE_TYPE = 290 + registryCodec(RegistryKey.DAMAGE_TYPE); 291 + 292 + /** 293 + * Stores a {@link DataComponentType} by its registry key. 294 + * 295 + * @since 1.0.0 296 + */ 297 + @SuppressWarnings("UnstableApiUsage") 298 + public static final Codec<DataComponentType> DATA_COMPONENT_TYPE = 299 + registryCodec(RegistryKey.DATA_COMPONENT_TYPE); 300 + 301 + /** 302 + * Stores a {@link Dialog} by its registry key. 303 + * 304 + * @since 1.0.0 305 + */ 306 + public static final Codec<Dialog> DIALOG = 307 + registryCodec(RegistryKey.DIALOG); 308 + 309 + /** 310 + * Stores an {@link Enchantment} by its registry key. 311 + * 312 + * @since 1.0.0 313 + */ 314 + public static final Codec<Enchantment> ENCHANTMENT = 315 + registryCodec(RegistryKey.ENCHANTMENT); 316 + 317 + /** 318 + * Stores an {@link EntityType} by its registry key. 319 + * 320 + * @since 1.0.0 321 + */ 322 + public static final Codec<EntityType> ENTITY_TYPE = 323 + registryCodec(RegistryKey.ENTITY_TYPE); 324 + 325 + /** 326 + * Stores a {@link Fluid} by its registry key. 327 + * 328 + * @since 1.0.0 329 + */ 330 + public static final Codec<Fluid> FLUID = 331 + registryCodec(RegistryKey.FLUID); 332 + 333 + /** 334 + * Stores a {@link Frog.Variant} by its registry key. 335 + * 336 + * @since 1.0.0 337 + */ 338 + public static final Codec<Frog.Variant> FROG_VARIANT = 339 + registryCodec(RegistryKey.FROG_VARIANT); 340 + 341 + /** 342 + * Stores a {@link GameEvent} by its registry key. 343 + * 344 + * @since 1.0.0 345 + */ 346 + public static final Codec<GameEvent> GAME_EVENT = 347 + registryCodec(RegistryKey.GAME_EVENT); 348 + 349 + /** 350 + * Stores a {@link GameRule} by its registry key. 351 + * 352 + * @since 1.0.0 353 + */ 354 + public static final Codec<GameRule<?>> GAME_RULE = 355 + registryCodec(RegistryKey.GAME_RULE); 356 + 357 + /** 358 + * Stores a {@link MusicInstrument} by its registry key. 359 + * 360 + * @since 1.0.0 361 + */ 362 + public static final Codec<MusicInstrument> INSTRUMENT = 363 + registryCodec(RegistryKey.INSTRUMENT); 364 + 365 + /** 366 + * Stores an {@link ItemType} by its registry key. 367 + * 368 + * @since 1.0.0 369 + */ 370 + public static final Codec<ItemType> ITEM = 371 + registryCodec(RegistryKey.ITEM); 372 + 373 + /** 374 + * Stores a {@link JukeboxSong} by its registry key. 375 + * 376 + * @since 1.0.0 377 + */ 378 + public static final Codec<JukeboxSong> JUKEBOX_SONG = 379 + registryCodec(RegistryKey.JUKEBOX_SONG); 380 + 381 + /** 382 + * Stores a {@link MapCursor.Type} by its registry key. 383 + * 384 + * @since 1.0.0 385 + */ 386 + public static final Codec<MapCursor.Type> MAP_DECORATION_TYPE = 387 + registryCodec(RegistryKey.MAP_DECORATION_TYPE); 388 + 389 + /** 390 + * Stores a {@link MemoryKey} by its registry key. 391 + * 392 + * @since 1.0.0 393 + */ 394 + public static final Codec<MemoryKey<?>> MEMORY_MODULE_TYPE = 395 + registryCodec(RegistryKey.MEMORY_MODULE_TYPE); 396 + 397 + /** 398 + * Stores a {@link MenuType} by its registry key. 399 + * 400 + * @since 1.0.0 401 + */ 402 + @SuppressWarnings("UnstableApiUsage") 403 + public static final Codec<MenuType> MENU = 404 + registryCodec(RegistryKey.MENU); 405 + 406 + /** 407 + * Stores a {@link PotionEffectType} by its registry key. 408 + * 409 + * @since 1.0.0 410 + */ 411 + public static final Codec<PotionEffectType> MOB_EFFECT = 412 + registryCodec(RegistryKey.MOB_EFFECT); 413 + 414 + /** 415 + * Stores an {@link Art} by its registry key. 416 + * 417 + * @since 1.0.0 418 + */ 419 + public static final Codec<Art> PAINTING_VARIANT = 420 + registryCodec(RegistryKey.PAINTING_VARIANT); 421 + 422 + /** 423 + * Stores a {@link Particle} by its registry key. 424 + * 425 + * @since 1.0.0 426 + */ 427 + public static final Codec<Particle> PARTICLE_TYPE = 428 + registryCodec(RegistryKey.PARTICLE_TYPE); 429 + 430 + /** 431 + * Stores a {@link Pig.Variant} by its registry key. 432 + * 433 + * @since 1.0.0 434 + */ 435 + public static final Codec<Pig.Variant> PIG_VARIANT = 436 + registryCodec(RegistryKey.PIG_VARIANT); 437 + 438 + /** 439 + * Stores a {@link PotionType} by its registry key. 440 + * 441 + * @since 1.0.0 442 + */ 443 + public static final Codec<PotionType> POTION = 444 + registryCodec(RegistryKey.POTION); 445 + 446 + /** 447 + * Stores a {@link Sound} by its registry key. 448 + * 449 + * @since 1.0.0 450 + */ 451 + public static final Codec<Sound> SOUND_EVENT = 452 + registryCodec(RegistryKey.SOUND_EVENT); 453 + 454 + /** 455 + * Stores a {@link Structure} by its registry key. 456 + * 457 + * @since 1.0.0 458 + */ 459 + public static final Codec<Structure> STRUCTURE = 460 + registryCodec(RegistryKey.STRUCTURE); 461 + 462 + /** 463 + * Stores a {@link StructureType} by its registry key. 464 + * 465 + * @since 1.0.0 466 + */ 467 + public static final Codec<StructureType> STRUCTURE_TYPE = 468 + registryCodec(RegistryKey.STRUCTURE_TYPE); 469 + 470 + /** 471 + * Stores a {@link TrimMaterial} by its registry key. 472 + * 473 + * @since 1.0.0 474 + */ 475 + public static final Codec<TrimMaterial> TRIM_MATERIAL = 476 + registryCodec(RegistryKey.TRIM_MATERIAL); 477 + 478 + /** 479 + * Stores a {@link TrimPattern} by its registry key. 480 + * 481 + * @since 1.0.0 482 + */ 483 + public static final Codec<TrimPattern> TRIM_PATTERN = 484 + registryCodec(RegistryKey.TRIM_PATTERN); 485 + 486 + /** 487 + * Stores a {@link Villager.Profession} by its registry key. 488 + * 489 + * @since 1.0.0 490 + */ 491 + public static final Codec<Villager.Profession> VILLAGER_PROFESSION = 492 + registryCodec(RegistryKey.VILLAGER_PROFESSION); 493 + 494 + /** 495 + * Stores a {@link Villager.Type} by its registry key. 496 + * 497 + * @since 1.0.0 498 + */ 499 + public static final Codec<Villager.Type> VILLAGER_TYPE = 500 + registryCodec(RegistryKey.VILLAGER_TYPE); 501 + 502 + /** 503 + * Stores a {@link Wolf.SoundVariant} by its registry key. 504 + * 505 + * @since 1.0.0 506 + */ 507 + public static final Codec<Wolf.SoundVariant> WOLF_SOUND_VARIANT = 508 + registryCodec(RegistryKey.WOLF_SOUND_VARIANT); 509 + 510 + /** 511 + * Stores a {@link Wolf.Variant} by its registry key. 512 + * 513 + * @since 1.0.0 514 + */ 515 + public static final Codec<Wolf.Variant> WOLF_VARIANT = 516 + registryCodec(RegistryKey.WOLF_VARIANT); 517 + 518 + /** 519 + * Stores a {@link ZombieNautilus.Variant} by its registry key. 520 + * 521 + * @since 1.0.0 522 + */ 523 + public static final Codec<ZombieNautilus.Variant> ZOMBIE_NAUTILUS_VARIANT = 524 + registryCodec(RegistryKey.ZOMBIE_NAUTILUS_VARIANT); 525 + 526 + private static final Pattern PLAYER_NAME_PATTERN = 527 + Pattern.compile("^[A-Za-z0-9_ ]{1,16}$"); 528 + 529 + /** 530 + * Stores and validates a player name string. 531 + * 532 + * @since 1.0.0 533 + */ 534 + public static final Codec<String> PLAYER_NAME = 535 + Codec.STRING.validate(name -> { 536 + if (!PLAYER_NAME_PATTERN.matcher(name).matches()) { 537 + return DataResult.error(() -> "Invalid player name " + name); 538 + } 539 + return DataResult.success(name); 540 + }); 541 + 542 + private PaperCodecs() { 543 + throw new IllegalStateException("Utility class"); 544 + } 545 + 546 + private static <T extends Enum<T>> Codec<T> enumCodec(final Function<String, T> valueOfFunc) { 547 + return Codec.STRING.comapFlatMap( 548 + s -> Grimoire.safeDataResult(() -> valueOfFunc.apply(s.toUpperCase(Locale.ROOT))), 549 + v -> v.toString().toLowerCase(Locale.ROOT) 550 + ); 551 + } 552 + 553 + @SuppressWarnings({"NullableProblems", "DataFlowIssue"}) 554 + // ^^ false positives - `Grimoire.nonNullResult` handles this 555 + private static <T extends Keyed> Codec<T> registryCodec(final RegistryKey<T> registryKey) { 556 + return KeyCodecs.KEY.comapFlatMap(key -> Grimoire.nonNullResult(RegistryAccess.registryAccess() 557 + .getRegistry(registryKey) 558 + .get(key)), Keyed::key); 559 + } 560 + 561 + }
+7
grimoire-paper/src/main/java/com/nayrid/grimoire/paper/package-info.java
··· 1 + /** 2 + * Codecs for paper types. 3 + */ 4 + @NullMarked 5 + package com.nayrid.grimoire.paper; 6 + 7 + import org.jspecify.annotations.NullMarked;
+21
license.txt
··· 1 + MIT License 2 + 3 + Copyright (c) 2026 nayrid 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 all 13 + 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 THE 21 + SOFTWARE.
+21
license_header.txt
··· 1 + This file is part of grimoire, licensed under the MIT License. 2 + 3 + Copyright (c) 2026 nayrid 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 all 13 + 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 THE 21 + SOFTWARE.
+34
settings.gradle.kts
··· 1 + enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 2 + 3 + dependencyResolutionManagement { 4 + @Suppress("UnstableApiUsage") 5 + repositories { 6 + mavenCentral() 7 + maven { 8 + url = uri("https://libraries.minecraft.net") 9 + name = "minecraft" 10 + } 11 + maven { 12 + name = "papermc" 13 + url = uri("https://repo.papermc.io/repository/maven-public/") 14 + } 15 + maven { 16 + name = "nayridReleases" 17 + url = uri("https://repo.nayrid.com/releases") 18 + } 19 + } 20 + } 21 + 22 + pluginManagement { 23 + repositories { 24 + gradlePluginPortal() 25 + } 26 + includeBuild("build-logic") 27 + } 28 + 29 + rootProject.name = "grimoire" 30 + 31 + sequenceOf("common", "joml", "adventure-key", "paper").forEach { 32 + include("${rootProject.name}-$it") 33 + project(":${rootProject.name}-$it").projectDir = file("${rootProject.name}-$it") 34 + }