API重构工作 #1
This commit is contained in:
parent
5ae81a0001
commit
8d5b91e54a
134
build.gradle
134
build.gradle
|
|
@ -71,6 +71,22 @@ repositories {
|
||||||
includeModule 'me.lucko', 'spark-api'
|
includeModule 'me.lucko', 'spark-api'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
name "KosmX's maven"
|
||||||
|
url 'https://maven.kosmx.dev/'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "Curios"
|
||||||
|
url = uri("https://maven.theillusivec4.top/")
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'GeckoLib'
|
||||||
|
url 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/'
|
||||||
|
content {
|
||||||
|
includeGroupByRegex("software\\.bernie.*")
|
||||||
|
includeGroup("com.eliotlash.mclib")
|
||||||
|
}
|
||||||
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
flatDir {
|
flatDir {
|
||||||
dir "libs"
|
dir "libs"
|
||||||
|
|
@ -98,7 +114,7 @@ legacyForge {
|
||||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
||||||
// // 设置 RenderDoc library 路径
|
// // 设置 RenderDoc library 路径
|
||||||
// // 系统属性,使用项目相对路径
|
// // 系统属性,使用项目相对路径
|
||||||
// systemProperty 'neoforge.rendernurse.renderdoc.library', file('RenderDoc_1.40_64/renderdoc.dll').absolutePath
|
// systemProperty 'neoforged.rendernurse.renderdoc.library', file('RenderDoc_1.40_64/renderdoc.dll').absolutePath
|
||||||
//
|
//
|
||||||
// // JVM 参数
|
// // JVM 参数
|
||||||
// jvmArgument "-javaagent:${file('libs/RenderNurse-0.0.9.jar').absolutePath}"
|
// jvmArgument "-javaagent:${file('libs/RenderNurse-0.0.9.jar').absolutePath}"
|
||||||
|
|
@ -150,10 +166,19 @@ dependencies {
|
||||||
modRuntimeOnly("curse.maven:debug-utils-forge-783008:5337491")
|
modRuntimeOnly("curse.maven:debug-utils-forge-783008:5337491")
|
||||||
modCompileOnly("blank:curtain-1.20.1:1.3.2")
|
modCompileOnly("blank:curtain-1.20.1:1.3.2")
|
||||||
modRuntimeOnly("blank:curtain-1.20.1:1.3.2")
|
modRuntimeOnly("blank:curtain-1.20.1:1.3.2")
|
||||||
|
modImplementation("dev.kosmx.player-anim:player-animation-lib-forge:${player_anim_version}")
|
||||||
|
modImplementation("curse.maven:bendy-lib-623373:4550371")
|
||||||
|
modImplementation("software.bernie.geckolib:geckolib-forge-${minecraft_version}:${geckolib_version}")
|
||||||
|
implementation("com.eliotlash.mclib:mclib:20")
|
||||||
|
modCompileOnly("top.theillusivec4.curios:curios-forge:${curios_version}:api")
|
||||||
|
modCompileOnly("top.theillusivec4.curios:curios-forge:${curios_version}")
|
||||||
|
modRuntimeOnly("top.theillusivec4.curios:curios-forge:${curios_version}")
|
||||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}")
|
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}")
|
||||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}")
|
modCompileOnly("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}")
|
||||||
modRuntimeOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
modRuntimeOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
||||||
modRuntimeOnly("curse.maven:spark-361579:4738952")
|
modRuntimeOnly("curse.maven:spark-361579:4738952")
|
||||||
|
compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1"))
|
||||||
|
modImplementation("io.github.llamalad7:mixinextras-forge:0.4.1")
|
||||||
compileOnly ('me.lucko:spark-api:0.1-SNAPSHOT')
|
compileOnly ('me.lucko:spark-api:0.1-SNAPSHOT')
|
||||||
implementation 'org.ow2.asm:asm:9.6'
|
implementation 'org.ow2.asm:asm:9.6'
|
||||||
implementation 'org.ow2.asm:asm-tree:9.6'
|
implementation 'org.ow2.asm:asm-tree:9.6'
|
||||||
|
|
@ -170,6 +195,45 @@ dokkaJavadoc {
|
||||||
outputDirectory = file("$buildDir/javadoc")
|
outputDirectory = file("$buildDir/javadoc")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== API Jar 配置 ==========
|
||||||
|
tasks.register('apiJar', Jar) {
|
||||||
|
archiveClassifier.set('api')
|
||||||
|
from sourceSets.main.output
|
||||||
|
include "top/r3944realms/superleadrope/api/**/*"
|
||||||
|
include "top/r3944realms/superleadrope/SuperLeadRopeAPI.class"
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes([
|
||||||
|
'Specification-Title' : "${mod_id}-api",
|
||||||
|
'Specification-Vendor' : mod_authors,
|
||||||
|
'Specification-Version' : '1',
|
||||||
|
'Implementation-Title' : "${project.name}-api",
|
||||||
|
'Implementation-Version' : archiveVersion,
|
||||||
|
'Implementation-Vendor' : mod_authors,
|
||||||
|
'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||||
|
'FMLModType' : 'GAMELIBRARY'
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保包含 API 相关的源文件
|
||||||
|
dependsOn classes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建包含源码的 API Jar
|
||||||
|
tasks.register('sourcesApiJar', Jar) {
|
||||||
|
archiveClassifier.set('api-sources')
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
include "top/r3944realms/superleadrope/api/**/*"
|
||||||
|
include "top/r3944realms/superleadrope/SuperLeadRopeAPI.java"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 API Javadoc Jar
|
||||||
|
tasks.register('javadocApiJar', Jar) {
|
||||||
|
archiveClassifier.set('api-javadoc')
|
||||||
|
from dokkaJavadoc
|
||||||
|
dependsOn dokkaJavadoc
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 打包配置 ==========
|
// ========== 打包配置 ==========
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
|
|
@ -184,6 +248,10 @@ jar {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
archiveFileName = "${mod_id}-${mod_version}-origin.jar"
|
archiveFileName = "${mod_id}-${mod_version}-origin.jar"
|
||||||
|
|
||||||
|
// 可选:排除 API 类(如果你不想在主 jar 中包含 API)
|
||||||
|
// exclude "top/r3944realms/superleadrope/api/**/*"
|
||||||
|
|
||||||
finalizedBy 'proguard'
|
finalizedBy 'proguard'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,19 +283,6 @@ shadowJar {
|
||||||
outputs.upToDateWhen { false }
|
outputs.upToDateWhen { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本地 Maven 发布
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
create('mavenJava', MavenPublication) {
|
|
||||||
artifact jar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "file://${project.projectDir}/mcmodsrepo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 新建一个可解析配置专门给 ProGuard
|
// 新建一个可解析配置专门给 ProGuard
|
||||||
configurations {
|
configurations {
|
||||||
proguardLibs {
|
proguardLibs {
|
||||||
|
|
@ -279,6 +334,56 @@ afterEvaluate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 发布配置 ==========
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
artifact jar
|
||||||
|
// 添加 API 相关构件
|
||||||
|
artifact apiJar
|
||||||
|
artifact sourcesApiJar
|
||||||
|
artifact javadocApiJar
|
||||||
|
|
||||||
|
// POM 配置,便于其他模组依赖
|
||||||
|
pom {
|
||||||
|
name = "${mod_name} API"
|
||||||
|
description = "The API for ${mod_name}"
|
||||||
|
url = "https://github.com/3944Realms/SuperLeadMod"
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = mod_license
|
||||||
|
url = "https://opensource.org/licenses/MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = "r3944realms"
|
||||||
|
name = mod_authors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file://${project.projectDir}/mcmodsrepo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 构建任务依赖 ==========
|
||||||
|
// 确保构建任务包含 API Jar
|
||||||
|
tasks.named('build') {
|
||||||
|
dependsOn apiJar, sourcesApiJar, javadocApiJar
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理任务
|
||||||
|
tasks.named('clean') {
|
||||||
|
delete fileTree(dir: "${project.projectDir}/mcmodsrepo")
|
||||||
|
}
|
||||||
|
|
||||||
tasks.register("runWithRenderDoc", Exec) {
|
tasks.register("runWithRenderDoc", Exec) {
|
||||||
group = "minecraft"
|
group = "minecraft"
|
||||||
description = "Run Minecraft with RenderDoc using runClientAuth configuration"
|
description = "Run Minecraft with RenderDoc using runClientAuth configuration"
|
||||||
|
|
@ -314,7 +419,6 @@ tasks.register("runWithRenderDoc", Exec) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// IDEA 支持
|
// IDEA 支持
|
||||||
idea {
|
idea {
|
||||||
module {
|
module {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ neoForge.parchment.mappingsVersion=2023.09.03
|
||||||
enableProguard=false
|
enableProguard=false
|
||||||
# Jei Version
|
# Jei Version
|
||||||
jei_version=15.20.0.112
|
jei_version=15.20.0.112
|
||||||
|
#Other Mods Version
|
||||||
|
player_anim_version=1.0.2-rc1+1.20
|
||||||
|
geckolib_version=4.2.1
|
||||||
|
curios_version=5.5.0+1.20.1
|
||||||
## Environment Properties
|
## Environment Properties
|
||||||
|
|
||||||
# The Minecraft version must agree with the Forge version to get a valid artifact
|
# The Minecraft version must agree with the Forge version to get a valid artifact
|
||||||
|
|
@ -55,7 +59,7 @@ mod_name=Super Lead Rope
|
||||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||||
mod_license=GPLv3
|
mod_license=GPLv3
|
||||||
# The mod version. See https://semver.org/
|
# The mod version. See https://semver.org/
|
||||||
mod_version=0.0.0.3
|
mod_version=0.0.0.4
|
||||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
# 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.
|
# This should match the base package used for the mod sources.
|
||||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,9 @@ import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.Pose;
|
import net.minecraft.world.entity.Pose;
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.vehicle.Boat;
|
|
||||||
import net.minecraft.world.entity.vehicle.Minecart;
|
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
import net.minecraft.world.item.CreativeModeTabs;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
@ -53,14 +50,16 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
||||||
import top.r3944realms.superleadrope.config.LeashConfigManager;
|
import top.r3944realms.superleadrope.config.LeashConfigManager;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityRemainder;
|
import top.r3944realms.superleadrope.content.capability.CapabilityRemainder;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
import top.r3944realms.superleadrope.content.command.MotionCommand;
|
import top.r3944realms.superleadrope.content.command.MotionCommand;
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||||
|
|
@ -74,8 +73,8 @@ import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||||
import top.r3944realms.superleadrope.core.util.PotatoMode;
|
import top.r3944realms.superleadrope.core.util.PotatoMode;
|
||||||
import top.r3944realms.superleadrope.core.util.PotatoModeHelper;
|
import top.r3944realms.superleadrope.core.util.PotatoModeHelper;
|
||||||
import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue;
|
import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashStateAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashStateInnerAPI;
|
||||||
import top.r3944realms.superleadrope.util.model.RidingRelationship;
|
import top.r3944realms.superleadrope.util.model.RidingRelationship;
|
||||||
import top.r3944realms.superleadrope.util.riding.RidingApplier;
|
import top.r3944realms.superleadrope.util.riding.RidingApplier;
|
||||||
import top.r3944realms.superleadrope.util.riding.RidingDismounts;
|
import top.r3944realms.superleadrope.util.riding.RidingDismounts;
|
||||||
|
|
@ -97,8 +96,8 @@ public class CommonEventHandler {
|
||||||
Entity entity = event.getEntity();
|
Entity entity = event.getEntity();
|
||||||
if (entity.level().isClientSide) return;
|
if (entity.level().isClientSide) return;
|
||||||
if (LeashDataImpl.isLeashable(entity)) {
|
if (LeashDataImpl.isLeashable(entity)) {
|
||||||
LeashDataAPI.getLeashData(entity).ifPresent(LeashSyncManager.Data::track);
|
LeashDataInnerAPI.getLeashData(entity).ifPresent(LeashSyncManager.Data::track);
|
||||||
LeashStateAPI.getLeashState(entity).ifPresent(LeashSyncManager.State::track);
|
LeashStateInnerAPI.getLeashState(entity).ifPresent(LeashSyncManager.State::track);
|
||||||
if (entity instanceof ServerPlayer serverPlayer) {
|
if (entity instanceof ServerPlayer serverPlayer) {
|
||||||
LeashSyncManager.Data.forEach(i -> {
|
LeashSyncManager.Data.forEach(i -> {
|
||||||
if (i.isLeashedBy(serverPlayer) && i.isInDelayedLeash(serverPlayer.getUUID())) {
|
if (i.isLeashedBy(serverPlayer) && i.isInDelayedLeash(serverPlayer.getUUID())) {
|
||||||
|
|
@ -121,8 +120,8 @@ public class CommonEventHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
LeashDataAPI.getLeashData(entity).ifPresent(LeashSyncManager.Data::untrack);
|
LeashDataInnerAPI.getLeashData(entity).ifPresent(LeashSyncManager.Data::untrack);
|
||||||
LeashStateAPI.getLeashState(entity).ifPresent(LeashSyncManager.State::untrack);
|
LeashStateInnerAPI.getLeashState(entity).ifPresent(LeashSyncManager.State::untrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
|
@ -157,6 +156,12 @@ public class CommonEventHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ServerLevel getServerLevel() {
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerLevel sl;
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onServerStarting(ServerStartingEvent event) {
|
public static void onServerStarting(ServerStartingEvent event) {
|
||||||
PotatoMode mode = PotatoModeHelper.getCurrentMode();
|
PotatoMode mode = PotatoModeHelper.getCurrentMode();
|
||||||
|
|
@ -169,6 +174,7 @@ public class CommonEventHandler {
|
||||||
if (serverLevel.dimension() == Level.OVERWORLD) {
|
if (serverLevel.dimension() == Level.OVERWORLD) {
|
||||||
EternalPotatoFacade.initSavedData(serverLevel);
|
EternalPotatoFacade.initSavedData(serverLevel);
|
||||||
RidingSaver.setEntityProvider(serverLevel::getEntity);
|
RidingSaver.setEntityProvider(serverLevel::getEntity);
|
||||||
|
sl = serverLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +185,7 @@ public class CommonEventHandler {
|
||||||
// 只在主世界卸载时清空
|
// 只在主世界卸载时清空
|
||||||
if (serverLevel.dimension() == Level.OVERWORLD) {
|
if (serverLevel.dimension() == Level.OVERWORLD) {
|
||||||
EternalPotatoFacade.clear();
|
EternalPotatoFacade.clear();
|
||||||
|
sl = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -256,10 +263,10 @@ public class CommonEventHandler {
|
||||||
if (!(level instanceof ServerLevel serverLevel)) return;
|
if (!(level instanceof ServerLevel serverLevel)) return;
|
||||||
|
|
||||||
// 获取范围内可被拴住实体
|
// 获取范围内可被拴住实体
|
||||||
List<Entity> entities = LeashDataImpl.leashableInArea(telEntity);
|
List<Entity> entities = SuperLeadRopeApi.leashableInArea(telEntity);
|
||||||
//规则关闭则禁止
|
//规则关闭则禁止
|
||||||
if(!SLPGameruleRegistry.getGameruleBoolValue(event.getEntity().level(), TeleportWithLeashedEntities.ID)) {
|
if(!SLPGameruleRegistry.getGameruleBoolValue(event.getEntity().level(), TeleportWithLeashedEntities.ID)) {
|
||||||
entities.forEach(entity -> LeashDataAPI.LeashOperations.detach(entity, telEntity));
|
entities.forEach(entity -> LeashDataInnerAPI.LeashOperations.detach(entity, telEntity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Entity beLeashedEntity : entities) {
|
for (Entity beLeashedEntity : entities) {
|
||||||
|
|
@ -270,8 +277,8 @@ public class CommonEventHandler {
|
||||||
float originalPitch = beLeashedEntity.getXRot();
|
float originalPitch = beLeashedEntity.getXRot();
|
||||||
Vec3 originalDeltaMovement = beLeashedEntity.getDeltaMovement();
|
Vec3 originalDeltaMovement = beLeashedEntity.getDeltaMovement();
|
||||||
|
|
||||||
AtomicReference<ILeashData.LeashInfo> originalLeashInfo = new AtomicReference<>();
|
AtomicReference<LeashInfo> originalLeashInfo = new AtomicReference<>();
|
||||||
LeashDataAPI.getLeashData(beLeashedEntity).ifPresent(data -> {
|
LeashDataInnerAPI.getLeashData(beLeashedEntity).ifPresent(data -> {
|
||||||
originalLeashInfo.set(data.getLeashInfo(telEntity).orElse(null));
|
originalLeashInfo.set(data.getLeashInfo(telEntity).orElse(null));
|
||||||
data.removeLeash(telEntity);
|
data.removeLeash(telEntity);
|
||||||
});
|
});
|
||||||
|
|
@ -306,10 +313,10 @@ public class CommonEventHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 将holder替换 ---
|
// --- 将holder替换 ---
|
||||||
ILeashData.LeashInfo leashInfo = Optional.ofNullable(originalLeashInfo.get())
|
LeashInfo leashInfo = Optional.ofNullable(originalLeashInfo.get())
|
||||||
.orElse(ILeashData.LeashInfo.EMPTY);
|
.orElse(LeashInfo.EMPTY);
|
||||||
|
|
||||||
LeashDataAPI.LeashOperations.attachWithInfo(beLeashedEntity, telEntity, leashInfo);
|
LeashDataInnerAPI.LeashOperations.attachWithInfo(beLeashedEntity, telEntity, leashInfo);
|
||||||
|
|
||||||
// --- 重新应用骑乘关系,仅保留白名单根载具 ---
|
// --- 重新应用骑乘关系,仅保留白名单根载具 ---
|
||||||
RidingRelationship filteredRelationship = RidingSaver.filterByWhitelistRoot(originalRidingRelationship);
|
RidingRelationship filteredRelationship = RidingSaver.filterByWhitelistRoot(originalRidingRelationship);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||||
import top.r3944realms.superleadrope.util.file.ConfigUtil;
|
import top.r3944realms.superleadrope.util.file.ConfigUtil;
|
||||||
|
|
||||||
@Mod(value = SuperLeadRope.MOD_ID)
|
@Mod(value = SuperLeadRope.MOD_ID)
|
||||||
|
//TODO: API规范化
|
||||||
public class SuperLeadRope {
|
public class SuperLeadRope {
|
||||||
public static final Logger logger = LoggerFactory.getLogger(SuperLeadRope.class);
|
public static final Logger logger = LoggerFactory.getLogger(SuperLeadRope.class);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api;
|
||||||
|
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
|
|
||||||
|
public class SLPCapability {
|
||||||
|
public static final Capability<ILeashData> LEASH_DATA_CAP = CapabilityManager.get(new CapabilityToken<>(){});
|
||||||
|
public static final Capability<ILeashState> LEASH_STATE_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import top.r3944realms.superleadrope.api.type.util.ILeashHelper;
|
||||||
|
import top.r3944realms.superleadrope.api.workspace.Services;
|
||||||
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class SuperLeadRopeApi {
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger(SuperLeadRopeApi.class);
|
||||||
|
public static String MOD_ID = "superleadrope";
|
||||||
|
public static ILeashHelper getLeashHelper() {
|
||||||
|
return Services.WORK_SPACE.getLeashHelper();
|
||||||
|
}
|
||||||
|
public static @NotNull List<Entity> leashableInArea(Level pLevel, Vec3 pPos, Predicate<Entity> filter) {
|
||||||
|
return leashableInArea(pLevel, pPos, filter, 1024D);
|
||||||
|
}
|
||||||
|
public static @NotNull List<Entity> leashableInArea(@NotNull Entity entity, Predicate<Entity> filter, double fetchDistance) {
|
||||||
|
return leashableInArea(entity.level(), entity.getBoundingBox().getCenter(), filter, fetchDistance);
|
||||||
|
}
|
||||||
|
public static @NotNull List<Entity> leashableInArea(@NotNull Level pLevel, Vec3 pPos, Predicate<Entity> filter, double fetchDistance) {
|
||||||
|
return Services.WORK_SPACE.leashableInArea(pLevel, pPos, filter, fetchDistance);
|
||||||
|
}
|
||||||
|
public static @NotNull List<Entity> leashableInArea(Entity entity, Predicate<Entity> filter) {
|
||||||
|
return leashableInArea(entity, filter, 1024D);
|
||||||
|
}
|
||||||
|
public static @NotNull List<Entity> leashableInArea(Entity holder) {
|
||||||
|
return leashableInArea(holder, i -> isLeashHolder(i, holder), 1024D);
|
||||||
|
}
|
||||||
|
public static boolean isSuperLeadKnot(Entity entity) {
|
||||||
|
return Services.WORK_SPACE.isSuperLeadKnot(entity);
|
||||||
|
}
|
||||||
|
public static BlockPos getSuperLeadKnotPos(Entity entity) {
|
||||||
|
return Services.WORK_SPACE.getSuperLeadPos(entity);
|
||||||
|
}
|
||||||
|
public static boolean isLeashable(Entity entity) {
|
||||||
|
return Services.WORK_SPACE.isLeashable(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLeashHolder(@NotNull Entity pEntity, Entity pTestHolder) {
|
||||||
|
return pTestHolder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
|
isLeashHolder(pEntity, superLeashKnotEntity.getPos()) :
|
||||||
|
isLeashHolder(pEntity, pTestHolder.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLeashHolder(@NotNull Entity pEntity, UUID pHolderUUID) {
|
||||||
|
return LeashDataInnerAPI.getLeashData(pEntity)
|
||||||
|
.map(leashData -> leashData.isLeashedBy(pHolderUUID))
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLeashHolder(@NotNull Entity pEntity, BlockPos pKnotPos) {
|
||||||
|
return LeashDataInnerAPI.getLeashData(pEntity)
|
||||||
|
.map(leashData -> leashData.isLeashedBy(pKnotPos))
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.event;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraftforge.eventbus.api.Cancelable;
|
||||||
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
import net.minecraftforge.fml.event.IModBusEvent;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public abstract class SuperLeadRopeEvent extends Event implements IModBusEvent {
|
||||||
|
private final Entity LeashedEntity;
|
||||||
|
|
||||||
|
protected SuperLeadRopeEvent(Entity leashedEntity) {
|
||||||
|
LeashedEntity = leashedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entity getLeashedEntity() {
|
||||||
|
return LeashedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cancelable
|
||||||
|
public static class AddLeash extends SuperLeadRopeEvent {
|
||||||
|
private final Entity holderEntity;
|
||||||
|
@Nullable
|
||||||
|
private final Double maxLeashDistance;
|
||||||
|
@Nullable
|
||||||
|
private final Double elasticDistanceScale;
|
||||||
|
protected AddLeash(Entity leashedEntity, Entity holderEntity) {
|
||||||
|
super(leashedEntity);
|
||||||
|
this.holderEntity = holderEntity;
|
||||||
|
this.maxLeashDistance = null;
|
||||||
|
this.elasticDistanceScale = null;
|
||||||
|
}
|
||||||
|
public Entity getHolderEntity() {
|
||||||
|
return holderEntity;
|
||||||
|
}
|
||||||
|
public @Nullable Double getMaxLeashDistance() {
|
||||||
|
return maxLeashDistance;
|
||||||
|
}
|
||||||
|
public @Nullable Double getElasticDistanceScale() {
|
||||||
|
return elasticDistanceScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ADD LEASH
|
||||||
|
|
||||||
|
// TRANSFORM LEASH
|
||||||
|
|
||||||
|
// REMOVE LEASH
|
||||||
|
|
||||||
|
// MODIFY LEASH MAX_LEASH_LENGTH / ELASTIC_DISTANCE_SCALE
|
||||||
|
|
||||||
|
// HAS FOCUS
|
||||||
|
|
||||||
|
// KEEP NOT BREAK TICK
|
||||||
|
|
||||||
|
// TELEPORT
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.type.capabilty;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capability interface for managing leash data of entities and knots.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface ILeashData extends INBTSerializable<CompoundTag> {
|
||||||
|
Double getStaticMaxDistance();
|
||||||
|
void setStaticMaxDistance(Double distance);
|
||||||
|
double getDefaultMaxDistance();
|
||||||
|
double getCurrentMaxDistance();
|
||||||
|
void updateAllMaxDistance();
|
||||||
|
Double getStaticElasticDistanceScale();
|
||||||
|
void setStaticElasticDistanceScale(Double distance);
|
||||||
|
double getDefaultElasticDistanceScale();
|
||||||
|
double getCurrentElasticDistanceScale();
|
||||||
|
void updateAllElasticDistanceScale();
|
||||||
|
default void updateAll() {
|
||||||
|
updateAllMaxDistance();
|
||||||
|
updateAllElasticDistanceScale();
|
||||||
|
}
|
||||||
|
/* ----------------------
|
||||||
|
* Add / removeApplyEntity leashes
|
||||||
|
* ---------------------- */
|
||||||
|
boolean addLeash(Entity holder);
|
||||||
|
boolean addLeash(Entity holder, String reserved);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, int maxKeepTicks);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, String reserved);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance, String reserved);
|
||||||
|
boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
void addLeash(Entity holder, LeashInfo info);
|
||||||
|
|
||||||
|
void addDelayedLeash(Player holderPlayer);
|
||||||
|
void removeDelayedLeash(UUID onceHolderPlayerUUID);
|
||||||
|
|
||||||
|
boolean removeLeash(Entity holder);
|
||||||
|
boolean removeLeash(UUID holderUUID);
|
||||||
|
boolean removeLeash(BlockPos knotPos);
|
||||||
|
|
||||||
|
void removeAllLeashes();
|
||||||
|
void removeAllHolderLeashes();
|
||||||
|
void removeAllKnotLeashes();
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Modify leash properties
|
||||||
|
* ---------------------- */
|
||||||
|
boolean setMaxDistance(Entity holder, Double distance);
|
||||||
|
boolean setMaxDistance(Entity holder, Double distance, int maxKeepTicks);
|
||||||
|
boolean setMaxDistance(Entity holder, Double distance, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
boolean setMaxDistance(UUID holderUUID, Double distance);
|
||||||
|
boolean setMaxDistance(UUID holderUUID, Double distance, int maxKeepTicks);
|
||||||
|
boolean setMaxDistance(UUID holderUUID, Double distance, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
boolean setMaxDistance(BlockPos knotPos, Double distance);
|
||||||
|
boolean setMaxDistance(BlockPos knotPos, Double distance, int maxKeepTicks);
|
||||||
|
boolean setMaxDistance(BlockPos knotPos, Double distance, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
boolean setElasticDistanceScale(Entity holder, Double scale);
|
||||||
|
boolean setElasticDistanceScale(Entity holder, Double scale, int maxKeepTicks);
|
||||||
|
boolean setElasticDistanceScale(Entity holder, Double scale, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
boolean setElasticDistanceScale(UUID holderUUID, Double scale);
|
||||||
|
boolean setElasticDistanceScale(UUID holderUUID, Double scale, int maxKeepTicks);
|
||||||
|
boolean setElasticDistanceScale(UUID holderUUID, Double scale, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
boolean setElasticDistanceScale(BlockPos knotPos, Double scale);
|
||||||
|
boolean setElasticDistanceScale(BlockPos knotPos, Double scale, int maxKeepTicks);
|
||||||
|
boolean setElasticDistanceScale(BlockPos knotPos, Double scale, int maxKeepTicks, String reserved);
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Apply physics
|
||||||
|
* ---------------------- */
|
||||||
|
void applyLeashForces();
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Transfer leash holders
|
||||||
|
* ---------------------- */
|
||||||
|
boolean transferLeash(Entity holder, Entity newHolder);
|
||||||
|
boolean transferLeash(Entity holder, Entity newHolder, String reserved);
|
||||||
|
|
||||||
|
boolean transferLeash(UUID holderUUID, Entity newHolder);
|
||||||
|
boolean transferLeash(UUID holderUUID, Entity newHolder, String reserved);
|
||||||
|
|
||||||
|
boolean transferLeash(BlockPos knotPos, Entity newHolder);
|
||||||
|
boolean transferLeash(BlockPos knotPos, Entity newHolder, String reserved);
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Query state
|
||||||
|
* ---------------------- */
|
||||||
|
boolean hasLeash();
|
||||||
|
boolean hasKnotLeash();
|
||||||
|
boolean hasHolderLeash();
|
||||||
|
|
||||||
|
Collection<LeashInfo> getAllLeashes();
|
||||||
|
|
||||||
|
boolean isLeashedBy(Entity holder);
|
||||||
|
boolean isLeashedBy(UUID holderUUID);
|
||||||
|
boolean isLeashedBy(BlockPos knotPos);
|
||||||
|
|
||||||
|
boolean isInDelayedLeash(UUID holderUUID);
|
||||||
|
|
||||||
|
Optional<LeashInfo> getLeashInfo(Entity holder);
|
||||||
|
Optional<LeashInfo> getLeashInfo(UUID holderUUID);
|
||||||
|
Optional<LeashInfo> getLeashInfo(BlockPos knotPos);
|
||||||
|
|
||||||
|
boolean canBeLeashed();
|
||||||
|
boolean canBeAttachedTo(Entity entity);
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Occupy / sync
|
||||||
|
* ---------------------- */
|
||||||
|
/**
|
||||||
|
* 抢占位(已离线玩家)。
|
||||||
|
* 用于解决玩家下线后所持有对象会移除持有者的问题(实际上是占用个弱集合)
|
||||||
|
*/
|
||||||
|
Optional<UUID> occupyLeash();
|
||||||
|
|
||||||
|
void markForSync();
|
||||||
|
void immediateSync();
|
||||||
|
void checkSync();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package top.r3944realms.superleadrope.content.capability.inter;
|
package top.r3944realms.superleadrope.api.type.capabilty;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
|
@ -0,0 +1,347 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.type.capabilty;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Data record
|
||||||
|
* ---------------------- */
|
||||||
|
@SuppressWarnings({"RegExpRedundantEscape", "DuplicatedCode"})
|
||||||
|
public record LeashInfo(
|
||||||
|
Optional<BlockPos> blockPosOpt,
|
||||||
|
Optional<UUID> holderUUIDOpt,
|
||||||
|
Optional<Integer> holderIdOpt, // Only for client side use
|
||||||
|
Set<String> marks, // 标记字段
|
||||||
|
String reserved, // 保留字段
|
||||||
|
Double maxDistance, // 最大距离 (可null,null则用全局&默认)
|
||||||
|
Double elasticDistanceScale, // 弹性距离比例 (可null,null则用全局&默认)
|
||||||
|
int keepLeashTicks, // 剩余 Tick 数
|
||||||
|
int maxKeepLeashTicks // 最大保持 Tick 数
|
||||||
|
) {
|
||||||
|
// 预定义的标记常量
|
||||||
|
public static final String MARK_NOT_UPDATE = "NOT_UPDATE";
|
||||||
|
public static final String MARK_ONLY_NOT_UPDATE_MAX_DISTANCE = "NOT_UPDATE_MAX_DISTANCE";
|
||||||
|
public static final String MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE = "NOT_UPDATE_ELASTIC_DISTANCE_SCALE";
|
||||||
|
|
||||||
|
public static final LeashInfo EMPTY = new LeashInfo(
|
||||||
|
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||||
|
Set.of(), "", 12.0D, 6.0D, 0, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
/* ---------- Factory ---------- */
|
||||||
|
public static LeashInfo create(
|
||||||
|
Entity entity,
|
||||||
|
Set<String> marks,
|
||||||
|
String reserved,
|
||||||
|
Double maxDistance,
|
||||||
|
Double elasticDistanceScale,
|
||||||
|
int keepTicks,
|
||||||
|
int maxKeepTicks
|
||||||
|
) {
|
||||||
|
return SuperLeadRopeApi.isSuperLeadKnot(entity)
|
||||||
|
? new LeashInfo(SuperLeadRopeApi.getSuperLeadKnotPos(entity), entity.getId(), marks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks)
|
||||||
|
: new LeashInfo(entity.getUUID(), entity.getId(), marks, reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向后兼容的工厂方法
|
||||||
|
public static LeashInfo create(
|
||||||
|
Entity entity,
|
||||||
|
String reserved,
|
||||||
|
Double maxDistance,
|
||||||
|
Double elasticDistanceScale,
|
||||||
|
int keepTicks,
|
||||||
|
int maxKeepTicks
|
||||||
|
) {
|
||||||
|
return create(entity, Set.of(), reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo(UUID holderUUID, int holderId, String reserved,
|
||||||
|
Double maxDistance, Double elasticDistanceScale, int keepTicks, int maxKeepTicks) {
|
||||||
|
this(Optional.empty(), Optional.of(holderUUID), Optional.of(holderId),
|
||||||
|
Set.of(), reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo(UUID holderUUID, int holderId, Set<String> marks, String reserved,
|
||||||
|
Double maxDistance, Double elasticDistanceScale, int keepTicks, int maxKeepTicks) {
|
||||||
|
this(Optional.empty(), Optional.of(holderUUID), Optional.of(holderId),
|
||||||
|
marks, reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo(BlockPos knotPos, int holderId, String reserved,
|
||||||
|
Double maxDistance, Double elasticDistanceScale, int keepTicks, int maxKeepTicks) {
|
||||||
|
this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId),
|
||||||
|
Set.of(), reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo(BlockPos knotPos, int holderId, Set<String> marks, String reserved,
|
||||||
|
Double maxDistance, Double elasticDistanceScale, int keepTicks, int maxKeepTicks) {
|
||||||
|
this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId),
|
||||||
|
marks, reserved, maxDistance, elasticDistanceScale, keepTicks, maxKeepTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- State updates ---------- */
|
||||||
|
public LeashInfo decrementKeepTicks() {
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, marks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale,
|
||||||
|
Math.max(0, keepLeashTicks - 1), maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo resetKeepTicks() {
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, marks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale,
|
||||||
|
maxKeepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo transferHolder(Entity entity) {
|
||||||
|
return transferHolder(entity, reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo transferHolder(Entity entity, String newReserved) {
|
||||||
|
boolean isKnot = SuperLeadRopeApi.isSuperLeadKnot(entity);
|
||||||
|
return new LeashInfo(
|
||||||
|
isKnot ? Optional.of(SuperLeadRopeApi.getSuperLeadKnotPos(entity)) : Optional.empty(),
|
||||||
|
!isKnot ? Optional.of(entity.getUUID()) : Optional.empty(),
|
||||||
|
Optional.of(entity.getId()),
|
||||||
|
marks, newReserved, maxDistance, elasticDistanceScale,
|
||||||
|
keepLeashTicks, maxKeepLeashTicks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改保留字段
|
||||||
|
*/
|
||||||
|
public LeashInfo withReserved(String newReserved) {
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, marks, newReserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改标记集合
|
||||||
|
*/
|
||||||
|
public LeashInfo withMarks(Set<String> newMarks) {
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, Set.copyOf(newMarks), reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 标记管理方法(基于Set的新实现) ---------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加无需更新标记(如果不存在则添加)
|
||||||
|
*/
|
||||||
|
public LeashInfo markNotUpdate() {
|
||||||
|
return hasMark(MARK_NOT_UPDATE) ? this : addMark(MARK_NOT_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo markNotUpdateDistance() {
|
||||||
|
if (hasMark(MARK_NOT_UPDATE)) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
if (hasMark(MARK_ONLY_NOT_UPDATE_MAX_DISTANCE)) {
|
||||||
|
return this;
|
||||||
|
} else if (hasMark(MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE)) {
|
||||||
|
return this.removeMark(MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE).addMark(MARK_NOT_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.addMark(MARK_ONLY_NOT_UPDATE_MAX_DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeashInfo markNotUpdateScale() {
|
||||||
|
if (hasMark(MARK_NOT_UPDATE)) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
if (hasMark(MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE)) {
|
||||||
|
return this;
|
||||||
|
} else if (hasMark(MARK_ONLY_NOT_UPDATE_MAX_DISTANCE)) {
|
||||||
|
return this.removeMark(MARK_ONLY_NOT_UPDATE_MAX_DISTANCE).addMark(MARK_NOT_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.addMark(MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除无需更新标记
|
||||||
|
*/
|
||||||
|
public LeashInfo unmarkNotUpdate() {
|
||||||
|
return removeMarks(MARK_NOT_UPDATE, MARK_ONLY_NOT_UPDATE_MAX_DISTANCE, MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除无需更新距离标记
|
||||||
|
*/
|
||||||
|
public LeashInfo unmarkNotUpdateDistance() {
|
||||||
|
return removeMarks(MARK_NOT_UPDATE, MARK_ONLY_NOT_UPDATE_MAX_DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除无需更新比例标记
|
||||||
|
*/
|
||||||
|
public LeashInfo unmarkNotUpdateScale() {
|
||||||
|
return removeMarks(MARK_NOT_UPDATE, MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含无需更新标记
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
|
public boolean isNotUpdate() {
|
||||||
|
return hasMark(MARK_NOT_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需距离更新标记
|
||||||
|
*/
|
||||||
|
public boolean isNeedUpdateDistance() {
|
||||||
|
return !isNotUpdate() && !hasMark(MARK_ONLY_NOT_UPDATE_MAX_DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需比例更新
|
||||||
|
*/
|
||||||
|
public boolean isNeedUpdateScale() {
|
||||||
|
return !isNotUpdate() && !hasMark(MARK_ONLY_NOT_UPDATE_ELASTIC_DISTANCE_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加标记(如果不存在则添加)
|
||||||
|
*/
|
||||||
|
public LeashInfo addMark(String mark) {
|
||||||
|
if (marks.contains(mark)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Set<String> newMarks = new HashSet<>(marks);
|
||||||
|
newMarks.add(mark);
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, newMarks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加多个标记(自动检测并跳过重复标记)
|
||||||
|
*/
|
||||||
|
public LeashInfo addMarks(String @NotNull ... marksToAdd) {
|
||||||
|
Set<String> newMarks = new HashSet<>(marks);
|
||||||
|
boolean changed = false;
|
||||||
|
for (String mark : marksToAdd) {
|
||||||
|
if (newMarks.add(mark)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed ? new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, newMarks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加多个标记(集合版本)
|
||||||
|
*/
|
||||||
|
public LeashInfo addMarks(@NotNull Collection<String> marksToAdd) {
|
||||||
|
return addMarks(marksToAdd.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除单个标记
|
||||||
|
*/
|
||||||
|
public LeashInfo removeMark(String mark) {
|
||||||
|
if (!marks.contains(mark)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Set<String> newMarks = new HashSet<>(marks);
|
||||||
|
newMarks.remove(mark);
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, newMarks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除多个标记
|
||||||
|
*/
|
||||||
|
public LeashInfo removeMarks(String @NotNull ... marksToRemove) {
|
||||||
|
Set<String> newMarks = new HashSet<>(marks);
|
||||||
|
boolean changed = false;
|
||||||
|
for (String mark : marksToRemove) {
|
||||||
|
if (newMarks.remove(mark)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed ? new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, newMarks, reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除多个标记(集合版本)
|
||||||
|
*/
|
||||||
|
public LeashInfo removeMarks(@NotNull Collection<String> marksToRemove) {
|
||||||
|
return removeMarks(marksToRemove.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含指定标记
|
||||||
|
*/
|
||||||
|
public boolean hasMark(String mark) {
|
||||||
|
return marks.contains(mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含所有指定标记
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
public boolean hasAllMarks(String @NotNull ... marksToCheck) {
|
||||||
|
for (String mark : marksToCheck) {
|
||||||
|
if (!marks.contains(mark)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含任意指定标记
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
public boolean hasAnyMark(String @NotNull ... marksToCheck) {
|
||||||
|
for (String mark : marksToCheck) {
|
||||||
|
if (marks.contains(mark)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有标记(不可修改的视图)
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
public @Unmodifiable Set<String> getMarks() {
|
||||||
|
return Set.copyOf(marks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有标记
|
||||||
|
*/
|
||||||
|
public LeashInfo clearAllMarks() {
|
||||||
|
if (marks.isEmpty()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, Set.of(), reserved,
|
||||||
|
maxDistance, elasticDistanceScale, keepLeashTicks, maxKeepLeashTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,319 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.type.util;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public interface ILeashHelper {
|
||||||
|
IHolder getHolderHelper(Entity holder);
|
||||||
|
ILeashed getLeashedHelper(Entity leashed);
|
||||||
|
interface IHolder {
|
||||||
|
Entity getHolderEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该实体持有的所有拴绳数据
|
||||||
|
*/
|
||||||
|
Set<ILeashData> getAllLeashData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该实体持有的拴绳数量
|
||||||
|
*/
|
||||||
|
default int getLeashCount() {
|
||||||
|
return getAllLeashData().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否持有任何拴绳
|
||||||
|
*/
|
||||||
|
default boolean hasLeashes() {
|
||||||
|
return !getAllLeashData().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放所有持有的拴绳
|
||||||
|
*/
|
||||||
|
default void releaseAllLeashes() {
|
||||||
|
getAllLeashData().forEach(i -> i.removeLeash(getHolderEntity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否持有特定实体的拴绳
|
||||||
|
*/
|
||||||
|
default boolean isHoldingLeash(Entity entity) {
|
||||||
|
return getAllLeashData().stream().anyMatch(i -> i.isLeashedBy(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否持有特定实体的拴绳
|
||||||
|
*/
|
||||||
|
default boolean isHoldingLeash(UUID uuid) {
|
||||||
|
return getAllLeashData().stream().anyMatch(i -> i.isLeashedBy(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否持有特定实体的拴绳
|
||||||
|
*/
|
||||||
|
default boolean isHoldingLeash(BlockPos blockPos) {
|
||||||
|
return getAllLeashData().stream().anyMatch(i -> i.isLeashedBy(blockPos));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 拴住另一个实体
|
||||||
|
*/
|
||||||
|
default boolean leashEntity(Entity target) {
|
||||||
|
if (SuperLeadRopeApi.isLeashable(target)) {
|
||||||
|
if (isHoldingLeash(target)) {
|
||||||
|
return false;
|
||||||
|
} else return leashEntity(target.getUUID());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean leashEntity(UUID uuid);
|
||||||
|
/**
|
||||||
|
* 解拴另一个实体
|
||||||
|
*/
|
||||||
|
default boolean unleashEntity(Entity target) {
|
||||||
|
if (SuperLeadRopeApi.isLeashable(target)) {
|
||||||
|
if (!isHoldingLeash(target)) {
|
||||||
|
return false;
|
||||||
|
} else return unleashEntity(target.getUUID());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean unleashEntity(UUID uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILeashed {
|
||||||
|
/**
|
||||||
|
* 获取该实体的拴绳数据
|
||||||
|
*/
|
||||||
|
ILeashData getLeashData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定拴绳到实体
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder) {
|
||||||
|
return getLeashData().addLeash(holder);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 绑定拴绳到实体
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder, String reserved) {
|
||||||
|
return getLeashData().addLeash(holder, reserved);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 绑定拴绳并设置参数
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder, Double maxDistance, Double elasticDistanceScale) {
|
||||||
|
return getLeashData().addLeash(holder, maxDistance, elasticDistanceScale);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 绑定拴绳并设置参数
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, String reserved) {
|
||||||
|
return getLeashData().addLeash(holder, maxDistance, elasticDistanceScale, reserved);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 绑定拴绳并设置参数
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, int maxKeepTicks) {
|
||||||
|
return getLeashData().addLeash(holder, maxDistance, elasticDistanceScale, maxKeepTicks);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 绑定拴绳并设置参数
|
||||||
|
*/
|
||||||
|
default boolean attachLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, int maxKeepTicks, String reserved) {
|
||||||
|
return getLeashData().addLeash(holder, maxDistance, elasticDistanceScale, maxKeepTicks, reserved);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解绑拴绳(自动判断类型)
|
||||||
|
*/
|
||||||
|
default boolean detachLeash(Entity entity) {
|
||||||
|
return getLeashData().removeLeash(entity);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解绑拴绳
|
||||||
|
*/
|
||||||
|
default boolean detachLeash(UUID uuid) {
|
||||||
|
return getLeashData().removeLeash(uuid);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解绑拴绳
|
||||||
|
*/
|
||||||
|
default boolean detachLeash(BlockPos blockPos) {
|
||||||
|
return getLeashData().removeLeash(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑所有拴绳
|
||||||
|
*/
|
||||||
|
default void detachAllLeashes() {
|
||||||
|
getLeashData().removeAllLeashes();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解绑所有实体拴绳
|
||||||
|
*/
|
||||||
|
default void removeAllHolderLeashes() {
|
||||||
|
getLeashData().removeAllHolderLeashes();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解绑所有绳结拴绳
|
||||||
|
*/
|
||||||
|
default void removeAllKnotLeashes() {
|
||||||
|
getLeashData().removeAllKnotLeashes();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否被拴住
|
||||||
|
*/
|
||||||
|
default boolean isLeashed() {
|
||||||
|
return getLeashData().hasLeash();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否被持有者拴住
|
||||||
|
*/
|
||||||
|
default boolean hasHolderLeashed() {
|
||||||
|
return getLeashData().hasHolderLeash();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否被绳结拴住
|
||||||
|
*/
|
||||||
|
default boolean isKnotLeashed() {
|
||||||
|
return getLeashData().hasKnotLeash();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否被特定实体拴住(自动判断类型)
|
||||||
|
*/
|
||||||
|
default boolean isLeashedBy(Entity entity) {
|
||||||
|
return getLeashData().isLeashedBy(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否被特定UUID实体拴住
|
||||||
|
*/
|
||||||
|
default boolean isLeashedBy(UUID uuid) {
|
||||||
|
return getLeashData().isLeashedBy(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否被特定绳结实体拴住
|
||||||
|
*/
|
||||||
|
default boolean isLeashedBy(BlockPos blockPos) {
|
||||||
|
return getLeashData().isLeashedBy(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取拴绳信息(自动判断类型)
|
||||||
|
*/
|
||||||
|
default Optional<LeashInfo> getLeashInfo(Entity entity) {
|
||||||
|
return getLeashData().getLeashInfo(entity);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取拴绳信息
|
||||||
|
*/
|
||||||
|
default Optional<LeashInfo> getLeashInfo(UUID holderUUID) {
|
||||||
|
return getLeashData().getLeashInfo(holderUUID);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取拴绳信息
|
||||||
|
*/
|
||||||
|
default Optional<LeashInfo> getLeashInfo(BlockPos knotPos) {
|
||||||
|
return getLeashData().getLeashInfo(knotPos);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者(自动判断类型)
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(Entity fromEntity, Entity toEntity) {
|
||||||
|
return getLeashData().transferLeash(fromEntity, toEntity);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者(自动判断类型)
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(Entity fromEntity, Entity toEntity, String reserved) {
|
||||||
|
return getLeashData().transferLeash(fromEntity, toEntity, reserved);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(UUID fromEntityUUID, Entity toEntity) {
|
||||||
|
return getLeashData().transferLeash(fromEntityUUID, toEntity);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(UUID fromEntityUUID, Entity toEntity, String reserved) {
|
||||||
|
return getLeashData().transferLeash(fromEntityUUID, toEntity, reserved);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(BlockPos fromKnotBlockPos, Entity toEntity) {
|
||||||
|
return getLeashData().transferLeash(fromKnotBlockPos, toEntity);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 转移拴绳到新持有者
|
||||||
|
*/
|
||||||
|
default boolean transferLeash(BlockPos fromKnotBlockPos, Entity toEntity, String reserved) {
|
||||||
|
return getLeashData().transferLeash(fromKnotBlockPos, toEntity, reserved);
|
||||||
|
}
|
||||||
|
default boolean isInDelayedLeash(UUID holderUUID) {
|
||||||
|
return getLeashData().isInDelayedLeash(holderUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用拴绳物理效果
|
||||||
|
*/
|
||||||
|
default void applyLeashPhysics() {
|
||||||
|
getLeashData().applyLeashForces();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否可以被拴绳
|
||||||
|
*/
|
||||||
|
default boolean canBeLeashed() {
|
||||||
|
return getLeashData().canBeLeashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否可以拴到特定目标
|
||||||
|
*/
|
||||||
|
default boolean canBeAttachedTo(Entity holder) {
|
||||||
|
return getLeashData().canBeAttachedTo(holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static boolean chooseMethodWithBooleanRet(@NotNull Supplier<Boolean> cond, Supplier<Boolean> trueSupplier, Supplier<Boolean> falseSupplier) {
|
||||||
|
if (cond.get()) {
|
||||||
|
return trueSupplier.get();
|
||||||
|
}
|
||||||
|
return falseSupplier.get();
|
||||||
|
}
|
||||||
|
static void chooseMethodWithVoidRet(@NotNull Supplier<Boolean> cond, Supplier<Void> trueSupplier, Supplier<Void> falseSupplier) {
|
||||||
|
if (cond.get()) {
|
||||||
|
trueSupplier.get();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
falseSupplier.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.workspace;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.type.util.ILeashHelper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public interface IWorkSpaceHelper {
|
||||||
|
@NotNull List<Entity> leashableInArea(@NotNull Level pLevel, Vec3 pPos, Predicate<Entity> filter, double fetchDistance);
|
||||||
|
ILeashHelper getLeashHelper();
|
||||||
|
boolean isSuperLeadKnot(Entity pEntity);
|
||||||
|
BlockPos getSuperLeadPos(Entity pEntity) throws IllegalArgumentException;
|
||||||
|
boolean isLeashable(@NotNull Entity pEntity);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.api.workspace;
|
||||||
|
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
|
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
public class Services {
|
||||||
|
public static final IWorkSpaceHelper WORK_SPACE = load(IWorkSpaceHelper.class);
|
||||||
|
public static <T> T load(Class<T> clazz) {
|
||||||
|
final T loadedService = ServiceLoader.load(clazz)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
|
||||||
|
SuperLeadRopeApi.LOGGER.debug("Loaded {} for service {}", loadedService, clazz);
|
||||||
|
return loadedService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,10 +23,10 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
import top.r3944realms.superleadrope.client.renderer.resolver.SuperLeashStateResolver;
|
import top.r3944realms.superleadrope.client.renderer.resolver.SuperLeashStateResolver;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -46,17 +46,17 @@ public class LeashRenderHandler {
|
||||||
|
|
||||||
// 遍历摄像机附近所有实体
|
// 遍历摄像机附近所有实体
|
||||||
for (Entity entity : level.getEntitiesOfClass(Entity.class,
|
for (Entity entity : level.getEntitiesOfClass(Entity.class,
|
||||||
cameraEntity.getBoundingBox().inflate(100))) {
|
cameraEntity.getBoundingBox().inflate(32*16))) {
|
||||||
|
|
||||||
LeashDataAPI.getLeashData(entity).ifPresent(leashData -> {
|
LeashDataInnerAPI.getLeashData(entity).ifPresent(leashData -> {
|
||||||
for (ILeashData.LeashInfo leashInfo : leashData.getAllLeashes()) {
|
for (LeashInfo leashInfo : leashData.getAllLeashes()) {
|
||||||
renderLeashFromInfo(entity, leashInfo, poseStack, bufferSource, partialTick);
|
renderLeashFromInfo(entity, leashInfo, poseStack, bufferSource, partialTick);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderLeashFromInfo(Entity entity, ILeashData.LeashInfo leashInfo,
|
private static void renderLeashFromInfo(Entity entity, LeashInfo leashInfo,
|
||||||
PoseStack poseStack, MultiBufferSource bufferSource,
|
PoseStack poseStack, MultiBufferSource bufferSource,
|
||||||
float partialTick) {
|
float partialTick) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -76,10 +76,10 @@ public class LeashRenderHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Optional<Entity> getHolderFromLeashInfo(Level level, ILeashData.LeashInfo leashInfo) {
|
private static Optional<Entity> getHolderFromLeashInfo(Level level, LeashInfo leashInfo) {
|
||||||
if (leashInfo.blockPosOpt().isPresent()) {
|
if (leashInfo.blockPosOpt().isPresent()) {
|
||||||
BlockPos pos = leashInfo.blockPosOpt().get();
|
BlockPos pos = leashInfo.blockPosOpt().get();
|
||||||
return Optional.of(SuperLeashKnotEntity.getOrCreateKnot(level, pos));
|
return SuperLeashKnotEntity.get(level,pos).map(Entity.class::cast);
|
||||||
} else if (leashInfo.holderUUIDOpt().isPresent()) {
|
} else if (leashInfo.holderUUIDOpt().isPresent()) {
|
||||||
UUID holderUUID = leashInfo.holderUUIDOpt().get();
|
UUID holderUUID = leashInfo.holderUUIDOpt().get();
|
||||||
for (Entity e : ((ClientLevel)level).entitiesForRendering()) {
|
for (Entity e : ((ClientLevel)level).entitiesForRendering()) {
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ public class SuperLeashRenderer {
|
||||||
// 颜色渐变
|
// 颜色渐变
|
||||||
private static float[] computeColor(SuperLeashRenderState state, int index, boolean reversePass) {
|
private static float[] computeColor(SuperLeashRenderState state, int index, boolean reversePass) {
|
||||||
float distance = (float) state.startPos().distanceTo(state.endPos());
|
float distance = (float) state.startPos().distanceTo(state.endPos());
|
||||||
float ratio = Mth.clamp(distance / (state.maxDistance() * 2f), 0f, 1f);
|
float ratio = (float) Mth.clamp(distance / (state.maxDistance() * 2f), 0f, 1f);
|
||||||
|
|
||||||
// 定义颜色
|
// 定义颜色
|
||||||
float rStart = 0.42f; // 深棕 R
|
float rStart = 0.42f; // 深棕 R
|
||||||
|
|
@ -154,11 +154,11 @@ public class SuperLeashRenderer {
|
||||||
return mc.level.getBrightness(LightLayer.BLOCK, pos);
|
return mc.level.getBrightness(LightLayer.BLOCK, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getSkyLight(BlockPos pos) {
|
// private static int getSkyLight(BlockPos pos) {
|
||||||
Minecraft mc = Minecraft.getInstance();
|
// Minecraft mc = Minecraft.getInstance();
|
||||||
if (mc.level == null) return 15; // 默认亮度,防止空指针
|
// if (mc.level == null) return 15; // 默认亮度,防止空指针
|
||||||
return mc.level.getBrightness(LightLayer.SKY, pos);
|
// return mc.level.getBrightness(LightLayer.SKY, pos);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/** 横纵偏移数据 */
|
/** 横纵偏移数据 */
|
||||||
private static class Offsets {
|
private static class Offsets {
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,16 @@ import net.minecraft.world.entity.HumanoidArm;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
import top.r3944realms.superleadrope.client.renderer.state.SuperLeashRenderState;
|
import top.r3944realms.superleadrope.client.renderer.state.SuperLeashRenderState;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashStateAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashStateInnerAPI;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
//TODO: 未来实现更高级的渲染
|
//TODO: 未来实现更高级的渲染
|
||||||
public class SuperLeashStateResolver {
|
public class SuperLeashStateResolver {
|
||||||
|
|
@ -48,11 +51,11 @@ public class SuperLeashStateResolver {
|
||||||
/* ------------------------ 主解析方法 ------------------------ */
|
/* ------------------------ 主解析方法 ------------------------ */
|
||||||
|
|
||||||
public static Optional<SuperLeashRenderState> resolve(Entity holder, Entity leashedEntity,
|
public static Optional<SuperLeashRenderState> resolve(Entity holder, Entity leashedEntity,
|
||||||
ILeashData.LeashInfo leashInfo, float partialTicks) {
|
LeashInfo leashInfo, float partialTicks) {
|
||||||
|
|
||||||
if (holder == null || leashedEntity == null) return Optional.empty();
|
if (holder == null || leashedEntity == null) return Optional.empty();
|
||||||
|
|
||||||
Optional<ILeashState> leashedEntityStateOpt = LeashStateAPI.getLeashState(leashedEntity);
|
Optional<ILeashState> leashedEntityStateOpt = LeashStateInnerAPI.getLeashState(leashedEntity);
|
||||||
if (leashedEntityStateOpt.isEmpty()) return Optional.empty();
|
if (leashedEntityStateOpt.isEmpty()) return Optional.empty();
|
||||||
|
|
||||||
ILeashState leashedEntityState = leashedEntityStateOpt.get();
|
ILeashState leashedEntityState = leashedEntityStateOpt.get();
|
||||||
|
|
@ -95,7 +98,7 @@ public class SuperLeashStateResolver {
|
||||||
// 物理参数
|
// 物理参数
|
||||||
double distance = currentHolderPos.distanceTo(currentEntityPos);
|
double distance = currentHolderPos.distanceTo(currentEntityPos);
|
||||||
double maxDistance = leashInfo.maxDistance();
|
double maxDistance = leashInfo.maxDistance();
|
||||||
double elasticDistance = leashInfo.elasticDistance();
|
double elasticDistance = leashInfo.elasticDistanceScale();
|
||||||
float tension = calculateTension(distance, maxDistance, elasticDistance);
|
float tension = calculateTension(distance, maxDistance, elasticDistance);
|
||||||
float stretchRatio = (float) (distance / maxDistance);
|
float stretchRatio = (float) (distance / maxDistance);
|
||||||
boolean isCritical = distance > maxDistance * 1.5;
|
boolean isCritical = distance > maxDistance * 1.5;
|
||||||
|
|
@ -120,7 +123,7 @@ public class SuperLeashStateResolver {
|
||||||
selectColor(tension, isCritical),
|
selectColor(tension, isCritical),
|
||||||
THICKNESS_BASE + tension * THICKNESS_TENSION,
|
THICKNESS_BASE + tension * THICKNESS_TENSION,
|
||||||
swing.angle(), swing.speed(),
|
swing.angle(), swing.speed(),
|
||||||
(float) leashInfo.maxDistance(),
|
leashInfo.maxDistance(),
|
||||||
isFirstPerson, holder.blockPosition()
|
isFirstPerson, holder.blockPosition()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -129,7 +132,7 @@ public class SuperLeashStateResolver {
|
||||||
|
|
||||||
/* ------------------------ 实体偏移计算 ------------------------ */
|
/* ------------------------ 实体偏移计算 ------------------------ */
|
||||||
private static @NotNull Vec3 getEntityLeashOffset(Entity entity, ILeashState.@NotNull LeashState leashState) {
|
private static @NotNull Vec3 getEntityLeashOffset(Entity entity, ILeashState.@NotNull LeashState leashState) {
|
||||||
Optional<ILeashState> entityStateOpt = LeashStateAPI.getLeashState(entity);
|
Optional<ILeashState> entityStateOpt = LeashStateInnerAPI.getLeashState(entity);
|
||||||
Vec3 baseOffset = entityStateOpt
|
Vec3 baseOffset = entityStateOpt
|
||||||
.map(eState -> eState.getLeashApplyEntityLocationOffset()
|
.map(eState -> eState.getLeashApplyEntityLocationOffset()
|
||||||
.orElse(eState.getDefaultLeashApplyEntityLocationOffset()))
|
.orElse(eState.getDefaultLeashApplyEntityLocationOffset()))
|
||||||
|
|
@ -137,8 +140,8 @@ public class SuperLeashStateResolver {
|
||||||
return baseOffset.add(leashState.applyEntityLocationOffset());
|
return baseOffset.add(leashState.applyEntityLocationOffset());
|
||||||
}
|
}
|
||||||
private static Vec3 getHolderOffset(Entity holder, ILeashState.LeashState leashState) {
|
private static Vec3 getHolderOffset(Entity holder, ILeashState.LeashState leashState) {
|
||||||
if (LeashStateAPI.Query.hasLeashState(holder)) {
|
if (LeashStateInnerAPI.Query.hasLeashState(holder)) {
|
||||||
Optional<ILeashState> holderStateOpt = LeashStateAPI.getLeashState(holder);
|
Optional<ILeashState> holderStateOpt = LeashStateInnerAPI.getLeashState(holder);
|
||||||
if (holderStateOpt.isPresent()) {
|
if (holderStateOpt.isPresent()) {
|
||||||
ILeashState holderState = holderStateOpt.get();
|
ILeashState holderState = holderStateOpt.get();
|
||||||
return holderState.getLeashApplyEntityLocationOffset()
|
return holderState.getLeashApplyEntityLocationOffset()
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ public record SuperLeashRenderState(
|
||||||
float thickness, // 线宽(根据张力变化)
|
float thickness, // 线宽(根据张力变化)
|
||||||
float swingAngle, // 当前摆动角度(弧度)
|
float swingAngle, // 当前摆动角度(弧度)
|
||||||
float swingSpeed, // 摆动速度(弧度/tick)
|
float swingSpeed, // 摆动速度(弧度/tick)
|
||||||
float maxDistance, // 最大距离
|
Double maxDistance, // 最大距离
|
||||||
boolean isFirstPerson, // 是否是第一人称
|
boolean isFirstPerson, // 是否是第一人称
|
||||||
BlockPos belowBlockPos // 持有者位置
|
BlockPos belowBlockPos // 持有者位置
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ public class LeashCommonConfig {
|
||||||
|
|
||||||
// Leash settings
|
// Leash settings
|
||||||
public final ForgeConfigSpec.DoubleValue maxLeashLength;
|
public final ForgeConfigSpec.DoubleValue maxLeashLength;
|
||||||
public final ForgeConfigSpec.DoubleValue elasticDistance;
|
public final ForgeConfigSpec.DoubleValue elasticDistanceScale;
|
||||||
public final ForgeConfigSpec.DoubleValue extremeSnapFactor;
|
public final ForgeConfigSpec.DoubleValue extremeSnapFactor;
|
||||||
public final ForgeConfigSpec.DoubleValue springDampening;
|
public final ForgeConfigSpec.DoubleValue springDampening;
|
||||||
public final ForgeConfigSpec.ConfigValue<List<? extends Double>> axisSpecificElasticity;
|
public final ForgeConfigSpec.ConfigValue<List<? extends Double>> axisSpecificElasticity;
|
||||||
|
|
@ -84,9 +84,9 @@ public class LeashCommonConfig {
|
||||||
.comment("Maximum leash distance (in blocks) for any entity")
|
.comment("Maximum leash distance (in blocks) for any entity")
|
||||||
.defineInRange("maxLeashLength", 12.0, 6.0, 256.0);
|
.defineInRange("maxLeashLength", 12.0, 6.0, 256.0);
|
||||||
|
|
||||||
elasticDistance = builder
|
elasticDistanceScale = builder
|
||||||
.comment("Default elastic distance for the Super Lead rope")
|
.comment("Default elastic distance for the Super Lead rope")
|
||||||
.defineInRange("elasticDistance", 6.0, 6.0, 128.0);
|
.defineInRange("elasticDistanceScale", 1.0, 0.2, 4.0);
|
||||||
|
|
||||||
extremeSnapFactor = builder
|
extremeSnapFactor = builder
|
||||||
.comment("Leash break factor = maxDistance * factor")
|
.comment("Leash break factor = maxDistance * factor")
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public class LeashConfigManager {
|
||||||
private volatile double mobSpringFactor = 0.5;
|
private volatile double mobSpringFactor = 0.5;
|
||||||
|
|
||||||
private volatile double maxLeashLength = 12.0;
|
private volatile double maxLeashLength = 12.0;
|
||||||
private volatile double elasticDistance = 6.0;
|
private volatile double elasticDistanceScale = 1.0;
|
||||||
private volatile double extremeSnapFactor = 2.0;
|
private volatile double extremeSnapFactor = 2.0;
|
||||||
private volatile double springDampening = 0.7;
|
private volatile double springDampening = 0.7;
|
||||||
private volatile List<Double> axisElasticity = List.of(0.8, 0.2, 0.8);
|
private volatile List<Double> axisElasticity = List.of(0.8, 0.2, 0.8);
|
||||||
|
|
@ -186,9 +186,8 @@ public class LeashConfigManager {
|
||||||
public double getMobSpringFactor() { return mobSpringFactor; }
|
public double getMobSpringFactor() { return mobSpringFactor; }
|
||||||
|
|
||||||
public double getMaxLeashLength() { return maxLeashLength; }
|
public double getMaxLeashLength() { return maxLeashLength; }
|
||||||
public double getElasticDistance() { return elasticDistance; }
|
public double getElasticDistanceScale() { return elasticDistanceScale; }
|
||||||
public double getExtremeSnapFactor() { return extremeSnapFactor; }
|
public double getExtremeSnapFactor() { return extremeSnapFactor; }
|
||||||
public double getBreakDistance() { return maxLeashLength * extremeSnapFactor; }
|
|
||||||
public double getSpringDampening() { return springDampening; }
|
public double getSpringDampening() { return springDampening; }
|
||||||
public List<Double> getAxisElasticity() { return Collections.unmodifiableList(axisElasticity); }
|
public List<Double> getAxisElasticity() { return Collections.unmodifiableList(axisElasticity); }
|
||||||
public double getXElasticity() { return !axisElasticity.isEmpty() ? axisElasticity.get(0) : 0.8; }
|
public double getXElasticity() { return !axisElasticity.isEmpty() ? axisElasticity.get(0) : 0.8; }
|
||||||
|
|
@ -209,7 +208,7 @@ public class LeashConfigManager {
|
||||||
commandPrefixEnabledCache = LeashCommonConfig.COMMON.enableSLPModCommandPrefix.get();
|
commandPrefixEnabledCache = LeashCommonConfig.COMMON.enableSLPModCommandPrefix.get();
|
||||||
|
|
||||||
maxLeashLength = LeashCommonConfig.COMMON.maxLeashLength.get();
|
maxLeashLength = LeashCommonConfig.COMMON.maxLeashLength.get();
|
||||||
elasticDistance = LeashCommonConfig.COMMON.elasticDistance.get();
|
elasticDistanceScale = LeashCommonConfig.COMMON.elasticDistanceScale.get();
|
||||||
extremeSnapFactor = LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
extremeSnapFactor = LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
||||||
springDampening = LeashCommonConfig.COMMON.springDampening.get();
|
springDampening = LeashCommonConfig.COMMON.springDampening.get();
|
||||||
axisElasticity = new ArrayList<>(LeashCommonConfig.COMMON.axisSpecificElasticity.get());
|
axisElasticity = new ArrayList<>(LeashCommonConfig.COMMON.axisSpecificElasticity.get());
|
||||||
|
|
|
||||||
|
|
@ -22,26 +22,25 @@ import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
import net.minecraftforge.common.capabilities.CapabilityToken;
|
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
import top.r3944realms.superleadrope.content.capability.provider.EternalPotatoProvider;
|
import top.r3944realms.superleadrope.content.capability.provider.EternalPotatoProvider;
|
||||||
import top.r3944realms.superleadrope.content.capability.provider.LeashDataProvider;
|
import top.r3944realms.superleadrope.content.capability.provider.LeashDataProvider;
|
||||||
import top.r3944realms.superleadrope.content.capability.provider.LeashStateProvider;
|
import top.r3944realms.superleadrope.content.capability.provider.LeashStateProvider;
|
||||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||||
|
|
||||||
public class CapabilityHandler {
|
public class CapabilityHandler {
|
||||||
public static final Capability<ILeashData> LEASH_DATA_CAP = CapabilityManager.get(new CapabilityToken<>(){});
|
public static final Capability<IEternalPotato> ETERNAL_POTATO_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
||||||
public static Capability<ILeashState> LEASH_STATE_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) {
|
||||||
public static Capability<IEternalPotato> ETERNAL_POTATO_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
|
||||||
public static void registerCapability(RegisterCapabilitiesEvent event) {
|
|
||||||
event.register(ILeashData.class);
|
event.register(ILeashData.class);
|
||||||
event.register(IEternalPotato.class);
|
event.register(IEternalPotato.class);
|
||||||
event.register(ILeashState.class);
|
event.register(ILeashState.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void attachCapability(AttachCapabilitiesEvent<?> event) {
|
public static void attachCapability(@NotNull AttachCapabilitiesEvent<?> event) {
|
||||||
Object object = event.getObject();
|
Object object = event.getObject();
|
||||||
if(object instanceof Entity entity &&
|
if(object instanceof Entity entity &&
|
||||||
(LeashDataImpl.isLeashable(entity))//只对活体 船 矿车添加CAP
|
(LeashDataImpl.isLeashable(entity))//只对活体 船 矿车添加CAP
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package top.r3944realms.superleadrope.content.capability;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashStateAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashStateInnerAPI;
|
||||||
|
|
||||||
public class CapabilityRemainder {
|
public class CapabilityRemainder {
|
||||||
public static void onPlayerClone(PlayerEvent.Clone event) {
|
public static void onPlayerClone(PlayerEvent.Clone event) {
|
||||||
|
|
@ -26,9 +26,9 @@ public class CapabilityRemainder {
|
||||||
if(newEntity instanceof ServerPlayer newPlayer) {
|
if(newEntity instanceof ServerPlayer newPlayer) {
|
||||||
Player original = event.getOriginal();
|
Player original = event.getOriginal();
|
||||||
original.reviveCaps();
|
original.reviveCaps();
|
||||||
LeashStateAPI.getLeashState(original)
|
LeashStateInnerAPI.getLeashState(original)
|
||||||
.ifPresent(oldCap ->
|
.ifPresent(oldCap ->
|
||||||
LeashStateAPI.getLeashState(newPlayer)
|
LeashStateInnerAPI.getLeashState(newPlayer)
|
||||||
.ifPresent(newData ->
|
.ifPresent(newData ->
|
||||||
newData.copy(oldCap, newEntity)
|
newData.copy(oldCap, newEntity)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,30 +29,31 @@ import net.minecraft.world.entity.animal.horse.Llama;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||||
import net.minecraft.world.entity.vehicle.Boat;
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.ClipContext;
|
||||||
import net.minecraft.world.level.pathfinder.Path;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||||
import net.minecraftforge.network.PacketDistributor;
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.superleadrope.CommonEventHandler;
|
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
import top.r3944realms.superleadrope.compat.CurtainCompat;
|
import top.r3944realms.superleadrope.compat.CurtainCompat;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||||
import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket;
|
import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashStateInnerAPI;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashStateAPI;
|
|
||||||
import top.r3944realms.superleadrope.util.riding.RindingLeash;
|
import top.r3944realms.superleadrope.util.riding.RindingLeash;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
@ -89,6 +90,12 @@ public class LeashDataImpl implements ILeashData {
|
||||||
private final Entity entity;
|
private final Entity entity;
|
||||||
private boolean needsSync = false;
|
private boolean needsSync = false;
|
||||||
private long lastSyncTime;
|
private long lastSyncTime;
|
||||||
|
@Nullable
|
||||||
|
private Double staticMaxDistance;
|
||||||
|
private double defaultMaxDistance;
|
||||||
|
@Nullable
|
||||||
|
private Double staticElasticDistanceScale;
|
||||||
|
private double defaultElasticDistanceScale;
|
||||||
private final Set<UUID> delayedHolders = new CopyOnWriteArraySet<>();
|
private final Set<UUID> delayedHolders = new CopyOnWriteArraySet<>();
|
||||||
private final Map<UUID, LeashInfo> leashHolders = new ConcurrentHashMap<>();
|
private final Map<UUID, LeashInfo> leashHolders = new ConcurrentHashMap<>();
|
||||||
// 引入解决 绳结不保存导致第二进入持有者不存在的问题
|
// 引入解决 绳结不保存导致第二进入持有者不存在的问题
|
||||||
|
|
@ -143,38 +150,124 @@ public class LeashDataImpl implements ILeashData {
|
||||||
needsSync = false;
|
needsSync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getStaticMaxDistance() {
|
||||||
|
return staticMaxDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStaticMaxDistance(@Nullable Double distance) {
|
||||||
|
staticMaxDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDefaultMaxDistance() {
|
||||||
|
boolean isNotClient = !FMLEnvironment.dist.isClient();
|
||||||
|
if (isNotClient) {
|
||||||
|
defaultMaxDistance = CommonEventHandler.leashConfigManager.getMaxLeashLength();
|
||||||
|
}
|
||||||
|
return defaultMaxDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getCurrentMaxDistance() {
|
||||||
|
return staticMaxDistance != null ? staticMaxDistance : defaultMaxDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAllMaxDistance() {
|
||||||
|
leashHolders.forEach((uuid, leashInfo) -> {
|
||||||
|
if (leashInfo.isNeedUpdateDistance()) {
|
||||||
|
setMaxDistance(uuid, getCurrentMaxDistance());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
leashKnots.forEach((blockPos, leashInfo) -> {
|
||||||
|
if (leashInfo.isNeedUpdateDistance()) {
|
||||||
|
setMaxDistance(blockPos, getCurrentMaxDistance());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getStaticElasticDistanceScale() {
|
||||||
|
return staticElasticDistanceScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStaticElasticDistanceScale(@Nullable Double distance) {
|
||||||
|
staticElasticDistanceScale = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDefaultElasticDistanceScale() {
|
||||||
|
boolean isNotClient = !FMLEnvironment.dist.isClient();
|
||||||
|
if (isNotClient) {
|
||||||
|
defaultElasticDistanceScale = CommonEventHandler.leashConfigManager.getElasticDistanceScale();
|
||||||
|
}
|
||||||
|
return defaultElasticDistanceScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getCurrentElasticDistanceScale() {
|
||||||
|
return staticElasticDistanceScale != null ? staticElasticDistanceScale : defaultElasticDistanceScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAllElasticDistanceScale() {
|
||||||
|
leashHolders.forEach((uuid, leashInfo) -> {
|
||||||
|
if (leashInfo.isNeedUpdateScale()) {
|
||||||
|
setElasticDistanceScale(uuid, getCurrentElasticDistanceScale());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
leashKnots.forEach((blockPos, leashInfo) -> {
|
||||||
|
if (leashInfo.isNeedUpdateScale()) {
|
||||||
|
setElasticDistanceScale(blockPos, getCurrentMaxDistance());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder) {
|
public boolean addLeash(Entity holder) {
|
||||||
return addLeash(holder, CommonEventHandler.leashConfigManager.getMaxLeashLength());
|
return addLeash(holder, (Double) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder, String reserved) {
|
public boolean addLeash(Entity holder, String reserved) {
|
||||||
return addLeash(holder, CommonEventHandler.leashConfigManager.getMaxLeashLength(), reserved);
|
return addLeash(holder, null, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加拴绳(支持自定义最大长度)
|
// 添加拴绳(支持自定义最大长度)
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder, double maxDistance) {
|
public boolean addLeash(Entity holder, Double maxDistance) {
|
||||||
return addLeash(holder, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistance(), 0, "");
|
return addLeash(holder, maxDistance, null, 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale) {
|
||||||
|
return addLeash(holder, maxDistance, elasticDistanceScale, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加拴绳(支持自定义最大长度和弹性距离)
|
// 添加拴绳(支持自定义最大长度和弹性距离)
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepLeashTicks) {
|
public boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, int maxKeepLeashTicks) {
|
||||||
return addLeash(holder, maxDistance, elasticDistance, maxKeepLeashTicks, "");
|
return addLeash(holder, maxDistance, elasticDistanceScale, maxKeepLeashTicks, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addLeash(Entity holder, Double maxDistance, Double elasticDistanceScale, String reserved) {
|
||||||
|
return addLeash(holder, maxDistance, elasticDistanceScale, 0, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加拴绳(支持自定义最大长度 + reserved 字段)
|
// 添加拴绳(支持自定义最大长度 + reserved 字段)
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder, double maxDistance, String reserved) {
|
public boolean addLeash(Entity holder, Double maxDistance, String reserved) {
|
||||||
return addLeash(holder, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistance(), 0, reserved);
|
return addLeash(holder, maxDistance, null, 0, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加拴绳(最终实现:支持最大长度、弹性距离、保持 Tick、reserved)
|
// 添加拴绳(最终实现:支持最大长度、弹性距离、保持 Tick、reserved)
|
||||||
@Override
|
@Override
|
||||||
public boolean addLeash(Entity holder, double maxDistance,
|
public boolean addLeash(Entity holder, Double maxDistance,
|
||||||
double elasticDistance, int maxKeepLeashTicks, String reserved) {
|
Double elasticDistanceScale, int maxKeepLeashTicks, String reserved) {
|
||||||
boolean isSuperKnot = holder instanceof SuperLeashKnotEntity;
|
boolean isSuperKnot = holder instanceof SuperLeashKnotEntity;
|
||||||
if ((!isSuperKnot && leashHolders.containsKey(holder.getUUID()))
|
if ((!isSuperKnot && leashHolders.containsKey(holder.getUUID()))
|
||||||
|| (isSuperKnot && leashKnots.containsKey(((SuperLeashKnotEntity) holder).getPos()))) {
|
|| (isSuperKnot && leashKnots.containsKey(((SuperLeashKnotEntity) holder).getPos()))) {
|
||||||
|
|
@ -193,7 +286,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
holder,
|
holder,
|
||||||
reserved,
|
reserved,
|
||||||
maxDistance,
|
maxDistance,
|
||||||
elasticDistance,
|
elasticDistanceScale,
|
||||||
maxKeepLeashTicks,
|
maxKeepLeashTicks,
|
||||||
maxKeepLeashTicks
|
maxKeepLeashTicks
|
||||||
);
|
);
|
||||||
|
|
@ -203,24 +296,24 @@ public class LeashDataImpl implements ILeashData {
|
||||||
} else {
|
} else {
|
||||||
leashHolders.put(holder.getUUID(), info);
|
leashHolders.put(holder.getUUID(), info);
|
||||||
}
|
}
|
||||||
LeashStateAPI.Offset.setHolderFor(entity, holder);
|
LeashStateInnerAPI.Offset.setHolderFor(entity, holder);
|
||||||
markForSync();
|
markForSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用已有的 LeashInfo 添加拴绳(直接走最终实现)
|
// 使用已有的 LeashInfo 添加拴绳(直接走最终实现)
|
||||||
@Override
|
@Override
|
||||||
public void addLeash(Entity holder, LeashInfo leashInfo) {
|
public void addLeash(Entity holder, @NotNull LeashInfo leashInfo) {
|
||||||
addLeash(holder,
|
addLeash(holder,
|
||||||
leashInfo.maxDistance(),
|
leashInfo.maxDistance(),
|
||||||
leashInfo.elasticDistance(),
|
leashInfo.elasticDistanceScale(),
|
||||||
leashInfo.maxKeepLeashTicks(),
|
leashInfo.maxKeepLeashTicks(),
|
||||||
leashInfo.reserved()
|
leashInfo.reserved()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDelayedLeash(Player holderPlayer) {
|
public void addDelayedLeash(@NotNull Player holderPlayer) {
|
||||||
delayedHolders.add(holderPlayer.getUUID());
|
delayedHolders.add(holderPlayer.getUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +323,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
}
|
}
|
||||||
|
|
||||||
private <K> boolean updateLeashInfo(
|
private <K> boolean updateLeashInfo(
|
||||||
Map<K, LeashInfo> map,
|
@NotNull Map<K, LeashInfo> map,
|
||||||
K key,
|
K key,
|
||||||
Function<LeashInfo, LeashInfo> updater
|
Function<LeashInfo, LeashInfo> updater
|
||||||
) {
|
) {
|
||||||
|
|
@ -246,21 +339,21 @@ public class LeashDataImpl implements ILeashData {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(Entity holder, double newMaxDistance) {
|
public boolean setMaxDistance(Entity holder, @Nullable Double newMaxDistance) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance) :
|
setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance) :
|
||||||
setMaxDistance(holder.getUUID(), newMaxDistance);
|
setMaxDistance(holder.getUUID(), newMaxDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(Entity holder, double newMaxDistance, int newMaxKeepLeashTicks) {
|
public boolean setMaxDistance(Entity holder, @Nullable Double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance, newMaxKeepLeashTicks) :
|
setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance, newMaxKeepLeashTicks) :
|
||||||
setMaxDistance(holder.getUUID(), newMaxDistance, newMaxKeepLeashTicks);
|
setMaxDistance(holder.getUUID(), newMaxDistance, newMaxKeepLeashTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks, String reserved) {
|
public boolean setMaxDistance(Entity holder, @Nullable Double distance, int maxKeepTicks, String reserved) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setMaxDistance(superLeashKnotEntity.getPos(), distance, maxKeepTicks, reserved) :
|
setMaxDistance(superLeashKnotEntity.getPos(), distance, maxKeepTicks, reserved) :
|
||||||
setMaxDistance(holder.getUUID(), distance, maxKeepTicks, reserved);
|
setMaxDistance(holder.getUUID(), distance, maxKeepTicks, reserved);
|
||||||
|
|
@ -268,13 +361,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(UUID holderUUID, double newMaxDistance) {
|
public boolean setMaxDistance(UUID holderUUID, @Nullable Double newMaxDistance) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
newMaxDistance,
|
newMaxDistance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
old.keepLeashTicks(),
|
old.keepLeashTicks(),
|
||||||
old.maxKeepLeashTicks()
|
old.maxKeepLeashTicks()
|
||||||
));
|
));
|
||||||
|
|
@ -282,13 +376,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(UUID holderUUID, double newMaxDistance, int newMaxKeepLeashTicks) {
|
public boolean setMaxDistance(UUID holderUUID, @Nullable Double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
newMaxDistance,
|
newMaxDistance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||||
newMaxKeepLeashTicks
|
newMaxKeepLeashTicks
|
||||||
));
|
));
|
||||||
|
|
@ -296,13 +391,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
public boolean setMaxDistance(UUID holderUUID, @Nullable Double distance, int maxKeepTicks, String reserved) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
reserved,
|
reserved,
|
||||||
distance,
|
distance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||||
maxKeepTicks
|
maxKeepTicks
|
||||||
));
|
));
|
||||||
|
|
@ -310,13 +406,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance) {
|
public boolean setMaxDistance(BlockPos knotPos, @Nullable Double newMaxDistance) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
newMaxDistance,
|
newMaxDistance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
old.keepLeashTicks(),
|
old.keepLeashTicks(),
|
||||||
old.maxKeepLeashTicks()
|
old.maxKeepLeashTicks()
|
||||||
));
|
));
|
||||||
|
|
@ -324,13 +421,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks) {
|
public boolean setMaxDistance(BlockPos knotPos, @Nullable Double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
newMaxDistance,
|
newMaxDistance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||||
newMaxKeepLeashTicks
|
newMaxKeepLeashTicks
|
||||||
));
|
));
|
||||||
|
|
@ -338,35 +436,37 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved) {
|
public boolean setMaxDistance(BlockPos knotPos, @Nullable Double distance, int maxKeepTicks, String reserved) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
reserved,
|
reserved,
|
||||||
distance,
|
distance,
|
||||||
old.elasticDistance(),
|
old.elasticDistanceScale(),
|
||||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||||
maxKeepTicks
|
maxKeepTicks
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(Entity holder, double newElasticDistance) {
|
public boolean setElasticDistanceScale(Entity holder, @Nullable Double scale) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setElasticDistance(superLeashKnotEntity.getPos(), newElasticDistance) :
|
setElasticDistanceScale(superLeashKnotEntity.getPos(), scale) :
|
||||||
setElasticDistance(holder.getUUID(), newElasticDistance);
|
setElasticDistanceScale(holder.getUUID(), scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态修改弹性距离
|
// 动态修改弹性距离
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(UUID holderUUID, double newElasticDistance) {
|
public boolean setElasticDistanceScale(UUID holderUUID, @Nullable Double scale) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
newElasticDistance,
|
scale,
|
||||||
old.keepLeashTicks(),
|
old.keepLeashTicks(),
|
||||||
old.maxKeepLeashTicks()
|
old.maxKeepLeashTicks()
|
||||||
));
|
));
|
||||||
|
|
@ -374,42 +474,44 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance) {
|
public boolean setElasticDistanceScale(BlockPos knotPos, @Nullable Double scale) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
newElasticDistance,
|
scale,
|
||||||
old.keepLeashTicks(),
|
old.keepLeashTicks(),
|
||||||
old.maxKeepLeashTicks()
|
old.maxKeepLeashTicks()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(Entity holder, double newElasticDistance, int newMaxKeepLeashTicks) {
|
public boolean setElasticDistanceScale(Entity holder, @Nullable Double scale, int newMaxKeepLeashTicks) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setElasticDistance(superLeashKnotEntity.getPos(), newElasticDistance, newMaxKeepLeashTicks) :
|
setElasticDistanceScale(superLeashKnotEntity.getPos(), scale, newMaxKeepLeashTicks) :
|
||||||
setElasticDistance(holder.getUUID(), newElasticDistance, newMaxKeepLeashTicks);
|
setElasticDistanceScale(holder.getUUID(), scale, newMaxKeepLeashTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks, String reserved) {
|
public boolean setElasticDistanceScale(Entity holder, @Nullable Double scale, int maxKeepTicks, String reserved) {
|
||||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||||
setElasticDistance(superLeashKnotEntity.getPos(), distance, maxKeepTicks, reserved) :
|
setElasticDistanceScale(superLeashKnotEntity.getPos(), scale, maxKeepTicks, reserved) :
|
||||||
setElasticDistance(holder.getUUID(), distance, maxKeepTicks, reserved);
|
setElasticDistanceScale(holder.getUUID(), scale, maxKeepTicks, reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态修改弹性距离
|
// 动态修改弹性距离
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks) {
|
public boolean setElasticDistanceScale(UUID holderUUID, @Nullable Double scale, int newMaxKeepLeashTicks) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
newElasticDistance,
|
scale,
|
||||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||||
newMaxKeepLeashTicks
|
newMaxKeepLeashTicks
|
||||||
));
|
));
|
||||||
|
|
@ -417,13 +519,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
public boolean setElasticDistanceScale(UUID holderUUID, @Nullable Double scale, int maxKeepTicks, String reserved) {
|
||||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||||
old.holderUUIDOpt().get(),
|
old.holderUUIDOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
reserved,
|
reserved,
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
distance,
|
scale,
|
||||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||||
maxKeepTicks
|
maxKeepTicks
|
||||||
));
|
));
|
||||||
|
|
@ -431,13 +534,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks) {
|
public boolean setElasticDistanceScale(BlockPos knotPos, @Nullable Double scale, int newMaxKeepLeashTicks) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
old.reserved(),
|
old.reserved(),
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
newElasticDistance,
|
scale,
|
||||||
old.keepLeashTicks(),
|
old.keepLeashTicks(),
|
||||||
old.maxKeepLeashTicks()
|
old.maxKeepLeashTicks()
|
||||||
));
|
));
|
||||||
|
|
@ -445,13 +549,14 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||||
@Override
|
@Override
|
||||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks, String reserved) {
|
public boolean setElasticDistanceScale(BlockPos knotPos, @Nullable Double scale, int newMaxKeepLeashTicks, String reserved) {
|
||||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||||
old.blockPosOpt().get(),
|
old.blockPosOpt().get(),
|
||||||
old.holderIdOpt().get(),
|
old.holderIdOpt().get(),
|
||||||
|
old.marks(),
|
||||||
reserved,
|
reserved,
|
||||||
old.maxDistance(),
|
old.maxDistance(),
|
||||||
newElasticDistance,
|
scale,
|
||||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||||
newMaxKeepLeashTicks
|
newMaxKeepLeashTicks
|
||||||
));
|
));
|
||||||
|
|
@ -509,7 +614,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
/**
|
/**
|
||||||
* 给非玩家实体施加拴绳力(取消阻力)
|
* 给非玩家实体施加拴绳力(取消阻力)
|
||||||
*/
|
*/
|
||||||
private void applyForceToNonPlayerEntity(Entity entity, Vec3 combinedForce,
|
private void applyForceToNonPlayerEntity(@NotNull Entity entity, Vec3 combinedForce,
|
||||||
int validLeashes, Vec3 combinedDirection) {
|
int validLeashes, Vec3 combinedDirection) {
|
||||||
// 直接施加合力,不再加阻力
|
// 直接施加合力,不再加阻力
|
||||||
entity.setDeltaMovement(entity.getDeltaMovement().add(combinedForce));
|
entity.setDeltaMovement(entity.getDeltaMovement().add(combinedForce));
|
||||||
|
|
@ -517,10 +622,12 @@ public class LeashDataImpl implements ILeashData {
|
||||||
|
|
||||||
// 如果是生物,处理导航
|
// 如果是生物,处理导航
|
||||||
if (entity instanceof Mob mob) {
|
if (entity instanceof Mob mob) {
|
||||||
if (validLeashes > 0 && canMobMove(mob)) {
|
if(mob.tickCount % 5 == 0){
|
||||||
moveMobTowardsCombinedDirection(mob, combinedDirection, validLeashes, combinedForce.length());
|
if (validLeashes > 0 && canMobMove(mob)) {
|
||||||
} else {
|
moveMobTowardsCombinedDirection(mob, combinedDirection, combinedForce.length());
|
||||||
mob.getNavigation().stop();
|
} else {
|
||||||
|
mob.getNavigation().stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -528,77 +635,97 @@ public class LeashDataImpl implements ILeashData {
|
||||||
/**
|
/**
|
||||||
* 检查生物是否能够移动
|
* 检查生物是否能够移动
|
||||||
*/
|
*/
|
||||||
private boolean canMobMove(Mob mob) {
|
private boolean canMobMove(@NotNull Mob mob) {
|
||||||
// 检查各种无法移动的情况
|
// 检查各种无法移动的情况
|
||||||
return !mob.isNoGravity() && // 有重力才能移动
|
return !mob.isDeadOrDying() && // 没有死亡或濒死
|
||||||
!mob.isSleeping() && // 没有在睡觉
|
|
||||||
!mob.isDeadOrDying() && // 没有死亡或濒死
|
|
||||||
!mob.isFreezing() && // 没有被冻结
|
|
||||||
mob.canUpdate() && // 可以更新
|
|
||||||
mob.isEffectiveAi() && // AI有效
|
mob.isEffectiveAi() && // AI有效
|
||||||
mob.getDeltaMovement().lengthSqr() < 100.0; // 移动速度不是特别快(防止异常情况)
|
mob.getDeltaMovement().lengthSqr() < 25.0; // 降低速度阈值
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让生物朝着合力方向移动
|
* 让生物朝着合力方向移动
|
||||||
*/
|
*/
|
||||||
private void moveMobTowardsCombinedDirection(Mob mob, Vec3 combinedDirection, int leashCount, double forceMagnitude) {
|
private void moveMobTowardsCombinedDirection(Mob mob, @NotNull Vec3 combinedDirection, double forceMagnitude) {
|
||||||
if (combinedDirection.equals(Vec3.ZERO) || !canMobMove(mob)) {
|
if (combinedDirection.equals(Vec3.ZERO) || !canMobMove(mob)) {
|
||||||
mob.getNavigation().stop();
|
return;// 减少不必要的stop调用
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算平均方向
|
// 计算平均方向(简化计算)
|
||||||
Vec3 averageDirection = combinedDirection.scale(1.0 / leashCount).normalize();
|
Vec3 averageDirection = combinedDirection.normalize();
|
||||||
|
|
||||||
// 根据力的大小调整移动速度
|
// 根据力的大小调整移动速度
|
||||||
double speed = calculateMobSpeed(mob, forceMagnitude);
|
double speed = calculateMobSpeed(mob, forceMagnitude);
|
||||||
|
|
||||||
// 计算目标位置(在合力方向上稍微超前一点)
|
// 计算目标位置(缩短距离)
|
||||||
Vec3 targetPos = mob.position().add(averageDirection.scale(3.0)); // 3格距离
|
Vec3 targetPos = mob.position().add(averageDirection.scale(2.0)); // 从3格减少到2格
|
||||||
|
|
||||||
// 检查目标位置是否可达
|
// 使用快速可达性检查
|
||||||
if (isPositionReachable(mob, targetPos)) {
|
if (isPositionQuickReachable(mob, targetPos)) {
|
||||||
// 设置移动目标
|
// 设置移动目标
|
||||||
mob.getNavigation().moveTo(targetPos.x, targetPos.y, targetPos.z, speed);
|
mob.getNavigation().moveTo(targetPos.x, targetPos.y, targetPos.z, speed);
|
||||||
|
|
||||||
// 设置生物朝向合力方向
|
// 降低朝向更新频率
|
||||||
mob.getLookControl().setLookAt(targetPos);
|
if (mob.tickCount % 10 == 0) {
|
||||||
} else {
|
mob.getLookControl().setLookAt(targetPos);
|
||||||
// 位置不可达时停止导航
|
}
|
||||||
mob.getNavigation().stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查位置是否可达
|
* 快速可达性检查(替代原来的路径查找)
|
||||||
*/
|
*/
|
||||||
private boolean isPositionReachable(Mob mob, Vec3 targetPos) {
|
private boolean isPositionQuickReachable(@NotNull Mob mob, Vec3 targetPos) {
|
||||||
// 简单的距离检查
|
// 1. 距离检查(缩短最大距离)
|
||||||
if (mob.position().distanceTo(targetPos) > 20.0) return false;// 距离太远
|
double distance = mob.position().distanceTo(targetPos);
|
||||||
// 检查是否有导航路径
|
if (distance > 10.0) return false; // 从20格减少到10格
|
||||||
Path path = mob.getNavigation().createPath(targetPos.x, targetPos.y, targetPos.z, 0);
|
|
||||||
return path != null && !path.isDone();
|
// 2. 高度差检查
|
||||||
|
double heightDiff = Math.abs(targetPos.y - mob.position().y);
|
||||||
|
if (heightDiff > 2.0) return false;
|
||||||
|
|
||||||
|
// 3. 简单的视线检查
|
||||||
|
// 如果性能仍然有问题,可以注释掉这个检查
|
||||||
|
if (mob.level().isLoaded(BlockPos.containing(targetPos))) {
|
||||||
|
BlockHitResult hitResult = mob.level().clip(new ClipContext(
|
||||||
|
mob.position(),
|
||||||
|
targetPos,
|
||||||
|
ClipContext.Block.COLLIDER,
|
||||||
|
ClipContext.Fluid.NONE,
|
||||||
|
mob
|
||||||
|
));
|
||||||
|
return hitResult.getType() == HitResult.Type.MISS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 检查位置是否可达
|
||||||
|
// */
|
||||||
|
// private boolean isPositionReachable(Mob mob, Vec3 targetPos) {
|
||||||
|
// // 简单的距离检查
|
||||||
|
// if (mob.position().distanceTo(targetPos) > 20.0) return false;// 距离太远
|
||||||
|
// // 检查是否有导航路径
|
||||||
|
// Path path = mob.getNavigation().createPath(targetPos.x, targetPos.y, targetPos.z, 0);
|
||||||
|
// return path != null && !path.isDone();
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据生物类型和力的大小计算移动速度
|
* 根据生物类型和力的大小计算移动速度(优化版)
|
||||||
*/
|
*/
|
||||||
private double calculateMobSpeed(Mob mob, double forceMagnitude) {
|
private double calculateMobSpeed(Mob mob, double forceMagnitude) {
|
||||||
double baseSpeed = mob instanceof Llama ? 2.0 : 1.0;
|
double baseSpeed = mob instanceof Llama ? 1.5 : 1.0; // 降低基础速度
|
||||||
|
|
||||||
// 力越大,移动速度越快(但有上限)
|
// 力越大,移动速度越快(降低加速效果)
|
||||||
double forceFactor = Math.min(forceMagnitude * 0.5, 2.0); // 限制最大加速2倍
|
double forceFactor = Math.min(forceMagnitude * 0.3, 1.5); // 降低加速系数和上限
|
||||||
|
|
||||||
return baseSpeed * (1.0 + forceFactor);
|
return baseSpeed * (1.0 + forceFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为UUID拴绳计算力
|
* 为UUID拴绳计算力
|
||||||
*/
|
*/
|
||||||
private Vec3 calculateLeashForceForUUID(Map.Entry<UUID, LeashInfo> entry) {
|
private @Nullable Vec3 calculateLeashForceForUUID(Map.@NotNull Entry<UUID, LeashInfo> entry) {
|
||||||
UUID uuid = entry.getKey();
|
UUID uuid = entry.getKey();
|
||||||
Entity uuidHolder = ((ServerLevel) entity.level()).getEntity(uuid);
|
Entity uuidHolder = ((ServerLevel) entity.level()).getEntity(uuid);
|
||||||
if (uuidHolder != null) {
|
if (uuidHolder != null) {
|
||||||
|
|
@ -615,80 +742,90 @@ public class LeashDataImpl implements ILeashData {
|
||||||
/**
|
/**
|
||||||
* 为方块位置拴绳计算力
|
* 为方块位置拴绳计算力
|
||||||
*/
|
*/
|
||||||
private Vec3 calculateLeashForceForBlockPos(Map.Entry<BlockPos, LeashInfo> entry) {
|
private Vec3 calculateLeashForceForBlockPos(Map.@NotNull Entry<BlockPos, LeashInfo> entry) {
|
||||||
SuperLeashKnotEntity orCreateKnot = SuperLeashKnotEntity.getOrCreateKnot(entity.level(), entry.getKey());
|
SuperLeashKnotEntity orCreateKnot = SuperLeashKnotEntity.getOrCreateKnot(entity.level(), entry.getKey());
|
||||||
return calculateLeashForce(orCreateKnot, entry);
|
return calculateLeashForce(orCreateKnot, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private @Nullable Vec3 calculateLeashForce(@NotNull Entity holder, Map.@NotNull Entry<?, LeashInfo> entry) {
|
||||||
* 计算单个拴绳的力
|
|
||||||
*/
|
|
||||||
private Vec3 calculateLeashForce(Entity holder, Map.Entry<?, LeashInfo> entry) {
|
|
||||||
Vec3 holderPos = holder.position().add(0, holder.getBbHeight() * 0.7, 0);
|
Vec3 holderPos = holder.position().add(0, holder.getBbHeight() * 0.7, 0);
|
||||||
LeashInfo info = entry.getValue();
|
LeashInfo info = entry.getValue();
|
||||||
Vec3 entityPos = entity.position();
|
Vec3 entityPos = entity.position();
|
||||||
double distance = holderPos.distanceTo(entityPos);
|
double distance = holderPos.distanceTo(entityPos);
|
||||||
double extremeSnapDist = CommonEventHandler.leashConfigManager.getBreakDistance();
|
|
||||||
|
|
||||||
|
double maxDistance = info.maxDistance() == null ? getCurrentMaxDistance() : info.maxDistance();
|
||||||
|
double extremeSnapDist = maxDistance * CommonEventHandler.leashConfigManager.getExtremeSnapFactor();
|
||||||
|
double elasticDistanceScale = info.elasticDistanceScale() == null ? getCurrentElasticDistanceScale() : info.elasticDistanceScale();
|
||||||
|
// 修正:计算弹性限度距离
|
||||||
|
double elasticLimitDistance = maxDistance * elasticDistanceScale;
|
||||||
// 1. 检查是否超出断裂距离
|
// 1. 检查是否超出断裂距离
|
||||||
if (distance > extremeSnapDist) {
|
if (distance > extremeSnapDist) {
|
||||||
if (info.keepLeashTicks() > 0) {
|
if (info.keepLeashTicks() > 0) {
|
||||||
// 计算临界拉力
|
// 计算临界拉力
|
||||||
Vec3 pullForce = calculateCriticalPullForce(holderPos, entityPos, distance, info);
|
Vec3 pullForce = calculateCriticalPullForce(holderPos, entityPos, distance, maxDistance, elasticLimitDistance);
|
||||||
entry.setValue(info.decrementKeepTicks());
|
entry.setValue(info.decrementKeepTicks());
|
||||||
return pullForce;
|
return pullForce;
|
||||||
}
|
}
|
||||||
// 断裂
|
// 断裂
|
||||||
removeLeash(holder);
|
removeLeash(holder);
|
||||||
//TODO: 是不是应该考虑让断裂统一发出声音,还是就这样由断裂发出
|
|
||||||
entity.level().playSound(null, holder.getOnPos(), SLPSoundEvents.LEAD_BREAK.get(), SoundSource.PLAYERS);
|
entity.level().playSound(null, holder.getOnPos(), SLPSoundEvents.LEAD_BREAK.get(), SoundSource.PLAYERS);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 2. 正常弹性拉力逻辑
|
// 2. 正常弹性拉力逻辑
|
||||||
Vec3 pullForce = Vec3.ZERO;
|
Vec3 pullForce = Vec3.ZERO;
|
||||||
if (distance > info.elasticDistance()) {
|
if (distance > elasticLimitDistance) {
|
||||||
pullForce = calculatePullForce(holderPos, entityPos, distance, info);
|
pullForce = calculatePullForce(holderPos, entityPos, distance, maxDistance, elasticLimitDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 重置缓冲Tick
|
// 3. 重置缓冲Tick
|
||||||
if (distance <= info.maxDistance() && info.keepLeashTicks() < info.maxKeepLeashTicks()) {
|
if (distance <= extremeSnapDist && info.keepLeashTicks() < info.maxKeepLeashTicks()) {
|
||||||
entry.setValue(info.resetKeepTicks());
|
entry.setValue(info.resetKeepTicks());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pullForce;
|
return pullForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算正常拉力(保持不变)
|
// 计算正常拉力
|
||||||
@Contract("_, _, _, _ -> new")
|
@Contract("_, _, _, _, _ -> new")
|
||||||
private @NotNull Vec3 calculatePullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, @NotNull LeashInfo info) {
|
private @NotNull Vec3 calculatePullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, double maxDistance, double elasticLimitDistance) {
|
||||||
Vec3 pullDirection = holderPos.subtract(entityPos).normalize();
|
Vec3 pullDirection = holderPos.subtract(entityPos).normalize();
|
||||||
double pullStrength = 0.2;
|
double pullStrength = 0.2;
|
||||||
|
|
||||||
if (distance > info.maxDistance()) {
|
// 计算超过弹性限度的距离
|
||||||
double excessRatio = (distance - info.maxDistance()) / info.maxDistance();
|
double excessDistance = distance - elasticLimitDistance;
|
||||||
|
|
||||||
|
if (distance > maxDistance) {
|
||||||
|
double excessRatio = (distance - maxDistance) / (maxDistance - elasticLimitDistance);
|
||||||
pullStrength += excessRatio * 0.8;
|
pullStrength += excessRatio * 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拉力与超过弹性限度的距离成正比
|
||||||
Vec3 pullForce = pullDirection.scale(
|
Vec3 pullForce = pullDirection.scale(
|
||||||
(distance - info.elasticDistance()) * pullStrength * CommonEventHandler.leashConfigManager.getSpringDampening()
|
excessDistance * pullStrength * CommonEventHandler.leashConfigManager.getSpringDampening()
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Vec3(
|
return new Vec3(
|
||||||
pullForce.x * CommonEventHandler.leashConfigManager.getXElasticity(),
|
pullForce.x * CommonEventHandler.leashConfigManager.getXElasticity(),
|
||||||
pullForce.y * CommonEventHandler.leashConfigManager.getXElasticity(),
|
pullForce.y * CommonEventHandler.leashConfigManager.getYElasticity(), // 修正:应该是 YElasticity
|
||||||
pullForce.z * CommonEventHandler.leashConfigManager.getZElasticity()
|
pullForce.z * CommonEventHandler.leashConfigManager.getZElasticity()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算临界拉力(保持不变)
|
// 计算临界拉力(修正版)
|
||||||
private @NotNull Vec3 calculateCriticalPullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, @NotNull LeashInfo info) {
|
private @NotNull Vec3 calculateCriticalPullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, double maxDistance, double elasticLimitDistance) {
|
||||||
Vec3 pullDirection = holderPos.subtract(entityPos).normalize();
|
Vec3 pullDirection = holderPos.subtract(entityPos).normalize();
|
||||||
double excessRatio = (distance - info.maxDistance()) / info.maxDistance();
|
|
||||||
|
double excessRatio = (distance - maxDistance) / maxDistance;
|
||||||
double pullStrength = 1.0 + excessRatio * 2.0;
|
double pullStrength = 1.0 + excessRatio * 2.0;
|
||||||
|
|
||||||
|
// 计算超过弹性限度的距离
|
||||||
|
double excessDistance = distance - elasticLimitDistance;
|
||||||
|
|
||||||
Vec3 pullForce = pullDirection.scale(
|
Vec3 pullForce = pullDirection.scale(
|
||||||
(distance - info.elasticDistance()) * pullStrength * CommonEventHandler.leashConfigManager.getSpringDampening()
|
excessDistance * pullStrength * CommonEventHandler.leashConfigManager.getSpringDampening()
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Vec3(
|
return new Vec3(
|
||||||
|
|
@ -709,7 +846,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
public boolean removeLeash(UUID holderUUID) {
|
public boolean removeLeash(UUID holderUUID) {
|
||||||
boolean removed = leashHolders.remove(holderUUID) != null;
|
boolean removed = leashHolders.remove(holderUUID) != null;
|
||||||
if (removed) {
|
if (removed) {
|
||||||
LeashStateAPI.Operations.detach(entity, holderUUID);
|
LeashStateInnerAPI.Operations.detach(entity, holderUUID);
|
||||||
markForSync();
|
markForSync();
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
|
|
@ -719,7 +856,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
public boolean removeLeash(BlockPos knotPos) {
|
public boolean removeLeash(BlockPos knotPos) {
|
||||||
boolean removed = leashKnots.remove(knotPos) != null;
|
boolean removed = leashKnots.remove(knotPos) != null;
|
||||||
if (removed) {
|
if (removed) {
|
||||||
LeashStateAPI.Operations.detach(entity, knotPos);
|
LeashStateInnerAPI.Operations.detach(entity, knotPos);
|
||||||
markForSync();
|
markForSync();
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
|
|
@ -729,21 +866,21 @@ public class LeashDataImpl implements ILeashData {
|
||||||
public void removeAllLeashes() {
|
public void removeAllLeashes() {
|
||||||
leashHolders.clear();
|
leashHolders.clear();
|
||||||
leashKnots.clear();
|
leashKnots.clear();
|
||||||
LeashStateAPI.Offset.removeHolderAll(entity);
|
LeashStateInnerAPI.Offset.removeHolderAll(entity);
|
||||||
markForSync();
|
markForSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAllHolderLeashes() {
|
public void removeAllHolderLeashes() {
|
||||||
leashHolders.clear();
|
leashHolders.clear();
|
||||||
LeashStateAPI.Offset.removeAllHolderUUIDs(entity);
|
LeashStateInnerAPI.Offset.removeAllHolderUUIDs(entity);
|
||||||
markForSync();
|
markForSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAllKnotLeashes() {
|
public void removeAllKnotLeashes() {
|
||||||
leashKnots.clear();
|
leashKnots.clear();
|
||||||
LeashStateAPI.Offset.removeAllHolderBlockPoses(entity);
|
LeashStateInnerAPI.Offset.removeAllHolderBlockPoses(entity);
|
||||||
markForSync();
|
markForSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -773,7 +910,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
LeashInfo leashInfo = info.transferHolder(newHolder);
|
LeashInfo leashInfo = info.transferHolder(newHolder);
|
||||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||||
}
|
}
|
||||||
LeashStateAPI.Operations.transfer(entity, oldHolderUUID, newHolder);
|
LeashStateInnerAPI.Operations.transfer(entity, oldHolderUUID, newHolder);
|
||||||
markForSync();
|
markForSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -788,7 +925,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
||||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||||
}
|
}
|
||||||
LeashStateAPI.Operations.transfer(entity, oldHolderUUID, newHolder);
|
LeashStateInnerAPI.Operations.transfer(entity, oldHolderUUID, newHolder);
|
||||||
markForSync();
|
markForSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -804,7 +941,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
LeashInfo leashInfo = info.transferHolder(newHolder);
|
LeashInfo leashInfo = info.transferHolder(newHolder);
|
||||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||||
}
|
}
|
||||||
LeashStateAPI.Operations.transfer(entity, knotPos, newHolder);
|
LeashStateInnerAPI.Operations.transfer(entity, knotPos, newHolder);
|
||||||
markForSync();
|
markForSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -820,7 +957,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
||||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||||
}
|
}
|
||||||
LeashStateAPI.Operations.transfer(entity, knotPos, newHolder);
|
LeashStateInnerAPI.Operations.transfer(entity, knotPos, newHolder);
|
||||||
markForSync();
|
markForSync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -841,7 +978,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
}
|
}
|
||||||
|
|
||||||
//只能系在这些实体上,在这里,其它情况一律忽略
|
//只能系在这些实体上,在这里,其它情况一律忽略
|
||||||
//TODO: 标签支持控制
|
//TODO: 未来更新计划 - 标签支持控制
|
||||||
public static boolean isLeashable(Entity entity) {
|
public static boolean isLeashable(Entity entity) {
|
||||||
return entity instanceof LivingEntity || entity instanceof Boat || entity instanceof AbstractMinecart;
|
return entity instanceof LivingEntity || entity instanceof Boat || entity instanceof AbstractMinecart;
|
||||||
}
|
}
|
||||||
|
|
@ -901,6 +1038,10 @@ public class LeashDataImpl implements ILeashData {
|
||||||
CompoundTag tag = new CompoundTag();
|
CompoundTag tag = new CompoundTag();
|
||||||
ListTag holdersList = new ListTag();
|
ListTag holdersList = new ListTag();
|
||||||
ListTag delayedHolderList = new ListTag();
|
ListTag delayedHolderList = new ListTag();
|
||||||
|
if (staticMaxDistance != null) tag.putDouble("StaticMaxDistance", staticMaxDistance);
|
||||||
|
tag.putDouble("DefaultMaxDistance", defaultMaxDistance);
|
||||||
|
if (staticElasticDistanceScale != null) tag.putDouble("StaticElasticDistanceScale", staticElasticDistanceScale);
|
||||||
|
tag.putDouble("DefaultElasticDistanceScale", defaultElasticDistanceScale);
|
||||||
for (LeashInfo info : leashHolders.values()) {
|
for (LeashInfo info : leashHolders.values()) {
|
||||||
CompoundTag infoTag = generateCompoundTagFromUUIDLeashInfo(info);
|
CompoundTag infoTag = generateCompoundTagFromUUIDLeashInfo(info);
|
||||||
holdersList.add(infoTag);
|
holdersList.add(infoTag);
|
||||||
|
|
@ -947,7 +1088,7 @@ public class LeashDataImpl implements ILeashData {
|
||||||
infoTag.putInt("HolderID", info.holderIdOpt().get());
|
infoTag.putInt("HolderID", info.holderIdOpt().get());
|
||||||
infoTag.putString("LeashItem", info.reserved());
|
infoTag.putString("LeashItem", info.reserved());
|
||||||
infoTag.putDouble("MaxDistance", info.maxDistance());
|
infoTag.putDouble("MaxDistance", info.maxDistance());
|
||||||
infoTag.putDouble("ElasticDistance", info.elasticDistance());
|
infoTag.putDouble("ElasticDistance", info.elasticDistanceScale());
|
||||||
infoTag.putInt("KeepLeashTicks", info.keepLeashTicks());
|
infoTag.putInt("KeepLeashTicks", info.keepLeashTicks());
|
||||||
infoTag.putInt("MaxKeepLeashTicks", info.maxKeepLeashTicks());
|
infoTag.putInt("MaxKeepLeashTicks", info.maxKeepLeashTicks());
|
||||||
return infoTag;
|
return infoTag;
|
||||||
|
|
@ -958,6 +1099,19 @@ public class LeashDataImpl implements ILeashData {
|
||||||
leashHolders.clear();
|
leashHolders.clear();
|
||||||
leashKnots.clear();
|
leashKnots.clear();
|
||||||
delayedHolders.clear();
|
delayedHolders.clear();
|
||||||
|
if (nbt.contains("DefaultMaxDistance")) {
|
||||||
|
defaultMaxDistance = nbt.getDouble("DefaultMaxDistance");
|
||||||
|
if (nbt.contains("StaticMaxDistance")) {
|
||||||
|
staticMaxDistance = nbt.getDouble("StaticMaxDistance");
|
||||||
|
} else staticMaxDistance = null;
|
||||||
|
|
||||||
|
} else defaultMaxDistance = CommonEventHandler.leashConfigManager.getMaxLeashLength();
|
||||||
|
if(nbt.contains("DefaultElasticDistanceScale")) {
|
||||||
|
staticElasticDistanceScale = nbt.getDouble("DefaultElasticDistanceScale");
|
||||||
|
if (nbt.contains("StaticElasticDistanceScale")) {
|
||||||
|
staticElasticDistanceScale = nbt.getDouble("StaticElasticDistanceScale");
|
||||||
|
} else staticElasticDistanceScale = null;
|
||||||
|
} else staticElasticDistanceScale = CommonEventHandler.leashConfigManager.getElasticDistanceScale();
|
||||||
if (nbt.contains("LeashHolders", ListTag.TAG_LIST)) {
|
if (nbt.contains("LeashHolders", ListTag.TAG_LIST)) {
|
||||||
ListTag holdersList = nbt.getList("LeashHolders", ListTag.TAG_COMPOUND);
|
ListTag holdersList = nbt.getList("LeashHolders", ListTag.TAG_COMPOUND);
|
||||||
|
|
||||||
|
|
@ -1046,47 +1200,12 @@ public class LeashDataImpl implements ILeashData {
|
||||||
return Optional.empty(); // 理论上不会到这里
|
return Optional.empty(); // 理论上不会到这里
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static @NotNull List<Entity> leashableInArea(Level pLevel, Vec3 pPos, Predicate<Entity> filter) {
|
|
||||||
return leashableInArea(pLevel, pPos, filter, 1024D);
|
|
||||||
}
|
|
||||||
public static @NotNull List<Entity> leashableInArea(@NotNull Level pLevel, Vec3 pPos, Predicate<Entity> filter, double fetchDistance) {
|
|
||||||
AABB box = AABB.ofSize(pPos, fetchDistance, fetchDistance, fetchDistance);
|
|
||||||
return pLevel.getEntitiesOfClass(Entity.class, box, e -> LeashDataImpl.isLeashable(e) && filter.test(e));
|
|
||||||
}
|
|
||||||
public static @NotNull List<Entity> leashableInArea(@NotNull Entity entity, Predicate<Entity> filter, double fetchDistance) {
|
|
||||||
return leashableInArea(entity.level(), entity.getBoundingBox().getCenter(), filter, fetchDistance);
|
|
||||||
}
|
|
||||||
public static @NotNull List<Entity> leashableInArea(Entity entity, Predicate<Entity> filter) {
|
|
||||||
return leashableInArea(entity, filter, 1024D);
|
|
||||||
}
|
|
||||||
public static @NotNull List<Entity> leashableInArea(Entity holder) {
|
|
||||||
return leashableInArea(holder, i -> isLeashHolder(i, holder), 1024D);
|
|
||||||
}
|
|
||||||
public boolean canBeAttachedTo(Entity pEntity) {
|
public boolean canBeAttachedTo(Entity pEntity) {
|
||||||
if (pEntity == entity) {
|
if (pEntity == entity) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
Optional<LeashInfo> leashInfo = getLeashInfo(pEntity);
|
Optional<LeashInfo> leashInfo = getLeashInfo(pEntity);
|
||||||
return leashInfo.isEmpty() && (entity.distanceTo(pEntity) <= CommonEventHandler.leashConfigManager.getElasticDistance() * CommonEventHandler.leashConfigManager.getExtremeSnapFactor()) && canBeLeashed();//距离最大,则不可以被固定或转移
|
return leashInfo.isEmpty() && (entity.distanceTo(pEntity) <= CommonEventHandler.leashConfigManager.getElasticDistanceScale() * CommonEventHandler.leashConfigManager.getExtremeSnapFactor()) && canBeLeashed();//距离最大,则不可以被固定或转移
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static boolean isLeashHolder(@NotNull Entity pEntity, Entity pTestHolder) {
|
|
||||||
return pTestHolder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
|
||||||
isLeashHolder(pEntity, superLeashKnotEntity.getPos()) :
|
|
||||||
isLeashHolder(pEntity, pTestHolder.getUUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLeashHolder(@NotNull Entity pEntity, UUID pHolderUUID) {
|
|
||||||
return LeashDataAPI.getLeashData(pEntity)
|
|
||||||
.map(leashData -> leashData.isLeashedBy(pHolderUUID))
|
|
||||||
.orElse(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLeashHolder(@NotNull Entity pEntity, BlockPos pKnotPos) {
|
|
||||||
return LeashDataAPI.getLeashData(pEntity)
|
|
||||||
.map(leashData -> leashData.isLeashedBy(pKnotPos))
|
|
||||||
.orElse(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.superleadrope.CommonEventHandler;
|
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||||
import top.r3944realms.superleadrope.network.toClient.LeashStateSyncPacket;
|
import top.r3944realms.superleadrope.network.toClient.LeashStateSyncPacket;
|
||||||
|
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
/*
|
|
||||||
* Super Lead rope mod
|
|
||||||
* Copyright (C) 2025 R3944Realms
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package top.r3944realms.superleadrope.content.capability.inter;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraftforge.common.util.INBTSerializable;
|
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capability interface for managing leash data of entities and knots.
|
|
||||||
*/
|
|
||||||
public interface ILeashData extends INBTSerializable<CompoundTag> {
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Add / removeApplyEntity leashes
|
|
||||||
* ---------------------- */
|
|
||||||
boolean addLeash(Entity holder);
|
|
||||||
boolean addLeash(Entity holder, String reserved);
|
|
||||||
boolean addLeash(Entity holder, double maxDistance);
|
|
||||||
boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepTicks);
|
|
||||||
boolean addLeash(Entity holder, double maxDistance, String reserved);
|
|
||||||
boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
void addLeash(Entity holder, LeashInfo info);
|
|
||||||
|
|
||||||
void addDelayedLeash(Player holderPlayer);
|
|
||||||
void removeDelayedLeash(UUID onceHolderPlayerUUID);
|
|
||||||
|
|
||||||
boolean removeLeash(Entity holder);
|
|
||||||
boolean removeLeash(UUID holderUUID);
|
|
||||||
boolean removeLeash(BlockPos knotPos);
|
|
||||||
|
|
||||||
void removeAllLeashes();
|
|
||||||
void removeAllHolderLeashes();
|
|
||||||
void removeAllKnotLeashes();
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Modify leash properties
|
|
||||||
* ---------------------- */
|
|
||||||
boolean setMaxDistance(Entity holder, double distance);
|
|
||||||
boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks);
|
|
||||||
boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
boolean setMaxDistance(UUID holderUUID, double distance);
|
|
||||||
boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks);
|
|
||||||
boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
boolean setMaxDistance(BlockPos knotPos, double distance);
|
|
||||||
boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks);
|
|
||||||
boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
boolean setElasticDistance(Entity holder, double distance);
|
|
||||||
boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks);
|
|
||||||
boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
boolean setElasticDistance(UUID holderUUID, double distance);
|
|
||||||
boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks);
|
|
||||||
boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
boolean setElasticDistance(BlockPos knotPos, double distance);
|
|
||||||
boolean setElasticDistance(BlockPos knotPos, double distance, int maxKeepTicks);
|
|
||||||
boolean setElasticDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved);
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Apply physics
|
|
||||||
* ---------------------- */
|
|
||||||
void applyLeashForces();
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Transfer leash holders
|
|
||||||
* ---------------------- */
|
|
||||||
boolean transferLeash(Entity holder, Entity newHolder);
|
|
||||||
boolean transferLeash(Entity holder, Entity newHolder, String reserved);
|
|
||||||
|
|
||||||
boolean transferLeash(UUID holderUUID, Entity newHolder);
|
|
||||||
boolean transferLeash(UUID holderUUID, Entity newHolder, String reserved);
|
|
||||||
|
|
||||||
boolean transferLeash(BlockPos knotPos, Entity newHolder);
|
|
||||||
boolean transferLeash(BlockPos knotPos, Entity newHolder, String reserved);
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Query state
|
|
||||||
* ---------------------- */
|
|
||||||
boolean hasLeash();
|
|
||||||
boolean hasKnotLeash();
|
|
||||||
boolean hasHolderLeash();
|
|
||||||
|
|
||||||
Collection<LeashInfo> getAllLeashes();
|
|
||||||
|
|
||||||
boolean isLeashedBy(Entity holder);
|
|
||||||
boolean isLeashedBy(UUID holderUUID);
|
|
||||||
boolean isLeashedBy(BlockPos knotPos);
|
|
||||||
|
|
||||||
boolean isInDelayedLeash(UUID holderUUID);
|
|
||||||
|
|
||||||
Optional<LeashInfo> getLeashInfo(Entity holder);
|
|
||||||
Optional<LeashInfo> getLeashInfo(UUID holderUUID);
|
|
||||||
Optional<LeashInfo> getLeashInfo(BlockPos knotPos);
|
|
||||||
|
|
||||||
boolean canBeLeashed();
|
|
||||||
boolean canBeAttachedTo(Entity entity);
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Occupy / sync
|
|
||||||
* ---------------------- */
|
|
||||||
/**
|
|
||||||
* 抢占位(已离线玩家)。
|
|
||||||
* 用于解决玩家下线后所持有对象会移除持有者的问题(实际上是占用个弱集合)
|
|
||||||
*/
|
|
||||||
Optional<UUID> occupyLeash();
|
|
||||||
|
|
||||||
void markForSync();
|
|
||||||
void immediateSync();
|
|
||||||
void checkSync();
|
|
||||||
|
|
||||||
/* ----------------------
|
|
||||||
* Data record
|
|
||||||
* ---------------------- */
|
|
||||||
record LeashInfo(
|
|
||||||
Optional<BlockPos> blockPosOpt,
|
|
||||||
Optional<UUID> holderUUIDOpt,
|
|
||||||
Optional<Integer> holderIdOpt, // Only for client side use
|
|
||||||
String reserved, // 保留字段
|
|
||||||
double maxDistance,
|
|
||||||
double elasticDistance,
|
|
||||||
int keepLeashTicks, // 剩余 Tick 数
|
|
||||||
int maxKeepLeashTicks // 最大保持 Tick 数
|
|
||||||
) {
|
|
||||||
public static final LeashInfo EMPTY = new LeashInfo(
|
|
||||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
|
||||||
"", 12.0D, 6.0D, 0, 0
|
|
||||||
);
|
|
||||||
|
|
||||||
/* ---------- Factory ---------- */
|
|
||||||
public static LeashInfo create(
|
|
||||||
Entity entity,
|
|
||||||
String reserved,
|
|
||||||
double maxDistance,
|
|
||||||
double elasticDistance,
|
|
||||||
int keepTicks,
|
|
||||||
int maxKeepTicks
|
|
||||||
) {
|
|
||||||
return entity instanceof SuperLeashKnotEntity knot
|
|
||||||
? new LeashInfo(knot.getPos(), entity.getId(), reserved,
|
|
||||||
maxDistance, elasticDistance, keepTicks, maxKeepTicks)
|
|
||||||
: new LeashInfo(entity.getUUID(), entity.getId(), reserved, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeashInfo(UUID holderUUID, int holderId, String reserved,
|
|
||||||
double maxDistance, double elasticDistance, int keepTicks, int maxKeepTicks) {
|
|
||||||
this(Optional.empty(), Optional.of(holderUUID), Optional.of(holderId),
|
|
||||||
reserved, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeashInfo(BlockPos knotPos, int holderId, String reserved,
|
|
||||||
double maxDistance, double elasticDistance, int keepTicks, int maxKeepTicks) {
|
|
||||||
this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId),
|
|
||||||
reserved, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- State updates ---------- */
|
|
||||||
public LeashInfo decrementKeepTicks() {
|
|
||||||
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, reserved,
|
|
||||||
maxDistance, elasticDistance,
|
|
||||||
Math.max(0, keepLeashTicks - 1), maxKeepLeashTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeashInfo resetKeepTicks() {
|
|
||||||
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, reserved,
|
|
||||||
maxDistance, elasticDistance,
|
|
||||||
maxKeepLeashTicks, maxKeepLeashTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeashInfo transferHolder(Entity entity) {
|
|
||||||
return transferHolder(entity, reserved);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeashInfo transferHolder(Entity entity, String newReserved) {
|
|
||||||
boolean isKnot = entity instanceof SuperLeashKnotEntity;
|
|
||||||
return new LeashInfo(
|
|
||||||
isKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(),
|
|
||||||
!isKnot ? Optional.of(entity.getUUID()) : Optional.empty(),
|
|
||||||
Optional.of(entity.getId()),
|
|
||||||
newReserved, maxDistance, elasticDistance,
|
|
||||||
keepLeashTicks, maxKeepLeashTicks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -25,9 +25,9 @@ import net.minecraftforge.common.util.LazyOptional;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
|
|
||||||
public class LeashDataProvider implements ICapabilitySerializable<CompoundTag> {
|
public class LeashDataProvider implements ICapabilitySerializable<CompoundTag> {
|
||||||
public static final ResourceLocation LEASH_DATA_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_data");
|
public static final ResourceLocation LEASH_DATA_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_data");
|
||||||
|
|
@ -39,7 +39,7 @@ public class LeashDataProvider implements ICapabilitySerializable<CompoundTag> {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||||
return CapabilityHandler.LEASH_DATA_CAP.orEmpty(cap, optional);
|
return SLPCapability.LEASH_DATA_CAP.orEmpty(cap, optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.superleadrope.CommonEventHandler;
|
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashStateImpl;
|
import top.r3944realms.superleadrope.content.capability.impi.LeashStateImpl;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
|
|
||||||
public class LeashStateProvider implements ICapabilitySerializable<CompoundTag> {
|
public class LeashStateProvider implements ICapabilitySerializable<CompoundTag> {
|
||||||
public static final ResourceLocation LEASH_STATE_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_state");
|
public static final ResourceLocation LEASH_STATE_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_state");
|
||||||
|
|
@ -40,7 +40,7 @@ public class LeashStateProvider implements ICapabilitySerializable<CompoundTag>
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||||
return CapabilityHandler.LEASH_STATE_CAP.orEmpty(cap, optional);
|
return SLPCapability.LEASH_STATE_CAP.orEmpty(cap, optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,16 @@
|
||||||
package top.r3944realms.superleadrope.content.command;
|
package top.r3944realms.superleadrope.content.command;
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.arguments.*;
|
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.commands.arguments.*;
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
||||||
import net.minecraft.commands.arguments.selector.EntitySelector;
|
import net.minecraft.commands.arguments.selector.EntitySelector;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
@ -33,11 +35,11 @@ import net.minecraft.world.entity.Entity;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.superleadrope.CommonEventHandler;
|
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.content.gamerule.server.CreateSuperLeashKnotEntityIfAbsent;
|
import top.r3944realms.superleadrope.content.gamerule.server.CreateSuperLeashKnotEntityIfAbsent;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPGameruleRegistry;
|
import top.r3944realms.superleadrope.core.register.SLPGameruleRegistry;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -45,7 +47,6 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static top.r3944realms.superleadrope.content.command.Command.*;
|
import static top.r3944realms.superleadrope.content.command.Command.*;
|
||||||
import static top.r3944realms.superleadrope.content.command.Command.SHOULD_USE_PREFIX;
|
|
||||||
public class LeashDataCommand {
|
public class LeashDataCommand {
|
||||||
public static final String SLP_LEASH_MESSAGE_ = SuperLeadRope.MOD_ID + ".command.leash.message.";
|
public static final String SLP_LEASH_MESSAGE_ = SuperLeadRope.MOD_ID + ".command.leash.message.";
|
||||||
public static final String LEASH_DATA_GET_ = SLP_LEASH_MESSAGE_ + ".get.",
|
public static final String LEASH_DATA_GET_ = SLP_LEASH_MESSAGE_ + ".get.",
|
||||||
|
|
@ -67,19 +68,19 @@ public class LeashDataCommand {
|
||||||
.then(Commands.argument("maxDistance", DoubleArgumentType.doubleArg(1.0, 256.0))
|
.then(Commands.argument("maxDistance", DoubleArgumentType.doubleArg(1.0, 256.0))
|
||||||
.executes(context -> addLeash(context,
|
.executes(context -> addLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance")))
|
DoubleArgumentType.getDouble(context, "maxDistance")))
|
||||||
.then(Commands.argument("elasticDistance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
.then(Commands.argument("elasticDistanceScale", DoubleArgumentType.doubleArg(1.0, 128.0))
|
||||||
.executes(context -> addLeash(context,
|
.executes(context -> addLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance")))
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale")))
|
||||||
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
||||||
.executes(context -> addLeash(context,
|
.executes(context -> addLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance"),
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale"),
|
||||||
IntegerArgumentType.getInteger(context, "keepTicks")))
|
IntegerArgumentType.getInteger(context, "keepTicks")))
|
||||||
.then(Commands.argument("reserved", StringArgumentType.string())
|
.then(Commands.argument("reserved", StringArgumentType.string())
|
||||||
.executes(context -> addLeash(context,
|
.executes(context -> addLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance"),
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale"),
|
||||||
IntegerArgumentType.getInteger(context, "keepTicks"),
|
IntegerArgumentType.getInteger(context, "keepTicks"),
|
||||||
StringArgumentType.getString(context, "reserved")))
|
StringArgumentType.getString(context, "reserved")))
|
||||||
)
|
)
|
||||||
|
|
@ -92,19 +93,19 @@ public class LeashDataCommand {
|
||||||
.then(Commands.argument("maxDistance", DoubleArgumentType.doubleArg(1.0, 256.0))
|
.then(Commands.argument("maxDistance", DoubleArgumentType.doubleArg(1.0, 256.0))
|
||||||
.executes(context -> addBlockLeash(context,
|
.executes(context -> addBlockLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance")))
|
DoubleArgumentType.getDouble(context, "maxDistance")))
|
||||||
.then(Commands.argument("elasticDistance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
.then(Commands.argument("elasticDistanceScale", DoubleArgumentType.doubleArg(1.0, 128.0))
|
||||||
.executes(context -> addBlockLeash(context,
|
.executes(context -> addBlockLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance"), 0, ""))
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale"), 0, ""))
|
||||||
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
||||||
.executes(context -> addBlockLeash(context,
|
.executes(context -> addBlockLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance"),
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale"),
|
||||||
IntegerArgumentType.getInteger(context, "keepTicks")))
|
IntegerArgumentType.getInteger(context, "keepTicks")))
|
||||||
.then(Commands.argument("reserved", StringArgumentType.string())
|
.then(Commands.argument("reserved", StringArgumentType.string())
|
||||||
.executes(context -> addBlockLeash(context,
|
.executes(context -> addBlockLeash(context,
|
||||||
DoubleArgumentType.getDouble(context, "maxDistance"),
|
DoubleArgumentType.getDouble(context, "maxDistance"),
|
||||||
DoubleArgumentType.getDouble(context, "elasticDistance"),
|
DoubleArgumentType.getDouble(context, "elasticDistanceScale"),
|
||||||
IntegerArgumentType.getInteger(context, "keepTicks"),
|
IntegerArgumentType.getInteger(context, "keepTicks"),
|
||||||
StringArgumentType.getString(context, "reserved")))
|
StringArgumentType.getString(context, "reserved")))
|
||||||
)
|
)
|
||||||
|
|
@ -189,7 +190,7 @@ public class LeashDataCommand {
|
||||||
)
|
)
|
||||||
|
|
||||||
// 设置弹性距离
|
// 设置弹性距离
|
||||||
.then(Commands.literal("elasticDistance")
|
.then(Commands.literal("elasticDistanceScale")
|
||||||
.then(Commands.argument("distance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
.then(Commands.argument("distance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
||||||
.executes(context -> setElasticDistance(context, 0, ""))
|
.executes(context -> setElasticDistance(context, 0, ""))
|
||||||
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
||||||
|
|
@ -222,7 +223,7 @@ public class LeashDataCommand {
|
||||||
)
|
)
|
||||||
|
|
||||||
// 设置弹性距离
|
// 设置弹性距离
|
||||||
.then(Commands.literal("elasticDistance")
|
.then(Commands.literal("elasticDistanceScale")
|
||||||
.then(Commands.argument("distance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
.then(Commands.argument("distance", DoubleArgumentType.doubleArg(1.0, 128.0))
|
||||||
.executes(LeashDataCommand::setBlockElasticDistance)
|
.executes(LeashDataCommand::setBlockElasticDistance)
|
||||||
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
.then(Commands.argument("keepTicks", IntegerArgumentType.integer(0))
|
||||||
|
|
@ -350,18 +351,18 @@ public class LeashDataCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
Collection<ILeashData.LeashInfo> leashes = LeashDataAPI.QueryOperations.getAllLeashes(target);
|
Collection<LeashInfo> leashes = LeashDataInnerAPI.QueryOperations.getAllLeashes(target);
|
||||||
// +++
|
// +++
|
||||||
|
|
||||||
source.sendSuccess(() -> Component.literal("=== Leash Data for " + target.getName().getString() + " ==="), false);
|
source.sendSuccess(() -> Component.literal("=== Leash Data for " + target.getName().getString() + " ==="), false);
|
||||||
source.sendSuccess(() -> Component.literal("Total leashes: " + leashes.size()), false);
|
source.sendSuccess(() -> Component.literal("Total leashes: " + leashes.size()), false);
|
||||||
// TODO:翻译支持 HoverTip实现部分信息简化显示
|
// TODO:翻译支持 HoverTip实现部分信息简化显示
|
||||||
for (ILeashData.LeashInfo leash : leashes) {
|
for (LeashInfo leash : leashes) {
|
||||||
StringBuilder info = new StringBuilder();
|
StringBuilder info = new StringBuilder();
|
||||||
leash.blockPosOpt().ifPresent(pos -> info.append("Block: ").append(pos.toShortString()).append(" "));
|
leash.blockPosOpt().ifPresent(pos -> info.append("Block: ").append(pos.toShortString()).append(" "));
|
||||||
leash.holderUUIDOpt().ifPresent(uuid -> info.append("UUID: ").append(uuid).append(" "));
|
leash.holderUUIDOpt().ifPresent(uuid -> info.append("UUID: ").append(uuid).append(" "));
|
||||||
info.append("Max: ").append(leash.maxDistance()).append(" ");
|
info.append("Max: ").append(leash.maxDistance()).append(" ");
|
||||||
info.append("Elastic: ").append(leash.elasticDistance()).append(" ");
|
info.append("Elastic: ").append(leash.elasticDistanceScale()).append(" ");
|
||||||
info.append("Keep: ").append(leash.keepLeashTicks()).append("/").append(leash.maxKeepLeashTicks());
|
info.append("Keep: ").append(leash.keepLeashTicks()).append("/").append(leash.maxKeepLeashTicks());
|
||||||
if (!leash.reserved().isEmpty()) {
|
if (!leash.reserved().isEmpty()) {
|
||||||
info.append(" Reserved: ").append(leash.reserved());
|
info.append(" Reserved: ").append(leash.reserved());
|
||||||
|
|
@ -374,12 +375,12 @@ public class LeashDataCommand {
|
||||||
return targets.size();
|
return targets.size();
|
||||||
}
|
}
|
||||||
private static int addLeash(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
private static int addLeash(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||||
return addLeash(context, CommonEventHandler.leashConfigManager.getMaxLeashLength(), CommonEventHandler.leashConfigManager.getElasticDistance(), 0, "");
|
return addLeash(context, CommonEventHandler.leashConfigManager.getMaxLeashLength(), CommonEventHandler.leashConfigManager.getElasticDistanceScale(), 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int addLeash(CommandContext<CommandSourceStack> context,
|
private static int addLeash(CommandContext<CommandSourceStack> context,
|
||||||
double maxDistance) throws CommandSyntaxException {
|
double maxDistance) throws CommandSyntaxException {
|
||||||
return addLeash(context, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistance(), 0, "");
|
return addLeash(context, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistanceScale(), 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int addLeash(CommandContext<CommandSourceStack> context,
|
private static int addLeash(CommandContext<CommandSourceStack> context,
|
||||||
|
|
@ -398,7 +399,7 @@ public class LeashDataCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
List<Entity> successful = new ArrayList<>(), failed = new ArrayList<>();
|
List<Entity> successful = new ArrayList<>(), failed = new ArrayList<>();
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
if(LeashDataAPI.LeashOperations.attach(target, holder, maxDistance, elasticDistance, keepTicks, reserved)) {
|
if(LeashDataInnerAPI.LeashOperations.attach(target, holder, maxDistance, elasticDistance, keepTicks, reserved)) {
|
||||||
successful.add(target);
|
successful.add(target);
|
||||||
} else failed.add(target);
|
} else failed.add(target);
|
||||||
}
|
}
|
||||||
|
|
@ -406,11 +407,11 @@ public class LeashDataCommand {
|
||||||
return successful.size();
|
return successful.size();
|
||||||
}
|
}
|
||||||
private static int addBlockLeash(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
private static int addBlockLeash(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||||
return addBlockLeash(context, CommonEventHandler.leashConfigManager.getMaxLeashLength(), CommonEventHandler.leashConfigManager.getElasticDistance(), 0, "");
|
return addBlockLeash(context, CommonEventHandler.leashConfigManager.getMaxLeashLength(), CommonEventHandler.leashConfigManager.getElasticDistanceScale(), 0, "");
|
||||||
}
|
}
|
||||||
private static int addBlockLeash(CommandContext<CommandSourceStack> context,
|
private static int addBlockLeash(CommandContext<CommandSourceStack> context,
|
||||||
double maxDistance) throws CommandSyntaxException {
|
double maxDistance) throws CommandSyntaxException {
|
||||||
return addBlockLeash(context, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistance(), 0, "");
|
return addBlockLeash(context, maxDistance, CommonEventHandler.leashConfigManager.getElasticDistanceScale(), 0, "");
|
||||||
}
|
}
|
||||||
private static int addBlockLeash(CommandContext<CommandSourceStack> context,
|
private static int addBlockLeash(CommandContext<CommandSourceStack> context,
|
||||||
double maxDistance, double elasticDistance, int keepTicks) throws CommandSyntaxException {
|
double maxDistance, double elasticDistance, int keepTicks) throws CommandSyntaxException {
|
||||||
|
|
@ -435,7 +436,7 @@ public class LeashDataCommand {
|
||||||
}
|
}
|
||||||
List<Entity> successful = new ArrayList<>(), failed = new ArrayList<>();
|
List<Entity> successful = new ArrayList<>(), failed = new ArrayList<>();
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
if(LeashDataAPI.LeashOperations.attach(target, knotEntity, maxDistance, elasticDistance, keepTicks, reserved)) {
|
if(LeashDataInnerAPI.LeashOperations.attach(target, knotEntity, maxDistance, elasticDistance, keepTicks, reserved)) {
|
||||||
successful.add(target);
|
successful.add(target);
|
||||||
} else failed.add(target);
|
} else failed.add(target);
|
||||||
}
|
}
|
||||||
|
|
@ -450,7 +451,7 @@ public class LeashDataCommand {
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
boolean success = LeashDataAPI.LeashOperations.detach(target, holder);
|
boolean success = LeashDataInnerAPI.LeashOperations.detach(target, holder);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
@ -472,7 +473,7 @@ public class LeashDataCommand {
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
boolean success = LeashDataAPI.LeashOperations.detach(target, pos);
|
boolean success = LeashDataInnerAPI.LeashOperations.detach(target, pos);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
@ -492,7 +493,7 @@ public class LeashDataCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
LeashDataAPI.LeashOperations.detachAll(target);
|
LeashDataInnerAPI.LeashOperations.detachAll(target);
|
||||||
source.sendSuccess(() -> Component.literal("Removed all leashes from " + target.getName().getString()), false);
|
source.sendSuccess(() -> Component.literal("Removed all leashes from " + target.getName().getString()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -512,8 +513,8 @@ public class LeashDataCommand {
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
boolean success = reserved.isEmpty() ?
|
boolean success = reserved.isEmpty() ?
|
||||||
LeashDataAPI.TransferOperations.transfer(target, from, to) :
|
LeashDataInnerAPI.TransferOperations.transfer(target, from, to) :
|
||||||
LeashDataAPI.TransferOperations.transfer(target, from, to, reserved);
|
LeashDataInnerAPI.TransferOperations.transfer(target, from, to, reserved);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
@ -532,7 +533,7 @@ public class LeashDataCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
|
|
||||||
for (Entity target : targets) {
|
for (Entity target : targets) {
|
||||||
LeashDataAPI.PhysicsOperations.applyForces(target);
|
LeashDataInnerAPI.PhysicsOperations.applyForces(target);
|
||||||
source.sendSuccess(() -> Component.literal("Applied leash forces to " + target.getName().getString()), false);
|
source.sendSuccess(() -> Component.literal("Applied leash forces to " + target.getName().getString()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -81,9 +81,9 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
||||||
this.kill();
|
this.kill();
|
||||||
this.markHurt();
|
this.markHurt();
|
||||||
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
||||||
List<Entity> entities = LeashDataImpl.leashableInArea(this.level(), pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, this));
|
List<Entity> entities = SuperLeadRopeApi.leashableInArea(this.level(), pos.getCenter(), entity -> SuperLeadRopeApi.isLeashHolder(entity, this));
|
||||||
entities.forEach(entity ->
|
entities.forEach(entity ->
|
||||||
LeashDataAPI.getLeashData(entity)
|
LeashDataInnerAPI.getLeashData(entity)
|
||||||
.map(iLeashDataCapability -> iLeashDataCapability.removeLeash(this))
|
.map(iLeashDataCapability -> iLeashDataCapability.removeLeash(this))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +96,8 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
||||||
public boolean survives() {
|
public boolean survives() {
|
||||||
boolean supportBlock = SuperLeashKnotEntity.isSupportBlock(this.level().getBlockState(this.pos));
|
boolean supportBlock = SuperLeashKnotEntity.isSupportBlock(this.level().getBlockState(this.pos));
|
||||||
if (!supportBlock) {
|
if (!supportBlock) {
|
||||||
for (Entity entity : LeashDataImpl.leashableInArea(this)) {
|
for (Entity entity : SuperLeadRopeApi.leashableInArea(this)) {
|
||||||
LeashDataAPI.LeashOperations.detach(entity, this);
|
LeashDataInnerAPI.LeashOperations.detach(entity, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return supportBlock;
|
return supportBlock;
|
||||||
|
|
@ -193,10 +193,10 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
AtomicBoolean isTransferLeash = new AtomicBoolean(false);
|
AtomicBoolean isTransferLeash = new AtomicBoolean(false);
|
||||||
List<Entity> entities = LeashDataImpl.leashableInArea(player);
|
List<Entity> entities = SuperLeadRopeApi.leashableInArea(player);
|
||||||
for(Entity entity : entities) {
|
for(Entity entity : entities) {
|
||||||
if (LeashDataImpl.isLeashHolder(entity, player.getUUID()))
|
if (SuperLeadRopeApi.isLeashHolder(entity, player.getUUID()))
|
||||||
LeashDataAPI.getLeashData(entity)
|
LeashDataInnerAPI.getLeashData(entity)
|
||||||
.ifPresent(i -> {
|
.ifPresent(i -> {
|
||||||
i.transferLeash(player.getUUID(), this);
|
i.transferLeash(player.getUUID(), this);
|
||||||
isTransferLeash.set(true);
|
isTransferLeash.set(true);
|
||||||
|
|
@ -207,9 +207,9 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
||||||
if (((ServerPlayer) player).gameMode.getGameModeForPlayer() != GameType.ADVENTURE) {
|
if (((ServerPlayer) player).gameMode.getGameModeForPlayer() != GameType.ADVENTURE) {
|
||||||
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
||||||
this.discard();
|
this.discard();
|
||||||
List<Entity> entities1 = LeashDataImpl.leashableInArea(this);
|
List<Entity> entities1 = SuperLeadRopeApi.leashableInArea(this);
|
||||||
entities1.forEach(entity ->
|
entities1.forEach(entity ->
|
||||||
LeashDataAPI.getLeashData(entity)
|
LeashDataInnerAPI.getLeashData(entity)
|
||||||
.ifPresent(iLeashDataCapability -> {
|
.ifPresent(iLeashDataCapability -> {
|
||||||
iLeashDataCapability.removeLeash(this);
|
iLeashDataCapability.removeLeash(this);
|
||||||
isRemoveLeashKnot.set(true);
|
isRemoveLeashKnot.set(true);
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||||||
import net.minecraftforge.common.extensions.IForgeItem;
|
import net.minecraftforge.common.extensions.IForgeItem;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
import top.r3944realms.superleadrope.content.SLPToolTier;
|
import top.r3944realms.superleadrope.content.SLPToolTier;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
|
||||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -121,13 +121,13 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
||||||
boolean isSuccess = false;
|
boolean isSuccess = false;
|
||||||
|
|
||||||
// 查找当前玩家持有的可拴生物
|
// 查找当前玩家持有的可拴生物
|
||||||
List<Entity> list = LeashDataImpl.leashableInArea(
|
List<Entity> list = SuperLeadRopeApi.leashableInArea(
|
||||||
level, pos.getCenter(),
|
level, pos.getCenter(),
|
||||||
entity -> LeashDataImpl.isLeashHolder(entity, player.getUUID())
|
entity -> SuperLeadRopeApi.isLeashHolder(entity, player.getUUID())
|
||||||
);
|
);
|
||||||
|
|
||||||
for (Entity e : list) {
|
for (Entity e : list) {
|
||||||
Optional<ILeashData> leashDataOpt = LeashDataAPI.getLeashData(e);
|
Optional<ILeashData> leashDataOpt = LeashDataInnerAPI.getLeashData(e);
|
||||||
|
|
||||||
if (leashDataOpt.map(i -> i.canBeAttachedTo(newHolder)).orElse(false)) {
|
if (leashDataOpt.map(i -> i.canBeAttachedTo(newHolder)).orElse(false)) {
|
||||||
leashDataOpt.ifPresent(i -> i.transferLeash(player.getUUID(), newHolder));
|
leashDataOpt.ifPresent(i -> i.transferLeash(player.getUUID(), newHolder));
|
||||||
|
|
@ -170,8 +170,8 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
||||||
AtomicBoolean isSuccess = new AtomicBoolean(false);
|
AtomicBoolean isSuccess = new AtomicBoolean(false);
|
||||||
UUID uuid = player.getUUID();
|
UUID uuid = player.getUUID();
|
||||||
|
|
||||||
List<Entity> list = LeashDataImpl.leashableInArea(level, pos.getCenter(),
|
List<Entity> list = SuperLeadRopeApi.leashableInArea(level, pos.getCenter(),
|
||||||
entity -> LeashDataImpl.isLeashHolder(entity, uuid));
|
entity -> SuperLeadRopeApi.isLeashHolder(entity, uuid));
|
||||||
|
|
||||||
// 情况一:拴自己到新 knot
|
// 情况一:拴自己到新 knot
|
||||||
if (shouldBindSelf && list.isEmpty()) {
|
if (shouldBindSelf && list.isEmpty()) {
|
||||||
|
|
@ -182,7 +182,7 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
||||||
knot.playPlacementSound();
|
knot.playPlacementSound();
|
||||||
|
|
||||||
SuperLeashKnotEntity finalKnot = knot;
|
SuperLeashKnotEntity finalKnot = knot;
|
||||||
LeashDataAPI.getLeashData(player).ifPresent(i -> {
|
LeashDataInnerAPI.getLeashData(player).ifPresent(i -> {
|
||||||
if (i.canBeAttachedTo(finalKnot)) {
|
if (i.canBeAttachedTo(finalKnot)) {
|
||||||
if (!level.isClientSide) i.addLeash(finalKnot);
|
if (!level.isClientSide) i.addLeash(finalKnot);
|
||||||
isSuccess.set(true);
|
isSuccess.set(true);
|
||||||
|
|
@ -198,7 +198,7 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
||||||
}
|
}
|
||||||
SuperLeashKnotEntity finalKnot = knot;
|
SuperLeashKnotEntity finalKnot = knot;
|
||||||
|
|
||||||
LeashDataAPI.getLeashData(e).ifPresent(i -> {
|
LeashDataInnerAPI.getLeashData(e).ifPresent(i -> {
|
||||||
if (i.canBeAttachedTo(finalKnot)) {
|
if (i.canBeAttachedTo(finalKnot)) {
|
||||||
if (!level.isClientSide) i.transferLeash(uuid, finalKnot);
|
if (!level.isClientSide) i.transferLeash(uuid, finalKnot);
|
||||||
isSuccess.set(true);
|
isSuccess.set(true);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import net.minecraft.client.renderer.culling.Frustum;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.Mob;
|
import net.minecraft.world.entity.Mob;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
@ -28,7 +28,7 @@ public class LeashRenderHook {
|
||||||
public static boolean shouldRenderExtra(Mob mob, Frustum camera) {
|
public static boolean shouldRenderExtra(Mob mob, Frustum camera) {
|
||||||
SuperLeadRope.logger.debug("[SuperLeash] Checking entity: {} at position: {}, {}, {}", mob.getName().getString(), mob.getX(), mob.getY(), mob.getZ());
|
SuperLeadRope.logger.debug("[SuperLeash] Checking entity: {} at position: {}, {}, {}", mob.getName().getString(), mob.getX(), mob.getY(), mob.getZ());
|
||||||
AtomicBoolean flag = new AtomicBoolean(false);
|
AtomicBoolean flag = new AtomicBoolean(false);
|
||||||
LeashDataAPI.getLeashData(mob).ifPresent(i -> {
|
LeashDataInnerAPI.getLeashData(mob).ifPresent(i -> {
|
||||||
i.getAllLeashes().forEach(j -> {
|
i.getAllLeashes().forEach(j -> {
|
||||||
Optional<Integer> i1 = j.holderIdOpt();
|
Optional<Integer> i1 = j.holderIdOpt();
|
||||||
if (i1.isPresent()) {
|
if (i1.isPresent()) {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
package top.r3944realms.superleadrope.core.leash;
|
package top.r3944realms.superleadrope.core.leash;
|
||||||
|
|
||||||
|
|
||||||
import net.minecraft.sounds.SoundEvent;
|
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.sounds.SoundSource;
|
import net.minecraft.sounds.SoundSource;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
|
|
@ -28,12 +27,13 @@ import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||||||
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ public class LeashInteractHandler {
|
||||||
if (!LeashDataImpl.isLeashable(target)) {
|
if (!LeashDataImpl.isLeashable(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Optional<ILeashData> LeashCap = LeashDataAPI.getLeashData(target);
|
Optional<ILeashData> LeashCap = LeashDataInnerAPI.getLeashData(target);
|
||||||
if (LeashCap.isEmpty()) {
|
if (LeashCap.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ public class LeashInteractHandler {
|
||||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (LeashDataImpl.isLeashHolder(target, player)) {
|
if (SuperLeadRopeApi.isLeashHolder(target, player)) {
|
||||||
LeashCap.ifPresent(
|
LeashCap.ifPresent(
|
||||||
iLeashDataCapability -> iLeashDataCapability.removeLeash(player.getUUID())
|
iLeashDataCapability -> iLeashDataCapability.removeLeash(player.getUUID())
|
||||||
);
|
);
|
||||||
|
|
@ -127,7 +127,7 @@ public class LeashInteractHandler {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (flag) {
|
if (flag) {
|
||||||
LeashDataAPI.getLeashData(target).ifPresent(leashDataCapability -> {
|
LeashDataInnerAPI.getLeashData(target).ifPresent(leashDataCapability -> {
|
||||||
if (leashDataCapability.hasLeash()){
|
if (leashDataCapability.hasLeash()){
|
||||||
int size = leashDataCapability.getAllLeashes().size();
|
int size = leashDataCapability.getAllLeashes().size();
|
||||||
if (player.isSecondaryUseActive())
|
if (player.isSecondaryUseActive())
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
package top.r3944realms.superleadrope.core.leash;
|
package top.r3944realms.superleadrope.core.leash;
|
||||||
|
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ public record LeashDataSyncPacket(int entityId, CompoundTag leashData) {
|
||||||
if (level != null) {
|
if (level != null) {
|
||||||
Entity entity = level.getEntity(msg.entityId);
|
Entity entity = level.getEntity(msg.entityId);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
LeashDataAPI.getLeashData(entity).ifPresent(cap -> {
|
LeashDataInnerAPI.getLeashData(entity).ifPresent(cap -> {
|
||||||
// 只在数据确实变化时更新
|
// 只在数据确实变化时更新
|
||||||
CompoundTag current = cap.serializeNBT();
|
CompoundTag current = cap.serializeNBT();
|
||||||
if (!current.equals(msg.leashData)) {
|
if (!current.equals(msg.leashData)) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ public record LeashStateSyncPacket(int entityId, CompoundTag leashState) {
|
||||||
if (level != null) {
|
if (level != null) {
|
||||||
Entity entity = level.getEntity(msg.entityId);
|
Entity entity = level.getEntity(msg.entityId);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).ifPresent(cap -> {
|
entity.getCapability(SLPCapability.LEASH_STATE_CAP).ifPresent(cap -> {
|
||||||
// 只在数据确实变化时更新
|
// 只在数据确实变化时更新
|
||||||
CompoundTag current = cap.serializeNBT();
|
CompoundTag current = cap.serializeNBT();
|
||||||
if (!current.equals(msg.leashState)) {
|
if (!current.equals(msg.leashState)) {
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ package top.r3944realms.superleadrope.util.capability;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
@ -28,11 +30,12 @@ import java.util.*;
|
||||||
* 拴绳数据API - 提供统一的API接口操作拴绳数据能力
|
* 拴绳数据API - 提供统一的API接口操作拴绳数据能力
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class LeashDataAPI {
|
@ApiStatus.Internal
|
||||||
|
public final class LeashDataInnerAPI {
|
||||||
// ==================== 基础能力获取 ====================
|
// ==================== 基础能力获取 ====================
|
||||||
public static Optional<ILeashData> getLeashData(@NotNull Entity entity) {
|
public static @NotNull Optional<ILeashData> getLeashData(@NotNull Entity entity) {
|
||||||
Objects.requireNonNull(entity, "Entity cannot be null");
|
Objects.requireNonNull(entity, "Entity cannot be null");
|
||||||
return entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).resolve();
|
return entity.getCapability(SLPCapability.LEASH_DATA_CAP).resolve();
|
||||||
}
|
}
|
||||||
// ==================== 拴绳数据管理 API ====================
|
// ==================== 拴绳数据管理 API ====================
|
||||||
|
|
||||||
|
|
@ -64,7 +67,7 @@ public final class LeashDataAPI {
|
||||||
return getLeashData(entity).map(data -> data.addLeash(holder, maxDistance, elasticDistance, maxKeepTicks, reserved)).orElse(false);
|
return getLeashData(entity).map(data -> data.addLeash(holder, maxDistance, elasticDistance, maxKeepTicks, reserved)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void attachWithInfo(Entity entity, Entity holder, ILeashData.LeashInfo info) {
|
public static void attachWithInfo(Entity entity, Entity holder, LeashInfo info) {
|
||||||
getLeashData(entity).ifPresent(data -> data.addLeash(holder, info));
|
getLeashData(entity).ifPresent(data -> data.addLeash(holder, info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,39 +150,39 @@ public final class LeashDataAPI {
|
||||||
|
|
||||||
// ---------------------- 设置弹性距离 ----------------------
|
// ---------------------- 设置弹性距离 ----------------------
|
||||||
public static boolean setElasticDistance(Entity entity, Entity holder, double distance) {
|
public static boolean setElasticDistance(Entity entity, Entity holder, double distance) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holder, distance)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holder, distance)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, Entity holder, double distance, int maxKeepTicks) {
|
public static boolean setElasticDistance(Entity entity, Entity holder, double distance, int maxKeepTicks) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holder, distance, maxKeepTicks)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holder, distance, maxKeepTicks)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, Entity holder, double distance, int maxKeepTicks, String reserved) {
|
public static boolean setElasticDistance(Entity entity, Entity holder, double distance, int maxKeepTicks, String reserved) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holder, distance, maxKeepTicks, reserved)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holder, distance, maxKeepTicks, reserved)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance) {
|
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holderUUID, distance)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holderUUID, distance)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance, int maxKeepTicks) {
|
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance, int maxKeepTicks) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holderUUID, distance, maxKeepTicks)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holderUUID, distance, maxKeepTicks)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
public static boolean setElasticDistance(Entity entity, UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(holderUUID, distance, maxKeepTicks, reserved)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(holderUUID, distance, maxKeepTicks, reserved)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance) {
|
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(knotPos, distance)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(knotPos, distance)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance, int maxKeepTicks) {
|
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance, int maxKeepTicks) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(knotPos, distance, maxKeepTicks)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(knotPos, distance, maxKeepTicks)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance, int maxKeepTicks, String reserved) {
|
public static boolean setElasticDistance(Entity entity, BlockPos knotPos, double distance, int maxKeepTicks, String reserved) {
|
||||||
return getLeashData(entity).map(data -> data.setElasticDistance(knotPos, distance, maxKeepTicks, reserved)).orElse(false);
|
return getLeashData(entity).map(data -> data.setElasticDistanceScale(knotPos, distance, maxKeepTicks, reserved)).orElse(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,7 +243,7 @@ public final class LeashDataAPI {
|
||||||
return getLeashData(entity).map(ILeashData::hasHolderLeash).orElse(false);
|
return getLeashData(entity).map(ILeashData::hasHolderLeash).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<ILeashData.LeashInfo> getAllLeashes(Entity entity) {
|
public static Collection<LeashInfo> getAllLeashes(Entity entity) {
|
||||||
return getLeashData(entity).map(ILeashData::getAllLeashes).orElse(Collections.emptyList());
|
return getLeashData(entity).map(ILeashData::getAllLeashes).orElse(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,15 +263,15 @@ public final class LeashDataAPI {
|
||||||
return getLeashData(entity).map(data -> data.isInDelayedLeash(holderUUID)).orElse(false);
|
return getLeashData(entity).map(data -> data.isInDelayedLeash(holderUUID)).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ILeashData.LeashInfo> getLeashInfo(Entity entity, Entity holder) {
|
public static Optional<LeashInfo> getLeashInfo(Entity entity, Entity holder) {
|
||||||
return getLeashData(entity).flatMap(data -> data.getLeashInfo(holder));
|
return getLeashData(entity).flatMap(data -> data.getLeashInfo(holder));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ILeashData.LeashInfo> getLeashInfo(Entity entity, UUID holderUUID) {
|
public static Optional<LeashInfo> getLeashInfo(Entity entity, UUID holderUUID) {
|
||||||
return getLeashData(entity).flatMap(data -> data.getLeashInfo(holderUUID));
|
return getLeashData(entity).flatMap(data -> data.getLeashInfo(holderUUID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ILeashData.LeashInfo> getLeashInfo(Entity entity, BlockPos knotPos) {
|
public static Optional<LeashInfo> getLeashInfo(Entity entity, BlockPos knotPos) {
|
||||||
return getLeashData(entity).flatMap(data -> data.getLeashInfo(knotPos));
|
return getLeashData(entity).flatMap(data -> data.getLeashInfo(knotPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,9 +18,10 @@ package top.r3944realms.superleadrope.util.capability;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashState;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -28,14 +29,15 @@ import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class LeashStateAPI {
|
@ApiStatus.Internal
|
||||||
|
public final class LeashStateInnerAPI {
|
||||||
|
|
||||||
private LeashStateAPI() {
|
private LeashStateInnerAPI() {
|
||||||
} // 防止实例化
|
} // 防止实例化
|
||||||
|
|
||||||
public static Optional<ILeashState> getLeashState(@NotNull Entity entity) {
|
public static @NotNull Optional<ILeashState> getLeashState(@NotNull Entity entity) {
|
||||||
Objects.requireNonNull(entity, "Entity cannot be null");
|
Objects.requireNonNull(entity, "Entity cannot be null");
|
||||||
return entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).resolve();
|
return entity.getCapability(SLPCapability.LEASH_STATE_CAP).resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 查询操作 ====================
|
// ==================== 查询操作 ====================
|
||||||
|
|
@ -19,6 +19,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.config.ModConfig;
|
import net.minecraftforge.fml.config.ModConfig;
|
||||||
import net.minecraftforge.fml.loading.FMLPaths;
|
import net.minecraftforge.fml.loading.FMLPaths;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -48,7 +49,7 @@ public class ConfigUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerConfig (
|
public static void registerConfig (
|
||||||
ModLoadingContext context,
|
@NotNull ModLoadingContext context,
|
||||||
ModConfig.Type type,
|
ModConfig.Type type,
|
||||||
ForgeConfigSpec configSpec,
|
ForgeConfigSpec configSpec,
|
||||||
String folderName,
|
String folderName,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class NBTReader {
|
public class NBTReader {
|
||||||
|
private NBTReader() {}
|
||||||
public static Vec3 readVec3(CompoundTag nbt) {
|
public static Vec3 readVec3(CompoundTag nbt) {
|
||||||
if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) {
|
if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) {
|
||||||
return new Vec3(
|
return new Vec3(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class NBTWriter {
|
public class NBTWriter {
|
||||||
|
private NBTWriter() {}
|
||||||
public static CompoundTag writeVec3(Vec3 vec) {
|
public static CompoundTag writeVec3(Vec3 vec) {
|
||||||
CompoundTag nbt = new CompoundTag();
|
CompoundTag nbt = new CompoundTag();
|
||||||
if (vec == null) throw new IllegalArgumentException("Vec3 cannot be null");
|
if (vec == null) throw new IllegalArgumentException("Vec3 cannot be null");
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ package top.r3944realms.superleadrope.util.riding;
|
||||||
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.Mob;
|
|
||||||
import net.minecraft.world.entity.ai.goal.Goal;
|
import net.minecraft.world.entity.ai.goal.Goal;
|
||||||
import net.minecraft.world.entity.animal.Animal;
|
import net.minecraft.world.entity.animal.Animal;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.workspace;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||||
|
import top.r3944realms.superleadrope.api.SLPCapability;
|
||||||
|
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
||||||
|
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||||
|
import top.r3944realms.superleadrope.api.type.util.ILeashHelper;
|
||||||
|
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class LeashHelper implements ILeashHelper {
|
||||||
|
@Override
|
||||||
|
public IHolder getHolderHelper(Entity holder) {
|
||||||
|
return new IHolder() {
|
||||||
|
@Override
|
||||||
|
public Entity getHolderEntity() {
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ILeashData> getAllLeashData() {
|
||||||
|
return SuperLeadRopeApi.leashableInArea(getHolderEntity())
|
||||||
|
.stream()
|
||||||
|
.map(i -> i.getCapability(SLPCapability.LEASH_DATA_CAP).resolve())
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean leashEntity(UUID uuid) {
|
||||||
|
Entity entity = CommonEventHandler.Game.getServerLevel().getEntity(uuid);
|
||||||
|
if (entity != null && SuperLeadRopeApi.isLeashable(entity)) {
|
||||||
|
return LeashDataInnerAPI.getLeashData(entity).map(i-> i.addLeash(entity)).orElse(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean unleashEntity(UUID uuid) {
|
||||||
|
Entity entity = CommonEventHandler.Game.getServerLevel().getEntity(uuid);
|
||||||
|
if (entity != null && SuperLeadRopeApi.isLeashable(entity)) {
|
||||||
|
return LeashDataInnerAPI.getLeashData(entity).map(i-> i.removeLeash(entity)).orElse(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ILeashed getLeashedHelper(Entity leashed) {
|
||||||
|
return () -> LeashDataInnerAPI.getLeashData(leashed).orElseThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Super Lead rope mod
|
||||||
|
* Copyright (C) 2025 R3944Realms
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package top.r3944realms.superleadrope.workspace;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.superleadrope.api.type.util.ILeashHelper;
|
||||||
|
import top.r3944realms.superleadrope.api.workspace.IWorkSpaceHelper;
|
||||||
|
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||||
|
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class WorkSpaceHelper implements IWorkSpaceHelper {
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Entity> leashableInArea(@NotNull Level pLevel, Vec3 pPos, Predicate<Entity> filter, double fetchDistance) {
|
||||||
|
AABB box = AABB.ofSize(pPos, fetchDistance, fetchDistance, fetchDistance);
|
||||||
|
return pLevel.getEntitiesOfClass(Entity.class, box, e -> LeashDataImpl.isLeashable(e) && filter.test(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ILeashHelper getLeashHelper() {
|
||||||
|
return new LeashHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuperLeadKnot(Entity pEntity) {
|
||||||
|
return pEntity instanceof SuperLeashKnotEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockPos getSuperLeadPos(Entity pEntity) throws IllegalArgumentException {
|
||||||
|
if (isSuperLeadKnot(pEntity)) {
|
||||||
|
return (((SuperLeashKnotEntity) pEntity).getPos());
|
||||||
|
}
|
||||||
|
else throw new IllegalArgumentException(pEntity.getClass().getName() + " is not a superlead knot");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeashable(@NotNull Entity pEntity) {
|
||||||
|
return LeashDataImpl.isLeashable(pEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
top.r3944realms.superleadrope.workspace.WorkSpaceHelper
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
package top.r3944realms.superleadropetest;
|
package top.r3944realms.superleadropetest;
|
||||||
|
|
||||||
import top.r3944realms.superleadrope.util.capability.LeashDataAPI;
|
|
||||||
|
|
||||||
public class Placeholder {
|
public class Placeholder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user