2024-10-05

修复了 发射器不能发射箭的BUG
修复了 拴绳箭种类单一的BUG
This commit is contained in:
叁玖领域 2024-10-05 22:56:42 +08:00
parent cf74d05b10
commit 1f6e23e2a1
52 changed files with 1345 additions and 195 deletions

View File

@ -0,0 +1,39 @@
package com.r3944realms.leashedplayer.client.models;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import java.util.function.Function;
public abstract class BasicEntityModel<T extends Entity> extends EntityModel<T> {
public int textureWidth = 64;
public int textureHeight = 32;
protected BasicEntityModel() {
this(RenderType::entityCutoutNoCull);
}
protected BasicEntityModel(Function<ResourceLocation, RenderType> pRenderType) {
super(pRenderType);
}
@Override
public void renderToBuffer(PoseStack p_103013_, VertexConsumer p_103014_, int p_103015_, int p_103016_, float p_103017_, float p_103018_, float p_103019_, float p_103020_) {
this.parts().forEach((p_103030_) -> {
p_103030_.render(p_103013_, p_103014_, p_103015_, p_103016_, p_103017_, p_103018_, p_103019_, p_103020_);
});
}
public abstract Iterable<BasicModelPart> parts();
@Override
public abstract void setupAnim(T p_102618_, float p_102619_, float p_102620_, float p_102621_, float p_102622_, float p_102623_);
@Override
public void prepareMobModel(T p_102614_, float p_102615_, float p_102616_, float p_102617_) {
}
}

View File

