版本更新到1.0.0
1. 对WayStone做进一步适配(显然WS自己有问题) 2. 添加了禁拴效果及其对应的药水 3. 添加了彩蛋内容(暂无非作弊获取方式) 4. 添加了最大拴绳拉力阈值,在配置中调整
This commit is contained in:
parent
186103e0c5
commit
ad275c4d37
|
|
@ -167,6 +167,7 @@ dependencies {
|
|||
modImplementation("curse.maven:bendy-lib-623373:4550371")
|
||||
modImplementation("curse.maven:waystones-245755:6856603")
|
||||
modImplementation("curse.maven:balm-531761:7087245")
|
||||
// modImplementation("curse.maven:kaleidoscope-doll-1233277:7201584")
|
||||
// modRuntimeOnly("curse.maven:luckperms-431733:4738950")
|
||||
modImplementation("software.bernie.geckolib:geckolib-forge-${minecraft_version}:${geckolib_version}")
|
||||
implementation("com.eliotlash.mclib:mclib:20")
|
||||
|
|
|
|||
|
|
@ -59,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.
|
||||
mod_license=GPLv3
|
||||
# The mod version. See https://semver.org/
|
||||
mod_version=0.0.0.9
|
||||
mod_version=1.0.0
|
||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
|
|
|
|||
1
res/doll.bbmodel
Normal file
1
res/doll.bbmodel
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-12-04T18:55:51.5054614 Languages: zh_tw
|
||||
ff7556f7a8bd62a8c4cc776e45947835ffc19689 assets/superleadrope/lang/zh_tw.json
|
||||
// 1.20.1 2025-12-11T17:31:55.2360112 Languages: zh_tw
|
||||
d1253ab3534285cc6a4d6c0e5495720f48edd62f assets/superleadrope/lang/zh_tw.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-12-04T18:55:51.5004568 Languages: zh_cn
|
||||
f5128cf6058db0e79f91aece8de7f5bdd8e04193 assets/superleadrope/lang/zh_cn.json
|
||||
// 1.20.1 2025-12-11T17:31:55.2360112 Languages: zh_cn
|
||||
7f4db04637eb656488388de206cad9070a53ae48 assets/superleadrope/lang/zh_cn.json
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// 1.20.1 2025-09-05T21:41:43.7307014 Item Models: superleadrope
|
||||
// 1.20.1 2025-12-11T18:08:58.6978167 Item Models: superleadrope
|
||||
c982e91b60c03a6460d1cc7b516628cf09a28417 assets/superleadrope/models/item/broken_super_lead_rope.json
|
||||
50782bef004ff1c69c09aa397a8ee92b71a8b858 assets/superleadrope/models/item/doll.json
|
||||
7b072a8cc70b53d54e37e5fa72d705bd07780943 assets/superleadrope/models/item/eternal_potato.json
|
||||
4fb737a5f8f15642212aa581a02a81cf649fc36f assets/superleadrope/models/item/super_lead_rope.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
// 1.20.1 2025-12-11T17:31:55.2360112 Block States: superleadrope
|
||||
6e9e15398c0d85d14941797931eb3f7c886a800a assets/superleadrope/blockstates/doll.json
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// 1.20.1 2025-12-11T17:31:55.2360112 Loot Tables
|
||||
c31110372e9281cf7264482c2c89c8927fb67fe2 data/superleadrope/loot_tables/blocks/doll.json
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-12-04T18:55:51.5034621 Languages: lzh
|
||||
8dde976f77c0ca836ed66627ea2af29b20e5f7c5 assets/superleadrope/lang/lzh.json
|
||||
// 1.20.1 2025-12-11T17:31:55.2360112 Languages: lzh
|
||||
c03cdd0fb0e9a7bcf525fc0e18fe31e2b906f8f0 assets/superleadrope/lang/lzh.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-12-04T18:55:51.5024633 Languages: en_us
|
||||
b1f5523a28ab74acc8bd5b0ec167bf254e0b0dea assets/superleadrope/lang/en_us.json
|
||||
// 1.20.1 2025-12-11T17:31:55.2360112 Languages: en_us
|
||||
d1d1d2a67f7602340c0f0e0dcf1ea1b93fdc23f4 assets/superleadrope/lang/en_us.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"variants": {
|
||||
"facing=east,waterlogged=false": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 90
|
||||
},
|
||||
"facing=east,waterlogged=true": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 90
|
||||
},
|
||||
"facing=north,waterlogged=false": {
|
||||
"model": "superleadrope:block/doll"
|
||||
},
|
||||
"facing=north,waterlogged=true": {
|
||||
"model": "superleadrope:block/doll"
|
||||
},
|
||||
"facing=south,waterlogged=false": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 180
|
||||
},
|
||||
"facing=south,waterlogged=true": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 180
|
||||
},
|
||||
"facing=west,waterlogged=false": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 270
|
||||
},
|
||||
"facing=west,waterlogged=true": {
|
||||
"model": "superleadrope:block/doll",
|
||||
"y": 270
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"block.superleadrope.doll": "Doll",
|
||||
"death.attack.eternal_potato_not_complete": "§c%1$s was not the rightful owner, struck by lightning!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s was not the rightful owner, struck by lightning!",
|
||||
"effect.superleadrope.no_super_leash": "No Super Leash",
|
||||
"entity.superleadrope.super_lead_knot": "Super Lead Knot",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent": "Create Leash Fence Knot Entity if absent",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent.description": "Create LeashKnot Entity if it's absent on fence or other supported positions",
|
||||
|
|
@ -22,6 +24,9 @@
|
|||
"item.eternal_potato.tooltip.punish": "§cOverdue punishments: §4%d §7(will be applied), grace exceeded: §4%d",
|
||||
"item.eternal_potato.tooltip.title": "§6Mythical Item §7- §6Eternal Potato",
|
||||
"item.eternal_potato.tooltip.unbound": "§cUnbound",
|
||||
"item.minecraft.lingering_potion.effect.no_super_leash": "Splash No Super Leash Potion",
|
||||
"item.minecraft.potion.effect.no_super_leash": "No Super Leash Potion",
|
||||
"item.minecraft.splash_potion.effect.no_super_leash": "Splash No Super Leash Potion",
|
||||
"item.superleadrope.eternal_potato": "Eternal Potato",
|
||||
"item.superleadrope.super_lead_rope": "Super Lead Rope",
|
||||
"sound.superleadrope.subtitle.lead_break": "Lead Break",
|
||||
|
|
@ -105,5 +110,6 @@
|
|||
"superleadrope.command.motion.message.multiply.successful": "§bMultiply Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§bSet Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"superleadrope.command.none": "<None>",
|
||||
"superleadrope.command.state": "State"
|
||||
"superleadrope.command.state": "State",
|
||||
"tooltip.superleadrope.author": "Author : R3944Realms"
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"block.superleadrope.doll": "戲像",
|
||||
"death.attack.eternal_potato_not_complete": "§c%1$s 非汝所主,雷霆降身!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 非汝所主,雷霆降身!",
|
||||
"effect.superleadrope.no_super_leash": "禁系之效",
|
||||
"entity.superleadrope.super_lead_knot": "神駒羈縻索結",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent": "若阙则创超级繫绳结",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent.description": "若栅等支处阙超级繫绳结,则创之",
|
||||
|
|
@ -22,6 +24,9 @@
|
|||
"item.eternal_potato.tooltip.punish": "§c逾期责务尚未完成: §4%d §7(將受懲罰),超出寬限數: §4%d",
|
||||
"item.eternal_potato.tooltip.title": "§6永恒土豆 §7- §6传奇之物",
|
||||
"item.eternal_potato.tooltip.unbound": "§c尚未绑定主人",
|
||||
"item.minecraft.lingering_potion.effect.no_super_leash": "缠绵禁系汤",
|
||||
"item.minecraft.potion.effect.no_super_leash": "禁系汤剂",
|
||||
"item.minecraft.splash_potion.effect.no_super_leash": "飞溅禁系汤",
|
||||
"item.superleadrope.eternal_potato": "不滅薯",
|
||||
"item.superleadrope.super_lead_rope": "神駒羈縻索",
|
||||
"sound.superleadrope.subtitle.lead_break": "索絕",
|
||||
|
|
@ -105,5 +110,6 @@
|
|||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b定值既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.none": "無",
|
||||
"superleadrope.command.state": "狀"
|
||||
"superleadrope.command.state": "狀",
|
||||
"tooltip.superleadrope.author": "作者 : R3944Realms"
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"block.superleadrope.doll": "玩偶",
|
||||
"death.attack.eternal_potato_not_complete": "§c%1$s 因使用非自己绑定物品,受到闪电惩罚!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 因使用非自己绑定物品,受到闪电惩罚!",
|
||||
"effect.superleadrope.no_super_leash": "禁拴",
|
||||
"entity.superleadrope.super_lead_knot": "超级拴绳结",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent": "如果缺失则创建超级拴绳结",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent.description": "如果在栅栏等支持处缺失超级拴绳结,则创建它",
|
||||
|
|
@ -22,6 +24,9 @@
|
|||
"item.eternal_potato.tooltip.punish": "§c逾期未完成责务: §4%d §7(将会受罚),超出宽限数: §4%d",
|
||||
"item.eternal_potato.tooltip.title": "§6神话物品 §7- §6永恒土豆",
|
||||
"item.eternal_potato.tooltip.unbound": "§c未绑定主人",
|
||||
"item.minecraft.lingering_potion.effect.no_super_leash": "滞留型禁拴药水",
|
||||
"item.minecraft.potion.effect.no_super_leash": "禁拴药水",
|
||||
"item.minecraft.splash_potion.effect.no_super_leash": "喷溅型禁拴药水",
|
||||
"item.superleadrope.eternal_potato": "永恒土豆",
|
||||
"item.superleadrope.super_lead_rope": "超级拴绳",
|
||||
"sound.superleadrope.subtitle.lead_break": "拴绳断裂",
|
||||
|
|
@ -105,5 +110,6 @@
|
|||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b设置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.none": "无",
|
||||
"superleadrope.command.state": "状态"
|
||||
"superleadrope.command.state": "状态",
|
||||
"tooltip.superleadrope.author": "作者 : R3944Realms"
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"block.superleadrope.doll": "玩偶",
|
||||
"death.attack.eternal_potato_not_complete": "§c%1$s 因使用非自己綁定物品,受到閃電懲罰!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 因使用非自己綁定物品,受到閃電懲罰!",
|
||||
"effect.superleadrope.no_super_leash": "禁拴",
|
||||
"entity.superleadrope.super_lead_knot": "超級拴繩結",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent": "如果缺失則創建超級拴繩結",
|
||||
"gamerule.SLP.CreateSuperLeashKnotEntityIfAbsent.description": "如果在柵欄等支持處缺失超級拴繩結,則創建它",
|
||||
|
|
@ -22,6 +24,9 @@
|
|||
"item.eternal_potato.tooltip.punish": "§c逾期未完成责務: §4%d §7(將會受罰),超出寬限數: §4%d",
|
||||
"item.eternal_potato.tooltip.title": "§6神話物品 §7- §6永恒土豆",
|
||||
"item.eternal_potato.tooltip.unbound": "§c未綁定主人",
|
||||
"item.minecraft.lingering_potion.effect.no_super_leash": "滯留型禁拴藥水",
|
||||
"item.minecraft.potion.effect.no_super_leash": "禁拴藥水",
|
||||
"item.minecraft.splash_potion.effect.no_super_leash": "噴濺型禁拴藥水",
|
||||
"item.superleadrope.eternal_potato": "永恆馬鈴薯",
|
||||
"item.superleadrope.super_lead_rope": "超級拴繩",
|
||||
"sound.superleadrope.subtitle.lead_break": "拴繩斷裂",
|
||||
|
|
@ -105,5 +110,6 @@
|
|||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b設置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.none": "無",
|
||||
"superleadrope.command.state": "狀態"
|
||||
"superleadrope.command.state": "狀態",
|
||||
"tooltip.superleadrope.author": "作者 : R3944Realms"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"parent": "superleadrope:block/doll"
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "superleadrope:doll"
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "superleadrope:blocks/doll"
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ import top.r3944realms.superleadrope.core.leash.LeashSyncManager;
|
|||
import top.r3944realms.superleadrope.core.potato.EternalPotatoFacade;
|
||||
import top.r3944realms.superleadrope.core.register.SLPGameruleRegistry;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.core.register.SLPPotionRecipeRegistry;
|
||||
import top.r3944realms.superleadrope.core.util.PotatoMode;
|
||||
import top.r3944realms.superleadrope.core.util.PotatoModeHelper;
|
||||
import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue;
|
||||
|
|
@ -499,6 +500,7 @@ public class CommonEventHandler {
|
|||
public static void onFMLCommonInit(FMLCommonSetupEvent event) {
|
||||
event.enqueueWork(Mod::checkAndSet);
|
||||
event.enqueueWork(SLPGameruleRegistry::register);
|
||||
event.enqueueWork(SLPPotionRecipeRegistry::init);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import top.r3944realms.superleadrope.compat.WayStoneCompat;
|
||||
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.core.register.*;
|
||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||
import top.r3944realms.superleadrope.util.file.ConfigUtil;
|
||||
|
||||
|
|
@ -53,8 +51,11 @@ public class SuperLeadRope {
|
|||
public SuperLeadRope() {
|
||||
IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
SLPItems.register(eventBus);
|
||||
SLPBlocks.register(eventBus);
|
||||
SLPEntityTypes.register(eventBus);
|
||||
SLPSoundEvents.register(eventBus);
|
||||
SLPEffects.register(eventBus);
|
||||
SLPPotions.register(eventBus);
|
||||
NetworkHandler.register();
|
||||
initialize();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,137 @@
|
|||
package top.r3944realms.superleadrope.compat;
|
||||
|
||||
import com.ibm.icu.impl.Pair;
|
||||
import net.blay09.mods.waystones.api.WaystoneTeleportEvent;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.api.event.SuperLeadRopeEvent;
|
||||
import top.r3944realms.superleadrope.api.type.capabilty.LeashInfo;
|
||||
import top.r3944realms.superleadrope.api.type.util.ILeashHelper;
|
||||
import top.r3944realms.superleadrope.api.workspace.Services;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||
import top.r3944realms.superleadrope.core.leash.LeashSyncManager;
|
||||
import top.r3944realms.superleadrope.core.register.SLPGameruleRegistry;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashStateInnerAPI;
|
||||
import top.r3944realms.superleadrope.util.entity.TeleportUtil;
|
||||
import top.r3944realms.superleadrope.util.model.RidingRelationship;
|
||||
import top.r3944realms.superleadrope.util.riding.RidingApplier;
|
||||
import top.r3944realms.superleadrope.util.riding.RidingDismounts;
|
||||
import top.r3944realms.superleadrope.util.riding.RidingFinder;
|
||||
import top.r3944realms.superleadrope.util.riding.RidingSaver;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class WayStoneCompat {
|
||||
public final static boolean isModLoaded = ModList.get().isLoaded("waystones");
|
||||
public final static Map<UUID, Set<Pair<Entity, OriginalState>>> tempLeashMap = new ConcurrentHashMap<>();
|
||||
public final static Map<UUID, UUID> uuidMap = new ConcurrentHashMap<>();
|
||||
public record OriginalState(Pose pose, boolean isSprinting, float yaw, float pitch, Vec3 deltaMovement, LeashInfo leashInfo, RidingRelationship ridingRelationship) {}
|
||||
public static void init() {
|
||||
if (isModLoaded) {
|
||||
MinecraftForge.EVENT_BUS.addListener(WayStoneCompat::onWayStoneTeleport);
|
||||
MinecraftForge.EVENT_BUS.addListener(WayStoneCompat::onWayStoneTeleport$Pre);
|
||||
MinecraftForge.EVENT_BUS.addListener(WayStoneCompat::onWayStoneTeleport$Post);
|
||||
}
|
||||
}
|
||||
public static void onWayStoneTeleport(WaystoneTeleportEvent.@NotNull Pre event) {
|
||||
Entity entity = event.getContext().getEntity();
|
||||
ILeashHelper.IHolder holderHelper = Services.WORK_SPACE.getLeashHelper().getHolderHelper(entity);
|
||||
public static void onWayStoneTeleport$Pre(WaystoneTeleportEvent.@NotNull Pre event) {
|
||||
Entity telEntity = event.getContext().getEntity();
|
||||
ILeashHelper.IHolder holderHelper = Services.WORK_SPACE.getLeashHelper().getHolderHelper(telEntity);
|
||||
Set<Entity> allLeashedEntities = holderHelper.getAllLeashedEntities();
|
||||
allLeashedEntities.forEach(event::addAdditionalEntity);
|
||||
if(!SLPGameruleRegistry.getGameruleBoolValue(telEntity.level(), TeleportWithLeashedEntities.ID)) {
|
||||
holderHelper.getAllLeashedEntities();
|
||||
return;
|
||||
}
|
||||
ServerLevel level = event.getContext().getDestination().getLevel();
|
||||
Vec3 destination = event.getContext().getDestination().getLocation();
|
||||
Set<Pair<Entity, OriginalState>> set = new HashSet<>();
|
||||
for (Entity beLeashedEntity : allLeashedEntities) {
|
||||
// --- 保存状态快照 ---
|
||||
if (MinecraftForge.EVENT_BUS.post(new SuperLeadRopeEvent.teleportWithHolder(beLeashedEntity, telEntity, beLeashedEntity.level(), level, beLeashedEntity.position(), destination)))
|
||||
continue;
|
||||
Pose originalPose = beLeashedEntity.getPose();
|
||||
boolean originalIsSprinting = beLeashedEntity.isSprinting();
|
||||
float originalYaw = beLeashedEntity.getYRot();
|
||||
float originalPitch = beLeashedEntity.getXRot();
|
||||
Vec3 originalDeltaMovement = beLeashedEntity.getDeltaMovement();
|
||||
|
||||
AtomicReference<LeashInfo> originalLeashInfo = new AtomicReference<>();
|
||||
LeashDataInnerAPI.getLeashData(beLeashedEntity).ifPresent(data -> {
|
||||
originalLeashInfo.set(data.getLeashInfo(telEntity).orElse(null));
|
||||
data.removeLeash(telEntity);
|
||||
});
|
||||
|
||||
|
||||
// --- 保存骑乘关系(可修改列表) ---
|
||||
RidingRelationship originalRidingRelationship = RidingSaver.save(beLeashedEntity, true);
|
||||
|
||||
// --- 解除骑乘 ---
|
||||
List<Entity> allPassengers = RidingFinder.getEntityFromRidingShip(originalRidingRelationship, level::getEntity);
|
||||
RidingDismounts.dismountEntities(allPassengers);
|
||||
set.add(Pair.of(beLeashedEntity, new OriginalState(
|
||||
originalPose,
|
||||
originalIsSprinting,
|
||||
originalYaw,
|
||||
originalPitch,
|
||||
originalDeltaMovement,
|
||||
originalLeashInfo.get(),
|
||||
originalRidingRelationship
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
tempLeashMap.put(telEntity.getUUID(), set);
|
||||
}
|
||||
public static void onWayStoneTeleport$Post(WaystoneTeleportEvent.@NotNull Post event) {
|
||||
Entity telEntity = event.getContext().getEntity();
|
||||
ServerLevel serverLevel = event.getContext().getDestination().getLevel();
|
||||
Vec3 destination = event.getContext().getDestination().getLocation();
|
||||
Set<Pair<Entity, OriginalState>> set = tempLeashMap.get(telEntity.getUUID());
|
||||
Set<UUID> shouldBeRemoved = new HashSet<>();
|
||||
if (set != null) {
|
||||
HashSet<Pair<Entity, OriginalState>> newSet = new HashSet<>();
|
||||
// --- 传送实体及乘客 ---
|
||||
for (Pair<Entity, OriginalState> entityPair : set) {
|
||||
Entity beLeashedEntity = entityPair.first;
|
||||
Entity newEntity = TeleportUtil.teleportEntity(beLeashedEntity, serverLevel, destination, beLeashedEntity.getDirection());
|
||||
if (!beLeashedEntity.getUUID().equals(newEntity.getUUID())){
|
||||
uuidMap.put(beLeashedEntity.getUUID(), newEntity.getUUID());
|
||||
}
|
||||
newSet.add(Pair.of(newEntity, entityPair.second));
|
||||
}
|
||||
for (Pair<Entity, OriginalState> entityPair : newSet) {
|
||||
// --- 恢复状态 ---
|
||||
Entity beLeashedEntity = entityPair.first;
|
||||
OriginalState originalState = entityPair.second;
|
||||
LeashStateInnerAPI.getLeashState(beLeashedEntity).ifPresent(LeashSyncManager.State::track);
|
||||
LeashDataInnerAPI.getLeashData(beLeashedEntity).ifPresent(LeashSyncManager.Data::track);
|
||||
beLeashedEntity.setDeltaMovement(originalState.deltaMovement);
|
||||
beLeashedEntity.setPose(originalState.pose);
|
||||
beLeashedEntity.setSprinting(originalState.isSprinting);
|
||||
// --- 将holder替换 ---
|
||||
LeashInfo leashInfo = Optional.ofNullable(originalState.leashInfo)
|
||||
.orElse(LeashInfo.EMPTY);
|
||||
if (leashInfo.holderUUIDOpt().isPresent() && uuidMap.containsKey(leashInfo.holderUUIDOpt().get())) {
|
||||
leashInfo.transferHolder(beLeashedEntity);
|
||||
shouldBeRemoved.add(leashInfo.holderUUIDOpt().get());
|
||||
}
|
||||
LeashDataInnerAPI.LeashOperations.attachWithInfo(beLeashedEntity, telEntity, leashInfo);
|
||||
// --- 重新应用骑乘关系,仅保留白名单根载具 ---
|
||||
uuidMap.forEach((oldUUID, newUUID) -> {
|
||||
int andReplaceAll = originalState.ridingRelationship.findAndReplaceAll(oldUUID, newUUID);
|
||||
if (andReplaceAll != 0) shouldBeRemoved.add(oldUUID);
|
||||
});
|
||||
RidingRelationship filteredRelationship = RidingSaver.filterByWhitelistRoot(originalState.ridingRelationship);
|
||||
RidingApplier.applyRidingRelationship(filteredRelationship, serverLevel::getEntity);
|
||||
}
|
||||
shouldBeRemoved.forEach(uuidMap::remove);
|
||||
tempLeashMap.remove(telEntity.getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public class LeashCommonConfig {
|
|||
*/
|
||||
// Leash settings
|
||||
public final ForgeConfigSpec.DoubleValue maxLeashLength;
|
||||
public final ForgeConfigSpec.DoubleValue maxMovement;
|
||||
/**
|
||||
* The Elastic distance scale.
|
||||
*/
|
||||
|
|
@ -155,7 +156,9 @@ public class LeashCommonConfig {
|
|||
maxLeashLength = builder
|
||||
.comment("Maximum leash distance (in blocks) for any entity")
|
||||
.defineInRange("maxLeashLength", 6.0, LeashConfigManager.MAX_DISTANCE_MIN_VALUE, LeashConfigManager.MAX_DISTANCE_MAX_VALUE);
|
||||
|
||||
maxMovement = builder
|
||||
.comment("Defines the maximum acceleration in standard coordinate directions (X/Y/Z axes)")
|
||||
.defineInRange("maxMovement", 100.0, 10.0, Double.MAX_VALUE);
|
||||
elasticDistanceScale = builder
|
||||
.comment("Default elastic distance for the Super Lead rope")
|
||||
.defineInRange("elasticDistanceScale", 1.0, LeashConfigManager.ELASTIC_DISTANCE_MIN_VALUE, LeashConfigManager.ELASTIC_DISTANCE_MAX_VALUE);
|
||||
|
|
@ -200,6 +203,8 @@ public class LeashCommonConfig {
|
|||
.defineInRange("mobSpringFactor", 0.5, 0.05, 2.0);
|
||||
builder.pop();
|
||||
|
||||
|
||||
|
||||
// ===== Leash State Offsets =====
|
||||
builder.push("LeashStateSettings");
|
||||
defaultApplyEntityLocationOffset = builder
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ public class LeashConfigManager {
|
|||
private volatile double mobSpringFactor = 0.5;
|
||||
|
||||
private volatile double maxLeashLength = 12.0;
|
||||
private volatile double maxMovement = 100.0;
|
||||
private volatile double elasticDistanceScale = 1.0;
|
||||
private volatile double extremeSnapFactor = 2.0;
|
||||
private volatile double springDampening = 0.7;
|
||||
|
|
@ -318,6 +319,7 @@ public class LeashConfigManager {
|
|||
* @return the max leash length
|
||||
*/
|
||||
public double getMaxLeashLength() { return maxLeashLength; }
|
||||
public double getMaxMovement() { return maxMovement; }
|
||||
|
||||
/**
|
||||
* Gets elastic distance scale.
|
||||
|
|
@ -399,6 +401,7 @@ public class LeashConfigManager {
|
|||
commandPrefixEnabledCache = LeashCommonConfig.COMMON.enableSLPModCommandPrefix.get();
|
||||
|
||||
maxLeashLength = LeashCommonConfig.COMMON.maxLeashLength.get();
|
||||
maxMovement = LeashCommonConfig.COMMON.maxMovement.get();
|
||||
elasticDistanceScale = LeashCommonConfig.COMMON.elasticDistanceScale.get();
|
||||
extremeSnapFactor = LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
||||
springDampening = LeashCommonConfig.COMMON.springDampening.get();
|
||||
|
|
@ -489,6 +492,7 @@ public class LeashConfigManager {
|
|||
tag.putDouble("mob_spring_factor", mobSpringFactor);
|
||||
|
||||
tag.putDouble("max_leash_length", maxLeashLength);
|
||||
tag.putDouble("max_movement", maxMovement);
|
||||
tag.putDouble("elastic_distance_scale", elasticDistanceScale);
|
||||
tag.putDouble("extreme_snap_factor", extremeSnapFactor);
|
||||
tag.putDouble("spring_dampening", springDampening);
|
||||
|
|
@ -524,6 +528,7 @@ public class LeashConfigManager {
|
|||
|
||||
// ========== 更新物理参数 ==========
|
||||
LeashCommonConfig.COMMON.maxLeashLength.set(maxLeashLength);
|
||||
LeashCommonConfig.COMMON.maxMovement.set(maxMovement);
|
||||
LeashCommonConfig.COMMON.elasticDistanceScale.set(elasticDistanceScale);
|
||||
LeashCommonConfig.COMMON.extremeSnapFactor.set(extremeSnapFactor);
|
||||
LeashCommonConfig.COMMON.springDampening.set(springDampening);
|
||||
|
|
@ -641,6 +646,9 @@ public class LeashConfigManager {
|
|||
if (tag.contains("max_leash_length", Tag.TAG_DOUBLE)) {
|
||||
maxLeashLength = tag.getDouble("max_leash_length");
|
||||
}
|
||||
if (tag.contains("max_movement", Tag.TAG_DOUBLE)) {
|
||||
maxLeashLength = tag.getDouble("max_movement");
|
||||
}
|
||||
if (tag.contains("elastic_distance_scale", Tag.TAG_DOUBLE)) {
|
||||
elasticDistanceScale = tag.getDouble("elastic_distance_scale");
|
||||
}
|
||||
|
|
@ -696,6 +704,7 @@ public class LeashConfigManager {
|
|||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(playerSpringFactor));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(mobSpringFactor));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(maxLeashLength));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(maxMovement));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(elasticDistanceScale));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(extremeSnapFactor));
|
||||
hash = fnv1aHashLong(hash, Double.doubleToLongBits(springDampening));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
package top.r3944realms.superleadrope.content.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class DollBlock extends HorizontalDirectionalBlock implements SimpleWaterloggedBlock {
|
||||
private static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
private static final VoxelShape DOLL_SHAPE = Block.box(2.0d, 0.0d, 2.0d, 14.0d, 12.0d, 14.0d);
|
||||
|
||||
private static final double PARTICLE_OFFSET_RANGE = 0.25;
|
||||
private static final double PARTICLE_HEIGHT_OFFSET = 1.0;
|
||||
private static final double PARTICLE_HEIGHT_VARIANCE = 0.2;
|
||||
private static final float NOTE_COLOR_DIVISOR = 24.0F;
|
||||
private static final int MAX_NOTE_COLORS = 4;
|
||||
|
||||
private static final float BASE_VOLUME = 1.0f;
|
||||
private static final float PITCH_VARIANCE = 0.5f;
|
||||
private static final float BASE_PITCH = 0.75f;
|
||||
|
||||
public DollBlock() {
|
||||
super(BlockBehaviour.Properties.of()
|
||||
.instrument(NoteBlockInstrument.BASEDRUM)
|
||||
.sound(SoundType.WOOL)
|
||||
.strength(0f, 10f)
|
||||
.noOcclusion());
|
||||
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.SOUTH)
|
||||
.setValue(WATERLOGGED, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState updateShape(@NotNull BlockState currentState, @NotNull Direction direction, @NotNull BlockState neighborState,
|
||||
@NotNull LevelAccessor level, @NotNull BlockPos currentPos, @NotNull BlockPos neighborPos) {
|
||||
if (currentState.getValue(WATERLOGGED)) {
|
||||
level.scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
|
||||
}
|
||||
return super.updateShape(currentState, direction, neighborState, level, currentPos, neighborPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FluidState getFluidState(@NotNull BlockState blockState) {
|
||||
return blockState.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InteractionResult use(@NotNull BlockState blockState, @NotNull Level level, @NotNull BlockPos blockPos, @NotNull Player player,
|
||||
@NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) {
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
// 播放粒子效果
|
||||
spawnNoteParticles(serverLevel, blockPos);
|
||||
// 播放音效
|
||||
playDollSound(serverLevel, blockPos);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在玩偶位置生成音符粒子效果
|
||||
*/
|
||||
private void spawnNoteParticles(ServerLevel serverLevel, BlockPos blockPos) {
|
||||
Vec3 particlePosition = calculateParticlePosition(serverLevel, blockPos);
|
||||
float noteColor = calculateNoteColor(serverLevel);
|
||||
|
||||
serverLevel.sendParticles(ParticleTypes.NOTE,
|
||||
particlePosition.x(), particlePosition.y(), particlePosition.z(),
|
||||
0, noteColor, 0, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算粒子生成位置,添加随机偏移
|
||||
*/
|
||||
private @NotNull Vec3 calculateParticlePosition(@NotNull ServerLevel serverLevel, BlockPos blockPos) {
|
||||
return Vec3.atBottomCenterOf(blockPos).add(
|
||||
(serverLevel.getRandom().nextFloat() - 0.5) * PARTICLE_OFFSET_RANGE * 2,
|
||||
PARTICLE_HEIGHT_OFFSET + serverLevel.getRandom().nextFloat() * PARTICLE_HEIGHT_VARIANCE,
|
||||
(serverLevel.getRandom().nextFloat() - 0.5) * PARTICLE_OFFSET_RANGE * 2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算音符粒子的颜色
|
||||
*/
|
||||
private float calculateNoteColor(@NotNull ServerLevel serverLevel) {
|
||||
return serverLevel.getRandom().nextInt(MAX_NOTE_COLORS) / NOTE_COLOR_DIVISOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放玩偶音效
|
||||
*/
|
||||
private void playDollSound(@NotNull ServerLevel serverLevel, BlockPos blockPos) {
|
||||
float pitch = BASE_PITCH + serverLevel.random.nextFloat() * PITCH_VARIANCE;
|
||||
serverLevel.playSound(null, blockPos, SoundEvents.NOTE_BLOCK_BASEDRUM.get(),
|
||||
SoundSource.BLOCKS, BASE_VOLUME, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
|
||||
FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos());
|
||||
boolean isWaterlogged = fluidState.getType() == Fluids.WATER;
|
||||
|
||||
return this.defaultBlockState()
|
||||
.setValue(FACING, context.getHorizontalDirection().getOpposite())
|
||||
.setValue(WATERLOGGED, isWaterlogged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull VoxelShape getShape(@NotNull BlockState blockState, @NotNull BlockGetter level, @NotNull BlockPos blockPos, @NotNull CollisionContext context) {
|
||||
return DOLL_SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
||||
builder.add(FACING, WATERLOGGED);
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ import java.util.stream.Stream;
|
|||
|
||||
/**
|
||||
* 预期行为
|
||||
* <pre>
|
||||
* <table border="1">
|
||||
* <thead>
|
||||
* <tr>
|
||||
|
|
@ -90,6 +91,7 @@ import java.util.stream.Stream;
|
|||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* </pre>
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class LeashDataImpl implements ILeashData {
|
||||
|
|
@ -804,7 +806,24 @@ public class LeashDataImpl implements ILeashData {
|
|||
boolean hasForce = !combinedForce.equals(Vec3.ZERO);
|
||||
Entity targetEntity = RindingLeash.getFinalEntityForLeashIfForce(entity, hasForce);
|
||||
if(targetEntity instanceof LocalPlayer && hasForce){
|
||||
entity.addDeltaMovement(combinedForce);
|
||||
entity.addDeltaMovement(limitMovement(combinedForce));
|
||||
}
|
||||
}
|
||||
|
||||
public Vec3 limitMovement(@NotNull Vec3 movement) {
|
||||
double maxMovement = CommonEventHandler.leashConfigManager.getMaxMovement();
|
||||
return new Vec3(
|
||||
clamp(movement.x, maxMovement),
|
||||
clamp(movement.y, maxMovement),
|
||||
clamp(movement.z, maxMovement)
|
||||
);
|
||||
}
|
||||
|
||||
private double clamp(double value, double max) {
|
||||
if (value > 0) {
|
||||
return Math.min(value, max);
|
||||
} else {
|
||||
return Math.max(value, -max);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -842,6 +861,7 @@ public class LeashDataImpl implements ILeashData {
|
|||
boolean hasForce = !combinedForce.equals(Vec3.ZERO);
|
||||
Entity targetEntity = RindingLeash.getFinalEntityForLeashIfForce(entity, hasForce);
|
||||
if (targetEntity != null && hasForce) {
|
||||
combinedForce = limitMovement(combinedForce);
|
||||
SuperLeadRopeEvent.hasFocus hasFocus = new SuperLeadRopeEvent.hasFocus(this.entity, targetEntity, combinedForce, vaildLeashHolders, vaildLeashKnots);
|
||||
if (MinecraftForge.EVENT_BUS.post(hasFocus)) return;
|
||||
combinedForce = hasFocus.getCombinedForce();
|
||||
|
|
@ -850,11 +870,11 @@ public class LeashDataImpl implements ILeashData {
|
|||
// 是真实玩家则交给客户端自行处理拴绳逻辑
|
||||
// DO NOTHING
|
||||
if(targetEntity != entity){
|
||||
NetworkHandler.sendToPlayer(new UpdatePlayerMovementPacket(UpdatePlayerMovementPacket.Operation.ADD, combinedForce), player);
|
||||
NetworkHandler.sendToPlayer(new UpdatePlayerMovementPacket(UpdatePlayerMovementPacket.Operation.ADD, limitMovement(combinedForce)), player);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
applyForceToNonPlayerEntity(targetEntity, combinedForce, validLeashes, combinedDirection);
|
||||
applyForceToNonPlayerEntity(targetEntity, limitMovement(combinedForce), validLeashes, combinedDirection);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package top.r3944realms.superleadrope.content.effect;
|
||||
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEffects;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class NoSuperLeashEffect extends MobEffect {
|
||||
public NoSuperLeashEffect(MobEffectCategory category, int color) {
|
||||
super(category, color);
|
||||
}
|
||||
@Override
|
||||
public void applyEffectTick(@NotNull LivingEntity pLivingEntity, int pAmplifier) {
|
||||
MobEffectInstance effect = pLivingEntity.getEffect(SLPEffects.NO_SUPER_LEASH_EFFECT.get());
|
||||
if(effect != null && effect.getDuration() != 0) {
|
||||
Optional<ILeashData> leashData = LeashDataInnerAPI.getLeashData(pLivingEntity);
|
||||
if (leashData.isPresent() && leashData.get().hasLeash()) {
|
||||
LeashDataInnerAPI.LeashOperations.detachAll(pLivingEntity);
|
||||
pLivingEntity.level().playSound(null,
|
||||
pLivingEntity.getOnPos(),
|
||||
SLPSoundEvents.LEAD_UNTIED.get(),
|
||||
SoundSource.AMBIENT
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDurationEffectTick(int duration, int amplifier) {
|
||||
return duration >= 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package top.r3944realms.superleadrope.content.item;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.superleadrope.core.register.SLPBlocks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DollItem extends BlockItem {
|
||||
public DollItem(Properties properties) {
|
||||
super(SLPBlocks.DOLL.get(), properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, List<Component> tooltip, @NotNull TooltipFlag flag) {
|
||||
tooltip.add(Component.translatable("tooltip.superleadrope.author"));
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import net.minecraft.sounds.SoundSource;
|
|||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
|
@ -34,6 +35,7 @@ import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
|||
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.SLPToolTier;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEffects;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||
|
||||
|
|
@ -195,6 +197,10 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
|||
|
||||
// 情况一:拴自己到新 knot
|
||||
if (shouldBindSelf && list.isEmpty()) {
|
||||
MobEffectInstance effect = player.getEffect(SLPEffects.NO_SUPER_LEASH_EFFECT.get());
|
||||
if (effect != null && effect.getDuration() >= 1) {
|
||||
return false;
|
||||
}
|
||||
if (leashStack.isEmpty() || !canUse(leashStack)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ import net.minecraft.sounds.SoundEvents;
|
|||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
|
@ -31,6 +33,7 @@ import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
|
|||
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEffects;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
|
||||
|
|
@ -53,7 +56,6 @@ public class LeashInteractHandler {
|
|||
//只有玩家可以互动触发(其它的暂不支持(考虑到0 Mixin)
|
||||
public static void onEntityRightInteract(Level level, InteractionHand hand, Entity target , Player player, PlayerInteractEvent.EntityInteract event) {
|
||||
//WARNING: 主手和副手都会触发一次该事件
|
||||
|
||||
// ===== 卫语句 =====
|
||||
if (level.isClientSide) {
|
||||
if (hand == InteractionHand.MAIN_HAND &&
|
||||
|
|
@ -63,6 +65,12 @@ public class LeashInteractHandler {
|
|||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
}
|
||||
if (target instanceof LivingEntity livingEntity) { //禁止拴绳效果存在则取消下面的逻辑
|
||||
MobEffectInstance effect = livingEntity.getEffect(SLPEffects.NO_SUPER_LEASH_EFFECT.get());
|
||||
if (effect != null && effect.getDuration() >= 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (SuperLeadRopeApi.isLeashHolder(target, player)) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
|
|
@ -97,6 +105,12 @@ public class LeashInteractHandler {
|
|||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
}
|
||||
} else {
|
||||
if (target instanceof LivingEntity livingEntity) { //禁止拴绳效果存在则取消下面的逻辑
|
||||
MobEffectInstance effect = livingEntity.getEffect(SLPEffects.NO_SUPER_LEASH_EFFECT.get());
|
||||
if (effect != null && effect.getDuration() >= 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (SuperLeadRopeApi.isLeashHolder(target, player)) {
|
||||
LeashCap.ifPresent(
|
||||
iLeashDataCapability -> iLeashDataCapability.removeLeash(player.getUUID())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package top.r3944realms.superleadrope.core.register;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.block.DollBlock;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class SLPBlocks {
|
||||
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, SuperLeadRope.MOD_ID);
|
||||
public static final RegistryObject<Block> DOLL = BLOCKS.register("doll", DollBlock::new);
|
||||
public static Collection<RegistryObject<Block>> getEntries() {
|
||||
return BLOCKS.getEntries();
|
||||
}
|
||||
public static void register(IEventBus eventBus) {
|
||||
BLOCKS.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package top.r3944realms.superleadrope.core.register;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.effect.NoSuperLeashEffect;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SLPEffects {
|
||||
public static DeferredRegister<MobEffect> MOB_EFFECT = DeferredRegister.create(Registries.MOB_EFFECT, SuperLeadRope.MOD_ID);
|
||||
public static RegistryObject<MobEffect> NO_SUPER_LEASH_EFFECT = register(
|
||||
"no_super_leash",
|
||||
() -> new NoSuperLeashEffect(MobEffectCategory.NEUTRAL, 12063764)
|
||||
);
|
||||
public static <T extends MobEffect> RegistryObject<MobEffect> register(String name, Supplier<T> effect) {
|
||||
return MOB_EFFECT.register(name, effect);
|
||||
}
|
||||
|
||||
public static String getEffectKey(MobEffect effect) {
|
||||
return effect.getDescriptionId();
|
||||
}
|
||||
public static String getModEffectKey(RegistryObject<MobEffect> effect) {
|
||||
return getEffectKey(effect.get());
|
||||
}
|
||||
public static void register(IEventBus eventBus) {
|
||||
MOB_EFFECT.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,11 +16,13 @@
|
|||
package top.r3944realms.superleadrope.core.register;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Rarity;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.item.DollItem;
|
||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
||||
|
||||
|
|
@ -49,6 +51,15 @@ public class SLPItems {
|
|||
.stacksTo(1) // 只能有一颗
|
||||
.fireResistant() // 防火
|
||||
));
|
||||
public static final RegistryObject<Item> DOLL =
|
||||
ITEMS.register("doll",
|
||||
() -> new DollItem(
|
||||
new Item.Properties()
|
||||
.stacksTo(1)
|
||||
.fireResistant()
|
||||
.rarity(Rarity.EPIC)
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Register.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
package top.r3944realms.superleadrope.core.register;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraft.world.item.alchemy.PotionUtils;
|
||||
import net.minecraft.world.item.alchemy.Potions;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraftforge.common.brewing.BrewingRecipe;
|
||||
import net.minecraftforge.common.brewing.BrewingRecipeRegistry;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class SLPPotionRecipeRegistry {
|
||||
public static class ProperBrewingRecipe extends BrewingRecipe {
|
||||
private final Ingredient input;
|
||||
|
||||
public ProperBrewingRecipe(Ingredient input, Ingredient ingredient, ItemStack output) {
|
||||
super(input, ingredient, output);
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isInput(@NotNull ItemStack stack) {
|
||||
ItemStack[] matchingStacks = input.getItems();
|
||||
if (matchingStacks.length == 0) {
|
||||
return stack.isEmpty();
|
||||
} else {
|
||||
for (ItemStack itemstack : matchingStacks) {
|
||||
if (ItemStack.isSameItem(stack, itemstack) && ItemStack.isSameItemSameTags(itemstack, stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
public static @NotNull ItemStack createPotion(@NotNull RegistryObject<Potion> potion){
|
||||
return PotionUtils.setPotion(new ItemStack(Items.POTION), potion.get());
|
||||
}
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static @NotNull ItemStack createPotion(Potion potion){
|
||||
return PotionUtils.setPotion(new ItemStack(Items.POTION), potion);
|
||||
}
|
||||
public static void init() {
|
||||
BrewingRecipeRegistry.addRecipe(
|
||||
new ProperBrewingRecipe(Ingredient.of(createPotion(Potions.INVISIBILITY)), Ingredient.of(Items.SLIME_BALL), createPotion(SLPPotions.NO_SUPER_LEASH)));
|
||||
BrewingRecipeRegistry.addRecipe(
|
||||
new ProperBrewingRecipe(Ingredient.of(createPotion(Potions.LONG_INVISIBILITY)), Ingredient.of(Items.SLIME_BALL), createPotion(SLPPotions.LONG_NO_SUPER_LEASH)));
|
||||
BrewingRecipeRegistry.addRecipe(
|
||||
new ProperBrewingRecipe(Ingredient.of(createPotion(SLPPotions.NO_SUPER_LEASH)), Ingredient.of(Items.REDSTONE), createPotion(SLPPotions.LONG_NO_SUPER_LEASH)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package top.r3944realms.superleadrope.core.register;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SLPPotions {
|
||||
public static DeferredRegister<Potion> POTIONS = DeferredRegister.create(Registries.POTION, SuperLeadRope.MOD_ID);
|
||||
public static final RegistryObject<Potion> NO_SUPER_LEASH = register("no_super_leash",
|
||||
() -> new Potion("no_super_leash", new MobEffectInstance(SLPEffects.NO_SUPER_LEASH_EFFECT.get(), 1200, 0))
|
||||
);
|
||||
public static final RegistryObject<Potion> LONG_NO_SUPER_LEASH = register("long_no_super_leash",
|
||||
() -> new Potion("no_super_leash", new MobEffectInstance(SLPEffects.NO_SUPER_LEASH_EFFECT.get(), 3600, 0))
|
||||
);
|
||||
public static <T extends Potion>RegistryObject<Potion> register(String Name, Supplier<T> supplier) {
|
||||
return POTIONS.register(Name, supplier);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param name the Name of Potion
|
||||
* @param type (char)<br/> [ <br/> 0 & 3 ~ 255 : potion <br/>1 : lingering_potion <br/>2 : splash_potion<br/>]
|
||||
* @return Language Key
|
||||
*/
|
||||
public static String getPotionNameKey(String name, char type) {
|
||||
return "item.minecraft." +
|
||||
(type == 1 ? "lingering_potion" :
|
||||
(type == 2 ? "splash_potion" : "potion")
|
||||
)
|
||||
+ ".effect." + name;
|
||||
}
|
||||
public static String getTippedArrowNameKey(String Name) {
|
||||
return "item.minecraft.tipped_arrow.effect." + Name;
|
||||
}
|
||||
|
||||
public static void register(IEventBus eventBus) {
|
||||
POTIONS.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,9 @@ public class SLPDataGenEvent {
|
|||
LanguageGenerator(event, LanguageEnum.LiteraryChinese);
|
||||
RecipeGenerator(event);
|
||||
ModelDataGenerate(event);
|
||||
BlockStateGenerate(event);
|
||||
TagsProvider(event, lookupProvider);
|
||||
LootTableGenerate(event);
|
||||
SoundProvider(event);
|
||||
}
|
||||
private static void LanguageGenerator(GatherDataEvent event, LanguageEnum language) {
|
||||
|
|
@ -97,4 +99,16 @@ public class SLPDataGenEvent {
|
|||
(DataProvider.Factory<SLPItemModelProvider>) pOutput -> new SLPItemModelProvider(pOutput, event.getExistingFileHelper())
|
||||
);
|
||||
}
|
||||
private static void LootTableGenerate(GatherDataEvent event) {
|
||||
event.getGenerator().addProvider(
|
||||
event.includeClient(),
|
||||
(DataProvider.Factory<SLPLootTableProvider>) SLPLootTableProvider::new
|
||||
);
|
||||
}
|
||||
private static void BlockStateGenerate(GatherDataEvent event) {
|
||||
event.getGenerator().addProvider(
|
||||
event.includeClient(),
|
||||
(DataProvider.Factory<SLPBlockStateGenerator>) pOutput -> new SLPBlockStateGenerator(pOutput, event.getExistingFileHelper())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ import top.r3944realms.superleadrope.content.command.MotionCommand;
|
|||
import top.r3944realms.superleadrope.content.gamerule.server.CreateSuperLeashKnotEntityIfAbsent;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.core.register.*;
|
||||
import top.r3944realms.superleadrope.util.lang.LanguageEnum;
|
||||
import top.r3944realms.superleadrope.util.lang.ModPartEnum;
|
||||
|
||||
|
|
@ -917,6 +915,47 @@ public enum SLPLangKeyValue {
|
|||
"成功觸發%s的力",
|
||||
"%s之力,今已發"
|
||||
),
|
||||
NO_LEASH_EFFECT(
|
||||
SLPEffects.getEffectKey(SLPEffects.NO_SUPER_LEASH_EFFECT.get()), ModPartEnum.NAME,
|
||||
"No Super Leash",
|
||||
"禁拴",
|
||||
"禁拴",
|
||||
"禁系之效"
|
||||
),
|
||||
NO_LEASH_POTION(
|
||||
SLPPotions.getPotionNameKey("no_super_leash", (char) 0), ModPartEnum.NAME,
|
||||
"No Super Leash Potion",
|
||||
"禁拴药水",
|
||||
"禁拴藥水",
|
||||
"禁系汤剂"
|
||||
),
|
||||
NO_LEASH_POTION_SPLASH(
|
||||
SLPPotions.getPotionNameKey("no_super_leash", (char) 2), ModPartEnum.NAME,
|
||||
"Splash No Super Leash Potion",
|
||||
"喷溅型禁拴药水",
|
||||
"噴濺型禁拴藥水",
|
||||
"飞溅禁系汤"
|
||||
),
|
||||
NO_LEASH_POTION_LINGERING(
|
||||
SLPPotions.getPotionNameKey("no_super_leash", (char) 1), ModPartEnum.NAME,
|
||||
"Splash No Super Leash Potion",
|
||||
"滞留型禁拴药水",
|
||||
"滯留型禁拴藥水",
|
||||
"缠绵禁系汤"
|
||||
),
|
||||
DOLL_BLOCK(
|
||||
SLPBlocks.DOLL, ModPartEnum.BLOCK,
|
||||
"Doll", "玩偶", "玩偶", "戲像"
|
||||
),
|
||||
DOLL_ITEM(
|
||||
SLPItems.DOLL, ModPartEnum.ITEM,
|
||||
"Doll", "玩偶", "玩偶", "戲像"
|
||||
),
|
||||
AUTHOR_TOOLTIP(
|
||||
"tooltip.superleadrope.author", ModPartEnum.DESCRIPTION,
|
||||
"Author : R3944Realms", "作者 : R3944Realms",
|
||||
"作者 : R3944Realms", "作者 : R3944Realms"
|
||||
)
|
||||
|
||||
;
|
||||
private final Supplier<?> supplier;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* *
|
||||
* * Copyright (c) 2025 R3944Realms. All rights reserved.
|
||||
* *
|
||||
* * This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||
* * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
* * or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
* *
|
||||
* * 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
|
||||
*
|
||||
*/
|
||||
|
||||
package top.r3944realms.superleadrope.datagen.provider;
|
||||
|
||||
import net.minecraft.data.loot.BlockLootSubProvider;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.core.register.SLPBlocks;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class SLPBlockLootTables extends BlockLootSubProvider {
|
||||
public SLPBlockLootTables() {
|
||||
super(Set.of(), FeatureFlags.REGISTRY.allFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generate() {
|
||||
dropSelf(SLPBlocks.DOLL.get());
|
||||
}
|
||||
@Override
|
||||
protected @NotNull Iterable<Block> getKnownBlocks() {
|
||||
return SLPBlocks.getEntries().stream().map(RegistryObject::get)::iterator;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package top.r3944realms.superleadrope.datagen.provider;
|
||||
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraftforge.client.model.generators.BlockStateProvider;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.core.register.SLPBlocks;
|
||||
|
||||
public class SLPBlockStateGenerator extends BlockStateProvider {
|
||||
public SLPBlockStateGenerator(PackOutput output, ExistingFileHelper exFileHelper) {
|
||||
super(output, SuperLeadRope.MOD_ID, exFileHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerStatesAndModels() {
|
||||
horizontalBlock(SLPBlocks.DOLL.get(), models().getExistingFile(modLoc("block/doll")));
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import net.minecraftforge.client.model.generators.ModelFile;
|
|||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -35,6 +36,7 @@ import java.util.Objects;
|
|||
*/
|
||||
public class SLPItemModelProvider extends ItemModelProvider {
|
||||
private static List<Item> objectList;
|
||||
public static final ResourceLocation DOLL = new ResourceLocation(SuperLeadRope.MOD_ID, "block/doll");
|
||||
/**
|
||||
* The constant GENERATED.
|
||||
*/
|
||||
|
|
@ -60,6 +62,7 @@ public class SLPItemModelProvider extends ItemModelProvider {
|
|||
protected void registerModels() {
|
||||
DefaultModItemModelRegister();
|
||||
superLeadRopeModel();
|
||||
generateDollItemModel();
|
||||
}
|
||||
private void init() {
|
||||
for(SLPLangKeyValue obj : SLPLangKeyValue.values()) {
|
||||
|
|
@ -93,6 +96,10 @@ public class SLPItemModelProvider extends ItemModelProvider {
|
|||
public void itemHandHeldModel(Item item, ResourceLocation location){
|
||||
withExistingParent(itemName(item), HANDHELD).texture("layer0", location);
|
||||
}
|
||||
private void generateDollItemModel() {
|
||||
withExistingParent(itemName(SLPItems.DOLL.get()), DOLL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Super lead rope model.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package top.r3944realms.superleadrope.datagen.provider;
|
||||
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.loot.LootTableProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.level.storage.loot.ValidationContext;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The type Simple loot table provider.
|
||||
*/
|
||||
public class SLPLootTableProvider extends LootTableProvider {
|
||||
/**
|
||||
* Instantiates a new Simple loot table provider.
|
||||
*
|
||||
* @param output the output
|
||||
* @param subProvidersWrapper the sub providers wrapper
|
||||
*/
|
||||
public SLPLootTableProvider(PackOutput output) {
|
||||
super(output, Set.of(), List.of(new LootTableProvider.SubProviderEntry(
|
||||
SLPBlockLootTables::new,
|
||||
LootContextParamSets.BLOCK
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void validate(@NotNull Map<ResourceLocation, LootTable> map, @NotNull ValidationContext validationcontext) {
|
||||
map.forEach((id, table) -> table.validate(validationcontext));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package top.r3944realms.superleadrope.util.entity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class TeleportUtil {
|
||||
|
||||
/**
|
||||
* 通用实体传送(支持玩家、普通生物、跨维度、生物停飞、导航停止等)
|
||||
*/
|
||||
public static @NotNull Entity teleportEntity(Entity oldEntity, ServerLevel targetWorld, @NotNull Vec3 targetPos, @NotNull Direction direction) {
|
||||
float yaw = direction.toYRot();
|
||||
double x = targetPos.x;
|
||||
double y = targetPos.y;
|
||||
double z = targetPos.z;
|
||||
|
||||
if (oldEntity instanceof ServerPlayer player) {
|
||||
teleportPlayer(player, targetWorld, x, y, z, yaw);
|
||||
} else {
|
||||
oldEntity = teleportNonPlayer(oldEntity, targetWorld, x, y, z, yaw);
|
||||
}
|
||||
|
||||
// 停止滑翔,否则 Elytra 无限飞
|
||||
if (!(oldEntity instanceof LivingEntity living) || !living.isFallFlying()) {
|
||||
oldEntity.setDeltaMovement(oldEntity.getDeltaMovement().multiply(1.0, 0.0, 1.0));
|
||||
oldEntity.setOnGround(true);
|
||||
}
|
||||
|
||||
// 停止 AI 导航,避免卡行为树
|
||||
if (oldEntity instanceof PathfinderMob mob) {
|
||||
mob.getNavigation().stop();
|
||||
}
|
||||
|
||||
sendHackySyncPacketsAfterTeleport(oldEntity);
|
||||
|
||||
return oldEntity;
|
||||
}
|
||||
|
||||
|
||||
// --- 分离后的子方法 ------------------------------------------------
|
||||
|
||||
private static void teleportPlayer(@NotNull ServerPlayer player, @NotNull ServerLevel targetWorld,
|
||||
double x, double y, double z, float yaw) {
|
||||
|
||||
ChunkPos chunkPos = new ChunkPos(BlockPos.containing(x, y, z));
|
||||
targetWorld.getChunkSource().addRegionTicket(
|
||||
TicketType.POST_TELEPORT,
|
||||
chunkPos,
|
||||
1,
|
||||
player.getId()
|
||||
);
|
||||
|
||||
// 玩家睡觉状态处理
|
||||
if (player.isSleeping()) {
|
||||
player.stopSleepInBed(true, true);
|
||||
}
|
||||
|
||||
player.stopRiding();
|
||||
|
||||
// 同维度直接 connection.teleport
|
||||
if (targetWorld == player.level()) {
|
||||
player.connection.teleport(x, y, z, yaw, player.getXRot(), Collections.emptySet());
|
||||
} else {
|
||||
player.teleportTo(targetWorld, x, y, z, yaw, player.getXRot());
|
||||
}
|
||||
|
||||
player.setYHeadRot(yaw);
|
||||
}
|
||||
|
||||
|
||||
private static @NotNull Entity teleportNonPlayer(@NotNull Entity entity, ServerLevel targetWorld,
|
||||
double x, double y, double z, float yaw) {
|
||||
|
||||
float pitch = Mth.clamp(entity.getXRot(), -90, 90);
|
||||
|
||||
// 同维度移动
|
||||
if (targetWorld == entity.level()) {
|
||||
entity.moveTo(x, y, z, yaw, pitch);
|
||||
entity.setYHeadRot(yaw);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// 跨维度传送
|
||||
entity.unRide();
|
||||
|
||||
Entity newEntity = entity.getType().create(targetWorld);
|
||||
|
||||
if (newEntity == null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
newEntity.restoreFrom(entity);
|
||||
newEntity.moveTo(x, y, z, yaw, pitch);
|
||||
newEntity.setYHeadRot(yaw);
|
||||
|
||||
entity.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION);
|
||||
targetWorld.addDuringTeleport(newEntity);
|
||||
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修复玩家经验条显示等问题的同步包
|
||||
*/
|
||||
private static void sendHackySyncPacketsAfterTeleport(Entity entity) {
|
||||
if (entity instanceof ServerPlayer player) {
|
||||
player.connection.send(
|
||||
new ClientboundSetExperiencePacket(
|
||||
player.experienceProgress,
|
||||
player.totalExperience,
|
||||
player.experienceLevel
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
package top.r3944realms.superleadrope.util.model;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
|
@ -138,6 +140,121 @@ public class RidingRelationship {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 查找并替换所有匹配的UUID
|
||||
*
|
||||
* @param oldUuid 要查找的旧UUID
|
||||
* @param newUuid 要替换的新UUID
|
||||
* @return 替换的数量
|
||||
*/
|
||||
public int findAndReplaceAll(UUID oldUuid, UUID newUuid) {
|
||||
int replacedCount = 0;
|
||||
|
||||
// 替换当前节点的entityId
|
||||
if (Objects.equals(this.entityId, oldUuid)) {
|
||||
this.entityId = newUuid;
|
||||
replacedCount++;
|
||||
}
|
||||
|
||||
// 替换当前节点的vehicleId
|
||||
if (Objects.equals(this.vehicleId, oldUuid)) {
|
||||
this.vehicleId = newUuid;
|
||||
replacedCount++;
|
||||
}
|
||||
|
||||
// 递归替换所有乘客
|
||||
for (RidingRelationship passenger : passengers) {
|
||||
replacedCount += passenger.findAndReplaceAll(oldUuid, newUuid);
|
||||
}
|
||||
|
||||
return replacedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找所有出现的UUID位置
|
||||
*
|
||||
* @param targetUuid 要查找的UUID
|
||||
* @return 包含位置的列表,格式为"角色(实体/载具)-索引"
|
||||
*/
|
||||
public List<String> findAllOccurrences(UUID targetUuid) {
|
||||
List<String> occurrences = new ArrayList<>();
|
||||
findAllOccurrencesRecursive(targetUuid, this, occurrences, "");
|
||||
return occurrences;
|
||||
}
|
||||
|
||||
private void findAllOccurrencesRecursive(UUID targetUuid, @NotNull RidingRelationship node,
|
||||
List<String> occurrences, String path) {
|
||||
// 检查当前节点的entityId
|
||||
if (Objects.equals(node.entityId, targetUuid)) {
|
||||
String fullPath = path.isEmpty() ? "根实体" : path + "->乘客";
|
||||
occurrences.add(fullPath + "(实体ID)");
|
||||
}
|
||||
|
||||
// 检查当前节点的vehicleId
|
||||
if (Objects.equals(node.vehicleId, targetUuid)) {
|
||||
String fullPath = path.isEmpty() ? "根实体" : path;
|
||||
occurrences.add(fullPath + "(载具ID)");
|
||||
}
|
||||
|
||||
// 递归检查乘客
|
||||
for (int i = 0; i < node.passengers.size(); i++) {
|
||||
String newPath = path.isEmpty() ? "乘客[" + i + "]" : path + "->乘客[" + i + "]";
|
||||
findAllOccurrencesRecursive(targetUuid, node.passengers.get(i), occurrences, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找并替换所有UUID(支持批量替换)
|
||||
*
|
||||
* @param replacements 替换映射表,key为旧UUID,value为新UUID
|
||||
* @return 总替换数量
|
||||
*/
|
||||
public int batchFindAndReplace(Map<UUID, UUID> replacements) {
|
||||
int totalReplaced = 0;
|
||||
|
||||
// 替换当前节点的entityId
|
||||
if (this.entityId != null && replacements.containsKey(this.entityId)) {
|
||||
this.entityId = replacements.get(this.entityId);
|
||||
totalReplaced++;
|
||||
}
|
||||
|
||||
// 替换当前节点的vehicleId
|
||||
if (this.vehicleId != null && replacements.containsKey(this.vehicleId)) {
|
||||
this.vehicleId = replacements.get(this.vehicleId);
|
||||
totalReplaced++;
|
||||
}
|
||||
|
||||
// 递归批量替换所有乘客
|
||||
for (RidingRelationship passenger : passengers) {
|
||||
totalReplaced += passenger.batchFindAndReplace(replacements);
|
||||
}
|
||||
|
||||
return totalReplaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树中所有唯一的UUID集合
|
||||
*
|
||||
* @return 包含所有UUID的集合
|
||||
*/
|
||||
public Set<UUID> getAllUniqueUUIDs() {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
getAllUniqueUUIDsRecursive(this, uuids);
|
||||
return uuids;
|
||||
}
|
||||
|
||||
private void getAllUniqueUUIDsRecursive(RidingRelationship node, Set<UUID> uuids) {
|
||||
if (node.entityId != null) {
|
||||
uuids.add(node.entityId);
|
||||
}
|
||||
if (node.vehicleId != null) {
|
||||
uuids.add(node.vehicleId);
|
||||
}
|
||||
|
||||
for (RidingRelationship passenger : node.passengers) {
|
||||
getAllUniqueUUIDsRecursive(passenger, uuids);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ package top.r3944realms.superleadrope.util.riding;
|
|||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.CommonEventHandler;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.core.exception.RidingCycleException;
|
||||
import top.r3944realms.superleadrope.core.util.ImmutablePair;
|
||||
import top.r3944realms.superleadrope.util.model.RidingRelationship;
|
||||
|
|
@ -36,7 +39,8 @@ public class RidingSaver {
|
|||
* @param entity the entity
|
||||
* @return the riding relationship
|
||||
*/
|
||||
public static RidingRelationship save(@Nullable Entity entity) {
|
||||
@Contract("null -> new")
|
||||
public static @NotNull RidingRelationship save(@Nullable Entity entity) {
|
||||
return save(entity, true);
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +51,8 @@ public class RidingSaver {
|
|||
* @param findRoot the find root
|
||||
* @return the riding relationship
|
||||
*/
|
||||
public static RidingRelationship save(@Nullable Entity entity, boolean findRoot) {
|
||||
@Contract("null, _ -> new")
|
||||
public static @NotNull RidingRelationship save(@Nullable Entity entity, boolean findRoot) {
|
||||
if (entity == null) {
|
||||
return new RidingRelationship(Collections.emptyList(), null, null);
|
||||
}
|
||||
|
|
@ -118,33 +123,37 @@ public class RidingSaver {
|
|||
*/
|
||||
public static RidingRelationship filterByWhitelistRoot(RidingRelationship relationship) {
|
||||
if (relationship == null) return null;
|
||||
|
||||
// 如果当前根节点在白名单,则直接处理子节点
|
||||
if (CommonEventHandler.leashConfigManager.isEntityTeleportAllowed(Objects.requireNonNull(getEntityType(relationship.getEntityId())))) {
|
||||
RidingRelationship filtered = new RidingRelationship();
|
||||
filtered.setEntityId(relationship.getEntityId());
|
||||
filtered.setVehicleId(relationship.getVehicleId());
|
||||
filtered.setPassengers(filterPassengers(relationship.getPassengers()));
|
||||
return filtered;
|
||||
} else {
|
||||
// 根节点不在白名单,尝试找到合法的子节点作为新的根
|
||||
for (RidingRelationship child : relationship.getPassengers()) {
|
||||
if (CommonEventHandler.leashConfigManager.isEntityTeleportAllowed(Objects.requireNonNull(getEntityType(child.getEntityId())))) {
|
||||
// 设置父节点为当前节点的父(倒二叉逻辑)
|
||||
RidingRelationship newRoot = new RidingRelationship();
|
||||
newRoot.setEntityId(child.getEntityId());
|
||||
newRoot.setVehicleId(relationship.getVehicleId());
|
||||
newRoot.setPassengers(filterPassengers(child.getPassengers()));
|
||||
return newRoot;
|
||||
try {
|
||||
// 如果当前根节点在白名单,则直接处理子节点
|
||||
if (CommonEventHandler.leashConfigManager.isEntityTeleportAllowed(Objects.requireNonNull(getEntityType(relationship.getEntityId())))) {
|
||||
RidingRelationship filtered = new RidingRelationship();
|
||||
filtered.setEntityId(relationship.getEntityId());
|
||||
filtered.setVehicleId(relationship.getVehicleId());
|
||||
filtered.setPassengers(filterPassengers(relationship.getPassengers()));
|
||||
return filtered;
|
||||
} else {
|
||||
// 根节点不在白名单,尝试找到合法的子节点作为新的根
|
||||
for (RidingRelationship child : relationship.getPassengers()) {
|
||||
if (CommonEventHandler.leashConfigManager.isEntityTeleportAllowed(Objects.requireNonNull(getEntityType(child.getEntityId())))) {
|
||||
// 设置父节点为当前节点的父(倒二叉逻辑)
|
||||
RidingRelationship newRoot = new RidingRelationship();
|
||||
newRoot.setEntityId(child.getEntityId());
|
||||
newRoot.setVehicleId(relationship.getVehicleId());
|
||||
newRoot.setPassengers(filterPassengers(child.getPassengers()));
|
||||
return newRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
SuperLeadRope.logger.error("Catch null", e);
|
||||
}
|
||||
|
||||
// 如果整个子树都不在白名单,返回空关系
|
||||
return new RidingRelationship(new ArrayList<>(), null, null);
|
||||
}
|
||||
|
||||
private static List<RidingRelationship> filterPassengers(List<RidingRelationship> passengers) {
|
||||
@Contract("null -> new")
|
||||
private static @NotNull List<RidingRelationship> filterPassengers(List<RidingRelationship> passengers) {
|
||||
if (passengers == null || passengers.isEmpty()) return new ArrayList<>();
|
||||
List<RidingRelationship> filtered = new ArrayList<>();
|
||||
for (RidingRelationship passenger : passengers) {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
291
src/main/resources/assets/superleadrope/models/block/doll.json
Normal file
291
src/main/resources/assets/superleadrope/models/block/doll.json
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
{
|
||||
"format_version": "1.21.6",
|
||||
"credit": "3D Model © 2025 LeisureTimeDock",
|
||||
"render_type": "cutout",
|
||||
"textures": {
|
||||
"0": "superleadrope:block/custom/author",
|
||||
"1": "block/pink_tulip",
|
||||
"particle": "block/white_wool"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Toggle_Helmet",
|
||||
"from": [3.5, 8.8, 7.5],
|
||||
"to": [12.5, 17.8, 16.5],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 9.3, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [10, 2, 12, 4], "texture": "#0"},
|
||||
"east": {"uv": [8, 2, 10, 4], "texture": "#0"},
|
||||
"south": {"uv": [14, 2, 16, 4], "texture": "#0"},
|
||||
"west": {"uv": [12, 2, 14, 4], "texture": "#0"},
|
||||
"up": {"uv": [10, 2, 12, 0], "texture": "#0"},
|
||||
"down": {"uv": [12, 0, 14, 2], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Head",
|
||||
"from": [4, 9.3, 8],
|
||||
"to": [12, 17.3, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 9.3, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 2, 4, 4], "texture": "#0"},
|
||||
"east": {"uv": [0, 2, 2, 4], "texture": "#0"},
|
||||
"south": {"uv": [6, 2, 8, 4], "texture": "#0"},
|
||||
"west": {"uv": [4, 2, 6, 4], "texture": "#0"},
|
||||
"up": {"uv": [4, 2, 2, 0], "texture": "#0"},
|
||||
"down": {"uv": [6, 0, 4, 2], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Toggle_Chest_Armor",
|
||||
"from": [4.75, 2.05, 9.75],
|
||||
"to": [11.25, 9.55, 13.25],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5.8, 11.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [5, 9, 7, 12], "texture": "#0"},
|
||||
"east": {"uv": [4, 9, 5, 12], "texture": "#0"},
|
||||
"south": {"uv": [8, 9, 10, 12], "texture": "#0"},
|
||||
"west": {"uv": [7, 9, 8, 12], "texture": "#0"},
|
||||
"up": {"uv": [5, 8, 7, 9], "texture": "#0"},
|
||||
"down": {"uv": [7, 8, 9, 9], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Body",
|
||||
"from": [5, 2.3, 10],
|
||||
"to": [11, 9.3, 13],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5.8, 11.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [5, 5, 7, 8], "texture": "#0"},
|
||||
"east": {"uv": [4, 5, 5, 8], "texture": "#0"},
|
||||
"south": {"uv": [8, 5, 10, 8], "texture": "#0"},
|
||||
"west": {"uv": [7, 5, 8, 8], "texture": "#0"},
|
||||
"up": {"uv": [7, 5, 5, 4], "texture": "#0"},
|
||||
"down": {"uv": [9, 4, 7, 5], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Toggle_Left_Arm_Armor",
|
||||
"from": [2.75, 6.25, 3.8],
|
||||
"to": [5.25, 9.75, 13.3],
|
||||
"rotation": {"angle": -22.5, "axis": "y", "origin": [3, 8, 12.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [13.75, 12, 14.5, 13], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [12, 13, 13, 16], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [13, 12, 13.75, 13], "texture": "#0"},
|
||||
"west": {"uv": [13.75, 13, 14.75, 16], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [13, 13, 13.75, 16], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [14.75, 13, 15.5, 16], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Left_arm",
|
||||
"from": [3, 6.5, 3.8],
|
||||
"to": [5, 9.5, 12.8],
|
||||
"rotation": {"angle": -22.5, "axis": "y", "origin": [4, 8, 12.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [10.5, 12, 9.75, 13], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [8, 13, 9, 16], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [9.75, 13, 9, 12], "texture": "#0"},
|
||||
"west": {"uv": [9.75, 13, 10.5, 16], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [9, 13, 9.75, 16], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [10.5, 13, 11.5, 16], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Toggle_Right_Arm_Armor",
|
||||
"from": [10.75, 6.25, 3.8],
|
||||
"to": [13.25, 9.75, 13.3],
|
||||
"rotation": {"angle": 22.5, "axis": "y", "origin": [12, 8, 11.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [11.75, 8, 12.5, 9], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [10, 9, 11, 12], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [11, 8, 11.75, 9], "texture": "#0"},
|
||||
"west": {"uv": [11.75, 9, 12.75, 12], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [11, 9, 11.75, 12], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [12.75, 9, 13.5, 12], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Right_arm",
|
||||
"from": [11, 6.5, 3.8],
|
||||
"to": [13.5, 9.5, 12.8],
|
||||
"rotation": {"angle": 22.5, "axis": "y", "origin": [12, 8, 11.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.5, 4, 11.75, 5], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [10, 5, 11, 8], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [11.75, 5, 11, 4], "texture": "#0"},
|
||||
"west": {"uv": [11.75, 5, 12.5, 8], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [11, 5, 11.75, 8], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [12.5, 5, 13.5, 8], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Toggle_Left_Leg_Armor",
|
||||
"from": [5.2, -0.25, 3.05],
|
||||
"to": [8.7, 3.25, 12.55],
|
||||
"rotation": {"angle": 22.5, "axis": "y", "origin": [5.7, 2, 13]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 12, 3, 13], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [0, 13, 1, 16], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [1, 12, 2, 13], "texture": "#0"},
|
||||
"west": {"uv": [2, 13, 3, 16], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [1, 13, 2, 16], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [3, 13, 4, 16], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Left_leg",
|
||||
"from": [5.5, 0, 3.3],
|
||||
"to": [8.5, 3, 12.3],
|
||||
"rotation": {"angle": 22.5, "axis": "y", "origin": [6, 2, 13]},
|
||||
"faces": {
|
||||
"north": {"uv": [7, 12, 6, 13], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [4, 13, 5, 16], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [5.95, 13, 5, 11.925], "texture": "#0"},
|
||||
"west": {"uv": [6, 13, 7, 16], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [5, 13, 6, 16], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [7, 13, 8, 16], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Toggle_Right_Leg_Armor",
|
||||
"from": [7.2, -0.25, 3.05],
|
||||
"to": [10.7, 3.25, 12.55],
|
||||
"rotation": {"angle": -22.5, "axis": "y", "origin": [8.7, 2, 13]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 8, 3, 9], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [0, 9, 1, 12], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [1, 8, 2, 9], "texture": "#0"},
|
||||
"west": {"uv": [2, 9, 3, 12], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [1, 9, 2, 12], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [3, 9, 4, 12], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Right_leg",
|
||||
"from": [7.5, 0, 3.3],
|
||||
"to": [10.5, 3, 12.3],
|
||||
"rotation": {"angle": -22.5, "axis": "y", "origin": [9, 2, 13]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 4, 2, 5], "rotation": 180, "texture": "#0"},
|
||||
"east": {"uv": [0, 5, 1, 8], "rotation": 270, "texture": "#0"},
|
||||
"south": {"uv": [2, 5, 1, 4], "texture": "#0"},
|
||||
"west": {"uv": [2, 5, 3, 8], "rotation": 90, "texture": "#0"},
|
||||
"up": {"uv": [1, 5, 2, 8], "rotation": 180, "texture": "#0"},
|
||||
"down": {"uv": [3, 5, 4, 8], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [7, 6, 1],
|
||||
"to": [7, 14, 9],
|
||||
"rotation": {"angle": 45, "axis": "y", "origin": [7, 10, 3.5]},
|
||||
"faces": {
|
||||
"east": {"uv": [0, 0, 16, 16], "texture": "#1"},
|
||||
"west": {"uv": [0, 0, 16, 16], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [9, 6, 1],
|
||||
"to": [9, 14, 9],
|
||||
"rotation": {"angle": -45, "axis": "y", "origin": [9, 10, 3.5]},
|
||||
"faces": {
|
||||
"east": {"uv": [0, 0, 16, 16], "texture": "#1"},
|
||||
"west": {"uv": [0, 0, 16, 16], "texture": "#1"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [75, 45, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [75, 45, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [0, 124, 0],
|
||||
"translation": [2, 3, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [0, 120, 0],
|
||||
"translation": [1.5, 2.75, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"ground": {
|
||||
"translation": [0, 2, 0],
|
||||
"scale": [0.5, 0.5, 0.5]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [30, -135, 0],
|
||||
"translation": [0.75, -1, 0],
|
||||
"scale": [0.625, 0.625, 0.625]
|
||||
},
|
||||
"head": {
|
||||
"translation": [0, 14, -0.75]
|
||||
},
|
||||
"fixed": {
|
||||
"translation": [0, 0, -2.75],
|
||||
"scale": [0.5, 0.5, 0.5]
|
||||
},
|
||||
"on_shelf": {
|
||||
"rotation": [0, -180, 0],
|
||||
"translation": [0, 0, 5.25]
|
||||
}
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"name": "Player",
|
||||
"origin": [3, -6.7, 6],
|
||||
"color": 0,
|
||||
"children": [
|
||||
{
|
||||
"name": "Head",
|
||||
"origin": [8, 16, 8],
|
||||
"color": 0,
|
||||
"children": [0, 1]
|
||||
},
|
||||
{
|
||||
"name": "Body",
|
||||
"origin": [8, 11, 8],
|
||||
"color": 0,
|
||||
"children": [2, 3]
|
||||
},
|
||||
{
|
||||
"name": "Left_Arm",
|
||||
"origin": [5, 15, 6],
|
||||
"color": 0,
|
||||
"children": [4, 5]
|
||||
},
|
||||
{
|
||||
"name": "Right_Arm",
|
||||
"origin": [11, 15, 6],
|
||||
"color": 0,
|
||||
"children": [6, 7]
|
||||
},
|
||||
{
|
||||
"name": "Left_Leg",
|
||||
"origin": [7, 13, 7],
|
||||
"color": 0,
|
||||
"children": [8, 9]
|
||||
},
|
||||
{
|
||||
"name": "Right_Leg",
|
||||
"origin": [10, 13, 7],
|
||||
"color": 0,
|
||||
"children": [10, 11]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item",
|
||||
"origin": [0, 4, 2.5],
|
||||
"color": 0,
|
||||
"children": [12, 13]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 372 B |
Loading…
Reference in New Issue
Block a user