从1.21.5迁移更新到1.21.6版本
Some checks failed
Build / build (push) Failing after 33s

支持其它生物,待修复渲染和箭矢功能异常BUG
This commit is contained in:
叁玖领域 2025-06-18 18:34:35 +08:00
parent 9de55bd40d
commit 557795ab02
70 changed files with 969 additions and 591 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2023 NeoForged project
Copyright (c) 2025 R3944Realms
This license applies to the template files as supplied by github.com/NeoForged/MDK

View File

@ -1,7 +1,7 @@
plugins {
id 'java-library'
id 'maven-publish'
id 'net.neoforged.gradle.userdev' version '7.0.184'
id 'net.neoforged.gradle.userdev' version '7.0.185'
}
tasks.named('wrapper', Wrapper).configure {

View File

@ -7,26 +7,26 @@ org.gradle.configuration-cache=false
#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
neogradle.subsystems.parchment.minecraftVersion=1.21.4
neogradle.subsystems.parchment.mappingsVersion=2025.03.23
neogradle.subsystems.parchment.minecraftVersion=1.21.5
neogradle.subsystems.parchment.mappingsVersion=2025.06.15
# Environment Properties
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
# The Minecraft version must agree with the Neo version to get a valid artifact
minecraft_version=1.21.5
minecraft_version=1.21.6
# The Minecraft version range can use any release version of Minecraft as bounds.
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21.5]
minecraft_version_range=[1.21.6]
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.5.30-beta
neo_version=21.6.0-beta
# The Neo version range can use any version of Neo as bounds
neo_version_range=[21.5.30-beta,)
neo_version_range=[21.6.0-beta,)
# The loader version range can only use the major version of FML as bounds
loader_version_range=[1,)
## Mod Properties
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
# Must match the String constant located in the main mod class annotated with @Mod.
mod_id=leashedplayer
# The human-readable display name for the mod.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.12-bin.zip
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@ -3,6 +3,7 @@ pluginManagement {
mavenLocal()
gradlePluginPortal()
maven { url = 'https://maven.neoforged.net/releases' }
maven { url = 'https://maven.parchmentmc.org' } // Add this line
}
}

View File

@ -1,3 +1,3 @@
// 1.21.5 2025-03-29T16:40:03.0405054 Registries
// 1.21.6 2025-06-18T18:13:35.4577733 Registries
f2536789df7f06362718a59ba4a96890e2f9b8aa data/leashedplayer/jukebox_song/what_does_the_fox_say.json
84106976f4f71012fc5bd1784303a0d135623c77 data/leashedplayer/painting_variant/group_photo.json

View File

@ -1,4 +1,4 @@
// 1.21.5 2025-03-29T16:40:02.9875592 Tags for minecraft:item mod id leashedplayer
// 1.21.6 2025-06-18T18:13:35.4379687 Tags for minecraft:item mod id leashedplayer
84707301f1fe2490a899deb51302d413cfff5a89 data/c/tags/item/tools/shear.json
bde6ca31173d1f22d5f6fe355dc90c9faa35b239 data/minecraft/tags/item/amethyst_tool_materials.json
63e4ad58dc8397171f84264d53dfe4fb503c7b1e data/minecraft/tags/item/arrows.json

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:03.0435015 Languages: en_us for mod: leashedplayer
2c7f061dfc276db13135adce15c68cfc145ccf37 assets/leashedplayer/lang/en_us.json
// 1.21.6 2025-06-18T18:13:35.4587797 Languages: en_us for mod: leashedplayer
0d9f238cc355f438904865d0105ea2288d8ab5ba assets/leashedplayer/lang/en_us.json

View File

@ -1 +1 @@
// 1.21.5 2025-03-29T16:40:03.0112992 Tags for minecraft:block mod id leashedplayer
// 1.21.6 2025-06-18T18:13:35.4478159 Tags for minecraft:block mod id leashedplayer

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:03.0510463 Sound Definitions
// 1.21.6 2025-06-18T18:13:35.4661082 Sound Definitions
81f1cc9f404c2670bf7cc679107177ffb0b48c77 assets/leashedplayer/sounds.json

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:03.0163693 Tags for minecraft:painting_variant mod id leashedplayer
// 1.21.6 2025-06-18T18:13:35.4508133 Tags for minecraft:painting_variant mod id leashedplayer
e081a053d7c2f2d3238cf38436185ef23d234505 data/minecraft/tags/painting_variant/placeable.json

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:02.9987109 Languages: lzh for mod: leashedplayer
// 1.21.6 2025-06-18T18:13:35.4409646 Languages: lzh for mod: leashedplayer
7536eb6d1c69695c06ebb9da5b57a391174b02cb assets/leashedplayer/lang/lzh.json

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:03.0306291 Languages: zh_cn for mod: leashedplayer
f7bcf89907a8ca5f575e4b519d53cd0628bb1e6b assets/leashedplayer/lang/zh_cn.json
// 1.21.6 2025-06-18T18:13:35.4553638 Languages: zh_cn for mod: leashedplayer
bd16693f46f05f6bd5d6b9cb26a8bf7c460d34b9 assets/leashedplayer/lang/zh_cn.json

View File

@ -1,4 +1,4 @@
// 1.21.5 2025-03-29T16:40:03.0040344 LeashedPlayer Recipes
// 1.21.6 2025-06-18T18:13:35.4448617 LeashedPlayer Recipes
13ebe9a580731296eb10c05d1844657d58e07cc1 data/leashedplayer/advancement/recipes/misc/amethyst_shears.json
1b45d1ad8dc73f1787c97777ad13d9771c9e0ad1 data/leashedplayer/advancement/recipes/misc/leash_rope_arrow.json
a26d63c2360b32df0b636a5dec96dd919139e022 data/leashedplayer/advancement/recipes/misc/spectral_leash_rope_arrow.json

View File

@ -1,9 +1,12 @@
// 1.21.5 2025-03-29T16:40:03.0481 Model Definitions - leashedplayer
// 1.21.6 2025-06-18T18:13:35.4621401 Model Definitions - leashedplayer
4239e6d8ef328b74d7ea1a48309758fe7979861c assets/leashedplayer/blockstates/test_block.json
d213db38f45b911f2023c83e15b018371a630ae0 assets/leashedplayer/items/amethyst_shears.json
bc53c9feb22db83882974d60456bef0d3ef3ef5e assets/leashedplayer/items/fabric.json
e4e426067245e93d282a3d953c420fca04c23f3d assets/leashedplayer/items/leash_rope_arrow.json
6151e1b11ec884d511b2fd595e39c9f12674e824 assets/leashedplayer/items/spectral_leash_rope_arrow.json
e08c92045a5fb984dee259c719ddd6b3a3f06615 assets/leashedplayer/items/test_block_item.json
1b914911c9077563701e9ac4b7f8c425f6eff4ee assets/leashedplayer/items/tipped_leash_rope_arrow.json
149b31dffff370f181edceef0284696c0ab31130 assets/leashedplayer/models/block/test_block.json
766c487fbf0c59e9045eeaf81daf583eb679b0e1 assets/leashedplayer/models/item/amethyst_shears.json
5846df9d85726428905701120ef34c9324c20faf assets/leashedplayer/models/item/bow_lra_pulling_0.json
845a7316b86e26f88c6932d4ef2656126503727a assets/leashedplayer/models/item/bow_lra_pulling_1.json
@ -12,6 +15,7 @@ e4e426067245e93d282a3d953c420fca04c23f3d assets/leashedplayer/items/leash_rope_a
bb0d76077719c83c8a8bd4346a24ea1766175125 assets/leashedplayer/models/item/fabric.json
114d3cc5832ef047403114504483c6f3ea07e77c assets/leashedplayer/models/item/leash_rope_arrow.json
c4748995a5fe190d20e3bd16f4b2244164ec0f83 assets/leashedplayer/models/item/spectral_leash_rope_arrow.json
de0da544ae0eaab40c8560af30ceb760dded3758 assets/leashedplayer/models/item/test_block_item.json
ba065b1a88d82f95e10d026bf7bfdac7923de24c assets/leashedplayer/models/item/tipped_leash_rope_arrow.json
fe3d4b8fd83f9ba4e2a951ec2e23ea98a347c2cc assets/minecraft/items/bow.json
12be767d961ae273ae0968ad06f022b57afbb0b0 assets/minecraft/items/crossbow.json

View File

@ -1,4 +1,4 @@
// 1.21.5 2025-03-30T19:34:30.4253532 Advancements
// 1.21.6 2025-06-18T18:13:35.4686422 Advancements
4d97adba079f1966090a52443bb439319f550680 data/leashedplayer/advancement/advancement_leash_arrow.json
f16184b81ea35a0fbd8f2c49b085a96c32818c69 data/leashedplayer/advancement/dog_running_player.json
bce12ed339b3b0fded263ba039f7a4e6fcfb84ca data/leashedplayer/advancement/follow_arrow.json

View File

@ -1,2 +1,2 @@
// 1.21.5 2025-03-29T16:40:03.0241113 Languages: zh_tw for mod: leashedplayer
c23825af72a73bc54b72ad3817acb5a03d299375 assets/leashedplayer/lang/zh_tw.json
// 1.21.6 2025-06-18T18:13:35.4528154 Languages: zh_tw for mod: leashedplayer
112cc45974d69bb6427982c2e8c906d300e91585 assets/leashedplayer/lang/zh_tw.json

View File

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "leashedplayer:block/test_block"
}
}
}

View File

@ -0,0 +1,6 @@
{
"model": {
"type": "minecraft:model",
"model": "leashedplayer:item/test_block_item"
}
}

View File

@ -21,6 +21,7 @@
"advancement.leashedplayer.no_leash.desc": "You cannot be leashed by ANY",
"advancement.leashedplayer.tipped_leash_arrow": "God said there should be more arrows",
"advancement.leashedplayer.tipped_leash_arrow.desc": "A dazzling array of Leash Rope arrows",
"block.leashedplayer.test_block": "Test Block",
"creativetab.leashedplayer.leashedplayer_tab": "Leashed Player",
"effect.leashedplayer.no_leash": "No Leash",
"entity.leashedplayer.kid_player": "Kid",
@ -44,6 +45,7 @@
"item.leashedplayer.leash_rope_arrow": "Leash Rope Arrow",
"item.leashedplayer.neoforge": "NeoForge",
"item.leashedplayer.spectral_leash_rope_arrow": "Spectral Leash Rope Arrow",
"item.leashedplayer.test_block_item": "Test Block",
"item.minecraft.lingering_potion.effect.no_leash": "Splash No Leash Potion",
"item.minecraft.potion.effect.no_leash": "No Leash Potion",
"item.minecraft.splash_potion.effect.no_leash": "Splash No Leash Potion",

View File

@ -21,6 +21,7 @@
"advancement.leashedplayer.no_leash.desc": "你不会被任何东西拴住",
"advancement.leashedplayer.tipped_leash_arrow": "神说要有更多箭矢",
"advancement.leashedplayer.tipped_leash_arrow.desc": "真是琳琅满目啊",
"block.leashedplayer.test_block": "测试方块",
"creativetab.leashedplayer.leashedplayer_tab": "可拴玩家",
"effect.leashedplayer.no_leash": "禁拴",
"entity.leashedplayer.kid_player": "小孩",
@ -44,6 +45,7 @@
"item.leashedplayer.leash_rope_arrow": "拴绳箭",
"item.leashedplayer.neoforge": "NeoForge",
"item.leashedplayer.spectral_leash_rope_arrow": "拴绳光灵箭",
"item.leashedplayer.test_block_item": "测试方块",
"item.minecraft.lingering_potion.effect.no_leash": "滞留型禁拴药水",
"item.minecraft.potion.effect.no_leash": "禁拴药水",
"item.minecraft.splash_potion.effect.no_leash": "喷溅型禁拴药水",

View File

@ -21,6 +21,7 @@
"advancement.leashedplayer.no_leash.desc": "恁不會被任何拴住",
"advancement.leashedplayer.tipped_leash_arrow": "神說要有更多箭矢",
"advancement.leashedplayer.tipped_leash_arrow.desc": "真是琳琅滿目啊",
"block.leashedplayer.test_block": "測試方塊",
"creativetab.leashedplayer.leashedplayer_tab": "可拴玩家",
"effect.leashedplayer.no_leash": "禁拴",
"entity.leashedplayer.kid_player": "小孩",
@ -44,6 +45,7 @@
"item.leashedplayer.leash_rope_arrow": "拴繩箭",
"item.leashedplayer.neoforge": "NeoForge",
"item.leashedplayer.spectral_leash_rope_arrow": "拴繩光靈箭",
"item.leashedplayer.test_block_item": "測試方塊",
"item.minecraft.lingering_potion.effect.no_leash": "滯留型禁拴藥水",
"item.minecraft.potion.effect.no_leash": "禁拴藥水",
"item.minecraft.splash_potion.effect.no_leash": "噴濺型禁拴藥水",

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "leashedplayer:block/test_block"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "leashedplayer:item/test_block_item"
}
}

View File