@ -0,0 +1,314 @@
package com.r3944realms.leashedplayer.client.models;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.client.event.RenderTooltipEvent;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.core.Direction;
import java.util.Random;
/*
* @since 1.9.0
* Duplicate of ModelPart class which is not final
*/
@OnlyIn(Dist.CLIENT)
public class BasicModelPart {
public float textureWidth = 64.0F;
public float textureHeight = 32.0F;
public int textureOffsetX;
public int textureOffsetY;
public float rotationPointX;
public float rotationPointY;
public float rotationPointZ;
public float rotateAngleX;
public float rotateAngleY;
public float rotateAngleZ;
public boolean mirror;
public boolean showModel = true;
private final ObjectList<BasicModelPart.ModelBox> cubeList = new ObjectArrayList<>();
private final ObjectList<BasicModelPart> childModels = new ObjectArrayList<>();
public BasicModelPart(BasicEntityModel model) {
this.setTextureSize(model.textureWidth, model.textureHeight);
}
public BasicModelPart(BasicEntityModel model, int texOffX, int texOffY) {
this(model.textureWidth, model.textureHeight, texOffX, texOffY);
}
public BasicModelPart(int textureWidthIn, int textureHeightIn, int textureOffsetXIn, int textureOffsetYIn) {
this.setTextureSize(textureWidthIn, textureHeightIn);
this.setTextureOffset(textureOffsetXIn, textureOffsetYIn);
}
private BasicModelPart() {
}
public BasicModelPart getModelAngleCopy() {
BasicModelPart BasicModelPart = new BasicModelPart();
BasicModelPart.copyModelAngles(this);
return BasicModelPart;
}
public void copyModelAngles(BasicModelPart BasicModelPartIn) {
this.rotateAngleX = BasicModelPartIn.rotateAngleX;
this.rotateAngleY = BasicModelPartIn.rotateAngleY;
this.rotateAngleZ = BasicModelPartIn.rotateAngleZ;
this.rotationPointX = BasicModelPartIn.rotationPointX;
this.rotationPointY = BasicModelPartIn.rotationPointY;
this.rotationPointZ = BasicModelPartIn.rotationPointZ;
}
/**
* Sets the current box's rotation points and rotation angles to another box.
*/
public void addChild(BasicModelPart renderer) {
this.childModels.add(renderer);
}
public BasicModelPart setTextureOffset(int x, int y) {
this.textureOffsetX = x;
this.textureOffsetY = y;
return this;
}
public BasicModelPart addBox(String partName, float x, float y, float z, int width, int height, int depth, float delta, int texX, int texY) {
this.setTextureOffset(texX, texY);
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, (float)width, (float)height, (float)depth, delta, delta, delta, this.mirror, false);
return this;
}
public BasicModelPart addBox(float x, float y, float z, float width, float height, float depth) {
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, width, height, depth, 0.0F, 0.0F, 0.0F, this.mirror, false);
return this;
}
public BasicModelPart addBox(float x, float y, float z, float width, float height, float depth, boolean mirrorIn) {
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, width, height, depth, 0.0F, 0.0F, 0.0F, mirrorIn, false);
return this;
}
public void addBox(float x, float y, float z, float width, float height, float depth, float delta) {
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, width, height, depth, delta, delta, delta, this.mirror, false);
}
public void addBox(float x, float y, float z, float width, float height, float depth, float deltaX, float deltaY, float deltaZ) {
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, width, height, depth, deltaX, deltaY, deltaZ, this.mirror, false);
}
public void addBox(float x, float y, float z, float width, float height, float depth, float delta, boolean mirrorIn) {
this.addBox(this.textureOffsetX, this.textureOffsetY, x, y, z, width, height, depth, delta, delta, delta, mirrorIn, false);
}
private void addBox(int texOffX, int texOffY, float x, float y, float z, float width, float height, float depth, float deltaX, float deltaY, float deltaZ, boolean mirorIn, boolean p_228305_13_) {
this.cubeList.add(new BasicModelPart.ModelBox(texOffX, texOffY, x, y, z, width, height, depth, deltaX, deltaY, deltaZ, mirorIn, this.textureWidth, this.textureHeight));
}
public void setRotationPoint(float rotationPointXIn, float rotationPointYIn, float rotationPointZIn) {
this.rotationPointX = rotationPointXIn;
this.rotationPointY = rotationPointYIn;
this.rotationPointZ = rotationPointZIn;
}
public void render(PoseStack matrixStackIn, VertexConsumer bufferIn, int packedLightIn, int packedOverlayIn) {
this.render(matrixStackIn, bufferIn, packedLightIn, packedOverlayIn, 1.0F, 1.0F, 1.0F, 1.0F);
}
public void render(PoseStack matrixStackIn, VertexConsumer bufferIn, int packedLightIn, int packedOverlayIn, float red, float green, float blue, float alpha) {
if (this.showModel) {
if (!this.cubeList.isEmpty() || !this.childModels.isEmpty()) {
matrixStackIn.pushPose();
this.translateRotate(matrixStackIn);
this.doRender(matrixStackIn.last(), bufferIn, packedLightIn, packedOverlayIn, red, green, blue, alpha);
for(BasicModelPart BasicModelPart : this.childModels) {
BasicModelPart.render(matrixStackIn, bufferIn, packedLightIn, packedOverlayIn, red, green, blue, alpha);
}
matrixStackIn.popPose();
}
}
}
public void translateRotate(PoseStack matrixStackIn) {
matrixStackIn.translate((double)(this.rotationPointX / 16.0F), (double)(this.rotationPointY / 16.0F), (double)(this.rotationPointZ / 16.0F));
if (this.rotateAngleZ != 0.0F) {
matrixStackIn.mulPose(Axis.ZP.rotation(this.rotateAngleZ));
}
if (this.rotateAngleY != 0.0F) {
matrixStackIn.mulPose(Axis.YP.rotation(this.rotateAngleY));
}
if (this.rotateAngleX != 0.0F) {
matrixStackIn.mulPose(Axis.XP.rotation(this.rotateAngleX));
}
}
private void doRender(PoseStack.Pose matrixEntryIn, VertexConsumer bufferIn, int packedLightIn, int packedOverlayIn, float red, float green, float blue, float alpha) {
Matrix4f matrix4f = matrixEntryIn.pose();
Matrix3f matrix3f = matrixEntryIn.normal();
for(BasicModelPart.ModelBox BasicModelPart$modelbox : this.cubeList) {
for(BasicModelPart.TexturedQuad BasicModelPart$texturedquad : BasicModelPart$modelbox.quads) {
Vector3f vector3f = new Vector3f(BasicModelPart$texturedquad.normal);
vector3f.mul(matrix3f);
float f = vector3f.x();
float f1 = vector3f.y();
float f2 = vector3f.z();
for(int i = 0; i < 4; ++i) {
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex = BasicModelPart$texturedquad.vertexPositions[i];
float f3 = BasicModelPart$positiontexturevertex.position.x() / 16.0F;
float f4 = BasicModelPart$positiontexturevertex.position.y() / 16.0F;
float f5 = BasicModelPart$positiontexturevertex.position.z() / 16.0F;
Vector4f vector4f = new Vector4f(f3, f4, f5, 1.0F);
vector4f.mul(matrix4f);
bufferIn
.setColor(red, green, blue, alpha)
.addVertex(vector4f.x(), vector4f.y(), vector4f.z())
.setUv(BasicModelPart$positiontexturevertex.textureU, BasicModelPart$positiontexturevertex.textureV)
.setLight(packedLightIn)
.setOverlay(packedOverlayIn)
.setNormal(f, f1, f2);
}
}
}
}
/**
* Returns the model renderer with the new texture parameters.
*/
public BasicModelPart setTextureSize(int textureWidthIn, int textureHeightIn) {
this.textureWidth = (float)textureWidthIn;
this.textureHeight = (float)textureHeightIn;
return this;
}
public BasicModelPart.ModelBox getRandomCube(Random randomIn) {
return this.cubeList.get(randomIn.nextInt(this.cubeList.size()));
}
@OnlyIn(Dist.CLIENT)
public static class ModelBox {
private final BasicModelPart.TexturedQuad[] quads;
public final float posX1;
public final float posY1;
public final float posZ1;
public final float posX2;
public final float posY2;
public final float posZ2;
public ModelBox(int texOffX, int texOffY, float x, float y, float z, float width, float height, float depth, float deltaX, float deltaY, float deltaZ, boolean mirorIn, float texWidth, float texHeight) {
this.posX1 = x;
this.posY1 = y;
this.posZ1 = z;
this.posX2 = x + width;
this.posY2 = y + height;
this.posZ2 = z + depth;
this.quads = new BasicModelPart.TexturedQuad[6];
float f = x + width;
float f1 = y + height;
float f2 = z + depth;
x = x - deltaX;
y = y - deltaY;
z = z - deltaZ;
f = f + deltaX;
f1 = f1 + deltaY;
f2 = f2 + deltaZ;
if (mirorIn) {
float f3 = f;
f = x;
x = f3;
}
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex7 = new BasicModelPart.PositionTextureVertex(x, y, z, 0.0F, 0.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex = new BasicModelPart.PositionTextureVertex(f, y, z, 0.0F, 8.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex1 = new BasicModelPart.PositionTextureVertex(f, f1, z, 8.0F, 8.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex2 = new BasicModelPart.PositionTextureVertex(x, f1, z, 8.0F, 0.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex3 = new BasicModelPart.PositionTextureVertex(x, y, f2, 0.0F, 0.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex4 = new BasicModelPart.PositionTextureVertex(f, y, f2, 0.0F, 8.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex5 = new BasicModelPart.PositionTextureVertex(f, f1, f2, 8.0F, 8.0F);
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex6 = new BasicModelPart.PositionTextureVertex(x, f1, f2, 8.0F, 0.0F);
float f4 = (float)texOffX;
float f5 = (float)texOffX + depth;
float f6 = (float)texOffX + depth + width;
float f7 = (float)texOffX + depth + width + width;
float f8 = (float)texOffX + depth + width + depth;
float f9 = (float)texOffX + depth + width + depth + width;
float f10 = (float)texOffY;
float f11 = (float)texOffY + depth;
float f12 = (float)texOffY + depth + height;
this.quads[2] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex4, BasicModelPart$positiontexturevertex3, BasicModelPart$positiontexturevertex7, BasicModelPart$positiontexturevertex}, f5, f10, f6, f11, texWidth, texHeight, mirorIn, Direction.DOWN);
this.quads[3] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex1, BasicModelPart$positiontexturevertex2, BasicModelPart$positiontexturevertex6, BasicModelPart$positiontexturevertex5}, f6, f11, f7, f10, texWidth, texHeight, mirorIn, Direction.UP);
this.quads[1] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex7, BasicModelPart$positiontexturevertex3, BasicModelPart$positiontexturevertex6, BasicModelPart$positiontexturevertex2}, f4, f11, f5, f12, texWidth, texHeight, mirorIn, Direction.WEST);
this.quads[4] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex, BasicModelPart$positiontexturevertex7, BasicModelPart$positiontexturevertex2, BasicModelPart$positiontexturevertex1}, f5, f11, f6, f12, texWidth, texHeight, mirorIn, Direction.NORTH);
this.quads[0] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex4, BasicModelPart$positiontexturevertex, BasicModelPart$positiontexturevertex1, BasicModelPart$positiontexturevertex5}, f6, f11, f8, f12, texWidth, texHeight, mirorIn, Direction.EAST);
this.quads[5] = new BasicModelPart.TexturedQuad(new BasicModelPart.PositionTextureVertex[]{BasicModelPart$positiontexturevertex3, BasicModelPart$positiontexturevertex4, BasicModelPart$positiontexturevertex5, BasicModelPart$positiontexturevertex6}, f8, f11, f9, f12, texWidth, texHeight, mirorIn, Direction.SOUTH);
}
}
@OnlyIn(Dist.CLIENT)
static class PositionTextureVertex {
public final Vector3f position;
public final float textureU;
public final float textureV;
public PositionTextureVertex(float x, float y, float z, float texU, float texV) {
this(new Vector3f(x, y, z), texU, texV);
}
public BasicModelPart.PositionTextureVertex setTextureUV(float texU, float texV) {
return new BasicModelPart.PositionTextureVertex(this.position, texU, texV);
}
public PositionTextureVertex(Vector3f posIn, float texU, float texV) {
this.position = posIn;
this.textureU = texU;
this.textureV = texV;
}
}
@OnlyIn(Dist.CLIENT)
static class TexturedQuad {
public final BasicModelPart.PositionTextureVertex[] vertexPositions;
public final Vector3f normal;
public TexturedQuad(BasicModelPart.PositionTextureVertex[] positionsIn, float u1, float v1, float u2, float v2, float texWidth, float texHeight, boolean mirrorIn, Direction directionIn) {
this.vertexPositions = positionsIn;
float f = 0.0F / texWidth;
float f1 = 0.0F / texHeight;
positionsIn[0] = positionsIn[0].setTextureUV(u2 / texWidth - f, v1 / texHeight + f1);
positionsIn[1] = positionsIn[1].setTextureUV(u1 / texWidth + f, v1 / texHeight + f1);
positionsIn[2] = positionsIn[2].setTextureUV(u1 / texWidth + f, v2 / texHeight - f1);
positionsIn[3] = positionsIn[3].setTextureUV(u2 / texWidth - f, v2 / texHeight - f1);
if (mirrorIn) {
int i = positionsIn.length;
for(int j = 0; j < i / 2; ++j) {
BasicModelPart.PositionTextureVertex BasicModelPart$positiontexturevertex = positionsIn[j];
positionsIn[j] = positionsIn[i - 1 - j];
positionsIn[i - 1 - j] = BasicModelPart$positiontexturevertex;
}
}
this.normal = directionIn.step();
if (mirrorIn) {
this.normal.mul(-1.0F, 1.0F, 1.0F);
}
}
}
}

View File

