diff --git a/build.gradle b/build.gradle index 2bd2892..3202ee3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,24 @@ -//file:noinspection GroovyAssignabilityCheck plugins { - id 'java' - id 'idea' id 'java-library' id 'maven-publish' - id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'net.neoforged.moddev.legacyforge' version '2.0.103' -} - -java { - toolchain.languageVersion = JavaLanguageVersion.of(17) + id 'net.neoforged.moddev' version '2.0.116' + id 'idea' } tasks.named('wrapper', Wrapper).configure { + // Define wrapper values here so as to not have to always do so when updating gradlew.properties. + // Switching this to Wrapper.DistributionType.ALL will download the full gradle sources that comes with + // documentation attached on cursor hover of gradle classes and methods. However, this comes with increased + // file size for Gradle. If you do switch this to ALL, run the Gradle wrapper task twice afterwards. + // (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`) distributionType = Wrapper.DistributionType.BIN } -version = "${minecraft_version}-${mod_version}" +version = mod_version group = mod_group_id repositories { + // Add here additional repositories if required by some of the dependencies below. mavenLocal() maven { url = "https://libraries.minecraft.net/" } maven { url = "https://neoforged.forgecdn.net/releases" } @@ -38,24 +37,31 @@ base { archivesName = mod_id } -// Mojang ships Java 17 to end users in 1.20.1, so mods should target Java 17. -java.toolchain.languageVersion = JavaLanguageVersion.of(17) +// Mojang ships Java 21 to end users in 1.21.10, so mods should target Java 21. +java.toolchain.languageVersion = JavaLanguageVersion.of(21) -legacyForge { - // Specify the version of MinecraftForge to use. - version = project.minecraft_version + '-' + project.forge_version +neoForge { + // Specify the version of NeoForge to use. + version = project.neo_version parchment { mappingsVersion = project.parchment_mappings_version minecraftVersion = project.parchment_minecraft_version } + // This line is optional. Access Transformers are automatically detected + accessTransformers = project.files('src/main/templates/META-INF/accesstransformer.cfg') + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. runs { client { client() - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } + clientAuth{ devLogin = true client() @@ -64,27 +70,47 @@ legacyForge { server { server() - programArgument '--nogui' - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. gameTestServer { type = "gameTestServer" - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } data { - data() + clientData() + + // example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it + // gameDirectory = project.file('run-data') + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() } + // applies to all the run configs above configureEach { + // Recommended logging data for a userdev environment + // The markers can be added/remove as needed separated by commas. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. systemProperty 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels logLevel = org.slf4j.event.Level.DEBUG } } mods { + // define mod <-> source bindings + // these are used to tell the game which sources are for which mod + // multi mod projects should define one per mod "${mod_id}" { sourceSet(sourceSets.main) } @@ -94,267 +120,86 @@ legacyForge { // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } +// Sets up a dependency configuration called 'localRuntime'. +// This configuration should be used instead of 'runtimeOnly' to declare +// a dependency that will be present for runtime testing but that is +// "optional", meaning it will not be pulled by dependents of this mod. configurations { runtimeClasspath.extendsFrom localRuntime } -obfuscation { - createRemappingConfiguration(configurations.localRuntime) -} dependencies { - // 依赖项可以在这里添加 + // Example optional mod dependency with JEI + // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime + // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" + // compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" + // We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it + // localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" + // Example mod dependency using a mod jar from ./libs with a flat dir repository + // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar + // The group id is ignored when searching -- in this case, it is "blank" + // implementation "blank:coolmod-${mc_version}:${coolmod_version}" + + // Example mod dependency using a file as dependency + // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") + + // Example project dependency using a sister or child project: + // implementation project(":myproject") + + // For more info: + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html } // This block of code expands all declared replace properties in the specified resource targets. +// A missing property will result in an error. Properties are expanded using ${} Groovy notation. var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ - minecraft_version : minecraft_version, - minecraft_version_range : minecraft_version_range, - forge_version : forge_version, - forge_version_range : forge_version_range, - loader_version_range : loader_version_range, - mod_id : mod_id, - mod_name : mod_name, - mod_license : mod_license, - mod_version : mod_version, - mod_authors : mod_authors, - mod_description : mod_description, - mod_credits : mod_credits + minecraft_version : minecraft_version, + minecraft_version_range: minecraft_version_range, + neo_version : neo_version, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, + mod_authors : mod_authors, + mod_credits : mod_credits, + mod_description : mod_description ] - duplicatesStrategy = DuplicatesStrategy.EXCLUDE inputs.properties replaceProperties expand replaceProperties from "src/main/templates" into "build/generated/sources/modMetadata" } - +// Include the output of "generateModMetadata" as an input directory for the build +// this works with both building through Gradle and the IDE. sourceSets.main.resources.srcDir generateModMetadata -legacyForge.ideSyncTask generateModMetadata +// To avoid having to run "generateModMetadata" manually, make it run on every project reload +neoForge.ideSyncTask generateModMetadata -// ==================== Javadoc 配置 ==================== -javadoc { - options { - encoding = 'UTF-8' - charSet = 'UTF-8' - author = true - version = true - windowTitle = "Lib39 ${project.mod_version} API" - docTitle = "Lib39 ${project.mod_version} API" - memberLevel = JavadocMemberLevel.PROTECTED - links = [ - 'https://docs.oracle.com/javase/8/docs/api/' - ] - addBooleanOption('Xdoclint:none', true) - addBooleanOption('html5', true) - } - - source = sourceSets.main.allJava - classpath = configurations.compileClasspath - exclude '**/test/**' - exclude '**/internal/**' -} - -tasks.register('javadocJar', Jar) { - archiveClassifier.set('javadoc') - from tasks.javadoc - dependsOn tasks.javadoc -} - -// ===================== 主包完整 Jar(class + java) ===================== -tasks.register('deobfJar', Jar) { - archiveFileName = "${mod_id}-${minecraft_version}-${mod_version}.jar" - from(sourceSets.main.output) - - // === 避免重复打包资源(即使混入其他 jar 时也不会重复) === - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - - manifest { - attributes( - 'Specification-Title': mod_id, - 'Specification-Vendor': mod_authors, - 'Implementation-Title': project.name, - 'Implementation-Version': archiveVersion, - 'Implementation-Vendor': mod_authors, - 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ) - } - - dependsOn classes -} - - - - -// ==================== 发布配置 ==================== +// Example configuration to allow publishing using the maven-publish plugin publishing { publications { - mavenJava(MavenPublication) { - artifactId = mod_id - artifact deobfJar - artifact javadocJar - - pom { - name = 'Lib39' - description = 'Lib39 is a general-purpose dependency library for Minecraft mods.' - url = 'https://github.com/3944Realms/lib39' - - properties = [ - 'minecraft.version': project.minecraft_version, - 'mod.version': project.mod_version, - 'forge.version': project.forge_version, - 'java.version': '17' - ] - - licenses { - license { - name = 'MIT' - url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE' - distribution = 'repo' - } - } - - developers { - developer { - id = 'R3944Realms' - name = "${mod_authors}" - email = 'f256198830@hotmail.com' - } - } - - scm { - connection = 'scm:git:https://github.com/3944Realms/lib39.git' - developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git' - url = 'https://github.com/3944Realms/lib39' - tag = 'main' - } - - issueManagement { - system = 'GitHub' - url = 'https://github.com/3944Realms/lib39/issues' - } - } + register('mavenJava', MavenPublication) { + from components.java } } - repositories { - // 本地仓库 maven { - name = 'local' - url = layout.buildDirectory.dir("repo") - } - - // Nexus 远程仓库 - maven { - name = 'LTDNexus' - url = 'https://nexus.bot.leisuretimedock.top/repository/maven-releases/' - credentials { - username = System.getenv('LTDNexusUsername') ?: '' - password = System.getenv('LTDNexusPassword') ?: '' - } + url "file://${project.projectDir}/repo" } } } -// ==================== 任务配置 ==================== tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' - options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation'] + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } -// 配置 Javadoc JAR - 使用标准 javadoc 任务输出 -tasks.named('javadocJar') { - from javadoc.destinationDir -} -// ==================== 验证任务 ==================== -tasks.register('verifyNexusCredentials') { - doLast { - def username = System.getenv('LTDNexusUsername') - def password = System.getenv('LTDNexusPassword') - - // 安全地显示用户名和密码(只显示最后两位) - def displayUsername = username ? "***${username.length() > 2 ? username.substring(username.length() - 2) : '**'}" : 'NOT SET' - def displayPassword = password ? "***${password.length() > 2 ? password.substring(password.length() - 2) : '**'}" : 'NOT SET' - - println "Nexus Username: ${displayUsername}" - println "Nexus Password: ${displayPassword}" - - if (!username || !password) { - throw new GradleException('LTDNexusUsername or LTDNexusPassword environment variables are not set') - } - } -} - -tasks.register('checkPublicationContents') { - doLast { - def publication = publishing.publications.mavenJava - println "=== Publication Details ===" - println "Group: ${publication.groupId}" - println "Artifact: ${publication.artifactId}" - println "Version: ${publication.version}" - println "Artifacts:" - publication.artifacts.each { artifact -> - def file = artifact.file - def exists = file.exists() - println " - ${file.name} (${artifact.classifier ?: 'main'}) - Exists: ${exists}" - - if (!exists) { - throw new GradleException("Publication artifact missing: ${file.absolutePath}") - } - } - } -} - -// ==================== 任务依赖 ==================== -tasks.named('publishMavenJavaPublicationToLTDNexusRepository') { - dependsOn verifyNexusCredentials - dependsOn checkPublicationContents -} - -tasks.withType(PublishToMavenRepository) { - dependsOn assemble - dependsOn javadocJar -} - -// ==================== 便捷任务 ==================== -tasks.register('publishToNexus') { - group = 'publishing' - description = 'Publishes all publications to LTD Nexus' - dependsOn 'publishMavenJavaPublicationToLTDNexusRepository' -} - -tasks.register('publishLocal') { - group = 'publishing' - description = 'Publishes all publications to the local Maven repository' - dependsOn 'publishToMavenLocal' -} - -tasks.register('cleanRepo', Delete) { - delete layout.buildDirectory.dir("repo") -} - -tasks.named('clean') { - dependsOn cleanRepo -} - -// ==================== IDEA 配置 ==================== +// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. idea { module { downloadSources = true downloadJavadoc = true } } - -// 禁用模块元数据生成 -tasks.withType(GenerateModuleMetadata) { - enabled = false -} - -afterEvaluate { - tasks.named('deobfJar') { - doLast { - def jar = file(layout.buildDirectory.dir("repo") + "${mod_id}-${minecraft_version}-${mod_version}.jar") - if (jar.exists()) ant.delete(jar) - } - } -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f707d4d..43c58b4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,22 +7,18 @@ org.gradle.configuration-cache=false #read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment # you can also find the latest versions at: https://parchmentmc.org/docs/getting-started -parchment_minecraft_version=1.20.1 -parchment_mappings_version=2023.09.03 +parchment_minecraft_version=1.21.10 +parchment_mappings_version=2025.10.12 # Environment Properties # You can find the latest versions here: https://files.minecraftforge.net/net/minecraftforge/forge/index_1.20.1.html # The Minecraft version must agree with the Forge version to get a valid artifact -minecraft_version=1.20.1 +minecraft_version=1.21.10 # The Minecraft version range can use any release version of Minecraft as bounds. # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly # as they do not follow standard versioning conventions. -minecraft_version_range=[1.20.1, 1.21) -# The Forge version must agree with the Minecraft version to get a valid artifact -forge_version=47.1.3 -# The Forge version range can use any version of Forge as bounds -forge_version_range=[47.1.3,) -# The loader version range can only use the major version of FML as bounds -loader_version_range=[47,) +minecraft_version_range=[1.21.10] + +neo_version=21.10.42-beta ## Mod Properties # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} diff --git a/settings.gradle b/settings.gradle index bcbdfe2..153968c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,11 @@ -//file:noinspection GroovyAssignabilityCheck pluginManagement { repositories { - mavenLocal() gradlePluginPortal() maven { url = 'https://maven.neoforged.net/releases' } - maven { url = 'https://maven.parchmentmc.org' } // Add this line + maven { url = 'https://maven.parchmentmc.org' } } } + plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' -} \ No newline at end of file +} diff --git a/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 b/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 deleted file mode 100644 index 6acc8d5..0000000 --- a/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2025-10-25T19:14:21.1829335 Languages: zh_tw -4cb94c651f6aa74538a2ab25cb183cffd75be688 assets/lib39/lang/zh_tw.json diff --git a/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac b/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac deleted file mode 100644 index d291622..0000000 --- a/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2025-10-25T19:14:21.1764262 Languages: zh_cn -a1db601a0fca923c5434b8b0843773a3115d0b59 assets/lib39/lang/zh_cn.json diff --git a/src/generated/resources/.cache/2dbf84d84cf6f7b7a95fea9038e192dbf226e5f5 b/src/generated/resources/.cache/2dbf84d84cf6f7b7a95fea9038e192dbf226e5f5 deleted file mode 100644 index c17c4ef..0000000 --- a/src/generated/resources/.cache/2dbf84d84cf6f7b7a95fea9038e192dbf226e5f5 +++ /dev/null @@ -1,3 +0,0 @@ -// 1.20.1 2025-10-25T18:42:29.3405259 Item Models: lib39 -14f581c8f8e7f0de004c57a180f371e60e7b12ae assets/lib39/models/item/fabric.json -447b36747d0aa8748dcd86715f4cce2cff19aca7 assets/lib39/models/item/neoforge.json diff --git a/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 b/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 deleted file mode 100644 index b518cbb..0000000 --- a/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2025-10-25T19:14:21.1804258 Languages: lzh -098df025475d3f4d9d2abefa91a7d38c44644ba4 assets/lib39/lang/lzh.json diff --git a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 deleted file mode 100644 index 99da09b..0000000 --- a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2025-10-25T19:14:21.1784269 Languages: en_us -c6b6aadca0a922823a8c949ebde93f8f999737f9 assets/lib39/lang/en_us.json diff --git a/src/generated/resources/assets/lib39/lang/en_us.json b/src/generated/resources/assets/lib39/lang/en_us.json deleted file mode 100644 index 1989dd6..0000000 --- a/src/generated/resources/assets/lib39/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "item.lib39.fabric": "Fabric", - "item.lib39.neoforge": "NeoForge" -} \ No newline at end of file diff --git a/src/generated/resources/assets/lib39/lang/lzh.json b/src/generated/resources/assets/lib39/lang/lzh.json deleted file mode 100644 index 865d7b3..0000000 --- a/src/generated/resources/assets/lib39/lang/lzh.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "item.lib39.fabric": "織", - "item.lib39.neoforge": "狸" -} \ No newline at end of file diff --git a/src/generated/resources/assets/lib39/lang/zh_cn.json b/src/generated/resources/assets/lib39/lang/zh_cn.json deleted file mode 100644 index ad3ca87..0000000 --- a/src/generated/resources/assets/lib39/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "item.lib39.fabric": "织布", - "item.lib39.neoforge": "小狐狸" -} \ No newline at end of file diff --git a/src/generated/resources/assets/lib39/lang/zh_tw.json b/src/generated/resources/assets/lib39/lang/zh_tw.json deleted file mode 100644 index e14a166..0000000 --- a/src/generated/resources/assets/lib39/lang/zh_tw.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "item.lib39.fabric": "織布", - "item.lib39.neoforge": "狐狸" -} \ No newline at end of file diff --git a/src/generated/resources/assets/lib39/models/item/fabric.json b/src/generated/resources/assets/lib39/models/item/fabric.json deleted file mode 100644 index 828b259..0000000 --- a/src/generated/resources/assets/lib39/models/item/fabric.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "lib39:item/fabric" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/lib39/models/item/neoforge.json b/src/generated/resources/assets/lib39/models/item/neoforge.json deleted file mode 100644 index c0446b5..0000000 --- a/src/generated/resources/assets/lib39/models/item/neoforge.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "lib39:item/neoforge" - } -} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/Lib39.java b/src/main/java/top/r3944realms/lib39/Lib39.java index e294953..2bd4fb8 100644 --- a/src/main/java/top/r3944realms/lib39/Lib39.java +++ b/src/main/java/top/r3944realms/lib39/Lib39.java @@ -1,11 +1,12 @@ package top.r3944realms.lib39; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.loading.FMLEnvironment; + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.ModList; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.FMLEnvironment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import top.r3944realms.lib39.core.network.NetworkHandler; import top.r3944realms.lib39.example.Lib39Example; /** @@ -25,19 +26,18 @@ public class Lib39 { /** * Instantiates a new Lib 39. */ - public Lib39() { - initialize(); + public Lib39(IEventBus event) { + initialize(event); } /** * Initialize. */ - public static void initialize() { + public static void initialize(IEventBus event) { LOGGER.info("[Lib39] Initializing Lib39"); - NetworkHandler.register(); if (shouldRegisterExamples()) { LOGGER.info("[Lib39] Registering Examples"); - registerExamples(); + registerExamples(event); } LOGGER.info("[Lib39] Initialized Lib39"); @@ -66,17 +66,17 @@ public class Lib39 { * @return the boolean */ static boolean shouldRegisterExamples() { - return !FMLEnvironment.production; + return !FMLEnvironment.isProduction(); } /** * Register examples. */ - static void registerExamples() { + static void registerExamples(IEventBus event) { LOGGER.info("[Lib39] Starting example demonstrations"); try { // 创建示例实例并演示功能 - Lib39Example example = new Lib39Example(); + Lib39Example example = new Lib39Example(event); example.demonstrateFeature(); LOGGER.info("[Lib39] Example demonstrations completed successfully"); diff --git a/src/main/java/top/r3944realms/lib39/api/event/RegisterCompatEvent.java b/src/main/java/top/r3944realms/lib39/api/event/RegisterCompatEvent.java index f34b815..9cc1463 100644 --- a/src/main/java/top/r3944realms/lib39/api/event/RegisterCompatEvent.java +++ b/src/main/java/top/r3944realms/lib39/api/event/RegisterCompatEvent.java @@ -1,8 +1,8 @@ package top.r3944realms.lib39.api.event; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.event.IModBusEvent; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.event.IModBusEvent; import top.r3944realms.lib39.core.compat.CompatManager; import top.r3944realms.lib39.core.compat.ICompat; diff --git a/src/main/java/top/r3944realms/lib39/api/event/SyncManagerRegisterEvent.java b/src/main/java/top/r3944realms/lib39/api/event/SyncManagerRegisterEvent.java index ebb61a4..ebdf342 100644 --- a/src/main/java/top/r3944realms/lib39/api/event/SyncManagerRegisterEvent.java +++ b/src/main/java/top/r3944realms/lib39/api/event/SyncManagerRegisterEvent.java @@ -2,8 +2,7 @@ package top.r3944realms.lib39.api.event; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.eventbus.api.Event; +import net.neoforged.bus.api.Event; import top.r3944realms.lib39.core.sync.ISyncData; import top.r3944realms.lib39.core.sync.ISyncManager; import top.r3944realms.lib39.core.sync.SyncData2Manager; @@ -39,22 +38,6 @@ public class SyncManagerRegisterEvent extends Event { return syncs2Manager; } - /** - * 类型安全的同步管理器注册 - * - * @param the type parameter - * @param the type parameter - * @param id the id - * @param syncManager the sync manager - * @param capability the capability - */ - public > void registerSyncManager( - ResourceLocation id, - ISyncManager syncManager, - Capability capability - ) { - syncs2Manager.registerManager(id, syncManager, entity -> entity.getCapability(capability).resolve()); - } /** * 类型安全的同步管理器注册 @@ -103,16 +86,6 @@ public class SyncManagerRegisterEvent extends Event { syncs2Manager.disallowEntityClass(id, entityClasses); } - /** - * 绑定能力(用于分离注册的情况) - * - * @param the type parameter - * @param id 必须先注册安全同步管理器,再绑定Cap,否则会抛出{@link IllegalStateException 未找到对应安全同步管理器} - * @param capability the capability - */ - public > void bindCapability(ResourceLocation id, Capability capability) { - syncs2Manager.bindDataGetter(id, entity -> entity.getCapability(capability).resolve()); - } /** * 解绑数据提供者 @@ -123,27 +96,6 @@ public class SyncManagerRegisterEvent extends Event { syncs2Manager.unbindDataProvider(id); } - /** - * 完整的类型安全注册 - * - * @param the type parameter - * @param the type parameter - * @param id the id - * @param syncManager the sync manager - * @param capability the capability - * @param allowedEntityClasses the allowed entity classes - */ - public > void registerComplete( - ResourceLocation id, - ISyncManager syncManager, - Capability capability, - Class... allowedEntityClasses - ) { - registerSyncManager(id, syncManager, capability); - if (allowedEntityClasses.length > 0) { - addAllowEntityClass(id, allowedEntityClasses); - } - } /** * 完整的类型安全注册 diff --git a/src/main/java/top/r3944realms/lib39/core/compat/CompatManager.java b/src/main/java/top/r3944realms/lib39/core/compat/CompatManager.java index 6bede5d..88def3e 100644 --- a/src/main/java/top/r3944realms/lib39/core/compat/CompatManager.java +++ b/src/main/java/top/r3944realms/lib39/core/compat/CompatManager.java @@ -1,9 +1,8 @@ package top.r3944realms.lib39.core.compat; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.Lib39; @@ -58,7 +57,7 @@ public class CompatManager { * @param compat the compat */ public void registerCompat(String namespace, String path, ICompat compat) { - registerCompat(new ResourceLocation(namespace, path), compat); + registerCompat(ResourceLocation.fromNamespaceAndPath(namespace, path), compat); } /** @@ -67,8 +66,8 @@ public class CompatManager { * @param dists the dists * @param bus the bus */ - public void addListenerForAll(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus) { - listenerConfigs.add(new ListenerConfig(null, dists, bus)); + public void addListenerForAll(@Nullable Dist dists, boolean isModbus) { + listenerConfigs.add(new ListenerConfig(null, dists, isModbus)); } /** @@ -78,8 +77,8 @@ public class CompatManager { * @param dists the dists * @param bus the bus */ - public void addListenerForCompat(ResourceLocation compatId, @Nullable Dist dists, Mod.EventBusSubscriber.Bus bus) { - listenerConfigs.add(new ListenerConfig(compatId, dists, bus)); + public void addListenerForCompat(ResourceLocation compatId, @Nullable Dist dists, boolean isModbus) { + listenerConfigs.add(new ListenerConfig(compatId, dists, isModbus)); } /** @@ -89,8 +88,8 @@ public class CompatManager { * @param bus the bus * @param consumer the consumer */ - public void addListenerForLoaded(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus, Consumer consumer) { - listenerConfigs.add(new ListenerConfig(null, dists, bus) { + public void addListenerForLoaded(@Nullable Dist dists, boolean isModbus, Consumer consumer) { + listenerConfigs.add(new ListenerConfig(null, dists, isModbus) { @Override boolean shouldApply(@NotNull ICompat compat) { return super.shouldApply(compat); @@ -167,14 +166,14 @@ public class CompatManager { if (config.dists != null) { switch (config.dists) { case CLIENT -> { - if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) { + if (!config.isModBus) { compat.addClientGameListener(gameEventBus); } else { compat.addClientModListener(modEventBus); } } case DEDICATED_SERVER -> { - if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) { + if (!config.isModBus) { compat.addServerGameListener(gameEventBus); } else { compat.addServerModListener(modEventBus); @@ -183,7 +182,7 @@ public class CompatManager { } } else { // 通用监听器 - if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) { + if (!config.isModBus) { compat.addCommonGameListener(gameEventBus); } else { compat.addCommonModListener(modEventBus); @@ -204,9 +203,9 @@ public class CompatManager { private @NotNull String getListenerTypeName(@NotNull ListenerConfig config) { if (config.dists != null) { return config.dists.name().toLowerCase() + " " + - (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod"); + (!config.isModBus ? "game" : "mod"); } else { - return "common " + (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod"); + return "common " + (!config.isModBus ? "game" : "mod"); } } @@ -217,8 +216,8 @@ public class CompatManager { * @param compatId the compat id * @param bus the bus */ - public void addListenerForCompat(ResourceLocation compatId, Mod.EventBusSubscriber.Bus bus) { - addListenerForCompat(compatId, null, bus); + public void addListenerForCompat(ResourceLocation compatId, boolean isModbus) { + addListenerForCompat(compatId, null, isModbus); } private static class ListenerConfig { @@ -233,7 +232,7 @@ public class CompatManager { /** * The Bus. */ - final Mod.EventBusSubscriber.Bus bus; + final boolean isModBus; /** * Instantiates a new Listener config. @@ -242,10 +241,10 @@ public class CompatManager { * @param dists the dists * @param bus the bus */ - ListenerConfig(ResourceLocation compatId, Dist dists, Mod.EventBusSubscriber.Bus bus) { + ListenerConfig(ResourceLocation compatId, Dist dists, boolean isModbus) { this.compatId = compatId; this.dists = dists; - this.bus = bus; + this.isModBus = isModbus; } /** diff --git a/src/main/java/top/r3944realms/lib39/core/compat/ICompat.java b/src/main/java/top/r3944realms/lib39/core/compat/ICompat.java index 467bfa6..d53479a 100644 --- a/src/main/java/top/r3944realms/lib39/core/compat/ICompat.java +++ b/src/main/java/top/r3944realms/lib39/core/compat/ICompat.java @@ -1,7 +1,7 @@ package top.r3944realms.lib39.core.compat; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.eventbus.api.IEventBus; +import net.neoforged.bus.api.IEventBus; import java.util.concurrent.Callable; diff --git a/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java b/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java index a4951fa..eaa5662 100644 --- a/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java +++ b/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java @@ -7,21 +7,24 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.event.entity.EntityLeaveLevelEvent; -import net.minecraftforge.event.level.LevelEvent; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; +import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; +import net.neoforged.neoforge.event.entity.EntityLeaveLevelEvent; +import net.neoforged.neoforge.event.level.LevelEvent; +import net.neoforged.neoforge.event.tick.ServerTickEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.registries.DeferredHolder; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.api.event.RegisterCompatEvent; import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent; import top.r3944realms.lib39.core.compat.CompatManager; +import top.r3944realms.lib39.core.network.NetworkHandler; import top.r3944realms.lib39.core.sync.ISyncData; import top.r3944realms.lib39.core.sync.SyncData2Manager; @@ -38,7 +41,7 @@ public class CommonEventHandler { * The type Game. */ @SuppressWarnings("unused") - @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE) + @EventBusSubscriber(modid = Lib39.MOD_ID) public static class Game extends CommonEventHandler { private static ServerLevel sl; @@ -79,7 +82,7 @@ public class CommonEventHandler { synchronized (Game.class) { if (!isSync2MInitialized) { syncData2Manager = new SyncData2Manager(); - MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager)); + NeoForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager)); isSync2MInitialized = true; sl = serverLevel; Lib39.LOGGER.info("SyncData2Manager initialized on world load"); @@ -107,13 +110,11 @@ public class CommonEventHandler { * @param event the event */ @SubscribeEvent - public static void onServerTick(TickEvent.ServerTickEvent event) { - if (event.phase == TickEvent.Phase.END) { - if (syncData2Manager == null) return; - if (event.getServer().getTickCount() % 10 == 0) - syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::markDirty))); - syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::checkIfDirtyThenUpdate))); - } + public static void onServerTick(ServerTickEvent.Post event) { + if (syncData2Manager == null) return; + if (event.getServer().getTickCount() % 10 == 0) + syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::markDirty))); + syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::checkIfDirtyThenUpdate))); } /** @@ -124,7 +125,7 @@ public class CommonEventHandler { @SubscribeEvent public static void onEntityJoinWorld(EntityJoinLevelEvent event) { Entity entity = event.getEntity(); - if (entity.level().isClientSide) return; + if (entity.level().isClientSide()) return; for (ResourceLocation id : syncData2Manager.getRegisteredKeys()) { if (syncData2Manager.isEntityClassAllowed(id, entity.getClass())) { @@ -141,7 +142,7 @@ public class CommonEventHandler { @SubscribeEvent public static void onEntityLeaveWorld(EntityLeaveLevelEvent event) { Entity entity = event.getEntity(); - if (entity.level().isClientSide) return; + if (entity.level().isClientSide()) return; for (ResourceLocation id : syncData2Manager.getRegisteredKeys()) { if (syncData2Manager.isEntityClassAllowed(id, entity.getClass())) { @@ -155,10 +156,10 @@ public class CommonEventHandler { * The type Mod. */ @SuppressWarnings("unused") - @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD) + @EventBusSubscriber(modid = Lib39.MOD_ID) public static class Mod extends CommonEventHandler { - private static final Map, ResourceKey[]> itemAddMap = new ConcurrentHashMap<>(); - private static final Map, List>> tabToItemsMap = new ConcurrentHashMap<>(); + private static final Map, ResourceKey[]> itemAddMap = new ConcurrentHashMap<>(); + private static final Map, List>> tabToItemsMap = new ConcurrentHashMap<>(); /** * Gets compat manager. @@ -182,12 +183,16 @@ public class CommonEventHandler { @SubscribeEvent public static void onFMLCommonSetup (FMLCommonSetupEvent event) { event.enqueueWork(() -> { - IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); - IEventBus gameBus = MinecraftForge.EVENT_BUS; + IEventBus modBus = ModLoadingContext.get().getActiveContainer().getEventBus(); + IEventBus gameBus = NeoForge.EVENT_BUS; compatManager = new CompatManager(modBus, gameBus); - MinecraftForge.EVENT_BUS.post(new RegisterCompatEvent(compatManager)); + gameBus.post(new RegisterCompatEvent(compatManager)); }); } + @SubscribeEvent + public static void onPacketRegister (RegisterPayloadHandlersEvent event) { + NetworkHandler.registerPackets(event); + } /** * Add item to tabs. @@ -196,7 +201,7 @@ public class CommonEventHandler { * @param tabs the tabs */ @SafeVarargs - public static void addItemToTabs(RegistryObject item, ResourceKey... tabs) { + public static void addItemToTabs(DeferredHolder item, ResourceKey... tabs) { itemAddMap.put(item, tabs); // 更新反向映射 @@ -212,9 +217,9 @@ public class CommonEventHandler { */ @SubscribeEvent public static void onBuildCreativeTabContents(BuildCreativeModeTabContentsEvent event) { - List> itemsForTab = tabToItemsMap.get(event.getTabKey()); + List> itemsForTab = tabToItemsMap.get(event.getTabKey()); if (itemsForTab != null) { - itemsForTab.forEach(event::accept); + itemsForTab.forEach(i -> event.accept(i.get().asItem().getDefaultInstance(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS)); } } @@ -223,7 +228,7 @@ public class CommonEventHandler { * * @return the item add map */ - public static Map, ResourceKey[]> getItemAddMap() { + public static Map, ResourceKey[]> getItemAddMap() { return itemAddMap; } } diff --git a/src/main/java/top/r3944realms/lib39/core/network/NetworkHandler.java b/src/main/java/top/r3944realms/lib39/core/network/NetworkHandler.java index 78e13ad..e73e194 100644 --- a/src/main/java/top/r3944realms/lib39/core/network/NetworkHandler.java +++ b/src/main/java/top/r3944realms/lib39/core/network/NetworkHandler.java @@ -1,73 +1,17 @@ package top.r3944realms.lib39.core.network; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.PacketDistributor; -import net.minecraftforge.network.simple.SimpleChannel; + +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; -import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPack; /** * The type Network handler. */ @SuppressWarnings("unused") public class NetworkHandler { - private static int cid = 0; - /** - * The constant INSTANCE. - */ - public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( - new ResourceLocation(Lib39.MOD_ID, "main"), - () -> Lib39.ModInfo.VERSION, - Lib39.ModInfo.VERSION::equals, - Lib39.ModInfo.VERSION::equals - ); - - /** - * Register. - */ - public static void register() { - INSTANCE.messageBuilder(SyncNBTCapDataEntityS2CPack.class, cid++, NetworkDirection.PLAY_TO_CLIENT) - .encoder(SyncNBTCapDataEntityS2CPack::encode) - .decoder(SyncNBTCapDataEntityS2CPack::decode) - .consumerNetworkThread(SyncNBTCapDataEntityS2CPack::handle) - .add(); - } - - /** - * Send to player. - * - * @param the type parameter - * @param message the message - * @param player the player - */ - public static void sendToPlayer(MSG message, ServerPlayer player){ - INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message); - } - - /** - * Send to player. - * - * @param the type parameter - * @param the type parameter - * @param message the message - * @param entity the entity - * @param packetDistributor the packet distributor - */ - public static void sendToPlayer(MSG message, T entity, @NotNull PacketDistributor packetDistributor){ - INSTANCE.send(packetDistributor.with(() -> entity), message); - } - - /** - * Send to player. - * - * @param the type parameter - * @param message the message - */ - public static void sendToAllPlayer(MSG message){ - INSTANCE.send(PacketDistributor.ALL.noArg(), message); + public static void registerPackets(@NotNull RegisterPayloadHandlersEvent event) { + PayloadRegistrar registrar = event.registrar(Lib39.MOD_ID + "-" + Lib39.ModInfo.VERSION); } } diff --git a/src/main/java/top/r3944realms/lib39/core/network/toClient/SyncNBTCapDataEntityS2CPack.java b/src/main/java/top/r3944realms/lib39/core/network/toClient/SyncNBTCapDataEntityS2CPack.java deleted file mode 100644 index d841474..0000000 --- a/src/main/java/top/r3944realms/lib39/core/network/toClient/SyncNBTCapDataEntityS2CPack.java +++ /dev/null @@ -1,94 +0,0 @@ -package top.r3944realms.lib39.core.network.toClient; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.network.NetworkEvent; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import top.r3944realms.lib39.Lib39; -import top.r3944realms.lib39.core.event.CommonEventHandler; -import top.r3944realms.lib39.core.sync.ISyncData; -import top.r3944realms.lib39.core.sync.NBTEntitySyncData; -import top.r3944realms.lib39.core.sync.SyncData2Manager; - -import java.util.Optional; -import java.util.function.Supplier; - -/** - * The type Sync nbt data s 2 c pack. - */ -@SuppressWarnings("unused") -public record SyncNBTCapDataEntityS2CPack(int entityId, ResourceLocation id, CompoundTag data) { - - /** - * Instantiates a new Sync nbt data s 2 c pack. - * - * @param entityId the entity id - * @param id the id - * @param data the data - */ - public SyncNBTCapDataEntityS2CPack(int entityId, ResourceLocation id, @NotNull NBTEntitySyncData data) { - this(entityId, data.id(), data.serializeNBT()); - } - - /** - * Encode. - * - * @param msg the msg - * @param buffer the buffer - */ - public static void encode(@NotNull SyncNBTCapDataEntityS2CPack msg, @NotNull FriendlyByteBuf buffer) { - buffer.writeInt(msg.entityId); - buffer.writeResourceLocation(msg.id); - buffer.writeNbt(msg.data); - } - - /** - * Decode sync nbt data s 2 c pack. - * - * @param buffer the buffer - * @return the sync nbt data s 2 c pack - */ - @Contract("_ -> new") - public static @NotNull SyncNBTCapDataEntityS2CPack decode(@NotNull FriendlyByteBuf buffer) { - return new SyncNBTCapDataEntityS2CPack(buffer.readInt(), buffer.readResourceLocation(), buffer.readNbt()); - } - - /** - * Handle. - * - * @param msg the msg - * @param ctx the ctx - */ - public static void handle(SyncNBTCapDataEntityS2CPack msg, @NotNull Supplier ctx) { - NetworkEvent.Context context = ctx.get(); - context.enqueueWork(() -> { - ClientLevel level = Minecraft.getInstance().level; - if (level != null) { - Entity entity = level.getEntity(msg.entityId); - if (entity != null) { - Optional>> capability = - CommonEventHandler.Game - .getSyncData2Manager() - .getDataProvider(msg.id); - capability.flatMap(dataProvider -> dataProvider.getData(entity)) - .ifPresent(cap -> { - if (cap instanceof NBTEntitySyncData nbtCap) { - CompoundTag current = nbtCap.serializeNBT(); - if (!current.equals(msg.data)) { - nbtCap.deserializeNBT(msg.data); - } - } else Lib39.LOGGER.debug("Unhandled sync data: {}", msg.data); - } - ); - } - } - }); - context.setPacketHandled(true); - } - -} diff --git a/src/main/java/top/r3944realms/lib39/core/sync/NBTEntitySyncData.java b/src/main/java/top/r3944realms/lib39/core/sync/NBTEntitySyncData.java deleted file mode 100644 index 73f3470..0000000 --- a/src/main/java/top/r3944realms/lib39/core/sync/NBTEntitySyncData.java +++ /dev/null @@ -1,59 +0,0 @@ -package top.r3944realms.lib39.core.sync; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.util.INBTSerializable; -import org.jetbrains.annotations.NotNull; -import top.r3944realms.lib39.core.network.NetworkHandler; -import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPack; - -/** - * The type Nbt sync data. - */ -public abstract class NBTEntitySyncData implements IEntity, ISyncData, INBTSerializable { - /** - * The Dirty. - */ - protected boolean dirty; - /** - * The Id. - */ - protected final ResourceLocation id; - - /** - * Instantiates a new Nbt sync data. - * - * @param id the id - */ - protected NBTEntitySyncData(ResourceLocation id) { - this.id = id; - } - - @Override - public ResourceLocation id() { - return id; - } - - @Override - public boolean isDirty() { - return dirty; - } - - @Override - public void setDirty(boolean dirty) { - this.dirty = dirty; - } - - @Override - public void copyFrom(@NotNull NBTEntitySyncData src) { - this.dirty = src.isDirty(); - } - - @Override - public void checkIfDirtyThenUpdate() { - if (isDirty()) { - NetworkHandler.sendToAllPlayer(new SyncNBTCapDataEntityS2CPack(entityId(), id(), serializeNBT())); - } - dirty = false; - } -} diff --git a/src/main/java/top/r3944realms/lib39/core/sync/SyncData2CapManager.java b/src/main/java/top/r3944realms/lib39/core/sync/SyncData2CapManager.java deleted file mode 100644 index 71919d6..0000000 --- a/src/main/java/top/r3944realms/lib39/core/sync/SyncData2CapManager.java +++ /dev/null @@ -1,390 +0,0 @@ -package top.r3944realms.lib39.core.sync; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.capabilities.Capability; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.BiConsumer; - -/** - * The type Sync data 2 manager. - */ -@SuppressWarnings("unused") -public class SyncData2CapManager { - private final Map> typedEntries = Maps.newConcurrentMap(); - - private static class TypedSyncEntry> { - /** - * The Manager. - */ - final ISyncManager manager; - /** - * The Capability. - */ - @Nullable - Capability capability; - /** - * The Allowed classes. - */ - final Set> allowedClasses; - - /** - * Instantiates a new Typed sync entry. - * - * @param manager the manager - * @param capability the capability - */ - TypedSyncEntry(ISyncManager manager, @Nullable Capability capability) { - this.manager = manager; - this.capability = capability; - this.allowedClasses = Sets.newConcurrentHashSet(); - } - } - - /** - * Register manager. - * - * @param the type parameter - * @param the type parameter - * @param key the key - * @param manager the manager - * @param capability the capability - */ - public > void registerManager( - ResourceLocation key, - ISyncManager manager, - Capability capability - ) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(manager, "Sync manager cannot be null"); - Objects.requireNonNull(capability, "Capability cannot be null"); - - typedEntries.put(key, new TypedSyncEntry<>(manager, capability)); - } - - /** - * 向后兼容的注册方法(只注册管理器,不注册能力) - * - * @param key the key - * @param manager the manager - */ - @SuppressWarnings("unchecked") - public void registerManager(ResourceLocation key, ISyncManager> manager) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(manager, "Sync manager cannot be null"); - - // 创建一个虚拟的 TypedSyncEntry,但 capability 为 null - // 注意:这种方法会限制类型安全的功能 - typedEntries.put(key, new TypedSyncEntry<>( - (ISyncManager>) manager, - null - )); - } - - /** - * Gets manager. - * - * @param the type parameter - * @param the type parameter - * @param key the key - * @return the manager - */ - @SuppressWarnings("unchecked") - public > Optional> getManager(ResourceLocation key) { - TypedSyncEntry entry = typedEntries.get(key); - return entry != null ? Optional.of((ISyncManager) entry.manager) : Optional.empty(); - } - - /** - * Gets capability. - * - * @param the type parameter - * @param key the key - * @return the capability - */ - @SuppressWarnings("unchecked") - public > Optional> getCapability(ResourceLocation key) { - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null && entry.capability != null) { - return Optional.of((Capability) entry.capability); - } - return Optional.empty(); - } - - /** - * Allow entity class. - * - * @param key the key - * @param classes the classes - */ - public final void allowEntityClass(ResourceLocation key, Class... classes) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(classes, "Classes array cannot be null"); - - if (classes.length == 0) { - return; - } - - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null) { - entry.allowedClasses.addAll(Arrays.asList(classes)); - } - } - - /** - * 移除允许的实体类 - * - * @param key the key - * @param classes the classes - */ - public final void disallowEntityClass(ResourceLocation key, Class... classes) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(classes, "Classes array cannot be null"); - - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null && classes.length > 0) { - Arrays.asList(classes).forEach(entry.allowedClasses::remove); - - } - } - - /** - * 绑定能力(用于分离注册的情况) - * - * @param the type parameter - * @param key the key - * @param capability the capability - */ - public > void bindCapability(ResourceLocation key, Capability capability) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(capability, "Capability cannot be null"); - - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null) { - // 更新现有条目的能力 - updateCapabilityInEntry(key, entry, capability); - } else throw new IllegalArgumentException("No manager found for " + key); - } - - /** - * 解绑能力 - * - * @param key the key - */ - public void unbindCapability(ResourceLocation key) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null) { - // 将能力设置为null,但保留管理器和其他配置 - updateCapabilityInEntry(key, entry, null); - } - } - - /** - * 清除允许的实体类 - * - * @param key the key - */ - public void clearAllowedEntityClasses(ResourceLocation key) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - - TypedSyncEntry entry = typedEntries.get(key); - if (entry != null) { - entry.allowedClasses.clear(); - } - } - - /** - * Is entity class allowed boolean. - * - * @param key the key - * @param entityClass the entity class - * @return the boolean - */ - public boolean isEntityClassAllowed(ResourceLocation key, Class entityClass) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - Objects.requireNonNull(entityClass, "Entity class cannot be null"); - - TypedSyncEntry entry = typedEntries.get(key); - boolean isAllowed = false; - if (entry != null) { - for (Class allowedClass : entry.allowedClasses) { - if (entityClass.isAssignableFrom(allowedClass)) { - isAllowed = true; - break; - } - } - } - return entry != null && isAllowed ; - } - - /** - * Track entity for manager. - * - * @param entity the entity - * @param managerId the manager id - */ -// 类型安全的事件处理 - @SuppressWarnings("unchecked") - public void trackEntityForManager(Entity entity, ResourceLocation managerId) { - TypedSyncEntry entry = (TypedSyncEntry) typedEntries.get(managerId); - if (entry != null) { - trackEntityWithTypedEntry(entity, entry); - } - } - - private > void trackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry entry) { - if (entry.capability != null) { - entity.getCapability(entry.capability) - .ifPresent(cap -> entry.manager.track(entity.getUUID(), cap)); - } - } - - /** - * Untrack entity for manager. - * - * @param entity the entity - * @param managerId the manager id - */ -// 类型安全的事件处理 - 取消跟踪实体 - @SuppressWarnings("unchecked") - public void untrackEntityForManager(Entity entity, ResourceLocation managerId) { - TypedSyncEntry entry = (TypedSyncEntry) typedEntries.get(managerId); - if (entry != null) { - untrackEntityWithTypedEntry(entity, entry); - } - } - - private > void untrackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry entry) { - if (entry.capability != null) { - entity.getCapability(entry.capability) - .ifPresent(cap -> entry.manager.untrack(entity.getUUID(), cap)); - } - } - - /** - * 从所有管理器中移除实体跟踪 - * - * @param entity the entity - */ - public void untrackEntityFromAllManagers(Entity entity) { - for (ResourceLocation id : getRegisteredKeys()) { - if (isEntityClassAllowed(id, entity.getClass())) { - untrackEntityForManager(entity, id); - } - } - } - - /** - * 批量从管理器中移除实体跟踪 - * - * @param entities the entities - * @param managerId the manager id - */ - public void untrackEntitiesForManager(@NotNull Iterable entities, ResourceLocation managerId) { - for (Entity entity : entities) { - untrackEntityForManager(entity, managerId); - } - } - - /** - * 从所有管理器中批量移除实体跟踪 - * - * @param entities the entities - */ - public void untrackEntitiesFromAllManagers(@NotNull Iterable entities) { - for (Entity entity : entities) { - untrackEntityFromAllManagers(entity); - } - } - - /** - * 强制清理管理器中的所有跟踪数据 - * - * @param managerId the manager id - */ - public void clearAllTrackedData(ResourceLocation managerId) { - TypedSyncEntry entry = typedEntries.get(managerId); - if (entry != null) { - clearTrackedDataForEntry(entry); - } - } - - private > void clearTrackedDataForEntry(@NotNull TypedSyncEntry entry) { - // 获取当前跟踪的集合并清空 - Set syncSet = entry.manager.getSyncSet(); - if (syncSet != null) { - syncSet.clear(); - } - } - - /** - * 清理所有管理器的跟踪数据 - */ - public void clearAllTrackedData() { - for (ResourceLocation id : getRegisteredKeys()) { - clearAllTrackedData(id); - } - } - - // 辅助方法:更新条目的能力 - @SuppressWarnings("unchecked") - private > void updateCapabilityInEntry(ResourceLocation id, TypedSyncEntry entry, Capability newCapability) { - TypedSyncEntry typedEntry = (TypedSyncEntry) entry; - //重构了 TypedSyncEntry 使 capability 可变 - typedEntry.capability = newCapability; - typedEntries.computeIfPresent(id, (resourceLocation, typedSyncEntry) -> typedEntry); - } - - - /** - * Gets registered keys. - * - * @return the registered keys - */ - public Set getRegisteredKeys() { - return Collections.unmodifiableSet(typedEntries.keySet()); - } - - /** - * For each. - * - * @param consumer the consumer - */ - public void forEach(BiConsumer> consumer) { - Objects.requireNonNull(consumer, "Consumer cannot be null"); - typedEntries.forEach((key, entry) -> consumer.accept(key, entry.manager)); - } - - /** - * Gets manager count. - * - * @return the manager count - */ - public int getManagerCount() { - return typedEntries.size(); - } - - /** - * Clear all. - */ - public void clearAll() { - typedEntries.clear(); - } - - /** - * 移除管理器(包括所有相关配置) - * - * @param key the key - */ - public void removeManager(ResourceLocation key) { - Objects.requireNonNull(key, "ResourceLocation key cannot be null"); - typedEntries.remove(key); - } -} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/datagen/provider/SimpleLanguageProvider.java b/src/main/java/top/r3944realms/lib39/datagen/provider/SimpleLanguageProvider.java index 58da14b..6d3e204 100644 --- a/src/main/java/top/r3944realms/lib39/datagen/provider/SimpleLanguageProvider.java +++ b/src/main/java/top/r3944realms/lib39/datagen/provider/SimpleLanguageProvider.java @@ -1,7 +1,7 @@ package top.r3944realms.lib39.datagen.provider; import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.LanguageProvider; +import net.neoforged.neoforge.common.data.LanguageProvider; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.datagen.value.ILangKeyValue; import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection; diff --git a/src/main/java/top/r3944realms/lib39/datagen/value/IResourceKeyValue.java b/src/main/java/top/r3944realms/lib39/datagen/value/IResourceKeyValue.java new file mode 100644 index 0000000..bc0449a --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/datagen/value/IResourceKeyValue.java @@ -0,0 +1,8 @@ +package top.r3944realms.lib39.datagen.value; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.Item; + +public interface IResourceKeyValue { + ResourceKey getResourceKey(); +} diff --git a/src/main/java/top/r3944realms/lib39/datagen/value/McLocale.java b/src/main/java/top/r3944realms/lib39/datagen/value/McLocale.java index 91cd9b6..2d70a12 100644 --- a/src/main/java/top/r3944realms/lib39/datagen/value/McLocale.java +++ b/src/main/java/top/r3944realms/lib39/datagen/value/McLocale.java @@ -21,7 +21,7 @@ public enum McLocale implements ILocaleEntry { /** * The Lzh. */ - LZH("lzh", new Locale("lzh", "ZH")), + LZH("lzh", Locale.of("lzh", "ZH")), /** * Ja jp mc locale. */ @@ -33,7 +33,7 @@ public enum McLocale implements ILocaleEntry { /** * The Ru ru. */ - RU_RU("ru_ru", new Locale("ru", "RU")), + RU_RU("ru_ru", Locale.of("ru", "RU")), /** * Fr fr mc locale. */ @@ -45,7 +45,7 @@ public enum McLocale implements ILocaleEntry { /** * The Es es. */ - ES_ES("es_es", new Locale("es", "ES")); + ES_ES("es_es", Locale.of("es", "ES")); private final String mcCode; private final Locale javaLocale; diff --git a/src/main/java/top/r3944realms/lib39/example/Lib39Example.java b/src/main/java/top/r3944realms/lib39/example/Lib39Example.java index 78c6902..2434fee 100644 --- a/src/main/java/top/r3944realms/lib39/example/Lib39Example.java +++ b/src/main/java/top/r3944realms/lib39/example/Lib39Example.java @@ -1,10 +1,9 @@ package top.r3944realms.lib39.example; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.NeoForge; import top.r3944realms.lib39.example.core.event.ExCommonEventHandler; -import top.r3944realms.lib39.example.core.network.ExNetworkHandler; +import top.r3944realms.lib39.example.core.register.ExLib39Attachments; import top.r3944realms.lib39.example.core.register.ExLib39Items; /** @@ -16,22 +15,19 @@ public class Lib39Example { /** * Instantiates a new Lib 39 example. */ - public Lib39Example() { + public Lib39Example(IEventBus modEventBus) { if (!registered) { - init(); - registerToEventBus(); + init(modEventBus); + registerToEventBus(modEventBus); registered = true; } } - private void init() { - IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + private void init(IEventBus modEventBus) { ExLib39Items.register(modEventBus); - ExNetworkHandler.register(); + ExLib39Attachments.register(modEventBus); } - private void registerToEventBus() { - IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); - IEventBus gameBus = MinecraftForge.EVENT_BUS; + private void registerToEventBus(IEventBus modBus) { // DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> { // modBus.register(ExClientEventHandler.Mod.class); // gameBus.register(ExClientEventHandler.Game.class); @@ -43,7 +39,7 @@ public class Lib39Example { // return null; // }); modBus.register(ExCommonEventHandler.Mod.class); - gameBus.register(ExCommonEventHandler.Game.class); + NeoForge.EVENT_BUS.register(ExCommonEventHandler.Game.class); } diff --git a/src/main/java/top/r3944realms/lib39/example/content/capability/AbstractedTestSyncData.java b/src/main/java/top/r3944realms/lib39/example/content/capability/AbstractedTestSyncData.java index 2dc49ad..04df6b6 100644 --- a/src/main/java/top/r3944realms/lib39/example/content/capability/AbstractedTestSyncData.java +++ b/src/main/java/top/r3944realms/lib39/example/content/capability/AbstractedTestSyncData.java @@ -1,20 +1,25 @@ package top.r3944realms.lib39.example.content.capability; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import top.r3944realms.lib39.core.sync.NBTEntitySyncData; +import net.neoforged.neoforge.common.util.ValueIOSerializable; +import top.r3944realms.lib39.core.sync.IEntity; /** * The type Abstracted test sync data. */ @SuppressWarnings("unused") -public abstract class AbstractedTestSyncData extends NBTEntitySyncData { +public abstract class AbstractedTestSyncData implements ValueIOSerializable, IEntity { + /** * Instantiates a new Nbt sync data. * * @param id the id */ protected AbstractedTestSyncData(ResourceLocation id) { - super(id); + } /** @@ -126,10 +131,17 @@ public abstract class AbstractedTestSyncData extends NBTEntitySyncData { * 测试数据对象 */ public static class TestData { + public static StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, TestData::getName, + ByteBufCodecs.INT, TestData::getValue, + ByteBufCodecs.BOOL, TestData::isFlag, + TestData::new + ); private String name; private int value; private boolean flag; + /** * Instantiates a new Test data. */ diff --git a/src/main/java/top/r3944realms/lib39/example/content/capability/ExCapabilityHandler.java b/src/main/java/top/r3944realms/lib39/example/content/capability/ExCapabilityHandler.java index dbdffe4..31e89fd 100644 --- a/src/main/java/top/r3944realms/lib39/example/content/capability/ExCapabilityHandler.java +++ b/src/main/java/top/r3944realms/lib39/example/content/capability/ExCapabilityHandler.java @@ -1,12 +1,15 @@ package top.r3944realms.lib39.example.content.capability; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import org.jetbrains.annotations.NotNull; +import net.minecraft.resources.ResourceLocation; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.entity.vehicle.Minecart; +import net.neoforged.neoforge.capabilities.EntityCapability; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.example.core.register.ExLib39Attachments; +import top.r3944realms.lib39.util.capability.EntityCapabilityHelper; /** * The type Ex capability handler. @@ -15,26 +18,29 @@ public class ExCapabilityHandler { /** * The constant TEST_CAP. */ - public static final Capability TEST_CAP = CapabilityManager.get(new CapabilityToken<>() {}); + public static final EntityCapability TEST_CAP = EntityCapability.createVoid( + ResourceLocation.fromNamespaceAndPath(Lib39.MOD_ID, "test_data"), + AbstractedTestSyncData.class + ); - /** - * Register capability. - * - * @param event the event - */ - public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) { - event.register(AbstractedTestSyncData.class); - } - - /** - * Attach capability. - * - * @param event the event - */ - public static void attachCapability(@NotNull AttachCapabilitiesEvent event) { - Object object = event.getObject(); - if(object instanceof Entity entity ) { - event.addCapability(TestSyncCapProvider.TEST_SYNC_REL, new TestSyncCapProvider(entity)); - } + public static void registerCapabilities(RegisterCapabilitiesEvent event) { + EntityCapabilityHelper.registerForEntityClass( + event, + TEST_CAP, + (entity, context) -> entity.getData(ExLib39Attachments.TEST_DATA_ATTACHMENT), + LivingEntity.class + ); + EntityCapabilityHelper.registerForEntityClass( + event, + TEST_CAP, + (entity, context) -> entity.getData(ExLib39Attachments.TEST_DATA_ATTACHMENT), + Boat.class + ); + EntityCapabilityHelper.registerForEntityClass( + event, + TEST_CAP, + (entity, context) -> entity.getData(ExLib39Attachments.TEST_DATA_ATTACHMENT), + Minecart.class + ); } } diff --git a/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncCapProvider.java b/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncCapProvider.java deleted file mode 100644 index f500642..0000000 --- a/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncCapProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -package top.r3944realms.lib39.example.content.capability; - -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilitySerializable; -import net.minecraftforge.common.util.LazyOptional; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import top.r3944realms.lib39.Lib39; - -/** - * The type Test sync cap provider. - */ -public class TestSyncCapProvider implements ICapabilitySerializable { - - /** - * The constant TEST_SYNC_REL. - */ - public static final ResourceLocation TEST_SYNC_REL = new ResourceLocation(Lib39.MOD_ID, "test_sync_data"); - private final AbstractedTestSyncData instance; - private final LazyOptional optional; - - /** - * Instantiates a new Test sync cap provider. - * - * @param entity the entity - */ - public TestSyncCapProvider(Entity entity) { - this.instance = new TestSyncData(entity); - this.optional = LazyOptional.of(() -> instance); - } - @Override - public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { - return ExCapabilityHandler.TEST_CAP.orEmpty(cap, optional); - } - - @Override - public CompoundTag serializeNBT() { - return instance.serializeNBT(); - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - instance.deserializeNBT(nbt); - } -} diff --git a/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncData.java b/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncData.java index bbba0d9..2424cb1 100644 --- a/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncData.java +++ b/src/main/java/top/r3944realms/lib39/example/content/capability/TestSyncData.java @@ -1,14 +1,21 @@ package top.r3944realms.lib39.example.content.capability; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.neoforged.neoforge.attachment.IAttachmentHolder; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; -import top.r3944realms.lib39.util.nbt.NBTReader; -import top.r3944realms.lib39.util.nbt.NBTWriter; +import top.r3944realms.lib39.example.core.register.ExLib39Attachments; +import top.r3944realms.lib39.example.core.register.ExLib39ItemResourceKeys; +import top.r3944realms.lib39.util.storage.valueio.ValueInputReader; +import top.r3944realms.lib39.util.storage.valueio.ValueOutputWriter; +import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -16,25 +23,59 @@ import java.util.concurrent.atomic.AtomicReference; /** * 测试同步数据实现 */ -@SuppressWarnings("unused") public class TestSyncData extends AbstractedTestSyncData { - /** - * The constant ID. - */ - public static final ResourceLocation ID = new ResourceLocation(Lib39.MOD_ID, "test_sync_data"); + private static final Random RANDOM = new Random(); - // NBT 键常量 - private static final String NBT_KEY_STRING = "test_string"; - private static final String NBT_KEY_INT = "test_int"; - private static final String NBT_KEY_BOOLEAN = "test_boolean"; - private static final String NBT_KEY_DOUBLE = "test_double"; - private static final String NBT_KEY_COUNTER = "counter"; - private static final String NBT_KEY_SYNC_TIME = "last_sync_time"; - private static final String NBT_KEY_CUSTOM_DATA = "custom_data"; - private static final String NBT_KEY_CUSTOM_NAME = "name"; - private static final String NBT_KEY_CUSTOM_VALUE = "value"; - private static final String NBT_KEY_CUSTOM_FLAG = "flag"; + public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(Lib39.MOD_ID, "test_sync_data"); + // 网络同步编解码器 + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, TestSyncData::getTestString, + ByteBufCodecs.INT, TestSyncData::getTestInt, + ByteBufCodecs.BOOL, TestSyncData::isTestBoolean, + ByteBufCodecs.DOUBLE, TestSyncData::getTestDouble, + TestData.CODEC, TestSyncData::getCustomData, + ByteBufCodecs.INT, TestSyncData::getCounter, + ByteBufCodecs.LONG, TestSyncData::getLastSyncTime, + (testString, testInt, testBoolean, testDouble, customData, counter, lastSyncTime) -> { + TestSyncData data = new TestSyncData(); + data.testString = testString; + data.testInt = testInt; + data.testBoolean = testBoolean; + data.testDouble = testDouble; + data.customData = customData; + data.counter = counter; + data.lastSyncTime = lastSyncTime; + return data; + } + ); + /** 重置为默认值 */ + public void resetToDefaults() { + this.testString = "default_string"; + this.testInt = 0; + this.testDouble = 0.0; + this.testBoolean = false; + this.counter = 0; + this.lastSyncTime = System.currentTimeMillis(); + this.customData = new TestData("init", 0, false); + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); + } + + /** 随机生成一组数据 */ + public void generateRandomData() { + this.testString = "rand_" + RANDOM.nextInt(10000); + this.testInt = RANDOM.nextInt(1000); + this.testDouble = RANDOM.nextDouble() * 100.0; + this.testBoolean = RANDOM.nextBoolean(); + this.counter = RANDOM.nextInt(20); + this.lastSyncTime = System.currentTimeMillis(); + this.customData = new TestData( + "custom_" + RANDOM.nextInt(1000), + RANDOM.nextInt(500), + RANDOM.nextBoolean() + ); + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); + } // 数据字段 private String testString = "default_value"; private int testInt = 42; @@ -45,332 +86,134 @@ public class TestSyncData extends AbstractedTestSyncData { private TestData customData = new TestData("default", 100, false); private Entity self; - /** - * 构造函数 - * - * @param entity 关联的实体 - */ + // --- 构造函数区域 --- + + /** 默认构造函数(反序列化/同步使用) */ + public TestSyncData() { + super(ID); + } + + /** 用于实体附加 */ public TestSyncData(Entity entity) { super(ID); this.self = entity; } - /** - * 构造函数(用于测试) - * - * @param entityId 实体ID - * @param self the self - */ - public TestSyncData(int entityId, Entity self) { - super(ID); - this.self = self; + /** 用于 AttachmentType.serializable(holder -> ...) */ + public TestSyncData(IAttachmentHolder holder) { + this(holder instanceof Entity e ? e : null); + if (self == null) throw new IllegalArgumentException("TestSyncData must be attached to Entity"); } - /** - * 构造函数(用于数据包反序列化) - * - * @param buf 字节缓冲区 - */ - public TestSyncData(FriendlyByteBuf buf) { - super(ID); - this.self = null; // 实体在从数据包重建时可能为null,需要在接收端设置 - fromBytes(buf); + // --- 数据逻辑部分 --- + + public String getTestString() { return testString; } + public void setTestString(String s) { + this.testString = s; + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - /** - * 将数据写入字节缓冲区(用于网络传输) - * - * @param buf 字节缓冲区 - */ - public void toBytes(FriendlyByteBuf buf) { - // 写入基本类型字段 - buf.writeUtf(testString != null ? testString : ""); - buf.writeInt(testInt); - buf.writeBoolean(testBoolean); - buf.writeDouble(testDouble); - buf.writeInt(counter); - buf.writeLong(lastSyncTime); - - // 写入自定义数据 - if (customData != null) { - buf.writeUtf(customData.getName() != null ? customData.getName() : ""); - buf.writeInt(customData.getValue()); - buf.writeBoolean(customData.isFlag()); - } else { - buf.writeUtf(""); - buf.writeInt(0); - buf.writeBoolean(false); - } - - // 写入实体ID(如果实体存在) - if (self != null) { - buf.writeInt(self.getId()); - } else { - buf.writeInt(-1); - } - - // 写入脏数据状态 - buf.writeBoolean(isDirty()); + public int getTestInt() { return testInt; } + public void setTestInt(int i) { + this.testInt = i; + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - /** - * 从字节缓冲区读取数据(用于网络传输) - * - * @param buf 字节缓冲区 - */ - public void fromBytes(@NotNull FriendlyByteBuf buf) { - // 读取基本类型字段 - this.testString = buf.readUtf(32767); // Minecraft字符串最大长度 - this.testInt = buf.readInt(); - this.testBoolean = buf.readBoolean(); - this.testDouble = buf.readDouble(); - this.counter = buf.readInt(); - this.lastSyncTime = buf.readLong(); - - // 读取自定义数据 - String customName = buf.readUtf(); - int customValue = buf.readInt(); - boolean customFlag = buf.readBoolean(); - this.customData = new TestData(customName, customValue, customFlag); - - // 读取实体ID(在接收端可能需要额外处理) - int entityId = buf.readInt(); - - // 读取脏数据状态 - boolean wasDirty = buf.readBoolean(); - if (wasDirty) { - markDirty(); - } + public boolean isTestBoolean() { return testBoolean; } + public void setTestBoolean(boolean b) { this.testBoolean = b; + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - /** - * 静态方法:从字节缓冲区创建 TestSyncData 实例 - * - * @param buf 字节缓冲区 - * @return 新的 TestSyncData 实例 - */ - public static TestSyncData staticFromBytes(FriendlyByteBuf buf) { - return new TestSyncData(buf); + public double getTestDouble() { return testDouble; } + public void setTestDouble(double d) { + this.testDouble = d; + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - @Override - public String getTestString() { - return testString; - } - - @Override - public void setTestString(String value) { - if (!java.util.Objects.equals(this.testString, value)) { - this.testString = value; - markDirty(); - } - } - - @Override - public int getTestInt() { - return testInt; - } - - @Override - public void setTestInt(int value) { - if (this.testInt != value) { - this.testInt = value; - markDirty(); - } - } - - @Override - public boolean isTestBoolean() { - return testBoolean; - } - - @Override - public void setTestBoolean(boolean value) { - if (this.testBoolean != value) { - this.testBoolean = value; - markDirty(); - } - } - - @Override - public double getTestDouble() { - return testDouble; - } - - @Override - public void setTestDouble(double value) { - if (this.testDouble != value) { - this.testDouble = value; - markDirty(); - } - } - - @Override - public int getCounter() { - return counter; - } - - @Override + public int getCounter() { return counter; } public void incrementCounter() { this.counter++; - markDirty(); + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - @Override - public long getLastSyncTime() { - return lastSyncTime; - } - - @Override + public long getLastSyncTime() { return lastSyncTime; } public void updateSyncTime() { this.lastSyncTime = System.currentTimeMillis(); - markDirty(); + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - @Override - public TestData getCustomData() { - return customData; - } - - @Override + public TestData getCustomData() { return customData; } public void setCustomData(TestData data) { - if (data == null) { - throw new IllegalArgumentException("Custom data cannot be null"); - } - if (!java.util.Objects.equals(this.customData, data)) { - this.customData = data; - markDirty(); - } + this.customData = data; + self.syncData(ExLib39Attachments.TEST_DATA_ATTACHMENT); } - @Override public boolean validateData() { - return testString != null && - !testString.isEmpty() && - customData != null && - customData.getName() != null && - !customData.getName().isEmpty() && - counter >= 0 && - testInt >= 0; + return testString != null && !testString.isEmpty() + && customData != null && customData.getName() != null + && counter >= 0 && testInt >= 0; + } + + // --- 实体管理 --- + + public int entityId() { return self != null ? self.getId() : -1; } + + public void setSelf(Entity entity) { + this.self = entity; + } + public TestSyncData createSyncCopy(Entity entity) { + TestSyncData copy = new TestSyncData(entity); + copy.testString = testString; + copy.testInt = testInt; + copy.testBoolean = testBoolean; + copy.testDouble = testDouble; + copy.counter = counter; + copy.lastSyncTime = lastSyncTime; + copy.customData = new TestData(customData.getName(), customData.getValue(), customData.isFlag()); + return copy; } @Override - public CompoundTag serializeNBT() { - return NBTWriter.builder() - .string(NBT_KEY_STRING, testString) - .intValue(NBT_KEY_INT, testInt) - .booleanValue(NBT_KEY_BOOLEAN, testBoolean) - .doubleValue(NBT_KEY_DOUBLE, testDouble) - .intValue(NBT_KEY_COUNTER, counter) - .longValue(NBT_KEY_SYNC_TIME, lastSyncTime) - .compound( - NBT_KEY_CUSTOM_DATA, - NBTWriter.builder() - .string(NBT_KEY_CUSTOM_NAME, customData.getName()) - .intValue(NBT_KEY_CUSTOM_VALUE, customData.getValue()) - .booleanValue(NBT_KEY_CUSTOM_FLAG, customData.isFlag()) - .build() - ).build(); + public void serialize(@NotNull ValueOutput out) { + ValueOutputWriter.of(out) + .string("test_string", testString) + .intValue("test_int", testInt) + .booleanValue("test_boolean", testBoolean) + .doubleValue("test_double", testDouble) + .intValue("counter", counter) + .longValue("last_sync_time", lastSyncTime) + .nested("custom_data", n -> + n.string("name", customData.getName()) + .intValue("value", customData.getValue()) + .booleanValue("flag", customData.isFlag())); } @Override - public void deserializeNBT(CompoundTag nbt) { - NBTReader.of(nbt) - .intValue(NBT_KEY_INT, integer -> testInt = integer) - .string(NBT_KEY_STRING, string -> testString = string) - .booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool) - .intValue(NBT_KEY_COUNTER, integer -> counter = integer) - .doubleValue(NBT_KEY_DOUBLE, dou -> testDouble = dou) - .longValue(NBT_KEY_SYNC_TIME, sync -> lastSyncTime = sync) - .compound(NBT_KEY_CUSTOM_DATA, customDataTag -> { - AtomicReference name = new AtomicReference<>(""); - AtomicInteger value = new AtomicInteger(-1); + public void deserialize(@NotNull ValueInput in) { + ValueInputReader.of(in) + .string("test_string", s -> testString = s) + .intValue("test_int", i -> testInt = i) + .booleanValue("test_boolean", b -> testBoolean = b) + .doubleValue("test_double", d -> testDouble = d) + .intValue("counter", c -> counter = c) + .longValue("last_sync_time", t -> lastSyncTime = t) + .nested("custom_data", n -> { + AtomicReference name = new AtomicReference<>("default"); + AtomicInteger value = new AtomicInteger(100); AtomicBoolean flag = new AtomicBoolean(false); - NBTReader.of(customDataTag) - .string(NBT_KEY_CUSTOM_NAME, name::set) - .intValue(NBT_KEY_CUSTOM_VALUE, value::set) - .booleanValue(NBT_KEY_CUSTOM_FLAG, flag::set); - this.customData = new TestData(name.get(), value.get(), flag.get()); + n.string("name", name::set) + .intValue("value", value::set) + .booleanValue("flag", flag::set); + customData = new TestData(name.get(), value.get(), flag.get()); }); } - @Override - public int entityId() { - return self != null ? self.getId() : -1; - } - - /** - * 设置关联的实体 - * - * @param entity 关联的实体 - */ - public void setEntity(Entity entity) { - this.self = entity; - } - - - /** - * 获取所有数据的字符串表示(用于调试) - */ @Override public String toString() { return String.format( - "TestSyncData{id=%d, string='%s', int=%d, boolean=%s, double=%.2f, counter=%d, lastSync=%d, custom=%s}", - self.getId(), testString, testInt, testBoolean, testDouble, counter, lastSyncTime, customData + "TestSyncData[%s,id=%d]{str=%s,int=%d,bool=%s,double=%.2f,counter=%d,time=%d,custom=%s}", + self == null ? "null" : self.getClass().getSimpleName(), + entityId(), testString, testInt, testBoolean, testDouble, counter, lastSyncTime, customData ); } - - /** - * 重置为默认值 - */ - public void resetToDefaults() { - testString = "default_value"; - testInt = 42; - testBoolean = true; - testDouble = 3.14159; - counter = 0; - lastSyncTime = 0L; - customData = new TestData("default", 100, false); - markDirty(); - } - - /** - * 生成随机测试数据 - */ - public void generateRandomData() { - testString = "random_" + System.currentTimeMillis(); - testInt = (int) (Math.random() * 1000); - testBoolean = Math.random() > 0.5; - testDouble = Math.random() * 100.0; - counter++; - lastSyncTime = System.currentTimeMillis(); - customData = new TestData( - "custom_" + counter, - (int) (Math.random() * 500), - Math.random() > 0.5 - ); - markDirty(); - } - - /** - * 创建一个不依赖实体的副本(用于网络传输) - * - * @return 不包含实体引用的副本 test sync data - */ - public TestSyncData createNetworkCopy() { - TestSyncData copy = new TestSyncData((Entity) null); - copy.testString = this.testString; - copy.testInt = this.testInt; - copy.testBoolean = this.testBoolean; - copy.testDouble = this.testDouble; - copy.counter = this.counter; - copy.lastSyncTime = this.lastSyncTime; - copy.customData = new TestData( - this.customData.getName(), - this.customData.getValue(), - this.customData.isFlag() - ); - return copy; - } - -} \ No newline at end of file +} diff --git a/src/main/java/top/r3944realms/lib39/example/content/item/FabricItem.java b/src/main/java/top/r3944realms/lib39/example/content/item/FabricItem.java index f3ba19a..011eecd 100644 --- a/src/main/java/top/r3944realms/lib39/example/content/item/FabricItem.java +++ b/src/main/java/top/r3944realms/lib39/example/content/item/FabricItem.java @@ -1,9 +1,10 @@ package top.r3944realms.lib39.example.content.item; +import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -11,20 +12,22 @@ import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.TooltipDisplay; import net.minecraft.world.level.Level; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.client.network.ClientPacketDistributor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData; import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler; import top.r3944realms.lib39.example.content.capability.TestSyncData; -import top.r3944realms.lib39.example.core.network.ClientDataPacket; -import top.r3944realms.lib39.example.core.network.ExNetworkHandler; +import top.r3944realms.lib39.example.core.network.ClientDataPayload; +import top.r3944realms.lib39.util.chat.MessageDisplayClientHelper; -import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; /** * 用于执行数据查询并检查同步状态的物品 @@ -43,8 +46,7 @@ public class FabricItem extends Item { } @Override - public @NotNull InteractionResultHolder use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand hand) { - ItemStack itemStack = player.getItemInHand(hand); + public @NotNull InteractionResult use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand hand) { if (level.isClientSide()) { // 客户端逻辑 @@ -61,17 +63,17 @@ public class FabricItem extends Item { if (player.isShiftKeyDown()) { // 服务器端已经通过数据包处理双端检查,这里只发送开始消息 - player.sendSystemMessage(Component.literal("§b开始双端同步检查,请等待客户端数据...")); + ((ServerPlayer) player).sendSystemMessage(Component.literal("§b开始双端同步检查,请等待客户端数据...")); } else { // 服务器单端查询 handleServerSingleEndQuery(serverPlayer); } // 添加冷却时间 - player.getCooldowns().addCooldown(this, 20); // 1秒冷却 + player.getCooldowns().addCooldown(this.getDefaultInstance(), 20); // 1秒冷却 } - return InteractionResultHolder.sidedSuccess(itemStack, level.isClientSide()); + return InteractionResult.SUCCESS; } /** @@ -89,15 +91,15 @@ public class FabricItem extends Item { sendClientDataToServer(clientData, livingTarget.getId()); // 客户端提示 - player.sendSystemMessage(Component.literal("§b已发送客户端数据到服务器,等待对比结果...")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§b已发送客户端数据到服务器,等待对比结果..."), false); } else { - player.sendSystemMessage(Component.literal("§c无法获取客户端本地数据")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§c无法获取客户端本地数据"), false); } } else { if (targetEntity == null && player.isShiftKeyDown()) { handlePlayerSelfData(player); } else { - player.sendSystemMessage(Component.literal("§c请对准一个生物进行同步检查!")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§c请对准一个生物进行同步检查!"), false); } } } @@ -114,9 +116,9 @@ public class FabricItem extends Item { sendClientDataToServer(clientData, player.getId()); // 客户端提示 - player.sendSystemMessage(Component.literal("§b已发送玩家自身客户端数据到服务器,等待对比结果...")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§b已发送玩家自身客户端数据到服务器,等待对比结果..."), false); } else { - player.sendSystemMessage(Component.literal("§c无法获取玩家自身客户端数据")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§c无法获取玩家自身客户端数据"), false); } } /** @@ -129,12 +131,12 @@ public class FabricItem extends Item { TestSyncData clientData = getLocalClientData(livingTarget); if (clientData != null) { - displayClientSideResults(player, livingTarget, clientData); + displayClientSideResults(livingTarget, clientData); } else { - player.sendSystemMessage(Component.literal("§c无法查询客户端本地数据")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§c无法查询客户端本地数据"), false); } } else { - player.sendSystemMessage(Component.literal("§c请对准一个生物使用!")); + Minecraft.getInstance().getChatListener().handleSystemMessage(Component.literal("§c请对准一个生物使用!"), false); } } @@ -161,7 +163,7 @@ public class FabricItem extends Item { */ private TestSyncData getLocalClientData(LivingEntity target) { try { - AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null); + AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP); if (abstractData instanceof TestSyncData) { return (TestSyncData) abstractData; } @@ -176,7 +178,7 @@ public class FabricItem extends Item { */ private void sendClientDataToServer(TestSyncData clientData, int targetEntityId) { // 使用网络系统发送数据包 - ExNetworkHandler.INSTANCE.sendToServer(new ClientDataPacket(clientData, targetEntityId)); + ClientPacketDistributor.sendToServer(new ClientDataPayload(clientData, targetEntityId)); } /** @@ -209,7 +211,7 @@ public class FabricItem extends Item { */ private static @Nullable TestSyncData getServerSideData(LivingEntity target) { try { - AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null); + AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP); if (abstractData instanceof TestSyncData) { return (TestSyncData) abstractData; } @@ -229,9 +231,7 @@ public class FabricItem extends Item { Thread.sleep(3000); // 在服务器线程中执行结果处理 - player.server.execute(() -> { - displayServerSingleEndResults(player, target); - }); + player.server.execute(() -> displayServerSingleEndResults(player, target)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -268,24 +268,23 @@ public class FabricItem extends Item { /** * 显示客户端查询结果 */ - private void displayClientSideResults(Player player, LivingEntity target, TestSyncData clientData) { - player.sendSystemMessage(Component.literal("§6=== 客户端数据查询结果 ===")); - player.sendSystemMessage(Component.literal("§7目标生物: §e" + target.getName().getString())); - player.sendSystemMessage(Component.literal("§7数据来源: §9客户端本地")); - player.sendSystemMessage(Component.literal("")); + private void displayClientSideResults(LivingEntity target, TestSyncData clientData) { + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§6=== 客户端数据查询结果 ===")); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7目标生物: §e" + target.getName().getString())); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7数据来源: §9客户端本地")); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("")); - player.sendSystemMessage(Component.literal("§a基础数据:")); - player.sendSystemMessage(Component.literal("§7字符串: §f" + clientData.getTestString())); - player.sendSystemMessage(Component.literal("§7整数值: §f" + clientData.getTestInt())); - player.sendSystemMessage(Component.literal("§7布尔值: §f" + clientData.isTestBoolean())); - player.sendSystemMessage(Component.literal("§7双精度值: §f" + String.format("%.2f", clientData.getTestDouble()))); - player.sendSystemMessage(Component.literal("§7计数器: §f" + clientData.getCounter())); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§a基础数据:")); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7字符串: §f" + clientData.getTestString())); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7整数值: §f" + clientData.getTestInt())); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7布尔值: §f" + clientData.isTestBoolean())); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7双精度值: §f" + String.format("%.2f", clientData.getTestDouble()))); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7计数器: §f" + clientData.getCounter())); // 显示客户端特定信息 - player.sendSystemMessage(Component.literal("")); - player.sendSystemMessage(Component.literal("§e客户端状态:")); - player.sendSystemMessage(Component.literal("§7数据验证: " + (clientData.validateData() ? "§a通过" : "§c失败"))); - player.sendSystemMessage(Component.literal("§7同步状态: " + (clientData.isDirty() ? "§6待同步" : "§a已同步"))); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("")); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§e客户端状态:")); + MessageDisplayClientHelper.sendSystemMessage(Component.literal("§7数据验证: " + (clientData.validateData() ? "§a通过" : "§c失败"))); } /** @@ -342,9 +341,6 @@ public class FabricItem extends Item { player.sendSystemMessage(Component.literal( String.format("§7数据验证: %s", isValid ? "§a通过" : "§c失败") )); - player.sendSystemMessage(Component.literal( - String.format("§7数据状态: %s", testData.isDirty() ? "§6未同步" : "§a已同步") - )); } /** @@ -360,7 +356,7 @@ public class FabricItem extends Item { // 显示双端数据来源 player.sendSystemMessage(Component.literal("§a数据来源:")); player.sendSystemMessage(Component.literal("§7- §c服务器端§7: 实体ID " + serverData.entityId())); - player.sendSystemMessage(Component.literal("§7- §9客户端§7: 实体ID " + clientData.entityId())); + player.sendSystemMessage(Component.literal("§7- §9客户端§7: 实体ID " + serverData.entityId())); player.sendSystemMessage(Component.literal("")); // 比较各个字段 @@ -410,12 +406,6 @@ public class FabricItem extends Item { // 显示数据状态差异 player.sendSystemMessage(Component.literal("")); player.sendSystemMessage(Component.literal("§a数据状态差异:")); - player.sendSystemMessage(Component.literal( - String.format("§7服务器脏数据状态: %s", serverData.isDirty() ? "§6脏" : "§a干净") - )); - player.sendSystemMessage(Component.literal( - String.format("§7客户端脏数据状态: %s", clientData.isDirty() ? "§6脏" : "§a干净") - )); player.sendSystemMessage(Component.literal( String.format("§7服务器验证状态: %s", serverData.validateData() ? "§a通过" : "§c失败") )); @@ -552,38 +542,37 @@ public class FabricItem extends Item { */ private AbstractedTestSyncData getTestSyncData(Entity entity) { try { - return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null); + return entity.getCapability(ExCapabilityHandler.TEST_CAP); } catch (Exception e) { Lib39.LOGGER.debug("[FabricItem] 获取生物 {} 的 TestSyncData 失败: {}", entity.getName().getString(), e.getMessage()); return null; } } - - @Override - public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, - @NotNull List tooltip, @NotNull TooltipFlag flag) { - super.appendHoverText(stack, level, tooltip, flag); - - tooltip.add(Component.literal("§7右键点击在 3 秒后执行")); - tooltip.add(Component.literal("§7§e准星瞄准生物§7的数据查询")); - tooltip.add(Component.literal("§7§oShift + 右键§7进行§e客户端-服务器双端同步检查§7")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§6查询延迟: §e3秒")); - tooltip.add(Component.literal("§6瞄准距离: §e20格")); - tooltip.add(Component.literal("§6冷却时间: §e1秒")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§a单端查询内容:")); - tooltip.add(Component.literal("§7- 基础数据字段")); - tooltip.add(Component.literal("§7- 自定义数据结构")); - tooltip.add(Component.literal("§7- 数据验证状态")); - tooltip.add(Component.literal("§7- 同步状态信息")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§e双端同步检查:")); - tooltip.add(Component.literal("§7- 客户端和服务器同时查询")); - tooltip.add(Component.literal("§7- 字段级同步状态对比")); - tooltip.add(Component.literal("§7- 总体同步率计算")); - tooltip.add(Component.literal("§7- 双端数据状态差异")); - tooltip.add(Component.literal("§7- 同步建议")); + @SuppressWarnings("deprecation") + public void appendHoverText( + @NotNull ItemStack stack, Item.@NotNull TooltipContext context, @NotNull TooltipDisplay tooltipDisplay, @NotNull Consumer tooltipAdder, @NotNull TooltipFlag flag + ) { + tooltipAdder.accept(Component.literal("§7右键点击在 3 秒后执行")); + tooltipAdder.accept(Component.literal("§7§e准星瞄准生物§7的数据查询")); + tooltipAdder.accept(Component.literal("§7§oShift + 右键§7进行§e客户端-服务器双端同步检查§7")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§6查询延迟: §e3秒")); + tooltipAdder.accept(Component.literal("§6瞄准距离: §e20格")); + tooltipAdder.accept(Component.literal("§6冷却时间: §e1秒")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§a单端查询内容:")); + tooltipAdder.accept(Component.literal("§7- 基础数据字段")); + tooltipAdder.accept(Component.literal("§7- 自定义数据结构")); + tooltipAdder.accept(Component.literal("§7- 数据验证状态")); + tooltipAdder.accept(Component.literal("§7- 同步状态信息")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§e双端同步检查:")); + tooltipAdder.accept(Component.literal("§7- 客户端和服务器同时查询")); + tooltipAdder.accept(Component.literal("§7- 字段级同步状态对比")); + tooltipAdder.accept(Component.literal("§7- 总体同步率计算")); + tooltipAdder.accept(Component.literal("§7- 双端数据状态差异")); + tooltipAdder.accept(Component.literal("§7- 同步建议")); } + } \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/content/item/NeoForgeItem.java b/src/main/java/top/r3944realms/lib39/example/content/item/NeoForgeItem.java index 4d669f8..78de2e2 100644 --- a/src/main/java/top/r3944realms/lib39/example/content/item/NeoForgeItem.java +++ b/src/main/java/top/r3944realms/lib39/example/content/item/NeoForgeItem.java @@ -3,7 +3,7 @@ package top.r3944realms.lib39.example.content.item; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -11,18 +11,19 @@ import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.TooltipDisplay; import net.minecraft.world.level.Level; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData; import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler; import top.r3944realms.lib39.example.content.capability.TestSyncData; +import top.r3944realms.lib39.util.chat.MessageDisplayClientHelper; -import java.util.List; import java.util.Random; +import java.util.function.Consumer; /** * 用于对准星生物触发 TestSyncData 随机变换的物品 @@ -42,9 +43,7 @@ public class NeoForgeItem extends Item { } @Override - public @NotNull InteractionResultHolder use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand hand) { - ItemStack itemStack = player.getItemInHand(hand); - + public @NotNull InteractionResult use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand hand) { if (!level.isClientSide()) { ServerPlayer serverPlayer = (ServerPlayer) player; @@ -57,10 +56,10 @@ public class NeoForgeItem extends Item { } // 添加冷却时间 - player.getCooldowns().addCooldown(this, 20); // 1秒冷却 + player.getCooldowns().addCooldown(this.getDefaultInstance(), 20); // 1秒冷却 } - return InteractionResultHolder.sidedSuccess(itemStack, level.isClientSide()); + return InteractionResult.SUCCESS_SERVER; } /** @@ -207,8 +206,8 @@ public class NeoForgeItem extends Item { } // 显示数据预览(仅对玩家自己操作时显示) - if (entity instanceof Player) { - displayDataPreview((Player) entity, testData); + if (entity instanceof Player player) { + displayDataPreview(player, testData); } return true; @@ -224,16 +223,18 @@ public class NeoForgeItem extends Item { * 显示数据预览给玩家 */ private void displayDataPreview(Player player, TestSyncData testData) { - player.sendSystemMessage(Component.literal("§6数据预览:")); - player.sendSystemMessage(Component.literal( - String.format("§7字符串: §f%s", testData.getTestString()) - )); - player.sendSystemMessage(Component.literal( - String.format("§7计数器: §f%d", testData.getCounter()) - )); - player.sendSystemMessage(Component.literal( - String.format("§7验证状态: %s", testData.validateData() ? "§a通过" : "§c失败") - )); + if(player instanceof ServerPlayer serverPlayer) { + serverPlayer.sendSystemMessage(Component.literal("§6数据预览:")); + serverPlayer.sendSystemMessage(Component.literal( + String.format("§7字符串: §f%s", testData.getTestString()) + )); + serverPlayer.sendSystemMessage(Component.literal( + String.format("§7计数器: §f%d", testData.getCounter()) + )); + serverPlayer.sendSystemMessage(Component.literal( + String.format("§7验证状态: %s", testData.validateData() ? "§a通过" : "§c失败") + )); + } } /** @@ -249,7 +250,7 @@ public class NeoForgeItem extends Item { private AbstractedTestSyncData getOrCreateTestSyncData(Entity entity) { try { - return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElseThrow(); + return entity.getCapability(ExCapabilityHandler.TEST_CAP); } catch (Exception e) { Lib39.LOGGER.error("[NeoForgeItem] 获取 {} 的 TestSyncData 失败: {}", getEntityName((LivingEntity) entity), e.getMessage()); @@ -257,28 +258,28 @@ public class NeoForgeItem extends Item { } } - @Override - public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, - @NotNull List tooltip, @NotNull TooltipFlag flag) { - super.appendHoverText(stack, level, tooltip, flag); + @SuppressWarnings("deprecation") + public void appendHoverText( + @NotNull ItemStack stack, Item.@NotNull TooltipContext context, @NotNull TooltipDisplay tooltipDisplay, @NotNull Consumer tooltipAdder, @NotNull TooltipFlag flag + ) { - tooltip.add(Component.literal("§7右键点击触发§e准星瞄准生物§7的")); - tooltip.add(Component.literal("§7测试数据随机变换")); - tooltip.add(Component.literal("§7§oShift + 右键§7操作§e自身§7数据")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§6冷却时间: §e1秒")); - tooltip.add(Component.literal("§6瞄准距离: §e20格")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§a变换类型:")); - tooltip.add(Component.literal("§7- 完全随机数据")); - tooltip.add(Component.literal("§7- 字符串+计数器")); - tooltip.add(Component.literal("§7- 数值数据")); - tooltip.add(Component.literal("§7- 自定义数据")); - tooltip.add(Component.literal("§7- 重置默认值")); - tooltip.add(Component.literal("§7- 玩家专属数据")); - tooltip.add(Component.literal("")); - tooltip.add(Component.literal("§e自身操作特性:")); - tooltip.add(Component.literal("§7- 显示数据预览")); - tooltip.add(Component.literal("§7- 玩家专属数据变换")); + tooltipAdder.accept(Component.literal("§7右键点击触发§e准星瞄准生物§7的")); + tooltipAdder.accept(Component.literal("§7测试数据随机变换")); + tooltipAdder.accept(Component.literal("§7§oShift + 右键§7操作§e自身§7数据")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§6冷却时间: §e1秒")); + tooltipAdder.accept(Component.literal("§6瞄准距离: §e20格")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§a变换类型:")); + tooltipAdder.accept(Component.literal("§7- 完全随机数据")); + tooltipAdder.accept(Component.literal("§7- 字符串+计数器")); + tooltipAdder.accept(Component.literal("§7- 数值数据")); + tooltipAdder.accept(Component.literal("§7- 自定义数据")); + tooltipAdder.accept(Component.literal("§7- 重置默认值")); + tooltipAdder.accept(Component.literal("§7- 玩家专属数据")); + tooltipAdder.accept(Component.literal("")); + tooltipAdder.accept(Component.literal("§e自身操作特性:")); + tooltipAdder.accept(Component.literal("§7- 显示数据预览")); + tooltipAdder.accept(Component.literal("§7- 玩家专属数据变换")); } } \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/core/event/ExCommonEventHandler.java b/src/main/java/top/r3944realms/lib39/example/core/event/ExCommonEventHandler.java index d3c6a11..ba316de 100644 --- a/src/main/java/top/r3944realms/lib39/example/core/event/ExCommonEventHandler.java +++ b/src/main/java/top/r3944realms/lib39/example/core/event/ExCommonEventHandler.java @@ -1,20 +1,20 @@ package top.r3944realms.lib39.example.core.event; import net.minecraft.world.entity.Entity; -import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent; -import top.r3944realms.lib39.core.sync.CachedSyncManager; -import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.entity.vehicle.Minecart; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import net.neoforged.neoforge.data.event.GatherDataEvent; +import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler; import top.r3944realms.lib39.example.content.capability.TestSyncData; -import top.r3944realms.lib39.example.datagen.EXLib39DataGenEvent; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import top.r3944realms.lib39.example.core.network.ExNetworkHandler; +import top.r3944realms.lib39.example.core.register.ExLib39Attachments; +import top.r3944realms.lib39.example.datagen.ExLib39DataGenEvent; /** * The type Common handler. @@ -26,40 +26,18 @@ public class ExCommonEventHandler { @SuppressWarnings("unused") public static class Game extends ExCommonEventHandler { - /** - * Attach capability. - * - * @param event the event - */ @SubscribeEvent - public static void attachCapability(AttachCapabilitiesEvent event) { - ExCapabilityHandler.attachCapability(event); + public static void onEntityJoinLevel(EntityJoinLevelEvent event) { + Entity entity = event.getEntity(); + if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) { + TestSyncData data = entity.getData(ExLib39Attachments.TEST_DATA_ATTACHMENT); + if (data.entityId() == -1) { + data.setSelf(entity); + } + } } - - /** - * On register sync. - * - * @param event the event - */ - @SubscribeEvent - public static void onRegisterSync (SyncManagerRegisterEvent event) { - event.registerSyncManager( - TestSyncData.ID, - new CachedSyncManager() { - private final Map syncDataMap = new ConcurrentHashMap<>(); - @Override - public Map getSyncMap() { - return syncDataMap; - } - }, - ExCapabilityHandler.TEST_CAP - - ); - } - } - /** * The type Mod. */ @@ -84,7 +62,7 @@ public class ExCommonEventHandler { */ @SubscribeEvent public static void registerCapability(RegisterCapabilitiesEvent event) { - ExCapabilityHandler.registerCapability(event); + ExCapabilityHandler.registerCapabilities(event); } /** @@ -93,8 +71,12 @@ public class ExCommonEventHandler { * @param event the event */ @SubscribeEvent - public static void gatherData(GatherDataEvent event) { - EXLib39DataGenEvent.gatherData(event); + public static void gatherData(GatherDataEvent.Client event) { + ExLib39DataGenEvent.gatherData(event); + } + @SubscribeEvent + public static void registerPayloadPacket (RegisterPayloadHandlersEvent event) { + ExNetworkHandler.registerPackets(event); } } } diff --git a/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPacket.java b/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPacket.java deleted file mode 100644 index 81e5a46..0000000 --- a/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPacket.java +++ /dev/null @@ -1,69 +0,0 @@ -package top.r3944realms.lib39.example.core.network; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent; -import top.r3944realms.lib39.example.content.capability.TestSyncData; -import top.r3944realms.lib39.example.content.item.FabricItem; - -import java.util.function.Supplier; - -/** - * The type Client data packet. - */ -public class ClientDataPacket { - private final TestSyncData clientData; - private final int targetEntityId; - - /** - * Instantiates a new Client data packet. - * - * @param clientData the client data - * @param targetEntityId the target entity id - */ - public ClientDataPacket(TestSyncData clientData, int targetEntityId) { - this.clientData = clientData; - this.targetEntityId = targetEntityId; - } - - /** - * Instantiates a new Client data packet. - * - * @param buf the buf - */ - public ClientDataPacket(FriendlyByteBuf buf) { - this.clientData = TestSyncData.staticFromBytes(buf); - this.targetEntityId = buf.readInt(); - } - - /** - * To bytes. - * - * @param buf the buf - */ - public void toBytes(FriendlyByteBuf buf) { - clientData.toBytes(buf); - buf.writeInt(targetEntityId); - } - - /** - * Handle. - * - * @param supplier the supplier - */ - public void handle(Supplier supplier) { - NetworkEvent.Context context = supplier.get(); - context.enqueueWork(() -> { - ServerPlayer player = context.getSender(); - if (player != null) { - // 处理客户端发送的数据 - handleClientData(player, clientData, targetEntityId); - } - }); - context.setPacketHandled(true); - } - - private void handleClientData(ServerPlayer player, TestSyncData clientData, int targetEntityId) { - FabricItem.handleClientDataFromPacket(player, clientData, targetEntityId); - } -} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPayload.java b/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPayload.java new file mode 100644 index 0000000..36bbc33 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/core/network/ClientDataPayload.java @@ -0,0 +1,43 @@ +package top.r3944realms.lib39.example.core.network; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; + +import net.neoforged.neoforge.network.handling.IPayloadContext; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.example.content.capability.TestSyncData; +import top.r3944realms.lib39.example.content.item.FabricItem; + +/** + * The type Client data packet. + */ +public record ClientDataPayload(TestSyncData clientData, int targetEntityId) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Lib39.MOD_ID, "client_data")); + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + TestSyncData.CODEC, ClientDataPayload::clientData, + ByteBufCodecs.INT, ClientDataPayload::targetEntityId, + ClientDataPayload::new + ); + public void handle(IPayloadContext context) { + context.enqueueWork(() -> { + ServerPlayer player = (ServerPlayer) context.player(); + // 处理客户端发送的数据 + handleClientData(player, clientData, targetEntityId); + }); + } + + private void handleClientData(ServerPlayer player, TestSyncData clientData, int targetEntityId) { + FabricItem.handleClientDataFromPacket(player, clientData, targetEntityId); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/core/network/ExNetworkHandler.java b/src/main/java/top/r3944realms/lib39/example/core/network/ExNetworkHandler.java index d85fdab..661102e 100644 --- a/src/main/java/top/r3944realms/lib39/example/core/network/ExNetworkHandler.java +++ b/src/main/java/top/r3944realms/lib39/example/core/network/ExNetworkHandler.java @@ -1,37 +1,21 @@ package top.r3944realms.lib39.example.core.network; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.simple.SimpleChannel; + +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; /** * The type Ex network handler. */ public class ExNetworkHandler { - /** - * The constant INSTANCE. - */ - public static final SimpleChannel INSTANCE; - private static int ID = 0; - - static { - INSTANCE = NetworkRegistry.newSimpleChannel( - new ResourceLocation(Lib39.MOD_ID, "test"), - () -> "1.0", - s -> true, - s -> true + public static void registerPackets(@NotNull RegisterPayloadHandlersEvent event) { + PayloadRegistrar registrar = event.registrar(Lib39.MOD_ID + "-ex-" + Lib39.ModInfo.VERSION); + registrar.playToServer( + ClientDataPayload.TYPE, + ClientDataPayload.STREAM_CODEC, + ClientDataPayload::handle ); } - - /** - * Register. - */ - public static void register() { - // 注册数据包 - INSTANCE.registerMessage(ID++, ClientDataPacket.class, - ClientDataPacket::toBytes, - ClientDataPacket::new, - ClientDataPacket::handle); - } } \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Attachments.java b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Attachments.java new file mode 100644 index 0000000..9bee2d8 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Attachments.java @@ -0,0 +1,36 @@ +package top.r3944realms.lib39.example.core.register; + +import net.minecraft.world.entity.Entity; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.attachment.AttachmentType; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.example.content.capability.TestSyncData; + +import java.util.function.Supplier; + +public class ExLib39Attachments { + private static final DeferredRegister> ATTACHMENTS = + DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, Lib39.MOD_ID); + + public static final Supplier> TEST_DATA_ATTACHMENT = + ATTACHMENTS.register( + "test_data", + () -> AttachmentType + .serializable(holder -> new TestSyncData(holder)) + .copyOnDeath() + .copyHandler((attachment, holder, provider) -> { + if (!(holder instanceof Entity newEntity)) { + throw new IllegalArgumentException("TestSyncData can only be copied to entities"); + } + return attachment.createSyncCopy(newEntity); + }) + .sync(TestSyncData.CODEC) + .build() + ); + + public static void register(IEventBus iModBus) { + ATTACHMENTS.register(iModBus); + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39ItemResourceKeys.java b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39ItemResourceKeys.java new file mode 100644 index 0000000..945edee --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39ItemResourceKeys.java @@ -0,0 +1,30 @@ +package top.r3944realms.lib39.example.core.register; + +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.neoforged.neoforge.registries.DeferredHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.datagen.value.IResourceKeyValue; + +public enum ExLib39ItemResourceKeys implements IResourceKeyValue { + FABRIC("fabric"), + NEOFORGE("neoforge"), + ; + private final ResourceKey resourceKey; + ExLib39ItemResourceKeys(String name) { + resourceKey = ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(Lib39.MOD_ID, name)); + } + ExLib39ItemResourceKeys(@NotNull DeferredHolder item) { + resourceKey = ResourceKey.create(Registries.ITEM, item.getId()); + } + @Contract(pure = true) + @Override + public @Nullable ResourceKey getResourceKey() { + return resourceKey; + } +} diff --git a/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Items.java b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Items.java index de21c86..f16b4d5 100644 --- a/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Items.java +++ b/src/main/java/top/r3944realms/lib39/example/core/register/ExLib39Items.java @@ -1,14 +1,18 @@ package top.r3944realms.lib39.example.core.register; + +import net.minecraft.core.registries.Registries; import net.minecraft.world.item.Item; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.example.content.item.FabricItem; import top.r3944realms.lib39.example.content.item.NeoForgeItem; +import java.util.Objects; + /** * The type Ex lib 39 items. */ @@ -16,27 +20,29 @@ public class ExLib39Items { /** * The constant ITEMS. */ - public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Lib39.MOD_ID); + public static final DeferredRegister ITEMS = DeferredRegister.create(Registries.ITEM, Lib39.MOD_ID); /** * The constant SUPER_LEAD_ROPE. */ - public static final RegistryObject FABRIC = ITEMS.register( + public static final DeferredHolder FABRIC = ITEMS.register( "fabric", () -> new FabricItem( new Item.Properties() .stacksTo(1) .fireResistant() + .setId(Objects.requireNonNull(ExLib39ItemResourceKeys.FABRIC.getResourceKey())) ) ); /** * The constant ETERNAL_POTATO. */ - public static final RegistryObject NEOFORGE = + public static final DeferredHolder NEOFORGE = ITEMS.register("neoforge", () -> new NeoForgeItem( new Item.Properties() .stacksTo(1) .fireResistant() + .setId(Objects.requireNonNull(ExLib39ItemResourceKeys.NEOFORGE.getResourceKey())) )); /** diff --git a/src/main/java/top/r3944realms/lib39/example/datagen/EXLib39DataGenEvent.java b/src/main/java/top/r3944realms/lib39/example/datagen/ExLib39DataGenEvent.java similarity index 56% rename from src/main/java/top/r3944realms/lib39/example/datagen/EXLib39DataGenEvent.java rename to src/main/java/top/r3944realms/lib39/example/datagen/ExLib39DataGenEvent.java index a1b4ca3..21deb70 100644 --- a/src/main/java/top/r3944realms/lib39/example/datagen/EXLib39DataGenEvent.java +++ b/src/main/java/top/r3944realms/lib39/example/datagen/ExLib39DataGenEvent.java @@ -1,48 +1,48 @@ package top.r3944realms.lib39.example.datagen; import net.minecraft.data.DataProvider; -import net.minecraftforge.data.event.GatherDataEvent; +import net.neoforged.neoforge.data.event.GatherDataEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.datagen.provider.SimpleLanguageProvider; import top.r3944realms.lib39.datagen.value.McLocale; import top.r3944realms.lib39.example.datagen.data.ExLib39LangKeys; -import top.r3944realms.lib39.example.datagen.provider.ExItemModelProvider; +import top.r3944realms.lib39.example.datagen.provider.ExModelDataProvider; /** * The type Ex lib 39 data gen event. */ -public class EXLib39DataGenEvent { +public class ExLib39DataGenEvent { /** * The Logger. */ - static Logger logger = LoggerFactory.getLogger(EXLib39DataGenEvent.class); + static Logger logger = LoggerFactory.getLogger(ExLib39DataGenEvent.class); /** * Gather data. * * @param event the event */ - public static void gatherData(GatherDataEvent event) { + public static void gatherData(GatherDataEvent.Client event) { logger.info("GatherDataEvent thread: {}", Thread.currentThread().getName()); - LanguageGenerator(event, McLocale.EN_US); - LanguageGenerator(event, McLocale.ZH_CN); - LanguageGenerator(event, McLocale.ZH_TW); - LanguageGenerator(event, McLocale.LZH); + LanguageGenerate(event, McLocale.EN_US); + LanguageGenerate(event, McLocale.ZH_CN); + LanguageGenerate(event, McLocale.ZH_TW); + LanguageGenerate(event, McLocale.LZH); ModelDataGenerate(event); } - private static void LanguageGenerator(GatherDataEvent event, McLocale language) { + private static void LanguageGenerate(GatherDataEvent event, McLocale language) { event.getGenerator().addProvider( - event.includeClient(), + true, (DataProvider.Factory) pOutput -> new SimpleLanguageProvider(pOutput, Lib39.MOD_ID ,language ,ExLib39LangKeys.INSTANCE) ); } private static void ModelDataGenerate(GatherDataEvent event) { event.getGenerator().addProvider( - event.includeClient(), - (DataProvider.Factory) pOutput -> new ExItemModelProvider(pOutput, event.getExistingFileHelper()) + true, + (DataProvider.Factory) pOutput -> new ExModelDataProvider(pOutput, Lib39.MOD_ID) ); } } diff --git a/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExBlockModelGenerator.java b/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExBlockModelGenerator.java new file mode 100644 index 0000000..47025a9 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExBlockModelGenerator.java @@ -0,0 +1,21 @@ +package top.r3944realms.lib39.example.datagen.generator; + +import net.minecraft.client.data.models.BlockModelGenerators; +import net.minecraft.client.data.models.ItemModelOutput; +import net.minecraft.client.data.models.blockstates.BlockModelDefinitionGenerator; +import net.minecraft.client.data.models.model.ModelInstance; +import net.minecraft.resources.ResourceLocation; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class ExBlockModelGenerator extends BlockModelGenerators { + public ExBlockModelGenerator(Consumer blockStateOutput, ItemModelOutput itemModelOutput, BiConsumer modelOutput) { + super(blockStateOutput, itemModelOutput, modelOutput); + } + + @Override + public void run() { + + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExItemModelGenerators.java b/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExItemModelGenerators.java new file mode 100644 index 0000000..265bbc8 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/datagen/generator/ExItemModelGenerators.java @@ -0,0 +1,68 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.lib39.example.datagen.generator; + +import net.minecraft.client.data.models.ItemModelGenerators; +import net.minecraft.client.data.models.ItemModelOutput; +import net.minecraft.client.data.models.model.ModelInstance; +import net.minecraft.client.data.models.model.ModelTemplates; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import top.r3944realms.lib39.datagen.value.LangKeyValue; +import top.r3944realms.lib39.datagen.value.ModPartEnum; +import top.r3944realms.lib39.example.datagen.data.ExLib39LangKeys; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; + +/** + * The type Slp item model provider. + */ +public class ExItemModelGenerators extends ItemModelGenerators { + private static List objectList; + + /** + * Instantiates a new Slp item model provider. + * + * @param output the output + * @param existingFileHelper the existing file helper + */ + public ExItemModelGenerators(ItemModelOutput itemModelOutput, BiConsumer modelOutput) { + super(itemModelOutput, modelOutput); + objectList = new ArrayList<>(); + init(); + } + + private void init() { + for(LangKeyValue obj : ExLib39LangKeys.INSTANCE.getValues()) { + if(!(obj.isDefault() && obj.getMPE().equals(ModPartEnum.ITEM))) continue; + objectList.add(obj.getItem()); + } + } + @Override + public void run() { + DefaultModItemModelRegister(); + } + + /** + * @implNote
 先有纹理才会成功构建 + */ + private void DefaultModItemModelRegister() { + objectList.forEach(i -> generateFlatItem(i, ModelTemplates.FLAT_ITEM)); + } + +} diff --git a/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExItemModelProvider.java b/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExItemModelProvider.java deleted file mode 100644 index 459ad8d..0000000 --- a/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExItemModelProvider.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Super Lead rope mod - * Copyright (C) 2025 R3944Realms - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package top.r3944realms.lib39.example.datagen.provider; - -import net.minecraft.data.PackOutput; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.minecraftforge.client.model.generators.ItemModelProvider; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.registries.ForgeRegistries; -import top.r3944realms.lib39.Lib39; -import top.r3944realms.lib39.datagen.value.LangKeyValue; -import top.r3944realms.lib39.datagen.value.ModPartEnum; -import top.r3944realms.lib39.example.datagen.data.ExLib39LangKeys; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * The type Slp item model provider. - */ -public class ExItemModelProvider extends ItemModelProvider { - private static List objectList; - /** - * The constant GENERATED. - */ - public static final String GENERATED = "item/generated"; - /** - * The constant HANDHELD. - */ - public static final String HANDHELD = "item/handheld"; - - /** - * Instantiates a new Slp item model provider. - * - * @param output the output - * @param existingFileHelper the existing file helper - */ - public ExItemModelProvider(PackOutput output, ExistingFileHelper existingFileHelper) { - super(output, Lib39.MOD_ID, existingFileHelper); - objectList = new ArrayList<>(); - init(); - } - - @Override - protected void registerModels() { - DefaultModItemModelRegister(); - } - private void init() { - for(LangKeyValue obj : ExLib39LangKeys.INSTANCE.getValues()) { - if(!(obj.isDefault() && obj.getMPE().equals(ModPartEnum.ITEM))) continue; - objectList.add(obj.getItem()); - } - } - /** - * @implNote
 先有纹理才会成功构建 - */ - private void DefaultModItemModelRegister() { - objectList.forEach(this::basicItem); - } - - /** - * Item generate model. - * - * @param item the item - * @param location the location - */ - public void itemGenerateModel(Item item, ResourceLocation location){ - withExistingParent(itemName(item), GENERATED).texture("layer0", location); - } - - /** - * Item hand held model. - * - * @param item the item - * @param location the location - */ - public void itemHandHeldModel(Item item, ResourceLocation location){ - withExistingParent(itemName(item), HANDHELD).texture("layer0", location); - } - - /** - * Item name string. - * - * @param item the item - * @return the string - */ - public String itemName(Item item){ - return Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)).getPath(); - } - - /** - * Resource item resource location. - * - * @param path the path - * @return the resource location - */ - public ResourceLocation resourceItem(String path){ - return modLoc("item/" + path); - } -} diff --git a/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExModelDataProvider.java b/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExModelDataProvider.java new file mode 100644 index 0000000..1fcd21b --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/example/datagen/provider/ExModelDataProvider.java @@ -0,0 +1,179 @@ +package top.r3944realms.lib39.example.datagen.provider; + +import com.google.common.collect.Maps; +import com.google.gson.JsonElement; +import net.minecraft.client.data.models.ItemModelOutput; +import net.minecraft.client.data.models.ModelProvider; +import net.minecraft.client.data.models.blockstates.BlockModelDefinitionGenerator; +import net.minecraft.client.data.models.model.ItemModelUtils; +import net.minecraft.client.data.models.model.ModelInstance; +import net.minecraft.client.data.models.model.ModelLocationUtils; +import net.minecraft.client.renderer.block.model.BlockModelDefinition; +import net.minecraft.client.renderer.item.ClientItem; +import net.minecraft.client.renderer.item.ItemModel; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.lib39.example.datagen.generator.ExBlockModelGenerator; +import top.r3944realms.lib39.example.datagen.generator.ExItemModelGenerators; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class ExModelDataProvider extends ModelProvider { + private final PackOutput.PathProvider blockStatePathProvider; + private final PackOutput.PathProvider itemInfoPathProvider; + private final PackOutput.PathProvider modelPathProvider; + public ExModelDataProvider(PackOutput packOutput, String modId) { + super(packOutput, modId); + this.blockStatePathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "blockstates"); + this.itemInfoPathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "items"); + this.modelPathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "models"); + } + + @Override + public @NotNull CompletableFuture run(@NotNull CachedOutput cachedOutput) { + + ItemInfoCollector itemModelOutput = new ItemInfoCollector(this::getKnownItems); + BlockStateGeneratorCollector blockModelOutput = new BlockStateGeneratorCollector(this::getKnownBlocks); + SimpleModelCollector modelOutput = new SimpleModelCollector(); + itemModelOutput.finalizeAndValidate(); + this.registerModels(new ExBlockModelGenerator(blockModelOutput, itemModelOutput, modelOutput), new ExItemModelGenerators(itemModelOutput, modelOutput)); + return CompletableFuture.allOf(blockModelOutput.save(cachedOutput, this.blockStatePathProvider), modelOutput.save(cachedOutput, this.modelPathProvider), itemModelOutput.save(cachedOutput, this.itemInfoPathProvider)); + } + + static class ItemInfoCollector implements ItemModelOutput { + private final Map itemInfos; + private final Map copies; + private final Supplier>> knownItems; + + public ItemInfoCollector(Supplier>> knownItems) { + this.itemInfos = new HashMap<>(); + this.copies = new HashMap<>(); + this.knownItems = knownItems; + } + + + public void accept(@NotNull Item item, ItemModel.@NotNull Unbaked model) { + this.register(item, new ClientItem(model, ClientItem.Properties.DEFAULT)); + } + + public void register(@NotNull Item item, @NotNull ClientItem clientItem) { + ClientItem clientitem = this.itemInfos.put(item, clientItem); + if (clientitem != null) { + throw new IllegalStateException("Duplicate item model definition for " + item); + } + } + + public void copy(@NotNull Item item, @NotNull Item copyItem) { + this.copies.put(copyItem, item); + } + + public void finalizeAndValidate() { + (this.knownItems.get()).map(Holder::value).forEach((item) -> { + if (!this.copies.containsKey(item) && item instanceof BlockItem blockitem) { + if (!this.itemInfos.containsKey(blockitem)) { + ResourceLocation resourcelocation = ModelLocationUtils.getModelLocation(blockitem.getBlock()); + this.accept(blockitem, ItemModelUtils.plainModel(resourcelocation)); + } + } + + }); + this.copies.forEach((item, item1) -> { + ClientItem clientitem = this.itemInfos.get(item1); + if (clientitem == null) { + String item1Name = String.valueOf(item1); + throw new IllegalStateException("Missing donor: " + item1Name + " -> " + item); + } else { + this.register(item, clientitem); + } + }); + List list = (this.knownItems.get()).filter((holder) -> !this.itemInfos.containsKey(holder.value())).map((holder) -> holder.unwrapKey().orElseThrow().location()).toList(); + + if (!list.isEmpty()) { + LOGGER.warn("Missing item model definitions for: {}", list); + } + } + + public CompletableFuture save(CachedOutput cachedOutput, PackOutput.PathProvider pathProvider) { + return DataProvider.saveAll(cachedOutput, ClientItem.CODEC, (item) -> pathProvider.json(item.builtInRegistryHolder().key().location()), this.itemInfos); + } + } + + static class SimpleModelCollector implements BiConsumer { + private final Map models = new HashMap<>(); + + SimpleModelCollector() { + } + + public void accept(ResourceLocation resourceLocation, ModelInstance modelInstance) { + Supplier supplier = this.models.put(resourceLocation, modelInstance); + if (supplier != null) { + throw new IllegalStateException("Duplicate model definition for " + resourceLocation); + } + } + + public CompletableFuture save(CachedOutput cachedOutput, PackOutput.PathProvider pathProvider) { + Objects.requireNonNull(pathProvider); + return saveAll(cachedOutput, pathProvider::json, this.models); + } + + static CompletableFuture saveAll(CachedOutput cachedOutput, Function tPathFunction, Map> tMap) { + return DataProvider.saveAll(cachedOutput, Supplier::get, tPathFunction, tMap); + } + } + + static class BlockStateGeneratorCollector implements Consumer { + private final Map generators = new HashMap<>(); + private final Supplier>> knownBlocks; + + public BlockStateGeneratorCollector(Supplier>> knownBlocks) { + this.knownBlocks = knownBlocks; + } + + @Deprecated // Neo: Provided for vanilla/multi-loader compatibility. Use constructor with Supplier parameter. + public BlockStateGeneratorCollector() { + this(BuiltInRegistries.BLOCK::listElements); + } + + public void accept(BlockModelDefinitionGenerator p_405192_) { + Block block = p_405192_.block(); + BlockModelDefinitionGenerator blockmodeldefinitiongenerator = this.generators.put(block, p_405192_); + if (blockmodeldefinitiongenerator != null) { + throw new IllegalStateException("Duplicate blockstate definition for " + block); + } + } + + public void validate() { + Stream> stream = knownBlocks.get(); + List list = stream.filter(p_386843_ -> !this.generators.containsKey(p_386843_.value())) + .map(p_386823_ -> p_386823_.unwrapKey().orElseThrow().location()) + .toList(); + if (!list.isEmpty()) { + throw new IllegalStateException("Missing blockstate definitions for: " + list); + } + } + + public CompletableFuture save(CachedOutput output, PackOutput.PathProvider pathProvider) { + Map map = Maps.transformValues(this.generators, BlockModelDefinitionGenerator::create); + Function function = p_387598_ -> pathProvider.json(p_387598_.builtInRegistryHolder().key().location()); + return DataProvider.saveAll(output, BlockModelDefinition.CODEC, function, map); + } + } +} diff --git a/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java b/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java index 2415ad1..8993f0b 100644 --- a/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java +++ b/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java @@ -4,8 +4,9 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.level.block.Block; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.neoforge.registries.DeferredBlock; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.core.event.CommonEventHandler; @@ -18,7 +19,7 @@ import java.util.function.Supplier; @SuppressWarnings({"UnusedReturnValue", "unused"}) public class BlockRegistryBuilder { private String registryName; - private RegistryObject blockObject; + private DeferredHolder blockObject; /** * 创建新的构建器实例 @@ -57,7 +58,7 @@ public class BlockRegistryBuilder { * 内部方法:注册对应的方块物品 */ @SafeVarargs - private void registerBlockItem(RegistryObject blockObject, ResourceKey... creativeTabs) { + private void registerBlockItem(DeferredHolder blockObject, ResourceKey... creativeTabs) { CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs); } @@ -92,7 +93,7 @@ public class BlockRegistryBuilder { * * @return the registry object */ - public RegistryObject build() { + public DeferredHolder build() { return this.blockObject; } diff --git a/src/main/java/top/r3944realms/lib39/util/capability/EntityCapabilityHelper.java b/src/main/java/top/r3944realms/lib39/util/capability/EntityCapabilityHelper.java new file mode 100644 index 0000000..63d2cff --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/util/capability/EntityCapabilityHelper.java @@ -0,0 +1,199 @@ +package top.r3944realms.lib39.util.capability; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.monster.Monster; +import net.neoforged.neoforge.capabilities.EntityCapability; +import net.neoforged.neoforge.capabilities.ICapabilityProvider; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Predicate; + +/** + * 实体 Capability 注册工具类 + * 简化批量注册实体能力的过程 + */ +@SuppressWarnings("unused") +public class EntityCapabilityHelper { + + /** + * 为多个实体类型注册相同的 Capability Provider + */ + public static void registerForEntityTypes( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + EntityType... entityTypes) { + + if (entityTypes.length == 0) { + throw new IllegalArgumentException("必须提供至少一个实体类型"); + } + + for (EntityType entityType : entityTypes) { + event.registerEntity(capability, entityType, provider); + } + } + + /** + * 为继承自某个基类的所有实体注册 Capability + */ + public static void registerForEntityClass( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + Class baseClass) { + + BuiltInRegistries.ENTITY_TYPE.stream() + .filter(entityType -> entityType.getBaseClass().isAssignableFrom(baseClass)) + .forEach(entityType -> event.registerEntity(capability, entityType, provider)); + } + + /** + * 为特定命名空间的所有实体注册 Capability + */ + public static void registerForModEntities( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + String namespace) { + + BuiltInRegistries.ENTITY_TYPE.stream() + .filter(entityType -> { + ResourceLocation key = BuiltInRegistries.ENTITY_TYPE.getKey(entityType); + return namespace.equals(key.getNamespace()); + }) + .forEach(entityType -> event.registerEntity(capability, entityType, provider)); + } + + /** + * 为特定生物类别的所有实体注册 Capability + */ + public static void registerForMobCategory( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + MobCategory category) { + + BuiltInRegistries.ENTITY_TYPE.stream() + .filter(entityType -> entityType.getCategory() == category) + .forEach(entityType -> event.registerEntity(capability, entityType, provider)); + } + + /** + * 基于条件筛选注册实体 Capability + */ + public static void registerEntitiesByCondition( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + Predicate> condition) { + + BuiltInRegistries.ENTITY_TYPE.stream() + .filter(condition) + .forEach(entityType -> event.registerEntity(capability, entityType, provider)); + } + + /** + * 为所有生物实体注册 Capability(包括玩家) + */ + public static void registerForAllLivingEntities( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider) { + + registerForEntityClass(event, capability, provider, LivingEntity.class); + } + + /** + * 为所有怪物实体注册 Capability + */ + public static void registerForAllMonsters( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider) { + + registerForEntityClass(event, capability, provider, Monster.class); + } + + /** + * 为所有动物实体注册 Capability + */ + public static void registerForAllAnimals( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider) { + + registerForEntityClass(event, capability, provider, Animal.class); + } + + /** + * 为所有玩家注册 Capability + */ + public static void registerForPlayers( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider) { + + registerForEntityTypes(event, capability, provider, EntityType.PLAYER); + } + + /** + * 为所有BOSS实体注册 Capability + */ + public static void registerForBossEntities( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider) { + + registerEntitiesByCondition(event, capability, provider, entityType -> + entityType == EntityType.ENDER_DRAGON || + entityType == EntityType.WITHER || + entityType == EntityType.WARDEN + ); + } + + /** + * 排除特定实体类型进行注册 + */ + public static void registerWithExclusions( + RegisterCapabilitiesEvent event, + EntityCapability capability, + ICapabilityProvider provider, + Collection> includedEntities, + EntityType... excludedTypes) { + + Collection> excludedSet = Arrays.asList(excludedTypes); + + includedEntities.stream() + .filter(entityType -> !excludedSet.contains(entityType)) + .forEach(entityType -> event.registerEntity(capability, entityType, provider)); + } + + /** + * 检查某个实体类型是否已经注册了指定的 Capability + */ + public static boolean isEntityCapabilityRegistered( + RegisterCapabilitiesEvent event, + EntityCapability capability, + EntityType entityType) { + + return event.isEntityRegistered(capability, entityType); + } + + /** + * 获取已注册指定 Capability 的实体类型数量 + */ + public static long getRegisteredEntityCount( + RegisterCapabilitiesEvent event, + EntityCapability capability) { + + return BuiltInRegistries.ENTITY_TYPE.stream() + .filter(entityType -> event.isEntityRegistered(capability, entityType)) + .count(); + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/util/chat/MessageDisplayClientHelper.java b/src/main/java/top/r3944realms/lib39/util/chat/MessageDisplayClientHelper.java new file mode 100644 index 0000000..a63f0b4 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/util/chat/MessageDisplayClientHelper.java @@ -0,0 +1,13 @@ +package top.r3944realms.lib39.util.chat; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; + +public class MessageDisplayClientHelper { + public static void sendSystemMessage(Component component) { + sendSystemMessage(component, false); + } + public static void sendSystemMessage(Component component, boolean isOverlay) { + Minecraft.getInstance().execute(() -> Minecraft.getInstance().getChatListener().handleSystemMessage(component, isOverlay)); + } +} diff --git a/src/main/java/top/r3944realms/lib39/util/riding/RidingApplier.java b/src/main/java/top/r3944realms/lib39/util/riding/RidingApplier.java index 9611659..d9502e7 100644 --- a/src/main/java/top/r3944realms/lib39/util/riding/RidingApplier.java +++ b/src/main/java/top/r3944realms/lib39/util/riding/RidingApplier.java @@ -75,7 +75,7 @@ public class RidingApplier { if (RidingValidator.wouldCreateCycle(entity, vehicle)) { throw new RidingCycleException(entityId, vehicleId); } - boolean success = entity.startRiding(vehicle, true); + boolean success = entity.startRiding(vehicle, true, true); if (!success) { Lib39.LOGGER.error("Failed to mount entity {} to vehicle {}", entityId, vehicleId); } diff --git a/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java b/src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTReader.java similarity index 67% rename from src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java rename to src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTReader.java index 86a4a08..184b45b 100644 --- a/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java +++ b/src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTReader.java @@ -1,19 +1,4 @@ -/* - * Super Lead rope mod - * Copyright (C) 2025 R3944Realms - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package top.r3944realms.lib39.util.nbt; +package top.r3944realms.lib39.util.storage.nbt; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -21,7 +6,6 @@ import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.UUID; import java.util.function.Consumer; /** @@ -55,8 +39,8 @@ public class NBTReader { */ // 基本读取方法 - 直接赋值给成员变量 public NBTReader string(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getString(key)); + if (nbt.contains(key) && nbt.getString(key).isPresent()) { + setter.accept(nbt.getString(key).get()); } return this; } @@ -70,7 +54,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader string(String key, @NotNull Consumer setter, String defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getString(key) : defaultValue); + setter.accept(nbt.contains(key) && nbt.getString(key).isPresent() ? nbt.getString(key).get() : defaultValue); return this; } @@ -82,8 +66,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader byteValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getByte(key)); + if (nbt.contains(key) && nbt.getByte(key).isPresent()) { + setter.accept(nbt.getByte(key).get()); } return this; } @@ -97,7 +81,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader byteValue(String key, @NotNull Consumer setter, byte defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getByte(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getByteOr(key, defaultValue) : defaultValue); return this; } @@ -109,8 +93,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader shortValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getShort(key)); + if (nbt.contains(key) && nbt.getShort(key).isPresent()) { + setter.accept(nbt.getShort(key).get()); } return this; } @@ -124,7 +108,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader shortValue(String key, @NotNull Consumer setter, short defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getShort(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getShortOr(key, defaultValue) : defaultValue); return this; } @@ -136,8 +120,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader intValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getInt(key)); + if (nbt.contains(key) && nbt.getInt(key).isPresent()) { + setter.accept(nbt.getInt(key).get()); } return this; } @@ -151,7 +135,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader intValue(String key, @NotNull Consumer setter, int defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getInt(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getIntOr(key, defaultValue) : defaultValue); return this; } @@ -163,8 +147,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader longValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getLong(key)); + if (nbt.contains(key) && nbt.getLong(key).isPresent()) { + setter.accept(nbt.getLong(key).get()); } return this; } @@ -178,7 +162,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader longValue(String key, @NotNull Consumer setter, long defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getLong(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getLongOr(key, defaultValue) : defaultValue); return this; } @@ -190,8 +174,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader floatValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getFloat(key)); + if (nbt.contains(key) && nbt.getFloat(key).isPresent()) { + setter.accept(nbt.getFloat(key).get()); } return this; } @@ -205,10 +189,9 @@ public class NBTReader { * @return the nbt reader */ public NBTReader floatValue(String key, @NotNull Consumer setter, float defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getFloat(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getFloatOr(key, defaultValue) : defaultValue); return this; } - /** * Double value nbt reader. * @@ -217,8 +200,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader doubleValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getDouble(key)); + if (nbt.contains(key) && nbt.getDouble(key).isPresent()) { + setter.accept(nbt.getDouble(key).get()); } return this; } @@ -232,7 +215,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader doubleValue(String key, @NotNull Consumer setter, double defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getDouble(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getDoubleOr(key, defaultValue) : defaultValue); return this; } @@ -244,8 +227,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader booleanValue(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getBoolean(key)); + if (nbt.contains(key) && nbt.getBoolean(key).isPresent()) { + setter.accept(nbt.getBoolean(key).get()); } return this; } @@ -259,7 +242,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader booleanValue(String key, @NotNull Consumer setter, boolean defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getBoolean(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getBooleanOr(key, defaultValue) : defaultValue); return this; } @@ -270,14 +253,26 @@ public class NBTReader { * @param setter the setter * @return the nbt reader */ -// 数组类型 public NBTReader byteArray(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getByteArray(key)); + if (nbt.contains(key) && nbt.getByteArray(key).isPresent()) { + setter.accept(nbt.getByteArray(key).get()); } return this; } + /** + * Byte array nbt reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the nbt reader + */ + public NBTReader byteArray(String key, @NotNull Consumer setter, byte[] defaultValue) { + setter.accept(nbt.contains(key) ? nbt.getByteArray(key).orElse(defaultValue) : defaultValue); + return this; + } + /** * Int array nbt reader. * @@ -286,12 +281,25 @@ public class NBTReader { * @return the nbt reader */ public NBTReader intArray(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getIntArray(key)); + if (nbt.contains(key) && nbt.getIntArray(key).isPresent()) { + setter.accept(nbt.getIntArray(key).get()); } return this; } + /** + * Int array nbt reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the nbt reader + */ + public NBTReader intArray(String key, @NotNull Consumer setter, int[] defaultValue) { + setter.accept(nbt.contains(key) ? nbt.getIntArray(key).orElse(defaultValue) : defaultValue); + return this; + } + /** * Long array nbt reader. * @@ -300,37 +308,22 @@ public class NBTReader { * @return the nbt reader */ public NBTReader longArray(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getLongArray(key)); + if (nbt.contains(key) && nbt.getLongArray(key).isPresent()) { + setter.accept(nbt.getLongArray(key).get()); } return this; } /** - * Uuid nbt reader. - * - * @param key the key - * @param setter the setter - * @return the nbt reader - */ -// UUID - public NBTReader uuid(String key, Consumer setter) { - if (nbt.hasUUID(key)) { - setter.accept(nbt.getUUID(key)); - } - return this; - } - - /** - * Uuid nbt reader. + * Long array nbt reader. * * @param key the key * @param setter the setter * @param defaultValue the default value * @return the nbt reader */ - public NBTReader uuid(String key, @NotNull Consumer setter, UUID defaultValue) { - setter.accept(nbt.hasUUID(key) ? nbt.getUUID(key) : defaultValue); + public NBTReader longArray(String key, @NotNull Consumer setter, long[] defaultValue) { + setter.accept(nbt.contains(key) ? nbt.getLongArray(key).orElse(defaultValue) : defaultValue); return this; } @@ -341,10 +334,10 @@ public class NBTReader { * @param setter the setter * @return the nbt reader */ -// CompoundTag + @SuppressWarnings("UnusedReturnValue") public NBTReader compound(String key, Consumer setter) { - if (nbt.contains(key)) { - setter.accept(nbt.getCompound(key)); + if (nbt.contains(key) && nbt.getCompound(key).isPresent()) { + setter.accept(nbt.getCompound(key).get()); } return this; } @@ -358,7 +351,7 @@ public class NBTReader { * @return the nbt reader */ public NBTReader compound(String key, @NotNull Consumer setter, CompoundTag defaultValue) { - setter.accept(nbt.contains(key) ? nbt.getCompound(key) : defaultValue); + setter.accept(nbt.contains(key) ? nbt.getCompound(key).orElse(defaultValue) : defaultValue); return this; } @@ -366,14 +359,33 @@ public class NBTReader { * List nbt reader. * * @param key the key - * @param type the type * @param setter the setter * @return the nbt reader */ -// ListTag - public NBTReader list(String key, int type, Consumer setter) { + public NBTReader list(String key, Consumer setter) { + if (nbt.contains(key) && nbt.getList(key).isPresent()) { + ListTag list = nbt.getList(key).get(); + if (!list.isEmpty()) { + setter.accept(list); + } + } + return this; + } + + /** + * List nbt reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the nbt reader + */ + public NBTReader list(String key, @NotNull Consumer setter, ListTag defaultValue) { if (nbt.contains(key)) { - setter.accept(nbt.getList(key, type)); + ListTag list = nbt.getListOrEmpty(key); + setter.accept(list.isEmpty() ? defaultValue : list); + } else { + setter.accept(defaultValue); } return this; } @@ -385,15 +397,14 @@ public class NBTReader { * @param setter the setter * @return the nbt reader */ -// Vec3支持 public NBTReader vec3(String key, Consumer setter) { - if (nbt.contains(key)) { - CompoundTag vecTag = nbt.getCompound(key); + if (nbt.contains(key) && nbt.getCompound(key).isPresent()) { + CompoundTag vecTag = nbt.getCompound(key).get(); if (vecTag.contains("X") && vecTag.contains("Y") && vecTag.contains("Z")) { setter.accept(new Vec3( - vecTag.getDouble("X"), - vecTag.getDouble("Y"), - vecTag.getDouble("Z") + vecTag.getDouble("X").orElse(0.0), + vecTag.getDouble("Y").orElse(0.0), + vecTag.getDouble("Z").orElse(0.0) )); } } @@ -409,13 +420,13 @@ public class NBTReader { * @return the nbt reader */ public NBTReader vec3(String key, Consumer setter, Vec3 defaultValue) { - if (nbt.contains(key)) { - CompoundTag vecTag = nbt.getCompound(key); + if (nbt.contains(key) && nbt.getCompound(key).isPresent()) { + CompoundTag vecTag = nbt.getCompound(key).get(); if (vecTag.contains("X") && vecTag.contains("Y") && vecTag.contains("Z")) { setter.accept(new Vec3( - vecTag.getDouble("X"), - vecTag.getDouble("Y"), - vecTag.getDouble("Z") + vecTag.getDouble("X").orElse(0.0), + vecTag.getDouble("Y").orElse(0.0), + vecTag.getDouble("Z").orElse(0.0) )); return this; } @@ -433,14 +444,13 @@ public class NBTReader { * @param setter the setter * @return the nbt reader */ -// 枚举支持 public > NBTReader enumValue(String key, Class enumClass, Consumer setter) { - if (nbt.contains(key)) { - String value = nbt.getString(key); + if (nbt.contains(key) && nbt.getString(key).isPresent()) { + String value = nbt.getString(key).get(); try { setter.accept(Enum.valueOf(enumClass, value.toUpperCase())); } catch (IllegalArgumentException ignored) { - // 保持setter的当前值 + } } return this; @@ -457,8 +467,8 @@ public class NBTReader { * @return the nbt reader */ public > NBTReader enumValue(String key, Class enumClass, Consumer setter, T defaultValue) { - if (nbt.contains(key)) { - String value = nbt.getString(key); + if (nbt.contains(key) && nbt.getString(key).isPresent()) { + String value = nbt.getString(key).get(); try { setter.accept(Enum.valueOf(enumClass, value.toUpperCase())); return this; @@ -476,10 +486,9 @@ public class NBTReader { * @param consumer the consumer * @return the nbt reader */ -// 嵌套读取支持 public NBTReader nested(String key, Consumer consumer) { - if (nbt.contains(key)) { - consumer.accept(new NBTReader(nbt.getCompound(key))); + if (nbt.contains(key) && nbt.getCompound(key).isPresent()) { + consumer.accept(new NBTReader(nbt.getCompound(key).get())); } return this; } @@ -493,8 +502,8 @@ public class NBTReader { * @return the nbt reader */ public NBTReader nested(String key, Consumer consumer, Runnable orElse) { - if (nbt.contains(key)) { - consumer.accept(new NBTReader(nbt.getCompound(key))); + if (nbt.contains(key) && nbt.getCompound(key).isPresent()) { + consumer.accept(new NBTReader(nbt.getCompound(key).get())); } else { orElse.run(); } @@ -508,7 +517,6 @@ public class NBTReader { * @param action the action * @return the nbt reader */ -// 条件读取 public NBTReader ifPresent(String key, Runnable action) { if (nbt.contains(key)) { action.run(); @@ -535,7 +543,6 @@ public class NBTReader { * * @return the raw */ -// 获取原始NBT @NotNull public CompoundTag getRaw() { return nbt; @@ -547,14 +554,13 @@ public class NBTReader { * @param nbt the nbt * @return the vec 3 */ -// 便捷的静态方法(保持原有功能) @NotNull public static Vec3 readVec3(@NotNull CompoundTag nbt) { if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) { return new Vec3( - nbt.getDouble("X"), - nbt.getDouble("Y"), - nbt.getDouble("Z") + nbt.getDouble("X").orElse(0.0), + nbt.getDouble("Y").orElse(0.0), + nbt.getDouble("Z").orElse(0.0) ); } else { throw new IllegalArgumentException("NBT is missing X, Y, or Z value for Vec3"); @@ -571,11 +577,11 @@ public class NBTReader { public static Vec3 readVec3Safe(@NotNull CompoundTag nbt) { if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) { return new Vec3( - nbt.getDouble("X"), - nbt.getDouble("Y"), - nbt.getDouble("Z") + nbt.getDouble("X").orElse(0.0), + nbt.getDouble("Y").orElse(0.0), + nbt.getDouble("Z").orElse(0.0) ); } return null; } -} +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/lib39/util/nbt/NBTWriter.java b/src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTWriter.java similarity index 96% rename from src/main/java/top/r3944realms/lib39/util/nbt/NBTWriter.java rename to src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTWriter.java index 7235330..737af11 100644 --- a/src/main/java/top/r3944realms/lib39/util/nbt/NBTWriter.java +++ b/src/main/java/top/r3944realms/lib39/util/storage/nbt/NBTWriter.java @@ -1,4 +1,4 @@ -package top.r3944realms.lib39.util.nbt; +package top.r3944realms.lib39.util.storage.nbt; import net.minecraft.nbt.*; import net.minecraft.world.phys.Vec3; @@ -6,7 +6,6 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.UUID; import java.util.function.Consumer; /** @@ -394,38 +393,6 @@ public class NBTWriter { return this; } - /** - * Uuid nbt writer. - * - * @param key the key - * @param value the value - * @return the nbt writer - */ -// UUID支持 - public NBTWriter uuid(String key, UUID value) { - if (value != null) { - root.putUUID(key, value); - } - return this; - } - - /** - * Uuid nbt writer. - * - * @param key the key - * @param value the value - * @param defaultValue the default value - * @return the nbt writer - */ - public NBTWriter uuid(String key, UUID value, UUID defaultValue) { - if (value != null) { - root.putUUID(key, value); - } else if (defaultValue != null) { - root.putUUID(key, defaultValue); - } - return this; - } - /** * Compound nbt writer. * @@ -1061,7 +1028,7 @@ public class NBTWriter { * @return the all keys */ public java.util.Set getAllKeys() { - return root.getAllKeys(); + return root.tags.keySet(); } /** diff --git a/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueInputReader.java b/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueInputReader.java new file mode 100644 index 0000000..606d32c --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueInputReader.java @@ -0,0 +1,526 @@ +package top.r3944realms.lib39.util.storage.valueio; + + +import com.mojang.serialization.Codec; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Consumer; + +/** + * ValueInput Helper类 + * 提供链式操作和类型安全的ValueInput数据读取 + */ +@SuppressWarnings("unused") +public class ValueInputReader { + private final net.minecraft.world.level.storage.ValueInput valueInput; + + private ValueInputReader(net.minecraft.world.level.storage.ValueInput valueInput) { + this.valueInput = valueInput; + } + + /** + * 从ValueInput创建读取器 + * + * @param valueInput the value input + * @return the value input reader + */ + @NotNull + public static ValueInputReader of(@NotNull net.minecraft.world.level.storage.ValueInput valueInput) { + return new ValueInputReader(valueInput); + } + + /** + * String value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + // 基本读取方法 - 直接赋值给成员变量 + public ValueInputReader string(String key, Consumer setter) { + valueInput.getString(key).ifPresent(setter); + return this; + } + + /** + * String value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader string(String key, @NotNull Consumer setter, String defaultValue) { + setter.accept(valueInput.getStringOr(key, defaultValue)); + return this; + } + + /** + * Boolean value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader booleanValue(String key, Consumer setter) { + valueInput.read(key, Codec.BOOL).ifPresent(setter); + return this; + } + + /** + * Boolean value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader booleanValue(String key, @NotNull Consumer setter, boolean defaultValue) { + setter.accept(valueInput.getBooleanOr(key, defaultValue)); + return this; + } + + /** + * Byte value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader byteValue(String key, Consumer setter) { + valueInput.read(key, Codec.BYTE).ifPresent(setter); + return this; + } + + /** + * Byte value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader byteValue(String key, @NotNull Consumer setter, byte defaultValue) { + setter.accept(valueInput.getByteOr(key, defaultValue)); + return this; + } + + /** + * Short value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader shortValue(String key, Consumer setter) { + valueInput.read(key, Codec.SHORT).ifPresent(setter); + return this; + } + + /** + * Short value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader shortValue(String key, @NotNull Consumer setter, short defaultValue) { + setter.accept((short) valueInput.getShortOr(key, defaultValue)); + return this; + } + + /** + * Int value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader intValue(String key, Consumer setter) { + valueInput.getInt(key).ifPresent(setter); + return this; + } + + /** + * Int value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader intValue(String key, @NotNull Consumer setter, int defaultValue) { + setter.accept(valueInput.getIntOr(key, defaultValue)); + return this; + } + + /** + * Long value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader longValue(String key, Consumer setter) { + valueInput.getLong(key).ifPresent(setter); + return this; + } + + /** + * Long value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader longValue(String key, @NotNull Consumer setter, long defaultValue) { + setter.accept(valueInput.getLongOr(key, defaultValue)); + return this; + } + + /** + * Float value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader floatValue(String key, Consumer setter) { + valueInput.read(key, Codec.FLOAT).ifPresent(setter); + return this; + } + + /** + * Float value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader floatValue(String key, @NotNull Consumer setter, float defaultValue) { + setter.accept(valueInput.getFloatOr(key, defaultValue)); + return this; + } + + /** + * Double value value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader doubleValue(String key, Consumer setter) { + valueInput.read(key, Codec.DOUBLE).ifPresent(setter); + return this; + } + + /** + * Double value value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader doubleValue(String key, @NotNull Consumer setter, double defaultValue) { + setter.accept(valueInput.getDoubleOr(key, defaultValue)); + return this; + } + + /** + * Int array value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader intArray(String key, Consumer setter) { + valueInput.getIntArray(key).ifPresent(setter); + return this; + } + + /** + * Int array value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader intArray(String key, @NotNull Consumer setter, int[] defaultValue) { + setter.accept(valueInput.getIntArray(key).orElse(defaultValue)); + return this; + } + + /** + * Codec value value input reader. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader codecValue(String key, Codec codec, Consumer setter) { + valueInput.read(key, codec).ifPresent(setter); + return this; + } + + /** + * Codec value value input reader. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader codecValue(String key, Codec codec, @NotNull Consumer setter, T defaultValue) { + setter.accept(valueInput.read(key, codec).orElse(defaultValue)); + return this; + } + + /** + * Vec 3 value input reader. + * + * @param key the key + * @param setter the setter + * @return the value input reader + */ + public ValueInputReader vec3(String key, Consumer setter) { + valueInput.child(key).ifPresent(child -> { + try { + Vec3 vec = readVec3(child); + setter.accept(vec); + } catch (IllegalArgumentException ignored) { + // 忽略解析错误 + } + }); + return this; + } + + /** + * Vec 3 value input reader. + * + * @param key the key + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader vec3(String key, Consumer setter, Vec3 defaultValue) { + Optional child = valueInput.child(key); + if (child.isPresent()) { + try { + Vec3 vec = readVec3(child.get()); + setter.accept(vec); + return this; + } catch (IllegalArgumentException ignored) { + // 忽略解析错误,使用默认值 + } + } + setter.accept(defaultValue); + return this; + } + + /** + * Enum value value input reader. + * + * @param the type parameter + * @param key the key + * @param enumClass the enum class + * @param setter the setter + * @return the value input reader + */ + public > ValueInputReader enumValue(String key, Class enumClass, Consumer setter) { + valueInput.getString(key).ifPresent(value -> { + try { + setter.accept(Enum.valueOf(enumClass, value.toUpperCase())); + } catch (IllegalArgumentException ignored) { + // 忽略枚举解析错误 + } + }); + return this; + } + + /** + * Enum value value input reader. + * + * @param the type parameter + * @param key the key + * @param enumClass the enum class + * @param setter the setter + * @param defaultValue the default value + * @return the value input reader + */ + public > ValueInputReader enumValue(String key, Class enumClass, Consumer setter, T defaultValue) { + Optional value = valueInput.getString(key); + if (value.isPresent()) { + try { + setter.accept(Enum.valueOf(enumClass, value.get().toUpperCase())); + return this; + } catch (IllegalArgumentException ignored) { + // 忽略枚举解析错误 + } + } + setter.accept(defaultValue); + return this; + } + + /** + * Nested value input reader. + * + * @param key the key + * @param consumer the consumer + * @return the value input reader + */ + public ValueInputReader nested(String key, Consumer consumer) { + valueInput.child(key).ifPresent(child -> consumer.accept(new ValueInputReader(child))); + return this; + } + + /** + * Nested value input reader. + * + * @param key the key + * @param consumer the consumer + * @param orElse the or else + * @return the value input reader + */ + public ValueInputReader nested(String key, Consumer consumer, Runnable orElse) { + Optional child = valueInput.child(key); + if (child.isPresent()) { + consumer.accept(new ValueInputReader(child.get())); + } else { + orElse.run(); + } + return this; + } + + /** + * List value input reader. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param consumer the consumer + * @return the value input reader + */ + public ValueInputReader list(String key, Codec codec, Consumer> consumer) { + valueInput.list(key, codec).ifPresent(list -> { + if (!list.isEmpty()) { + consumer.accept(list.stream()); + } + }); + return this; + } + + /** + * List value input reader. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param consumer the consumer + * @param defaultValue the default value + * @return the value input reader + */ + public ValueInputReader list(String key, Codec codec, @NotNull Consumer> consumer, java.util.stream.Stream defaultValue) { + Optional> list = valueInput.list(key, codec); + if (list.isPresent() && !list.get().isEmpty()) { + consumer.accept(list.get().stream()); + } else { + consumer.accept(defaultValue); + } + return this; + } + + /** + * Children list value input reader. + * + * @param key the key + * @param consumer the consumer + * @return the value input reader + */ + public ValueInputReader childrenList(String key, Consumer> consumer) { + valueInput.childrenList(key).ifPresent(list -> { + if (!list.isEmpty()) { + consumer.accept(list.stream().map(ValueInputReader::new)); + } + }); + return this; + } + + /** + * If present value input reader. + * + * @param key the key + * @param action the action + * @return the value input reader + */ + public ValueInputReader ifPresent(String key, Runnable action) { + if (valueInput.child(key).isPresent()) { + action.run(); + } + return this; + } + + /** + * If absent value input reader. + * + * @param key the key + * @param action the action + * @return the value input reader + */ + public ValueInputReader ifAbsent(String key, Runnable action) { + if (valueInput.child(key).isEmpty()) { + action.run(); + } + return this; + } + + /** + * Gets raw. + * + * @return the raw + */ + @NotNull + public net.minecraft.world.level.storage.ValueInput getRaw() { + return valueInput; + } + + /** + * Read vec 3 vec 3. + * + * @param valueInput the value input + * @return the vec 3 + */ + @NotNull + public static Vec3 readVec3(@NotNull net.minecraft.world.level.storage.ValueInput valueInput) { + double x = valueInput.getDoubleOr("X", 0.0); + double y = valueInput.getDoubleOr("Y", 0.0); + double z = valueInput.getDoubleOr("Z", 0.0); + return new Vec3(x, y, z); + } + + /** + * Read vec 3 safe vec 3. + * + * @param valueInput the value input + * @return the vec 3 + */ + @Nullable + public static Vec3 readVec3Safe(@NotNull net.minecraft.world.level.storage.ValueInput valueInput) { + try { + return readVec3(valueInput); + } catch (Exception e) { + return null; + } + } +} diff --git a/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueOutputWriter.java b/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueOutputWriter.java new file mode 100644 index 0000000..c48af72 --- /dev/null +++ b/src/main/java/top/r3944realms/lib39/util/storage/valueio/ValueOutputWriter.java @@ -0,0 +1,634 @@ +package top.r3944realms.lib39.util.storage.valueio; + +import com.mojang.serialization.Codec; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * ValueOutput Helper类 + * 提供链式操作和类型安全的ValueOutput数据写入 + */ +@SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType", "UnusedReturnValue"}) +public class ValueOutputWriter { + private final net.minecraft.world.level.storage.ValueOutput valueOutput; + private ValueOutputWriter() { + this.valueOutput = TagValueOutput.createWithoutContext(ProblemReporter.DISCARDING); + } + private ValueOutputWriter(net.minecraft.world.level.storage.ValueOutput valueOutput) { + this.valueOutput = valueOutput; + } + /** + * 创建一个新的NBT构建器 + * + * @return the nbt writer + */ + @Contract(value = " -> new", pure = true) + public static @NotNull ValueOutputWriter builder() { + return new ValueOutputWriter(); + } + + /** + * 从ValueOutput创建写入器 + * + * @param valueOutput the value output + * @return the value output writer + */ + @NotNull + public static ValueOutputWriter of(@NotNull net.minecraft.world.level.storage.ValueOutput valueOutput) { + return new ValueOutputWriter(valueOutput); + } + + /** + * String value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + // 基本写入方法 + public ValueOutputWriter string(String key, String value) { + if (value != null) { + valueOutput.putString(key, value); + } + return this; + } + + /** + * String value output writer. + * + * @param key the key + * @param value the value + * @param defaultValue the default value + * @return the value output writer + */ + public ValueOutputWriter string(String key, @Nullable String value, String defaultValue) { + valueOutput.putString(key, value != null ? value : defaultValue); + return this; + } + + /** + * String value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter string(String key, Optional value) { + value.ifPresent(v -> valueOutput.putString(key, v)); + return this; + } + + /** + * Boolean value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter booleanValue(String key, boolean value) { + valueOutput.putBoolean(key, value); + return this; + } + + /** + * Boolean value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter booleanValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putBoolean(key, v)); + return this; + } + + /** + * Byte value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter byteValue(String key, byte value) { + valueOutput.putByte(key, value); + return this; + } + + /** + * Byte value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter byteValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putByte(key, v)); + return this; + } + + /** + * Short value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter shortValue(String key, short value) { + valueOutput.putShort(key, value); + return this; + } + + /** + * Short value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter shortValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putShort(key, v)); + return this; + } + + /** + * Int value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter intValue(String key, int value) { + valueOutput.putInt(key, value); + return this; + } + + /** + * Int value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter intValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putInt(key, v)); + return this; + } + + /** + * Long value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter longValue(String key, long value) { + valueOutput.putLong(key, value); + return this; + } + + /** + * Long value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter longValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putLong(key, v)); + return this; + } + + /** + * Float value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter floatValue(String key, float value) { + valueOutput.putFloat(key, value); + return this; + } + + /** + * Float value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter floatValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putFloat(key, v)); + return this; + } + + /** + * Double value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter doubleValue(String key, double value) { + valueOutput.putDouble(key, value); + return this; + } + + /** + * Double value value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter doubleValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putDouble(key, v)); + return this; + } + + /** + * Int array value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter intArray(String key, int[] value) { + if (value != null && value.length > 0) { + valueOutput.putIntArray(key, value); + } + return this; + } + + /** + * Int array value output writer. + * + * @param key the key + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter intArray(String key, Optional value) { + value.ifPresent(v -> { + if (v.length > 0) { + valueOutput.putIntArray(key, v); + } + }); + return this; + } + + /** + * Codec value value output writer. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter codecValue(String key, Codec codec, T value) { + if (value != null) { + valueOutput.store(key, codec, value); + } + return this; + } + + /** + * Codec value value output writer. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter codecValue(String key, Codec codec, Optional value) { + value.ifPresent(v -> valueOutput.store(key, codec, v)); + return this; + } + + /** + * Codec nullable value value output writer. + * + * @param the type parameter + * @param key the key + * @param codec the codec + * @param value the value + * @return the value output writer + */ + public ValueOutputWriter codecNullable(String key, Codec codec, @Nullable T value) { + valueOutput.storeNullable(key, codec, value); + return this; + } + + /** + * Vec 3 value output writer. + * + * @param key the key + * @param vec the vec + * @return the value output writer + */ + public ValueOutputWriter vec3(String key, Vec3 vec) { + if (vec != null) { + ValueOutput child = valueOutput.child(key); + writeVec3(child, vec); + } + return this; + } + + /** + * Vec 3 value output writer. + * + * @param key the key + * @param vec the vec + * @return the value output writer + */ + public ValueOutputWriter vec3(String key, Optional vec) { + vec.ifPresent(v -> vec3(key, v)); + return this; + } + + /** + * Enum value value output writer. + * + * @param the type parameter + * @param key the key + * @param value the value + * @return the value output writer + */ + public > ValueOutputWriter enumValue(String key, T value) { + if (value != null) { + valueOutput.putString(key, value.name().toLowerCase()); + } + return this; + } + + /** + * Enum value value output writer. + * + * @param the type parameter + * @param key the key + * @param value the value + * @return the value output writer + */ + public > ValueOutputWriter enumValue(String key, Optional value) { + value.ifPresent(v -> valueOutput.putString(key, v.name().toLowerCase())); + return this; + } + + /** + * Nested value output writer. + * + * @param key the key + * @param consumer the consumer + * @return the value output writer + */ + public ValueOutputWriter nested(String key, Consumer consumer) { + ValueOutput child = valueOutput.child(key); + consumer.accept(new ValueOutputWriter(child)); + return this; + } + + /** + * Nested if present value output writer. + * + * @param key the key + * @param supplier the supplier + * @param consumer the consumer + * @return the value output writer + */ + public ValueOutputWriter nestedIfPresent(String key, Supplier supplier, Consumer consumer) { + if (supplier.get()) { + ValueOutput child = valueOutput.child(key); + consumer.accept(new ValueOutputWriter(child)); + } + return this; + } + + /** + * List value output writer. + * + * @param the type parameter + * @param key the key + * @param elementCodec the element codec + * @param elements the elements + * @param consumer the consumer + * @return the value output writer + */ + public ValueOutputWriter list(String key, Codec elementCodec, Iterable elements, Consumer> consumer) { + ValueOutput.TypedOutputList list = valueOutput.list(key, elementCodec); + if (!list.isEmpty()) { + TypedListWriter writer = new TypedListWriter<>(list); + consumer.accept(writer); + } + return this; + } + + /** + * List value output writer. + * + * @param the type parameter + * @param key the key + * @param elementCodec the element codec + * @param elements the elements + * @return the value output writer + */ + public ValueOutputWriter list(String key, Codec elementCodec, Iterable elements) { + ValueOutput.TypedOutputList list = valueOutput.list(key, elementCodec); + for (T element : elements) { + if (element != null) { + list.add(element); + } + } + return this; + } + + /** + * Children list value output writer. + * + * @param key the key + * @param consumer the consumer + * @return the value output writer + */ + public ValueOutputWriter childrenList(String key, Consumer consumer) { + ValueOutput.ValueOutputList list = valueOutput.childrenList(key); + if (!list.isEmpty()) { + ChildrenListWriter writer = new ChildrenListWriter(list); + consumer.accept(writer); + } + return this; + } + + /** + * If present value output writer. + * + * @param condition the condition + * @param action the action + * @return the value output writer + */ + public ValueOutputWriter ifPresent(boolean condition, Consumer action) { + if (condition) { + action.accept(this); + } + return this; + } + + /** + * If present value output writer. + * + * @param condition the condition + * @param action the action + * @return the value output writer + */ + public ValueOutputWriter ifPresent(Supplier condition, Consumer action) { + if (condition.get()) { + action.accept(this); + } + return this; + } + + /** + * Discard value output writer. + * + * @param key the key + * @return the value output writer + */ + public ValueOutputWriter discard(String key) { + valueOutput.discard(key); + return this; + } + + /** + * Gets raw. + * + * @return the raw + */ + @NotNull + public net.minecraft.world.level.storage.ValueOutput getRaw() { + return valueOutput; + } + + /** + * Write vec 3. + * + * @param valueOutput the value output + * @param vec the vec + */ + public static void writeVec3(@NotNull net.minecraft.world.level.storage.ValueOutput valueOutput, @NotNull Vec3 vec) { + valueOutput.putDouble("X", vec.x); + valueOutput.putDouble("Y", vec.y); + valueOutput.putDouble("Z", vec.z); + } + + /** + * Write vec 3 safe. + * + * @param valueOutput the value output + * @param vec the vec + */ + public static void writeVec3Safe(@NotNull net.minecraft.world.level.storage.ValueOutput valueOutput, @Nullable Vec3 vec) { + if (vec != null) { + writeVec3(valueOutput, vec); + } + } + + /** + * The type Typed list writer. + * + * @param the type parameter + */ + public static class TypedListWriter { + private final ValueOutput.TypedOutputList list; + + private TypedListWriter(ValueOutput.TypedOutputList list) { + this.list = list; + } + + /** + * Add typed list writer. + * + * @param element the element + * @return the typed list writer + */ + public TypedListWriter add(T element) { + if (element != null) { + list.add(element); + } + return this; + } + + /** + * Add all typed list writer. + * + * @param elements the elements + * @return the typed list writer + */ + public TypedListWriter addAll(Iterable elements) { + for (T element : elements) { + if (element != null) { + list.add(element); + } + } + return this; + } + + /** + * Is empty boolean. + * + * @return the boolean + */ + public boolean isEmpty() { + return list.isEmpty(); + } + } + + /** + * The type Children list writer. + */ + public static class ChildrenListWriter { + private final ValueOutput.ValueOutputList list; + + private ChildrenListWriter(ValueOutput.ValueOutputList list) { + this.list = list; + } + + /** + * Add child value output writer. + * + * @param consumer the consumer + * @return the children list writer + */ + public ChildrenListWriter addChild(Consumer consumer) { + ValueOutput child = list.addChild(); + consumer.accept(new ValueOutputWriter(child)); + return this; + } + + /** + * Discard last children list writer. + * + * @return the children list writer + */ + public ChildrenListWriter discardLast() { + list.discardLast(); + return this; + } + + /** + * Is empty boolean. + * + * @return the boolean + */ + public boolean isEmpty() { + return list.isEmpty(); + } + } +} diff --git a/src/main/templates/META-INF/accesstransformer.cfg b/src/main/templates/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..d83d96a --- /dev/null +++ b/src/main/templates/META-INF/accesstransformer.cfg @@ -0,0 +1,3 @@ +# private -> public +public net.minecraft.server.level.ServerPlayer server +public net.minecraft.nbt.CompoundTag tags \ No newline at end of file diff --git a/src/main/templates/META-INF/mods.toml b/src/main/templates/META-INF/neoforge.mods.toml similarity index 82% rename from src/main/templates/META-INF/mods.toml rename to src/main/templates/META-INF/neoforge.mods.toml index 07e87be..a06dfcd 100644 --- a/src/main/templates/META-INF/mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -1,14 +1,3 @@ -# This is an example mods.toml file. It contains the data relating to the loading mods. -# There are several mandatory fields (#mandatory), and many more that are optional (#optional). -# The overall format is standard TOML format, v0.5.0. -# Note that there are a couple of TOML lists in this file. -# Find more information on toml format here: https://github.com/toml-lang/toml -# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml -modLoader="javafml" #mandatory - -# A version range to match for said mod loader - for regular FML @Mod it will be the Forge version -loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See download page for lists of versions. - # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. license="${mod_license}" @@ -57,14 +46,18 @@ authors="${mod_authors}" #optional # The description text for the mod (multi line!) (#mandatory) description='''${mod_description}''' + +[[accessTransformers]] +file="META-INF/accesstransformer.cfg" + # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.${mod_id}]] #optional # the modid of the dependency - modId="forge" #mandatory + modId="neoforge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified - mandatory=true #mandatory + type="required" # The version range of the dependency - versionRange="${forge_version_range}" #mandatory + versionRange="[${neo_version},)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory # BEFORE - This mod is loaded BEFORE the dependency # AFTER - This mod is loaded AFTER the dependency @@ -75,7 +68,7 @@ description='''${mod_description}''' # Here's another dependency [[dependencies.${mod_id}]] modId="minecraft" - mandatory=true + type="required" # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange="${minecraft_version_range}" ordering="NONE" diff --git a/src/main/templates/pack.mcmeta b/src/main/templates/pack.mcmeta deleted file mode 100644 index ae03c9b..0000000 --- a/src/main/templates/pack.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pack": { - "description": "${mod_name} resources", - "pack_format": 15 - } -}