feat:调整配置 & fix: 修正渲染问题
This commit is contained in:
parent
c878df45e9
commit
0ecebeba88
|
|
@ -151,6 +151,7 @@ dependencies {
|
|||
modCompileOnly("blank:curtain-1.20.1:1.3.2")
|
||||
modRuntimeOnly("blank:curtain-1.20.1:1.3.2")
|
||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge-api:${jei_version}")
|
||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-common-api:${jei_version}")
|
||||
modRuntimeOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
||||
modRuntimeOnly("curse.maven:spark-361579:4738952")
|
||||
compileOnly ('me.lucko:spark-api:0.1-SNAPSHOT')
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public class CommonEventHandler {
|
|||
public static void onEntityJoinWorld(EntityJoinLevelEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (entity.level().isClientSide) return;
|
||||
if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) {
|
||||
if (LeashDataImpl.isLeashable(entity)) {
|
||||
LeashDataAPI.getLeashData(entity).ifPresent(LeashSyncManager.Data::track);
|
||||
LeashStateAPI.getLeashState(entity).ifPresent(LeashSyncManager.State::track);
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
|
|
@ -113,7 +113,7 @@ public class CommonEventHandler {
|
|||
public static void onEntityLeaveWorld(EntityLeaveLevelEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (entity.level().isClientSide) return;
|
||||
if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) {
|
||||
if (LeashDataImpl.isLeashable(entity)) {
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
LeashSyncManager.Data.forEach(i -> {
|
||||
if(i.isLeashedBy(serverPlayer)) {
|
||||
|
|
|
|||
|
|
@ -167,9 +167,13 @@ public class SuperLeashStateResolver {
|
|||
if (entity instanceof Player player && (player.isFallFlying() || player.isAutoSpinAttack())) {
|
||||
roll = getRoll(player, partialTicks, roll);
|
||||
}
|
||||
|
||||
boolean isFirstPerson = Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON;
|
||||
// 应用旋转到局部偏移
|
||||
Vec3 rotatedOffset = localOffset.yRot(-yaw).zRot(-roll);
|
||||
Vec3 rotatedOffset = localOffset;
|
||||
if (!isFirstPerson && entity instanceof Player) {
|
||||
rotatedOffset = rotatedOffset.add(0,0,0.2);
|
||||
}
|
||||
rotatedOffset = rotatedOffset.yRot(-yaw).zRot(-roll);
|
||||
|
||||
// 返回世界坐标
|
||||
return centerPos.add(rotatedOffset);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.compat.jei;
|
||||
|
||||
import mezz.jei.api.IModPlugin;
|
||||
import mezz.jei.api.JeiPlugin;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
|
||||
@JeiPlugin
|
||||
public class JEIPlugin implements IModPlugin {
|
||||
private static final ResourceLocation UID = new ResourceLocation(SuperLeadRope.MOD_ID, "jei_plugin");
|
||||
|
||||
@Override
|
||||
public @NotNull ResourceLocation getPluginUid() {
|
||||
return UID;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,3 @@
|
|||
/*
|
||||
* 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.config;
|
||||
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
|
|
@ -22,38 +7,61 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
public class LeashCommonConfig {
|
||||
public static ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
public static ForgeConfigSpec SPEC;
|
||||
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
public static final ForgeConfigSpec SPEC;
|
||||
public static final Common COMMON;
|
||||
|
||||
static {
|
||||
BUILDER.comment("Leash Common Config");
|
||||
COMMON = new Common(BUILDER);
|
||||
SPEC = BUILDER.build();
|
||||
}
|
||||
|
||||
public static class Common {
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> teleportWhitelist;
|
||||
// Command
|
||||
public final ForgeConfigSpec.BooleanValue enableSLPModCommandPrefix;
|
||||
public final ForgeConfigSpec.ConfigValue<String> SLPModCommandPrefix;
|
||||
public final ForgeConfigSpec.BooleanValue EnableSLPModCommandPrefix;
|
||||
|
||||
// Entity
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> teleportWhitelist;
|
||||
|
||||
// Leash settings
|
||||
public final ForgeConfigSpec.DoubleValue maxLeashLength;
|
||||
public final ForgeConfigSpec.DoubleValue elasticDistance;
|
||||
public final ForgeConfigSpec.DoubleValue extremeSnapFactor;
|
||||
public final ForgeConfigSpec.DoubleValue springDampening;
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends Double>> axisSpecificElasticity;
|
||||
public final ForgeConfigSpec.IntValue maxLeashesPerEntity;
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> defaultApplyEntityLocationOffset, defaultHolderLocationOffset;
|
||||
|
||||
// True damping
|
||||
public final ForgeConfigSpec.BooleanValue enableTrueDamping;
|
||||
public final ForgeConfigSpec.DoubleValue dampingFactor;
|
||||
public final ForgeConfigSpec.DoubleValue maxForce;
|
||||
public final ForgeConfigSpec.DoubleValue playerSpringFactor;
|
||||
public final ForgeConfigSpec.DoubleValue mobSpringFactor;
|
||||
|
||||
// Leash state offsets
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> defaultApplyEntityLocationOffset;
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> defaultHolderLocationOffset;
|
||||
|
||||
// 正则表达式模式
|
||||
static final Pattern OFFSET_PATTERN = Pattern.compile(
|
||||
"(?i)(?:vec3|vec3d|vector3|offset)\\s*\\(\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*,\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*,\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*\\)\\s*:\\s*\\[\\s*([^]]+?)\\s*]\\s*" );
|
||||
"(?i)(?:vec3|vec3d|vector3|offset)\\s*\\(\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*,\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*,\\s*([-+]?[0-9]*\\.?[0-9]+)\\s*\\)\\s*:\\s*\\[\\s*([^]]+?)\\s*]\\s*"
|
||||
);
|
||||
|
||||
public Common(ForgeConfigSpec.Builder builder) {
|
||||
BUILDER.push("Command");
|
||||
EnableSLPModCommandPrefix = builder
|
||||
.comment("The prefix of this mod's commands")
|
||||
.define("SLPModCommandPrefix", true);
|
||||
// ===== Command =====
|
||||
builder.push("Command");
|
||||
enableSLPModCommandPrefix = builder
|
||||
.comment("Enable or disable the SLP mod command prefix")
|
||||
.define("enableSLPModCommandPrefix", true);
|
||||
|
||||
SLPModCommandPrefix = builder
|
||||
.comment("The prefix of this mod's commands", " [ Default:'slp'] ")
|
||||
.define("EnableSLPModCommandPrefix", "slp");
|
||||
BUILDER.pop();
|
||||
.define("SLPModCommandPrefix", "slp");
|
||||
builder.pop();
|
||||
|
||||
// ===== Entity =====
|
||||
builder.push("Entity");
|
||||
teleportWhitelist = builder
|
||||
.comment(
|
||||
|
|
@ -64,15 +72,18 @@ public class LeashCommonConfig {
|
|||
" - #modid:tag_name : allow teleporting to all entities under a given entity type tag"
|
||||
)
|
||||
.defineListAllowEmpty(
|
||||
List.of("allowedTeleportEntities"),
|
||||
List.of("teleportWhitelist"),
|
||||
List.of("#minecraft", "modernlife:bicycle", "modernlife:motorboat"),
|
||||
o -> o instanceof String s && isValidEntityRefFormat(s)
|
||||
);
|
||||
builder.pop();
|
||||
|
||||
// ===== Leash Settings =====
|
||||
builder.push("LeashSettings");
|
||||
maxLeashLength = builder
|
||||
.comment("Maximum leash distance (in blocks) for any entity")
|
||||
.defineInRange("maxLeashLength", 12.0, 6.0, 256.0);
|
||||
|
||||
elasticDistance = builder
|
||||
.comment("Default elastic distance for the Super Lead rope")
|
||||
.defineInRange("elasticDistance", 6.0, 6.0, 128.0);
|
||||
|
|
@ -92,8 +103,32 @@ public class LeashCommonConfig {
|
|||
maxLeashesPerEntity = builder
|
||||
.comment("Maximum number of leashes per entity")
|
||||
.defineInRange("maxLeashesPerEntity", 6, 1, 24);
|
||||
|
||||
builder.pop();
|
||||
|
||||
// ===== True Damping =====
|
||||
builder.push("TrueDamping");
|
||||
enableTrueDamping = builder
|
||||
.comment("Enable true velocity-based damping force (adds -c*v term)")
|
||||
.define("enableTrueDamping", true);
|
||||
|
||||
dampingFactor = builder
|
||||
.comment("Damping factor (resistance against entity velocity)")
|
||||
.defineInRange("dampingFactor", 0.1, 0.0, 2.0);
|
||||
|
||||
maxForce = builder
|
||||
.comment("Maximum leash pulling force (to prevent over-aggressive pulling)")
|
||||
.defineInRange("maxForce", 1.0, 0.1, 10.0);
|
||||
|
||||
playerSpringFactor = builder
|
||||
.comment("Spring stiffness multiplier for players")
|
||||
.defineInRange("playerSpringFactor", 0.3, 0.05, 1.0);
|
||||
|
||||
mobSpringFactor = builder
|
||||
.comment("Spring stiffness multiplier for mobs")
|
||||
.defineInRange("mobSpringFactor", 0.5, 0.05, 2.0);
|
||||
builder.pop();
|
||||
|
||||
// ===== Leash State Offsets =====
|
||||
builder.push("LeashStateSettings");
|
||||
defaultApplyEntityLocationOffset = builder
|
||||
.comment(
|
||||
|
|
@ -101,12 +136,6 @@ public class LeashCommonConfig {
|
|||
"Reference point: the entity's eyeHeight (eye / head position).",
|
||||
"Format: vec3(x,y,z) : [entity_list]",
|
||||
"Optional names: vector3, vec3d, offset",
|
||||
"Entity list may contain:",
|
||||
" - modid:entity_id : specific entity (e.g. minecraft:bee)",
|
||||
" - #modid:tag_name : entity type tag (e.g. #minecraft:boats)",
|
||||
" - #modid : all entities from a mod (e.g. #minecraft)",
|
||||
" - * : all entities",
|
||||
"Multiple entries can be separated by commas",
|
||||
"Example: vec3(0,0.2,0) : [minecraft:bee, minecraft:horse]",
|
||||
"Priority order: specific entity > tag > mod > *"
|
||||
)
|
||||
|
|
@ -125,12 +154,6 @@ public class LeashCommonConfig {
|
|||
"Reference point: the entity's eyeHeight (eye / head position).",
|
||||
"Format: vec3(x,y,z) : [entity_list]",
|
||||
"Optional names: vector3, vec3d, offset",
|
||||
"Entity list may contain:",
|
||||
" - modid:entity_id : specific entity (e.g. minecraft:player)",
|
||||
" - #modid:tag_name : entity type tag (e.g. #minecraft:players)",
|
||||
" - #modid : all entities from a mod (e.g. #minecraft)",
|
||||
" - * : all entities",
|
||||
"Multiple entries can be separated by commas",
|
||||
"Example: vec3(0,-0.5,0) : [minecraft:player]",
|
||||
"Priority order: specific entity > tag > mod > *"
|
||||
)
|
||||
|
|
@ -142,42 +165,28 @@ public class LeashCommonConfig {
|
|||
),
|
||||
o -> o instanceof String s && isValidOffsetRefFormat(s)
|
||||
);
|
||||
BUILDER.pop();
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
private static boolean isValidEntityRefFormat(String s) {
|
||||
if ("*".equals(s)) {
|
||||
return true; // 支持任意实体通配
|
||||
}
|
||||
if ("*".equals(s)) return true; // 支持任意实体通配
|
||||
if (s.startsWith("#")) {
|
||||
String body = s.substring(1);
|
||||
// 支持 #modid (整个模组)或 #modid:tag_name (标签)
|
||||
return body.matches("[a-z0-9_]+(:[a-z0-9_/]+)?");
|
||||
}
|
||||
// 普通实体 ID: modid:entity_id
|
||||
return s.matches("[a-z0-9_]+:[a-z0-9_/]+");
|
||||
}
|
||||
|
||||
private static boolean isValidOffsetRefFormat(String s) {
|
||||
// 匹配格式: vec3(x,y,z) : [entity_list]
|
||||
Matcher matcher = Common.OFFSET_PATTERN.matcher(s);
|
||||
if (!matcher.matches()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查坐标值是否有效
|
||||
Matcher matcher = OFFSET_PATTERN.matcher(s);
|
||||
if (!matcher.matches()) return false;
|
||||
try {
|
||||
Double.parseDouble(matcher.group(1));
|
||||
Double.parseDouble(matcher.group(2));
|
||||
Double.parseDouble(matcher.group(3));
|
||||
|
||||
// 检查实体列表格式
|
||||
String entityList = matcher.group(4);
|
||||
String[] entities = entityList.split(",");
|
||||
String[] entities = matcher.group(4).split(",");
|
||||
for (String entity : entities) {
|
||||
if (!isValidEntityRefFormat(entity.trim())) {
|
||||
return false;
|
||||
}
|
||||
if (!isValidEntityRefFormat(entity.trim())) return false;
|
||||
}
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
|
|
|
|||
|
|
@ -30,424 +30,203 @@ import java.util.regex.Matcher;
|
|||
import static top.r3944realms.superleadrope.config.LeashCommonConfig.Common.OFFSET_PATTERN;
|
||||
|
||||
public class LeashConfigManager {
|
||||
private final Map<String, double[]> entityHolderOffsetMap = new ConcurrentHashMap<>(), entityLeashOffsetMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> tagHolderOffsetMap = new ConcurrentHashMap<>(), tagLeashOffsetMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> modHolderOffsetMap = new ConcurrentHashMap<>(), modLeashOffsetMap = new ConcurrentHashMap<>();
|
||||
|
||||
// 缓存常用配置值以提高性能
|
||||
private volatile List<String> teleportWhitelistCache;
|
||||
private volatile String commandPrefixCache;
|
||||
private volatile boolean enableCommandPrefixCache;
|
||||
private volatile double maxLeashLengthCache;
|
||||
private volatile double elasticDistanceCache;
|
||||
private volatile double extremeSnapFactorCache;
|
||||
private volatile double springDampeningCache;
|
||||
private volatile List<Double> axisSpecificElasticityCache;
|
||||
private volatile int maxLeashesPerEntityCache;
|
||||
// ========== 偏移映射 ==========
|
||||
private final Map<String, double[]> entityHolderMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> tagHolderMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> modHolderMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<String, double[]> entityLeashMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> tagLeashMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, double[]> modLeashMap = new ConcurrentHashMap<>();
|
||||
|
||||
// ========== 缓存配置 ==========
|
||||
private volatile List<String> teleportWhitelistCache = Collections.emptyList();
|
||||
private volatile String commandPrefixCache = "slp";
|
||||
private volatile boolean commandPrefixEnabledCache = true;
|
||||
|
||||
private volatile boolean enableTrueDamping = true;
|
||||
private volatile double maxForce = 1.0;
|
||||
private volatile double playerSpringFactor = 0.3;
|
||||
private volatile double mobSpringFactor = 0.5;
|
||||
|
||||
private volatile double maxLeashLength = 12.0;
|
||||
private volatile double elasticDistance = 6.0;
|
||||
private volatile double extremeSnapFactor = 2.0;
|
||||
private volatile double springDampening = 0.7;
|
||||
private volatile List<Double> axisElasticity = List.of(0.8, 0.2, 0.8);
|
||||
private volatile int maxLeashesPerEntity = 6;
|
||||
|
||||
public LeashConfigManager() {
|
||||
this.reloadAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析偏移配置(线程安全)
|
||||
*/
|
||||
public void parseOffsetConfig() {
|
||||
// --- Holder ---
|
||||
Map<String, double[]> holderEntityMap = new HashMap<>();
|
||||
Map<String, double[]> holderTagMap = new HashMap<>();
|
||||
Map<String, double[]> holderModMap = new HashMap<>();
|
||||
|
||||
List<? extends String> holderOffsets = LeashCommonConfig.COMMON.defaultHolderLocationOffset.get();
|
||||
for (String offsetConfig : holderOffsets) {
|
||||
Matcher matcher = OFFSET_PATTERN.matcher(offsetConfig);
|
||||
if (!matcher.matches()) continue;
|
||||
|
||||
try {
|
||||
double x = Double.parseDouble(matcher.group(1).trim());
|
||||
double y = Double.parseDouble(matcher.group(2).trim());
|
||||
double z = Double.parseDouble(matcher.group(3).trim());
|
||||
double[] offset = new double[]{x, y, z};
|
||||
|
||||
String entityList = matcher.group(4);
|
||||
for (String entity : entityList.split(",")) {
|
||||
String trimmed = entity.trim();
|
||||
if (trimmed.equals("*")) {
|
||||
// special case: apply to all entities
|
||||
holderModMap.put("*", offset);
|
||||
} else if (trimmed.startsWith("#")) {
|
||||
String body = trimmed.substring(1).trim();
|
||||
if (body.contains(":")) {
|
||||
holderTagMap.put(body, offset);
|
||||
} else {
|
||||
holderModMap.put(body, offset);
|
||||
}
|
||||
} else {
|
||||
holderEntityMap.put(trimmed, offset);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
SuperLeadRope.logger.error("Invalid holder offset config: {}", offsetConfig);
|
||||
}
|
||||
}
|
||||
|
||||
entityHolderOffsetMap.clear();
|
||||
entityHolderOffsetMap.putAll(holderEntityMap);
|
||||
tagHolderOffsetMap.clear();
|
||||
tagHolderOffsetMap.putAll(holderTagMap);
|
||||
modHolderOffsetMap.clear();
|
||||
modHolderOffsetMap.putAll(holderModMap);
|
||||
|
||||
// --- Leash ---
|
||||
Map<String, double[]> leashEntityMap = new HashMap<>();
|
||||
Map<String, double[]> leashTagMap = new HashMap<>();
|
||||
Map<String, double[]> leashModMap = new HashMap<>();
|
||||
|
||||
List<? extends String> leashOffsets = LeashCommonConfig.COMMON.defaultApplyEntityLocationOffset.get();
|
||||
for (String offsetConfig : leashOffsets) {
|
||||
Matcher matcher = OFFSET_PATTERN.matcher(offsetConfig);
|
||||
if (!matcher.matches()) continue;
|
||||
|
||||
try {
|
||||
double x = Double.parseDouble(matcher.group(1).trim());
|
||||
double y = Double.parseDouble(matcher.group(2).trim());
|
||||
double z = Double.parseDouble(matcher.group(3).trim());
|
||||
double[] offset = new double[]{x, y, z};
|
||||
|
||||
String entityList = matcher.group(4);
|
||||
for (String entity : entityList.split(",")) {
|
||||
String trimmed = entity.trim();
|
||||
if (trimmed.equals("*")) {
|
||||
leashModMap.put("*", offset);
|
||||
} else if (trimmed.startsWith("#")) {
|
||||
String body = trimmed.substring(1).trim();
|
||||
if (body.contains(":")) {
|
||||
leashTagMap.put(body, offset);
|
||||
} else {
|
||||
leashModMap.put(body, offset);
|
||||
}
|
||||
} else {
|
||||
leashEntityMap.put(trimmed, offset);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
SuperLeadRope.logger.error("Invalid leash offset config: {}", offsetConfig);
|
||||
}
|
||||
}
|
||||
|
||||
entityLeashOffsetMap.clear();
|
||||
entityLeashOffsetMap.putAll(leashEntityMap);
|
||||
tagLeashOffsetMap.clear();
|
||||
tagLeashOffsetMap.putAll(leashTagMap);
|
||||
modLeashOffsetMap.clear();
|
||||
modLeashOffsetMap.putAll(leashModMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新加载所有配置值到缓存
|
||||
*/
|
||||
public void reloadAll() {
|
||||
// 加载偏移配置
|
||||
parseOffsetConfig();
|
||||
|
||||
// 加载其他配置到缓存
|
||||
teleportWhitelistCache = new ArrayList<>(LeashCommonConfig.COMMON.teleportWhitelist.get());
|
||||
commandPrefixCache = LeashCommonConfig.COMMON.SLPModCommandPrefix.get();
|
||||
enableCommandPrefixCache = LeashCommonConfig.COMMON.EnableSLPModCommandPrefix.get();
|
||||
maxLeashLengthCache = LeashCommonConfig.COMMON.maxLeashLength.get();
|
||||
elasticDistanceCache = LeashCommonConfig.COMMON.elasticDistance.get();
|
||||
extremeSnapFactorCache = LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
||||
springDampeningCache = LeashCommonConfig.COMMON.springDampening.get();
|
||||
axisSpecificElasticityCache = new ArrayList<>(LeashCommonConfig.COMMON.axisSpecificElasticity.get());
|
||||
maxLeashesPerEntityCache = LeashCommonConfig.COMMON.maxLeashesPerEntity.get();
|
||||
|
||||
SuperLeadRope.logger.debug("All configs reloaded: {}", getStats());
|
||||
}
|
||||
|
||||
// ========== 偏移配置相关方法 ==========
|
||||
|
||||
/**
|
||||
* 获取实体类型的偏移量
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Vec3 getDefaultEntityOffset(EntityType<?> entityType) {
|
||||
String entityId = entityType.builtInRegistryHolder().key().location().toString();
|
||||
String modId = entityId.split(":")[0]; // 从实体ID提取modId
|
||||
|
||||
// 获取实体的标签
|
||||
List<String> tagStrings = new ArrayList<>();
|
||||
for (var tag : entityType.builtInRegistryHolder().tags().toList()) {
|
||||
tagStrings.add(tag.location().toString());
|
||||
}
|
||||
|
||||
double[] offset = getDefaultEntityOffset(entityId, modId, tagStrings);
|
||||
return offset != null ? new Vec3(offset[0], offset[1], offset[2]) : Vec3.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体对象的偏移量(便捷方法)
|
||||
*/
|
||||
public Vec3 getDefaultEntityOffset(Entity entity) {
|
||||
return getDefaultEntityOffset(entity.getType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取实体偏移量(原始数据)
|
||||
*/
|
||||
public double[] getDefaultEntityOffset(String entityId, String modId, List<String> tags) {
|
||||
// 1. 首先检查特定实体
|
||||
if (entityLeashOffsetMap.containsKey(entityId)) {
|
||||
return entityLeashOffsetMap.get(entityId);
|
||||
}
|
||||
|
||||
// 2. 检查标签
|
||||
for (String tag : tags) {
|
||||
if (tagLeashOffsetMap.containsKey(tag)) {
|
||||
return tagHolderOffsetMap.get(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 检查模组
|
||||
if (modLeashOffsetMap.containsKey(modId)) {
|
||||
return modLeashOffsetMap.get(modId);
|
||||
}
|
||||
|
||||
//4. 通配符
|
||||
if (modLeashOffsetMap.containsKey("*")) {
|
||||
return modLeashOffsetMap.get("*");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 获取实体类型的偏移量
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Vec3 getDefaultHolderOffset(EntityType<?> entityType) {
|
||||
String entityId = entityType.builtInRegistryHolder().key().location().toString();
|
||||
String modId = entityId.split(":")[0]; // 从实体ID提取modId
|
||||
|
||||
// 获取实体的标签
|
||||
List<String> tagStrings = new ArrayList<>();
|
||||
for (var tag : entityType.builtInRegistryHolder().tags().toList()) {
|
||||
tagStrings.add(tag.location().toString());
|
||||
}
|
||||
|
||||
double[] offset = getDefaultHolderOffset(entityId, modId, tagStrings);
|
||||
return offset != null ? new Vec3(offset[0], offset[1], offset[2]) : Vec3.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体对象的偏移量(便捷方法)
|
||||
*/
|
||||
public Vec3 getDefaultHolderOffset(Entity entity) {
|
||||
return getDefaultHolderOffset(entity.getType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取实体偏移量(原始数据)
|
||||
*/
|
||||
public double[] getDefaultHolderOffset(String entityId, String modId, List<String> tags) {
|
||||
// 1. 首先检查特定实体
|
||||
if (entityHolderOffsetMap.containsKey(entityId)) {
|
||||
return entityHolderOffsetMap.get(entityId);
|
||||
}
|
||||
|
||||
// 2. 检查标签
|
||||
for (String tag : tags) {
|
||||
if (tagHolderOffsetMap.containsKey(tag)) {
|
||||
return tagHolderOffsetMap.get(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 检查模组
|
||||
if (modHolderOffsetMap.containsKey(modId)) {
|
||||
return modHolderOffsetMap.get(modId);
|
||||
}
|
||||
|
||||
//4. 通配符
|
||||
if (modLeashOffsetMap.containsKey("*")) {
|
||||
return modHolderOffsetMap.get("*");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ========== 传送白名单相关方法 ==========
|
||||
|
||||
public List<String> getTeleportWhitelist() {
|
||||
return Collections.unmodifiableList(teleportWhitelistCache);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean isEntityTeleportAllowed(EntityType<?> entityType) {
|
||||
String entityId = entityType.builtInRegistryHolder().key().location().toString();
|
||||
String modid = entityId.split(":")[0];
|
||||
|
||||
for (String entry : teleportWhitelistCache) {
|
||||
if (entry.startsWith("#")) {
|
||||
String body = entry.substring(1);
|
||||
|
||||
// Case 1: #modid → allow all entities from this mod
|
||||
if (!body.contains(":")) {
|
||||
if (modid.equals(body)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Case 2: #modid:tag_name → allow all entities under this tag
|
||||
else {
|
||||
ResourceLocation tagId = new ResourceLocation(body);
|
||||
TagKey<EntityType<?>> tag = TagKey.create(Registries.ENTITY_TYPE, tagId);
|
||||
if (entityType.builtInRegistryHolder().is(tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Case 3: modid:entity_name → allow a specific entity
|
||||
if (entry.equals(entityId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEntityTeleportAllowed(String entityId) {
|
||||
// 对于字符串ID,我们无法检查标签,只能检查模组和特定实体
|
||||
String modid = entityId.contains(":") ? entityId.split(":")[0] : "minecraft";
|
||||
|
||||
for (String entry : teleportWhitelistCache) {
|
||||
if (entry.startsWith("#")) {
|
||||
String body = entry.substring(1);
|
||||
|
||||
// Case 1: #modid → allow all entities from this mod
|
||||
if (!body.contains(":")) {
|
||||
if (modid.equals(body)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Case 2: #modid:tag_name → 字符串ID无法检查标签,跳过
|
||||
// 如果需要支持标签检查,需要传入EntityType而不是String
|
||||
} else {
|
||||
// Case 3: modid:entity_name → allow a specific entity
|
||||
if (entry.equals(entityId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 辅助方法:检查实体ID是否匹配模式(用于旧的匹配逻辑)
|
||||
private boolean matchesTeleportPattern(String pattern, String entityId) {
|
||||
if (pattern.startsWith("#")) {
|
||||
String body = pattern.substring(1);
|
||||
if (body.contains(":")) {
|
||||
// 标签格式: #modid:tag_name - 字符串ID无法准确匹配标签
|
||||
// 返回模组匹配作为近似
|
||||
String patternModId = body.split(":")[0];
|
||||
String entityModId = entityId.split(":")[0];
|
||||
return entityModId.equals(patternModId);
|
||||
} else {
|
||||
// 模组格式: #modid
|
||||
String entityModId = entityId.split(":")[0];
|
||||
return entityModId.equals(body);
|
||||
}
|
||||
} else {
|
||||
// 实体格式: modid:entity_id
|
||||
return entityId.equals(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加一个重载方法,方便使用Entity对象
|
||||
public boolean isEntityTeleportAllowed(Entity entity) {
|
||||
return isEntityTeleportAllowed(entity.getType());
|
||||
}
|
||||
|
||||
// ========== 命令配置相关方法 ==========
|
||||
|
||||
public String getCommandPrefix() {
|
||||
return commandPrefixCache;
|
||||
}
|
||||
|
||||
public boolean isCommandPrefixEnabled() {
|
||||
return enableCommandPrefixCache;
|
||||
}
|
||||
|
||||
public String getFullCommand(String subCommand) {
|
||||
return isCommandPrefixEnabled() ?
|
||||
getCommandPrefix() + " " + subCommand :
|
||||
subCommand;
|
||||
}
|
||||
|
||||
// ========== 拴绳物理配置相关方法 ==========
|
||||
|
||||
public double getMaxLeashLength() {
|
||||
return maxLeashLengthCache;
|
||||
}
|
||||
|
||||
public double getElasticDistance() {
|
||||
return elasticDistanceCache;
|
||||
}
|
||||
|
||||
public double getExtremeSnapFactor() {
|
||||
return extremeSnapFactorCache;
|
||||
}
|
||||
|
||||
public double getBreakDistance() {
|
||||
return getMaxLeashLength() * getExtremeSnapFactor();
|
||||
}
|
||||
|
||||
public double getSpringDampening() {
|
||||
return springDampeningCache;
|
||||
}
|
||||
|
||||
public List<Double> getAxisSpecificElasticity() {
|
||||
return Collections.unmodifiableList(axisSpecificElasticityCache);
|
||||
}
|
||||
|
||||
public double getXElasticity() {
|
||||
return !axisSpecificElasticityCache.isEmpty() ? axisSpecificElasticityCache.get(0) : 0.8;
|
||||
}
|
||||
|
||||
public double getYElasticity() {
|
||||
return axisSpecificElasticityCache.size() > 1 ? axisSpecificElasticityCache.get(1) : 0.2;
|
||||
}
|
||||
|
||||
public double getZElasticity() {
|
||||
return axisSpecificElasticityCache.size() > 2 ? axisSpecificElasticityCache.get(2) : 0.8;
|
||||
}
|
||||
|
||||
// ========== 实体限制配置相关方法 ==========
|
||||
|
||||
public int getMaxLeashesPerEntity() {
|
||||
return maxLeashesPerEntityCache;
|
||||
}
|
||||
|
||||
public boolean canEntityAcceptMoreLeashes(Entity entity, int currentLeashCount) {
|
||||
return currentLeashCount < getMaxLeashesPerEntity();
|
||||
}
|
||||
|
||||
// ========== 管理方法 ==========
|
||||
|
||||
public void reload() {
|
||||
reloadAll();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
entityHolderOffsetMap.clear();entityLeashOffsetMap.clear();
|
||||
tagHolderOffsetMap.clear();tagLeashOffsetMap.clear();
|
||||
modHolderOffsetMap.clear();modLeashOffsetMap.clear();
|
||||
teleportWhitelistCache = Collections.emptyList();
|
||||
// ================== 偏移解析 ==================
|
||||
private Map<String, Map<String, double[]>> parseOffsetList(List<? extends String> offsetConfigs) {
|
||||
Map<String, double[]> entityMap = new HashMap<>();
|
||||
Map<String, double[]> tagMap = new HashMap<>();
|
||||
Map<String, double[]> modMap = new HashMap<>();
|
||||
|
||||
for (String config : offsetConfigs) {
|
||||
Matcher matcher = OFFSET_PATTERN.matcher(config);
|
||||
if (!matcher.matches()) continue;
|
||||
|
||||
try {
|
||||
double x = Double.parseDouble(matcher.group(1).trim());
|
||||
double y = Double.parseDouble(matcher.group(2).trim());
|
||||
double z = Double.parseDouble(matcher.group(3).trim());
|
||||
double[] offset = new double[]{x, y, z};
|
||||
|
||||
String[] entities = matcher.group(4).split(",");
|
||||
for (String e : entities) {
|
||||
String trimmed = e.trim();
|
||||
if (trimmed.equals("*")) modMap.put("*", offset);
|
||||
else if (trimmed.startsWith("#")) {
|
||||
String body = trimmed.substring(1).trim();
|
||||
if (body.contains(":")) tagMap.put(body, offset);
|
||||
else modMap.put(body, offset);
|
||||
} else entityMap.put(trimmed, offset);
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
SuperLeadRope.logger.error("Invalid offset config: {}", config);
|
||||
}
|
||||
}
|
||||
|
||||
return Map.of(
|
||||
"entity", entityMap,
|
||||
"tag", tagMap,
|
||||
"mod", modMap
|
||||
);
|
||||
}
|
||||
|
||||
public String getStats() {
|
||||
return String.format("Holder: Entities: %d, Tags: %d, Mods: %d \n Leash: Entities: %d, Tags: %d, Mods: %d, TeleportWhitelist: %d",
|
||||
entityHolderOffsetMap.size(), tagHolderOffsetMap.size(), modHolderOffsetMap.size(),
|
||||
entityLeashOffsetMap.size(), tagLeashOffsetMap.size(), modLeashOffsetMap.size(),
|
||||
teleportWhitelistCache.size());
|
||||
public void parseOffsetConfig() {
|
||||
Map<String, Map<String, double[]>> holder = parseOffsetList(LeashCommonConfig.COMMON.defaultHolderLocationOffset.get());
|
||||
entityHolderMap.clear(); entityHolderMap.putAll(holder.get("entity"));
|
||||
tagHolderMap.clear(); tagHolderMap.putAll(holder.get("tag"));
|
||||
modHolderMap.clear(); modHolderMap.putAll(holder.get("mod"));
|
||||
|
||||
Map<String, Map<String, double[]>> leash = parseOffsetList(LeashCommonConfig.COMMON.defaultApplyEntityLocationOffset.get());
|
||||
entityLeashMap.clear(); entityLeashMap.putAll(leash.get("entity"));
|
||||
tagLeashMap.clear(); tagLeashMap.putAll(leash.get("tag"));
|
||||
modLeashMap.clear(); modLeashMap.putAll(leash.get("mod"));
|
||||
}
|
||||
|
||||
// ================== 获取偏移 ==================
|
||||
private double[] getOffset(String entityId, String modId, List<String> tags,
|
||||
Map<String,double[]> entityMap,
|
||||
Map<String,double[]> tagMap,
|
||||
Map<String,double[]> modMap) {
|
||||
|
||||
if (entityMap.containsKey(entityId)) return entityMap.get(entityId);
|
||||
for (String tag : tags) if (tagMap.containsKey(tag)) return tagMap.get(tag);
|
||||
if (modMap.containsKey(modId)) return modMap.get(modId);
|
||||
return modMap.getOrDefault("*", null);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"DuplicatedCode", "deprecation"})
|
||||
public Vec3 getDefaultEntityOffset(EntityType<?> type) {
|
||||
String entityId = type.builtInRegistryHolder().key().location().toString();
|
||||
String modId = entityId.split(":")[0];
|
||||
List<String> tags = new ArrayList<>();
|
||||
for (var t : type.builtInRegistryHolder().tags().toList()) tags.add(t.location().toString());
|
||||
|
||||
double[] offset = getOffset(entityId, modId, tags, entityLeashMap, tagLeashMap, modLeashMap);
|
||||
return offset != null ? new Vec3(offset[0], offset[1], offset[2]) : Vec3.ZERO;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"DuplicatedCode", "deprecation"})
|
||||
public Vec3 getDefaultHolderOffset(EntityType<?> type) {
|
||||
String entityId = type.builtInRegistryHolder().key().location().toString();
|
||||
String modId = entityId.split(":")[0];
|
||||
List<String> tags = new ArrayList<>();
|
||||
for (var t : type.builtInRegistryHolder().tags().toList()) tags.add(t.location().toString());
|
||||
|
||||
double[] offset = getOffset(entityId, modId, tags, entityHolderMap, tagHolderMap, modHolderMap);
|
||||
return offset != null ? new Vec3(offset[0], offset[1], offset[2]) : Vec3.ZERO;
|
||||
}
|
||||
|
||||
public Vec3 getDefaultEntityOffset(Entity entity) { return getDefaultEntityOffset(entity.getType()); }
|
||||
public Vec3 getDefaultHolderOffset(Entity entity) { return getDefaultHolderOffset(entity.getType()); }
|
||||
|
||||
// ================== 白名单 ==================
|
||||
public List<String> getTeleportWhitelist() { return Collections.unmodifiableList(teleportWhitelistCache); }
|
||||
@SuppressWarnings({"DuplicatedCode", "deprecation"})
|
||||
public boolean isEntityTeleportAllowed(EntityType<?> type) {
|
||||
String entityId = type.builtInRegistryHolder().key().location().toString();
|
||||
String modId = entityId.split(":")[0];
|
||||
|
||||
for (String entry : teleportWhitelistCache) {
|
||||
if (entry.startsWith("#")) {
|
||||
String body = entry.substring(1);
|
||||
if (!body.contains(":") && body.equals(modId)) return true;
|
||||
|
||||
if (body.contains(":")) {
|
||||
ResourceLocation tagId = new ResourceLocation(body);
|
||||
TagKey<EntityType<?>> tag = TagKey.create(Registries.ENTITY_TYPE, tagId);
|
||||
if (type.builtInRegistryHolder().is(tag)) return true;
|
||||
}
|
||||
} else if (entry.equals(entityId)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEntityTeleportAllowed(Entity entity) { return isEntityTeleportAllowed(entity.getType()); }
|
||||
|
||||
// ================== 命令 ==================
|
||||
public String getCommandPrefix() { return commandPrefixCache; }
|
||||
public boolean isCommandPrefixEnabled() { return commandPrefixEnabledCache; }
|
||||
public String getFullCommand(String subCommand) {
|
||||
return isCommandPrefixEnabled() ? getCommandPrefix() + " " + subCommand : subCommand;
|
||||
}
|
||||
|
||||
// ================== 拴绳物理参数 ==================
|
||||
public boolean isEnableTrueDamping() { return enableTrueDamping; }
|
||||
public double getMaxForce() { return maxForce; }
|
||||
public double getPlayerSpringFactor() { return playerSpringFactor; }
|
||||
public double getMobSpringFactor() { return mobSpringFactor; }
|
||||
|
||||
public double getMaxLeashLength() { return maxLeashLength; }
|
||||
public double getElasticDistance() { return elasticDistance; }
|
||||
public double getExtremeSnapFactor() { return extremeSnapFactor; }
|
||||
public double getBreakDistance() { return maxLeashLength * extremeSnapFactor; }
|
||||
public double getSpringDampening() { return springDampening; }
|
||||
public List<Double> getAxisElasticity() { return Collections.unmodifiableList(axisElasticity); }
|
||||
public double getXElasticity() { return !axisElasticity.isEmpty() ? axisElasticity.get(0) : 0.8; }
|
||||
public double getYElasticity() { return axisElasticity.size() > 1 ? axisElasticity.get(1) : 0.2; }
|
||||
public double getZElasticity() { return axisElasticity.size() > 2 ? axisElasticity.get(2) : 0.8; }
|
||||
|
||||
public int getMaxLeashesPerEntity() { return maxLeashesPerEntity; }
|
||||
public boolean canEntityAcceptMoreLeashes(Entity entity, int currentCount) {
|
||||
return currentCount < maxLeashesPerEntity;
|
||||
}
|
||||
|
||||
// ================== 管理 ==================
|
||||
public void reloadAll() {
|
||||
parseOffsetConfig();
|
||||
|
||||
teleportWhitelistCache = new ArrayList<>(LeashCommonConfig.COMMON.teleportWhitelist.get());
|
||||
commandPrefixCache = LeashCommonConfig.COMMON.SLPModCommandPrefix.get();
|
||||
commandPrefixEnabledCache = LeashCommonConfig.COMMON.enableSLPModCommandPrefix.get();
|
||||
|
||||
maxLeashLength = LeashCommonConfig.COMMON.maxLeashLength.get();
|
||||
elasticDistance = LeashCommonConfig.COMMON.elasticDistance.get();
|
||||
extremeSnapFactor = LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
||||
springDampening = LeashCommonConfig.COMMON.springDampening.get();
|
||||
axisElasticity = new ArrayList<>(LeashCommonConfig.COMMON.axisSpecificElasticity.get());
|
||||
maxLeashesPerEntity = LeashCommonConfig.COMMON.maxLeashesPerEntity.get();
|
||||
|
||||
enableTrueDamping = LeashCommonConfig.COMMON.enableTrueDamping.get();
|
||||
maxForce = LeashCommonConfig.COMMON.maxForce.get();
|
||||
playerSpringFactor = LeashCommonConfig.COMMON.playerSpringFactor.get();
|
||||
mobSpringFactor = LeashCommonConfig.COMMON.mobSpringFactor.get();
|
||||
|
||||
SuperLeadRope.logger.debug("Configs reloaded: {}", getStats());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
entityHolderMap.clear(); tagHolderMap.clear(); modHolderMap.clear();
|
||||
entityLeashMap.clear(); tagLeashMap.clear(); modLeashMap.clear();
|
||||
teleportWhitelistCache = Collections.emptyList();
|
||||
}
|
||||
|
||||
public static void loading(LeashConfigManager manager) {
|
||||
|
|
@ -459,7 +238,15 @@ public class LeashConfigManager {
|
|||
}
|
||||
|
||||
public static void unloading(LeashConfigManager manager) {
|
||||
if(manager != null)
|
||||
manager.clear();
|
||||
if(manager != null) manager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public String getStats() {
|
||||
return String.format(
|
||||
"Holder: Entities: %d, Tags: %d, Mods: %d\nLeash: Entities: %d, Tags: %d, Mods: %d, TeleportWhitelist: %d",
|
||||
entityHolderMap.size(), tagHolderMap.size(), modHolderMap.size(),
|
||||
entityLeashMap.size(), tagLeashMap.size(), modLeashMap.size(),
|
||||
teleportWhitelistCache.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,8 +27,8 @@ import net.minecraft.world.entity.LivingEntity;
|
|||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.animal.horse.Llama;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||
import net.minecraft.world.entity.vehicle.Boat;
|
||||
import net.minecraft.world.entity.vehicle.Minecart;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
|
@ -466,7 +466,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
Vec3 combinedDirection = Vec3.ZERO;
|
||||
int validLeashes = 0;
|
||||
|
||||
// 计算所有拴绳的合力和平均方向
|
||||
// 1. 计算所有拴绳的合力和平均方向
|
||||
for (Map.Entry<UUID, LeashInfo> entry : leashHolders.entrySet()) {
|
||||
Vec3 force = calculateLeashForceForUUID(entry);
|
||||
if (force != null) {
|
||||
|
|
@ -486,31 +486,40 @@ public class LeashDataImpl implements ILeashData {
|
|||
}
|
||||
|
||||
boolean hasForce = !combinedForce.equals(Vec3.ZERO);
|
||||
Entity finalApplyEntity = RindingLeash.getFinalEntityForLeashIfForce(entity, hasForce);
|
||||
Entity targetEntity = RindingLeash.getFinalEntityForLeashIfForce(entity, hasForce);
|
||||
|
||||
if (hasForce) {
|
||||
// 处理玩家和其他实体
|
||||
if (finalApplyEntity instanceof ServerPlayer player && CurtainCompat.isNotFakePlayer(player)) {
|
||||
RindingLeash.applyForceToPlayer(player, combinedForce);
|
||||
if (targetEntity != null && hasForce) {
|
||||
// 玩家与普通实体统一力应用
|
||||
if (targetEntity instanceof ServerPlayer player && CurtainCompat.isNotFakePlayer(player)) {
|
||||
RindingLeash.applyForceToPlayer(
|
||||
player,
|
||||
combinedForce,
|
||||
CommonEventHandler.leashConfigManager.getPlayerSpringFactor(),
|
||||
0.0, // 阻力取消
|
||||
CommonEventHandler.leashConfigManager.getMaxForce()
|
||||
);
|
||||
} else {
|
||||
finalApplyEntity.setDeltaMovement(finalApplyEntity.getDeltaMovement().add(combinedForce));
|
||||
finalApplyEntity.hurtMarked = true;
|
||||
|
||||
// 对生物使用合力方向进行移动(只有在能够移动时才执行)
|
||||
if (finalApplyEntity instanceof Mob mob && validLeashes > 0 && canMobMove(mob)) {
|
||||
moveMobTowardsCombinedDirection(mob, combinedDirection, validLeashes, combinedForce.length());
|
||||
} else if (finalApplyEntity instanceof Mob mob) {
|
||||
// 无法移动时停止导航
|
||||
mob.getNavigation().stop();
|
||||
}
|
||||
applyForceToNonPlayerEntity(targetEntity, combinedForce, validLeashes, combinedDirection);
|
||||
}
|
||||
}
|
||||
|
||||
RindingLeash.protectAnimalMovement(finalApplyEntity, true);
|
||||
} else {
|
||||
RindingLeash.protectAnimalMovement(finalApplyEntity, false);
|
||||
// 保护动物移动
|
||||
RindingLeash.protectAnimalMovement(targetEntity, hasForce);
|
||||
}
|
||||
/**
|
||||
* 给非玩家实体施加拴绳力(取消阻力)
|
||||
*/
|
||||
private void applyForceToNonPlayerEntity(Entity entity, Vec3 combinedForce,
|
||||
int validLeashes, Vec3 combinedDirection) {
|
||||
// 直接施加合力,不再加阻力
|
||||
entity.setDeltaMovement(entity.getDeltaMovement().add(combinedForce));
|
||||
entity.hurtMarked = true;
|
||||
|
||||
// 没有力时也停止导航
|
||||
if (finalApplyEntity instanceof Mob mob) {
|
||||
// 如果是生物,处理导航
|
||||
if (entity instanceof Mob mob) {
|
||||
if (validLeashes > 0 && canMobMove(mob)) {
|
||||
moveMobTowardsCombinedDirection(mob, combinedDirection, validLeashes, combinedForce.length());
|
||||
} else {
|
||||
mob.getNavigation().stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -534,10 +543,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
* 让生物朝着合力方向移动
|
||||
*/
|
||||
private void moveMobTowardsCombinedDirection(Mob mob, Vec3 combinedDirection, int leashCount, double forceMagnitude) {
|
||||
if (combinedDirection.equals(Vec3.ZERO)) return;
|
||||
|
||||
// 再次检查是否能够移动
|
||||
if (!canMobMove(mob)) {
|
||||
if (combinedDirection.equals(Vec3.ZERO) || !canMobMove(mob)) {
|
||||
mob.getNavigation().stop();
|
||||
return;
|
||||
}
|
||||
|
|
@ -569,11 +575,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
*/
|
||||
private boolean isPositionReachable(Mob mob, Vec3 targetPos) {
|
||||
// 简单的距离检查
|
||||
double distance = mob.position().distanceTo(targetPos);
|
||||
if (distance > 20.0) { // 距离太远
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
@ -626,7 +628,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
LeashInfo info = entry.getValue();
|
||||
Vec3 entityPos = entity.position();
|
||||
double distance = holderPos.distanceTo(entityPos);
|
||||
double extremeSnapDist = info.maxDistance() * CommonEventHandler.leashConfigManager.getExtremeSnapFactor();
|
||||
double extremeSnapDist = CommonEventHandler.leashConfigManager.getBreakDistance();
|
||||
|
||||
// 1. 检查是否超出断裂距离
|
||||
if (distance > extremeSnapDist) {
|
||||
|
|
@ -841,7 +843,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
//只能系在这些实体上,在这里,其它情况一律忽略
|
||||
//TODO: 标签支持控制
|
||||
public static boolean isLeashable(Entity entity) {
|
||||
return entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart;
|
||||
return entity instanceof LivingEntity || entity instanceof Boat || entity instanceof AbstractMinecart;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package top.r3944realms.superleadrope.util.riding;
|
|||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
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.animal.Animal;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
|
@ -90,13 +91,31 @@ public class RindingLeash {
|
|||
/**
|
||||
* 给玩家应用拴绳力前的发包处理
|
||||
*/
|
||||
public static void applyForceToPlayer(ServerPlayer player, Vec3 force) {
|
||||
public static void applyForceToPlayer(ServerPlayer player, Vec3 leashVec, double k, double dampingFactor, double maxForce) {
|
||||
Vec3 velocity = player.getDeltaMovement();
|
||||
|
||||
// 弹簧力
|
||||
Vec3 springForce = leashVec.scale(k);
|
||||
|
||||
// 阻尼力
|
||||
Vec3 dampingForce = velocity.scale(-dampingFactor);
|
||||
|
||||
// 合力
|
||||
Vec3 finalForce = springForce.add(dampingForce);
|
||||
|
||||
// 限幅
|
||||
if (finalForce.length() > maxForce) {
|
||||
finalForce = finalForce.normalize().scale(maxForce);
|
||||
}
|
||||
|
||||
// 发包应用给玩家
|
||||
NetworkHandler.sendToPlayer(
|
||||
new UpdatePlayerMovementPacket(
|
||||
UpdatePlayerMovementPacket.Operation.ADD,
|
||||
force
|
||||
finalForce
|
||||
), player
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user