diff --git a/README.md b/README.md index 0af5304..46b8756 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 版本 0.0.3.0-Beta.0.1 提前介绍 【注意:本解釋簡繁混寫,因爲趕時間,所以並不怎麽規範,請諒解】 +# 版本 0.0.3.1-Alpha-2 提前介绍 【注意:本解釋簡繁混寫,因爲趕時間,所以並不怎麽規範,請諒解】 ## 简介 现在开始你可以用拴绳拴住玩家,也可以拴住自己了,不如尝试拴住彼此来通关我的世界吧( @@ -12,14 +12,16 @@ 1. 可改变指令前命名空间和关闭命名空间 2. 修改命令拴绳的可设置的长度范围 3. 设置拴绳在达到多少倍的拴绳长度后掉落 +4. 拴绳箭最大存活时间 ## 新物品 和 实体 ### 拴绳箭 获得飞一样的感觉(操作不当可能会摔死 #### 射中实体时,会将射击者拴绳绑定在改实体上(该实体父类必须是有LivingEntity类型),同时拴绳箭会以普通的箭矢掉落 #### 射中栅栏时,会自动将玩家拴在上面 ,同时拴绳箭会以普通的箭矢掉落 -## 指令 - +#### 在地面上的箭可以通过按Shift靠近来捡起,如果捡起实体为发射箭矢玩家,则直接获取拴绳箭矢,如果捡起者为非发射者则成为发送者的拴绳持有者,并获得普通箭矢 +## 指令 +可能会因为配置中差异性导致前缀'lp'变为其它或取消其存在,以模组配置文件为准 * `/lp leash length [<玩家>] set <长度> ` - 设置该玩家的拴绳长度 [ 如果<玩家>为空则代表执行对象是自己 ,<长度> 为在 5 ~ 1024之间的浮点数 ] * `/lp leash length [<玩家>] [get]` - 顯示该玩家的拴绳长度 [ 如果<玩家>为空则代表执行对象是自己 , [get] 可不写] @@ -28,8 +30,13 @@ * `/lp leash data [<玩家>] [get]` - 顯示该玩家的拴绳數據 [ 如果<玩家>为空则代表执行对象是自己 , [get] 可不写] +* `/lp leash clear [<玩家[可多个对象]>] ` - 清除該玩家的的拴繩數據實體 [ 如果<玩家>为空则代表执行对象是自己 ] + + ## 游戏规则 * `LP.TeleportWithLeashedPlayers` - 此規則啓用后, 被栓玩家將會随玩家拴绳持有者一起传送 [默认值: True] -* `LP.CreateLeashFenceKnotEntityIfAbsent` - 此規則啓用后, 在設置 leashData 時,如果對應方塊坐標上的柵欄沒有拴繩結則會自動創建這個實體並綁定 [默认值: True] \ No newline at end of file +* `LP.CreateLeashFenceKnotEntityIfAbsent` - 此規則啓用后, 在設置 leashData 時,如果對應方塊坐標上的柵欄沒有拴繩結則會自動創建這個實體並綁定 [默认值: True] + +* `LP.KeepLeashNotDropTime` - 此规则决定,当拴绳关系创建时一段时间里,即是距离已经达到了断裂距离,也保持其不断裂 [默认值: 240ticks ,可设置范围[80, 1200]ticks] \ No newline at end of file diff --git a/Resource/crossbow_leash_rope_arrow.png b/Resource/crossbow_leash_rope_arrow.png new file mode 100644 index 0000000..7517484 Binary files /dev/null and b/Resource/crossbow_leash_rope_arrow.png differ diff --git a/Resource/leashed_rope_arrow.png b/Resource/leashed_rope_arrow.png index 771bb73..83cec87 100644 Binary files a/Resource/leashed_rope_arrow.png and b/Resource/leashed_rope_arrow.png differ diff --git a/gradle.properties b/gradle.properties index 56bf4a9..b5e827d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -32,7 +32,7 @@ mod_name=Leashed Player # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=All Rights Reserved # The mod version. See https://semver.org/ -mod_version=0.0.3.0-Beta.0.1 +mod_version=0.0.3.1 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/generated/resources/.cache/0aef4464247e697f9a7226f384437b478152c21c b/src/generated/resources/.cache/0aef4464247e697f9a7226f384437b478152c21c index b185ed1..fa0efec 100644 --- a/src/generated/resources/.cache/0aef4464247e697f9a7226f384437b478152c21c +++ b/src/generated/resources/.cache/0aef4464247e697f9a7226f384437b478152c21c @@ -1,2 +1,6 @@ -// 1.21.1 2024-09-05T13:27:19.7536653 Item Models: leashedplayer +// 1.21.1 2024-09-07T10:24:45.3887825 Item Models: leashedplayer +5846df9d85726428905701120ef34c9324c20faf assets/leashedplayer/models/item/bow_lra_pulling_0.json +845a7316b86e26f88c6932d4ef2656126503727a assets/leashedplayer/models/item/bow_lra_pulling_1.json +5bd1f9f28b91005c587f1c38fb77cd19b59495e3 assets/leashedplayer/models/item/bow_lra_pulling_2.json +83946f4d60d0fb1758d6553c36330506c8e48ada assets/leashedplayer/models/item/crossbow_leash_rope_arrow.json 114d3cc5832ef047403114504483c6f3ea07e77c assets/leashedplayer/models/item/leash_rope_arrow.json diff --git a/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_0.json b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_0.json new file mode 100644 index 0000000..b1f5789 --- /dev/null +++ b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/bow", + "textures": { + "layer0": "leashedplayer:item/bow_lra_pulling_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_1.json b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_1.json new file mode 100644 index 0000000..34b266b --- /dev/null +++ b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/bow", + "textures": { + "layer0": "leashedplayer:item/bow_lra_pulling_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_2.json b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_2.json new file mode 100644 index 0000000..1171cc5 --- /dev/null +++ b/src/generated/resources/assets/leashedplayer/models/item/bow_lra_pulling_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/bow", + "textures": { + "layer0": "leashedplayer:item/bow_lra_pulling_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/leashedplayer/models/item/crossbow_leash_rope_arrow.json b/src/generated/resources/assets/leashedplayer/models/item/crossbow_leash_rope_arrow.json new file mode 100644 index 0000000..cced484 --- /dev/null +++ b/src/generated/resources/assets/leashedplayer/models/item/crossbow_leash_rope_arrow.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/crossbow", + "textures": { + "layer0": "leashedplayer:item/crossbow_leash_rope_arrow" + } +} \ No newline at end of file diff --git a/src/main/java/com/r3944realms/leashedplayer/ClientEventHandler.java b/src/main/java/com/r3944realms/leashedplayer/ClientEventHandler.java index bda491d..c41353e 100644 --- a/src/main/java/com/r3944realms/leashedplayer/ClientEventHandler.java +++ b/src/main/java/com/r3944realms/leashedplayer/ClientEventHandler.java @@ -1,14 +1,37 @@ package com.r3944realms.leashedplayer; import com.r3944realms.leashedplayer.client.renders.LeashRopeArrowRenderer; +import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow; import com.r3944realms.leashedplayer.content.entities.ModEntityRegister; +import com.r3944realms.leashedplayer.content.items.ModItemRegister; +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.core.component.DataComponents; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.ChargedProjectiles; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.EntityRenderersEvent; @EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = LeashedPlayer.MOD_ID) public class ClientEventHandler { + @SubscribeEvent + public static void onRegisterItemProperties(FMLClientSetupEvent event) { + event.enqueueWork(() -> { + ItemProperties.register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow"), + ((pStack, pLevel, pEntity, pSeed) -> { + ChargedProjectiles chargedProjectiles = pStack.get(DataComponents.CHARGED_PROJECTILES); + return chargedProjectiles != null && chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) ? 1.0F : 0.0F; + })); + ItemProperties.register(Items.BOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow_pulling"), + ((pStack, pLevel, pEntity, pSeed) -> + (pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && LeashRopeArrow.isLeashRopeArrow(pStack, pEntity)) ? 1.0F: 0.0F + )); + }); + + } @SubscribeEvent public static void RegisterRenderer(EntityRenderersEvent.RegisterRenderers event) { event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new); diff --git a/src/main/java/com/r3944realms/leashedplayer/CommonEventHandler.java b/src/main/java/com/r3944realms/leashedplayer/CommonEventHandler.java index d5c7a5a..42705cf 100644 --- a/src/main/java/com/r3944realms/leashedplayer/CommonEventHandler.java +++ b/src/main/java/com/r3944realms/leashedplayer/CommonEventHandler.java @@ -5,13 +5,63 @@ import com.r3944realms.leashedplayer.content.commands.LeashCommand; import net.minecraft.commands.CommandSourceStack; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.neoforge.event.RegisterCommandsEvent; -@EventBusSubscriber(modid = LeashedPlayer.MOD_ID) + public class CommonEventHandler { - @SubscribeEvent - public static void onRegisterCommander(RegisterCommandsEvent event) { - CommandDispatcher dispatcher = event.getDispatcher(); - LeashCommand.register(dispatcher); + @EventBusSubscriber(modid = LeashedPlayer.MOD_ID) + public static class Game extends CommonEventHandler { + @SubscribeEvent + public static void onRegisterCommander(RegisterCommandsEvent event) { + CommandDispatcher dispatcher = event.getDispatcher(); + LeashCommand.register(dispatcher); + } + } + @EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD) + public static class Mod extends CommonEventHandler { + @SubscribeEvent + public static void onCommonSetup(FMLCommonSetupEvent event) { +// NeoForge.EVENT_BUS.addListener(Mod::onPlayerTick); + } +// public static void onPlayerTick(PlayerTickEvent.Pre event) { +// if (!event.getEntity().level().isClientSide && !event.getEntity().isUsingItem()) { +// Player player = event.getEntity(); +// +// // 检测玩家视线中的实体 +// Entity entity = getEntityLookedAt(player); +// +// // 如果实体是自定义箭实体 +// if (entity instanceof LeashRopeArrow la) { +// +// // 处理玩家右键点击箭的交互逻辑 +// if (player.isShiftKeyDown()) { // 可以结合 Shift 键 +// if(la.pickup == AbstractArrow.Pickup.ALLOWED || ( player.isCreative() && la.pickup != AbstractArrow.Pickup.DISALLOWED )){ +// player.take(la, 1); +// player.addItem(ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance()); +// } +// } +// } +// } +// } +// +// // 射线检测方法,获取玩家视线内的实体//TODO:分离 Maybe XD +// private static Entity getEntityLookedAt(Player player) { +// double reach = 5.0D; // 设置射线检测距离 //TODO:与Player互动距离同步 +// Vec3 eyePosition = player.getEyePosition(1.0F); +// Vec3 lookVector = player.getViewVector(1.0F).scale(reach); +// Vec3 targetPosition = eyePosition.add(lookVector); +// +// // 创建一个射线并检测结果 +// AABB boundingBox = player.getBoundingBox().expandTowards(lookVector).inflate(1.0D, 1.0D, 1.0D); +// EntityHitResult hitResult = ProjectileUtil.getEntityHitResult(player, eyePosition, targetPosition, boundingBox, e -> e instanceof LeashRopeArrow, reach); +// +// return hitResult == null ? null : hitResult.getEntity(); +// } +// } + } + + + } diff --git a/src/main/java/com/r3944realms/leashedplayer/config/LeashPlayerCommonConfig.java b/src/main/java/com/r3944realms/leashedplayer/config/LeashPlayerCommonConfig.java index f152bde..a033597 100644 --- a/src/main/java/com/r3944realms/leashedplayer/config/LeashPlayerCommonConfig.java +++ b/src/main/java/com/r3944realms/leashedplayer/config/LeashPlayerCommonConfig.java @@ -2,14 +2,12 @@ package com.r3944realms.leashedplayer.config; import net.neoforged.neoforge.common.ModConfigSpec; -import java.util.function.Predicate; - public class LeashPlayerCommonConfig { public static ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); public static final ModConfigSpec SPEC; public static final ModConfigSpec.ConfigValue LeashedPlayerModCommandPrefix; public static final ModConfigSpec.BooleanValue EnableLeashPlayerCommandPrefix; - public static ModConfigSpec.IntValue MinimumLeashLengthCanBeSet, MaximumLeashLengthCanBeSet; + public static ModConfigSpec.IntValue MinimumLeashLengthCanBeSet, MaximumLeashLengthCanBeSet, TheLeashArrowMaxLifeTime; public static ModConfigSpec.ConfigValue TheMultipleThatLeashRopeArrowBreakLength, TheLeashBreakLengthTimesBase; static { BUILDER.comment("Leash Player Config"); @@ -23,7 +21,7 @@ public class LeashPlayerCommonConfig { BUILDER.push("Leash Rope Arrow"); TheMultipleThatLeashRopeArrowBreakLength = BUILDER.comment("How many times is the length of the arrow rope based on BreakLength TimeBase", "[ Default : 5.0f, Invalid Range:[1.0f, 10.0f] ]").define("TheMultipleArrowBreak", 5.0f, o -> (o instanceof Float f) && f >= 2.0f && f <= 10.0f); - + TheLeashArrowMaxLifeTime = BUILDER.comment("If the LeashArrowEntity's life is bigger than this value ,it will be discrad", "[ Default : 2400, Invalid Range:[1200 , 10240]").defineInRange("TheLeashArrowMaxLifeTime",2400, 1200, 10240); BUILDER.pop(); BUILDER.push("Misc"); diff --git a/src/main/java/com/r3944realms/leashedplayer/content/commands/LeashCommand.java b/src/main/java/com/r3944realms/leashedplayer/content/commands/LeashCommand.java index 90d225b..ec0285b 100644 --- a/src/main/java/com/r3944realms/leashedplayer/content/commands/LeashCommand.java +++ b/src/main/java/com/r3944realms/leashedplayer/content/commands/LeashCommand.java @@ -4,7 +4,6 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; 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.config.LeashPlayerCommonConfig; @@ -26,6 +25,7 @@ import net.minecraft.world.entity.Leashable; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class LeashCommand { @@ -79,7 +79,7 @@ public class LeashCommand { Command getRefPlayerLeashLength = context -> { CommandSourceStack source = context.getSource(); try { - ServerPlayer player = EntityArgument.getPlayer(context, "player"); + ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer"); float leashLength = ((ILivingEntityExtension)player).getLeashLength(); source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true); } catch (Exception e) { @@ -88,6 +88,20 @@ public class LeashCommand { } return 0; }; + Command getRefPlayersLeashLength = context -> { + CommandSourceStack source = context.getSource(); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayers"); + playerCol.forEach(player -> { + float leashLength = ((ILivingEntityExtension) player).getLeashLength(); + source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true); + }); + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; Command setSelfLengthLeashLength = context -> { CommandSourceStack source = context.getSource(); try { @@ -101,10 +115,10 @@ public class LeashCommand { } return 0; }; - Command setLengthLeashLength = context -> { + Command setRefPlayerLengthLeashLength = context -> { CommandSourceStack source = context.getSource(); try { - ServerPlayer player = EntityArgument.getPlayer(context, "player"); + ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer"); float leashLength = context.getArgument("leashLength", Float.class); ((ILivingEntityExtension)player).setLeashLength(leashLength); source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true); @@ -114,6 +128,25 @@ public class LeashCommand { } return 0; }; + Command setRefPlayersLengthLeashLength = context -> { + CommandSourceStack source = context.getSource(); + float leashLength = context.getArgument("leashLength", Float.class); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayer"); + playerCol.forEach(player -> { + try { + ((ILivingEntityExtension)player).setLeashLength(leashLength); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; //获取Data 构造一个MutableComponent显示数据 Command geSelfLeashData = context -> { CommandSourceStack source = context.getSource(); @@ -140,6 +173,24 @@ public class LeashCommand { } return 0; }; + Command getRefPlayersLeashData = context -> { + CommandSourceStack source = context.getSource(); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayers"); + playerCol.forEach(player -> { + try { + LeashLengthGetResultInt(player, source); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; //设置前要判断其实体距离(同一维度,且距离不得大于其绳长的1.2倍(待定,也许可以设置在配置文件里) Command setSelfLeashDataEntity = context -> { CommandSourceStack source = context.getSource(); @@ -182,6 +233,37 @@ public class LeashCommand { } return 0; }; + Command setRefPlayersLeashDataEntity = context -> { + CommandSourceStack source = context.getSource(); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayers"); + playerCol.forEach(player -> { + try { + LeashDataEntitySetResultInt(context, player, source); + } catch (CommandSyntaxException e) { + throw new RuntimeException(e); + } + }); + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; + Command setRefPlayersLeashDataByBlockPos = context -> { + CommandSourceStack source = context.getSource(); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayers"); + playerCol.forEach(player -> { + LeashDataBlockPosSetResultInt(context, source, player); + }); + + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; Command setRefPlayerLeashDataByBlockPos = context -> { CommandSourceStack source = context.getSource(); try { @@ -195,6 +277,7 @@ public class LeashCommand { } return 0; }; + Command clearSelfLeashData = context -> { CommandSourceStack source = context.getSource(); try { @@ -212,8 +295,25 @@ public class LeashCommand { CommandSourceStack source = context.getSource(); try { ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer"); - Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntityOrThrown(player, source.getLevel()),player); - if (x != null) return x; + Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player); + + } catch (Exception e) { + source.sendFailure(Component.translatable(LEASH_FAILED)); + return -1; + } + return 0; + }; + Command clearRefPlayersLeashData = context -> { + CommandSourceStack source = context.getSource(); + try { + Collection playerCol = EntityArgument.getPlayers(context, "targetPlayers"); + playerCol.forEach(player -> { + try { + LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); } catch (Exception e) { source.sendFailure(Component.translatable(LEASH_FAILED)); @@ -232,11 +332,19 @@ public class LeashCommand { LiteralArgumentBuilder RefPlayerLeashLength = $$leashRoot.then( Commands.literal("length") - .then(Commands.argument("player", EntityArgument.player()).executes(getRefPlayerLeashLength) + .then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashLength) .then(Commands.literal("get").executes(getRefPlayerLeashLength)) .then(Commands.literal("set").requires(cs -> cs.hasPermission(2)) .then( - Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setLengthLeashLength) + Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayerLengthLeashLength) + ) + ) + ) + .then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayerLeashLength) + .then(Commands.literal("get").executes(getRefPlayerLeashLength)) + .then(Commands.literal("set").requires(cs -> cs.hasPermission(2)) + .then( + Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayerLengthLeashLength) ) ) ) @@ -256,9 +364,22 @@ public class LeashCommand { .executes(setRefPlayerLeashDataByBlockPos) ) ) - .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearSelfLeashData)) + .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayerLeashData)) ) - ); + .then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayersLeashData) + .then(Commands.literal("get") + .executes(getRefPlayerLeashData) + ) + .then(Commands.literal("set").requires(cs -> cs.hasPermission(2)) + .then(Commands.argument("holderEntity", EntityArgument.entity()) + .executes(setRefPlayersLeashDataEntity) + ) + .then(Commands.argument("BlockPos", BlockPosArgument.blockPos()) + .executes(setRefPlayersLeashDataByBlockPos) + ) + ) + .then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayersLeashData)) + )); LiteralArgumentBuilder SelfData = $$leashRoot.then( Commands.literal("data") @@ -353,6 +474,7 @@ public class LeashCommand { source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashDataEntityDisplayName), true); return null; } + private static @Nullable Integer LeashDataClearResultInt(CommandSourceStack source, Entity leashDataEntity, ServerPlayer serverPlayer) { if(leashDataEntity == null) { source.sendFailure(Component.translatable(LEASH_DATA_CLEAR_FAILED_NO_DATA, serverPlayer.getDisplayName())); diff --git a/src/main/java/com/r3944realms/leashedplayer/content/entities/LeashRopeArrow.java b/src/main/java/com/r3944realms/leashedplayer/content/entities/LeashRopeArrow.java index d82beaf..d1113d9 100644 --- a/src/main/java/com/r3944realms/leashedplayer/content/entities/LeashRopeArrow.java +++ b/src/main/java/com/r3944realms/leashedplayer/content/entities/LeashRopeArrow.java @@ -1,6 +1,11 @@ package com.r3944realms.leashedplayer.content.entities; +import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig; +import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry; +import com.r3944realms.leashedplayer.content.gamerules.Server.KeepLeashNotDropTime; +import com.r3944realms.leashedplayer.content.items.LeashRopeArrowItem; import com.r3944realms.leashedplayer.content.items.ModItemRegister; +import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension; import com.r3944realms.leashedplayer.modInterface.PlayerLeashable; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -8,6 +13,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.decoration.LeashFenceKnotEntity; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.AbstractArrow; @@ -20,6 +26,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class LeashRopeArrow extends AbstractArrow { + private static final int maxLifeTime = LeashPlayerCommonConfig.TheLeashArrowMaxLifeTime.get(); protected LeashRopeArrow(EntityType entityType,Level pLevel) { super(entityType, pLevel); } @@ -37,6 +44,17 @@ public class LeashRopeArrow extends AbstractArrow { lPlayer.setLeashedTo(this, true); } } + public static boolean isLeashRopeArrow(ItemStack bowStack, LivingEntity entity) { + if (entity instanceof Player player) { + + // 获取将要发射的弹药 + ItemStack projectileStack = player.getProjectile(bowStack); + + // 判断该弹药是否为改箭 + return projectileStack.getItem() instanceof LeashRopeArrowItem; + } + return false; + } @Override protected @NotNull ItemStack getDefaultPickupItem() { @@ -52,25 +70,75 @@ public class LeashRopeArrow extends AbstractArrow { @Override protected boolean tryPickup(@NotNull Player pPlayer) { - if(life <= 240) { + //时间1.40 禁止 + //时间2.240 + // 如果(非仅创造拾取) + // 如果 (按Shift ) + // 如果(拥有者) -> 拾取到完整箭,取消绑定(super给父类处理) + // 否则:时间仍为原需时间 ->不能获取完整的箭,重绑定(当前拥有者的Holder是否为本箭,“是”才重绑定) + // 否则: 禁止 + // 否则: + // 如果 (按Shift ) + // 如果(拥有者) -> 且拾取到完整箭,取消绑定 + // 否则:时间仍为原需时间 ->不能获取完整的箭,重绑定 + // 否则: 禁止 + //时间3 + // 如果(拥有者) -> 拾取到完整箭,取消绑定 + // 否则:不能获取完整的箭,重绑定 + + if(life <= 40 ) { return false; - } else { - if(life >= 480 || this.ownedBy(pPlayer) && (this.pickup != Pickup.CREATIVE_ONLY) ) { - this.pickup = Pickup.ALLOWED; + } + else { + PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer; + if(life <= 240) { + if(pPlayer.isShiftKeyDown()) { + Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()); + if(this.ownedBy(pPlayer)) { + this.pickup = Pickup.ALLOWED; + if(this.equals(leashDataEntity)) playerLeashable.dropLeash(true, false); + } else { + if(life >= 120) { + Entity owner = getOwner(); + if( owner != null ) { + if(this.equals(leashDataEntity)) { + ((PlayerLeashable) owner).setLeashedTo(pPlayer, true); + ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), Items.ARROW.getDefaultInstance()); + level().addFreshEntity(itemEntity); + discard(); + } + } else return true; + } else return false; + } + } else return false; + + } + else { + Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()); if(this.ownedBy(pPlayer)) { - ((PlayerLeashable)pPlayer).dropLeash(true, false); - } else if (this.getOwner() instanceof PlayerLeashable pL){ - pL.setLeashedTo(this, false); + this.pickup = Pickup.ALLOWED; + if(this.equals(leashDataEntity)) playerLeashable.dropLeash(true, false); + } else { + if(this.equals(leashDataEntity)) { + Entity owner = getOwner(); + ((PlayerLeashable)owner).setLeashedTo(pPlayer, true); + ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), Items.ARROW.getDefaultInstance()); + level().addFreshEntity(itemEntity); + discard(); + } + } } - return super.tryPickup(pPlayer); } + + return super.tryPickup(pPlayer); } + @Override protected void tickDespawn() { this.life++; - if (this.life >= 2400) {//TODO 加到配置中去,修改 + if (this.life >= maxLifeTime) { ItemEntity leash_rope_arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance()); this.level().addFreshEntity(leash_rope_arrow); this.discard(); @@ -83,8 +151,10 @@ public class LeashRopeArrow extends AbstractArrow { if (getOwner() instanceof PlayerLeashable pL) { if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) { Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level()); - if(leashDataEntity != null) pL.dropLeash(true, true); + if(leashDataEntity != null) pL.dropLeash(true, !(leashDataEntity instanceof LeashRopeArrow)); Entity leashKnotFence = PlayerLeashable.createLeashKnotFence((ServerLevel) this.level(), pResult.getBlockPos()); + ILivingEntityExtension pLL = (ILivingEntityExtension) pL; + pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID)); pL.setLeashedTo(leashKnotFence, true); ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, Items.ARROW.getDefaultInstance()); this.level().addFreshEntity(arrow); @@ -99,14 +169,30 @@ public class LeashRopeArrow extends AbstractArrow { @Override protected void onHitEntity(@NotNull EntityHitResult pResult) { if(!level().isClientSide()){ - if(pResult.getEntity() instanceof LivingEntity){ + Entity entity = pResult.getEntity(); + if(entity instanceof LivingEntity){ + if(entity.equals(this.getOwner())) return; + if (getOwner() instanceof PlayerLeashable pL) { + Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level()); + if(leashDataEntity != null) pL.dropLeash(true, !(leashDataEntity instanceof LeashRopeArrow)); + ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, Items.ARROW.getDefaultInstance()); + ILivingEntityExtension pLL = (ILivingEntityExtension) pL; + pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID)); + pL.setLeashedTo(pResult.getEntity(), true); + this.level().addFreshEntity(arrow); + discard(); + } + } else if (entity instanceof LeashFenceKnotEntity leashKnotFence) { if (getOwner() instanceof PlayerLeashable pL) { Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level()); if(leashDataEntity != null) pL.dropLeash(true, true); - pL.setLeashedTo(pResult.getEntity(), true); ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, Items.ARROW.getDefaultInstance()); + ILivingEntityExtension pLL = (ILivingEntityExtension) pL; + pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID)); + pL.setLeashedTo(leashKnotFence, true); this.level().addFreshEntity(arrow); discard(); + return; } } } diff --git a/src/main/java/com/r3944realms/leashedplayer/content/gamerules/Server/KeepLeashNotDropTime.java b/src/main/java/com/r3944realms/leashedplayer/content/gamerules/Server/KeepLeashNotDropTime.java new file mode 100644 index 0000000..9bf9270 --- /dev/null +++ b/src/main/java/com/r3944realms/leashedplayer/content/gamerules/Server/KeepLeashNotDropTime.java @@ -0,0 +1,28 @@ +package com.r3944realms.leashedplayer.content.gamerules.Server; + +import com.r3944realms.leashedplayer.LeashedPlayer; +import com.r3944realms.leashedplayer.content.gamerules.Gamerules; +import com.r3944realms.leashedplayer.utils.Util; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.GameRules; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; + +import java.util.function.BiConsumer; + +import static com.r3944realms.leashedplayer.content.gamerules.Gamerules.GAMERULE_REGISTRY; + +@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD) +public class KeepLeashNotDropTime { + public static final int DEFAULT_VALUE = 240; + public static final String ID = Util.getGameruleName(KeepLeashNotDropTime.class); + public static final String DESCRIPTION_KEY = Gamerules.getDescriptionKey(KeepLeashNotDropTime.class); + public static final String NAME_KEY = Gamerules.getNameKey(KeepLeashNotDropTime.class); + public static final GameRules.Category CATEGORY = GameRules.Category.MISC; + + @SubscribeEvent + public static void onCommonSetup(final FMLCommonSetupEvent event) { + GAMERULE_REGISTRY.registerGamerule(ID, CATEGORY, DEFAULT_VALUE, 80, 1200, (BiConsumer) (i, j)->{}); + } +} diff --git a/src/main/java/com/r3944realms/leashedplayer/content/items/LeashRopeArrowItem.java b/src/main/java/com/r3944realms/leashedplayer/content/items/LeashRopeArrowItem.java index 21842a4..46db9e9 100644 --- a/src/main/java/com/r3944realms/leashedplayer/content/items/LeashRopeArrowItem.java +++ b/src/main/java/com/r3944realms/leashedplayer/content/items/LeashRopeArrowItem.java @@ -7,10 +7,12 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.item.ArrowItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; +import java.util.List; public class LeashRopeArrowItem extends ArrowItem { public static final String descKey = "item.leash_rope_arrow.description"; @@ -26,4 +28,8 @@ public class LeashRopeArrowItem extends ArrowItem { public @NotNull Component getDescription() { return Component.translatable(descKey).withStyle(ChatFormatting.GRAY); } + public void appendHoverText(@NotNull ItemStack pStack, Item.@NotNull TooltipContext pContext, @NotNull List pTooltipComponents, @NotNull TooltipFlag pTooltipFlag) { + //TODO:也许会做 + } + } diff --git a/src/main/java/com/r3944realms/leashedplayer/content/items/ModCreativeTab.java b/src/main/java/com/r3944realms/leashedplayer/content/items/ModCreativeTab.java index f397878..000df10 100644 --- a/src/main/java/com/r3944realms/leashedplayer/content/items/ModCreativeTab.java +++ b/src/main/java/com/r3944realms/leashedplayer/content/items/ModCreativeTab.java @@ -5,10 +5,8 @@ import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; - import net.minecraft.world.item.Items; import net.neoforged.bus.api.IEventBus; - import net.neoforged.neoforge.registries.DeferredRegister; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/r3944realms/leashedplayer/datagen/LanguageAndOtherData/ModLangKeyValue.java b/src/main/java/com/r3944realms/leashedplayer/datagen/LanguageAndOtherData/ModLangKeyValue.java index d3acc97..659a2d4 100644 --- a/src/main/java/com/r3944realms/leashedplayer/datagen/LanguageAndOtherData/ModLangKeyValue.java +++ b/src/main/java/com/r3944realms/leashedplayer/datagen/LanguageAndOtherData/ModLangKeyValue.java @@ -1,9 +1,9 @@ package com.r3944realms.leashedplayer.datagen.LanguageAndOtherData; import com.r3944realms.leashedplayer.content.commands.LeashCommand; -import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow; import com.r3944realms.leashedplayer.content.entities.ModEntityRegister; import com.r3944realms.leashedplayer.content.gamerules.Server.CreateLeashFenceKnotEntityIfAbsent; +import com.r3944realms.leashedplayer.content.gamerules.Server.KeepLeashNotDropTime; import com.r3944realms.leashedplayer.content.gamerules.Server.TeleportWithLeashedPlayers; import com.r3944realms.leashedplayer.content.items.LeashRopeArrowItem; import com.r3944realms.leashedplayer.content.items.ModCreativeTab; @@ -44,10 +44,11 @@ public enum ModLangKeyValue { //GAME_RULE_NAME TELEPORT_WITH_LEASHED_PLAYERS(TeleportWithLeashedPlayers.NAME_KEY, ModPartEnum.NAME, "Teleport leashed player with player holder", "被拴玩家随玩家持有者传送", "被拴玩家随玩家持有者傳送" ,false), CREATE_LEASH_FENCE_KNOT_ENTITY_IF_ABSENT(CreateLeashFenceKnotEntityIfAbsent.NAME_KEY, ModPartEnum.NAME, "Create Leash Fence Knot Entity if absent", "如果缺失则创建拴绳结", "如果缺失則創建拴繩結", false), + KEEP_LEASH_NOT_DROP_TIME(KeepLeashNotDropTime.NAME_KEY, ModPartEnum.NAME, "Keep leash alive Time", "保持拴绳不掉落的时间", "保持其不掉落的時間", false), //GAME_RULE_DESCRIPTION TELEPORT_WITH_LEASHED_DESCRIPTION(TeleportWithLeashedPlayers.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION, "Holder will teleport with their leashed players ", "传送时将被拴玩家与持有者一起传送", "將被拴玩家將隨持有者一起傳送" ,false), - CREATE_LEASH_FENCE_KNOT_ENTITY_IF_ABSENT_DESCRIPTION(CreateLeashFenceKnotEntityIfAbsent.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION, "Create LeashKnot Entity if it's absent on fence", "如果在栅栏处缺失拴绳结,则创建它", "如果在柵欄処缺失拴繩結,則創建它",false), - + CREATE_LEASH_FENCE_KNOT_ENTITY_IF_ABSENT_DESCRIPTION(CreateLeashFenceKnotEntityIfAbsent.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION, "Create LeashKnot Entity if it's absent on fence", "如果在栅栏处缺失拴绳结,则创建它", "如果在柵欄処缺失拴繩結,則創建它", false), + KEEP_LEASH_NOT_DROP_TIME_DESCRIPTION(KeepLeashNotDropTime.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION,"The time of Keep new leash which has far distance alive (Tick)", "当距离过远时,保持新建拴绳不掉落的时间 (刻)", "儅距離過遠時,保持其不掉落的時間(刻)", false), ; private final Supplier supplier; private String key; diff --git a/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModItemModelProvider.java b/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModItemModelProvider.java index 3dd69c9..249de34 100644 --- a/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModItemModelProvider.java +++ b/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModItemModelProvider.java @@ -1,10 +1,13 @@ package com.r3944realms.leashedplayer.datagen.provider; +import com.r3944realms.leashedplayer.LeashedPlayer; import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModLangKeyValue; import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.neoforged.neoforge.client.model.generators.ItemModelProvider; +import net.neoforged.neoforge.client.model.generators.ModelFile; import net.neoforged.neoforge.common.data.ExistingFileHelper; import java.util.ArrayList; @@ -31,6 +34,18 @@ public class ModItemModelProvider extends ItemModelProvider { } private void AdvancedModItemModelRegister() { /*手动生成更快,其实*/ + getBuilder("crossbow_leash_rope_arrow") + .parent(new ModelFile.UncheckedModelFile("item/crossbow")) + .texture("layer0", ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "item/crossbow_leash_rope_arrow")); + getBuilder("bow_lra_pulling_0") + .parent(new ModelFile.UncheckedModelFile("item/bow")) + .texture("layer0", ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_0")); + getBuilder("bow_lra_pulling_1") + .parent(new ModelFile.UncheckedModelFile("item/bow")) + .texture("layer0", ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_1")); + getBuilder("bow_lra_pulling_2") + .parent(new ModelFile.UncheckedModelFile("item/bow")) + .texture("layer0", ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_2")); } @Override diff --git a/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModRecipeProvider.java b/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModRecipeProvider.java index 6b15279..dc5998f 100644 --- a/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModRecipeProvider.java +++ b/src/main/java/com/r3944realms/leashedplayer/datagen/provider/ModRecipeProvider.java @@ -3,7 +3,10 @@ package com.r3944realms.leashedplayer.datagen.provider; import com.r3944realms.leashedplayer.content.items.ModItemRegister; import net.minecraft.core.HolderLookup; import net.minecraft.data.PackOutput; -import net.minecraft.data.recipes.*; +import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.data.recipes.ShapelessRecipeBuilder; import net.minecraft.world.item.Items; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinLivingEntity.java b/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinLivingEntity.java index aa5ad87..02b22f6 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinLivingEntity.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinLivingEntity.java @@ -17,6 +17,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LivingEntity.class) public abstract class MixinLivingEntity extends Entity implements ILivingEntityExtension { + @Unique + protected int Pl$LeashKeepTick;//保存状态,当超过断裂绳长时若LeashKeepTick大于0,则不断裂 + public MixinLivingEntity(EntityType pEntityType, Level pLevel) { super(pEntityType, pLevel); } @@ -35,6 +38,17 @@ public abstract class MixinLivingEntity extends Entity implements ILivingEntityE 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; + } + @Inject(method = {"defineSynchedData"}, at = {@At("TAIL")}) //定义Client/Server实体同步数据 private void defineSyncData(SynchedEntityData.Builder pBuilder, CallbackInfo ci) { diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinPlayer.java b/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinPlayer.java index 29099ef..9d4fc19 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinPlayer.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/both/MixinPlayer.java @@ -1,7 +1,6 @@ package com.r3944realms.leashedplayer.mixin.both; import com.r3944realms.leashedplayer.LeashedPlayer; -import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig; import com.r3944realms.leashedplayer.content.commands.LeashCommand; import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow; import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension; @@ -11,12 +10,10 @@ 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.util.Mth; 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; @@ -28,7 +25,6 @@ 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) @@ -37,6 +33,7 @@ public abstract class MixinPlayer extends LivingEntity implements PlayerLeashabl @Nullable private LeashData Pl$LeashData;//Data + @SuppressWarnings("WrongEntityDataParameterClass") @Unique//客户端与服务器端的实体同步数据 private static final EntityDataAccessor Pl$LEASH_DATA = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG); @@ -146,8 +143,10 @@ public abstract class MixinPlayer extends LivingEntity implements PlayerLeashabl } @Unique protected void Pl$tickLeash() { - if(this.Pl$LeashData == null) return;//没有Data直接退出 + ILivingEntityExtension self = (ILivingEntityExtension) this; + int keepLeashTick = self.getKeepLeashTick(); + //info -> Holder整理 Pl$RestoreLeashFormSave(); //默认值设为 @@ -155,27 +154,27 @@ public abstract class MixinPlayer extends LivingEntity implements PlayerLeashabl Entity entity = this.Pl$LeashData.leashHolder; //保存数据 saveLeashData(Pl$LeashData); - if(this instanceof ILivingEntityExtension iEntityExtension) { - //获取设定值 - float leashLengthSelf = iEntityExtension.getLeashLength(); - leashLength = leashLengthSelf > LeashCommand.MIN_VALUE ? leashLengthSelf : LeashCommand.MIN_VALUE; - } + ILivingEntityExtension iEntityExtension = (ILivingEntityExtension) this;//获取设定值 + float leashLengthSelf = iEntityExtension.getLeashLength(); + leashLength = leashLengthSelf > LeashCommand.MIN_VALUE ? leashLengthSelf : LeashCommand.MIN_VALUE; if (entity != null) { float breakDistanceTime = (entity instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1(); - if(!isAlive() || !entity.isAlive() || distanceTo(entity) > Math.max(leashLength * breakDistanceTime, LeashCommand.MIN_VALUE * breakDistanceTime)){ - //玩家死亡 或 持有者不存在 或 距离大于设定值的2倍(长度2倍若低于10格,则选10格) , + 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); dropLeash(true, shouldDrop); } else if(distanceTo(entity) > leashLength * 0.65f * breakDistanceTime && entity.onGround()) { - //大于1.3倍绳长则会让其跳跃(在<1.25格阻拦情况下,跳跃阻拦//TODO:待擴展 + //大于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 diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinEntityRenderer.java b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinEntityRenderer.java index 2b11020..b381ad1 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinEntityRenderer.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinEntityRenderer.java @@ -1,17 +1,13 @@ package com.r3944realms.leashedplayer.mixin.client; -import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.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; @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinLevelRenderer.java b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinLevelRenderer.java index 0ef5316..4cbb440 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinLevelRenderer.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinLevelRenderer.java @@ -15,7 +15,6 @@ import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.entity.player.PlayerRenderer; import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Leashable; @@ -115,7 +114,7 @@ public abstract class MixinLevelRenderer { } if (holder != null) { if(holder instanceof LeashRopeArrow) { - playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, new Vec3(0.,-0.09, 0));//TODO: 待擴展Vec3 + playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, new Vec3(0.,-0.09, 0));//TODO: 待擴展Vec3吗? } else playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder); } diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinPlayerRenderer.java b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinPlayerRenderer.java index b8769be..18947a6 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinPlayerRenderer.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/client/MixinPlayerRenderer.java @@ -85,7 +85,7 @@ public abstract class MixinPlayerRenderer extends LivingEntityRenderer void renderLeash(AbstractClientPlayer pEntity, float pPartialTick, PoseStack pPoseStack, MultiBufferSource pBufferSource, E pLeashHolder, Vec3 holderOffset) { pPoseStack.pushPose(); Vec3 vec3 = pLeashHolder.getRopeHoldPosition(pPartialTick).add(holderOffset); double d0 = (double)(pEntity.getPreciseBodyRotation(pPartialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2); - Vec3 vec31 = pEntity.getLeashOffset(pPartialTick); + Vec3 vec31 = pEntity.getLeashOffset(pPartialTick).add(0, -0.2, -0.2);//TODO:待擴展Vec3); double d1 = Math.cos(d0) * vec31.z + Math.sin(d0) * vec31.x; double d2 = Math.sin(d0) * vec31.z - Math.cos(d0) * vec31.x; double d3 = Mth.lerp(pPartialTick, pEntity.xo, pEntity.getX()) + d1; diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/item/MixinLeadItem.java b/src/main/java/com/r3944realms/leashedplayer/mixin/item/MixinLeadItem.java index 5bd7c29..f55f0c3 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/item/MixinLeadItem.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/item/MixinLeadItem.java @@ -2,7 +2,10 @@ 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; @@ -36,13 +39,17 @@ public class MixinLeadItem { //非创造模式减少,防止刷物品 if(!pPlayer.isCreative()) mainHandItem.shrink(1); //自己 - PlayerLeashable self = (PlayerLeashable) pPlayer; + Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) pPlayer, (ServerLevel) pLevel); + PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer; + if(leashDataEntity != null) { + playerLeashable.dropLeash(true, true); + } //获取拴绳结实体 LeashFenceKnotEntity leashfenceknotentity = LeashFenceKnotEntity.getOrCreateKnot(pLevel, pPos); //播放绳结被放置的声音 leashfenceknotentity.playPlacementSound(); //将自己与拴绳结绑定LeashData - self.setLeashedTo(leashfenceknotentity, true); + playerLeashable.setLeashedTo(leashfenceknotentity, true); pLevel.gameEvent(GameEvent.BLOCK_ATTACH, pPos, GameEvent.Context.of(pPlayer)); cir.setReturnValue(InteractionResult.SUCCESS); } diff --git a/src/main/java/com/r3944realms/leashedplayer/mixin/server/MixinServerGamePacketListenerImpl.java b/src/main/java/com/r3944realms/leashedplayer/mixin/server/MixinServerGamePacketListenerImpl.java index 44fc5bf..5b5d4b7 100644 --- a/src/main/java/com/r3944realms/leashedplayer/mixin/server/MixinServerGamePacketListenerImpl.java +++ b/src/main/java/com/r3944realms/leashedplayer/mixin/server/MixinServerGamePacketListenerImpl.java @@ -3,7 +3,6 @@ package com.r3944realms.leashedplayer.mixin.server; import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry; import com.r3944realms.leashedplayer.content.gamerules.Server.TeleportWithLeashedPlayers; import com.r3944realms.leashedplayer.modInterface.PlayerLeashable; - import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.world.entity.Entity; @@ -17,6 +16,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.*; import java.util.stream.Collectors; + import static com.r3944realms.leashedplayer.utils.Logger.logger; @Mixin(ServerGamePacketListenerImpl.class) public class MixinServerGamePacketListenerImpl { diff --git a/src/main/java/com/r3944realms/leashedplayer/modInterface/ILivingEntityExtension.java b/src/main/java/com/r3944realms/leashedplayer/modInterface/ILivingEntityExtension.java index 8eb1377..32e7165 100644 --- a/src/main/java/com/r3944realms/leashedplayer/modInterface/ILivingEntityExtension.java +++ b/src/main/java/com/r3944realms/leashedplayer/modInterface/ILivingEntityExtension.java @@ -12,4 +12,17 @@ public interface ILivingEntityExtension { * @param length 拴绳的长度(Float) */ void setLeashLength(float length); + + /** + * 设置超出断裂长度后等待时间,如果时间到仍超出则会执行断裂操作 + * @apiNote 该为服务器方法,只能在服务器端调用,切勿在客户端线程调用 + * @param keepTick 等待tick(int) + */ + void setKeepLeashTick(int keepTick); + /** + * 获取超出断裂长度后等待时间,如果时间到仍超出则会执行断裂操作 + * @apiNote 该为服务器方法,只能在服务器端调用,切勿在客户端线程调用 + * @return keepTick 等待tick(int) + */ + int getKeepLeashTick(); } diff --git a/src/main/resources/assets/leashedplayer/textures/entity/projectiles/leash_rope_arrow.png b/src/main/resources/assets/leashedplayer/textures/entity/projectiles/leash_rope_arrow.png index 2933376..c2a3b37 100644 Binary files a/src/main/resources/assets/leashedplayer/textures/entity/projectiles/leash_rope_arrow.png and b/src/main/resources/assets/leashedplayer/textures/entity/projectiles/leash_rope_arrow.png differ diff --git a/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_0.png b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_0.png new file mode 100644 index 0000000..7cd8732 Binary files /dev/null and b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_0.png differ diff --git a/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_1.png b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_1.png new file mode 100644 index 0000000..5f5c393 Binary files /dev/null and b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_1.png differ diff --git a/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_2.png b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_2.png new file mode 100644 index 0000000..2b67a06 Binary files /dev/null and b/src/main/resources/assets/leashedplayer/textures/item/bow_lra_pulling_2.png differ diff --git a/src/main/resources/assets/leashedplayer/textures/item/crossbow_leash_rope_arrow.png b/src/main/resources/assets/leashedplayer/textures/item/crossbow_leash_rope_arrow.png new file mode 100644 index 0000000..7517484 Binary files /dev/null and b/src/main/resources/assets/leashedplayer/textures/item/crossbow_leash_rope_arrow.png differ diff --git a/src/main/resources/assets/leashedplayer/textures/item/leash_rope_arrow.png b/src/main/resources/assets/leashedplayer/textures/item/leash_rope_arrow.png index 771bb73..83cec87 100644 Binary files a/src/main/resources/assets/leashedplayer/textures/item/leash_rope_arrow.png and b/src/main/resources/assets/leashedplayer/textures/item/leash_rope_arrow.png differ diff --git a/src/main/resources/assets/minecraft/models/item/bow.json b/src/main/resources/assets/minecraft/models/item/bow.json new file mode 100644 index 0000000..301bbd3 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/bow.json @@ -0,0 +1,70 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/bow" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ -80, 260, -40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "thirdperson_lefthand": { + "rotation": [ -80, -280, 40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 90, -25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + } + }, + "overrides": [ + { + "predicate": { + "pulling": 1 + }, + "model": "minecraft:item/bow_pulling_0" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.65 + }, + "model": "minecraft:item/bow_pulling_1" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.9 + }, + "model": "minecraft:item/bow_pulling_2" + }, + { + "predicate": { + "leash_rope_arrow_pulling": 1 + }, + "model": "leashedplayer:item/bow_lra_pulling_0" + }, + { + "predicate": { + "leash_rope_arrow_pulling": 1, + "pull": 0.65 + }, + "model": "leashedplayer:item/bow_lra_pulling_1" + }, + { + "predicate": { + "leash_rope_arrow_pulling": 1, + "pull": 0.9 + }, + "model": "leashedplayer:item/bow_lra_pulling_2" + } + ] +} diff --git a/src/main/resources/assets/minecraft/models/item/crossbow.json b/src/main/resources/assets/minecraft/models/item/crossbow.json new file mode 100644 index 0000000..e0d0ef9 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/crossbow.json @@ -0,0 +1,70 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/crossbow_standby" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ -90, 0, -60 ], + "translation": [ 2, 0.1, -3 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "thirdperson_lefthand": { + "rotation": [ -90, 0, 30 ], + "translation": [ 2, 0.1, -3 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "firstperson_righthand": { + "rotation": [ -90, 0, -55 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "firstperson_lefthand": { + "rotation": [ -90, 0, 35 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + } + }, + "overrides": [ + { + "predicate": { + "pulling": 1 + }, + "model": "minecraft:item/crossbow_pulling_0" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.58 + }, + "model": "minecraft:item/crossbow_pulling_1" + }, + { + "predicate": { + "pulling": 1, + "pull": 1.0 + }, + "model": "minecraft:item/crossbow_pulling_2" + }, + { + "predicate": { + "charged": 1 + }, + "model": "minecraft:item/crossbow_arrow" + }, + { + "predicate": { + "charged": 1, + "firework": 1 + }, + "model": "minecraft:item/crossbow_firework" + }, + { + "predicate": { + "charged": 1, + "leash_rope_arrow": 1 + }, + "model": "leashedplayer:item/crossbow_leash_rope_arrow" + } + ] +}