@ -55,7 +55,7 @@ public class ClientEventHandler {
assert player != null;
if (ModKeyMapping.KEY_ADD_LEASH_LENGTH.isDown()) {
PlayerLeashable playerLeashable = (PlayerLeashable) player;
if (playerLeashable.getLeashDataFromEntityData() == null) {
if (playerLeashable.getLeashData() == null) {
assert minecraft.level != null;
List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
@ -65,13 +65,13 @@ public class ClientEventHandler {
}
}
}
if (playerLeashable.getLeashDataFromEntityData() != null) {
if (playerLeashable.getLeashData() != null) {
PacketDistributor.sendToServer(new IncreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
}
}
if (ModKeyMapping.KEY_SUB_LEASH_LENGTH.isDown()) {
PlayerLeashable playerLeashable = (PlayerLeashable) player;
if (playerLeashable.getLeashDataFromEntityData() == null) {
if (playerLeashable.getLeashData() == null) {
assert minecraft.level != null;
List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
@ -81,7 +81,7 @@ public class ClientEventHandler {
}
}
}
if (playerLeashable.getLeashDataFromEntityData() != null) {
if (playerLeashable.getLeashData() != null) {
PacketDistributor.sendToServer(new DecreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
}
}

View File

@ -1,22 +1,32 @@
package com.r3944realms.leashedplayer;
import com.mojang.brigadier.CommandDispatcher;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import com.r3944realms.leashedplayer.content.blocks.entity.ItemMemoryBlockEntity;
import com.r3944realms.leashedplayer.content.capabilities.ModCapabilities;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.commands.MotionCommand;
import com.r3944realms.leashedplayer.content.commands.TickCommand;
import com.r3944realms.leashedplayer.content.effects.ModPotionRegister;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.content.misc.LeadBreakItemBehavior;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.network.client.SyncLeashRopeLength;
import com.r3944realms.leashedplayer.utils.Util;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionBrewing;
@ -26,10 +36,16 @@ import net.minecraft.world.level.block.DispenserBlock;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
import net.neoforged.neoforge.common.Tags;
import net.neoforged.neoforge.event.AnvilUpdateEvent;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
import net.neoforged.neoforge.event.tick.EntityTickEvent;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.neoforged.neoforge.network.PacketDistributor;
import org.jetbrains.annotations.NotNull;
public class CommonEventHandler {
@ -47,6 +63,7 @@ public class CommonEventHandler {
PotionBrewing.Builder builder = event.getBuilder();
builder.addMix(Potions.WATER, Items.SLIME_BALL, ModPotionRegister.NO_LEASH);
}
@SubscribeEvent
public static void OnLivingTickEvent(EntityTickEvent.Post event) {
Entity entity = event.getEntity();
@ -74,19 +91,67 @@ public class CommonEventHandler {
}
}
if (entity instanceof Leashable leashable) {
IEntityLeadExtension leadExtension = (IEntityLeadExtension) entity;
if (leashable.isLeashed() && leadExtension.hasLeadLengthSync()) {
PacketDistributor.sendToAllPlayers(
new SyncLeashRopeLength(entity.getUUID().toString(), leadExtension.getLeashLength())
);
leadExtension.setLeadLengthSync(true);
}
}
}
@SubscribeEvent
public static void onBlockInteract(PlayerInteractEvent.RightClickBlock event) {
Level level = event.getLevel();
BlockPos pos = event.getPos();
Player player = event.getEntity();
ItemStack heldItem = player.getItemInHand(event.getHand());
if (level.getBlockEntity(pos) instanceof ItemMemoryBlockEntity be) {
if(level.isClientSide) event.setCanceled(true);
// 阻止默认操作如打开GUI
event.setCanceled(true);
if (!heldItem.isEmpty()) {
// 如果手持物品记忆并复制
be.setMemorizedItem(heldItem);
copyAndDropItem(level, pos, heldItem.copy());
} else {
// 如果空手使用记忆的物品复制
ItemStack memorized = be.getMemorizedItem();
if (!memorized.isEmpty()) {
copyAndDropItem(level, pos, memorized.copy());
} else {
player.displayClientMessage(Component.literal("No item memorized!"), true);
}
}
}
}
// 复制并丢出物品
private static void copyAndDropItem(Level level, BlockPos pos, ItemStack stack) {
if (!level.isClientSide) {
ItemEntity itemEntity = new ItemEntity(
level,
pos.getX() + 0.5,
pos.getY() + 1.0,
pos.getZ() + 0.5,
stack
);
level.addFreshEntity(itemEntity);
}
}
@SubscribeEvent
public static void OnAnvilUpdated(AnvilUpdateEvent event) {
String name = event.getName();
ItemStack left = event.getLeft();
if (left.is(Items.ANVIL) && name != null && name.equals("NeoForge")) {
event.setCost(1);
event.setXpCost(1);
event.setOutput(ModItemRegister.NEOFORGE.get().getDefaultInstance());
} else if (left.is(ModItemRegister.NEOFORGE.get().asItem()) && name != null && name.equals("Forge")) {
ItemStack instance = Items.ANVIL.getDefaultInstance();
instance.set(DataComponents.CUSTOM_NAME, Component.literal("Forge").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.AQUA));
event.setOutput(instance);
event.setCost(1);
event.setXpCost(1);
}
}
}
@ -101,6 +166,30 @@ public class CommonEventHandler {
DispenserBlock.registerBehavior(ModItemRegister.AMETHYST_SHEARS.get(), new LeadBreakItemBehavior());
});
}
@SubscribeEvent
public static void onRegisterCapabilities(RegisterCapabilitiesEvent event) {
event.registerBlock(
ModCapabilities.ITEM_MEMORY_COPY_BLOCK_CAP,
((level, pos, state, blockEntity, context) -> new ItemStackHandler(1) {
@Override
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
return true;
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
if (!simulate && !stack.isEmpty()) {
if (blockEntity instanceof ItemMemoryBlockEntity itemMemoryBlockEntity)
itemMemoryBlockEntity.setMemorizedItem(stack);
else throw new IllegalStateException("BlockEntity must be an instance of ItemMemoryBlockEntity");
}
return stack; // 不实际存储物品直接返回原物品
}
}),
ModBlocksRegister.TEST_BLOCK.get()
);
}
}

View File

@ -1,6 +1,8 @@
package com.r3944realms.leashedplayer;
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import com.r3944realms.leashedplayer.content.blocks.entity.ModBlockEntityRegister;
import com.r3944realms.leashedplayer.content.criteriaTriggers.ModCriteriaTriggers;
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
import com.r3944realms.leashedplayer.content.effects.ModPotionRegister;
@ -26,6 +28,8 @@ public class LeashedPlayer {
private static Integer M4; //拴绳最大长度
public LeashedPlayer(IEventBus event) {
ModItemRegister.register(event);
ModBlocksRegister.register(event);
ModBlockEntityRegister.register(event);
ModRecipeRegister.register(event);
ModSoundRegister.register(event);
ModPaintingsRegister.register(event);
@ -66,5 +70,8 @@ public class LeashedPlayer {
}
return M4;
}
public static Double maxSize() {
return M1() * M4();
}
}

View File

