registry library vaguely similar to Minecraft
0
fork

Configure Feed

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

feat: initial commit

+1873
+118
.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/NoGenericExceptionCheck.java --> 100 + <module name="com.nayrid.checks.NoGenericExceptionCheck"/> 101 + 102 + <!-- https://tangled.org/nayrid.com/checks/blob/main/src/main/java/com/nayrid/checks/RequireSinceCheck.java --> 103 + <module name="com.nayrid.checks.RequireSinceCheck"/> 104 + 105 + <!-- https://checkstyle.org/checks/coding/requirethis.html --> 106 + <module name="RequireThis"> 107 + <property name="validateOnlyOverlapping" value="false"/> 108 + </module> 109 + 110 + <!-- https://checkstyle.org/filters/suppresswarningsfilter.html --> 111 + <module name="SuppressWarningsHolder"/> 112 + 113 + <!-- https://checkstyle.org/filters/suppressioncommentfilter.html --> 114 + <module name="SuppressionCommentFilter"/> 115 + 116 + </module> 117 + 118 + </module>
+10
.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 + <!-- don't require docs for tests --> 7 + <suppress files="registry-(api|dfu)[\\/]src[\\/]test[\\/]java[\\/].*" 8 + checks="(MissingJavadoc.*)"/> 9 + 10 + </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
+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 + }
+15
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 + relocate(pkg, "${project.group}.${project.name}.libs.$pkg") 15 + }
+24
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 + ) 21 + } 22 + } 23 + } 24 + }
+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.1.0-SNAPSHOT" 5 + common = "1.0.0-SNAPSHOT" 6 + shadow = "9.3.1" 7 + junit = "6.0.2" 8 + jspecify = "1.0.0" 9 + 10 + dfu = "8.0.16" 11 + jetbrains-annotations = "26.0.2" 12 + describe = "1.0.0-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 + jetbrains-annotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annotations" } 25 + 26 + # testing 27 + junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } 28 + junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit" } 29 + 30 + # libraries 31 + common = { group = "com.nayrid", name = "common-api", version.ref = "common" } 32 + dfu = { group = "com.mojang", name = "datafixerupper", version.ref = "dfu" } 33 + describe = { group = "com.nayrid", name = "describe-api", version.ref = "describe" }
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
+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 registry, 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.
+10
registry-api/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + compileOnlyApi(libs.jspecify) 7 + compileOnlyApi(libs.jetbrains.annotations) 8 + api(libs.common) 9 + api(libs.describe) 10 + }
+153
registry-api/src/main/java/com/nayrid/registry/AbstractRegistry.java
··· 1 + /* 2 + * This file is part of registry, 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.registry; 25 + 26 + import com.nayrid.common.Validate; 27 + import com.nayrid.describe.RecordStyleFormatter; 28 + import com.nayrid.registry.entry.RegistryEntry; 29 + import org.jetbrains.annotations.Contract; 30 + import org.jetbrains.annotations.UnmodifiableView; 31 + import org.jspecify.annotations.Nullable; 32 + 33 + import java.util.Collections; 34 + import java.util.HashMap; 35 + import java.util.Map; 36 + import java.util.Set; 37 + 38 + /** 39 + * An abstract base class for registry implementations. 40 + * 41 + * @param <K> the type of keys 42 + * @param <V> the type of values 43 + * @since 1.0.0 44 + */ 45 + public abstract class AbstractRegistry<K, V> implements Registry<K, V> { 46 + 47 + protected final K registryKey; 48 + 49 + protected final Map<K, RegistryEntry<K, V>> byKey = new HashMap<>(); 50 + protected final @UnmodifiableView Set<K> keySet = Collections.unmodifiableSet(this.byKey.keySet()); 51 + protected final Map<V, RegistryEntry<K, V>> byValue = new HashMap<>(); 52 + 53 + private static <V> String valueAlreadyRegistered(final V value) { 54 + return "Value '" + value + "' already registered"; 55 + } 56 + 57 + private static <K> String keyAlreadyRegistered(final K key) { 58 + return "Key '" + key + "' already registered"; 59 + } 60 + 61 + /** 62 + * Creates a new registry with the given key. 63 + * 64 + * @param registryKey the registry key 65 + * @throws NullPointerException if {@code registryKey} is {@code null} 66 + * @since 1.0.0 67 + */ 68 + @Contract("null -> fail") 69 + protected AbstractRegistry(final K registryKey) { 70 + this.registryKey = Validate.nonNull(registryKey, "registryKey"); 71 + } 72 + 73 + @Override 74 + public RegistryEntry<K, V> register(final K key, final V value) { 75 + Validate.nonNull(key, "key"); 76 + Validate.nonNull(value, "value"); 77 + final RegistryEntry<K, V> existingEntry = this.byKey.get(key); 78 + if (existingEntry != null) { 79 + if (existingEntry instanceof RegistryEntry.Delayed<K, V> delayedEntry) { 80 + if (this.byValue.containsKey(value)) { 81 + throw new IllegalStateException(valueAlreadyRegistered(value)); 82 + } 83 + if (delayedEntry.hasValue()) { 84 + throw new IllegalStateException(keyAlreadyRegistered(key)); 85 + } 86 + if (delayedEntry.set(value)) { 87 + this.byValue.put(value, delayedEntry); 88 + return delayedEntry; 89 + } else { 90 + throw new RuntimeException("Failed to set value on '" + key + "'"); 91 + } 92 + } else { 93 + throw new IllegalStateException(keyAlreadyRegistered(key)); 94 + } 95 + } 96 + 97 + if (this.byValue.containsKey(value)) { 98 + throw new IllegalStateException(valueAlreadyRegistered(value)); 99 + } 100 + 101 + final RegistryEntry<K, V> newEntry = RegistryEntry.immediate(key, value); 102 + this.byKey.put(key, newEntry); 103 + this.byValue.put(value, newEntry); 104 + return newEntry; 105 + } 106 + 107 + @Override 108 + public @Nullable RegistryEntry<K, V> get(final @Nullable K key) { 109 + if (key == null) { 110 + return null; 111 + } 112 + return this.byKey.get(key); 113 + } 114 + 115 + @Override 116 + public RegistryEntry<K, V> getOrCreate(final K key) { 117 + if (this.byKey.containsKey(key)) { 118 + return this.byKey.get(key); 119 + } else { 120 + final RegistryEntry.Delayed<K, V> entry = RegistryEntry.delayed(key); 121 + this.byKey.put(key, entry); 122 + return entry; 123 + } 124 + } 125 + 126 + @Override 127 + public Set<K> keySet() { 128 + return this.keySet; 129 + } 130 + 131 + @Override 132 + public final K registryKey() { 133 + return this.registryKey; 134 + } 135 + 136 + @Override 137 + public String toString() { 138 + return RecordStyleFormatter.noDepthLimit().format(this); 139 + } 140 + 141 + @Override 142 + public boolean equals(final Object object) { 143 + return this == object || 144 + (object instanceof final Registry<?, ?> that) && 145 + this.registryKey().equals(that.registryKey()); 146 + } 147 + 148 + @Override 149 + public int hashCode() { 150 + return 31 * this.registryKey().hashCode(); 151 + } 152 + 153 + }
+156
registry-api/src/main/java/com/nayrid/registry/Registry.java
··· 1 + /* 2 + * This file is part of registry, 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.registry; 25 + 26 + 27 + import com.nayrid.describe.Describable; 28 + import com.nayrid.describe.Descriptor; 29 + import com.nayrid.registry.entry.RegistryEntry; 30 + import org.jetbrains.annotations.Contract; 31 + import org.jspecify.annotations.Nullable; 32 + 33 + import java.util.NoSuchElementException; 34 + import java.util.Optional; 35 + import java.util.Set; 36 + import java.util.function.Supplier; 37 + 38 + /** 39 + * A simple, immutable mapping from keys to values. 40 + * 41 + * @param <K> the type of keys 42 + * @param <V> the type of values 43 + * @since 1.0.0 44 + */ 45 + public interface Registry<K, V> extends Describable { 46 + 47 + /** 48 + * Registers a new entry with the given key and value. 49 + * 50 + * <p>If the entry was created with {@link #getOrCreate(Object)}, this will set the 51 + * value if it has not already been set.</p> 52 + * 53 + * @param key the lookup key 54 + * @param value the value to register 55 + * @return the entry 56 + * @throws NullPointerException if the key or value is {@code null} 57 + * @throws IllegalStateException if the key or value are already registered 58 + * @since 1.0.0 59 + */ 60 + @Contract(value = "null, _ -> fail; _, null -> fail", mutates = "this") 61 + RegistryEntry<K, V> register(K key, V value); 62 + 63 + /** 64 + * Gets the entry associated with the given key, or {@code null} if none exists. 65 + * 66 + * @param key the lookup key 67 + * @return the matching entry, or {@code null} if not found 68 + * @since 1.0.0 69 + */ 70 + @Nullable RegistryEntry<K, V> get(@Nullable K key); 71 + 72 + /** 73 + * Gets or creates a new entry for the given key. 74 + * 75 + * @param key the lookup key 76 + * @return the matching entry 77 + * @throws NullPointerException if the key is {@code null} 78 + * @since 1.0.0 79 + */ 80 + @SuppressWarnings("checkstyle:MethodName") 81 + RegistryEntry<K, V> getOrCreate(K key); 82 + 83 + /** 84 + * Gets an {@link Optional} containing the entry for the given key, or an empty Optional. 85 + * 86 + * @param key the lookup key 87 + * @return an Optional of the matching entry 88 + * @since 1.0.0 89 + */ 90 + @SuppressWarnings("checkstyle:MethodName") 91 + default Optional<RegistryEntry<K, V>> getOptionally(final K key) { 92 + return Optional.ofNullable(this.get(key)); 93 + } 94 + 95 + /** 96 + * Gets the entry for the given key, or throws if not present. 97 + * 98 + * @param key the lookup key 99 + * @param exceptionMessageSupplier supplier for the exception message 100 + * @return the matching entry 101 + * @throws NoSuchElementException if no entry is found 102 + * @since 1.0.0 103 + */ 104 + @SuppressWarnings("checkstyle:MethodName") 105 + default RegistryEntry<K, V> getOrThrow( 106 + final K key, 107 + final Supplier<String> exceptionMessageSupplier 108 + ) { 109 + final RegistryEntry<K, V> entry = this.get(key); 110 + if (entry == null) { 111 + throw new NoSuchElementException(exceptionMessageSupplier.get()); 112 + } 113 + return entry; 114 + } 115 + 116 + /** 117 + * Gets the entry for the given key, or throws with a default message. 118 + * 119 + * @param key the lookup key 120 + * @return the matching entry 121 + * @throws NoSuchElementException if no entry is found 122 + * @since 1.0.0 123 + */ 124 + @SuppressWarnings("checkstyle:MethodName") 125 + default RegistryEntry<K, V> getOrThrow(final K key) { 126 + return this.getOrThrow( 127 + key, 128 + () -> "No entry found for key '%s' in registry '%s'".formatted(key, this.registryKey()) 129 + ); 130 + } 131 + 132 + /** 133 + * Gets an unmodifiable {@link Set} of all registry keys. 134 + * 135 + * @return the set of keys 136 + * @since 1.0.0 137 + */ 138 + Set<K> keySet(); 139 + 140 + /** 141 + * Gets this registry's identifier. 142 + * 143 + * @return the registry key 144 + * @since 1.0.0 145 + */ 146 + K registryKey(); 147 + 148 + @Override 149 + default Descriptor describe() { 150 + return Descriptor.of(this) 151 + .field("registryKey", this.registryKey()) 152 + .field("size", this.keySet().size()) 153 + .build(); 154 + } 155 + 156 + }
+80
registry-api/src/main/java/com/nayrid/registry/entry/DelayedEntryImpl.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.entry; 25 + 26 + import com.nayrid.common.Validate; 27 + import com.nayrid.describe.RecordStyleFormatter; 28 + import org.jspecify.annotations.Nullable; 29 + 30 + import java.util.Objects; 31 + 32 + final class DelayedEntryImpl<K, V> implements RegistryEntry.Delayed<K, V> { 33 + 34 + private final K key; 35 + 36 + private @Nullable V value; 37 + 38 + DelayedEntryImpl(final K key) { 39 + this.key = Validate.nonNull(key, "key"); 40 + } 41 + 42 + @Override 43 + public K key() { 44 + return this.key; 45 + } 46 + 47 + @Override 48 + public @Nullable V value() { 49 + return this.value; 50 + } 51 + 52 + @Override 53 + public boolean set(final @Nullable V value) { 54 + if (this.value == null && value != null) { 55 + this.value = value; 56 + return true; 57 + } else { 58 + return false; 59 + } 60 + } 61 + 62 + @Override 63 + public boolean equals(final Object o) { 64 + if (o == null || getClass() != o.getClass()) 65 + return false; 66 + final DelayedEntryImpl<?, ?> that = (DelayedEntryImpl<?, ?>) o; 67 + return Objects.equals(this.key, that.key) && Objects.equals(this.value, that.value); 68 + } 69 + 70 + @Override 71 + public int hashCode() { 72 + return Objects.hash(this.key, this.value); 73 + } 74 + 75 + @Override 76 + public String toString() { 77 + return RecordStyleFormatter.noDepthLimit().format(this.describe()); 78 + } 79 + 80 + }
+41
registry-api/src/main/java/com/nayrid/registry/entry/ImmediateEntryImpl.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.entry; 25 + 26 + import com.nayrid.common.Validate; 27 + import com.nayrid.describe.RecordStyleFormatter; 28 + 29 + record ImmediateEntryImpl<K, V>(K key, V value) implements RegistryEntry.Immediate<K, V> { 30 + 31 + ImmediateEntryImpl(final K key, final V value) { 32 + this.key = Validate.nonNull(key, "key"); 33 + this.value = Validate.nonNull(value, "value"); 34 + } 35 + 36 + @Override 37 + public String toString() { 38 + return RecordStyleFormatter.noDepthLimit().format(this.describe()); 39 + } 40 + 41 + }
+216
registry-api/src/main/java/com/nayrid/registry/entry/RegistryEntry.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.entry; 25 + 26 + import com.nayrid.common.Validate; 27 + import com.nayrid.describe.Describable; 28 + import com.nayrid.describe.Descriptor; 29 + import com.nayrid.registry.Registry; 30 + import org.jetbrains.annotations.ApiStatus; 31 + import org.jetbrains.annotations.Contract; 32 + import org.jspecify.annotations.Nullable; 33 + 34 + import java.util.Optional; 35 + import java.util.function.Consumer; 36 + import java.util.function.Function; 37 + 38 + /** 39 + * A key-value pair within a {@link Registry}. 40 + * 41 + * @param <K> the type of keys 42 + * @param <V> the type of values 43 + * @since 1.0.0 44 + */ 45 + public sealed interface RegistryEntry<K, V> extends Describable permits RegistryEntry.Delayed, 46 + RegistryEntry.Immediate { 47 + 48 + /** 49 + * Creates a {@link Delayed} entry with the given key. The value is not set at this time. 50 + * 51 + * @param key the key to set 52 + * @param <K> the type of keys 53 + * @param <V> the type of values 54 + * @return a new {@link Delayed} entry 55 + * @throws NullPointerException if the key is {@code null} 56 + * @since 1.0.0 57 + */ 58 + @Contract("null -> fail; _ -> new") 59 + static <K, V> Delayed<K, V> delayed(final K key) { 60 + return new DelayedEntryImpl<>(key); 61 + } 62 + 63 + /** 64 + * Creates an {@link Immediate} entry with the given key and value. 65 + * 66 + * @param key the key to set 67 + * @param value the value to set 68 + * @param <K> the type of keys 69 + * @param <V> the type of values 70 + * @return a new {@link Immediate} entry 71 + * @throws NullPointerException if the key or value are {@code null} 72 + * @since 1.0.0 73 + */ 74 + @Contract("null, _ -> fail; _, null -> fail; _, _ -> new") 75 + static <K, V> RegistryEntry<K, V> immediate(final K key, final V value) { 76 + return new ImmediateEntryImpl<>(key, value); 77 + } 78 + 79 + /** 80 + * Gets this entry's key. 81 + * 82 + * @return the entry key 83 + * @since 1.0.0 84 + */ 85 + K key(); 86 + 87 + /** 88 + * Gets this entry's value, or {@code null} if unset. 89 + * 90 + * @return the entry value, or {@code null} 91 + * @since 1.0.0 92 + */ 93 + @Nullable V value(); 94 + 95 + /** 96 + * Gets this entry's value wrapped in an {@link Optional}. 97 + * 98 + * @return an Optional containing the value, or empty if unset 99 + * @since 1.0.0 100 + */ 101 + default Optional<V> valueOptionally() { 102 + return Optional.ofNullable(this.value()); 103 + } 104 + 105 + /** 106 + * Gets this entry's value, or throws a {@link NullPointerException} with a message supplied 107 + * by the given function if unset. 108 + * 109 + * @param messageFn function that generates the exception message using the key 110 + * @return the entry value 111 + * @throws NullPointerException if the value is {@code null} or if the {@code messageFn} is {@code null} 112 + * @since 1.0.0 113 + */ 114 + @Contract 115 + default V valueOrThrow(final Function<K, String> messageFn) { 116 + Validate.nonNull(messageFn, "messageFn"); 117 + final V value = this.value(); 118 + if (value == null) { 119 + throw new NullPointerException(messageFn.apply(this.key())); 120 + } 121 + return value; 122 + } 123 + 124 + /** 125 + * Gets this entry's value, or throws a {@link NullPointerException}. 126 + * 127 + * @return the entry value 128 + * @throws NullPointerException if the value is {@code null} 129 + * @since 1.0.0 130 + */ 131 + default V valueOrThrow() { 132 + return this.valueOrThrow(key -> String.format("No value present for key '%s'", key)); 133 + } 134 + 135 + /** 136 + * Gets if this entry has a non-null value. 137 + * 138 + * @return {@code true} if value is present, {@code false} otherwise 139 + * @since 1.0.0 140 + */ 141 + default boolean hasValue() { 142 + return this.value() != null; 143 + } 144 + 145 + /** 146 + * If a value is present, invokes the given consumer with the value. 147 + * 148 + * @param consumer the function to call with the value 149 + * @throws NullPointerException if {@code consumer} is {@code null} 150 + * @since 1.0.0 151 + */ 152 + default void ifPresent(final Consumer<V> consumer) { 153 + Validate.nonNull(consumer, "consumer"); 154 + final V value = this.value(); 155 + if (value != null) { 156 + consumer.accept(value); 157 + } 158 + } 159 + 160 + @Override 161 + default Descriptor describe() { 162 + return Descriptor.of(this) 163 + .field("key", this.key()) 164 + .field("value", this.value()) 165 + .build(); 166 + } 167 + 168 + /** 169 + * An entry whose value is not immediately available and may be set later, but once set, it will 170 + * never be {@code null}. 171 + * 172 + * @param <K> the type of keys 173 + * @param <V> the type of values 174 + * @since 1.0.0 175 + */ 176 + sealed interface Delayed<K, V> extends RegistryEntry<K, V> permits DelayedEntryImpl { 177 + 178 + /** 179 + * Attempts to set this entry's value. If the value is already set, this method will 180 + * return {@code false}. 181 + * 182 + * @param value the new value to set 183 + * @return {@code true} if the value was set, {@code false} otherwise 184 + * @since 1.0.0 185 + */ 186 + @ApiStatus.Internal 187 + boolean set(final V value); 188 + 189 + @Override 190 + default Descriptor describe() { 191 + return Descriptor.of(this, "RegistryEntry.Delayed") 192 + .merge(RegistryEntry.super.describe()) 193 + .build(); 194 + } 195 + 196 + } 197 + 198 + /** 199 + * An entry whose {@link #value()} is immediately available and never null. 200 + * 201 + * @param <K> the type of keys 202 + * @param <V> the type of values 203 + * @since 1.0.0 204 + */ 205 + sealed interface Immediate<K, V> extends RegistryEntry<K, V> permits ImmediateEntryImpl { 206 + 207 + @Override 208 + default Descriptor describe() { 209 + return Descriptor.of(this, "RegistryEntry.Immediate") 210 + .merge(RegistryEntry.super.describe()) 211 + .build(); 212 + } 213 + 214 + } 215 + 216 + }
+7
registry-api/src/main/java/com/nayrid/registry/entry/package-info.java
··· 1 + /** 2 + * Contains classes for representing {@link com.nayrid.registry.Registry Registry} entries. 3 + */ 4 + @NullMarked 5 + package com.nayrid.registry.entry; 6 + 7 + import org.jspecify.annotations.NullMarked;
+7
registry-api/src/main/java/com/nayrid/registry/package-info.java
··· 1 + /** 2 + * A registry API for managing key-value pairs. 3 + */ 4 + @NullMarked 5 + package com.nayrid.registry; 6 + 7 + import org.jspecify.annotations.NullMarked;
+10
registry-dfu/build.gradle.kts
··· 1 + plugins { 2 + id("publishing-conventions") 3 + } 4 + 5 + dependencies { 6 + compileOnlyApi(libs.jspecify) 7 + compileOnlyApi(libs.jetbrains.annotations) 8 + api(projects.registryApi) 9 + api(libs.dfu) 10 + }
+107
registry-dfu/src/main/java/com/nayrid/registry/dfu/AbstractKeyableRegistry.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.DataResult; 28 + import com.mojang.serialization.DynamicOps; 29 + import com.mojang.serialization.Keyable; 30 + import com.mojang.serialization.Lifecycle; 31 + import com.nayrid.common.Validate; 32 + import com.nayrid.registry.AbstractRegistry; 33 + import com.nayrid.registry.entry.RegistryEntry; 34 + import org.jetbrains.annotations.Contract; 35 + import org.jspecify.annotations.Nullable; 36 + 37 + import java.util.Optional; 38 + import java.util.function.Function; 39 + import java.util.stream.Stream; 40 + 41 + /** 42 + * An abstract base class for {@link Keyable} registry implementations. 43 + * 44 + * @param <K> the type of keys 45 + * @param <V> the type of values 46 + * @since 1.0.0 47 + */ 48 + public abstract class AbstractKeyableRegistry<K, V> extends AbstractRegistry<K, V> implements KeyableRegistry<K, V> { 49 + 50 + private final Lifecycle lifecycle; 51 + private final Codec<K> keyCodec; 52 + private final Function<K, String> keyToStringFn; 53 + 54 + /** 55 + * Creates a new registry with the given key. 56 + * 57 + * @param registryKey the registry key 58 + * @param lifecycle the lifecycle 59 + * @param keyCodec the key's Codec 60 + * @param keyToStringFn function to convert key type to String 61 + * @throws NullPointerException if any argument is {@code null} 62 + * @since 1.0.0 63 + */ 64 + @Contract("null, _, _, _ -> fail") 65 + protected AbstractKeyableRegistry(final K registryKey, 66 + final Lifecycle lifecycle, 67 + final Codec<K> keyCodec, final Function<K, String> keyToStringFn) { 68 + super(registryKey); 69 + this.lifecycle = Validate.nonNull(lifecycle, "lifecycle"); 70 + this.keyCodec = Validate.nonNull(keyCodec, "keyCodec"); 71 + this.keyToStringFn = Validate.nonNull(keyToStringFn, "keyToStringFn"); 72 + } 73 + 74 + @SuppressWarnings({"NullableProblems", "DataFlowIssue"}) // false positive afaict 75 + @Override 76 + public Codec<V> codec() { 77 + return this.entryCodec().flatComapMap(RegistryEntry::value, this::dataResultEntryByValue); 78 + } 79 + 80 + @Override 81 + public Codec<RegistryEntry<K, V>> entryCodec() { 82 + return this.keyCodec.comapFlatMap(key -> this.getOptionally(key).map(DataResult::success) 83 + .orElseGet(() -> DataResult.error(() -> "Unknown key in " + this + ": " + key)), 84 + RegistryEntry::key).withLifecycle(this.lifecycle); 85 + } 86 + 87 + @SuppressWarnings("NullableProblems") // false positive afaict 88 + private DataResult<RegistryEntry<K, V>> dataResultEntryByValue(final V value) { 89 + return Optional.ofNullable(this.get(this.key(value))).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Unknown value in " + this + ": " + value)); 90 + } 91 + 92 + private @Nullable K key(final @Nullable V value) { 93 + final var entry = this.byValue.get(value); 94 + if (entry == null) { 95 + return null; 96 + } 97 + return entry.key(); 98 + } 99 + 100 + @Override 101 + public <T> Stream<T> keys(final DynamicOps<T> ops) { 102 + return this.keySet().stream().map(k -> 103 + ops.createString(this.keyToStringFn.apply(k)) 104 + ); 105 + } 106 + 107 + }
+56
registry-dfu/src/main/java/com/nayrid/registry/dfu/KeyableRegistry.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.Keyable; 28 + import com.nayrid.registry.Registry; 29 + import com.nayrid.registry.entry.RegistryEntry; 30 + 31 + /** 32 + * A registry that is compatible with DataFixerUpper. 33 + * 34 + * @param <K> the type of keys 35 + * @param <V> the type of values 36 + * @since 1.0.0 37 + */ 38 + public interface KeyableRegistry<K, V> extends Registry<K, V>, Keyable { 39 + 40 + /** 41 + * Returns the codec for serializing {@code V}. 42 + * 43 + * @return the codec for serializing {@code V}. 44 + * @since 1.0.0 45 + */ 46 + Codec<V> codec(); 47 + 48 + /** 49 + * Returns the codec for serializing the registry entry of {@code V}. 50 + * 51 + * @return the codec for serializing the registry entry of {@code V}. 52 + * @since 1.0.0 53 + */ 54 + Codec<RegistryEntry<K, V>> entryCodec(); 55 + 56 + }
+7
registry-dfu/src/main/java/com/nayrid/registry/dfu/package-info.java
··· 1 + /** 2 + * Registries with support for DataFixerUpper and {@link com.mojang.serialization.Codec#dispatch(java.util.function.Function, java.util.function.Function) Codec#dispatch}. 3 + */ 4 + @NullMarked 5 + package com.nayrid.registry.dfu; 6 + 7 + import org.jspecify.annotations.NullMarked;
+75
registry-dfu/src/test/java/com/nayrid/registry/dfu/CodecRegistryTests.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu; 25 + 26 + import com.google.gson.JsonElement; 27 + import com.mojang.serialization.DataResult; 28 + import com.mojang.serialization.JsonOps; 29 + import com.nayrid.registry.dfu.bean.Bean; 30 + import com.nayrid.registry.dfu.bean.BeanTypes; 31 + import com.nayrid.registry.dfu.bean.CountingBean; 32 + import com.nayrid.registry.dfu.bean.StringyBean; 33 + import org.junit.jupiter.api.Assertions; 34 + import org.junit.jupiter.api.Test; 35 + 36 + import static org.junit.jupiter.api.Assertions.assertEquals; 37 + import static org.junit.jupiter.api.Assertions.assertInstanceOf; 38 + 39 + public final class CodecRegistryTests { 40 + 41 + @Test 42 + void testCountingBean() { 43 + final CountingBean countingBean = new CountingBean(123); 44 + 45 + final DataResult<JsonElement> result = Bean.CODEC.encodeStart(JsonOps.INSTANCE, countingBean); 46 + final JsonElement element = result.getOrThrow(); 47 + 48 + assertEquals("{\"counting_number\":123,\"type\":\"counting_bean\"}", element.toString()); 49 + 50 + final Bean decodedBean = Bean.CODEC.parse(JsonOps.INSTANCE, element).getOrThrow(); 51 + 52 + Assertions.assertEquals(BeanTypes.COUNTING_BEAN, decodedBean.type()); 53 + assertInstanceOf(CountingBean.class, decodedBean); 54 + final CountingBean castedBean = (CountingBean) decodedBean; 55 + assertEquals(countingBean.countingNumber(), castedBean.countingNumber()); 56 + } 57 + 58 + @Test 59 + void testStringyBean() { 60 + final StringyBean stringyBean = new StringyBean("Hello World"); 61 + 62 + final DataResult<JsonElement> result = Bean.CODEC.encodeStart(JsonOps.INSTANCE, stringyBean); 63 + final JsonElement element = result.getOrThrow(); 64 + 65 + assertEquals("{\"stringy_string\":\"Hello World\",\"type\":\"stringy_bean\"}", element.toString()); 66 + 67 + final Bean decodedBean = Bean.CODEC.parse(JsonOps.INSTANCE, element).getOrThrow(); 68 + 69 + Assertions.assertEquals(BeanTypes.STRINGY_BEAN, decodedBean.type()); 70 + assertInstanceOf(StringyBean.class, decodedBean); 71 + final StringyBean castedBean = (StringyBean) decodedBean; 72 + assertEquals(stringyBean.stringyString(), castedBean.stringyString()); 73 + } 74 + 75 + }
+37
registry-dfu/src/test/java/com/nayrid/registry/dfu/KeyableRegistryImpl.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.Lifecycle; 28 + 29 + import java.util.function.Function; 30 + 31 + public final class KeyableRegistryImpl<K, V> extends AbstractKeyableRegistry<K, V> { 32 + 33 + public KeyableRegistryImpl(final K registryKey, final Lifecycle lifecycle, final Codec<K> keyCodec, final Function<K, String> keyToStringFn) { 34 + super(registryKey, lifecycle, keyCodec, keyToStringFn); 35 + } 36 + 37 + }
+35
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/Bean.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu.bean; 25 + 26 + import com.mojang.serialization.Codec; 27 + 28 + public interface Bean { 29 + 30 + Codec<Bean> CODEC = BeanType.REGISTRY.codec() 31 + .dispatch("type", Bean::type, BeanType::codec); 32 + 33 + BeanType<?> type(); 34 + 35 + }
+39
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/BeanType.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu.bean; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.Lifecycle; 28 + import com.mojang.serialization.MapCodec; 29 + import com.nayrid.registry.dfu.KeyableRegistry; 30 + import com.nayrid.registry.dfu.KeyableRegistryImpl; 31 + 32 + import java.util.function.Function; 33 + 34 + public record BeanType<T extends Bean>(MapCodec<T> codec) { 35 + 36 + public static final KeyableRegistry<String, BeanType<?>> REGISTRY = new KeyableRegistryImpl<>( 37 + "beans", Lifecycle.stable(), Codec.STRING, Function.identity()); 38 + 39 + }
+39
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/BeanTypes.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu.bean; 25 + 26 + public final class BeanTypes { 27 + 28 + private BeanTypes() { 29 + } 30 + 31 + public static final BeanType<StringyBean> STRINGY_BEAN = register("stringy_bean", new BeanType<>(StringyBean.CODEC)); 32 + public static final BeanType<CountingBean> COUNTING_BEAN = register("counting_bean", new BeanType<>(CountingBean.CODEC)); 33 + 34 + @SuppressWarnings("unchecked") 35 + public static <T extends Bean> BeanType<T> register(final String key, final BeanType<T> beanType) { 36 + return (BeanType<T>) BeanType.REGISTRY.register(key, beanType).valueOrThrow(); 37 + } 38 + 39 + }
+41
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/CountingBean.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu.bean; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.MapCodec; 28 + import com.mojang.serialization.codecs.RecordCodecBuilder; 29 + 30 + public record CountingBean(int countingNumber) implements Bean { 31 + 32 + public static final MapCodec<CountingBean> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( 33 + Codec.INT.fieldOf("counting_number").forGetter(CountingBean::countingNumber)) 34 + .apply(instance, CountingBean::new)); 35 + 36 + @Override 37 + public BeanType<?> type() { 38 + return BeanTypes.COUNTING_BEAN; 39 + } 40 + 41 + }
+41
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/StringyBean.java
··· 1 + /* 2 + * This file is part of registry, 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.registry.dfu.bean; 25 + 26 + import com.mojang.serialization.Codec; 27 + import com.mojang.serialization.MapCodec; 28 + import com.mojang.serialization.codecs.RecordCodecBuilder; 29 + 30 + public record StringyBean(String stringyString) implements Bean { 31 + 32 + public static final MapCodec<StringyBean> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( 33 + Codec.STRING.fieldOf("stringy_string").forGetter(StringyBean::stringyString)) 34 + .apply(instance, StringyBean::new)); 35 + 36 + @Override 37 + public BeanType<?> type() { 38 + return BeanTypes.STRINGY_BEAN; 39 + } 40 + 41 + }
+4
registry-dfu/src/test/java/com/nayrid/registry/dfu/bean/package-info.java
··· 1 + @NullMarked 2 + package com.nayrid.registry.dfu.bean; 3 + 4 + import org.jspecify.annotations.NullMarked;
+4
registry-dfu/src/test/java/com/nayrid/registry/dfu/package-info.java
··· 1 + @NullMarked 2 + package com.nayrid.registry.dfu; 3 + 4 + import org.jspecify.annotations.NullMarked;
+29
settings.gradle.kts
··· 1 + enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 2 + 3 + dependencyResolutionManagement { 4 + repositories { 5 + mavenCentral() 6 + maven { 7 + url = uri("https://libraries.minecraft.net") 8 + name = "minecraft" 9 + } 10 + maven { 11 + name = "nayridSnapshots" 12 + url = uri("https://repo.nayrid.com/snapshots") 13 + } 14 + } 15 + } 16 + 17 + pluginManagement { 18 + repositories { 19 + gradlePluginPortal() 20 + } 21 + includeBuild("build-logic") 22 + } 23 + 24 + rootProject.name = "registry" 25 + 26 + sequenceOf("api", "dfu").forEach { 27 + include("${rootProject.name}-$it") 28 + project(":${rootProject.name}-$it").projectDir = file("${rootProject.name}-$it") 29 + }