Jump to content

Recommended Posts

Posted

I'm trying to make a Spear that the Player can throw, so what I've done is essentially make a custom Trident Item with a custom entity as well. However when I release the spear the entity related is not spawning :/ If I summon the Entity via command it is spawned and rendered as well...

This is the class I'm using, very similar to the Trident Item class

public class SpearItem extends SwordItem implements Vanishable {

    public SpearItem(Tier tier, int attackDamageModifier, float attackSpeedModifier) {
        super(tier, attackDamageModifier, attackSpeedModifier, new Properties().durability(tier.getUses()).tab(BLTabs.TAB_COMBAT));
    }

    public @NotNull UseAnim getUseAnimation(@NotNull ItemStack itemStack) {
        return UseAnim.SPEAR;
    }

    public int getUseDuration(@NotNull ItemStack itemStack) {
        return 36000;
    }

    public void releaseUsing(@NotNull ItemStack stack, @NotNull Level level, @NotNull LivingEntity livingEntity, int timeLeft) {
        if (livingEntity instanceof Player player) {
            int i = this.getUseDuration(stack) - timeLeft;
            if (i >= 10) {
                if (!level.isClientSide) {
                    stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(livingEntity.getUsedItemHand()));

                    ThrownSpear thrownSpear = ThrownSpear.from(level, player, stack);
                    thrownSpear.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 2.5F, 1.0F);
                    if (player.getAbilities().instabuild) {
                        thrownSpear.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
                    }

                    level.addFreshEntity(thrownSpear);
                    level.playSound(null, thrownSpear, SoundEvents.TRIDENT_THROW, SoundSource.PLAYERS, 1.0F, 1.0F);
                    if (!player.getAbilities().instabuild) {
                        player.getInventory().removeItem(stack);
                    }
                }

                player.awardStat(Stats.ITEM_USED.get(this));
            }
        }
    }

    public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, Player player, @NotNull InteractionHand hand) {
        player.startUsingItem(hand);
        return InteractionResultHolder.consume(player.getItemInHand(hand));
    }
}

And this is the ThrownSpear entity class (again, very similar to the ThrownTrident class as well)

public class ThrownSpear extends AbstractArrow {

    private ItemStack spearItem = new ItemStack(BLItems.SPEAR.get());
    private boolean dealtDamage;

    public ThrownSpear(EntityType<? extends ThrownSpear> spear, Level world) {
        super(spear, world);
    }

    public void tick() {
        if (this.inGroundTime > 4) {
            this.dealtDamage = true;
        }

        super.tick();
    }

    protected ItemStack getPickupItem() {
        return this.spearItem.copy();
    }
    
    @Nullable
    protected EntityHitResult findHitEntity(Vec3 startVec, Vec3 endVec) {
        return this.dealtDamage ? null : super.findHitEntity(startVec, endVec);
    }
    
    protected void onHitEntity(EntityHitResult pResult) {
        Entity entity = pResult.getEntity();
        float f = 8.0F;
        if (entity instanceof LivingEntity livingentity) {
            f += EnchantmentHelper.getDamageBonus(this.spearItem, livingentity.getMobType());
        }

        Entity entity1 = this.getOwner();
        DamageSource damagesource = DamageSource.trident(this, (Entity)(entity1 == null ? this : entity1));
        this.dealtDamage = true;
        SoundEvent soundevent = SoundEvents.TRIDENT_HIT;
        if (entity.hurt(damagesource, f)) {
            if (entity.getType() == EntityType.ENDERMAN) {
                return;
            }

            if (entity instanceof LivingEntity livingentity1) {
                if (entity1 instanceof LivingEntity) {
                    EnchantmentHelper.doPostHurtEffects(livingentity1, entity1);
                    EnchantmentHelper.doPostDamageEffects((LivingEntity)entity1, livingentity1);
                }

                this.doPostHurtEffects(livingentity1);
            }
        }

        this.setDeltaMovement(this.getDeltaMovement().multiply(-0.01D, -0.1D, -0.01D));
        this.playSound(soundevent, 1.0F,  1.0F);
    }

    protected boolean tryPickup(Player player) {
        return super.tryPickup(player) || this.isNoPhysics() && this.ownedBy(player) && player.getInventory().add(this.getPickupItem());
    }
    
    protected SoundEvent getDefaultHitGroundSoundEvent() {
        return SoundEvents.TRIDENT_HIT_GROUND;
    }
    
    public void playerTouch(Player player) {
        if (this.ownedBy(player) || this.getOwner() == null) {
            super.playerTouch(player);
        }
    }
    