@ -0,0 +1,166 @@
package com.r3944realms.leashedplayer.content.entities;
import com.r3944realms.leashedplayer.content.entities.props.ChainLeashable;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.decoration.BlockAttachedEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.WallBlock;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class ChainTieEntity extends BlockAttachedEntity {
public ChainTieEntity(EntityType<? extends BlockAttachedEntity> type, Level worldIn, BlockPos hangingPositionIn) {
super(type, worldIn, hangingPositionIn);
this.setPos(hangingPositionIn.getX() + 0.5D, hangingPositionIn.getY(), hangingPositionIn.getZ() + 0.5D);
}
public ChainTieEntity(EntityType<? extends BlockAttachedEntity> hangingEntityEntityType, Level level) {
super(hangingEntityEntityType, level);
}
public void playPlacementSound() {
this.playSound(SoundEvents.ARMOR_EQUIP_CHAIN.value(), 1.0F, 1.0F);
}
public static ChainTieEntity createTie(Level worldIn, BlockPos fence) {
ChainTieEntity entityChainTie = new ChainTieEntity(ModEntityRegister.CHAIN_TIE.get(), worldIn, fence);
worldIn.addFreshEntity(entityChainTie);
entityChainTie.playPlacementSound();
return entityChainTie;
}
public static ChainTieEntity getOrCreateKnot(Level pLevel, BlockPos pPos) {
int i = pPos.getX();
int j = pPos.getY();
int k = pPos.getZ();
for (ChainTieEntity chainTieEntity : pLevel.getEntitiesOfClass(
ChainTieEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
)) {
if (chainTieEntity.getPos().equals(pPos)) {
return chainTieEntity;
}
}
ChainTieEntity chainTieEntity = createTie(pLevel, pPos);
pLevel.addFreshEntity(chainTieEntity);
return chainTieEntity;
}
@Override
protected void recalculateBoundingBox() {
this.setPosRaw(
this.pos.getX() + 0.5D,
this.pos.getY() + 0.5D,
this.pos.getZ() + 0.5D
);
double xSize = 0.3D;
double ySize = 0.875D;
this.setBoundingBox(
new AABB(
this.getX() - xSize,
this.getY() - 0.5,
this.getZ() - xSize,
this.getX() + xSize,
this.getY() + ySize - 0.5,
this.getZ() + xSize
)
);
}
@Override
public @NotNull InteractionResult interact(@NotNull Player pPlayer, @NotNull InteractionHand pHand) {
if (this.level().isClientSide) {
return InteractionResult.SUCCESS;
} else {
boolean flag = false;
List<ChainLeashable> list = ChainLeashable.leashableInArea(this.level(), this.getPos(), chainLeashable -> {
Entity entity = chainLeashable.getLeashHolder();
return entity == pPlayer || entity == this;
});
for (ChainLeashable ChainLeashable : list) {
if (ChainLeashable.getLeashHolder() == pPlayer) {
ChainLeashable.setLeashedTo(this, true);
flag = true;
}
}
boolean flag1 = false;
if (!flag) {
this.discard();
if (pPlayer.getAbilities().instabuild) {
for (ChainLeashable ChainLeashable : list) {
if (ChainLeashable.isLeashed() && ChainLeashable.getLeashHolder() == this) {
ChainLeashable.dropLeash(true, false);
flag1 = true;
}
}
}
}
if (flag || flag1) {
this.gameEvent(GameEvent.BLOCK_ATTACH, pPlayer);
}
return InteractionResult.CONSUME;
}
}
@Override
public boolean shouldRenderAtSqrDistance(double distance) {
return distance < 1024.0D;
}
@Override
public boolean survives() {
return this.level().getBlockState(this.pos).getBlock() instanceof WallBlock;
}
@Override
public void dropItem(@Nullable Entity pEntity) {
this.playSound(SoundEvents.ARMOR_EQUIP_CHAIN.value(), 1.0F, 1.0F);
}
@Override
protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) {
}
@Override
public void setPos(double x, double y, double z) {
super.setPos(Mth.floor(x) + 0.5D, Mth.floor(y) + 0.5D, Mth.floor(z) + 0.5D);
}
@Override
public @NotNull Packet<ClientGamePacketListener> getAddEntityPacket(@NotNull ServerEntity pEntity) {
return new ClientboundAddEntityPacket(this, 0, this.getPos());
}
@Override
public @NotNull Vec3 getRopeHoldPosition(float pPartialTicks) {
return this.getPosition(pPartialTicks).add(0.0, 0.2, 0.0);
}
@Override
public ItemStack getPickResult() {
return new ItemStack(Items.CHAIN);
}
}

View File

@ -0,0 +1,4 @@
package com.r3944realms.leashedplayer.client.models;
public class ChainTieModel extends BasicEnti{
}

View File

