Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

Ive been trying to create a custom projectile entity, and the entity kinda works, but i cant get it to render properly. It wont render at all.

 

My Classes:

Note, most of the entity code comes from the vanilla fireball

 

Abstract projectile

package com.mekelaina.gramarye.entities;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.projectile.ProjectileHelper;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.network.IPacket;
import net.minecraft.network.play.server.SSpawnObjectPacket;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.*;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

public abstract class AbstractBoltEntity extends Entity {

    public LivingEntity  shootingEntity;
    private int ticksAlive;
    private int ticksInAir;
    public double accelerationX;
    public double accelerationY;
    public double accelerationZ;

    protected AbstractBoltEntity(EntityType<? extends AbstractBoltEntity> entityType, World world) {
        super(entityType, world);
    }

    public AbstractBoltEntity(EntityType<? extends AbstractBoltEntity> EntityType, double x, double y, double z, double xAccIn, double yAccIn, double zAccIn, World world) {
        this(EntityType, world);
        this.setLocationAndAngles(x, y, z, this.rotationYaw, this.rotationPitch);
        this.setPosition(x, y, z);
        double d0 = (double) MathHelper.sqrt(xAccIn * xAccIn + yAccIn * yAccIn + zAccIn * zAccIn);
        this.accelerationX = xAccIn / d0 * 0.1D;
        this.accelerationY = yAccIn / d0 * 0.1D;
        this.accelerationZ = zAccIn / d0 * 0.1D;
    }

    public AbstractBoltEntity(EntityType<? extends AbstractBoltEntity> entityType, LivingEntity shootingEntityIn, double xAccIn, double yAccIn, double zAccIn, World world) {
        this(entityType, world);
        this.shootingEntity = shootingEntityIn;
        this.setLocationAndAngles(shootingEntityIn.posX, shootingEntityIn.posY, shootingEntityIn.posZ, shootingEntityIn.rotationYaw, shootingEntityIn.rotationPitch);
        this.setPosition(this.posX, this.posY, this.posZ);
        this.setMotion(Vec3d.ZERO);
        xAccIn = xAccIn + this.rand.nextGaussian() * 0.4D;
        yAccIn = yAccIn + this.rand.nextGaussian() * 0.4D;
        zAccIn = zAccIn + this.rand.nextGaussian() * 0.4D;
        double d0 = (double) MathHelper.sqrt(xAccIn * xAccIn + yAccIn * yAccIn + zAccIn * zAccIn);
        this.accelerationX = xAccIn / d0 * 0.1D;
        this.accelerationY = yAccIn / d0 * 0.1D;
        this.accelerationZ = zAccIn / d0 * 0.1D;
    }

    @OnlyIn(Dist.CLIENT)
    public boolean isInRangeToRenderDist(double distance) {
        double d0 = this.getBoundingBox().getAverageEdgeLength() * 4.0D;
        if (Double.isNaN(d0)) {
            d0 = 4.0D;
        }

        d0 = d0 * 64.0D;
        return distance < d0 * d0;
    }