    public void readAdditionalSaveData(CompoundTag compound) {
        super.readAdditionalSaveData(compound);
        if (compound.contains("Spear", 10)) {
            this.spearItem = ItemStack.of(compound.getCompound("Spear"));
        }

        this.dealtDamage = compound.getBoolean("DealtDamage");
    }

    public void addAdditionalSaveData(CompoundTag compound) {
        super.addAdditionalSaveData(compound);
        compound.put("Spear", this.spearItem.save(new CompoundTag()));
        compound.putBoolean("DealtDamage", this.dealtDamage);
    }

    public boolean shouldRender(double x, double y, double z) {
        return true;
    }

    public ItemStack getSpearItem() {
        return this.spearItem;
    }

    public static ThrownSpear from(Level world, LivingEntity entity, ItemStack stack) {
        ThrownSpear thrownSpear = new ThrownSpear(BLEntityTypes.SPEAR.get(), world);
        thrownSpear.spearItem = stack.copy();
        return thrownSpear;
    }

}

What am I missing in the Item or the Entity class?

Also, how do I make so the Item inside the inventory actually renders the entity? I've already registered the "throwing" property, like vanilla Trident does, but it looks like this is ignored

ItemProperties.register(item.get(), new ResourceLocation("throwing"), (stack, level, entity, seed) -> entity != null && entity.isUsingItem() && entity.getUseItem() == stack ? 1.0F : 0.0F);

where item is just a Spear item I'm passing (I have multiple spears registered that shares the same class and entity, just different textures).

I've already registered other Item properties, like the "pull" and "pulling" for a custom bow and they are working just fine, so I don't understand why is not working for the spears as well :/ 

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted (edited)

EDIT: Nevermind, I figured out 😅 I just need to explicit the class in the Builder
 

public static final RegistryObject<EntityType<ThrownSpear>> SPEAR = ENTITY_TYPES.register("spear",
            () -> EntityType.Builder.<ThrownSpear>of(ThrownSpear::new, MobCategory.MISC)
                    .sized(0.5F, 0.5F).clientTrackingRange(4).updateInterval(20)
                    .build(new ResourceLocation(BlazersMod.MOD_ID, "spear").toString()));

So I can now instance the Spear with the LivingEntity constructor and at least the spear gets spawned inside the world.
But this doesn't solve the model in hand issue, where the Spear appears as a regular Item. It gets shifted in position when charging, however the entity model is not showing :/ How can I bind the entity model to the item so that the actual Spear model gets displayed when holding/throwing the Item?

The problem is that if I add the Living Entity constructor, then the EntityType registration complains :/

I'm registering the EntityType like this

 

public static final RegistryObject<EntityType<ThrownSpear>> SPEAR = ENTITY_TYPES.register("spear",
            () -> EntityType.Builder.of(ThrownSpear::new, MobCategory.MISC)
                    .sized(0.5F, 0.5F).clientTrackingRange(4).updateInterval(20)
                    .build(new ResourceLocation(BlazersMod.MOD_ID, "spear").toString()));


And if I add the LivingEntity constructor, I get this error
 

Cannot resolve constructor 'ThrownSpear'

Of course the EntityType constructor still remains in the class

public ThrownSpear(EntityType<? extends AbstractArrow> type, Level level) {
        super(type, level);
    }

    public ThrownSpear(Level world, LivingEntity entity, ItemStack stack) {
        super(BLEntityTypes.SPEAR.get(), entity, world);
        this.spearItem = stack.copy();
    }

 

Edited by JimiIT92

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted
10 hours ago, JimiIT92 said:

So I can now instance the Spear with the LivingEntity constructor and at least the spear gets spawned inside the world.
But this doesn't solve the model in hand issue, where the Spear appears as a regular Item. It gets shifted in position when charging, however the entity model is not showing :/ How can I bind the entity model to the item so that the actual Spear model gets displayed when holding/throwing the Item?

you need to render the Model manually in the way how the Shield and the Trident it does,

override Item#initializeClient in your Item class and return a new IItemRenderProperties instance (use an anonymous class),
inside the IItemRenderProperties override IItemRenderProperties#getItemStackRenderer and retrun there a custom BlockEntityWithoutLevelRenderer,
you can extends BlockEntityWithoutLevelRenderer and render your Model in #renderByItem

Posted (edited)

EDIT: After some digging into the Forum I found out what was wrong. Codewise essentially nothing, except for the fact that I'm returning a new instance every time .The issue was in the JSON file. I've now ported the "spear_in_hand.json" content into the "spear.json" file and I now see the Spear in 3D like the Trident. However now I have the issue that is 3D in the inventory as well :/ How can I render a different texture in Inventory? 

