2024-09-07

版本0.0.3.1
添加:
1.新的游戏规则KeepLeashNotDropTime(保持拴绳箭实体存活时间
2.新的纹理 包括弓弩材质发射拴绳箭新材质
3.新的配置文件内容
4.所有指令现在 可以同时作用多个玩家对象了
调整:
1.拾取拴绳箭的逻辑, 在落地后2s后可以通过按住Shift靠近后拾取
2.优化逻辑
3. 创造模式拴绳箭拾取逻辑修正
修复:
1.拴繩不能正常掉落的問題
2. data clear节点指令错误(笔误

具體新内容請見 README.md 介紹
This commit is contained in:
叁玖领域 2024-09-07 18:03:02 +08:00
parent 987ec866c3
commit 9dadf48d38
36 changed files with 603 additions and 68 deletions

View File

@ -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]
* `LP.CreateLeashFenceKnotEntityIfAbsent` - 此規則啓用后, 在設置 leashData 時,如果對應方塊坐標上的柵欄沒有拴繩結則會自動創建這個實體並綁定 [默认值: True]
* `LP.KeepLeashNotDropTime` - 此规则决定,当拴绳关系创建时一段时间里,即是距离已经达到了断裂距离,也保持其不断裂 [默认值: 240ticks ,可设置范围[80, 1200]ticks]

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 B

After

Width:  |  Height:  |  Size: 243 B

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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<CommandSourceStack> 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<CommandSourceStack> 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();
// }
// }
}
}

View File

@ -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<String> LeashedPlayerModCommandPrefix;
public static final ModConfigSpec.BooleanValue EnableLeashPlayerCommandPrefix;
public static ModConfigSpec.IntValue MinimumLeashLengthCanBeSet, MaximumLeashLengthCanBeSet;
public static ModConfigSpec.IntValue MinimumLeashLengthCanBeSet, MaximumLeashLengthCanBeSet, TheLeashArrowMaxLifeTime;
public static ModConfigSpec.ConfigValue<Float> 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");

View File

@ -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<CommandSourceStack> 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<CommandSourceStack> getRefPlayersLeashLength = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<ServerPlayer> 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<CommandSourceStack> setSelfLengthLeashLength = context -> {
CommandSourceStack source = context.getSource();
try {
@ -101,10 +115,10 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setLengthLeashLength = context -> {
Command<CommandSourceStack> 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<CommandSourceStack> setRefPlayersLengthLeashLength = context -> {
CommandSourceStack source = context.getSource();
float leashLength = context.getArgument("leashLength", Float.class);
try {
Collection<ServerPlayer> 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<CommandSourceStack> geSelfLeashData = context -> {
CommandSourceStack source = context.getSource();
@ -140,6 +173,24 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> getRefPlayersLeashData = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<ServerPlayer> 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<CommandSourceStack> setSelfLeashDataEntity = context -> {
CommandSourceStack source = context.getSource();
@ -182,6 +233,37 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> setRefPlayersLeashDataEntity = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<ServerPlayer> 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<CommandSourceStack> setRefPlayersLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<ServerPlayer> 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<CommandSourceStack> setRefPlayerLeashDataByBlockPos = context -> {
CommandSourceStack source = context.getSource();
try {
@ -195,6 +277,7 @@ public class LeashCommand {
}
return 0;
};
Command<CommandSourceStack> 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<CommandSourceStack> clearRefPlayersLeashData = context -> {
CommandSourceStack source = context.getSource();
try {
Collection<ServerPlayer> 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<CommandSourceStack> 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<CommandSourceStack> 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()));

View File

@ -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<? extends AbstractArrow> 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;
}
}
}

View File

@ -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<MinecraftServer, GameRules.IntegerValue>) (i, j)->{});
}
}

View File

@ -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<Component> pTooltipComponents, @NotNull TooltipFlag pTooltipFlag) {
//TODO:也许会做
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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<CompoundTag> 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

View File

@ -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 {

View File

@ -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);
}

View File

@ -85,7 +85,7 @@ public abstract class MixinPlayerRenderer extends LivingEntityRenderer<AbstractC
}
if (holder != null) {
if(holder instanceof LeashRopeArrow) {
renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, holder, new Vec3(0,-0.09, 0));//TODO: 待擴展Vec3
renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, holder, new Vec3(0,0, 0));//TODO: 待擴展Vec3
}
else renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, holder);
}
@ -232,11 +232,13 @@ public abstract class MixinPlayerRenderer extends LivingEntityRenderer<AbstractC
poseStack.popPose();
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Unique
protected <E extends Entity> 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;

View File

@ -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);
}

View File

@ -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 {

View File

@ -12,4 +12,17 @@ public interface ILivingEntityExtension {
* @param length 拴绳的长度Float
*/
void setLeashLength(float length);
/**
* 设置超出断裂长度后等待时间如果时间到仍超出则会执行断裂操作
* @apiNote 该为服务器方法只能在服务器端调用切勿在客户端线程调用
* @param keepTick 等待tickint
*/
void setKeepLeashTick(int keepTick);
/**
* 获取超出断裂长度后等待时间如果时间到仍超出则会执行断裂操作
* @apiNote 该为服务器方法只能在服务器端调用切勿在客户端线程调用
* @return keepTick 等待tickint
*/
int getKeepLeashTick();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 B

After

Width:  |  Height:  |  Size: 243 B

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}