@ -0,0 +1,210 @@
package com.r3944realms.leashedplayer.content.entities.props;
import com.mojang.datafixers.util.Either;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Predicate;
public interface ChainLeashable {
String LEASH_TAG = "chain_leash";
@Nullable
ChainLeashable.ChainData getLeashData();
void setLeashData(@Nullable ChainLeashable.ChainData pLeashData);
default boolean isLeashed() {
return this.getLeashData() != null && this.getLeashData().leashHolder != null;
}
default boolean mayBeLeashed() {
return this.getLeashData() != null;
}
default boolean canHaveALeashAttachedToIt() {
return this.canBeLeashed() && !this.isLeashed();
}
default boolean canBeLeashed() {
return true;
}
default boolean handleLeashAtDistance(Entity pLeashHolder, float pDistance) {
return true;
}
default void leashTooFarBehaviour() {
this.dropLeash(true, true);
}
default void closeRangeLeashBehaviour(Entity pEntity) {
}
default void elasticRangeLeashBehaviour(Entity pLeashHolder, float pDistance) {
legacyElasticRangeLeashBehaviour((Entity & ChainLeashable)this, pLeashHolder, pDistance);
}
@Nullable
default Entity getLeashHolder() {
return getLeashHolder((Entity & ChainLeashable)this);
}
private static <E extends Entity & ChainLeashable> void legacyElasticRangeLeashBehaviour(E pEntity, Entity pLeashHolder, float pDistance) {
double d0 = (pLeashHolder.getX() - pEntity.getX()) / (double)pDistance;
double d1 = (pLeashHolder.getY() - pEntity.getY()) / (double)pDistance;
double d2 = (pLeashHolder.getZ() - pEntity.getZ()) / (double)pDistance;
pEntity.setDeltaMovement(
pEntity.getDeltaMovement().add(Math.copySign(d0 * d0 * 0.4, d0), Math.copySign(d1 * d1 * 0.4, d1), Math.copySign(d2 * d2 * 0.4, d2))
);
}
@Nullable
private static <E extends Entity & ChainLeashable> Entity getLeashHolder(E pEntity) {
ChainLeashable.ChainData chainLeashable$chaindata = pEntity.getLeashData();
if (chainLeashable$chaindata == null) {
return null;
} else {
if (chainLeashable$chaindata.delayedLeashHolderId != 0 && pEntity.level().isClientSide) {
Entity entity = pEntity.level().getEntity(chainLeashable$chaindata.delayedLeashHolderId);
if (entity instanceof Entity) {
chainLeashable$chaindata.setLeashHolder(entity);
}
}
return chainLeashable$chaindata.leashHolder;
}
}
default void setLeashedTo(Entity pLeashHolder, boolean pBroadcastPacket) {
setLeashedTo((Entity & ChainLeashable)this, pLeashHolder, pBroadcastPacket);
}
static List<ChainLeashable> leashableInArea(Level pLevel, BlockPos pPos, Predicate<ChainLeashable> pPredicate) {
double d0 = 7.0;
int i = pPos.getX();
int j = pPos.getY();
int k = pPos.getZ();
AABB aabb = new AABB((double)i - 7.0, (double)j - 7.0, (double)k - 7.0, (double)i + 7.0, (double)j + 7.0, (double)k + 7.0);
return pLevel.getEntitiesOfClass(Entity.class, aabb, p_353023_ -> p_353023_ instanceof ChainLeashable chainLeashable && pPredicate.test(chainLeashable)).stream().map(ChainLeashable.class::cast).toList();
}
private static <E extends Entity & ChainLeashable> void setLeashedTo(E pEntity, Entity pLeashHolder, boolean pBroadcastPacket) {
ChainLeashable.ChainData chainLeashable$chaindata = pEntity.getLeashData();
if (chainLeashable$chaindata == null) {
chainLeashable$chaindata = new ChainLeashable.ChainData(pLeashHolder);
pEntity.setLeashData(chainLeashable$chaindata);
} else {
chainLeashable$chaindata.setLeashHolder(pLeashHolder);
}
if (pBroadcastPacket && pEntity.level() instanceof ServerLevel serverlevel) {
//TODO自写Packet ClientboundSetEntityLinkPacket(pEntity, pLeashHolder)
serverlevel.getChunkSource().broadcast(pEntity, new ClientboundSetEntityLinkPacket(pEntity, pLeashHolder));
}
if (pEntity.isPassenger()) {
pEntity.stopRiding();
}
}
default void dropLeash(boolean pBroadcastPacket, boolean pDropItem) {
dropLeash((Entity & ChainLeashable)this, pBroadcastPacket, pDropItem);
}
private static <E extends Entity & ChainLeashable> void dropLeash(E pEntity, boolean pBroadcastPacket, boolean pDropItem) {
ChainLeashable.ChainData chainLeashable$chaindata = pEntity.getLeashData();
if (chainLeashable$chaindata != null && chainLeashable$chaindata.leashHolder != null) {
pEntity.setLeashData(null);
if (!pEntity.level().isClientSide && pDropItem) {
pEntity.spawnAtLocation(Items.CHAIN);
}
if (pBroadcastPacket && pEntity.level() instanceof ServerLevel serverlevel) {
serverlevel.getChunkSource().broadcast(pEntity, new ClientboundSetEntityLinkPacket(pEntity, null));
}
}
}
static <E extends Entity & ChainLeashable> void tickLeash(E pEntity) {
ChainLeashable.ChainData chainLeashable$chaindata = pEntity.getLeashData();
if (chainLeashable$chaindata != null && chainLeashable$chaindata.delayedLeashInfo != null) {
restoreLeashFromSave(pEntity, chainLeashable$chaindata);
}
if (chainLeashable$chaindata != null && chainLeashable$chaindata.leashHolder != null) {
if (!pEntity.isAlive() || !chainLeashable$chaindata.leashHolder.isAlive()) {
dropLeash(pEntity, true, true);
}
Entity entity = pEntity.getLeashHolder();
if (entity != null && entity.level() == pEntity.level()) {
float f = pEntity.distanceTo(entity);
if (!pEntity.handleLeashAtDistance(entity, f)) {
return;
}
if ((double)f > 10.0) {
pEntity.leashTooFarBehaviour();
} else if ((double)f > 6.0) {
pEntity.elasticRangeLeashBehaviour(entity, f);
pEntity.checkSlowFallDistance();
} else {
pEntity.closeRangeLeashBehaviour(entity);
}
}
}
}
private static <E extends Entity & ChainLeashable> void restoreLeashFromSave(E pEntity, ChainLeashable.ChainData pLeashData) {
if (pLeashData.delayedLeashInfo != null && pEntity.level() instanceof ServerLevel serverlevel) {
Optional<UUID> optional1 = pLeashData.delayedLeashInfo.left();
Optional<BlockPos> optional = pLeashData.delayedLeashInfo.right();
if (optional1.isPresent()) {
Entity entity = serverlevel.getEntity(optional1.get());
if (entity != null) {
setLeashedTo(pEntity, entity, true);
return;
}
} else if (optional.isPresent()) {
setLeashedTo(pEntity, LeashFenceKnotEntity.getOrCreateKnot(serverlevel, optional.get()), true);
return;
}
if (pEntity.tickCount > 100) {
pEntity.spawnAtLocation(Items.LEAD);
pEntity.setLeashData(null);
}
}
}
final class ChainData {
public int delayedLeashHolderId;
@Nullable
public Entity leashHolder;
@Nullable
public Either<UUID, BlockPos> delayedLeashInfo;
ChainData(@org.jetbrains.annotations.Nullable Either<UUID, BlockPos> pDelayedLeashInfo) {
this.delayedLeashInfo = pDelayedLeashInfo;
}
public ChainData(@org.jetbrains.annotations.Nullable Entity pLeashHolder) {
this.leashHolder = pLeashHolder;
}
ChainData(int pDelayedLeashInfoId) {
this.delayedLeashHolderId = pDelayedLeashInfoId;
}
public void setLeashHolder(Entity pLeashHolder) {
this.leashHolder = pLeashHolder;
this.delayedLeashInfo = null;
this.delayedLeashHolderId = 0;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 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=MIT
# The mod version. See https://semver.org/
mod_version=0.0.3.6
mod_version=0.0.3.7
# 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,7 +1,8 @@
// 1.21.1 2024-09-11T16:30:11.5982305 Item Models: leashedplayer
// 1.21.1 2024-10-05T22:32:01.8406652 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
bb0d76077719c83c8a8bd4346a24ea1766175125 assets/leashedplayer/models/item/fabric.json
114d3cc5832ef047403114504483c6f3ea07e77c assets/leashedplayer/models/item/leash_rope_arrow.json
c4748995a5fe190d20e3bd16f4b2244164ec0f83 assets/leashedplayer/models/item/spectral_leash_rope_arrow.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2024-09-05T15:23:52.4523518 Tags for minecraft:item mod id leashedplayer
a8cd7ac5b7e37b7dea044004a42a2f137d4027d6 data/minecraft/tags/item/arrows.json
// 1.21.1 2024-10-05T22:32:01.8406652 Tags for minecraft:item mod id leashedplayer
36c1cccc1dfa448620c4e9cbc4a7d73986ff9e47 data/minecraft/tags/item/arrows.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2024-09-11T16:30:11.6002137 Languages: en_us for mod: leashedplayer
c3d8ea4a7d24b56bd6b701c531aab3132cdc6da9 assets/leashedplayer/lang/en_us.json
// 1.21.1 2024-10-05T22:32:01.8406652 Languages: en_us for mod: leashedplayer
27fb1feca9c95470e67902e0a5287fa717f71137 assets/leashedplayer/lang/en_us.json

View File

@ -1,3 +1,7 @@
// 1.21.1 2024-09-05T13:20:35.9705404 Recipes
// 1.21.1 2024-10-05T22:33:13.2484086 Recipes
1b45d1ad8dc73f1787c97777ad13d9771c9e0ad1 data/leashedplayer/advancement/recipes/misc/leash_rope_arrow.json
974d74538b3e172946f2e169036b453b6eb6bc0a data/leashedplayer/recipe/leash_rope_arrow.json
c0e05f359296d3e28573fa1b205ac44736376622 data/minecraft/advancement/recipes/misc/spectral_leash_rope_arrow_with_glowstone_dust.json
131fcbef603bfde7204d8e1ad15e4544696926bf data/minecraft/advancement/recipes/misc/spectral_leash_rope_arrow_with_leash_rope_arrow.json
bb5909aa91d878c8f0ef9999881cfe89532509dd data/minecraft/recipe/spectral_leash_rope_arrow_with_glowstone_dust.json
a1381da885fbedec01243c78afbb0a50ca803ee4 data/minecraft/recipe/spectral_leash_rope_arrow_with_leash_rope_arrow.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2024-09-11T16:30:11.5982305 Languages: zh_cn for mod: leashedplayer
7e38a6c0cc14d7f6f362f97b2a00ca1ab2626c68 assets/leashedplayer/lang/zh_cn.json
// 1.21.1 2024-10-05T22:32:01.8406652 Languages: zh_cn for mod: leashedplayer
cf1999519d9de039d6a7d3e6f241f67b68c968ed assets/leashedplayer/lang/zh_cn.json

View File

@ -1,4 +1,5 @@
// 1.21.1 2024-09-09T15:52:23.955795 Advancements
// 1.21.1 2024-10-05T22:48:57.4441437 Advancements
4d97adba079f1966090a52443bb439319f550680 data/leashedplayer/advancement/advancement_leash_arrow.json
f16184b81ea35a0fbd8f2c49b085a96c32818c69 data/leashedplayer/advancement/dog_running_player.json
bce12ed339b3b0fded263ba039f7a4e6fcfb84ca data/leashedplayer/advancement/follow_arrow.json
29911bbed5a1b7ede2b08d82e6716cd9463bc061 data/leashedplayer/advancement/leashed_friend.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2024-09-11T16:30:11.5962153 Languages: zh_tw for mod: leashedplayer
1b05b79582ac4bce69560b88179dd216490ec0fe assets/leashedplayer/lang/zh_tw.json
// 1.21.1 2024-10-05T22:32:01.8406652 Languages: zh_tw for mod: leashedplayer
8d4b3e4d8f0513352a7ef4e1373be64f4d77f9cd assets/leashedplayer/lang/zh_tw.json

View File

@ -1,4 +1,6 @@
{
"advancement.leashedplayer.advancement_leash_arrow": "More advanced flash arrow with a Tether?",
"advancement.leashedplayer.advancement_leash_arrow.desc": "Well, apart from glowing, there doesn't seem to be any other difference",
"advancement.leashedplayer.dog_running_player": "It's Walking human time.",
"advancement.leashedplayer.dog_running_player.desc": "In the park where dogs are not allowed to be walked, the dog decided to walk the human instead",
"advancement.leashedplayer.follow_arrow": "Launch!!!",
@ -7,12 +9,13 @@
"advancement.leashedplayer.leash_arrow.desc": "Maybe you can using it to shoot some mob?",
"advancement.leashedplayer.leash_start": "The Power of Traction",
"advancement.leashedplayer.leash_start.desc": "Journey to becoming a Leash Expert",
"advancement.leashedplayer.leashed_friend": "Bond by Rope",
"advancement.leashedplayer.leashed_friend.desc": "bond player with lead",
"advancement.leashedplayer.leashed_friend": "Be bound by Rope",
"advancement.leashedplayer.leashed_friend.desc": "Be Bond by player with lead",
"advancement.leashedplayer.leashed_self": "Stable Connection",
"advancement.leashedplayer.leashed_self.desc": "“Restrain oneself with a rope",
"creativetab.leashedplayer.leashedplayer_tab": "Leashed Player",
"entity.leashedplayer.leash_rope_arrow": "Leash Rope Arrow",
"entity.leashedplayer.spectral_leash_rope_arrow": "Spectral Leash Rope Arrow",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent": "Create Leash Fence Knot Entity if absent",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent.description": "Create LeashKnot Entity if it's absent on fence",
"gamerule.LP.KeepLeashNotDropTime": "Keep leash alive Time",
@ -22,6 +25,7 @@
"item.leash_rope_arrow.description": "Arrows with ropes attached?",
"item.leashedplayer.fabric": "Fabric",
"item.leashedplayer.leash_rope_arrow": "Leash Rope Arrow",
"item.leashedplayer.spectral_leash_rope_arrow": "Spectral Leash Rope Arrow",
"leashedplayer.command.leash.message.leash.data.clear": "%1$s's LeashData(LeashHolderEntity: %2$s) now is clear",
"leashedplayer.command.leash.message.leash.data.clear.leash.clear.failed.no_data": "%1$s has no LeashData can be clear",
"leashedplayer.command.leash.message.leash.data.null": "%1$s has no LeashDataEntity",

View File

@ -1,4 +1,6 @@
{
"advancement.leashedplayer.advancement_leash_arrow": "更闪亮的拴绳箭?",
"advancement.leashedplayer.advancement_leash_arrow.desc": "嗯,除了发光,似乎没有什么其它不同了",
"advancement.leashedplayer.dog_running_player": "遛“人”时间",
"advancement.leashedplayer.dog_running_player.desc": "公园不能遛狗,于是狗站起来遛人",
"advancement.leashedplayer.follow_arrow": "启航!!!",
@ -8,11 +10,12 @@
"advancement.leashedplayer.leash_start": "牵引之力",
"advancement.leashedplayer.leash_start.desc": "拴绳大师之路",
"advancement.leashedplayer.leashed_friend": "拴绳链接",
"advancement.leashedplayer.leashed_friend.desc": "用拴绳链接玩家",
"advancement.leashedplayer.leashed_friend.desc": "被玩家用拴绳链接",
"advancement.leashedplayer.leashed_self": "稳固联结",
"advancement.leashedplayer.leashed_self.desc": "用拴绳拴住自己",
"creativetab.leashedplayer.leashedplayer_tab": "可拴玩家",
"entity.leashedplayer.leash_rope_arrow": "拴绳箭",
"entity.leashedplayer.spectral_leash_rope_arrow": "拴绳光灵箭",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent": "如果缺失则创建拴绳结",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent.description": "如果在栅栏处缺失拴绳结,则创建它",
"gamerule.LP.KeepLeashNotDropTime": "保持拴绳不掉落的时间",
@ -22,6 +25,7 @@
"item.leash_rope_arrow.description": "带有拴绳的箭矢?",
"item.leashedplayer.fabric": "Fabric",
"item.leashedplayer.leash_rope_arrow": "拴绳箭",
"item.leashedplayer.spectral_leash_rope_arrow": "拴绳光灵箭",
"leashedplayer.command.leash.message.leash.data.clear": "%1$s的拴绳数据拴绳持有者实体%2$s现在已清除",
"leashedplayer.command.leash.message.leash.data.clear.leash.clear.failed.no_data": "%1$s沒有拴绳数据可清除",
"leashedplayer.command.leash.message.leash.data.null": "%1$s沒有拴绳数据实体",

View File

@ -1,4 +1,6 @@
{
"advancement.leashedplayer.advancement_leash_arrow": "更閃亮的拴繩箭?",
"advancement.leashedplayer.advancement_leash_arrow.desc": "嗯,除了發光,其它好像沒什麽不同",
"advancement.leashedplayer.dog_running_player": "遛“人”時間",
"advancement.leashedplayer.dog_running_player.desc": "公園裏不許遛狗,於是狗站起來遛人",
"advancement.leashedplayer.follow_arrow": "啓航!!!",
@ -8,11 +10,12 @@
"advancement.leashedplayer.leash_start": "牽引之力",
"advancement.leashedplayer.leash_start.desc": "拴繩大師之路",
"advancement.leashedplayer.leashed_friend": "拴繩鏈接",
"advancement.leashedplayer.leashed_friend.desc": "用拴繩鏈接玩家",
"advancement.leashedplayer.leashed_friend.desc": "被玩家用拴繩鏈接",
"advancement.leashedplayer.leashed_self": "穩固聯結",
"advancement.leashedplayer.leashed_self.desc": "用栓繩拴住自己",
"creativetab.leashedplayer.leashedplayer_tab": "可拴玩家",
"entity.leashedplayer.leash_rope_arrow": "拴繩箭",
"entity.leashedplayer.spectral_leash_rope_arrow": "拴繩光靈箭",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent": "如果缺失則創建拴繩結",
"gamerule.LP.CreateLeashFenceKnotEntityIfAbsent.description": "如果在柵欄処缺失拴繩結,則創建它",
"gamerule.LP.KeepLeashNotDropTime": "保持其不掉落的時間",
@ -22,6 +25,7 @@
"item.leash_rope_arrow.description": "帶有拴繩的箭矢?",
"item.leashedplayer.fabric": "Fabric",
"item.leashedplayer.leash_rope_arrow": "拴繩箭",
"item.leashedplayer.spectral_leash_rope_arrow": "拴繩光靈箭",
"leashedplayer.command.leash.message.leash.data.clear": "%1$s的拴繩數據拴繩持有者實體%2$s現在已清除",
"leashedplayer.command.leash.message.leash.data.clear.leash.clear.failed.no_data": "%1$s沒有拴繩數據實體可被清除",
"leashedplayer.command.leash.message.leash.data.null": "%1$s沒有拴繩數據實體",

View File

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

View File

@ -0,0 +1,35 @@
{
"parent": "leashedplayer:leash_arrow",
"criteria": {
"has_flash_leash_rope_item": {
"conditions": {
"items": [
{
"items": "leashedplayer:spectral_leash_rope_arrow"
}
]
},
"trigger": "minecraft:inventory_changed"
}
},
"display": {
"announce_to_chat": false,
"description": {
"translate": "advancement.leashedplayer.advancement_leash_arrow.desc"
},
"hidden": true,
"icon": {
"count": 1,
"id": "leashedplayer:spectral_leash_rope_arrow"
},
"title": {
"translate": "advancement.leashedplayer.advancement_leash_arrow"
}
},
"requirements": [
[
"has_flash_leash_rope_item"
]
],
"sends_telemetry_event": true
}

View File

@ -0,0 +1,43 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_glowstone_dust": {
"conditions": {
"items": [
{
"items": "minecraft:glowstone_dust"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_lead": {
"conditions": {
"items": [
{
"items": "minecraft:lead"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "minecraft:spectral_leash_rope_arrow_with_glowstone_dust"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_lead",
"has_glowstone_dust"
]
],
"rewards": {
"recipes": [
"minecraft:spectral_leash_rope_arrow_with_glowstone_dust"
]
}
}

View File

@ -0,0 +1,43 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_lead": {
"conditions": {
"items": [
{
"items": "minecraft:lead"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_spectral_arrow": {
"conditions": {
"items": [
{
"items": "minecraft:spectral_arrow"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "minecraft:spectral_leash_rope_arrow_with_leash_rope_arrow"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_lead",
"has_spectral_arrow"
]
],
"rewards": {
"recipes": [
"minecraft:spectral_leash_rope_arrow_with_leash_rope_arrow"
]
}
}

View File

@ -0,0 +1,21 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"#": {
"item": "leashedplayer:leash_rope_arrow"
},
"$": {
"item": "minecraft:glowstone_dust"
}
},
"pattern": [
" $ ",
"$#$",
" $ "
],
"result": {
"count": 1,
"id": "leashedplayer:spectral_leash_rope_arrow"
}
}

View File

@ -0,0 +1,16 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "minecraft:lead"
},
{
"item": "minecraft:spectral_arrow"
}
],
"result": {
"count": 1,
"id": "leashedplayer:spectral_leash_rope_arrow"
}
}

View File

@ -1,5 +1,6 @@
{
"values": [
"leashedplayer:leash_rope_arrow"
"leashedplayer:leash_rope_arrow",
"leashedplayer:spectral_leash_rope_arrow"
]
}

View File

@ -1,9 +1,11 @@
package com.r3944realms.leashedplayer;
import com.r3944realms.leashedplayer.client.renders.LeashRopeArrowRenderer;
import com.r3944realms.leashedplayer.client.renders.entities.LeashRopeArrowRenderer;
import com.r3944realms.leashedplayer.client.renders.entities.SpectralLeashRopeArrowRenderer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.content.items.type.ILeashRopeArrow;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
@ -23,11 +25,11 @@ public class ClientEventHandler {
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;
return chargedProjectiles != null && (chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) || chargedProjectiles.contains(ModItemRegister.SPECTRAL_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
(pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && ILeashRopeArrow.isLeashRopeArrow(pStack, pEntity)) ? 1.0F: 0.0F
));
});
@ -35,6 +37,7 @@ public class ClientEventHandler {
@SubscribeEvent
public static void RegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new);
event.registerEntityRenderer(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), SpectralLeashRopeArrowRenderer::new);
}
}

View File

@ -2,7 +2,10 @@ package com.r3944realms.leashedplayer;
import com.mojang.brigadier.CommandDispatcher;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.items.ModCreativeTab;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.level.block.DispenserBlock;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
@ -23,6 +26,8 @@ public class CommonEventHandler {
public static class Mod extends CommonEventHandler {
@SubscribeEvent
public static void onCommonSetup(FMLCommonSetupEvent event) {
DispenserBlock.registerProjectileBehavior(ModItemRegister.LEASH_ROPE_ARROW.get());
DispenserBlock.registerProjectileBehavior(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get());
// NeoForge.EVENT_BUS.addListener(Mod::onPlayerTick);
}
// public static void onPlayerTick(PlayerTickEvent.Pre event) {

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.entities;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;

View File

@ -0,0 +1,23 @@
package com.r3944realms.leashedplayer.client.renders.entities;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
import net.minecraft.client.renderer.entity.ArrowRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import org.jetbrains.annotations.NotNull;
@OnlyIn(Dist.CLIENT)
public class SpectralLeashRopeArrowRenderer extends ArrowRenderer<SpectralLeashRopeArrow> {
public static final ResourceLocation SPECTRAL_LEASH_ROPE_ARROW = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/entity/projectiles/spectral_leash_rope_arrow.png");
public SpectralLeashRopeArrowRenderer(EntityRendererProvider.Context pContext) {
super(pContext);
}
@Override
public @NotNull ResourceLocation getTextureLocation(@NotNull SpectralLeashRopeArrow pEntity) {
return SPECTRAL_LEASH_ROPE_ARROW;
}
}

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.gui;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.vertex.PoseStack;

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.LeashedPlayer;

View File

@ -1,4 +1,4 @@
package com.r3944realms.leashedplayer.client.renders;
package com.r3944realms.leashedplayer.client.renders.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;

View File

@ -3,7 +3,7 @@ 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.type.LeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
@ -26,176 +26,176 @@ 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);
}
protected LeashRopeArrow(double pX, double pY, double pZ, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon, @Nullable ServerPlayer serverPlayer) {
super(ModEntityRegister.LEASH_ROPE_ARROW.get(), pX, pY, pZ, pLevel, pPickupItemStack, pFiredFromWeapon);
if(serverPlayer != null && !level().isClientSide) {
((PlayerLeashable)serverPlayer).setLeashedTo(this, true);
private static final int maxLifeTime = LeashPlayerCommonConfig.TheLeashArrowMaxLifeTime.get();
protected LeashRopeArrow(EntityType<? extends AbstractArrow> entityType,Level pLevel) {
super(entityType, pLevel);
}
}
public LeashRopeArrow(LivingEntity pOwner, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon) {
super(ModEntityRegister.LEASH_ROPE_ARROW.get(), pOwner, pLevel, pPickupItemStack, pFiredFromWeapon);
if(pOwner instanceof PlayerLeashable lPlayer && !level().isClientSide) {
lPlayer.setLeashedTo(this, true);
public LeashRopeArrow(EntityType<? extends AbstractArrow> entityType, double pX, double pY, double pZ, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon, @Nullable ServerPlayer serverPlayer) {
super(entityType, pX, pY, pZ, pLevel, pPickupItemStack, pFiredFromWeapon);
if(serverPlayer != null && !level().isClientSide) {
((PlayerLeashable)serverPlayer).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;
public LeashRopeArrow(EntityType<? extends AbstractArrow> entityType, LivingEntity pOwner, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon) {
super(entityType, pOwner, pLevel, pPickupItemStack, pFiredFromWeapon);
if(pOwner instanceof PlayerLeashable lPlayer && !level().isClientSide) {
lPlayer.setLeashedTo(this, true);
}
}
return false;
}
@Override
protected @NotNull ItemStack getDefaultPickupItem() {
return ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance();
}
@Override
public void setOwner(@Nullable Entity pEntity) {
super.setOwner(pEntity);
this.pickup = this.pickup == Pickup.CREATIVE_ONLY ? this.pickup : Pickup.DISALLOWED;
}
@Override
protected boolean tryPickup(@NotNull Player pPlayer) {
//时间1.40 禁止
//时间2.240
// 如果(非仅创造拾取)
// 如果 (按Shift )
// 如果(拥有者) -> 拾取到完整箭取消绑定(super给父类处理)
// 否则:时间仍为原需时间 ->不能获取完整的箭重绑定当前拥有者的Holder是否为本箭才重绑定
// 否则: 禁止
// 否则:
// 如果 (按Shift )
// 如果(拥有者) -> 且拾取到完整箭取消绑定
// 否则:时间仍为原需时间 ->不能获取完整的箭重绑定
// 否则: 禁止
//时间3
// 如果(拥有者) -> 拾取到完整箭取消绑定
// 否则:不能获取完整的箭重绑定
if(life <= 40 ) {
return false;
@Override
protected @NotNull ItemStack getDefaultPickupItem() {
return ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance();
}
else {
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
if(life <= 240) {
if(pPlayer.isShiftKeyDown()) {
@Override
public void setOwner(@Nullable Entity pEntity) {
super.setOwner(pEntity);
this.pickup = this.pickup == Pickup.CREATIVE_ONLY ? this.pickup : Pickup.DISALLOWED;
}
@Override
protected boolean tryPickup(@NotNull Player pPlayer) {
//时间1.40 禁止
//时间2.240
// 如果(非仅创造拾取)
// 如果 (按Shift )
// 如果(拥有者) -> 拾取到完整箭取消绑定(super给父类处理)
// 否则:时间仍为原需时间 ->不能获取完整的箭重绑定当前拥有者的Holder是否为本箭才重绑定
// 否则: 禁止
// 否则:
// 如果 (按Shift )
// 如果(拥有者) -> 且拾取到完整箭取消绑定
// 否则:时间仍为原需时间 ->不能获取完整的箭重绑定
// 否则: 禁止
//时间3
// 如果(拥有者) -> 拾取到完整箭取消绑定
// 否则:不能获取完整的箭重绑定
if(life <= 40 ) {
return false;
}
else {
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
if(this.getOwner() == null) {//未有Owner始终可检
return true;
}
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)) {
this.pickup = Pickup.ALLOWED;
if(this.equals(leashDataEntity)) playerLeashable.dropLeash(true, false);
} else {
if(life >= 120) {
if(this.equals(leashDataEntity)) {
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;
((PlayerLeashable)owner).setLeashedTo(pPlayer, true);
ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), Items.ARROW.getDefaultInstance());
level().addFreshEntity(itemEntity);
discard();
}
}
}
}
else {
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(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);
return super.tryPickup(pPlayer);
}
@Override
protected void tickDespawn() {
this.life++;
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();
}
}
@Override
protected void onHitBlock(@NotNull BlockHitResult pResult) {
if(!level().isClientSide) {
if (getOwner() instanceof PlayerLeashable pL) {
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
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);
discard();
}
}
}
super.onHitBlock(pResult);
}
return super.tryPickup(pPlayer);
}
@Override
protected void tickDespawn() {
this.life++;
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();
}
}
@Override
protected void onHitBlock(@NotNull BlockHitResult pResult) {
if(!level().isClientSide) {
if (getOwner() instanceof PlayerLeashable pL) {
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
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);
discard();
@Override
protected void onHitEntity(@NotNull EntityHitResult pResult) {
if(!level().isClientSide()){
Entity entity = pResult.getEntity();
if(entity instanceof LivingEntity livingEntity){
if(livingEntity.equals(this.getOwner())) return;
if(this.getOwner() == null && livingEntity instanceof PlayerLeashable pL) { //发射器发出或命令生成
setOwner(livingEntity);
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
if(leashDataEntity != null) pL.dropLeash(true, !(leashDataEntity instanceof LeashRopeArrow));
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
pL.setLeashedTo(this, true);
return;
} else if (this.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);
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;
}
}
}
super.onHitEntity(pResult);
}
super.onHitBlock(pResult);
}
@Override
protected void onHitEntity(@NotNull EntityHitResult pResult) {
if(!level().isClientSide()){
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);
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;
}
}
}
super.onHitEntity(pResult);
}
}