    /**
     * Called to update the entity's position/logic.
     */
    public void tick() {
        if (this.world.isRemote || (this.shootingEntity == null || !this.shootingEntity.removed) && this.world.isBlockLoaded(new BlockPos(this))) {
            super.tick();

            ++this.ticksInAir;
            RayTraceResult raytraceresult = ProjectileHelper.func_221266_a(this, true, this.ticksInAir >= 25, this.shootingEntity, RayTraceContext.BlockMode.COLLIDER);
            if (raytraceresult.getType() != RayTraceResult.Type.MISS && !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, raytraceresult)) {
                this.onImpact(raytraceresult);
            }

            Vec3d vec3d = this.getMotion();
            this.posX += vec3d.x;
            this.posY += vec3d.y;
            this.posZ += vec3d.z;
            ProjectileHelper.rotateTowardsMovement(this, 0.2F);
            float f = this.getMotionFactor();
            if (this.isInWater()) {
                for(int i = 0; i < 4; ++i) {
                    float f1 = 0.25F;
                    this.world.addParticle(ParticleTypes.BUBBLE, this.posX - vec3d.x * 0.25D, this.posY - vec3d.y * 0.25D, this.posZ - vec3d.z * 0.25D, vec3d.x, vec3d.y, vec3d.z);
                }

                f = 0.8F;
            }

            this.setMotion(vec3d.add(this.accelerationX, this.accelerationY, this.accelerationZ).scale((double)f));
            this.world.addParticle(this.getParticle(), this.posX, this.posY + 0.5D, this.posZ, 0.0D, 0.0D, 0.0D);
            this.setPosition(this.posX, this.posY, this.posZ);
        } else {
            this.remove();
        }
    }


    protected IParticleData getParticle() {
        return ParticleTypes.SMOKE;
    }

    /**
     * Return the motion factor for this projectile. The factor is multiplied by the original motion.
     */
    protected float getMotionFactor() {
        return 0.95F;
    }

    /**
     * Called when this EntityFireball hits a block or entity.
     */
    protected abstract void onImpact(RayTraceResult result);

    public void writeAdditional(CompoundNBT compound) {
        Vec3d vec3d = this.getMotion();
        compound.put("direction", this.newDoubleNBTList(new double[]{vec3d.x, vec3d.y, vec3d.z}));
        compound.put("power", this.newDoubleNBTList(new double[]{this.accelerationX, this.accelerationY, this.accelerationZ}));
        compound.putInt("life", this.ticksAlive);
    }

    /**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
    public void readAdditional(CompoundNBT compound) {
        if (compound.contains("power", 9)) {
            ListNBT listnbt = compound.getList("power", 6);
            if (listnbt.size() == 3) {
                this.accelerationX = listnbt.getDouble(0);
                this.accelerationY = listnbt.getDouble(1);
                this.accelerationZ = listnbt.getDouble(2);
            }
        }

        this.ticksAlive = compound.getInt("life");
        if (compound.contains("direction", 9) && compound.getList("direction", 6).size() == 3) {
            ListNBT listnbt1 = compound.getList("direction", 6);
            this.setMotion(listnbt1.getDouble(0), listnbt1.getDouble(1), listnbt1.getDouble(2));
        } else {
            this.remove();
        }

    }

    /**
     * Returns true if other Entities should be prevented from moving through this Entity.
     */
    public boolean canBeCollidedWith() {
        return true;
    }

    public float getCollisionBorderSize() {
        return 1.0F;
    }

    /**
     * Called when the entity is attacked.
     */
    public boolean attackEntityFrom(DamageSource source, float amount) {
        if (this.isInvulnerableTo(source)) {
            return false;
        } else {
            this.markVelocityChanged();
            if (source.getTrueSource() != null) {
                Vec3d vec3d = source.getTrueSource().getLookVec();
                this.setMotion(vec3d);
                this.accelerationX = vec3d.x * 0.1D;
                this.accelerationY = vec3d.y * 0.1D;
                this.accelerationZ = vec3d.z * 0.1D;
                if (source.getTrueSource() instanceof LivingEntity) {
                    this.shootingEntity = (LivingEntity)source.getTrueSource();
                }

                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * Gets how bright this entity is.
     */
    public float getBrightness() {
        return 1.0F;
    }

    @OnlyIn(Dist.CLIENT)
    public int getBrightnessForRender() {
        return 15728880;
    }

    public IPacket<?> createSpawnPacket() {
        int i = this.shootingEntity == null ? 0 : this.shootingEntity.getEntityId();
        return new SSpawnObjectPacket(this.getEntityId(), this.getUniqueID(), this.posX, this.posY, this.posZ, this.rotationPitch, this.rotationYaw, this.getType(), i, new Vec3d(this.accelerationX, this.accelerationY, this.accelerationZ));
    }
}

 

Actual entity

package com.mekelaina.gramarye.entities;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.IPacket;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;

public class SpellBoltEntity extends AbstractBoltEntity{

    protected boolean doesDamage = false;
    protected float damageAmt = 0f;
    protected DamageSource damageSource = DamageSource.GENERIC;

    public SpellBoltEntity(EntityType<? extends  AbstractBoltEntity> entityType, World world) {
        super(entityType, world);

    }

/*    @Override
    public IPacket<?> createSpawnPacket() {
        return NetworkHooks.getEntitySpawningPacket(this);
    }*/

    public SpellBoltEntity(EntityType<? extends AbstractBoltEntity> entityType, LivingEntity shootingEntityIn, double xAccIn, double yAccIn, double zAccIn, World world) {
        super(entityType, shootingEntityIn, xAccIn, yAccIn, zAccIn, world);
    }




    @Override
    protected void onImpact(RayTraceResult result) {
        BlockPos pos = new BlockPos(result.getHitVec().x, result.getHitVec().y, result.getHitVec().z);
        if(shootingEntity instanceof PlayerEntity) {
            ((PlayerEntity) shootingEntity).sendStatusMessage(this.world.getBlockState(pos).getBlock().getNameTextComponent(), false);
        }
        this.remove();
    }

    @Override
    protected void registerData() {

    }

    public boolean isDoesDamage() {
        return doesDamage;
    }

    public void setDoesDamage() {
        this.doesDamage = true;
    }

    public float getDamageAmt() {
        return damageAmt;
    }

    public void setDamageAmt(float damageAmt) {
        this.damageAmt = damageAmt;
    }

    public DamageSource getDamageSource() {
        return damageSource;
    }

    public void setDamageSource(DamageSource damageSource) {
        this.damageSource = damageSource;
    }

}

 

Renderer

package com.mekelaina.gramarye.entities;

import com.mekelaina.gramarye.Gramarye;
import com.mekelaina.gramarye.entities.SpellBoltEntity;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.util.ResourceLocation;

import javax.annotation.Nullable;

public class DefaultSpellBoltRenderer extends EntityRenderer<SpellBoltEntity> {

    private static final ResourceLocation TEXTURE = new ResourceLocation(Gramarye.MODID, "textures/entity/entitybolt2.png");

    //private static final DefaultSpellBoltModel MODEL = new DefaultSpellBoltModel();

    public DefaultSpellBoltRenderer(EntityRendererManager renderManager) {
        super(renderManager);
        bindTexture(TEXTURE);
    }

    @Nullable
    @Override
    protected ResourceLocation getEntityTexture(SpellBoltEntity entity) {
        return TEXTURE;
    }

    @Override
    public void doRender(SpellBoltEntity entity, double x, double y, double z, float entityYaw, float partialTicks) {
        super.doRender(entity, x, y, z, entityYaw, partialTicks);
        renderManager.renderEntity(entity, x, y, z, entityYaw, partialTicks, false);
       // MODEL.render(entity, 0f, 0f, 0f, entityYaw, e);
    }



}

 

Where its registered

package com.mekelaina.gramarye.setup;

import com.mekelaina.gramarye.Gramarye;
import com.mekelaina.gramarye.entities.DefaultSpellBoltRenderer;
import com.mekelaina.gramarye.entities.SpellBoltEntity;

import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;

@Mod.EventBusSubscriber(modid = Gramarye.MODID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ClientSetup {

    public static void init(final FMLClientSetupEvent event) {

    }

    @SubscribeEvent
    public static void onClientSetupEvent(FMLClientSetupEvent event) {
        RenderingRegistry.registerEntityRenderingHandler(SpellBoltEntity.class, DefaultSpellBoltRenderer::new);
    }
}

 

  • Author
50 minutes ago, poopoodice said:

use the new registerEntityRenderingHandler that requires an entity type, and createSpawnpacket looks right

what new registerEntityRenderingHandler? im using this one "RenderingRegistry.registerEntityRenderingHandler" in my client setup class. is there another one?

same but different parameter:

RenderingRegistry.registerEntityRenderingHandler(EntityType<T> entityClass, IRenderFactory<? super T> renderFactory)

 

15 minutes ago, Mekelaina said:

@poopoodice do you have an example of how to use IRenderFactory?

You should be able to just use YourEntityRenderer::new for the render factory, I believe it will work just fine as long as you have a constructor for the renderer that takes an EntityRendererManager as a parameter.

8 minutes ago, Mekelaina said:

its not working

Never just say "it's not working" :) Be descriptive what is not working, and also provide your debug.log, preferably posted on an external site (like a github gist) and then linked to here. There could very well be a clue in the log as to what is going on.

 

*edit: also, having your code in a github repository is super helpful. If you are not familiar with it, google "getting started with github" or something similar, and figure it out, you will thank me I promise :D

Edited by Ugdhar

  • Author

@Ugdhar sorry, its been a day. here is a link to my repository all of the entity code is in the entities package, and the ClientSetup class is where client side stuff is registered

  • Author
5 minutes ago, Mekelaina said:

@Ugdhar sorry, its been a day. here is a link to my repository all of the entity code is in the entities package, and the ClientSetup class is where client side stuff is registered

heres the log

  • Author

the entity wont render, and most of the time im not even sure if my wand item is actually creating the entity. and occasionally ill get the message in chat of it hitting a certain block but not consistently.

16 minutes ago, Mekelaina said:

the entity wont render, and most of the time im not even sure if my wand item is actually creating the entity. and occasionally ill get the message in chat of it hitting a certain block but not consistently.

Well, I have yet to mess with entities myself to be completely honest, I've only tinkered with a couple mobs so far.

I guess starting at the Wand part, where you have the item right click, what are those 2s for in the SpellBoltEntity constructor?

To begin with I'd start looking into that.

  • Author
12 minutes ago, Ugdhar said:

Well, I have yet to mess with entities myself to be completely honest, I've only tinkered with a couple mobs so far.

I guess starting at the Wand part, where you have the item right click, what are those 2s for in the SpellBoltEntity constructor?

To begin with I'd start looking into that.

the 2s were just a constant acceleration for the entity. Most of the actual code for the projectile entity was taken from vanillas fireball code. They are used to calculate how quickly the entity should accelerate.

1 hour ago, Mekelaina said:

the 2s were just a constant acceleration for the entity. Most of the actual code for the projectile entity was taken from vanillas fireball code. They are used to calculate how quickly the entity should accelerate.

Well, by my guess, having all 2s will make it accelerate in all 3 directions at once (X/Y/Z) in the same direction every time, and not in the direction you are looking. Again, I haven't tried doing any of this myself as of yet, so this is just a guess.

 

You should take a look at the ghast entity maybe, and see how it launches the fireball. Just instead of in the direction of the player, have your code use the direction the player is looking.

Edited by Ugdhar

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

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.