I tried this

{
  "parent": "minecraft:builtin/entity",
  "gui_light": "front",
  "textures": {
    "particle": "blazersmod:item/spear",
    "layer0": "#particle"
  },
  "display": {
    "thirdperson_righthand": {
      "rotation": [ 0, 60, 0 ],
      "translation": [ 11, 17, -2 ],
      "scale": [ 1, 1, 1 ]
    },
    "thirdperson_lefthand": {
      "rotation": [ 0, 60, 0 ],
      "translation": [ 3, 17, 12 ],
      "scale": [ 1, 1, 1 ]
    },
    "firstperson_righthand": {
      "rotation": [ 0, -90, 25 ],
      "translation": [ -3, 17, 1],
      "scale": [ 1, 1, 1 ]
    },
    "firstperson_lefthand": {
      "rotation": [ 0, 90, -25 ],
      "translation": [ 13, 17, 1],
      "scale": [ 1, 1, 1 ]
    },
    "gui": {
      "rotation": [ 15, -25, -5 ],
      "translation": [ 2, 3, 0 ],
      "scale": [ 0.65, 0.65, 0.65 ]
    },
    "fixed": {
      "rotation": [ 0, 180, 0 ],
      "translation": [ -2, 4, -5],
      "scale":[ 0.5, 0.5, 0.5]
    },
    "ground": {
      "rotation": [ 0, 0, 0 ],
      "translation": [ 4, 4, 2],
      "scale":[ 0.25, 0.25, 0.25]
    }
  },
  "overrides": [
    {
      "predicate": {
        "throwing": 1
      },
      "model": "blazersmod:item/spear_throwing"
    }
  ]
}

but I can't seem to display the texture in the inventory :/ 

Sorry I've never used this, so I'm fairly new to it 😅 I've overridden the initializeClient method, and added a custom IItemRenderProperties like this
 

@Override
  public void initializeClient(Consumer<IItemRenderProperties> consumer) {
  consumer.accept(new IItemRenderProperties() {
    @Override
      public BlockEntityWithoutLevelRenderer getItemStackRenderer() {
      return new SpearItemRenderer(new EntityModelSet());
    }
  });
}

With the ItemRenderer class being this

@OnlyIn(Dist.CLIENT)
public class SpearItemRenderer extends BlockEntityWithoutLevelRenderer {

    private ThrownSpearModel spearModel;
    private ThrownMalachiteSpearModel malachiteSpearModel;
    private final EntityModelSet entityModelSet;

    public SpearItemRenderer(EntityModelSet entityModelSet) {
        super(new BlockEntityRenderDispatcher(Minecraft.getInstance().font, entityModelSet, () -> Minecraft.getInstance().getBlockRenderer()), entityModelSet);
        this.entityModelSet = entityModelSet;
    }

    public void onResourceManagerReload(@NotNull ResourceManager resourceManager) {
        this.spearModel = new ThrownSpearModel(this.entityModelSet.bakeLayer(ThrownSpearModel.LAYER_LOCATION));
        this.malachiteSpearModel = new ThrownMalachiteSpearModel(this.entityModelSet.bakeLayer(ThrownMalachiteSpearModel.LAYER_LOCATION));
    }

    @Override
    public void renderByItem(ItemStack stack, ItemTransforms.@NotNull TransformType transformType, @NotNull PoseStack pose, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) {
        if(stack.getItem() instanceof SpearItem) {
            pose.pushPose();
            pose.scale(1.0F, -1.0F, -1.0F);
            boolean isMalachiteSpear = stack.is(BLItems.MALACHITE_SPEAR.get());
            EntityModel<ThrownSpear> model = isMalachiteSpear ? this.malachiteSpearModel : this.spearModel;
            ResourceLocation layerLocation = isMalachiteSpear ? ThrownMalachiteSpearRenderer.SPEAR_LOCATION : ThrownSpearRenderer.SPEAR_LOCATION;
            VertexConsumer vertexConsumer = ItemRenderer.getFoilBufferDirect(buffer, model.renderType(layerLocation), false, stack.hasFoil());
            model.renderToBuffer(pose, vertexConsumer, packedLight, packedOverlay, 1.0F, 1.0F, 1.0F, 1.0F);
            pose.popPose();
        }
    }
}

I also tried to look at how the Shield/Trident are rendered, but can't find anything related to the Item itself (something that binds the actual Item to the rendering, I just found the base BlockEntityWithoutLevelRenderer where those items are rendered)

Edited by JimiIT92

Don't blame me if i always ask for your help. I just want to learn to be better :)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.