View File

@ -19,6 +19,21 @@ public class ModEntityRegister {
.updateInterval(20)
.build("leash_rope_arrow")
);
public static final DeferredHolder<EntityType<?>, EntityType<SpectralLeashRopeArrow>> SPECTRAL_LEASH_ROPE_ARROW = ENTITY_TYPE.register(
"spectral_leash_rope_arrow",
() -> EntityType.Builder.<SpectralLeashRopeArrow>of(SpectralLeashRopeArrow::new, MobCategory.MISC)
.sized(0.5F, 0.5F)
.eyeHeight(0.13F)
.clientTrackingRange(4)
.updateInterval(20)
.build("spectral_leash_rope_arrow")
);
// public static final DeferredHolder<EntityType<?>, EntityType<ChainTieEntity>> CHAIN_TIE = ENTITY_TYPE.register(
// "chain_tie",
// () -> EntityType.Builder.<ChainTieEntity>of(ChainTieEntity::new, MobCategory.MISC)
// .sized(0.8F, 0.9F)
// .build("chain_tie")
// );
public static String getEntityNameKey(String entityName) {
return "entity." + LeashedPlayer.MOD_ID + "." + entityName;
}

View File

@ -0,0 +1,61 @@
package com.r3944realms.leashedplayer.content.entities;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpectralLeashRopeArrow extends LeashRopeArrow {
private int duration = 200;
public SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, double pX, double pY, double pZ, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon, @Nullable ServerPlayer serverPlayer) {
super(entityType, pX, pY, pZ, pLevel, pPickupItemStack, pFiredFromWeapon, serverPlayer);
}
protected SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, Level pLevel) {
super(entityType, pLevel);
}
public SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, LivingEntity pOwner, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon) {
super(entityType, pOwner, pLevel, pPickupItemStack, pFiredFromWeapon);
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide && !this.inGround) {
this.level().addParticle(ParticleTypes.INSTANT_EFFECT, this.getX(), this.getY(), this.getZ(), 0.0, 0.0, 0.0);
}
}
@Override
protected void doPostHurtEffects(@NotNull LivingEntity pLiving) {
super.doPostHurtEffects(pLiving);
MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0);
pLiving.addEffect(mobeffectinstance, this.getEffectSource());
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
@Override
public void readAdditionalSaveData(@NotNull CompoundTag pCompound) {
super.readAdditionalSaveData(pCompound);
if (pCompound.contains("Duration")) {
this.duration = pCompound.getInt("Duration");
}
}
@Override
public void addAdditionalSaveData(@NotNull CompoundTag pCompound) {
super.addAdditionalSaveData(pCompound);
pCompound.putInt("Duration", this.duration);
}
}

