Jump to content

Recommended Posts

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

 

Posted
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?

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

Posted (edited)
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
Posted

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.

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

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

Posted (edited)
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...

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