将SyncDataManager修改为更通用的同步管理
This commit is contained in:
parent
4f7a030843
commit
cf1b6dba5b
307
build.gradle
307
build.gradle
|
|
@ -8,12 +8,11 @@ plugins {
|
|||
id 'net.neoforged.moddev.legacyforge' version '2.0.103'
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +24,11 @@ repositories {
|
|||
maven { url = "https://libraries.minecraft.net/" }
|
||||
maven { url = "https://neoforged.forgecdn.net/releases" }
|
||||
maven { url = "https://neoforged.forgecdn.net/mojang-meta" }
|
||||
maven { url = "https://maven.neoforged.net/releases" }
|
||||
maven {
|
||||
name = "LTD Maven"
|
||||
url = "https://nexus.bot.leisuretimedock.top/repository/maven-public/"
|
||||
}
|
||||
flatDir {
|
||||
dir "libs"
|
||||
}
|
||||
|
|
@ -46,16 +50,10 @@ legacyForge {
|
|||
minecraftVersion = project.parchment_minecraft_version
|
||||
}
|
||||
|
||||
// This line is optional. Access Transformers are automatically detected
|
||||
// accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
// Default run configurations.
|
||||
// These can be tweaked, removed, or duplicated as needed.
|
||||
runs {
|
||||
client {
|
||||
client()
|
||||
|
||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
||||
}
|
||||
clientAuth{
|
||||
|
|
@ -70,9 +68,6 @@ legacyForge {
|
|||
systemProperty 'forge.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
|
||||
|
|
@ -80,35 +75,16 @@ legacyForge {
|
|||
|
||||
data {
|
||||
data()
|
||||
|
||||
// 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
|
||||
// mostly optional in a single mod project
|
||||
// but multi mod projects should define one per mod
|
||||
"${mod_id}" {
|
||||
sourceSet(sourceSets.main)
|
||||
}
|
||||
|
|
@ -118,10 +94,6 @@ legacyForge {
|
|||
// Include resources generated by data generators.
|
||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
||||
// Sets up a dependency configuration called 'localRuntime' and a deobfuscating one called 'modLocalRuntime'
|
||||
// These configurations 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
|
||||
}
|
||||
|
|
@ -130,52 +102,11 @@ obfuscation {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
// If you wish to declare dependencies against mods, make sure to use the 'mod*' configurations so that they're remapped.
|
||||
// See https://github.com/neoforged/ModDevGradle/blob/main/LEGACY.md#remapping-mod-dependencies for more information.
|
||||
|
||||
// Example optional mod dependency with JEI
|
||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||
// modCompileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
|
||||
// modCompileOnly "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
|
||||
// modLocalRuntime "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"
|
||||
// modImplementation "blank:coolmod-${mc_version}:${coolmod_version}"
|
||||
|
||||
// Example mod dependency using a file as dependency
|
||||
// modImplementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar")
|
||||
|
||||
// Example project dependency using a sister or child project:
|
||||
// modImplementation 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
|
||||
}
|
||||
|
||||
// Uncomment the lines below if you wish to configure mixin. The mixin file should be named modid.mixins.json.
|
||||
/*
|
||||
mixin {
|
||||
add sourceSets.main, "${mod_id}.refmap.json"
|
||||
config "${mod_id}.mixins.json"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes([
|
||||
"MixinConfigs": "${mod_id}.mixins.json"
|
||||
])
|
||||
}
|
||||
*/
|
||||
|
||||
// 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,
|
||||
|
|
@ -191,39 +122,239 @@ var generateModMetadata = tasks.register("generateModMetadata", ProcessResources
|
|||
mod_description : mod_description,
|
||||
mod_credits : mod_credits
|
||||
]
|
||||
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
|
||||
// To avoid having to run "generateModMetadata" manually, make it run on every project reload
|
||||
legacyForge.ideSyncTask generateModMetadata
|
||||
|
||||
// Example configuration to allow publishing using the maven-publish plugin
|
||||
// ==================== 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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ==================== 发布配置 ====================
|
||||
publishing {
|
||||
publications {
|
||||
register('mavenJava', MavenPublication) {
|
||||
from components.java
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
// 本地仓库
|
||||
maven {
|
||||
url "file://${project.projectDir}/repo"
|
||||
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') ?: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 任务配置 ====================
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation']
|
||||
}
|
||||
|
||||
// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
|
||||
// 配置 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ mod_name=3944Realms 's Lib Mod
|
|||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||
mod_license=MIT
|
||||
# The mod version. See https://semver.org/
|
||||
mod_version=0.0.14
|
||||
mod_version=0.0.16
|
||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
|
|
|
|||
|
|
@ -6,20 +6,44 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import top.r3944realms.lib39.core.network.NetworkHandler;
|
||||
|
||||
/**
|
||||
* The type Lib 39.
|
||||
*/
|
||||
@Mod(Lib39.MOD_ID)
|
||||
public class Lib39 {
|
||||
/**
|
||||
* The constant MOD_ID.
|
||||
*/
|
||||
public static final String MOD_ID = "lib39";
|
||||
/**
|
||||
* The constant LOGGER.
|
||||
*/
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(Lib39.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new Lib 39.
|
||||
*/
|
||||
public Lib39() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
public static void initialize() {
|
||||
LOGGER.info("[Lib39] Initializing Lib39");
|
||||
NetworkHandler.register();
|
||||
LOGGER.info("[Lib39] Initialized Lib39");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Mod info.
|
||||
*/
|
||||
public static class ModInfo {
|
||||
/**
|
||||
* The constant VERSION.
|
||||
*/
|
||||
public static final String VERSION;
|
||||
static {
|
||||
// 从 ModList 获取当前 ModContainer 的元数据
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package top.r3944realms.lib39.api.event;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import top.r3944realms.lib39.core.compat.CompatManager;
|
||||
import top.r3944realms.lib39.core.compat.ICompat;
|
||||
|
||||
/**
|
||||
* The type Register compat event.
|
||||
*/
|
||||
public class RegisterCompatEvent extends Event implements IModBusEvent {
|
||||
/**
|
||||
* The Compat manager.
|
||||
*/
|
||||
protected final CompatManager compatManager;
|
||||
|
||||
/**
|
||||
* Instantiates a new Register compat event.
|
||||
*
|
||||
* @param compatManager the compat manager
|
||||
*/
|
||||
public RegisterCompatEvent(CompatManager compatManager) {
|
||||
this.compatManager = compatManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets compat manager.
|
||||
*
|
||||
* @return the compat manager
|
||||
*/
|
||||
public CompatManager getCompatManager() {
|
||||
return compatManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register compat.
|
||||
*
|
||||
* @param id the id
|
||||
* @param compat the compat
|
||||
*/
|
||||
// 注册兼容模块
|
||||
public void registerCompat(ResourceLocation id, ICompat compat) {
|
||||
compatManager.registerCompat(id, compat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register compat.
|
||||
*
|
||||
* @param namespace the namespace
|
||||
* @param path the path
|
||||
* @param compat the compat
|
||||
*/
|
||||
// 注册兼容模块(简化版本)
|
||||
public void registerCompat(String namespace, String path, ICompat compat) {
|
||||
compatManager.registerCompat(namespace, path, compat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister compat.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
// 取消注册兼容模块
|
||||
public void unregisterCompat(ResourceLocation id) {
|
||||
compatManager.unregisterCompat(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,43 +1,93 @@
|
|||
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 top.r3944realms.lib39.core.sync.ISyncData;
|
||||
import top.r3944realms.lib39.core.sync.ISyncManager;
|
||||
import top.r3944realms.lib39.core.sync.SyncData2Manager;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The type Sync manager register event.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SyncManagerRegisterEvent extends Event {
|
||||
/**
|
||||
* The Syncs 2 manager.
|
||||
*/
|
||||
protected final SyncData2Manager syncs2Manager;
|
||||
|
||||
/**
|
||||
* Instantiates a new Sync manager register event.
|
||||
*
|
||||
* @param syncsManager the syncs manager
|
||||
*/
|
||||
public SyncManagerRegisterEvent(SyncData2Manager syncsManager) {
|
||||
this.syncs2Manager = syncsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets syncs manager.
|
||||
*
|
||||
* @return the syncs manager
|
||||
*/
|
||||
public SyncData2Manager getSyncsManager() {
|
||||
return syncs2Manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全的同步管理器注册
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param id the id
|
||||
* @param syncManager the sync manager
|
||||
* @param capability the capability
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerSyncManager(
|
||||
ResourceLocation id,
|
||||
ISyncManager<K, T> syncManager,
|
||||
Capability<T> capability
|
||||
) {
|
||||
syncs2Manager.registerManager(id, syncManager, capability);
|
||||
syncs2Manager.registerManager(id, syncManager, entity -> entity.getCapability(capability).resolve());
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全的同步管理器注册
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param id the id
|
||||
* @param syncManager the sync manager
|
||||
* @param dataProvider the dataProvider
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerSyncManager(
|
||||
ResourceLocation id,
|
||||
ISyncManager<K, T> syncManager,
|
||||
Function<Entity, Optional<T>> dataProvider
|
||||
) {
|
||||
syncs2Manager.registerManager(id, syncManager, dataProvider);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Unregister sync manager.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public void unregisterSyncManager(ResourceLocation id) {
|
||||
syncs2Manager.removeManager(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 允许实体类
|
||||
*
|
||||
* @param id the id
|
||||
* @param entityClasses the entity classes
|
||||
*/
|
||||
public final void addAllowEntityClass(ResourceLocation id, Class<?>... entityClasses) {
|
||||
syncs2Manager.allowEntityClass(id, entityClasses);
|
||||
|
|
@ -45,6 +95,9 @@ public class SyncManagerRegisterEvent extends Event {
|
|||
|
||||
/**
|
||||
* 移除允许的实体类
|
||||
*
|
||||
* @param id the id
|
||||
* @param entityClasses the entity classes
|
||||
*/
|
||||
public final void removeAllowEntityClass(ResourceLocation id, Class<?>... entityClasses) {
|
||||
syncs2Manager.disallowEntityClass(id, entityClasses);
|
||||
|
|
@ -52,21 +105,33 @@ public class SyncManagerRegisterEvent extends Event {
|
|||
|
||||
/**
|
||||
* 绑定能力(用于分离注册的情况)
|
||||
* @param id 必须先注册安全同步管理器,再绑定Cap,否则会抛出{@link IllegalStateException 未找到对应安全同步管理器}
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param id 必须先注册安全同步管理器,再绑定Cap,否则会抛出{@link IllegalStateException 未找到对应安全同步管理器}
|
||||
* @param capability the capability
|
||||
*/
|
||||
public <T extends ISyncData<?>> void bindCapability(ResourceLocation id, Capability<T> capability) {
|
||||
syncs2Manager.bindCapability(id, capability);
|
||||
syncs2Manager.bindDataGetter(id, entity -> entity.getCapability(capability).resolve());
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑能力
|
||||
* 解绑数据提供者
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public void unbindCapability(ResourceLocation id) {
|
||||
syncs2Manager.unbindCapability(id);
|
||||
public void unbindDataProvider(ResourceLocation id) {
|
||||
syncs2Manager.unbindDataProvider(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的类型安全注册
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param id the id
|
||||
* @param syncManager the sync manager
|
||||
* @param capability the capability
|
||||
* @param allowedEntityClasses the allowed entity classes
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerComplete(
|
||||
ResourceLocation id,
|
||||
|
|
@ -79,4 +144,26 @@ public class SyncManagerRegisterEvent extends Event {
|
|||
addAllowEntityClass(id, allowedEntityClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整的类型安全注册
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param id the id
|
||||
* @param syncManager the sync manager
|
||||
* @param dataProvider the capability
|
||||
* @param allowedEntityClasses the allowed entity classes
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerComplete(
|
||||
ResourceLocation id,
|
||||
ISyncManager<K, T> syncManager,
|
||||
Function<Entity, Optional<T>> dataProvider,
|
||||
Class<?>... allowedEntityClasses
|
||||
) {
|
||||
registerSyncManager(id, syncManager, dataProvider);
|
||||
if (allowedEntityClasses.length > 0) {
|
||||
addAllowEntityClass(id, allowedEntityClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The type Compat manager.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CompatManager {
|
||||
private final Map<ResourceLocation, ICompat> compats = new HashMap<>();
|
||||
private final IEventBus modEventBus, gameEventBus;
|
||||
|
||||
// 存储事件监听器配置
|
||||
private final List<ListenerConfig> listenerConfigs = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new Compat manager.
|
||||
*
|
||||
* @param modEventBus the mod event bus
|
||||
* @param gameEventBus the game event bus
|
||||
*/
|
||||
public CompatManager(IEventBus modEventBus, IEventBus gameEventBus) {
|
||||
this.modEventBus = modEventBus;
|
||||
this.gameEventBus = gameEventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register compat.
|
||||
*
|
||||
* @param id the id
|
||||
* @param compat the compat
|
||||
*/
|
||||
public void registerCompat(ResourceLocation id, ICompat compat) {
|
||||
if (compats.containsKey(id)) {
|
||||
Lib39.LOGGER.warn("Compat with id {} is already registered!", id);
|
||||
return;
|
||||
}
|
||||
compats.put(id, compat);
|
||||
Lib39.LOGGER.debug("Registered compat: {}", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register compat.
|
||||
*
|
||||
* @param namespace the namespace
|
||||
* @param path the path
|
||||
* @param compat the compat
|
||||
*/
|
||||
public void registerCompat(String namespace, String path, ICompat compat) {
|
||||
registerCompat(new ResourceLocation(namespace, path), compat);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为所有兼容模块配置事件监听器
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 为特定兼容模块配置事件监听器
|
||||
*
|
||||
* @param compatId the compat id
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 为已加载的兼容模块配置事件监听器
|
||||
*
|
||||
* @param dists the dists
|
||||
* @param bus the bus
|
||||
* @param consumer the consumer
|
||||
*/
|
||||
public void addListenerForLoaded(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus, Consumer<IEventBus> consumer) {
|
||||
listenerConfigs.add(new ListenerConfig(null, dists, bus) {
|
||||
@Override
|
||||
boolean shouldApply(@NotNull ICompat compat) {
|
||||
return super.shouldApply(compat);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===================== 初始化和管理 =====================
|
||||
|
||||
/**
|
||||
* 初始化所有兼容模块并应用事件监听器
|
||||
*/
|
||||
public void initializeAll() {
|
||||
Lib39.LOGGER.info("Initializing {} compatibility modules", compats.size());
|
||||
|
||||
// 1. 先初始化所有兼容模块
|
||||
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
|
||||
try {
|
||||
entry.getValue().initialize();
|
||||
Lib39.LOGGER.info("Initialized compat: {}", entry.getKey());
|
||||
} catch (Exception e) {
|
||||
Lib39.LOGGER.error("Failed to initialize compat: {}", entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 然后应用所有事件监听器
|
||||
applyAllEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用所有配置的事件监听器到对应的 ICompat 实例
|
||||
*/
|
||||
private void applyAllEventListeners() {
|
||||
Lib39.LOGGER.info("Applying {} event listener configurations", listenerConfigs.size());
|
||||
|
||||
for (ListenerConfig config : listenerConfigs) {
|
||||
if (config.compatId == null) {
|
||||
// 应用到所有兼容模块
|
||||
applyListenerToAllCompats(config);
|
||||
} else {
|
||||
// 应用到特定兼容模块
|
||||
applyListenerToCompat(config.compatId, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将监听器应用到所有兼容模块
|
||||
*/
|
||||
private void applyListenerToAllCompats(ListenerConfig config) {
|
||||
for (ICompat compat : compats.values()) {
|
||||
if (config.shouldApply(compat)) {
|
||||
applyListenerToCompat(compat, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将监听器应用到特定兼容模块
|
||||
*/
|
||||
private void applyListenerToCompat(ResourceLocation compatId, ListenerConfig config) {
|
||||
ICompat compat = compats.get(compatId);
|
||||
if (compat != null && config.shouldApply(compat)) {
|
||||
applyListenerToCompat(compat, config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将监听器应用到具体的 ICompat 实例
|
||||
*/
|
||||
private void applyListenerToCompat(ICompat compat, ListenerConfig config) {
|
||||
try {
|
||||
// 根据配置调用对应的 ICompat 方法
|
||||
if (config.dists != null) {
|
||||
switch (config.dists) {
|
||||
case CLIENT -> {
|
||||
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
|
||||
compat.addClientGameListener(gameEventBus);
|
||||
} else {
|
||||
compat.addClientModListener(modEventBus);
|
||||
}
|
||||
}
|
||||
case DEDICATED_SERVER -> {
|
||||
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
|
||||
compat.addServerGameListener(gameEventBus);
|
||||
} else {
|
||||
compat.addServerModListener(modEventBus);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 通用监听器
|
||||
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
|
||||
compat.addCommonGameListener(gameEventBus);
|
||||
} else {
|
||||
compat.addCommonModListener(modEventBus);
|
||||
}
|
||||
}
|
||||
|
||||
Lib39.LOGGER.debug("Applied {} listener to compat: {}",
|
||||
getListenerTypeName(config), compat.id());
|
||||
|
||||
} catch (Exception e) {
|
||||
Lib39.LOGGER.error("Failed to apply listener to compat: {}", compat.id(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监听器类型名称(用于日志)
|
||||
*/
|
||||
private @NotNull String getListenerTypeName(@NotNull ListenerConfig config) {
|
||||
if (config.dists != null) {
|
||||
return config.dists.name().toLowerCase() + " " +
|
||||
(config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
|
||||
} else {
|
||||
return "common " + (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 便捷方法 =====================
|
||||
|
||||
/**
|
||||
* Add listener for all.
|
||||
*
|
||||
* @param bus the bus
|
||||
*/
|
||||
public void addListenerForAll(Mod.EventBusSubscriber.Bus bus) {
|
||||
addListenerForAll(null, bus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for compat.
|
||||
*
|
||||
* @param compatId the compat id
|
||||
* @param bus the bus
|
||||
*/
|
||||
public void addListenerForCompat(ResourceLocation compatId, Mod.EventBusSubscriber.Bus bus) {
|
||||
addListenerForCompat(compatId, null, bus);
|
||||
}
|
||||
|
||||
private static class ListenerConfig {
|
||||
/**
|
||||
* The Compat id.
|
||||
*/
|
||||
final ResourceLocation compatId;
|
||||
/**
|
||||
* The Dists.
|
||||
*/
|
||||
final Dist dists;
|
||||
/**
|
||||
* The Bus.
|
||||
*/
|
||||
final Mod.EventBusSubscriber.Bus bus;
|
||||
|
||||
/**
|
||||
* Instantiates a new Listener config.
|
||||
*
|
||||
* @param compatId the compat id
|
||||
* @param dists the dists
|
||||
* @param bus the bus
|
||||
*/
|
||||
ListenerConfig(ResourceLocation compatId, Dist dists, Mod.EventBusSubscriber.Bus bus) {
|
||||
this.compatId = compatId;
|
||||
this.dists = dists;
|
||||
this.bus = bus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should apply boolean.
|
||||
*
|
||||
* @param compat the compat
|
||||
* @return the boolean
|
||||
*/
|
||||
boolean shouldApply(@NotNull ICompat compat) {
|
||||
return compat.isModLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 其他方法 =====================
|
||||
|
||||
/**
|
||||
* On load complete.
|
||||
*/
|
||||
public void onLoadComplete() {
|
||||
Lib39.LOGGER.info("Calling onLoadComplete for {} compatibility modules", compats.size());
|
||||
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
|
||||
try {
|
||||
entry.getValue().onLoadComplete();
|
||||
} catch (Exception e) {
|
||||
Lib39.LOGGER.error("Error in onLoadComplete for compat: {}", entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets compat.
|
||||
*
|
||||
* @param id the id
|
||||
* @return the compat
|
||||
*/
|
||||
public Optional<ICompat> getCompat(ResourceLocation id) {
|
||||
return Optional.ofNullable(compats.get(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Has compat boolean.
|
||||
*
|
||||
* @param id the id
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean hasCompat(ResourceLocation id) {
|
||||
return compats.containsKey(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister compat.
|
||||
*
|
||||
* @param id the id
|
||||
*/
|
||||
public void unregisterCompat(ResourceLocation id) {
|
||||
ICompat removed = compats.remove(id);
|
||||
if (removed != null) {
|
||||
Lib39.LOGGER.debug("Unregistered compat: {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets loaded compats.
|
||||
*
|
||||
* @return the loaded compats
|
||||
*/
|
||||
public List<ICompat> getLoadedCompats() {
|
||||
return compats.values().stream()
|
||||
.filter(ICompat::isModLoaded)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
132
src/main/java/top/r3944realms/lib39/core/compat/ICompat.java
Normal file
132
src/main/java/top/r3944realms/lib39/core/compat/ICompat.java
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package top.r3944realms.lib39.core.compat;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The interface Compat.
|
||||
*/
|
||||
public interface ICompat {
|
||||
|
||||
/**
|
||||
* Id resource location.
|
||||
*
|
||||
* @return the resource location
|
||||
*/
|
||||
ResourceLocation id();
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* On load complete.
|
||||
*/
|
||||
default void onLoadComplete() {}
|
||||
|
||||
/**
|
||||
* Is mod loaded boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
default boolean isModLoaded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call if present t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param callable the callable
|
||||
* @return the t
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
default <T> T callIfPresent(Callable<T> callable) throws Exception {
|
||||
if (isModLoaded()) return callable.call();
|
||||
else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call if pesent t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param callable the callable
|
||||
* @param elseCall the else call
|
||||
* @return the t
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
default <T> T callIfPresent(Callable<T> callable, Callable<T> elseCall) throws Exception {
|
||||
if (isModLoaded()) return callable.call();
|
||||
else return elseCall.call();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run if present boolean.
|
||||
*
|
||||
* @param runnable the runnable
|
||||
* @return the boolean
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
default boolean runIfPresent(Runnable runnable) throws Exception {
|
||||
if (isModLoaded()) runnable.run(); else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add common game listener.
|
||||
*
|
||||
* @param gameBus the game bus
|
||||
*/
|
||||
default void addCommonGameListener(IEventBus gameBus) {
|
||||
// 实现通用游戏事件监听器添加逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* Add common mod listener.
|
||||
*
|
||||
* @param modBus the mod bus
|
||||
*/
|
||||
default void addCommonModListener(IEventBus modBus) {
|
||||
// 实现通用模组事件监听器添加逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* Add client game listener.
|
||||
*
|
||||
* @param gameBus the game bus
|
||||
*/
|
||||
default void addClientGameListener(IEventBus gameBus) {
|
||||
// 实现客户端游戏事件监听器添加逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* Add client mod listener.
|
||||
*
|
||||
* @param modBus the mod bus
|
||||
*/
|
||||
default void addClientModListener(IEventBus modBus) {
|
||||
// 实现客户端模组事件监听器添加逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* Add server game listener.
|
||||
*
|
||||
* @param gameBus the game bus
|
||||
*/
|
||||
default void addServerGameListener(IEventBus gameBus) {
|
||||
// 实现服务端游戏事件监听器添加逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* Add server mod listener.
|
||||
*
|
||||
* @param modBus the mod bus
|
||||
*/
|
||||
default void addServerModListener(IEventBus modBus) {
|
||||
// 实现服务端模组事件监听器添加逻辑
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package top.r3944realms.lib39.core.event;
|
||||
|
||||
/**
|
||||
* The type Client handler.
|
||||
*/
|
||||
public class ClientEventHandler {
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package top.r3944realms.lib39.core.event;
|
||||
|
||||
public class ClientHandler {
|
||||
}
|
||||
|
|
@ -13,11 +13,16 @@ 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 top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.api.event.RegisterCompatEvent;
|
||||
import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent;
|
||||
import top.r3944realms.lib39.core.sync.ISyncData;
|
||||
import top.r3944realms.lib39.core.compat.CompatManager;
|
||||
import top.r3944realms.lib39.core.sync.SyncData2Manager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -25,44 +30,82 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class CommonHandler {
|
||||
/**
|
||||
* The type Common handler.
|
||||
*/
|
||||
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)
|
||||
public static class Game extends CommonHandler {
|
||||
public static class Game extends CommonEventHandler {
|
||||
private static ServerLevel sl;
|
||||
|
||||
/**
|
||||
* Gets server level.
|
||||
*
|
||||
* @return the server level
|
||||
*/
|
||||
public static ServerLevel getServerLevel() {
|
||||
return sl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Sync data 2 manager.
|
||||
*/
|
||||
static volatile SyncData2Manager syncData2Manager;
|
||||
private static boolean isInitialized = false;
|
||||
private static boolean isSync2MInitialized = false;
|
||||
|
||||
/**
|
||||
* Gets sync data 2 manager.
|
||||
*
|
||||
* @return the sync data 2 manager
|
||||
*/
|
||||
public static SyncData2Manager getSyncData2Manager() {
|
||||
return syncData2Manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* On world load.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onWorldLoad(LevelEvent.Load event) {
|
||||
if (event.getLevel().isClientSide() || !(event.getLevel() instanceof ServerLevel serverLevel)) return;
|
||||
// 只处理主世界(避免多次初始化)
|
||||
if (!serverLevel.dimension().equals(Level.OVERWORLD)) return;
|
||||
synchronized (Game.class) {
|
||||
if (!isInitialized) {
|
||||
if (!isSync2MInitialized) {
|
||||
syncData2Manager = new SyncData2Manager();
|
||||
MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
|
||||
isInitialized = true;
|
||||
isSync2MInitialized = true;
|
||||
sl = serverLevel;
|
||||
Lib39.LOGGER.info("SyncData2Manager initialized on world load");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On world unload.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onWorldUnload(LevelEvent.Unload event) {
|
||||
if (event.getLevel().isClientSide() || !(event.getLevel() instanceof ServerLevel serverLevel)) return;
|
||||
if (!serverLevel.dimension().equals(Level.OVERWORLD)) return;
|
||||
|
||||
sl = null;
|
||||
isInitialized = false;
|
||||
isSync2MInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* On server tick.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.END) {
|
||||
|
|
@ -72,6 +115,12 @@ public class CommonHandler {
|
|||
syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::checkIfDirtyThenUpdate)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On entity join world.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onEntityJoinWorld(EntityJoinLevelEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
|
@ -83,6 +132,12 @@ public class CommonHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On entity leave world.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onEntityLeaveWorld(EntityLeaveLevelEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
|
@ -95,12 +150,51 @@ public class CommonHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Mod.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD)
|
||||
public static class Mod extends CommonHandler {
|
||||
public static class Mod extends CommonEventHandler {
|
||||
private static final Map<RegistryObject<Block>, ResourceKey<CreativeModeTab>[]> itemAddMap = new ConcurrentHashMap<>();
|
||||
private static final Map<ResourceKey<CreativeModeTab>, List<RegistryObject<Block>>> tabToItemsMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Gets compat manager.
|
||||
*
|
||||
* @return the compat manager
|
||||
*/
|
||||
public static CompatManager getCompatManager() {
|
||||
return compatManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Compat manager.
|
||||
*/
|
||||
static volatile CompatManager compatManager;
|
||||
|
||||
/**
|
||||
* On fml common setup.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onFMLCommonSetup (FMLCommonSetupEvent event) {
|
||||
event.enqueueWork(() -> {
|
||||
IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
IEventBus gameBus = MinecraftForge.EVENT_BUS;
|
||||
compatManager = new CompatManager(modBus, gameBus);
|
||||
MinecraftForge.EVENT_BUS.post(new RegisterCompatEvent(compatManager));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to tabs.
|
||||
*
|
||||
* @param item the item
|
||||
* @param tabs the tabs
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static void addItemToTabs(RegistryObject<Block> item, ResourceKey<CreativeModeTab>... tabs) {
|
||||
itemAddMap.put(item, tabs);
|
||||
|
|
@ -111,6 +205,11 @@ public class CommonHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On build creative tab contents.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onBuildCreativeTabContents(BuildCreativeModeTabContentsEvent event) {
|
||||
List<RegistryObject<Block>> itemsForTab = tabToItemsMap.get(event.getTabKey());
|
||||
|
|
@ -119,6 +218,11 @@ public class CommonHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets item add map.
|
||||
*
|
||||
* @return the item add map
|
||||
*/
|
||||
public static Map<RegistryObject<Block>, ResourceKey<CreativeModeTab>[]> getItemAddMap() {
|
||||
return itemAddMap;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package top.r3944realms.lib39.core.event;
|
||||
|
||||
/**
|
||||
* The type Server handler.
|
||||
*/
|
||||
public class ServerEventHandler {
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package top.r3944realms.lib39.core.event;
|
||||
|
||||
public class ServerHandler {
|
||||
}
|
||||
|
|
@ -8,28 +8,66 @@ import net.minecraftforge.network.PacketDistributor;
|
|||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.core.network.toClient.SyncNBTDataS2CPack;
|
||||
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(SyncNBTDataS2CPack.class, cid++, NetworkDirection.PLAY_TO_CLIENT)
|
||||
.encoder(SyncNBTDataS2CPack::encode)
|
||||
.decoder(SyncNBTDataS2CPack::decode)
|
||||
.consumerNetworkThread(SyncNBTDataS2CPack::handle)
|
||||
INSTANCE.messageBuilder(SyncNBTCapDataEntityS2CPack.class, cid++, NetworkDirection.PLAY_TO_CLIENT)
|
||||
.encoder(SyncNBTCapDataEntityS2CPack::encode)
|
||||
.decoder(SyncNBTCapDataEntityS2CPack::decode)
|
||||
.consumerNetworkThread(SyncNBTCapDataEntityS2CPack::handle)
|
||||
.add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to player.
|
||||
*
|
||||
* @param <MSG> the type parameter
|
||||
* @param message the message
|
||||
* @param player the player
|
||||
*/
|
||||
public static <MSG> void sendToPlayer(MSG message, ServerPlayer player){
|
||||
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to player.
|
||||
*
|
||||
* @param <MSG> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param message the message
|
||||
* @param entity the entity
|
||||
* @param packetDistributor the packet distributor
|
||||
*/
|
||||
public static <MSG, T> void sendToPlayer(MSG message, T entity, @NotNull PacketDistributor<T> packetDistributor){
|
||||
INSTANCE.send(packetDistributor.with(() -> entity), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to player.
|
||||
*
|
||||
* @param <MSG> the type parameter
|
||||
* @param message the message
|
||||
*/
|
||||
public static <MSG> void sendToAllPlayer(MSG message){
|
||||
INSTANCE.send(PacketDistributor.ALL.noArg(), message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
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.common.capabilities.Capability;
|
||||
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<NetworkEvent.Context> 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<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +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.common.capabilities.Capability;
|
||||
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.CommonHandler;
|
||||
import top.r3944realms.lib39.core.sync.ISyncData;
|
||||
import top.r3944realms.lib39.core.sync.NBTSyncData;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record SyncNBTDataS2CPack(int entityId, ResourceLocation id, CompoundTag data) {
|
||||
|
||||
public SyncNBTDataS2CPack(int entityId, ResourceLocation id, @NotNull NBTSyncData data) {
|
||||
this(entityId, data.id(), data.serializeNBT());
|
||||
}
|
||||
|
||||
public static void encode(@NotNull SyncNBTDataS2CPack msg, @NotNull FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(msg.entityId);
|
||||
buffer.writeResourceLocation(msg.id);
|
||||
buffer.writeNbt(msg.data);
|
||||
}
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static @NotNull SyncNBTDataS2CPack decode(@NotNull FriendlyByteBuf buffer) {
|
||||
return new SyncNBTDataS2CPack(buffer.readInt(), buffer.readResourceLocation(), buffer.readNbt());
|
||||
}
|
||||
|
||||
public static void handle(SyncNBTDataS2CPack msg, @NotNull Supplier<NetworkEvent.Context> 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<ISyncData<?>>> capability = CommonHandler.Game.getSyncData2Manager().getCapability(msg.id);
|
||||
capability.ifPresent(dataCapability -> entity.getCapability(dataCapability).ifPresent(cap -> {
|
||||
if (cap instanceof NBTSyncData 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,6 +8,9 @@ import top.r3944realms.lib39.datagen.value.McLocale;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The type Locale registry.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LocaleRegistry {
|
||||
private static final Map<String, ILocaleEntry> REGISTRY = new LinkedHashMap<>();
|
||||
|
|
@ -19,23 +22,43 @@ public class LocaleRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
/** 注册(覆盖已有时直接返回旧值) */
|
||||
/**
|
||||
* 注册(覆盖已有时直接返回旧值) @param entry the entry
|
||||
*
|
||||
* @param entry the entry
|
||||
* @return the locale entry
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static ILocaleEntry register(ILocaleEntry entry) {
|
||||
return REGISTRY.putIfAbsent(entry.mcCode().toLowerCase(), entry);
|
||||
}
|
||||
|
||||
/** 通过 Minecraft 代码查找 */
|
||||
/**
|
||||
* 通过 Minecraft 代码查找 @param code the code
|
||||
*
|
||||
* @param code the code
|
||||
* @return the locale entry
|
||||
*/
|
||||
public static ILocaleEntry fromMcCode(@NotNull String code) {
|
||||
return REGISTRY.get(code.toLowerCase());
|
||||
}
|
||||
|
||||
/** 列出所有 */
|
||||
/**
|
||||
* 列出所有 @return the collection
|
||||
*
|
||||
* @return the collection
|
||||
*/
|
||||
public static @NotNull @UnmodifiableView Collection<ILocaleEntry> allValues() {
|
||||
return Collections.unmodifiableCollection(REGISTRY.values());
|
||||
}
|
||||
|
||||
/** 动态注册一个扩展 Locale */
|
||||
/**
|
||||
* 动态注册一个扩展 Locale @param mcCode the mc code
|
||||
*
|
||||
* @param mcCode the mc code
|
||||
* @param locale the locale
|
||||
* @return the locale entry
|
||||
*/
|
||||
public static ILocaleEntry registerDynamic(@NotNull String mcCode, Locale locale) {
|
||||
return REGISTRY.computeIfAbsent(mcCode.toLowerCase(),
|
||||
k -> new ExtendedLocale(mcCode.toLowerCase(), locale));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ package top.r3944realms.lib39.core.sync;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The type Cached sync manager.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class CachedSyncManager<K, T extends ISyncData<?>> implements ISyncManager<K, T> {
|
||||
|
||||
|
|
|
|||
13
src/main/java/top/r3944realms/lib39/core/sync/IEntity.java
Normal file
13
src/main/java/top/r3944realms/lib39/core/sync/IEntity.java
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package top.r3944realms.lib39.core.sync;
|
||||
|
||||
/**
|
||||
* The interface Entity.
|
||||
*/
|
||||
public interface IEntity {
|
||||
/**
|
||||
* Entity id int.
|
||||
*
|
||||
* @return the int
|
||||
*/
|
||||
int entityId();
|
||||
}
|
||||
|
|
@ -2,13 +2,49 @@ package top.r3944realms.lib39.core.sync;
|
|||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* The interface Sync data.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
*/
|
||||
public interface ISyncData<T> {
|
||||
/**
|
||||
* Id resource location.
|
||||
*
|
||||
* @return the resource location
|
||||
*/
|
||||
ResourceLocation id();
|
||||
|
||||
/**
|
||||
* Is dirty boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
boolean isDirty();
|
||||
|
||||
/**
|
||||
* Sets dirty.
|
||||
*
|
||||
* @param dirty the dirty
|
||||
*/
|
||||
void setDirty(boolean dirty);
|
||||
|
||||
/**
|
||||
* Make dirty.
|
||||
*/
|
||||
default void makeDirty() {
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from.
|
||||
*
|
||||
* @param src the src
|
||||
*/
|
||||
void copyFrom(T src);
|
||||
|
||||
/**
|
||||
* Check if dirty then update.
|
||||
*/
|
||||
void checkIfDirtyThenUpdate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,26 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The interface Sync manager.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface ISyncManager<K, T extends ISyncData<?>> {
|
||||
|
||||
/**
|
||||
* 获取同步映射
|
||||
*
|
||||
* @return the sync map
|
||||
*/
|
||||
Map<K, T> getSyncMap();
|
||||
|
||||
/**
|
||||
* 获取同步集合
|
||||
*
|
||||
* @return the sync set
|
||||
*/
|
||||
default Set<T> getSyncSet() {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -22,6 +32,9 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 跟踪实例
|
||||
*
|
||||
* @param key the key
|
||||
* @param instance the instance
|
||||
*/
|
||||
default void track(K key, T instance) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -33,6 +46,9 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 取消跟踪
|
||||
*
|
||||
* @param key the key
|
||||
* @param instance the instance
|
||||
*/
|
||||
default void untrack(K key, T instance) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -45,6 +61,8 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 遍历操作
|
||||
*
|
||||
* @param consumer the consumer
|
||||
*/
|
||||
default void foreach(Consumer<T> consumer) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -56,6 +74,8 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param instances the instances
|
||||
*/
|
||||
default void trackAll(Map<K, T> instances) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -67,6 +87,8 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 获取大小
|
||||
*
|
||||
* @return the int
|
||||
*/
|
||||
default int size() {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -75,6 +97,9 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 检查是否包含key
|
||||
*
|
||||
* @param key the key
|
||||
* @return the boolean
|
||||
*/
|
||||
default boolean containsKey(K key) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
@ -83,6 +108,9 @@ public interface ISyncManager<K, T extends ISyncData<?>> {
|
|||
|
||||
/**
|
||||
* 检查是否包含value
|
||||
*
|
||||
* @param value the value
|
||||
* @return the boolean
|
||||
*/
|
||||
default boolean containsValue(T value) {
|
||||
Map<K, T> syncMap = getSyncMap();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
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<NBTEntitySyncData>, INBTSerializable<CompoundTag> {
|
||||
/**
|
||||
* 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +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;
|
||||
|
||||
public abstract class NBTSyncData implements ISyncData<NBTSyncData>, INBTSerializable<CompoundTag> {
|
||||
protected boolean dirty;
|
||||
protected final ResourceLocation id;
|
||||
|
||||
protected NBTSyncData(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 NBTSyncData src) {
|
||||
this.dirty = src.isDirty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,390 @@
|
|||
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<ResourceLocation, TypedSyncEntry<?, ?>> typedEntries = Maps.newConcurrentMap();
|
||||
|
||||
private static class TypedSyncEntry<K, T extends ISyncData<?>> {
|
||||
/**
|
||||
* The Manager.
|
||||
*/
|
||||
final ISyncManager<K, T> manager;
|
||||
/**
|
||||
* The Capability.
|
||||
*/
|
||||
@Nullable
|
||||
Capability<T> capability;
|
||||
/**
|
||||
* The Allowed classes.
|
||||
*/
|
||||
final Set<Class<?>> allowedClasses;
|
||||
|
||||
/**
|
||||
* Instantiates a new Typed sync entry.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param capability the capability
|
||||
*/
|
||||
TypedSyncEntry(ISyncManager<K, T> manager, @Nullable Capability<T> capability) {
|
||||
this.manager = manager;
|
||||
this.capability = capability;
|
||||
this.allowedClasses = Sets.newConcurrentHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register manager.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param manager the manager
|
||||
* @param capability the capability
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerManager(
|
||||
ResourceLocation key,
|
||||
ISyncManager<K, T> manager,
|
||||
Capability<T> 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<?, ? extends ISyncData<?>> 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<?, ISyncData<?>>) manager,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets manager.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @return the manager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K, T extends ISyncData<?>> Optional<ISyncManager<K, T>> getManager(ResourceLocation key) {
|
||||
TypedSyncEntry<?,?> entry = typedEntries.get(key);
|
||||
return entry != null ? Optional.of((ISyncManager<K,T>) entry.manager) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets capability.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @return the capability
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ISyncData<?>> Optional<Capability<T>> getCapability(ResourceLocation key) {
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry != null && entry.capability != null) {
|
||||
return Optional.of((Capability<T>) 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 <T> the type parameter
|
||||
* @param key the key
|
||||
* @param capability the capability
|
||||
*/
|
||||
public <T extends ISyncData<?>> void bindCapability(ResourceLocation key, Capability<T> 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<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
||||
if (entry != null) {
|
||||
trackEntityWithTypedEntry(entity, entry);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends ISyncData<?>> void trackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry<UUID, T> 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<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
||||
if (entry != null) {
|
||||
untrackEntityWithTypedEntry(entity, entry);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends ISyncData<?>> void untrackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry<UUID, T> 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<Entity> entities, ResourceLocation managerId) {
|
||||
for (Entity entity : entities) {
|
||||
untrackEntityForManager(entity, managerId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从所有管理器中批量移除实体跟踪
|
||||
*
|
||||
* @param entities the entities
|
||||
*/
|
||||
public void untrackEntitiesFromAllManagers(@NotNull Iterable<Entity> 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 <K, T extends ISyncData<?>> void clearTrackedDataForEntry(@NotNull TypedSyncEntry<K, T> entry) {
|
||||
// 获取当前跟踪的集合并清空
|
||||
Set<T> syncSet = entry.manager.getSyncSet();
|
||||
if (syncSet != null) {
|
||||
syncSet.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理所有管理器的跟踪数据
|
||||
*/
|
||||
public void clearAllTrackedData() {
|
||||
for (ResourceLocation id : getRegisteredKeys()) {
|
||||
clearAllTrackedData(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:更新条目的能力
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, T extends ISyncData<?>> void updateCapabilityInEntry(ResourceLocation id, TypedSyncEntry<?,?> entry, Capability<T> newCapability) {
|
||||
TypedSyncEntry<K, T> typedEntry = (TypedSyncEntry<K, T>) entry;
|
||||
//重构了 TypedSyncEntry 使 capability 可变
|
||||
typedEntry.capability = newCapability;
|
||||
typedEntries.computeIfPresent(id, (resourceLocation, typedSyncEntry) -> typedEntry);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets registered keys.
|
||||
*
|
||||
* @return the registered keys
|
||||
*/
|
||||
public Set<ResourceLocation> getRegisteredKeys() {
|
||||
return Collections.unmodifiableSet(typedEntries.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* For each.
|
||||
*
|
||||
* @param consumer the consumer
|
||||
*/
|
||||
public void forEach(BiConsumer<ResourceLocation, ISyncManager<?,?>> 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,73 +4,178 @@ 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;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
/**
|
||||
* The type Sync data 2 manager.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "DuplicatedCode"})
|
||||
public class SyncData2Manager {
|
||||
private final Map<ResourceLocation, TypedSyncEntry<?, ?>> typedEntries = Maps.newConcurrentMap();
|
||||
|
||||
/**
|
||||
* 数据提供者接口 - 用于通过键获取数据
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DataProvider<K, T> {
|
||||
/**
|
||||
* 通过键获取数据的 Optional
|
||||
*
|
||||
* @param key 键
|
||||
* @return 数据的 Optional
|
||||
*/
|
||||
Optional<T> getData(K key);
|
||||
}
|
||||
|
||||
private static class TypedSyncEntry<K, T extends ISyncData<?>> {
|
||||
/**
|
||||
* The Manager.
|
||||
*/
|
||||
final ISyncManager<K, T> manager;
|
||||
/**
|
||||
* The Data provider.
|
||||
*/
|
||||
@Nullable
|
||||
Capability<T> capability;
|
||||
final DataProvider<Entity, T> dataProvider;
|
||||
/**
|
||||
* The Allowed classes.
|
||||
*/
|
||||
final Set<Class<?>> allowedClasses;
|
||||
|
||||
TypedSyncEntry(ISyncManager<K, T> manager, @Nullable Capability<T> capability) {
|
||||
/**
|
||||
* Instantiates a new Typed sync entry.
|
||||
*
|
||||
* @param manager the manager
|
||||
* @param dataProvider the data provider
|
||||
*/
|
||||
TypedSyncEntry(ISyncManager<K, T> manager, @Nullable DataProvider<Entity, T> dataProvider) {
|
||||
this.manager = manager;
|
||||
this.capability = capability;
|
||||
this.dataProvider = dataProvider;
|
||||
this.allowedClasses = Sets.newConcurrentHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
public <K, T extends ISyncData<?>> void registerManager(
|
||||
/**
|
||||
* Register manager with data provider.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param manager the manager
|
||||
* @param dataProvider the data provider
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerManagerWithProvider(
|
||||
ResourceLocation key,
|
||||
ISyncManager<K, T> manager,
|
||||
Capability<T> capability
|
||||
DataProvider<Entity, T> dataProvider
|
||||
) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||
Objects.requireNonNull(capability, "Capability cannot be null");
|
||||
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
||||
|
||||
typedEntries.put(key, new TypedSyncEntry<>(manager, capability));
|
||||
typedEntries.put(key, new TypedSyncEntry<>(manager, dataProvider));
|
||||
}
|
||||
|
||||
/**
|
||||
* 向后兼容的注册方法(只注册管理器,不注册能力)
|
||||
* Register manager with function getter.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param manager the manager
|
||||
* @param getter the data getter function
|
||||
*/
|
||||
public <K, T extends ISyncData<?>> void registerManager(
|
||||
ResourceLocation key,
|
||||
ISyncManager<K, T> manager,
|
||||
Function<Entity, Optional<T>> getter
|
||||
) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||
Objects.requireNonNull(getter, "Data getter function cannot be null");
|
||||
|
||||
typedEntries.put(key, new TypedSyncEntry<>(manager, getter::apply));
|
||||
}
|
||||
|
||||
/**
|
||||
* 向后兼容的注册方法(只注册管理器,不注册数据提供者)
|
||||
*
|
||||
* @param key the key
|
||||
* @param manager the manager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void registerManager(ResourceLocation key, ISyncManager<?, ? extends ISyncData<?>> manager) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||
|
||||
// 创建一个虚拟的 TypedSyncEntry,但 capability 为 null
|
||||
// 注意:这种方法会限制类型安全的功能
|
||||
// 创建一个没有数据提供者的 TypedSyncEntry
|
||||
typedEntries.put(key, new TypedSyncEntry<>(
|
||||
(ISyncManager<?, ISyncData<?>>) manager,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets manager.
|
||||
*
|
||||
* @param <K> the type parameter
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @return the manager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K, T extends ISyncData<?>> Optional<ISyncManager<K, T>> getManager(ResourceLocation key) {
|
||||
TypedSyncEntry<?,?> entry = typedEntries.get(key);
|
||||
return entry != null ? Optional.of((ISyncManager<K,T>) entry.manager) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data provider.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @return the data provider
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ISyncData<?>> Optional<Capability<T>> getCapability(ResourceLocation key) {
|
||||
public <T extends ISyncData<?>> Optional<DataProvider<Entity, T>> getDataProvider(ResourceLocation key) {
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry != null && entry.capability != null) {
|
||||
return Optional.of((Capability<T>) entry.capability);
|
||||
if (entry != null && entry.dataProvider != null) {
|
||||
return Optional.of((DataProvider<Entity, T>) entry.dataProvider);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数据
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param entity the entity
|
||||
* @return the entity data
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ISyncData<?>> Optional<T> getEntityData(ResourceLocation key, Entity entity) {
|
||||
return getDataProvider(key)
|
||||
.flatMap(provider -> {
|
||||
Optional<ISyncData<?>> result = provider.getData(entity);
|
||||
return (Optional<T>) result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
|
@ -87,6 +192,9 @@ public class SyncData2Manager {
|
|||
|
||||
/**
|
||||
* 移除允许的实体类
|
||||
*
|
||||
* @param key the key
|
||||
* @param classes the classes
|
||||
*/
|
||||
public final void disallowEntityClass(ResourceLocation key, Class<?>... classes) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
|
|
@ -95,39 +203,59 @@ public class SyncData2Manager {
|
|||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry != null && classes.length > 0) {
|
||||
Arrays.asList(classes).forEach(entry.allowedClasses::remove);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定能力(用于分离注册的情况)
|
||||
* 绑定数据提供者(用于分离注册的情况)
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param dataProvider the data provider
|
||||
*/
|
||||
public <T extends ISyncData<?>> void bindCapability(ResourceLocation key, Capability<T> capability) {
|
||||
public <T extends ISyncData<?>> void bindDataProvider(ResourceLocation key, DataProvider<Entity, T> dataProvider) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(capability, "Capability cannot be null");
|
||||
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry != null) {
|
||||
// 更新现有条目的能力
|
||||
updateCapabilityInEntry(key, entry, capability);
|
||||
} else throw new IllegalArgumentException("No manager found for " + key);
|
||||
// 更新现有条目的数据提供者
|
||||
updateDataProviderInEntry(key, entry, dataProvider);
|
||||
} else {
|
||||
throw new IllegalArgumentException("No manager found for " + key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑能力
|
||||
* 绑定简单的数据获取器
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param getter the data getter function
|
||||
*/
|
||||
public void unbindCapability(ResourceLocation key) {
|
||||
public <T extends ISyncData<?>> void bindDataGetter(ResourceLocation key, Function<Entity, Optional<T>> getter) {
|
||||
bindDataProvider(key, getter::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑数据提供者
|
||||
*
|
||||
* @param key the key
|
||||
*/
|
||||
public void unbindDataProvider(ResourceLocation key) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry != null) {
|
||||
// 将能力设置为null,但保留管理器和其他配置
|
||||
updateCapabilityInEntry(key, entry, null);
|
||||
// 将数据提供者设置为null,但保留管理器和其他配置
|
||||
updateDataProviderInEntry(key, entry, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除允许的实体类
|
||||
*
|
||||
* @param key the key
|
||||
*/
|
||||
public void clearAllowedEntityClasses(ResourceLocation key) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
|
|
@ -138,24 +266,38 @@ public class SyncData2Manager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
if (entry == null) {
|
||||
return false;
|
||||
}
|
||||
return entry != null && isAllowed ;
|
||||
|
||||
// 如果没有设置允许的类,则默认允许所有类
|
||||
if (entry.allowedClasses.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查实体类是否在允许的类中
|
||||
return entry.allowedClasses.stream()
|
||||
.anyMatch(allowedClass -> allowedClass.isAssignableFrom(entityClass));
|
||||
}
|
||||
|
||||
// 类型安全的事件处理
|
||||
/**
|
||||
* Track entity for manager.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param managerId the manager id
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void trackEntityForManager(Entity entity, ResourceLocation managerId) {
|
||||
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
||||
|
|
@ -165,12 +307,18 @@ public class SyncData2Manager {
|
|||
}
|
||||
|
||||
private <T extends ISyncData<?>> void trackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry<UUID, T> entry) {
|
||||
if (entry.capability != null) {
|
||||
entity.getCapability(entry.capability)
|
||||
.ifPresent(cap -> entry.manager.track(entity.getUUID(), cap));
|
||||
if (entry.dataProvider != null) {
|
||||
entry.dataProvider.getData(entity)
|
||||
.ifPresent(data -> entry.manager.track(entity.getUUID(), data));
|
||||
}
|
||||
}
|
||||
// 类型安全的事件处理 - 取消跟踪实体
|
||||
|
||||
/**
|
||||
* Untrack entity for manager.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param managerId the manager id
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void untrackEntityForManager(Entity entity, ResourceLocation managerId) {
|
||||
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
||||
|
|
@ -180,14 +328,16 @@ public class SyncData2Manager {
|
|||
}
|
||||
|
||||
private <T extends ISyncData<?>> void untrackEntityWithTypedEntry(Entity entity, @NotNull TypedSyncEntry<UUID, T> entry) {
|
||||
if (entry.capability != null) {
|
||||
entity.getCapability(entry.capability)
|
||||
.ifPresent(cap -> entry.manager.untrack(entity.getUUID(), cap));
|
||||
if (entry.dataProvider != null) {
|
||||
entry.dataProvider.getData(entity)
|
||||
.ifPresent(data -> entry.manager.untrack(entity.getUUID(), data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从所有管理器中移除实体跟踪
|
||||
*
|
||||
* @param entity the entity
|
||||
*/
|
||||
public void untrackEntityFromAllManagers(Entity entity) {
|
||||
for (ResourceLocation id : getRegisteredKeys()) {
|
||||
|
|
@ -199,6 +349,9 @@ public class SyncData2Manager {
|
|||
|
||||
/**
|
||||
* 批量从管理器中移除实体跟踪
|
||||
*
|
||||
* @param entities the entities
|
||||
* @param managerId the manager id
|
||||
*/
|
||||
public void untrackEntitiesForManager(@NotNull Iterable<Entity> entities, ResourceLocation managerId) {
|
||||
for (Entity entity : entities) {
|
||||
|
|
@ -208,6 +361,8 @@ public class SyncData2Manager {
|
|||
|
||||
/**
|
||||
* 从所有管理器中批量移除实体跟踪
|
||||
*
|
||||
* @param entities the entities
|
||||
*/
|
||||
public void untrackEntitiesFromAllManagers(@NotNull Iterable<Entity> entities) {
|
||||
for (Entity entity : entities) {
|
||||
|
|
@ -217,6 +372,8 @@ public class SyncData2Manager {
|
|||
|
||||
/**
|
||||
* 强制清理管理器中的所有跟踪数据
|
||||
*
|
||||
* @param managerId the manager id
|
||||
*/
|
||||
public void clearAllTrackedData(ResourceLocation managerId) {
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(managerId);
|
||||
|
|
@ -226,7 +383,6 @@ public class SyncData2Manager {
|
|||
}
|
||||
|
||||
private <K, T extends ISyncData<?>> void clearTrackedDataForEntry(@NotNull TypedSyncEntry<K, T> entry) {
|
||||
// 获取当前跟踪的集合并清空
|
||||
Set<T> syncSet = entry.manager.getSyncSet();
|
||||
if (syncSet != null) {
|
||||
syncSet.clear();
|
||||
|
|
@ -242,36 +398,62 @@ public class SyncData2Manager {
|
|||
}
|
||||
}
|
||||
|
||||
// 辅助方法:更新条目的能力
|
||||
// 辅助方法:更新条目的数据提供者
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, T extends ISyncData<?>> void updateCapabilityInEntry(ResourceLocation id, TypedSyncEntry<?,?> entry, Capability<T> newCapability) {
|
||||
TypedSyncEntry<K, T> typedEntry = (TypedSyncEntry<K, T>) entry;
|
||||
//重构了 TypedSyncEntry 使 capability 可变
|
||||
typedEntry.capability = newCapability;
|
||||
typedEntries.computeIfPresent(id, (resourceLocation, typedSyncEntry) -> typedEntry);
|
||||
private <K, T extends ISyncData<?>> void updateDataProviderInEntry(
|
||||
ResourceLocation id,
|
||||
TypedSyncEntry<?,?> entry,
|
||||
DataProvider<Entity, T> newDataProvider
|
||||
) {
|
||||
// 由于 DataProvider 是 final,我们需要创建一个新的 TypedSyncEntry
|
||||
TypedSyncEntry<K, T> newEntry = new TypedSyncEntry<>(
|
||||
(ISyncManager<K, T>) entry.manager,
|
||||
newDataProvider
|
||||
);
|
||||
newEntry.allowedClasses.addAll(entry.allowedClasses);
|
||||
|
||||
typedEntries.put(id, newEntry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets registered keys.
|
||||
*
|
||||
* @return the registered keys
|
||||
*/
|
||||
public Set<ResourceLocation> getRegisteredKeys() {
|
||||
return Collections.unmodifiableSet(typedEntries.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* For each.
|
||||
*
|
||||
* @param consumer the consumer
|
||||
*/
|
||||
public void forEach(BiConsumer<ResourceLocation, ISyncManager<?,?>> 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");
|
||||
|
|
|
|||
|
|
@ -11,12 +11,24 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The type Simple language provider.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SimpleLanguageProvider extends LanguageProvider {
|
||||
private final McLocale language;
|
||||
private final ILangKeyValue langKeyValue;
|
||||
private final Map<String, String> lanKeyMap;
|
||||
private static final List<String> objects = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new Simple language provider.
|
||||
*
|
||||
* @param output the output
|
||||
* @param modId the mod id
|
||||
* @param Lan the lan
|
||||
* @param langKeyValue the lang key value
|
||||
*/
|
||||
public SimpleLanguageProvider(PackOutput output, String modId, @NotNull McLocale Lan, ILangKeyValue langKeyValue) {
|
||||
super(output, modId, Lan.mcCode());
|
||||
this.language = Lan;
|
||||
|
|
|
|||
|
|
@ -4,10 +4,33 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The interface Lang key value.
|
||||
*/
|
||||
public interface ILangKeyValue {
|
||||
/**
|
||||
* Gets lang.
|
||||
*
|
||||
* @param locale the locale
|
||||
* @param key the key
|
||||
* @return the lang
|
||||
*/
|
||||
static String getLang(McLocale locale, @NotNull ILangKeyValue key) {
|
||||
return key.getLang(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets lang.
|
||||
*
|
||||
* @param locale the locale
|
||||
* @return the lang
|
||||
*/
|
||||
String getLang(McLocale locale);
|
||||
|
||||
/**
|
||||
* Gets values.
|
||||
*
|
||||
* @return the values
|
||||
*/
|
||||
List<ILangKeyValue> getValues();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,21 @@ package top.r3944realms.lib39.datagen.value;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The interface Locale entry.
|
||||
*/
|
||||
public interface ILocaleEntry {
|
||||
/**
|
||||
* Mc code string.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
String mcCode();
|
||||
|
||||
/**
|
||||
* Java locale locale.
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale javaLocale();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,42 @@ import org.jetbrains.annotations.NotNull;
|
|||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* The type Lang key value.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LangKeyValue implements ILangKeyValue {
|
||||
/**
|
||||
* The Supplier.
|
||||
*/
|
||||
protected final Supplier<?> supplier;
|
||||
/**
|
||||
* The Key.
|
||||
*/
|
||||
protected String key;
|
||||
/**
|
||||
* The Us en.
|
||||
*/
|
||||
protected final String US_EN;
|
||||
/**
|
||||
* The Sim cn.
|
||||
*/
|
||||
protected final String SIM_CN;
|
||||
/**
|
||||
* The Tra cn.
|
||||
*/
|
||||
protected final String TRA_CN;
|
||||
/**
|
||||
* The Lzh.
|
||||
*/
|
||||
protected final String LZH;
|
||||
/**
|
||||
* The Default.
|
||||
*/
|
||||
protected final Boolean Default;
|
||||
/**
|
||||
* The Mpe.
|
||||
*/
|
||||
protected final ModPartEnum MPE;
|
||||
private LangKeyValue(Supplier<?> supplier, String key, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN, String LZH, Boolean isDefault) {
|
||||
|
|
@ -28,42 +55,111 @@ public class LangKeyValue implements ILangKeyValue {
|
|||
this.Default = isDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Of supplier lang key value.
|
||||
*
|
||||
* @param supplier the supplier
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofSupplier(Supplier<?> supplier, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN) {
|
||||
return new LangKeyValue(supplier, null, MPE, US_EN, SIM_CN, TRA_CN, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of supplier lang key value.
|
||||
*
|
||||
* @param supplier the supplier
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @param LZH the lzh
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofSupplier(Supplier<?> supplier, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN, String LZH) {
|
||||
return new LangKeyValue(supplier, null, MPE, US_EN, SIM_CN, TRA_CN, LZH, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of supplier lang key value.
|
||||
*
|
||||
* @param supplier the supplier
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @param isDefault the is default
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofSupplier(Supplier<?> supplier, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) {
|
||||
return new LangKeyValue(supplier, null, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of key lang key value.
|
||||
*
|
||||
* @param key the key
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofKey(String key, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN) {
|
||||
return new LangKeyValue(null, key, MPE, US_EN, SIM_CN, TRA_CN, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of key lang key value.
|
||||
*
|
||||
* @param key the key
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @param LZH the lzh
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofKey(String key, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN, String LZH) {
|
||||
return new LangKeyValue(null, key, MPE, US_EN, SIM_CN, TRA_CN, LZH, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of key lang key value.
|
||||
*
|
||||
* @param key the key
|
||||
* @param MPE the mpe
|
||||
* @param US_EN the us en
|
||||
* @param SIM_CN the sim cn
|
||||
* @param TRA_CN the tra cn
|
||||
* @param isDefault the is default
|
||||
* @return the lang key value
|
||||
*/
|
||||
@Contract(value = "_, _, _, _, _, _ -> new", pure = true)
|
||||
public static @NotNull LangKeyValue ofKey(String key, ModPartEnum MPE,
|
||||
String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) {
|
||||
return new LangKeyValue(null, key, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets key.
|
||||
*
|
||||
* @return the key
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,49 @@ package top.r3944realms.lib39.datagen.value;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The enum Mc locale.
|
||||
*/
|
||||
public enum McLocale implements ILocaleEntry {
|
||||
/**
|
||||
* En us mc locale.
|
||||
*/
|
||||
EN_US("en_us", Locale.US),
|
||||
/**
|
||||
* Zh cn mc locale.
|
||||
*/
|
||||
ZH_CN("zh_cn", Locale.SIMPLIFIED_CHINESE),
|
||||
/**
|
||||
* Zh tw mc locale.
|
||||
*/
|
||||
ZH_TW("zh_tw", Locale.TRADITIONAL_CHINESE),
|
||||
/**
|
||||
* The Lzh.
|
||||
*/
|
||||
LZH("lzh", new Locale("lzh", "ZH")),
|
||||
/**
|
||||
* Ja jp mc locale.
|
||||
*/
|
||||
JA_JP("ja_jp", Locale.JAPAN),
|
||||
/**
|
||||
* Ko kr mc locale.
|
||||
*/
|
||||
KO_KR("ko_kr", Locale.KOREA),
|
||||
/**
|
||||
* The Ru ru.
|
||||
*/
|
||||
RU_RU("ru_ru", new Locale("ru", "RU")),
|
||||
/**
|
||||
* Fr fr mc locale.
|
||||
*/
|
||||
FR_FR("fr_fr", Locale.FRANCE),
|
||||
/**
|
||||
* De de mc locale.
|
||||
*/
|
||||
DE_DE("de_de", Locale.GERMANY),
|
||||
/**
|
||||
* The Es es.
|
||||
*/
|
||||
ES_ES("es_es", new Locale("es", "ES"));
|
||||
|
||||
private final String mcCode;
|
||||
|
|
|
|||
|
|
@ -7,62 +7,101 @@ import org.jetbrains.annotations.NotNull;
|
|||
* 模组各部分的类型枚举,用于数据生成与分类。
|
||||
*/
|
||||
public enum ModPartEnum {
|
||||
/** 默认/未指定类型 */
|
||||
/**
|
||||
* 默认/未指定类型
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/** 物品 */
|
||||
/**
|
||||
* 物品
|
||||
*/
|
||||
ITEM,
|
||||
|
||||
/** 方块 */
|
||||
/**
|
||||
* 方块
|
||||
*/
|
||||
BLOCK,
|
||||
|
||||
/** 附魔 */
|
||||
/**
|
||||
* 附魔
|
||||
*/
|
||||
ENCHANTMENT,
|
||||
|
||||
/** 成就 / 进度 */
|
||||
/**
|
||||
* 成就 / 进度
|
||||
*/
|
||||
ADVANCEMENT,
|
||||
|
||||
/** 创造模式物品栏 */
|
||||
/**
|
||||
* 创造模式物品栏
|
||||
*/
|
||||
CREATIVE_TAB,
|
||||
|
||||
/** 配置项 */
|
||||
/**
|
||||
* 配置项
|
||||
*/
|
||||
CONFIG,
|
||||
|
||||
/** 实体(生物、载具等) */
|
||||
/**
|
||||
* 实体(生物、载具等)
|
||||
*/
|
||||
ENTITY,
|
||||
|
||||
/** 图形界面 */
|
||||
/**
|
||||
* 图形界面
|
||||
*/
|
||||
GUI,
|
||||
|
||||
/** 作者信息 */
|
||||
/**
|
||||
* 作者信息
|
||||
*/
|
||||
AUTHOR,
|
||||
|
||||
/** 标题 */
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
TITLE,
|
||||
|
||||
/** 名称 */
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
NAME,
|
||||
|
||||
/** 游戏规则(/gamerule) */
|
||||
/**
|
||||
* 游戏规则(/gamerule)
|
||||
*/
|
||||
GAME_RULE,
|
||||
|
||||
/** 描述文本 */
|
||||
/**
|
||||
* 描述文本
|
||||
*/
|
||||
DESCRIPTION,
|
||||
|
||||
/** 一般信息 */
|
||||
/**
|
||||
* 一般信息
|
||||
*/
|
||||
INFO,
|
||||
|
||||
/** 消息(聊天、提示等) */
|
||||
/**
|
||||
* 消息(聊天、提示等)
|
||||
*/
|
||||
MESSAGE,
|
||||
|
||||
/** 命令 */
|
||||
/**
|
||||
* 命令
|
||||
*/
|
||||
COMMAND,
|
||||
|
||||
/** 声音资源 */
|
||||
/**
|
||||
* 声音资源
|
||||
*/
|
||||
SOUND;
|
||||
|
||||
/**
|
||||
* 根据枚举类型生成标准化 key 前缀
|
||||
* 例如 ITEM -> "item.", BLOCK -> "block."
|
||||
*
|
||||
* @return the key prefix
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
public @NotNull String getKeyPrefix() {
|
||||
|
|
@ -91,6 +130,9 @@ public enum ModPartEnum {
|
|||
/**
|
||||
* 根据枚举类型和具体名称生成完整 key
|
||||
* 例如 ITEM + "example_item" -> "item.example_item"
|
||||
*
|
||||
* @param name the name
|
||||
* @return the full key
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
public @NotNull String getFullKey(String name) {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@ import net.minecraft.world.item.CreativeModeTabs;
|
|||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.r3944realms.lib39.core.event.CommonHandler;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.core.event.CommonEventHandler;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* The type Block registry builder.
|
||||
*/
|
||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||
public class BlockRegistryBuilder {
|
||||
private String registryName;
|
||||
|
|
@ -17,22 +22,33 @@ public class BlockRegistryBuilder {
|
|||
|
||||
/**
|
||||
* 创建新的构建器实例
|
||||
*
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public static BlockRegistryBuilder create() {
|
||||
@Contract(value = " -> new", pure = true)
|
||||
public static @NotNull BlockRegistryBuilder create() {
|
||||
return new BlockRegistryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置注册名称
|
||||
*
|
||||
* @param name the name
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder withName(String name) {
|
||||
this.registryName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册方块(不自动注册物品)
|
||||
*
|
||||
* @param blockRegister the block register
|
||||
* @param blockSupplier the block supplier
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerBlock(DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
||||
public BlockRegistryBuilder registerBlock(@NotNull DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
||||
this.blockObject = blockRegister.register(this.registryName, blockSupplier);
|
||||
return this;
|
||||
}
|
||||
|
|
@ -42,11 +58,15 @@ public class BlockRegistryBuilder {
|
|||
*/
|
||||
@SafeVarargs
|
||||
private void registerBlockItem(RegistryObject<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
|
||||
CommonHandler.Mod.addItemToTabs(blockObject, creativeTabs);
|
||||
CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册方块和物品到建筑标签页
|
||||
*
|
||||
* @param blockRegister the block register
|
||||
* @param blockSupplier the block supplier
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerWithBuildingTab(DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
||||
registerBlock(blockRegister, blockSupplier);
|
||||
|
|
@ -56,6 +76,10 @@ public class BlockRegistryBuilder {
|
|||
|
||||
/**
|
||||
* 注册方块和物品到功能标签页
|
||||
*
|
||||
* @param blockRegister the block register
|
||||
* @param blockSupplier the block supplier
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerWithFunctionalTab(DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
||||
registerBlock(blockRegister, blockSupplier);
|
||||
|
|
@ -65,6 +89,8 @@ public class BlockRegistryBuilder {
|
|||
|
||||
/**
|
||||
* 获取注册的方块对象
|
||||
*
|
||||
* @return the registry object
|
||||
*/
|
||||
public RegistryObject<Block> build() {
|
||||
return this.blockObject;
|
||||
|
|
|
|||
|
|
@ -12,11 +12,18 @@ import net.minecraft.commands.Commands;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* The type Command alias helper.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CommandAliasHelper {
|
||||
|
||||
/**
|
||||
* 注册命令及其别名
|
||||
*
|
||||
* @param dispatcher the dispatcher
|
||||
* @param mainCommand the main command
|
||||
* @param aliases the aliases
|
||||
*/
|
||||
public static void registerWithAliases(@NotNull CommandDispatcher<CommandSourceStack> dispatcher,
|
||||
LiteralArgumentBuilder<CommandSourceStack> mainCommand,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,20 @@ package top.r3944realms.lib39.util.lang;
|
|||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The type Pair.
|
||||
*
|
||||
* @param <F> the type parameter
|
||||
* @param <S> the type parameter
|
||||
*/
|
||||
public final class Pair<F, S> {
|
||||
/**
|
||||
* The First.
|
||||
*/
|
||||
public F first;
|
||||
/**
|
||||
* The Second.
|
||||
*/
|
||||
public S second;
|
||||
|
||||
private Pair(F first, S second) {
|
||||
|
|
@ -12,6 +24,15 @@ public final class Pair<F, S> {
|
|||
this.second = second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Of @ not null pair.
|
||||
*
|
||||
* @param <F> the type parameter
|
||||
* @param <S> the type parameter
|
||||
* @param first the first
|
||||
* @param second the second
|
||||
* @return the @ not null pair
|
||||
*/
|
||||
@Contract("null, _ -> fail; !null, null -> fail; !null, !null -> new")
|
||||
public static <F, S> @NotNull Pair<F, S> of(F first, S second) {
|
||||
if (first == null || second == null) {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,26 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The type Triple.
|
||||
*
|
||||
* @param <A> the type parameter
|
||||
* @param <B> the type parameter
|
||||
* @param <C> the type parameter
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class Triple<A, B, C> {
|
||||
/**
|
||||
* The First.
|
||||
*/
|
||||
public A first;
|
||||
/**
|
||||
* The Second.
|
||||
*/
|
||||
public B second;
|
||||
/**
|
||||
* The Third.
|
||||
*/
|
||||
public C third;
|
||||
|
||||
private Triple(A first, B second, C third) {
|
||||
|
|
@ -17,6 +33,17 @@ public final class Triple<A, B, C> {
|
|||
this.third = third;
|
||||
}
|
||||
|
||||
/**
|
||||
* Of @ not null triple.
|
||||
*
|
||||
* @param <A> the type parameter
|
||||
* @param <B> the type parameter
|
||||
* @param <C> the type parameter
|
||||
* @param first the first
|
||||
* @param second the second
|
||||
* @param third the third
|
||||
* @return the @ not null triple
|
||||
*/
|
||||
@Contract(value = "_, _, _ -> new", pure = true)
|
||||
public static <A, B, C> @NotNull Triple<A, B, C> of(A first, B second, C third) {
|
||||
return new Triple<>(first, second, third);
|
||||
|
|
@ -37,8 +64,9 @@ public final class Triple<A, B, C> {
|
|||
return Objects.hash(first, second, third);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@Override
|
||||
public String toString() {
|
||||
public @NotNull String toString() {
|
||||
return "Triple{" +
|
||||
"first=" + first +
|
||||
", second=" + second +
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The type Tuple.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class Tuple {
|
||||
private final List<Object> elements;
|
||||
|
|
@ -16,15 +19,33 @@ public final class Tuple {
|
|||
this.elements = List.of(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Of tuple.
|
||||
*
|
||||
* @param elements the elements
|
||||
* @return the tuple
|
||||
*/
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
public static @NotNull Tuple of(Object... elements) {
|
||||
return new Tuple(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size int.
|
||||
*
|
||||
* @return the int
|
||||
*/
|
||||
public int size() {
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param index the index
|
||||
* @return the t
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(int index) {
|
||||
if (index < 0 || index >= elements.size()) {
|
||||
|
|
@ -33,27 +54,63 @@ public final class Tuple {
|
|||
return (T) elements.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* First t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @return the t
|
||||
*/
|
||||
public <T> T first() {
|
||||
return get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Second t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @return the t
|
||||
*/
|
||||
public <T> T second() {
|
||||
return get(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Third t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @return the t
|
||||
*/
|
||||
public <T> T third() {
|
||||
return get(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Last t.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @return the t
|
||||
*/
|
||||
public <T> T last() {
|
||||
return get(elements.size() - 1);
|
||||
}
|
||||
|
||||
public List<Object> toList() {
|
||||
/**
|
||||
* To list list.
|
||||
*
|
||||
* @return the list
|
||||
*/
|
||||
@Contract(value = " -> new", pure = true)
|
||||
public @NotNull List<Object> toList() {
|
||||
return new ArrayList<>(elements);
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
/**
|
||||
* To array object [ ].
|
||||
*
|
||||
* @return the object [ ]
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
public Object @NotNull [] toArray() {
|
||||
return elements.toArray();
|
||||
}
|
||||
|
||||
|
|
@ -70,15 +127,26 @@ public final class Tuple {
|
|||
return Objects.hash(elements);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@Override
|
||||
public String toString() {
|
||||
public @NotNull String toString() {
|
||||
return "Tuple" + elements;
|
||||
}
|
||||
|
||||
public Iterator<Object> iterator() {
|
||||
/**
|
||||
* Iterator iterator.
|
||||
*
|
||||
* @return the iterator
|
||||
*/
|
||||
public @NotNull Iterator<Object> iterator() {
|
||||
return elements.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream java . util . stream . stream.
|
||||
*
|
||||
* @return the java . util . stream . stream
|
||||
*/
|
||||
public java.util.stream.Stream<Object> stream() {
|
||||
return elements.stream();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ import org.jetbrains.annotations.Nullable;
|
|||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The type Nbt reader.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class NBTReader {
|
||||
private final CompoundTag nbt;
|
||||
|
|
@ -34,13 +37,23 @@ public class NBTReader {
|
|||
|
||||
/**
|
||||
* 从CompoundTag创建读取器
|
||||
*
|
||||
* @param nbt the nbt
|
||||
* @return the nbt reader
|
||||
*/
|
||||
@NotNull
|
||||
public static NBTReader of(@NotNull CompoundTag nbt) {
|
||||
return new NBTReader(nbt);
|
||||
}
|
||||
|
||||
// 基本读取方法 - 直接赋值给成员变量
|
||||
/**
|
||||
* String nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// 基本读取方法 - 直接赋值给成员变量
|
||||
public NBTReader string(String key, Consumer<String> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getString(key));
|
||||
|
|
@ -48,11 +61,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* String nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader string(String key, @NotNull Consumer<String> setter, String defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getString(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader byteValue(String key, Consumer<Byte> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getByte(key));
|
||||
|
|
@ -60,11 +88,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader byteValue(String key, @NotNull Consumer<Byte> setter, byte defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getByte(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Short value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader shortValue(String key, Consumer<Short> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getShort(key));
|
||||
|
|
@ -72,11 +115,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Short value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader shortValue(String key, @NotNull Consumer<Short> setter, short defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getShort(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Int value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader intValue(String key, Consumer<Integer> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getInt(key));
|
||||
|
|
@ -84,11 +142,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Int value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader intValue(String key, @NotNull Consumer<Integer> setter, int defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getInt(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Long value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader longValue(String key, Consumer<Long> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getLong(key));
|
||||
|
|
@ -96,11 +169,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Long value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader longValue(String key, @NotNull Consumer<Long> setter, long defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getLong(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Float value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader floatValue(String key, Consumer<Float> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getFloat(key));
|
||||
|
|
@ -108,11 +196,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Float value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader floatValue(String key, @NotNull Consumer<Float> setter, float defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getFloat(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Double value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader doubleValue(String key, Consumer<Double> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getDouble(key));
|
||||
|
|
@ -120,11 +223,26 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Double value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader doubleValue(String key, @NotNull Consumer<Double> setter, double defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getDouble(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boolean value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader booleanValue(String key, Consumer<Boolean> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getBoolean(key));
|
||||
|
|
@ -132,12 +250,27 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boolean value nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader booleanValue(String key, @NotNull Consumer<Boolean> setter, boolean defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getBoolean(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 数组类型
|
||||
/**
|
||||
* Byte array nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// 数组类型
|
||||
public NBTReader byteArray(String key, Consumer<byte[]> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getByteArray(key));
|
||||
|
|
@ -145,6 +278,13 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Int array nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader intArray(String key, Consumer<int[]> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getIntArray(key));
|
||||
|
|
@ -152,6 +292,13 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Long array nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader longArray(String key, Consumer<long[]> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getLongArray(key));
|
||||
|
|
@ -159,7 +306,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// UUID
|
||||
/**
|
||||
* Uuid nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// UUID
|
||||
public NBTReader uuid(String key, Consumer<UUID> setter) {
|
||||
if (nbt.hasUUID(key)) {
|
||||
setter.accept(nbt.getUUID(key));
|
||||
|
|
@ -167,12 +321,27 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uuid 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<UUID> setter, UUID defaultValue) {
|
||||
setter.accept(nbt.hasUUID(key) ? nbt.getUUID(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
// CompoundTag
|
||||
/**
|
||||
* Compound nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// CompoundTag
|
||||
public NBTReader compound(String key, Consumer<CompoundTag> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getCompound(key));
|
||||
|
|
@ -180,12 +349,28 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compound nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader compound(String key, @NotNull Consumer<CompoundTag> setter, CompoundTag defaultValue) {
|
||||
setter.accept(nbt.contains(key) ? nbt.getCompound(key) : defaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ListTag
|
||||
/**
|
||||
* 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<ListTag> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
setter.accept(nbt.getList(key, type));
|
||||
|
|
@ -193,7 +378,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// Vec3支持
|
||||
/**
|
||||
* Vec 3 nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// Vec3支持
|
||||
public NBTReader vec3(String key, Consumer<Vec3> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
CompoundTag vecTag = nbt.getCompound(key);
|
||||
|
|
@ -208,6 +400,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vec 3 nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader vec3(String key, Consumer<Vec3> setter, Vec3 defaultValue) {
|
||||
if (nbt.contains(key)) {
|
||||
CompoundTag vecTag = nbt.getCompound(key);
|
||||
|
|
@ -224,7 +424,16 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// 枚举支持
|
||||
/**
|
||||
* Enum value nbt reader.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param enumClass the enum class
|
||||
* @param setter the setter
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// 枚举支持
|
||||
public <T extends Enum<T>> NBTReader enumValue(String key, Class<T> enumClass, Consumer<T> setter) {
|
||||
if (nbt.contains(key)) {
|
||||
String value = nbt.getString(key);
|
||||
|
|
@ -237,6 +446,16 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum value nbt reader.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @param key the key
|
||||
* @param enumClass the enum class
|
||||
* @param setter the setter
|
||||
* @param defaultValue the default value
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public <T extends Enum<T>> NBTReader enumValue(String key, Class<T> enumClass, Consumer<T> setter, T defaultValue) {
|
||||
if (nbt.contains(key)) {
|
||||
String value = nbt.getString(key);
|
||||
|
|
@ -250,7 +469,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// 嵌套读取支持
|
||||
/**
|
||||
* Nested nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param consumer the consumer
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// 嵌套读取支持
|
||||
public NBTReader nested(String key, Consumer<NBTReader> consumer) {
|
||||
if (nbt.contains(key)) {
|
||||
consumer.accept(new NBTReader(nbt.getCompound(key)));
|
||||
|
|
@ -258,6 +484,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nested nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param consumer the consumer
|
||||
* @param orElse the or else
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader nested(String key, Consumer<NBTReader> consumer, Runnable orElse) {
|
||||
if (nbt.contains(key)) {
|
||||
consumer.accept(new NBTReader(nbt.getCompound(key)));
|
||||
|
|
@ -267,7 +501,14 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// 条件读取
|
||||
/**
|
||||
* If present nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param action the action
|
||||
* @return the nbt reader
|
||||
*/
|
||||
// 条件读取
|
||||
public NBTReader ifPresent(String key, Runnable action) {
|
||||
if (nbt.contains(key)) {
|
||||
action.run();
|
||||
|
|
@ -275,6 +516,13 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If absent nbt reader.
|
||||
*
|
||||
* @param key the key
|
||||
* @param action the action
|
||||
* @return the nbt reader
|
||||
*/
|
||||
public NBTReader ifAbsent(String key, Runnable action) {
|
||||
if (!nbt.contains(key)) {
|
||||
action.run();
|
||||
|
|
@ -282,13 +530,24 @@ public class NBTReader {
|
|||
return this;
|
||||
}
|
||||
|
||||
// 获取原始NBT
|
||||
/**
|
||||
* Gets raw.
|
||||
*
|
||||
* @return the raw
|
||||
*/
|
||||
// 获取原始NBT
|
||||
@NotNull
|
||||
public CompoundTag getRaw() {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
// 便捷的静态方法(保持原有功能)
|
||||
/**
|
||||
* Read vec 3 vec 3.
|
||||
*
|
||||
* @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")) {
|
||||
|
|
@ -302,6 +561,12 @@ public class NBTReader {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read vec 3 safe vec 3.
|
||||
*
|
||||
* @param nbt the nbt
|
||||
* @return the vec 3
|
||||
*/
|
||||
@Nullable
|
||||
public static Vec3 readVec3Safe(@NotNull CompoundTag nbt) {
|
||||
if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -24,13 +24,17 @@ import java.util.Queue;
|
|||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The type Riding applier.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingApplier {
|
||||
/**
|
||||
* 应用骑乘关系(在服务器端调用)
|
||||
* @param relationship 骑乘关系
|
||||
*
|
||||
* @param relationship 骑乘关系
|
||||
* @param entityProvider 实体提供器(根据UUID获取实体)
|
||||
* @return 应用成功的实体数量
|
||||
* @return 应用成功的实体数量 int
|
||||
*/
|
||||
public static int applyRidingRelationship(RidingRelationship relationship,
|
||||
Function<UUID, Entity> entityProvider) {
|
||||
|
|
@ -87,8 +91,12 @@ public class RidingApplier {
|
|||
|
||||
return appliedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量应用骑乘关系(适用于世界加载时)
|
||||
*
|
||||
* @param relationships the relationships
|
||||
* @param entityProvider the entity provider
|
||||
*/
|
||||
public static void applyRidingRelationships(Collection<RidingRelationship> relationships,
|
||||
Function<UUID, Entity> entityProvider) {
|
||||
|
|
@ -108,6 +116,10 @@ public class RidingApplier {
|
|||
|
||||
/**
|
||||
* 从JSON字符串应用骑乘关系
|
||||
*
|
||||
* @param json the json
|
||||
* @param entityProvider the entity provider
|
||||
* @return the int
|
||||
*/
|
||||
public static int applyRidingRelationshipFromJson(String json,
|
||||
Function<UUID, Entity> entityProvider) {
|
||||
|
|
|
|||
|
|
@ -17,11 +17,20 @@ package top.r3944realms.lib39.util.riding;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The type Riding cycle exception.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingCycleException extends IllegalStateException {
|
||||
private final UUID entityId;
|
||||
private final UUID vehicleId;
|
||||
|
||||
/**
|
||||
* Instantiates a new Riding cycle exception.
|
||||
*
|
||||
* @param entityId the entity id
|
||||
* @param vehicleId the vehicle id
|
||||
*/
|
||||
public RidingCycleException(UUID entityId, UUID vehicleId) {
|
||||
super(String.format("Cyclic riding reference detected. " +
|
||||
"Entity %s cannot be added as passenger to vehicle %s " +
|
||||
|
|
@ -31,10 +40,20 @@ public class RidingCycleException extends IllegalStateException {
|
|||
this.vehicleId = vehicleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets entity id.
|
||||
*
|
||||
* @return the entity id
|
||||
*/
|
||||
public UUID getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets vehicle id.
|
||||
*
|
||||
* @return the vehicle id
|
||||
*/
|
||||
public UUID getVehicleId() {
|
||||
return vehicleId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,15 @@ import net.minecraft.world.entity.Entity;
|
|||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The type Riding dismounts.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingDismounts {
|
||||
/**
|
||||
* 解除单个实体的骑乘关系
|
||||
*
|
||||
* @param entity the entity
|
||||
*/
|
||||
public static void dismountEntity(Entity entity) {
|
||||
if (entity == null) {
|
||||
|
|
@ -41,6 +46,8 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 解除实体及其所有乘客的骑乘关系(非递归)
|
||||
*
|
||||
* @param entity the entity
|
||||
*/
|
||||
public static void dismountAllPassengers(Entity entity) {
|
||||
if (entity == null) {
|
||||
|
|
@ -65,6 +72,8 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 解除根实体的骑乘关系(包括从载具下车)
|
||||
*
|
||||
* @param entity the entity
|
||||
*/
|
||||
public static void dismountRootEntity(Entity entity) {
|
||||
if (entity == null) {
|
||||
|
|
@ -86,6 +95,10 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 安全解除骑乘关系(带超时保护)
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param maxIterations the max iterations
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean safeDismountAll(Entity entity, int maxIterations) {
|
||||
if (entity == null) {
|
||||
|
|
@ -118,6 +131,8 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 批量解除多个实体的骑乘关系
|
||||
*
|
||||
* @param entities the entities
|
||||
*/
|
||||
public static void dismountEntities(Collection<Entity> entities) {
|
||||
if (entities == null || entities.isEmpty()) {
|
||||
|
|
@ -151,6 +166,9 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 根据骑乘关系数据结构解除骑乘
|
||||
*
|
||||
* @param relationship the relationship
|
||||
* @param entityProvider the entity provider
|
||||
*/
|
||||
public static void dismountByRelationship(RidingRelationship relationship,
|
||||
Function<UUID, Entity> entityProvider) {
|
||||
|
|
@ -181,6 +199,8 @@ public class RidingDismounts {
|
|||
|
||||
/**
|
||||
* 立即解除所有骑乘关系(强制方式)
|
||||
*
|
||||
* @param entity the entity
|
||||
*/
|
||||
public static void forceDismountAll(Entity entity) {
|
||||
if (entity == null) {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,17 @@ import org.jetbrains.annotations.Nullable;
|
|||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The type Riding finder.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingFinder {
|
||||
/**
|
||||
* 从JSON字符串应用骑乘关系
|
||||
*
|
||||
* @param ship the ship
|
||||
* @param entityProvider the entity provider
|
||||
* @return the entity from riding ship
|
||||
*/
|
||||
public static @NotNull List<Entity> getEntityFromRidingShip(RidingRelationship ship,
|
||||
Function<UUID, Entity> entityProvider) {
|
||||
|
|
@ -42,8 +49,12 @@ public class RidingFinder {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找根载具
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return the entity
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity findRootVehicle(@Nullable Entity entity) {
|
||||
|
|
@ -64,6 +75,9 @@ public class RidingFinder {
|
|||
|
||||
/**
|
||||
* 获取所有乘客(包括嵌套乘客)
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return the all passengers
|
||||
*/
|
||||
public static List<Entity> getAllPassengers(@Nullable Entity entity) {
|
||||
return getAllPassengers(entity, true);
|
||||
|
|
@ -71,6 +85,10 @@ public class RidingFinder {
|
|||
|
||||
/**
|
||||
* 获取所有乘客(包括嵌套乘客)
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param findRoot the find root
|
||||
* @return the all passengers
|
||||
*/
|
||||
public static List<Entity> getAllPassengers(@Nullable Entity entity, boolean findRoot) {
|
||||
if (entity == null) {
|
||||
|
|
|
|||
|
|
@ -26,46 +26,93 @@ public class RidingRelationship {
|
|||
private UUID vehicleId;
|
||||
private List<RidingRelationship> passengers;
|
||||
|
||||
/**
|
||||
* Instantiates a new Riding relationship.
|
||||
*/
|
||||
public RidingRelationship() {
|
||||
this.passengers = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Riding relationship.
|
||||
*
|
||||
* @param passengers the passengers
|
||||
* @param vehicleId the vehicle id
|
||||
* @param entityId the entity id
|
||||
*/
|
||||
public RidingRelationship(List<RidingRelationship> passengers, UUID vehicleId, UUID entityId) {
|
||||
this.passengers = passengers != null ? passengers : new ArrayList<>();
|
||||
this.vehicleId = vehicleId;
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets entity id.
|
||||
*
|
||||
* @return the entity id
|
||||
*/
|
||||
public UUID getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets entity id.
|
||||
*
|
||||
* @param entityId the entity id
|
||||
*/
|
||||
public void setEntityId(UUID entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets passengers.
|
||||
*
|
||||
* @return the passengers
|
||||
*/
|
||||
public List<RidingRelationship> getPassengers() {
|
||||
return Collections.unmodifiableList(passengers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets passengers.
|
||||
*
|
||||
* @param passengers the passengers
|
||||
*/
|
||||
public void setPassengers(List<RidingRelationship> passengers) {
|
||||
this.passengers = passengers != null ? passengers : new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add passenger.
|
||||
*
|
||||
* @param passenger the passenger
|
||||
*/
|
||||
public void addPassenger(RidingRelationship passenger) {
|
||||
this.passengers.add(passenger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets vehicle id.
|
||||
*
|
||||
* @return the vehicle id
|
||||
*/
|
||||
public UUID getVehicleId() {
|
||||
return vehicleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets vehicle id.
|
||||
*
|
||||
* @param vehicleId the vehicle id
|
||||
*/
|
||||
public void setVehicleId(UUID vehicleId) {
|
||||
this.vehicleId = vehicleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有嵌套乘客的数量
|
||||
*
|
||||
* @return the total passenger count
|
||||
*/
|
||||
public int getTotalPassengerCount() {
|
||||
int count = passengers.size();
|
||||
|
|
@ -77,6 +124,9 @@ public class RidingRelationship {
|
|||
|
||||
/**
|
||||
* 检查是否包含特定实体
|
||||
*
|
||||
* @param entityId the entity id
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean containsEntity(UUID entityId) {
|
||||
if (Objects.equals(this.entityId, entityId)) {
|
||||
|
|
|
|||
|
|
@ -25,10 +25,16 @@ import top.r3944realms.lib39.util.lang.Pair;
|
|||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The type Riding saver.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingSaver {
|
||||
/**
|
||||
* 保存骑乘关系
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return the riding relationship
|
||||
*/
|
||||
@Contract("null -> new")
|
||||
public static @NotNull RidingRelationship save(@Nullable Entity entity) {
|
||||
|
|
@ -37,6 +43,10 @@ public class RidingSaver {
|
|||
|
||||
/**
|
||||
* 保存骑乘关系
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param findRoot the find root
|
||||
* @return the riding relationship
|
||||
*/
|
||||
@Contract("null, _ -> new")
|
||||
public static @NotNull RidingRelationship save(@Nullable Entity entity, boolean findRoot) {
|
||||
|
|
@ -98,6 +108,11 @@ public class RidingSaver {
|
|||
// 传入一个实体提供器 Function<UUID, Entity>,通常在服务器侧就是 level::getEntity
|
||||
private static Function<UUID, Entity> entityProvider;
|
||||
|
||||
/**
|
||||
* Sets entity provider.
|
||||
*
|
||||
* @param provider the provider
|
||||
*/
|
||||
public static void setEntityProvider(Function<UUID, Entity> provider) {
|
||||
entityProvider = provider;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,18 @@ package top.r3944realms.lib39.util.riding;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The type Riding serializer.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingSerializer {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
/**
|
||||
* 序列化骑乘关系
|
||||
*
|
||||
* @param relationship the relationship
|
||||
* @return the string
|
||||
*/
|
||||
public static String serialize(RidingRelationship relationship) {
|
||||
return GSON.toJson(relationship);
|
||||
|
|
@ -29,6 +36,9 @@ public class RidingSerializer {
|
|||
|
||||
/**
|
||||
* 反序列化骑乘关系
|
||||
*
|
||||
* @param json the json
|
||||
* @return the riding relationship
|
||||
*/
|
||||
public static RidingRelationship deserialize(String json) {
|
||||
return GSON.fromJson(json, RidingRelationship.class);
|
||||
|
|
|
|||
|
|
@ -20,10 +20,17 @@ import net.minecraft.world.entity.Entity;
|
|||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* The type Riding validator.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class RidingValidator {
|
||||
/**
|
||||
* 检查骑乘是否会产生循环引用
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param vehicle the vehicle
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean wouldCreateCycle(Entity entity, Entity vehicle) {
|
||||
// 如果实体就是载具本身,直接产生循环
|
||||
|
|
@ -37,6 +44,10 @@ public class RidingValidator {
|
|||
|
||||
/**
|
||||
* 检查target是否是entity的间接乘客
|
||||
*
|
||||
* @param target the target
|
||||
* @param entity the entity
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean isIndirectPassenger(Entity target, Entity entity) {
|
||||
Queue<Entity> queue = new LinkedList<>();
|
||||
|
|
|
|||
|
|
@ -4,16 +4,43 @@ package top.r3944realms.lib39.util.shape;
|
|||
import com.mojang.math.Axis;
|
||||
import org.joml.Quaternionf;
|
||||
|
||||
/**
|
||||
* The type Quaternions.
|
||||
*/
|
||||
public final class Quaternions {
|
||||
/**
|
||||
* The constant XP_90.
|
||||
*/
|
||||
public static final Quaternionf XP_90 = Axis.XP.rotationDegrees(90);
|
||||
/**
|
||||
* The constant XP_180.
|
||||
*/
|
||||
public static final Quaternionf XP_180 = Axis.XP.rotationDegrees(180);
|
||||
/**
|
||||
* The constant XN_90.
|
||||
*/
|
||||
public static final Quaternionf XN_90 = Axis.XN.rotationDegrees(90);
|
||||
|
||||
/**
|
||||
* The constant YP_90.
|
||||
*/
|
||||
public static final Quaternionf YP_90 = Axis.YP.rotationDegrees(90);
|
||||
/**
|
||||
* The constant YN_90.
|
||||
*/
|
||||
public static final Quaternionf YN_90 = Axis.YN.rotationDegrees(90);
|
||||
|
||||
/**
|
||||
* The constant ZP_90.
|
||||
*/
|
||||
public static final Quaternionf ZP_90 = Axis.ZP.rotationDegrees(90);
|
||||
/**
|
||||
* The constant ZP_180.
|
||||
*/
|
||||
public static final Quaternionf ZP_180 = Axis.ZP.rotationDegrees(180);
|
||||
/**
|
||||
* The constant ZN_90.
|
||||
*/
|
||||
public static final Quaternionf ZN_90 = Axis.ZN.rotationDegrees(90);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@ import net.minecraft.core.Direction;
|
|||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The type Shape util.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ShapeUtil {
|
||||
|
||||
|
|
@ -15,6 +19,14 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 创建基于像素的碰撞箱(将像素坐标转换为方块坐标)
|
||||
*
|
||||
* @param minX the min x
|
||||
* @param minY the min y
|
||||
* @param minZ the min z
|
||||
* @param maxX the max x
|
||||
* @param maxY the max y
|
||||
* @param maxZ the max z
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape createPixelBasedShape(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
|
|
@ -24,6 +36,14 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 便捷方法:创建方块碰撞箱
|
||||
*
|
||||
* @param minX the min x
|
||||
* @param minY the min y
|
||||
* @param minZ the min z
|
||||
* @param maxX the max x
|
||||
* @param maxY the max y
|
||||
* @param maxZ the max z
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape createBox(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
|
|
@ -34,15 +54,22 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 创建单一形状的方向映射
|
||||
*
|
||||
* @param shape the shape
|
||||
* @return the map
|
||||
*/
|
||||
public static Map<Direction, VoxelShape> createUniformDirectionMap(VoxelShape shape) {
|
||||
public static @NotNull Map<Direction, VoxelShape> createUniformDirectionMap(VoxelShape shape) {
|
||||
return createRotatedDirectionMap(shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建原版双方块的形状映射
|
||||
*
|
||||
* @param lowerShape the lower shape
|
||||
* @param upperShape the upper shape
|
||||
* @return the map
|
||||
*/
|
||||
public static Map<DoubleBlockHalf, Map<Direction, VoxelShape>> createDoubleBlockShapeMap(VoxelShape lowerShape, VoxelShape upperShape) {
|
||||
public static @NotNull Map<DoubleBlockHalf, Map<Direction, VoxelShape>> createDoubleBlockShapeMap(VoxelShape lowerShape, VoxelShape upperShape) {
|
||||
EnumMap<DoubleBlockHalf, Map<Direction, VoxelShape>> shapeMap = new EnumMap<>(DoubleBlockHalf.class);
|
||||
shapeMap.put(DoubleBlockHalf.LOWER, createRotatedDirectionMap(lowerShape));
|
||||
shapeMap.put(DoubleBlockHalf.UPPER, createRotatedDirectionMap(upperShape));
|
||||
|
|
@ -53,6 +80,9 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 顺时针旋转碰撞箱(Y轴旋转)
|
||||
*
|
||||
* @param shape the shape
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape rotateVoxelShapeClockwise(@NotNull VoxelShape shape) {
|
||||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||||
|
|
@ -65,6 +95,9 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 绕X轴旋转碰撞箱
|
||||
*
|
||||
* @param shape the shape
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape rotateVoxelShapeXAxis(@NotNull VoxelShape shape) {
|
||||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||||
|
|
@ -77,6 +110,9 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 绕Z轴旋转碰撞箱
|
||||
*
|
||||
* @param shape the shape
|
||||
* @return the voxel shape
|
||||
*/
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
public static @NotNull VoxelShape rotateVoxelShapeZAxis(@NotNull VoxelShape shape) {
|
||||
|
|
@ -90,6 +126,10 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 按指定角度旋转碰撞箱
|
||||
*
|
||||
* @param shape the shape
|
||||
* @param degrees the degrees
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape rotateShape(@NotNull VoxelShape shape, int degrees) {
|
||||
int rotations = (degrees / 90) % 4;
|
||||
|
|
@ -107,7 +147,7 @@ public class ShapeUtil {
|
|||
* 组合多个形状列表
|
||||
*/
|
||||
@NotNull
|
||||
private static VoxelShape combineShapes(List<VoxelShape> shapes) {
|
||||
private static VoxelShape combineShapes(@NotNull List<VoxelShape> shapes) {
|
||||
if (shapes.isEmpty()) {
|
||||
return Shapes.block();
|
||||
}
|
||||
|
|
@ -122,6 +162,9 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 组合多个形状
|
||||
*
|
||||
* @param shapes the shapes
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public static @NotNull VoxelShape combineShapes(VoxelShape... shapes) {
|
||||
return combineShapes(Arrays.asList(shapes));
|
||||
|
|
@ -132,7 +175,7 @@ public class ShapeUtil {
|
|||
/**
|
||||
* 创建旋转方向映射
|
||||
*/
|
||||
private static Map<Direction, VoxelShape> createRotatedDirectionMap(VoxelShape baseShape) {
|
||||
private static @NotNull Map<Direction, VoxelShape> createRotatedDirectionMap(VoxelShape baseShape) {
|
||||
EnumMap<Direction, VoxelShape> directionMap = new EnumMap<>(Direction.class);
|
||||
directionMap.put(Direction.NORTH, baseShape);
|
||||
directionMap.put(Direction.EAST, rotateShape(baseShape, 90));
|
||||
|
|
@ -150,23 +193,56 @@ public class ShapeUtil {
|
|||
public static class ShapeBuilder {
|
||||
private final List<VoxelShape> shapes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add pixel box shape builder.
|
||||
*
|
||||
* @param minX the min x
|
||||
* @param minY the min y
|
||||
* @param minZ the min z
|
||||
* @param maxX the max x
|
||||
* @param maxY the max y
|
||||
* @param maxZ the max z
|
||||
* @return the shape builder
|
||||
*/
|
||||
public ShapeBuilder addPixelBox(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
shapes.add(createPixelBasedShape(minX, minY, minZ, maxX, maxY, maxZ));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add box shape builder.
|
||||
*
|
||||
* @param minX the min x
|
||||
* @param minY the min y
|
||||
* @param minZ the min z
|
||||
* @param maxX the max x
|
||||
* @param maxY the max y
|
||||
* @param maxZ the max z
|
||||
* @return the shape builder
|
||||
*/
|
||||
public ShapeBuilder addBox(double minX, double minY, double minZ,
|
||||
double maxX, double maxY, double maxZ) {
|
||||
shapes.add(createBox(minX, minY, minZ, maxX, maxY, maxZ));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add shape shape builder.
|
||||
*
|
||||
* @param shape the shape
|
||||
* @return the shape builder
|
||||
*/
|
||||
public ShapeBuilder addShape(VoxelShape shape) {
|
||||
shapes.add(shape);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build voxel shape.
|
||||
*
|
||||
* @return the voxel shape
|
||||
*/
|
||||
public VoxelShape build() {
|
||||
return combineShapes(shapes);
|
||||
}
|
||||
|
|
@ -174,8 +250,11 @@ public class ShapeUtil {
|
|||
|
||||
/**
|
||||
* 创建形状构建器
|
||||
*
|
||||
* @return the shape builder
|
||||
*/
|
||||
public static ShapeBuilder builder() {
|
||||
@Contract(" -> new")
|
||||
public static @NotNull ShapeBuilder builder() {
|
||||
return new ShapeBuilder();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,22 @@ package top.r3944realms.lib39.util.sound;
|
|||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The type Sound util.
|
||||
*/
|
||||
public class SoundUtil {
|
||||
/**
|
||||
* 为实体播放声音
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param soundEvent the sound event
|
||||
* @param soundCategory the sound category
|
||||
* @param volume the volume
|
||||
* @param pitch the pitch
|
||||
*/
|
||||
public static void playSoundForEntity(LivingEntity entity, SoundEvent soundEvent, SoundSource soundCategory, float volume, float pitch) {
|
||||
public static void playSoundForEntity(@NotNull LivingEntity entity, SoundEvent soundEvent, SoundSource soundCategory, float volume, float pitch) {
|
||||
entity.level().playSound(null, entity.getX(), entity.getY(), entity.getZ(), soundEvent, soundCategory, volume, pitch);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user