View File

@ -4,7 +4,6 @@ import com.r3944realms.leashedplayer.LeashedPlayer;
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;
@ -23,7 +22,7 @@ public class ModCreativeTab {
.displayItems(((pParameters, pOutput) -> {
pOutput.accept(Items.LEAD);
pOutput.accept(ModItemRegister.LEASH_ROPE_ARROW.get());
pOutput.accept(ModItemRegister.FABRIC.get());
pOutput.accept(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get());
})).build());
public static String getCreativeMod(@NotNull String tabs) {
return LEASHED_PLAYER_TAB_STRING + "." + tabs;

View File

@ -1,8 +1,12 @@
package com.r3944realms.leashedplayer.content.items;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.items.type.LeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.type.SpectralLeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.type.TestItem;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.SpectralArrowItem;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
@ -17,6 +21,8 @@ public class ModItemRegister {
public static final Supplier<Item> LEASH_ROPE_ARROW = ModItemRegister.register("leash_rope_arrow",
() -> new LeashRopeArrowItem(new Item.Properties().stacksTo(16))
);
public static final Supplier<Item> SPECTRAL_LEASH_ROPE_ARROW = ModItemRegister.register("spectral_leash_rope_arrow",
() -> new SpectralLeashRopeArrowItem(new Item.Properties().stacksTo(16)));
public static final Supplier<Item> FABRIC = ModItemRegister.register("fabric",
() -> new TestItem(new Item.Properties().stacksTo(1))

View File

@ -0,0 +1,19 @@
package com.r3944realms.leashedplayer.content.items.type;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
public interface ILeashRopeArrow {
static boolean isLeashRopeArrow(ItemStack bowStack, LivingEntity entity) {
if (entity instanceof Player player) {
// 获取将要发射的弹药
ItemStack projectileStack = player.getProjectile(bowStack);
// 判断该弹药是否为拴绳箭
return projectileStack.getItem() instanceof ILeashRopeArrow;
}
return false;
}
}

View File

@ -1,9 +1,14 @@
package com.r3944realms.leashedplayer.content.items;
package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ArrowItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -14,14 +19,21 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.List;
public class LeashRopeArrowItem extends ArrowItem {
public class LeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
public static final String descKey = "item.leash_rope_arrow.description";
public LeashRopeArrowItem(Item.Properties pProperties) {
super(pProperties);
}
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
return new com.r3944realms.leashedplayer.content.entities.LeashRopeArrow(pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
return new com.r3944realms.leashedplayer.content.entities.LeashRopeArrow(ModEntityRegister.LEASH_ROPE_ARROW.get(),pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
}
@Override
public @NotNull Projectile asProjectile(@NotNull Level pLevel, @NotNull Position pPos, @NotNull ItemStack pStack, @NotNull Direction pDirection) {
LeashRopeArrow arrow = new LeashRopeArrow(ModEntityRegister.LEASH_ROPE_ARROW.get(), pPos.x(), pPos.y(), pPos.z(), pLevel, this.getDefaultInstance(),null, null);
arrow.pickup = AbstractArrow.Pickup.DISALLOWED;
return arrow;
}
@Override

View File

@ -0,0 +1,47 @@
package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
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 SpectralLeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
public static final String descKey = "item.spectral_leash_rope_arrow.description";
public SpectralLeashRopeArrowItem(Properties pProperties) {
super(pProperties);
}
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
return new SpectralLeashRopeArrow(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
}
@Override
public @NotNull Projectile asProjectile(@NotNull Level pLevel, @NotNull Position pPos, @NotNull ItemStack pStack, @NotNull Direction pDirection) {
LeashRopeArrow arrow = new SpectralLeashRopeArrow(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), pPos.x(), pPos.y(), pPos.z(), pLevel, this.getDefaultInstance(),null, null);
arrow.pickup = AbstractArrow.Pickup.DISALLOWED;
return arrow;
}
@Override
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

@ -1,11 +1,11 @@
package com.r3944realms.leashedplayer.content.items;
package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
import com.r3944realms.leashedplayer.client.renders.AdaptiveGuiRendererHandler;
import com.r3944realms.leashedplayer.client.renders.IFadingProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.IProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.TestProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.gui.AdaptiveGuiRendererHandler;
import com.r3944realms.leashedplayer.client.renders.gui.IFadingProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.gui.IProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.gui.TestProcessBarRenderer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;

View File

@ -11,6 +11,7 @@ public enum ModAdvancementKey {
LEASHED_FRIEND("leashed_friend", LEASH_START),
LEASHED_SELF("leashed_self", LEASH_START),
LEASH_ARROW("leash_arrow", LEASH_START),
ADVANCEMENT_LEASH_ARROW("advancement_leash_arrow", LEASH_ARROW),
FOLLOW_LEASH_ARROW("follow_arrow", LEASH_ARROW),
DOG_RUNNING_PLAYER("dog_running_player", LEASH_ARROW),
;

View File

@ -5,7 +5,7 @@ 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.type.LeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.ModCreativeTab;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.utils.Enum.LanguageEnum;
@ -22,11 +22,13 @@ import static com.r3944realms.leashedplayer.content.items.ModCreativeTab.LEASHED
public enum ModLangKeyValue {
//ITEM
ITEM_LEASH_ROPE_ARROW(ModItemRegister.LEASH_ROPE_ARROW, ModPartEnum.ITEM, "Leash Rope Arrow", "拴绳箭", "拴繩箭", true),
ITEM_SPECTRAL_LEASH_ROPE_ARROW(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW, ModPartEnum.ITEM, "Spectral Leash Rope Arrow", "拴绳光灵箭", "拴繩光靈箭", true),
TEST_FABRIC_ITEM(ModItemRegister.FABRIC, ModPartEnum.ITEM, "Fabric", "Fabric", "Fabric", true),
//ITEM_DESC
DESC_ITEM_LEASH_ROPE_ARROW(LeashRopeArrowItem.descKey, ModPartEnum.DESCRIPTION, "Arrows with ropes attached?","带有拴绳的箭矢?", "帶有拴繩的箭矢?", false),
//ENTITY
LEASH_ROPE_ARROW(ModEntityRegister.getEntityNameKey("leash_rope_arrow"), ModPartEnum.ENTITY, "Leash Rope Arrow", "拴绳箭", "拴繩箭", false),
SPECTRAL_LEASH_ROPE_ARROW(ModEntityRegister.getEntityNameKey("spectral_leash_rope_arrow"), ModPartEnum.ENTITY, "Spectral Leash Rope Arrow", "拴绳光灵箭", "拴繩光靈箭", false),
//CREATIVE_TAB
CREATIVE_TAB_NAME(ModCreativeTab.getCreativeMod(LEASHED_PLAYER_ITEM), ModPartEnum.CREATIVE_TAB, "Leashed Player","可拴玩家", "可拴玩家", false),
//COMMAND_MESSAGE
@ -53,15 +55,17 @@ public enum ModLangKeyValue {
//ADV_NAME
LEASH_START(ModAdvancementKey.LEASH_START.getNameKey(), ModPartEnum.NAME, "The Power of Traction", "牵引之力", "牽引之力", false),
LEASH_LR_ARROW(ModAdvancementKey.LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "Arrow with a Tether?" , "拴绳之箭?", "拴繩之箭?", false),
LEASH_SLP_ARROW(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "More advanced flash arrow with a Tether?", "更闪亮的拴绳箭?", "更閃亮的拴繩箭?", false),
LEASH_SELF(ModAdvancementKey.LEASHED_SELF.getNameKey(), ModPartEnum.NAME, "Stable Connection", "稳固联结" ,"穩固聯結", false),
LEASH_PLAYER(ModAdvancementKey.LEASHED_FRIEND.getNameKey(),ModPartEnum.NAME, "Bond by Rope", "拴绳链接", "拴繩鏈接" , false),
LEASH_PLAYER(ModAdvancementKey.LEASHED_FRIEND.getNameKey(),ModPartEnum.NAME, "Be bound by Rope", "拴绳链接", "拴繩鏈接" , false),
FOLLOW_ARROW(ModAdvancementKey.FOLLOW_LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "Launch!!!", "启航!!!" , "啓航!!!",false),
FOLLOW_WOLF(ModAdvancementKey.DOG_RUNNING_PLAYER.getNameKey(), ModPartEnum.NAME, "It's Walking human time.", "遛“人”时间", "遛“人”時間",false),
//ADV_DESC
LEASH_START_DESC(ModAdvancementKey.LEASH_START.getDescKey(), ModPartEnum.DESCRIPTION, "Journey to becoming a Leash Expert", "拴绳大师之路", "拴繩大師之路", false),
LEASH_LR_ARROW_DESC(ModAdvancementKey.LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Maybe you can using it to shoot some mob?", "也许可以用它来发射生物?", "也許可以用它發射生物?", false),
LEASH_SLP_ARROW_DESC(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Well, apart from glowing, there doesn't seem to be any other difference", "嗯,除了发光,似乎没有什么其它不同了" ,"嗯,除了發光,其它好像沒什麽不同", false),
LEASH_SELF_DESC(ModAdvancementKey.LEASHED_SELF.getDescKey(), ModPartEnum.DESCRIPTION, "“Restrain oneself with a rope", "用拴绳拴住自己" ,"用栓繩拴住自己", false),
LEASH_PLAYER_DESC(ModAdvancementKey.LEASHED_FRIEND.getDescKey(),ModPartEnum.DESCRIPTION, "bond player with lead", "用拴绳链接玩家", "用拴繩鏈接玩家", false),
LEASH_PLAYER_DESC(ModAdvancementKey.LEASHED_FRIEND.getDescKey(),ModPartEnum.DESCRIPTION, "Be Bond by player with lead", "被玩家用拴绳链接", "被玩家用拴繩鏈接", false),
FOLLOW_ARROW_DESC(ModAdvancementKey.FOLLOW_LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Mc, what are you talking about in physics?", "抱歉,我的世界不存在物理学" , "抱歉,麦块不講物理學",false),
FOLLOW_WOLF_DESC(ModAdvancementKey.DOG_RUNNING_PLAYER.getDescKey(), ModPartEnum.DESCRIPTION, "In the park where dogs are not allowed to be walked, the dog decided to walk the human instead", "公园不能遛狗,于是狗站起来遛人", "公園裏不許遛狗,於是狗站起來遛人",false),
;

View File

@ -52,6 +52,19 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
.parent(hasLeashRopeItem)
.save(saver, ModAdvancementKey.LEASH_ARROW.getNameWithNameSpace());
AdvancementHolder hasFlashLeashRopeArrow = Advancement.Builder.advancement().display(
ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),
Component.translatable(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameKey()),
Component.translatable(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getDescKey()),
null,
AdvancementType.TASK,
true,
false,
true
).addCriterion("has_flash_leash_rope_item", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get()))
.parent(hasLeashRopeArrow)
.save(saver, ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameWithNameSpace());
AdvancementHolder leashedMySelf = Advancement.Builder.advancement().display(
Items.PLAYER_HEAD,
Component.translatable(ModAdvancementKey.LEASHED_SELF.getNameKey()),

View File

@ -21,6 +21,7 @@ public class ModItemTagProvider extends ItemTagsProvider {
@Override
protected void addTags(HolderLookup.@NotNull Provider pProvider) {
this.tag(ItemTags.ARROWS)
.add(ModItemRegister.LEASH_ROPE_ARROW.get());
.add(ModItemRegister.LEASH_ROPE_ARROW.get())
.add(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get());
}
}

View File

@ -3,10 +3,7 @@ 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.RecipeCategory;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.data.recipes.*;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
@ -25,7 +22,21 @@ public class ModRecipeProvider extends RecipeProvider {
.requires(Items.ARROW)
.unlockedBy("has_lead",has(Items.LEAD))
.save(pRecipeOutput);
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.requires(Items.LEAD)
.requires(Items.SPECTRAL_ARROW)
.unlockedBy("has_lead",has(Items.LEAD))
.unlockedBy("has_spectral_arrow",has(Items.SPECTRAL_ARROW))
.save(pRecipeOutput, "spectral_leash_rope_arrow_with_leash_rope_arrow");
ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.pattern(" $ ")
.pattern("$#$")
.pattern(" $ ")
.define('#', ModItemRegister.LEASH_ROPE_ARROW.get())
.define('$', Items.GLOWSTONE_DUST)
.unlockedBy("has_lead",has(Items.LEAD))
.unlockedBy("has_glowstone_dust",has(Items.GLOWSTONE_DUST))
.save(pRecipeOutput,"spectral_leash_rope_arrow_with_glowstone_dust");
}

View File

@ -5,6 +5,7 @@ import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import com.r3944realms.leashedplayer.utils.Logger;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
@ -14,6 +15,7 @@ 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;
@ -25,6 +27,7 @@ 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)
@ -82,6 +85,17 @@ public abstract class MixinPlayer extends LivingEntity implements PlayerLeashabl
if(leashHolder != null ) {
//存在则更新
Pl$UpdateLeash(leashHolder, (Entity) playerLeashable);
try {
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(1.25f);
} catch (Exception e) {
Logger.logger.error(e.getMessage());
}
} else {
try {
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(0.6f);
} catch (Exception e) {
Logger.logger.error(e.getMessage());
}
}
}
@Unique

View File

@ -41,7 +41,7 @@ public interface PlayerLeashable extends Leashable {
*/
default void setLeashedTo(@NotNull Entity pLeashHolder, boolean pBroadcastPacket) {
setLeashedTo((Entity & Leashable)this, pLeashHolder, pBroadcastPacket);
if(this instanceof ServerPlayer){
if(this instanceof ServerPlayer) {
ModCriteriaTriggers.LEASH_PLAYER_TRIGGER.get().trigger((ServerPlayer) this, pLeashHolder);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B