@ -5,7 +5,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.datafixers.util.Either;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.client.Camera;
@ -298,7 +298,7 @@ public class LeashRendererUtil {
double entityRotationAngleRadians = (double)(cameraEntity.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
// 计算实体的绳索偏移此处add偏移让渲染拴绳显示在玩家头部下大约在脖子处
Vec3 cameraEntityLeashOffset = cameraEntity.getLeashOffset(partialTick).add(0, -0.2, -0.5);
Vec3 cameraEntityLeashOffset = ((Leashable)cameraEntity).getLeashOffset(partialTick).add(0, -0.2, -0.5);
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
@ -351,7 +351,7 @@ public class LeashRendererUtil {
if(!(pCamera.getEntity() instanceof AbstractClientPlayer)) continue;
Minecraft mc = Minecraft.getInstance();
if (mc.options.getCameraType().isFirstPerson()) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashData();
if(leashDataFromEntityData == null) continue;
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
if(delayedLeashInfo != null) {
@ -373,7 +373,7 @@ public class LeashRendererUtil {
if (playerByUUID != null) {
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, playerByUUID, Vec3.ZERO);
} else {
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * LeashedPlayer.M1() * LeashedPlayer.M2();
double MaxLeashLength = ((IEntityLeadExtension) abstractClientPlayer).getLeashLength() * LeashedPlayer.M1() * LeashedPlayer.M2();
List<Entity> entities = level.getEntities(
null,
new AABB(
@ -423,7 +423,7 @@ public class LeashRendererUtil {
}
public static void createPlayerLeashState(AbstractClientPlayer abstractClientPlayer, IPlayerRenderStateExtension playerRenderState, float partialTick) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashData();
Leashable.LeashData leashData = ((PlayerLeashable) abstractClientPlayer).getLeashData();
PlayerRenderState playerRs = (PlayerRenderState)playerRenderState;
if (leashDataFromEntityData != null) {
@ -441,12 +441,12 @@ public class LeashRendererUtil {
playerRenderState.setPlayerLeashState(null);
}
} else if(leashData != null) {
playerRs.leashState = null;
playerRs.leashStates = null;
Entity leashHolder = ((PlayerLeashable) abstractClientPlayer).getLeashHolder();
PlayerLeashState playerLeashState = playerRenderState.getPlayerLeashState();
if (leashHolder != null & playerLeashState != null) {
float f = leashHolder.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0);
Vec3 vec3 = abstractClientPlayer.getLeashOffset(partialTick).yRot(-f);
Vec3 vec3 = ((Leashable)abstractClientPlayer).getLeashOffset(partialTick).yRot(-f);
BlockPos blockpos1 = BlockPos.containing(abstractClientPlayer.getEyePosition(partialTick));
BlockPos blockpos = BlockPos.containing(leashHolder.getEyePosition(partialTick));
playerLeashState.vanilaLeashState = new EntityRenderState.LeashState();
@ -498,7 +498,7 @@ public class LeashRendererUtil {
playerLeashState.pos = playerByUUID.position().add(0.0, playerByUUID.getEyeHeight() * 0.6, 0);
} else {
double breakDistanceTime = (leashDataFromEntityData.leashHolder instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * breakDistanceTime;
double MaxLeashLength = ((IEntityLeadExtension) abstractClientPlayer).getLeashLength() * breakDistanceTime;
List<Entity> entities = level.getEntities(
null,
new AABB(

View File

@ -1,7 +1,6 @@
package com.r3944realms.leashedplayer.client.renderer.gui;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
import net.minecraft.client.gui.GuiGraphics;
@ -9,6 +8,7 @@ import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RenderGuiEvent;
import org.joml.Matrix3x2fStack;
import java.util.Map;
@ -24,7 +24,7 @@ public class AdaptiveGuiRendererHandler {
@SubscribeEvent
public static void onRendererLevel(RenderGuiEvent.Pre event) {
PoseStack matrixStack = event.getGuiGraphics().pose();
Matrix3x2fStack matrixStack = event.getGuiGraphics().pose();
GuiGraphics guiGraphics = event.getGuiGraphics();
processBars.keySet().forEach(
processBar -> {

View File

@ -1,9 +1,9 @@
package com.r3944realms.leashedplayer.client.renderer.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
import net.minecraft.client.gui.GuiGraphics;
import org.joml.Matrix3x2fStack;
public interface IFadingProcessBarRenderer<T extends IProcessBar> extends IProcessBarRenderer<T> {
/**
@ -57,11 +57,11 @@ public interface IFadingProcessBarRenderer<T extends IProcessBar> extends IProce
*/
@Deprecated
@Override
default void renderProcessBar(PoseStack poseStack, GuiGraphics guiGraphics) {
default void renderProcessBar(Matrix3x2fStack poseStack, GuiGraphics guiGraphics) {
updateFadeEffect();
renderProcessBar0(poseStack, guiGraphics);
}
void renderProcessBar0(PoseStack poseStack, GuiGraphics guiGraphics);
void renderProcessBar0(Matrix3x2fStack poseStack, GuiGraphics guiGraphics);
default void fadeInTick(float fadeSpeed) {
if (getFadeAlpha() >= 1.0f) {

View File

@ -1,13 +1,13 @@
package com.r3944realms.leashedplayer.client.renderer.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
import net.minecraft.client.gui.GuiGraphics;
import org.joml.Matrix3x2fStack;
public interface IProcessBarRenderer<T extends IProcessBar> {
T getProcessBar();
void setProcessBar(T processBar);
void renderProcessBar(PoseStack poseStack, GuiGraphics guiGraphics);
void renderProcessBar(Matrix3x2fStack poseStack, GuiGraphics guiGraphics);
default void stopRender() {
T processBar = getProcessBar();
processBar.decreaseAliveCount();

View File

@ -1,6 +1,5 @@
package com.r3944realms.leashedplayer.client.renderer.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.LeashedPlayer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
@ -10,6 +9,7 @@ import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.RenderGuiEvent;
import org.joml.Matrix3x2fStack;
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, value = Dist.CLIENT)
public class ProcessBarRenderer {
@ -35,7 +35,7 @@ public class ProcessBarRenderer {
}
@SubscribeEvent
public static void onRendererLevel(RenderGuiEvent.Pre event) {
PoseStack matrixStack = event.getGuiGraphics().pose();
Matrix3x2fStack matrixStack = event.getGuiGraphics().pose();
GuiGraphics guiGraphics = event.getGuiGraphics();
if(isRendering) {
renderProgressBar(matrixStack, guiGraphics);
@ -44,7 +44,7 @@ public class ProcessBarRenderer {
public static float getProgress() {
return (float) currentProgress / progressDuration;
}
private static void renderProgressBar(PoseStack matrixStack, GuiGraphics guiGraphics) {
private static void renderProgressBar(Matrix3x2fStack matrixStack, GuiGraphics guiGraphics) {
Minecraft mc = Minecraft.getInstance();
int screenWidth = mc.getWindow().getGuiScaledWidth();
int screenHeight = mc.getWindow().getGuiScaledHeight();

View File

@ -1,12 +1,12 @@
package com.r3944realms.leashedplayer.client.renderer.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
import com.r3944realms.leashedplayer.utils.ColorUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix3x2fStack;
public class TestProcessBarRenderer implements IFadingProcessBarRenderer<IProcessBar>{
@Nullable
@ -122,7 +122,7 @@ public class TestProcessBarRenderer implements IFadingProcessBarRenderer<IProces
@Override
public void renderProcessBar0(PoseStack poseStack, GuiGraphics guiGraphics) {
public void renderProcessBar0(Matrix3x2fStack poseStack, GuiGraphics guiGraphics) {
Minecraft mc = Minecraft.getInstance();
int screenWidth = mc.getWindow().getGuiScaledWidth();
int screenHeight = mc.getWindow().getGuiScaledHeight();

View File

@ -0,0 +1,25 @@
package com.r3944realms.leashedplayer.content.blocks;
import com.r3944realms.leashedplayer.LeashedPlayer;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.neoforged.neoforge.registries.DeferredHolder;
public enum ModBlockResourceKeys {
TEST_BLOCK(ModBlocksRegister.TEST_BLOCK)
;
private final ResourceKey<Block> resourceKey;
ModBlockResourceKeys(String name) {
resourceKey = ResourceKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, name));
}
ModBlockResourceKeys(DeferredHolder<Block, ? extends Block> block) {
resourceKey = ResourceKey.create(Registries.BLOCK, block.getId());
}
public ResourceKey<Block> getResourceKey() {
return resourceKey;
}
}

View File

@ -0,0 +1,36 @@
package com.r3944realms.leashedplayer.content.blocks;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.blocks.type.ItemMemoryBlock;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.function.Supplier;
public class ModBlocksRegister {
public static DeferredRegister<Block> BLOCKS = DeferredRegister.createBlocks(LeashedPlayer.MOD_ID);
public static DeferredHolder<Block, Block> TEST_BLOCK = register("test_block",
() -> new ItemMemoryBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.GLASS)
.setId(ModBlockResourceKeys.TEST_BLOCK.getResourceKey()))
);
public static <T extends Block> DeferredHolder<Item, BlockItem> registerBlockItem(String name , DeferredHolder<T, ? extends T> block, ResourceKey<Item> itemResourceKey){
return ModItemRegister.registerBlockItem(
name,
() -> new BlockItem(block.get(),new Item.Properties().setId(itemResourceKey))
);
}
private static DeferredHolder<Block, Block> register(String name, Supplier<Block> blockSupplier) {
return BLOCKS.register(name, blockSupplier);
}
public static void register(IEventBus eventBus) {
BLOCKS.register(eventBus);
}
}

View File

@ -0,0 +1,42 @@
package com.r3944realms.leashedplayer.content.blocks.entity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jetbrains.annotations.NotNull;
public class ItemMemoryBlockEntity extends BlockEntity {
private ItemStack memorizedItem = ItemStack.EMPTY;
public ItemMemoryBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntityRegister.ITEM_MEMORY_BLOCK.get(), pos, blockState);
}
// 记忆物品
public void setMemorizedItem(ItemStack memorizedItem) {
this.memorizedItem = memorizedItem.copy();
this.memorizedItem.setCount(1);
setChanged();
}
// 获取记忆的物品
public ItemStack getMemorizedItem() {
return memorizedItem.copy();
}
//--- 数据持久化必须实现---//
@Override
protected void saveAdditional(@NotNull ValueOutput valueOutput) {
super.saveAdditional(valueOutput);
if (!memorizedItem.isEmpty()) {
valueOutput.store("memorizedItem", ItemStack.CODEC, memorizedItem);
}
}
@Override
protected void loadAdditional(@NotNull ValueInput valueInput) {
super.loadAdditional(valueInput);
memorizedItem = valueInput.read("memorizedItem", ItemStack.CODEC).orElse(ItemStack.EMPTY);
}
}

View File

@ -0,0 +1,26 @@
package com.r3944realms.leashedplayer.content.blocks.entity;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.Set;
public class ModBlockEntityRegister {
public static DeferredRegister<BlockEntityType<?>> BLOCK_ENTITY = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, LeashedPlayer.MOD_ID);
public static DeferredHolder<BlockEntityType<?>, BlockEntityType<ItemMemoryBlockEntity>> ITEM_MEMORY_BLOCK =
BLOCK_ENTITY.register(
"item_memory_block_entity",
() -> new BlockEntityType<>(
ItemMemoryBlockEntity::new,
Set.of(ModBlocksRegister.TEST_BLOCK.get())
)
);
public static void register(IEventBus eventBus) {
BLOCK_ENTITY.register(eventBus);
}
}

View File

@ -0,0 +1,22 @@
package com.r3944realms.leashedplayer.content.blocks.type;
import com.r3944realms.leashedplayer.content.blocks.entity.ItemMemoryBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ItemMemoryBlock extends Block implements EntityBlock {
public ItemMemoryBlock(Properties properties) {
super(properties);
}
@Nullable
@Override
public BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) {
return new ItemMemoryBlockEntity(pos, state);
}
}

View File

@ -0,0 +1,22 @@
package com.r3944realms.leashedplayer.content.capabilities;
import com.r3944realms.leashedplayer.LeashedPlayer;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.capabilities.BlockCapability;
import net.neoforged.neoforge.capabilities.EntityCapability;
import net.neoforged.neoforge.capabilities.ItemCapability;
import net.neoforged.neoforge.items.IItemHandler;
public class ModCapabilities {
public static final BlockCapability<IItemHandler, Void> ITEM_MEMORY_COPY_BLOCK_CAP =
BlockCapability.createVoid(
ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "item_memory_copy_block_cap"),
IItemHandler.class
);
// public static final EntityCapability<IItemHandler, Void> ENTITY_LEASH_LENGTH_CAP =
// EntityCapability.createVoid(
// ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "entity_leash_length_cap"),
// IItemHandler.class
// );
}

View File

@ -6,10 +6,11 @@ import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
import com.r3944realms.leashedplayer.content.gamerules.Server.CreateLeashFenceKnotEntityIfAbsent;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
@ -63,7 +64,7 @@ public class LeashCommand {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = source.getPlayerOrException();
float leashLength = ((ILivingEntityExtension)player).getLeashLength();
float leashLength = ((IEntityLeadExtension)player).getLeashLength();
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
@ -75,7 +76,7 @@ public class LeashCommand {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
float leashLength = ((ILivingEntityExtension)player).getLeashLength();
float leashLength = ((IEntityLeadExtension)player).getLeashLength();
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
@ -88,7 +89,7 @@ public class LeashCommand {
try {
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
playerCol.forEach(player -> {
float leashLength = ((ILivingEntityExtension) player).getLeashLength();
float leashLength = ((IEntityLeadExtension) player).getLeashLength();
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
});
} catch (Exception e) {
@ -97,12 +98,28 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> getRefEntitiesLeashLength = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
float leashLength = ((IEntityLeadExtension) entity).getLeashLength();
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, entity.getDisplayName(), leashLength), true);
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
Command<CommandSourceStack> setSelfLengthLeashLength = context -> {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = source.getPlayerOrException();
float leashLength = context.getArgument("leashLength", Float.class);
((ILivingEntityExtension)player).setLeashLength(leashLength);
IEntityLeadExtension player1 = (IEntityLeadExtension) player;
player1.setLeashLength(leashLength);
player1.setLeadLengthSync(false);
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
@ -115,7 +132,9 @@ public class LeashCommand {
try {
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
float leashLength = context.getArgument("leashLength", Float.class);
((ILivingEntityExtension)player).setLeashLength(leashLength);
IEntityLeadExtension player1 = (IEntityLeadExtension) player;
player1.setLeashLength(leashLength);
player1.setLeadLengthSync(false);
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
@ -130,7 +149,9 @@ public class LeashCommand {
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
playerCol.forEach(player -> {
try {
((ILivingEntityExtension)player).setLeashLength(leashLength);
IEntityLeadExtension player1 = (IEntityLeadExtension) player;
player1.setLeashLength(leashLength);
player1.setLeadLengthSync(false);
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
} catch (Exception e) {
throw new RuntimeException(e);
@ -143,6 +164,28 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setRefEntitiesLengthLeashLength = context -> {
CommandSourceStack source = context.getSource();
float leashLength = context.getArgument("leashLength", Float.class);
try {
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
try {
IEntityLeadExtension iEntityLeadExtension = (IEntityLeadExtension) entity;
iEntityLeadExtension.setLeashLength(leashLength);
iEntityLeadExtension.setLeadLengthSync(false);
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, entity.getDisplayName(), leashLength), true);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
//获取Data 构造一个MutableComponent显示数据
Command<CommandSourceStack> geSelfLeashData = context -> {
CommandSourceStack source = context.getSource();
@ -187,6 +230,24 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> getRefEntitiesLeashData = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
try {
LeashLengthGetResultInt(entity, source);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
//设置前要判断其实体距离同一维度且距离不得大于其绳长的1.2倍待定也许可以设置在配置文件里
Command<CommandSourceStack> setSelfLeashDataEntity = context -> {
CommandSourceStack source = context.getSource();
@ -201,21 +262,8 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setSelfLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = source.getPlayerOrException();
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
if (x != null) return x;
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
Command<CommandSourceStack> setRefPlayerLeashDataEntity = context -> {
CommandSourceStack source = context.getSource();
try {
@ -246,6 +294,50 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setRefEntitiesLeashDataEntity = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
try {
LeashDataEntitySetResultInt(context, entity, source);
} catch (CommandSyntaxException e) {
throw new RuntimeException(e);
}
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
Command<CommandSourceStack> setSelfLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = source.getPlayerOrException();
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
if (x != null) return x;
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
Command<CommandSourceStack> setRefPlayerLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
if (x != null) return x;
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
Command<CommandSourceStack> setRefPlayersLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
@ -260,12 +352,13 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setRefPlayerLeashDataByBlockPos = context -> {
Command<CommandSourceStack> setRefEntitiesLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
if (x != null) return x;
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
LeashDataBlockPosSetResultInt(context, source, entity);
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
@ -317,6 +410,24 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> clearRefEntitiesLeashData = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<? extends Entity> entities = EntityArgument.getEntities(context, "targetEntities");
entities.stream().filter(i->i instanceof Leashable).forEach(entity -> {
try {
LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(entity, source.getLevel()),entity);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception e) {
source.sendFailure(Component.translatable(LEASH_FAILED));
return -1;
}
return 0;
};
LiteralArgumentBuilder<CommandSourceStack> SelfLeashLength = $$leashRoot.then(Commands.literal("length").executes(getSelfLeashLength)
@ -326,7 +437,7 @@ public class LeashCommand {
)
);
LiteralArgumentBuilder<CommandSourceStack> RefPlayerLeashLength = $$leashRoot.then(
LiteralArgumentBuilder<CommandSourceStack> RefEntitiesLeashLength = $$leashRoot.then(
Commands.literal("length")
.then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashLength)
.then(Commands.literal("get").executes(getRefPlayerLeashLength))
@ -344,9 +455,18 @@ public class LeashCommand {
)
)
)
.then(Commands.argument("targetEntities", EntityArgument.entities()).executes(getRefEntitiesLeashLength)
.then(Commands.literal("get").executes(getRefEntitiesLeashLength))
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
.then(
Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefEntitiesLengthLeashLength)
)
)
)
);
LiteralArgumentBuilder<CommandSourceStack> RefPLayerData = $$leashRoot.then(
LiteralArgumentBuilder<CommandSourceStack> RefEntitiesData = $$leashRoot.then(
Commands.literal("data")
.then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashData)
.then(Commands.literal("get")
@ -375,7 +495,22 @@ public class LeashCommand {
)
)
.then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayersLeashData))
));
)
.then(Commands.argument("targetEntities", EntityArgument.entities()).executes(getRefEntitiesLeashData)
.then(Commands.literal("get")
.executes(getRefEntitiesLeashData)
)
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
.then(Commands.argument("holderEntity", EntityArgument.entity())
.executes(setRefEntitiesLeashDataEntity)
)
.then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
.executes(setRefEntitiesLeashDataByBlockPos)
)
)
.then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefEntitiesLeashData))
)
);
LiteralArgumentBuilder<CommandSourceStack> SelfData = $$leashRoot.then(
Commands.literal("data")
@ -397,9 +532,9 @@ public class LeashCommand {
if(shouldUsePrefix) {
literalArgumentBuilder
.then(RefPlayerLeashLength)
.then(RefEntitiesLeashLength)
.then(SelfLeashLength)
.then(RefPLayerData)
.then(RefEntitiesData)
.then(SelfData);
dispatcher.register(literalArgumentBuilder);
} else {
@ -408,24 +543,26 @@ public class LeashCommand {
}
private static @Nullable Integer LeashLengthGetResultInt(ServerPlayer player, CommandSourceStack source) throws Exception {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) player).getLeashDataFromEntityData();
private static @Nullable Integer LeashLengthGetResultInt(Entity entity, CommandSourceStack source) throws Exception {
Leashable.LeashData leashDataFromEntityData;
if(entity instanceof Leashable leashable)
leashDataFromEntityData = leashable.getLeashData();
else return null;
if(leashDataFromEntityData == null) {
source.sendSuccess(() -> Component.translatable(NO_LEASH_DATA, player.getDisplayName()), true);
source.sendSuccess(() -> Component.translatable(NO_LEASH_DATA, entity.getDisplayName()), true);
return 1;
} else {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntityOrThrown(leashDataFromEntityData, source.getLevel());
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SHOW, player.getDisplayName(), leashDataEntity.getDisplayName()), true);
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SHOW, entity.getDisplayName(), leashDataEntity.getDisplayName()), true);
}
return null;
}
private static @Nullable Integer LeashDataBlockPosSetResultInt(CommandContext<CommandSourceStack> context, CommandSourceStack source, ServerPlayer player) {
private static @Nullable Integer LeashDataBlockPosSetResultInt(CommandContext<CommandSourceStack> context, CommandSourceStack source, Entity entity) {
BlockPos blockPos = BlockPosArgument.getBlockPos(context, "BlockPos");
Entity leashDataEntity = PlayerLeashable.getLeashFenceKnotEntity(source.getLevel(), blockPos);
PlayerLeashable leashedPlayer = (PlayerLeashable) player;
Component targetPlayerDisplayName = player.getDisplayName();
Leashable leashedPlayer = (Leashable) entity;
Component targetPlayerDisplayName = entity.getDisplayName();
if(leashDataEntity == null) {
ServerLevel level = context.getSource().getLevel();
if(GameruleRegistry.getGameruleBoolValue(level,CreateLeashFenceKnotEntityIfAbsent.ID)) {
@ -441,43 +578,43 @@ public class LeashCommand {
}
Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();
return LeashDataCommonPartSetResultInt(source, player, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
return LeashDataCommonPartSetResultInt(source, entity, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
}
private static @Nullable Integer LeashDataEntitySetResultInt(CommandContext<CommandSourceStack> context, ServerPlayer player, CommandSourceStack source) throws CommandSyntaxException {
private static @Nullable Integer LeashDataEntitySetResultInt(CommandContext<CommandSourceStack> context, Entity entity, CommandSourceStack source) throws CommandSyntaxException {
Entity leashDataEntity = EntityArgument.getEntity(context, "holderEntity");
PlayerLeashable leashedPlayer = (PlayerLeashable) player;
Component targetPlayerDisplayName = player.getDisplayName();
Leashable leashable = (Leashable) entity;
Component targetPlayerDisplayName = entity.getDisplayName();
Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();
if(player.equals(leashDataEntity)) {
if(entity.equals(leashDataEntity)) {
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY));
return 1;
}
return LeashDataCommonPartSetResultInt(source, player, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
return LeashDataCommonPartSetResultInt(source, entity, leashDataEntity, leashable, targetPlayerDisplayName, leashDataEntityDisplayName);
}
private static @Nullable Integer LeashDataCommonPartSetResultInt(CommandSourceStack source, ServerPlayer player, Entity leashDataEntity, PlayerLeashable leashedPlayer, Component targetPlayerDisplayName, Component leashDataEntityDisplayName) {
if(player.level() != leashDataEntity.level()) {
private static @Nullable Integer LeashDataCommonPartSetResultInt(CommandSourceStack source, Entity entity, Entity leashDataEntity, Leashable leashable, Component targetPlayerDisplayName, Component leashDataEntityDisplayName) {
if(entity.level() != leashDataEntity.level()) {
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_DIFF_LEVEL, targetPlayerDisplayName, leashDataEntityDisplayName));
return 2;
}
ILivingEntityExtension targetPlayerExtension = (ILivingEntityExtension) player;
if (player.distanceTo(leashDataEntity) > targetPlayerExtension.getLeashLength() * 1.2f) {
IEntityLeadExtension targetPlayerExtension = (IEntityLeadExtension) entity;
if (entity.distanceTo(leashDataEntity) > targetPlayerExtension.getLeashLength() * LeashedPlayer.M1()) {
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_TOO_FAR, targetPlayerDisplayName, leashDataEntityDisplayName, targetPlayerExtension.getLeashLength()));
return 3;
}
leashedPlayer.setLeashedTo(leashDataEntity, true);
leashable.setLeashedTo(leashDataEntity, true);
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashDataEntityDisplayName), true);
return null;
}
private static @Nullable Integer LeashDataClearResultInt(CommandSourceStack source, Entity leashDataEntity, ServerPlayer serverPlayer) {
private static @Nullable Integer LeashDataClearResultInt(CommandSourceStack source, Entity leashDataEntity, Entity entity) {
if(leashDataEntity == null) {
source.sendFailure(Component.translatable(LEASH_DATA_CLEAR_FAILED_NO_DATA, serverPlayer.getDisplayName()));
source.sendFailure(Component.translatable(LEASH_DATA_CLEAR_FAILED_NO_DATA, entity.getDisplayName()));
return 1;
}
Leashable.dropLeash((Entity & Leashable) serverPlayer, true, false);
source.sendSuccess(() -> Component.translatable(LEASH_DATA_CLEAR, serverPlayer.getDisplayName(), leashDataEntity.getDisplayName()), true);
Leashable.dropLeash((Entity & Leashable) entity, true, false);
source.sendSuccess(() -> Component.translatable(LEASH_DATA_CLEAR, entity.getDisplayName(), leashDataEntity.getDisplayName()), true);
return null;
}

View File

@ -40,7 +40,7 @@ public class LeashPlayerTrigger extends SimpleCriterionTrigger<LeashPlayerTrigge
public boolean matches(ServerPlayer player, Entity holder) {
PlayerLeashable ppl = (PlayerLeashable) player;
return ppl.isLeashed() && holder.equals(PlayerLeashable.getLeashDataEntity(player, player.serverLevel())) && this.holder.isPresent() && this.holder.get().matches(player, holder);
return ppl.isLeashed() && holder.equals(PlayerLeashable.getLeashDataEntity(player, player.level())) && this.holder.isPresent() && this.holder.get().matches(player, holder);
}
}

View File

@ -5,7 +5,7 @@ import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
import com.r3944realms.leashedplayer.content.gamerules.Server.KeepLeashNotDropTime;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ColorParticleOption;
@ -86,7 +86,7 @@ public class LeashRopeArrow extends AbstractArrow {
if(serverPlayer != null && !level().isClientSide) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(serverPlayer, (ServerLevel) level());
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
leashRopeArrow.setOwner(null);//将先前的箭矢置空
leashRopeArrow.setOwner((Entity) null);//将先前的箭矢置空
}
((PlayerLeashable)serverPlayer).setLeashedTo(this, true);
}
@ -98,7 +98,7 @@ public class LeashRopeArrow extends AbstractArrow {
if (pOwner instanceof PlayerLeashable lPlayer && !level().isClientSide) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) lPlayer, (ServerLevel) level());
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
leashRopeArrow.setOwner(null);
leashRopeArrow.setOwner((Entity) null);
}
lPlayer.setLeashedTo(this, true);
}
@ -112,8 +112,7 @@ public class LeashRopeArrow extends AbstractArrow {
@Override
public void setOwner(@Nullable Entity pEntity) {
boolean isNull = pEntity == null;
this.ownerUUID = isNull ? null : pEntity.getUUID();
this.cachedOwner = isNull ? null : pEntity;
this.owner = null;
this.pickup = this.pickup == Pickup.CREATIVE_ONLY ? this.pickup : Pickup.DISALLOWED;
}
@ -142,11 +141,11 @@ public class LeashRopeArrow extends AbstractArrow {
if(this.getOwner() != null) {//未有Owner始终可检
if(life <= 240) {
if(pPlayer.isShiftKeyDown()) {
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()) : this.getOwner();
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity(this.getOwner(), (ServerLevel) level()) : this.getOwner();
if(this.ownedBy(pPlayer)) {
this.pickup = Pickup.ALLOWED;
if(this.equals(leashDataEntity)) {
pPlayer.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_BREAK, 1, 1);
Leashable.dropLeash((Entity & Leashable)playerLeashable, true, false);
}
} else {
@ -156,10 +155,10 @@ public class LeashRopeArrow extends AbstractArrow {
// if(this.equals(leashDataEntity)) {
if(owner instanceof PlayerLeashable player) {
player.setLeashedTo(pPlayer, true);
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_TIED, 1, 1);
} else if(owner instanceof Leashable leashable) {
leashable.setLeashedTo(pPlayer, true);
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_TIED, 1, 1);
}
ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), getOrginalItemStack());
level().addFreshEntity(itemEntity);
@ -174,21 +173,21 @@ public class LeashRopeArrow extends AbstractArrow {
}
} else {
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()) : this.getOwner();
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity(this.getOwner(), (ServerLevel) level()) : this.getOwner();
if(this.ownedBy(pPlayer)) {
this.pickup = Pickup.ALLOWED;
if(this.equals(leashDataEntity)) {
pPlayer.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_BREAK, 1, 1);
Leashable.dropLeash((Entity & Leashable) playerLeashable,true, false);
}
} else {
Entity owner = getOwner();
if(owner instanceof PlayerLeashable player) {
player.setLeashedTo(pPlayer, true);
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_TIED, 1, 1);
} else if(owner instanceof Leashable leashable) {
leashable.setLeashedTo(pPlayer, true);
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
pPlayer.playSound(SoundEvents.LEAD_TIED, 1, 1);
}
ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), getOrginalItemStack());
level().addFreshEntity(itemEntity);
@ -288,7 +287,7 @@ public class LeashRopeArrow extends AbstractArrow {
if(!level().isClientSide) {
if (getOwner() instanceof PlayerLeashable pL) {
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(getOwner(), (ServerLevel) level());
if(leashDataEntity != null) {
Leashable.dropLeash((Entity & Leashable) pL, true, !(leashDataEntity instanceof LeashRopeArrow));
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
@ -296,10 +295,10 @@ public class LeashRopeArrow extends AbstractArrow {
}
}
Entity leashKnotFence = PlayerLeashable.createLeashKnotFence((ServerLevel) this.level(), pResult.getBlockPos());
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
IEntityLeadExtension pLL = (IEntityLeadExtension) pL;
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
pL.setLeashedTo(leashKnotFence, true);
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
leashKnotFence.playSound(SoundEvents.LEAD_TIED, 1, 1);
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
this.level().addFreshEntity(arrow);
discard();
@ -308,15 +307,15 @@ public class LeashRopeArrow extends AbstractArrow {
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
Entity leashDataEntity = this.getOwner();
if(leashDataEntity != null) {
leashDataEntity.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
leashDataEntity.playSound(SoundEvents.LEAD_BREAK, 1, 1);
Leashable.dropLeash((Entity & Leashable) L,true, false);
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
leashRopeArrow.setOwner(null);
leashRopeArrow.setOwner((Entity) null);
}
}
Entity leashKnotFence = LeashFenceKnotEntity.getOrCreateKnot(this.level(), pResult.getBlockPos());
L.setLeashedTo(leashKnotFence, true);
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
leashKnotFence.playSound(SoundEvents.LEAD_TIED, 1, 1);
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
this.level().addFreshEntity(arrow);
discard();
@ -342,19 +341,19 @@ public class LeashRopeArrow extends AbstractArrow {
if(livingEntity.equals(this.getOwner())) return;
if(this.getOwner() == null && livingEntity instanceof PlayerLeashable pL) { //发射器发出或命令生成
setOwner(livingEntity);
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(getOwner(), (ServerLevel) level());
if(leashDataEntity != null) {
Leashable.dropLeash((Entity & Leashable) pL,true, !(leashDataEntity instanceof LeashRopeArrow));
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
leashRopeArrow.dropLeashHandler();
}
}
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
IEntityLeadExtension pLL = (IEntityLeadExtension) pL;
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
livingEntity.playSound(SoundEvents.LEAD_TIED, 1, 1);
pL.setLeashedTo(this, true);
} else if (this.getOwner() instanceof PlayerLeashable pL) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(getOwner(), (ServerLevel) level());
if(leashDataEntity != null) {
Leashable.dropLeash((Entity & Leashable) pL, true, !(leashDataEntity instanceof LeashRopeArrow));
if (leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
@ -362,9 +361,9 @@ public class LeashRopeArrow extends AbstractArrow {
}
}
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
IEntityLeadExtension pLL = (IEntityLeadExtension) pL;
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
livingEntity.playSound(SoundEvents.LEAD_TIED, 1, 1);
pL.setLeashedTo(pResult.getEntity(), true);
this.level().addFreshEntity(arrow);
discard();
@ -378,7 +377,7 @@ public class LeashRopeArrow extends AbstractArrow {
leashRopeArrow.dropLeashHandler();
}
}
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
livingEntity.playSound(SoundEvents.LEAD_TIED, 1, 1);
leashable.setLeashedTo(this, true);
this.setOwner(entity);
return;
@ -386,7 +385,7 @@ public class LeashRopeArrow extends AbstractArrow {
}
if (entity instanceof LivingEntity living) {
if (this.getOwner() != null && this.getOwner()instanceof Leashable leashable) {
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
livingEntity.playSound(SoundEvents.LEAD_TIED, 1, 1);
leashable.setLeashedTo(living, true);
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
this.level().addFreshEntity(arrow);
@ -400,7 +399,7 @@ public class LeashRopeArrow extends AbstractArrow {
}
else if (entity instanceof LeashFenceKnotEntity leashKnotFence) {
if (getOwner() instanceof PlayerLeashable pL) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(getOwner(), (ServerLevel) level());
if (leashDataEntity != null) {
Leashable.dropLeash((Entity & Leashable) pL,true, true);
if (leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
@ -408,9 +407,9 @@ public class LeashRopeArrow extends AbstractArrow {
}
}
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
IEntityLeadExtension pLL = (IEntityLeadExtension) pL;
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
leashKnotFence.playSound(SoundEvents.LEAD_TIED, 1, 1);
pL.setLeashedTo(leashKnotFence, true);
this.level().addFreshEntity(arrow);
discard();
@ -451,7 +450,7 @@ public class LeashRopeArrow extends AbstractArrow {
}
}
public void dropLeashHandler() {
this.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
this.setOwner(null);
this.playSound(SoundEvents.LEAD_TIED, 1, 1);
this.setOwner((Entity) null);
}
}

View File

@ -2,7 +2,6 @@ package com.r3944realms.leashedplayer.content.entities;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
@ -13,6 +12,8 @@ import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -48,17 +49,16 @@ public class SpectralLeashRopeArrow extends LeashRopeArrow {
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
@Override
public void readAdditionalSaveData(@NotNull CompoundTag pCompound) {
super.readAdditionalSaveData(pCompound);
if (pCompound.contains("Duration")) {
this.duration = pCompound.getInt("Duration").orElse(200);
}
public void readAdditionalSaveData(@NotNull ValueInput valueInput) {
super.readAdditionalSaveData(valueInput);
this.duration = valueInput.getInt("Duration").orElse(200);
}
@Override
public void addAdditionalSaveData(@NotNull CompoundTag pCompound) {
super.addAdditionalSaveData(pCompound);
pCompound.putInt("Duration", this.duration);
public void addAdditionalSaveData(@NotNull ValueOutput valueOutput) {
super.addAdditionalSaveData(valueOutput);
valueOutput.putInt("Duration", this.duration);
}
@Override

View File

@ -11,7 +11,6 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionContents;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.common.CommonHooks;
import net.neoforged.neoforge.registries.DeferredRegister;
import org.jetbrains.annotations.NotNull;

View File

@ -1,15 +1,16 @@
package com.r3944realms.leashedplayer.content.items;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import com.r3944realms.leashedplayer.content.items.type.*;
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModJukeboxSongs;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.JukeboxSong;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.ShearsItem;
import net.minecraft.world.item.alchemy.PotionContents;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
@ -44,11 +45,14 @@ public class ModItemRegister {
public static final DeferredHolder<Item, Item> NEOFORGE = ModItemRegister.register("neoforge",
() -> new Item(DistProperties(ModJukeboxSongs.FOX_MUSIC)
.setId(ModItemResourceKeys.NEOFORGE.getResourceKey())));
public static final DeferredHolder<Item, BlockItem> TEST_BLOCK_ITEM =
ModBlocksRegister.registerBlockItem("test_block_item", ModBlocksRegister.TEST_BLOCK, ModItemResourceKeys.TEST_BLOCK_ITEM.getResourceKey());
public static Item.Properties DistProperties(ResourceKey<JukeboxSong> song) {
return new Item.Properties().stacksTo(1).rarity(Rarity.RARE).jukeboxPlayable(song);
}
public static DeferredHolder<Item, BlockItem> registerBlockItem(String name, Supplier<? extends BlockItem> sup) {
return ITEMS.register(name, sup);
}
public static DeferredHolder<Item, Item> register(String name, Supplier<Item> supplier) {
return register(name, supplier, true);
}

View File

@ -13,13 +13,14 @@ public enum ModItemResourceKeys {
TIPPED_LEASH_ROPE_ARROW (ModItemRegister.TIPPED_LEASH_ROPE_ARROW),
AMETHYST_SHEARS(ModItemRegister.AMETHYST_SHEARS),
FABRIC(ModItemRegister.FABRIC),
NEOFORGE(ModItemRegister.NEOFORGE)
NEOFORGE(ModItemRegister.NEOFORGE),
TEST_BLOCK_ITEM("test_block_item"),
;
private final ResourceKey<Item> resourceKey;
ModItemResourceKeys(String name) {
resourceKey = ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, name));
}
ModItemResourceKeys(DeferredHolder<Item, Item> item) {
ModItemResourceKeys(DeferredHolder<Item, ? extends Item> item) {
resourceKey = ResourceKey.create(Registries.ITEM, item.getId());
}

View File

@ -114,7 +114,7 @@ public class LeadBreakerItem extends ShearsItem {
}
if(pLevel.isClientSide) {
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
if (playerLeashable.getLeashDataFromEntityData() != null) {
if (playerLeashable.getLeashData() != null) {
pPlayer.playSound(SoundEvents.SHEEP_SHEAR, 1.0F, 1.0F);
return InteractionResult.SUCCESS;
}

View File

@ -2,7 +2,6 @@ package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.network.chat.Component;
@ -17,7 +16,6 @@ import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
public class LeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{

View File

@ -3,7 +3,6 @@ package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.network.chat.Component;
@ -18,7 +17,6 @@ import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
public class SpectralLeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{

View File

@ -11,7 +11,6 @@ import net.minecraft.world.item.alchemy.Potions;
import net.minecraft.world.item.component.TooltipDisplay;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

View File

@ -28,7 +28,7 @@ public class LeadBreakItemBehavior extends OptionalDispenseItemBehavior {
ServerLevel serverLevel = blockSource.level();
if(!serverLevel.isClientSide()) {
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
this.setSuccess(tryShearBeehive(serverLevel, blockPos) || tryShearLivingEntity(serverLevel, blockPos, item));
this.setSuccess(tryShearBeehive(serverLevel, blockPos) || tryShearLivingEntity(serverLevel, blockPos));
if (this.isSuccess()) {
item.hurtAndBreak(1, serverLevel, null, p_348118_ -> {
});
@ -53,7 +53,7 @@ public class LeadBreakItemBehavior extends OptionalDispenseItemBehavior {
return false;
}
private static boolean tryShearLivingEntity(ServerLevel level, BlockPos pos, ItemStack item) {
private static boolean tryShearLivingEntity(ServerLevel level, BlockPos pos) {
for (LivingEntity livingentity : level.getEntitiesOfClass(LivingEntity.class, new AABB(pos), EntitySelector.NO_SPECTATORS)) {
if (livingentity instanceof PlayerLeashable playerLeashable) {
if (playerLeashable.isLeashed()){

View File

@ -1,6 +1,7 @@
package com.r3944realms.leashedplayer.datagen.LanguageAndOtherData;
import com.r3944realms.leashedplayer.content.ModKeyMapping;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.commands.MotionCommand;
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
@ -43,6 +44,8 @@ public enum ModLangKeyValue {
AMETHYST_SHEARS(ModItemRegister.AMETHYST_SHEARS, ModPartEnum.ITEM, "Amethyst Shears", "紫水晶剪刀", "紫水晶剪刀", true),
NEO_FORGE(ModItemRegister.NEOFORGE, ModPartEnum.ITEM, "NeoForge", "NeoForge", "NeoForge", false),
TIPPED_LEASH_ROPE_ARROW(TippedLeashRopeArrowItem.TIPPED_LEASH_ROPE_ARROW_NAME, ModPartEnum.ITEM, "Tipped Leash Rope Arrow Soaked By %1$s", "用%1$s浸泡过的拴绳箭", "蘸有%1$s的拴繩箭", false),
//BLOCK_ITEM
BLOCK_ITEM_TEST_BLOCK(ModItemRegister.TEST_BLOCK_ITEM, ModPartEnum.ITEM, "Test Block", "测试方块", "測試方塊", true),
//ITEM_DESC
DESC_ITEM_LEASH_R_ARROW_ONE(LeashRopeArrowItem.DESC_1, ModPartEnum.DESCRIPTION, "§7This arrow will carry the owner along with its flight:", "§7该箭将会携带拥有者随其飞行", "§7該箭將會攜帶擁有者隨其飛行", false),
DESC_ITEM_LEASH_R_ARROW_TWO(LeashRopeArrowItem.DESC_2, ModPartEnum.DESCRIPTION, "§c1.§r If it hits a fence or an entity, it will leash the owner to it and drop as a normal arrow.", "§c1.§r 若击中栅栏或生物时,将持有者拴在其上并已普通箭形式掉落;", "§c1.§r 若擊中柵欄或生物時,將持有者拴在其上並以普通箭的形式掉落;", false),
@ -55,7 +58,8 @@ public enum ModLangKeyValue {
DESC_ITEM_S_LEASH_R_ARROW_THREE(SpectralLeashRopeArrowItem.DESC, ModPartEnum.DESCRIPTION, "§c2.§r Strike the entity to give it a §e§lGlowing§r effect.", "§c2.§r 击中实体给与其§e§l发光§7(§e§lGlowing§7)§r效果", "擊中實體給予其§e§l發光§7(§e§lGlowing§7)§r效果", false),
DESC_ITEM_T_LEASH_R_ARROW_THREE(TippedLeashRopeArrowItem.DESC, ModPartEnum.DESCRIPTION, "§c2.§rStrike the entity to give it a Potion effect.", "§c2.§r 击中实体给与其药水效果", "擊中實體給予其药水效果", false),
DESC_ITEM_LEAD_BREAKER(LeadBreakerItem.HOVER_KEY, ModPartEnum.DESCRIPTION, "§7can break the link of leash", "§7可以破坏拴绳链接", "§7可以破壞拴繩鏈接", false),
//BLOCK
BLOCK_TEST_BLOCK(ModBlocksRegister.TEST_BLOCK, ModPartEnum.BLOCK, "Test Block", "测试方块", "測試方塊", false),
//PAINTING
GROUP_PHOTO_TITLE(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO),ModPartEnum.TITLE, "§dGroup Photo §7[§6memorable§7]§r", "§d集体照 §7[§6纪念§7]§r", "§d集體照 §7[§6紀念§7]§r", false),
GROUP_PHOTO_AUTHOR(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO),ModPartEnum.AUTHOR, "§9Leisure §4Time §eDock§r","§9闲趣§4时§e坞§r","§9閑趣§4時§e塢§r",false),

View File

@ -1,5 +1,6 @@
package com.r3944realms.leashedplayer.datagen.generator;
import com.r3944realms.leashedplayer.content.blocks.ModBlocksRegister;
import net.minecraft.client.data.models.BlockModelGenerators;
import net.minecraft.client.data.models.ItemModelOutput;
import net.minecraft.client.data.models.blockstates.BlockModelDefinitionGenerator;
@ -16,6 +17,6 @@ public class ModBlockModelGenerator extends BlockModelGenerators {
@Override
public void run() {
this.createTrivialCube(ModBlocksRegister.TEST_BLOCK.get());
}
}

View File

@ -5,11 +5,11 @@ import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModItemTags;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.ItemTagsProvider;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.neoforged.neoforge.common.Tags;
import net.neoforged.neoforge.common.data.ItemTagsProvider;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
@ -17,7 +17,7 @@ import java.util.concurrent.CompletableFuture;
public class ModItemTagProvider extends ItemTagsProvider {
public ModItemTagProvider(PackOutput pOutput, CompletableFuture<HolderLookup.Provider> pLookupProvider, CompletableFuture<TagLookup<Block>> pBlockTags) {
super(pOutput, pLookupProvider, pBlockTags, LeashedPlayer.MOD_ID);
super(pOutput, pLookupProvider,LeashedPlayer.MOD_ID);
}
@Override

View File

@ -1,20 +1,52 @@
package com.r3944realms.leashedplayer.mixin.both;
import com.mojang.serialization.Codec;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Optional;
@Mixin(Entity.class)
public abstract class MixinEntity {
@Shadow public abstract void igniteForSeconds(float pSeconds);
public abstract class MixinEntity implements IEntityLeadExtension {
@Unique int Pl$LeashKeepTick;//保存状态当超过断裂绳长时若LeashKeepTick大于0则不断裂
@Unique float Pl$LeashLength;
@Unique boolean Pl$isSync;
@Shadow public abstract Level level();
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public float getLeashLength() {
return Math.max(Pl$LeashLength, 6.0f);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public void setLeashLength(float length) {
this.Pl$LeashLength = length;
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public void setKeepLeashTick(int keepTick) {
this.Pl$LeashKeepTick = Math.max(keepTick, 0);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public int getKeepLeashTick() {
return this.Pl$LeashKeepTick;
}
/**
* 这里重定向当实体类实现了{@link PlayerLeashable}接口时<br/>
@ -30,8 +62,34 @@ public abstract class MixinEntity {
<E extends Entity & Leashable> void checkAndCancelIfTure(ServerLevel f, E entity) {
if(!(entity instanceof PlayerLeashable) && level() instanceof ServerLevel serverLevel_) {
Leashable.tickLeash(serverLevel_, entity);
} else {
PlayerLeashable.tickLeash(f, entity);
}
}
@Inject(
method = {"saveWithoutId"}, at = {@At("RETURN")}
)//数据保存
private void addSaveData(ValueOutput valueOutput, CallbackInfo ci) {
valueOutput.putFloat("LeashLength", ((IEntityLeadExtension)this).getLeashLength());
}
@Inject(
method = {"load"}, at = {@At("RETURN")}
)//数据读取
private void readSaveData(ValueInput valueInput, CallbackInfo ci) {
Optional<Float> leashLength = valueInput.read("LeashLength", Codec.FLOAT);
leashLength.ifPresent(i->((IEntityLeadExtension)this).setLeashLength(i));
if(!this.level().isClientSide) ((IEntityLeadExtension)this).setLeadLengthSync(false);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public boolean hasLeadLengthSync() {
return Pl$isSync;
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public void setLeadLengthSync(boolean sync) {
Pl$isSync = sync;
}
}

View File

@ -0,0 +1,29 @@
package com.r3944realms.leashedplayer.mixin.both;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import net.minecraft.world.entity.Leashable;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Leashable.class)
public interface MixinLeashable {
@WrapMethod(method = "leashSnapDistance")
default double leashSnapDistance(Operation<Double> original) {
if (this instanceof IEntityLeadExtension entityLeadExtension) {
int keepLeashTick = entityLeadExtension.getKeepLeashTick();
if (keepLeashTick != 0)
return Double.MAX_VALUE;
return entityLeadExtension.getLeashLength() * LeashedPlayer.M1();
}
return original.call();
}
@WrapMethod(method = "leashElasticDistance")
default double leashElasticDistance(Operation<Double> original) {
if (this instanceof IEntityLeadExtension entityLeadExtension) {
return entityLeadExtension.getLeashLength();
}
return original.call();
}
}

View File

@ -1,25 +1,13 @@
package com.r3944realms.leashedplayer.mixin.both;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import com.r3944realms.leashedplayer.utils.Logger;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@ -27,296 +15,41 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.function.Consumer;
@Mixin(Player.class)
public abstract class MixinPlayer extends LivingEntity implements PlayerLeashable, ILivingEntityExtension {
@Unique
protected int Pl$LeashKeepTick;//保存状态当超过断裂绳长时若LeashKeepTick大于0则不断裂
public abstract class MixinPlayer extends LivingEntity implements PlayerLeashable {
@Unique
@Nullable
private LeashData Pl$LeashData;//Data
@SuppressWarnings("WrongEntityDataParameterClass")
@Unique//客户端与服务器端的实体同步数据
private static final EntityDataAccessor<CompoundTag> Pl$LEASH_DATA = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
@Unique
@SuppressWarnings("WrongEntityDataParameterClass")
private static final EntityDataAccessor<Float> DATA_ENTITY_LEASH_LENGTH = SynchedEntityData.defineId(Player.class, EntityDataSerializers.FLOAT);
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public float getLeashLength() {
return this.entityData.get(DATA_ENTITY_LEASH_LENGTH);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public void setLeashLength(float length) {
this.entityData.set(DATA_ENTITY_LEASH_LENGTH, length);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public void setKeepLeashTick(int keepTick) {
this.Pl$LeashKeepTick = Math.max(keepTick, 0);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public int getKeepLeashTick() {
return this.Pl$LeashKeepTick;
}
private Leashable.LeashData Pl$LeashData;//Data
protected MixinPlayer(EntityType<? extends LivingEntity> pEntityType, Level pLevel) {
super(pEntityType, pLevel);
}
@Inject(method = {"tick"}, at = {@At("HEAD")})
private void tickForLeash(CallbackInfo ci) {
if(!this.level().isClientSide) {
Pl$tickLeash();//服务器端每tick任务
}
PlayerLeashable playerLeashable = this;
Entity leashHolder = playerLeashable.getLeashHolder();
if(leashHolder != null ) {
//存在则更新
Pl$UpdateLeash(leashHolder, (Entity) playerLeashable);
try {
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(1.25f);
} catch (Exception e) {
Logger.logger.error(e.getMessage());
}
} else {
try {
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(0.6f);
} catch (Exception e) {
Logger.logger.error(e.getMessage());
}
}
}
@Unique
private static void Pl$UpdateLeash(Entity holderEntity, Entity restrainedEntity) {
if (holderEntity == null || holderEntity.level() != restrainedEntity.level()) {
return;
}
float leashLength = LeashCommand.MIN_VALUE;
if (restrainedEntity instanceof ILivingEntityExtension iEntity) {
// 获取绳长
float leashLengthFormValue = iEntity.getLeashLength();
leashLength = leashLengthFormValue > LeashCommand.MIN_VALUE ? leashLengthFormValue : LeashCommand.MIN_VALUE;
}
// 两者距离
float distance = holderEntity.distanceTo(restrainedEntity);
Entity applyMovementEntity = restrainedEntity.isPassenger() ? restrainedEntity.getVehicle() : restrainedEntity;
// 仅当距离大于绳长时施加拉力
if (applyMovementEntity != null && distance > leashLength) {
// 计算朝向持有者的拉力方向
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
double dY = (holderEntity.getY() - applyMovementEntity.getY()) / (double) distance;
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
// 拉力大小距离越远拉力越强但施加一个最大限制
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
applyMovementEntity.setDeltaMovement(
applyMovementEntity.getDeltaMovement().add(
dX * pullStrength,
dY * pullStrength,
dZ * pullStrength
)
);
// 控制速度不要过快避免偏激移动
Whimsy$Brake(applyMovementEntity, entity -> {
Vec3 deltaMovement = entity.getDeltaMovement();
entity.setDeltaMovement(
Math.min(Math.abs(deltaMovement.x), 1.0) * Math.signum(deltaMovement.x),
Math.min(Math.abs(deltaMovement.y), 1.0) * Math.signum(deltaMovement.y),
Math.min(Math.abs(deltaMovement.z), 1.0) * Math.signum(deltaMovement.z)
);
entity.hurtMarked = true;
});
}
// 降低坠落伤害
restrainedEntity.checkSlowFallDistance();
}
/**
* 刹车
* @param pEntity 刹车的实体
* @param pMaxX X方向的最大动量
* @param pMaxY Y方向的最大动量
* @param pMaxZ Z方向的最大动量
*/
@Unique
private static void Whimsy$Brake(Entity pEntity, double pMaxX, double pMaxY, double pMaxZ) {
Vec3 deltaMovement = pEntity.getDeltaMovement();
double dX = Math.abs(deltaMovement.x) > pMaxX ? 0 : deltaMovement.x;
double dY = Math.abs(deltaMovement.y) > pMaxY ? 0 : deltaMovement.y;
double dZ = Math.abs(deltaMovement.z) > pMaxZ ? 0 : deltaMovement.z;
pEntity.setDeltaMovement(dX, dY,dZ);
pEntity.hurtMarked = true;
}
/**
* 刹车
* @param pEntity 刹车的实体
* @param pOpt 自定义规则
*/
@Unique
private static void Whimsy$Brake(Entity pEntity, @Nullable Consumer<Entity> pOpt) {
Consumer<Entity> consumer = pOpt;
if(pOpt == null) {
consumer = entity -> {
Vec3 deltaMovement = entity.getDeltaMovement();
double dX = Math.abs(deltaMovement.x) > 1 ? 0 : deltaMovement.x;
double dY = Math.abs(deltaMovement.y) > 1 ? 0 : deltaMovement.y;
double dZ = Math.abs(deltaMovement.z) > 1 ? 0 : deltaMovement.z;
entity.setDeltaMovement(dX, dY,dZ);
entity.hurtMarked = true;
};
}
consumer.accept(pEntity);
}
@Unique
protected void Pl$tickLeash() {
if(this.Pl$LeashData == null) return;//没有Data直接退出
ILivingEntityExtension self = this;
int keepLeashTick = self.getKeepLeashTick();
//info -> Holder整理
Pl$RestoreLeashFormSave();
//默认值设为
float leashLength = LeashCommand.MIN_VALUE;
Entity entity = this.Pl$LeashData.leashHolder;
//保存数据
saveLeashData(Pl$LeashData);
ILivingEntityExtension iEntityExtension = this;//获取设定值
float leashLengthSelf = iEntityExtension.getLeashLength();
leashLength = leashLengthSelf > LeashCommand.MIN_VALUE ? leashLengthSelf : LeashCommand.MIN_VALUE;
if (entity != null) {
double breakDistanceTime = (entity instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
if(!isAlive() || !entity.isAlive() ||( distanceTo(entity) > Math.max(leashLength * breakDistanceTime, LeashCommand.MIN_VALUE * breakDistanceTime) && keepLeashTick == 0)){
//玩家死亡 持有者不存在 距离大于设定值的 breakDistanceTime 倍且keepTick <=0长度的 breakDistanceTime 倍若低于 LeashCommand.MIN_VALUE 则选 LeashCommand.MIN_VALUE
// 则取消拴绳关系并掉落拴绳
boolean shouldDrop = !(entity instanceof LeashRopeArrow);
Leashable.dropLeash((Entity & Leashable) this, true, shouldDrop);
} else if(distanceTo(entity) > leashLength * 0.65f * breakDistanceTime && entity.onGround()) {
//大于eashLength * 0.65f * breakDistanceTime 倍绳长且在地面则会让其跳跃<1.25格阻拦情况下跳跃阻拦//TODO:待擴展
Entity applyMovementEntity = this.isPassenger() ? this.getVehicle() : this;
if(applyMovementEntity instanceof LivingEntity applyMovementLivingEntity) {
applyMovementLivingEntity.jumpFromGround();
}
}
}
if(keepLeashTick > 0) {//keepTick--
self.setKeepLeashTick(keepLeashTick - 1);
}
}
@Override
public Entity getLeashHolder() {
if (Pl$LeashData == null) return null;
if (Pl$LeashData.leashHolder == null && Pl$LeashData.delayedLeashHolderId != 0 ) {
Pl$LeashData.leashHolder = this.level().getEntity(Pl$LeashData.delayedLeashHolderId);
}
return Pl$LeashData.leashHolder;
}
/**
* 数据整理 -> 如果Pl$LeashData非null最终Pl$LeashData的leashHolder将不为null
*/
@Unique
private void Pl$RestoreLeashFormSave() {
assert this.Pl$LeashData != null;
if(!(this.level() instanceof ServerLevel)) {
//非服务器端退出
return;
}
if(this.Pl$LeashData.delayedLeashInfo == null) {
//delayedLeashInfo无数据
if(Pl$LeashData.leashHolder != null) {//且LeashHolder不为null则直接用它
setLeashedTo(Pl$LeashData.leashHolder, true);
return;
}
return;
}
if(this.Pl$LeashData.delayedLeashInfo.left().isPresent()) {
//如果有实体的UUID一般是LivingEntity则在服务器其通过UUID来查找实体
Entity entity = ((ServerLevel) this.level()).getEntity(this.Pl$LeashData.delayedLeashInfo.left().get());
if(entity != null) {
setLeashedTo(entity, true);
}
} else if(this.Pl$LeashData.delayedLeashInfo.right().isPresent()) {
//如果有实体的坐标一般就是拴绳结在服务器端获取拴绳结实体通过给定坐标和维度获取
setLeashedTo(LeashFenceKnotEntity.getOrCreateKnot(this.level(), this.Pl$LeashData.delayedLeashInfo.right().get()), true);
}
}
@org.jetbrains.annotations.Nullable
@Override
public LeashData getLeashData() {
return Pl$LeashData;
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
@Nullable
public LeashData getLeashDataFromEntityData() {
CompoundTag compoundTag = this.entityData.get(Pl$LEASH_DATA);
return compoundTag.read("Pl$LeashData", Leashable.LeashData.CODEC).orElse(null);
}
@Override
public void setLeashData(@org.jetbrains.annotations.Nullable Leashable.LeashData pLeashData) {
this.Pl$LeashData = pLeashData;
saveLeashData(pLeashData);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Unique
private void saveLeashData(@org.jetbrains.annotations.Nullable LeashData pLeashData) {
CompoundTag compoundTag = new CompoundTag();
this.writeLeashData(compoundTag, pLeashData);
this.entityData.set(Pl$LEASH_DATA, compoundTag);
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public boolean canBeLeashedInstantly(Player player) {
return !isLeashed();
}
@Inject(
method = {"defineSynchedData"}, at = {@At("TAIL")}
)
//定义Client/Server player 同步数据
private void defineSyncData (SynchedEntityData.Builder pBuilder, CallbackInfo ci) {
CompoundTag leashCompoundTag = new CompoundTag();
this.writeLeashData(leashCompoundTag, null);
pBuilder.define(Pl$LEASH_DATA, leashCompoundTag);
pBuilder.define(DATA_ENTITY_LEASH_LENGTH, 5.0F);
}
@Inject(
method = {"addAdditionalSaveData"}, at = {@At("RETURN")}
)//数据保存
private void addSaveData(CompoundTag pCompound, CallbackInfo ci) {
CompoundTag pLeashTag = new CompoundTag();
writeLeashData(pLeashTag, Pl$LeashData);
pCompound.put("Pl$LeashData", pLeashTag);
this.entityData.set(Pl$LEASH_DATA, pLeashTag);
pCompound.putFloat("LeashLength", getLeashLength());
private void addSaveData(ValueOutput valueOutput, CallbackInfo ci) {
writeLeashData(valueOutput, Pl$LeashData);
}
@Inject(
method = {"readAdditionalSaveData"}, at = {@At("RETURN")}
)//数据读取
private void readSaveData(CompoundTag pCompound, CallbackInfo ci) {
this.readLeashData(pCompound);
private void readSaveData(ValueInput valueInput, CallbackInfo ci) {
this.readLeashData(valueInput);
}
}

View File

@ -1,16 +1,17 @@
package com.r3944realms.leashedplayer.mixin.client;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.renderer.LeashRendererUtil;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderBuffers;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -33,7 +34,7 @@ public abstract class MixinLevelRenderer {
method = {"renderLevel"},
at = @At(value = "HEAD")
)
private void renderLevel(GraphicsResourceAllocator graphicsResourceAllocator, DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f frustumMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
private void renderLevel(GraphicsResourceAllocator graphicsResourceAllocator, DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, Matrix4f frustumMatrix, Matrix4f projectionMatrix, GpuBufferSlice gpuBufferSlice, Vector4f vector4f, boolean flag,CallbackInfo ci) {
assert this.level != null;
PoseStack poseStack = new PoseStack();
MultiBufferSource.BufferSource multibuffersource$buffersource = this.renderBuffers.bufferSource();

View File

@ -3,16 +3,17 @@ package com.r3944realms.leashedplayer.mixin.item;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.LeadItem;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -21,7 +22,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(LeadItem.class)
public class MixinLeadItem {
public abstract class MixinLeadItem extends Item {
public MixinLeadItem(Properties properties) {
super(properties);
}
/**
* 拴住自己的逻辑
*/
@ -30,7 +35,7 @@ public class MixinLeadItem {
at = @At("HEAD"),
cancellable = true)
private static void selfLeash(Player pPlayer, Level pLevel, BlockPos pPos, CallbackInfoReturnable<InteractionResult> cir) {
List<Leashable> list = LeadItem.leashableInArea(pLevel, pPos, p_353025_ -> p_353025_.getLeashHolder() == pPlayer);
List<Leashable> list = Leashable.leashableInArea(pLevel, Vec3.atCenterOf(pPos), p_353025_ -> p_353025_.getLeashHolder() == pPlayer);
if (list.isEmpty()) {
ItemStack mainHandItem = pPlayer.getMainHandItem();
if (!(mainHandItem.getItem() instanceof LeadItem )) {
@ -39,7 +44,7 @@ public class MixinLeadItem {
//非创造模式减少防止刷物品
if(!pPlayer.isCreative()) mainHandItem.shrink(1);
//自己
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) pPlayer, (ServerLevel) pLevel);
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(pPlayer, (ServerLevel) pLevel);
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
if(leashDataEntity != null) {
Leashable.dropLeash((Entity & Leashable) playerLeashable, true, true);

View File

@ -39,16 +39,16 @@ public class MixinServerGamePacketListenerImpl {
}
@Inject(method = {"teleport(Lnet/minecraft/world/entity/PositionMoveRotation;Ljava/util/Set;)V"}, at = {@At("TAIL")})
private void teleportTail(PositionMoveRotation moveRotation, Set<Relative> pRelativeSet, CallbackInfo ci) {
if(GameruleRegistry.getGameruleBoolValue(this.player.serverLevel(), TeleportWithLeashedPlayers.ID)) {
if(GameruleRegistry.getGameruleBoolValue(this.player.level(), TeleportWithLeashedPlayers.ID)) {
for (Entity Pl$LeashPlayer : this.Pl$LeashPlayers) {
if(Pl$LeashPlayer instanceof ServerPlayer) {
if(Pl$LeashPlayer instanceof PlayerLeashable playerLeashable) {
Leashable.dropLeash((Entity & Leashable) playerLeashable, false,false);
if(((ServerPlayer) playerLeashable).serverLevel() == this.player.serverLevel()) {
if(((ServerPlayer) playerLeashable).level() == this.player.level()) {
((ServerPlayer) playerLeashable).connection.teleport(moveRotation, pRelativeSet);
} else {
Vec3 vec3 = moveRotation.deltaMovement();
((ServerPlayer) playerLeashable).teleportTo(this.player.serverLevel(), vec3.x, vec3.y, vec3.z, pRelativeSet, moveRotation.yRot(), moveRotation.yRot(),false);
((ServerPlayer) playerLeashable).teleportTo(this.player.level(), vec3.x, vec3.y, vec3.z, pRelativeSet, moveRotation.yRot(), moveRotation.yRot(),false);
((ServerPlayer) playerLeashable).stopRiding();
}
playerLeashable.setLeashedTo(this.player, true);

View File

@ -1,6 +1,6 @@
package com.r3944realms.leashedplayer.modInterface;
public interface ILivingEntityExtension {
public interface IEntityLeadExtension {
/**
* 获取拴绳的长度
* @return length 拴绳的长度Float
@ -25,4 +25,16 @@ public interface ILivingEntityExtension {
* @return keepTick 等待tickint
*/
int getKeepLeashTick();
/**
* 是否需要同步
* @apiNote 该为服务器方法只能在服务器端调用切勿在客户端线程调用
* @return boolean
*/
boolean hasLeadLengthSync();
/**
* 设置是否需要同步
* @apiNote 该为服务器方法只能在服务器端调用切勿在客户端线程调用
*/
void setLeadLengthSync(boolean sync);
}

View File

@ -1,58 +1,179 @@
package com.r3944realms.leashedplayer.modInterface;
import com.mojang.serialization.Codec;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.criteriaTriggers.ModCriteriaTriggers;
import com.r3944realms.leashedplayer.utils.Util;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.network.client.UpdatePlayerMovement;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.network.PacketDistributor;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public interface PlayerLeashable extends Leashable {
/**
* 获取拴绳的持有者实体 可能不存在
*/
@Nullable
Entity getLeashHolder();
static <E extends Entity & Leashable> void tickLeash(ServerLevel level, E p_entity) {
Leashable.LeashData leashable$leashdata = p_entity.getLeashData();
if (leashable$leashdata != null && leashable$leashdata.delayedLeashInfo != null) {
restoreLeashFromSave(p_entity, leashable$leashdata);
}
/**
* 获取拴绳的持有者数据 从EntityData中获取
*/
LeashData getLeashDataFromEntityData();
if (leashable$leashdata != null && leashable$leashdata.leashHolder != null) {
if (!p_entity.isAlive() || !leashable$leashdata.leashHolder.isAlive()) {
if (level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
p_entity.dropLeash();
} else {
p_entity.removeLeash();
}
}
/**
* 是否立即可被拴住
*/
boolean canBeLeashedInstantly(Player player);
Entity entity = p_entity.getLeashHolder();
if (entity != null && entity.level() == p_entity.level()) {
double d0 = p_entity.leashDistanceTo(entity);
p_entity.whenLeashedTo(entity);
int keepLeashTick = 0;
if(entity instanceof IEntityLeadExtension leadExtension) {
keepLeashTick = leadExtension.getKeepLeashTick();
}
if (d0 > p_entity.leashSnapDistance() && keepLeashTick == 0) {
level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F);
p_entity.leashTooFarBehaviour();
} else if (d0 > p_entity.leashElasticDistance() - entity.getBbWidth() - p_entity.getBbWidth()
&& p_entity.checkElasticInteractions(entity, leashable$leashdata)) {
p_entity.onElasticLeashPull();
} else {
p_entity.closeRangeLeashBehaviour(entity);
}
p_entity.setYRot((float)(p_entity.getYRot() - leashable$leashdata.angularMomentum));
leashable$leashdata.angularMomentum = leashable$leashdata.angularMomentum * Leashable.angularFriction(p_entity);
}
}
}
@Override
default void writeLeashData(CompoundTag tag, @org.jetbrains.annotations.Nullable Leashable.LeashData leashData) {
tag.storeNullable("Pl$LeashData", Leashable.LeashData.CODEC, leashData);
default boolean checkElasticInteractions(Entity p_entity, Leashable.@NotNull LeashData p_418158_) {
boolean flag = p_entity.supportQuadLeashAsHolder() && this.supportQuadLeash();
List<Leashable.Wrench> list = computeElasticInteraction(
(Entity & Leashable)this,
p_entity,
flag ? SHARED_QUAD_ATTACHMENT_POINTS : ENTITY_ATTACHMENT_POINT,
flag ? SHARED_QUAD_ATTACHMENT_POINTS : LEASHER_ATTACHMENT_POINT
);
if (list.isEmpty()) {
return false;
} else {
Leashable.Wrench leashable$wrench = Leashable.Wrench.accumulate(list).scale(flag ? 0.25 : 1.0);
p_418158_.angularMomentum = p_418158_.angularMomentum + 10.0 * leashable$wrench.torque();
Entity applyMovementEntity = ((Entity & Leashable)this).isPassenger() ? ((Entity & Leashable)this).getVehicle() : ((Entity & Leashable)this);
Vec3 vec3 = Leashable.getHolderMovement(((Entity & Leashable)this)).subtract(((Entity)this).getKnownMovement());
if (applyMovementEntity != null) {
Vec3 add = leashable$wrench.force().multiply(AXIS_SPECIFIC_ELASTICITY).add(vec3.scale(0.11));
if (applyMovementEntity instanceof ServerPlayer player) {
PacketDistributor.sendToPlayer(player,new UpdatePlayerMovement(UpdatePlayerMovement.Operation.ADD, add.x, add.y, add.z));
} else applyMovementEntity.addDeltaMovement(add);
}
return true;
}
}
private static <E extends Entity & Leashable> List<Leashable.Wrench> computeElasticInteraction(
E p_418297_, Entity p_418456_, List<Vec3> p_418351_, List<Vec3> p_418397_
) {
double d0 = p_418297_.leashElasticDistance();
Vec3 vec3 = Leashable.getHolderMovement(p_418297_);
float f = p_418297_.getYRot() * (float) (Math.PI / 180.0);
Vec3 vec31 = new Vec3(p_418297_.getBbWidth(), p_418297_.getBbHeight(), p_418297_.getBbWidth());
float f1 = p_418456_.getYRot() * (float) (Math.PI / 180.0);
Vec3 vec32 = new Vec3(p_418456_.getBbWidth(), p_418456_.getBbHeight(), p_418456_.getBbWidth());
List<Leashable.Wrench> list = new ArrayList<>();
for (int i = 0; i < p_418351_.size(); i++) {
Vec3 vec33 = p_418351_.get(i).multiply(vec31).yRot(-f);
Vec3 vec34 = p_418297_.position().add(vec33);
Vec3 vec35 = p_418397_.get(i).multiply(vec32).yRot(-f1);
Vec3 vec36 = p_418456_.position().add(vec35);
Leashable.computeDampenedSpringInteraction(vec36, vec34, d0, vec3, vec33).ifPresent(list::add);
}
return list;
}
@Override
default double leashElasticDistance() {
if (this instanceof IEntityLeadExtension entityLeadExtension) {
return entityLeadExtension.getLeashLength();
}
return 6.0;
}
@Override
default void readLeashData(CompoundTag tag) {
CompoundTag compoundTag = tag.read("Pl$LeashData", CompoundTag.CODEC).orElse(null);
if (compoundTag != null) {
Leashable.LeashData leashable$leashdata = compoundTag.read("Pl$LeashData", Leashable.LeashData.CODEC).orElse(null);
if (this.getLeashData() != null && leashable$leashdata == null) {
this.removeLeash();
}
this.setLeashData(leashable$leashdata);
default double leashSnapDistance() {
if (this instanceof IEntityLeadExtension entityLeadExtension) {
return entityLeadExtension.getLeashLength() * LeashedPlayer.M1();
}
return 12.0;
}
@Override
default void leashTooFarBehaviour() {
boolean shouldDrop = !(this instanceof LeashRopeArrow);
Leashable.dropLeash((Entity & Leashable) this, true, shouldDrop);
}
static <E extends Entity & Leashable> void restoreLeashFromSave(E p_entity, Leashable.LeashData leashData) {
if (leashData.delayedLeashInfo != null && p_entity.level() instanceof ServerLevel serverlevel) {
Optional<UUID> optional1 = leashData.delayedLeashInfo.left();
Optional<BlockPos> optional = leashData.delayedLeashInfo.right();
if (optional1.isPresent()) {
Entity entity = serverlevel.getEntity(optional1.get());
if (entity != null) {
setLeashedTo(p_entity, entity, true);
return;
}
} else if (optional.isPresent()) {
setLeashedTo(p_entity, LeashFenceKnotEntity.getOrCreateKnot(serverlevel, optional.get()), true);
return;
}
if (p_entity.tickCount > 100) {
p_entity.spawnAtLocation(serverlevel, Items.LEAD);
p_entity.setLeashData(null);
}
}
}
@Override
default void writeLeashData(@NotNull ValueOutput valueOutput, @org.jetbrains.annotations.Nullable Leashable.LeashData leashData) {
valueOutput.storeNullable("Pl$LeashData", Leashable.LeashData.CODEC, leashData);
}
@Override
default void readLeashData(ValueInput valueInput) {
LeashData leashData = valueInput.read("Pl$LeashData", Leashable.LeashData.CODEC).orElse(null);
if (getLeashData() != null && leashData == null) {
this.removeLeash();
}
this.setLeashData(leashData);
}
/**
@ -82,101 +203,36 @@ public interface PlayerLeashable extends Leashable {
//这边覆写去掉了乘坐相关的逻辑即乘坐状态下也可以正常被栓住不影响其乘坐状态
}
static void legacyElasticRangeLeashBehaviour(Entity holderEntity, Entity restrainedEntity) {
float leashLength = LeashCommand.MIN_VALUE;
if (restrainedEntity instanceof ILivingEntityExtension iEntity) {
// 获取绳长
float leashLengthFormValue = iEntity.getLeashLength();
leashLength = leashLengthFormValue > LeashCommand.MIN_VALUE ? leashLengthFormValue : LeashCommand.MIN_VALUE;
}
// 两者距离
float distance = holderEntity.distanceTo(restrainedEntity);
Entity applyMovementEntity = restrainedEntity.isPassenger() ? restrainedEntity.getVehicle() : restrainedEntity;
// 仅当距离大于绳长时施加拉力
if (applyMovementEntity != null && distance > leashLength) {
MethodA(holderEntity, applyMovementEntity, distance, leashLength);
// 控制速度不要过快避免偏激移动
Util.MovementBrake(applyMovementEntity, entity -> {
Vec3 deltaMovement = entity.getDeltaMovement();
entity.setDeltaMovement(
Math.min(Math.abs(deltaMovement.x), 1.0) * Math.signum(deltaMovement.x),
Math.min(Math.abs(deltaMovement.y), 1.0) * Math.signum(deltaMovement.y),
Math.min(Math.abs(deltaMovement.z), 1.0) * Math.signum(deltaMovement.z)
);
entity.hurtMarked = true;
});
}
}
private static void MethodA(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
// 计算朝向持有者的拉力方向
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
double dY = (holderEntity.getY() - applyMovementEntity.getY()) / (double) distance;
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
// 拉力大小距离越远拉力越强但施加一个最大限制
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
applyMovementEntity.setDeltaMovement(
applyMovementEntity.getDeltaMovement().add(
dX * pullStrength,
dY * pullStrength,
dZ * pullStrength
)
);
}
private static void MethodB(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
// 计算朝向持有者的拉力方向
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
// 稳定点的目标高度
double targetY = holderEntity.getY() + 1.0; // 根据需要调整目标高度
double currentY = applyMovementEntity.getY();
double heightDifference = targetY - currentY;
// 控制垂直方向的拉力
double dY = heightDifference > 0.5 ? 0.1 : (heightDifference < -0.5 ? -0.1 : 0);
// 拉力大小距离越远拉力越强但施加一个最大限制
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
applyMovementEntity.setDeltaMovement(
applyMovementEntity.getDeltaMovement().add(
dX * pullStrength,
dY,
dZ * pullStrength
)
);
}
@Nullable
static Entity getLeashDataEntity(@NotNull ServerPlayer serverPlayer , @NotNull ServerLevel serverLevel) {
LeashData leashDataFromEntityData = ((PlayerLeashable) serverPlayer).getLeashDataFromEntityData();
if (leashDataFromEntityData != null) {
return getLeashDataEntity(leashDataFromEntityData, serverLevel);
}
else return null;
}
static Entity getLeashDataEntityOrThrown(@NotNull ServerPlayer serverPlayer ,@NotNull ServerLevel serverLevel) throws Exception {
Entity leashedEntity = getLeashDataEntity(serverPlayer, serverLevel);
if(leashedEntity == null) throw new Exception("invalid");
else return leashedEntity;
Entity entity = getLeashDataEntity(serverPlayer, serverLevel);
if(entity == null) throw new Exception("invalid");
else return entity;
}
@Nullable
static Entity getLeashDataEntity(@NotNull Leashable.LeashData leashDataFromEntityData, @NotNull ServerLevel level) {
if(leashDataFromEntityData.delayedLeashInfo != null) {
Optional<UUID> UUID = leashDataFromEntityData.delayedLeashInfo.left();
Optional<BlockPos> BlockPos = leashDataFromEntityData.delayedLeashInfo.right();
static Entity getLeashDataEntity(@NotNull Entity entity, @NotNull ServerLevel level) {
if (entity instanceof Leashable leashable) {
LeashData data = leashable.getLeashData();
if (data != null) {
return PlayerLeashable.getLeashDataEntity(data, level);
}
}
return null;
}
@Nullable
static Entity getLeashDataEntity(@NotNull Leashable.LeashData leashData, @NotNull ServerLevel level) {
if(leashData.delayedLeashInfo != null) {
Optional<UUID> UUID = leashData.delayedLeashInfo.left();
Optional<BlockPos> BlockPos = leashData.delayedLeashInfo.right();
if (UUID.isPresent()) {
return level.getEntity(UUID.get());
} else return BlockPos.map(pos -> LeashFenceKnotEntity.getOrCreateKnot(level, pos)).orElse(null);
}
else if(leashDataFromEntityData.leashHolder != null) {
return leashDataFromEntityData.leashHolder;
else if(leashData.leashHolder != null) {
return leashData.leashHolder;
}
else if(leashDataFromEntityData.delayedLeashHolderId != 0) {
return level.getEntity(leashDataFromEntityData.delayedLeashHolderId);
else if(leashData.delayedLeashHolderId != 0) {
return level.getEntity(leashData.delayedLeashHolderId);
}
else return null;
}
@ -207,20 +263,6 @@ public interface PlayerLeashable extends Leashable {
throw new Exception("invalid leash data");
}
}
static boolean isLeashFenceKnotEntityExisted(ServerLevel pLevel, BlockPos pPos) {
int i = pPos.getX();
int j = pPos.getY();
int k = pPos.getZ();
for (LeashFenceKnotEntity leashfenceknotentity : pLevel.getEntitiesOfClass(
LeashFenceKnotEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
)) {
if (leashfenceknotentity.getPos().equals(pPos)) {
return true;
}
}
return false;
}
@Nullable
static Entity getLeashFenceKnotEntity(ServerLevel pLevel, BlockPos pPos) {
int i = pPos.getX();

View File

@ -1,9 +1,11 @@
package com.r3944realms.leashedplayer.network;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.network.client.SyncLeashRopeLength;
import com.r3944realms.leashedplayer.network.client.UpdatePlayerMovement;
import com.r3944realms.leashedplayer.network.server.DecreaseLeashRopeLength;
import com.r3944realms.leashedplayer.network.server.IncreaseLeashRopeLength;
import net.minecraft.network.syncher.SynchedEntityData;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
@ -20,6 +22,11 @@ public class LeashedPlayerNetwork {
UpdatePlayerMovement.STREAM_CODEC,
UpdatePlayerMovement::handle
);
registrar.playToClient(
SyncLeashRopeLength.TYPE,
SyncLeashRopeLength.STREAM_CODEC,
SyncLeashRopeLength::handle
);
registrar.playToServer(
IncreaseLeashRopeLength.TYPE,
IncreaseLeashRopeLength.STREAM_CODEC,

View File

@ -0,0 +1,37 @@
package com.r3944realms.leashedplayer.network.client;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public record SyncLeashRopeLength(String entityUUID, float length) implements CustomPacketPayload {
public static final Type<SyncLeashRopeLength> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID,"sync_leash_rope_length"));
public static final StreamCodec<FriendlyByteBuf, SyncLeashRopeLength> STREAM_CODEC =
StreamCodec.composite(
ByteBufCodecs.STRING_UTF8, SyncLeashRopeLength::entityUUID,
ByteBufCodecs.FLOAT, SyncLeashRopeLength::length,
SyncLeashRopeLength::new
);
public void handle(IPayloadContext context) {
context.enqueueWork(() -> {
Entity entity = context.player().level().getEntity(UUID.fromString(entityUUID));
if (entity instanceof IEntityLeadExtension entityLeadExtension) {
entityLeadExtension.setLeashLength(length);
}
});
}
@Override
public @NotNull Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View File

@ -1,7 +1,7 @@
package com.r3944realms.leashedplayer.network.server;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
@ -36,16 +36,18 @@ public record DecreaseLeashRopeLength(Code code, String playerUUID) implements C
ServerLevel level = (ServerLevel) player.level();
Player playerByUUID = level.getPlayerByUUID(UUID.fromString(playerUUID));
if (playerByUUID != null) {
ILivingEntityExtension entityExtension = (ILivingEntityExtension) playerByUUID;
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) playerByUUID, level);
IEntityLeadExtension entityExtension = (IEntityLeadExtension) playerByUUID;
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(playerByUUID, level);
if ((leashDataEntity != null && code == Code.OTHER_ST && leashDataEntity == player ) || (leashDataEntity != null && code == Code.OTHER_ST)) {
float newValue = Math.max(Math.min(entityExtension.getLeashLength() - 1, LeashedPlayer.M4()), LeashedPlayer.M3());
entityExtension.setLeashLength(newValue);
entityExtension.setLeadLengthSync(false);
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(DECREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
((ServerPlayer) player).sendSystemMessage(Component.translatable(DECREASE_LEASH_ROPE_LENGTH, playerByUUID.getDisplayName(), newValue), true);
} else if (code == Code.SELF) {
float newValue = Math.max(Math.min(entityExtension.getLeashLength() - 1, LeashedPlayer.M4()), LeashedPlayer.M3());
entityExtension.setLeashLength(newValue);
entityExtension.setLeadLengthSync(false);
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(DECREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
} else {
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(Code.LEASH_LENGTH_FAILED_SET), true);

View File

@ -1,7 +1,7 @@
package com.r3944realms.leashedplayer.network.server;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
@ -19,12 +19,12 @@ import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public record IncreaseLeashRopeLength(Code code, String playerUUID) implements CustomPacketPayload {
public record IncreaseLeashRopeLength(Code code, String entityUUID) implements CustomPacketPayload {
public static final Type<IncreaseLeashRopeLength> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID,"add_leash_rope_length"));
public static final StreamCodec<FriendlyByteBuf, IncreaseLeashRopeLength> STREAM_CODEC =
StreamCodec.composite(
NeoForgeStreamCodecs.enumCodec(Code.class), IncreaseLeashRopeLength::code,
ByteBufCodecs.STRING_UTF8, IncreaseLeashRopeLength::playerUUID,
ByteBufCodecs.STRING_UTF8, IncreaseLeashRopeLength::entityUUID,
IncreaseLeashRopeLength::new
);
public static final String INCREASE_LEASH_ROPE_LENGTH = "leashedplayer.leash_rope.length.increase",
@ -35,18 +35,20 @@ public record IncreaseLeashRopeLength(Code code, String playerUUID) implements C
context.enqueueWork(() -> {
Player player = context.player();
ServerLevel level = (ServerLevel) player.level();
Player playerByUUID = level.getPlayerByUUID(UUID.fromString(playerUUID));
Player playerByUUID = level.getPlayerByUUID(UUID.fromString(entityUUID));
if (playerByUUID != null) {
ILivingEntityExtension entityExtension = (ILivingEntityExtension) playerByUUID;
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) playerByUUID, level);
IEntityLeadExtension entityExtension = (IEntityLeadExtension) playerByUUID;
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(playerByUUID, level);
if ((leashDataEntity != null && code == Code.OTHER_ST && leashDataEntity == player ) || (leashDataEntity != null && code == Code.OTHER_ST)) {
float newValue = Math.max(Math.min(entityExtension.getLeashLength() + 1, LeashedPlayer.M4()), LeashedPlayer.M3());
entityExtension.setLeashLength(newValue);
entityExtension.setLeadLengthSync(false);
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(INCREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
((ServerPlayer) player).sendSystemMessage(Component.translatable(INCREASE_LEASH_ROPE_LENGTH, playerByUUID.getDisplayName(), newValue), true);
} else if (code == Code.SELF) {
float newValue = Math.max(Math.min(entityExtension.getLeashLength() + 1, LeashedPlayer.M4()), LeashedPlayer.M3());
entityExtension.setLeashLength(newValue);
entityExtension.setLeadLengthSync(false);
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(INCREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
} else {
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(Code.LEASH_LENGTH_FAILED_SET), true);

View File

@ -22,4 +22,8 @@ public net.minecraft.world.effect.MobEffect <init>(Lnet/minecraft/world/effect/M
public net.minecraft.world.inventory.ArmorSlot #ArmorSlot
#private -> protected
protected net.minecraft.world.entity.projectile.Projectile cachedOwner # cachedOwner
protected net.minecraft.world.entity.projectile.Projectile ownerUUID # ownerUUID
protected net.minecraft.world.entity.projectile.Projectile ownerUUID # ownerUUID
public net.minecraft.world.entity.Leashable$Wrench torqueFromForce(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;)D # torqueFromForce
public net.minecraft.world.entity.Leashable$Wrench accumulate(Ljava/util/List;)Lnet/minecraft/world/entity/Leashable$Wrench; # accumulate
public net.minecraft.world.entity.Leashable computeDampenedSpringInteraction(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;DLnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;)Ljava/util/Optional; # computeDampenedSpringInteraction
public net.minecraft.world.entity.Leashable getHolderMovement(Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/world/phys/Vec3; # getHolderMovement

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

@ -2,6 +2,7 @@
"package": "com.r3944realms.leashedplayer.mixin",
"mixins": [
"both.MixinEntity",
"both.MixinLeashable",
"both.MixinLivingEntity",
"both.MixinPlayer",
"item.MixinArmorSlotMixin",