Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[1.7.10] Custom Entity Won't Spawn Naturally


zanda268_1
 Share

Recommended Posts

After starting with tutorials such as Jabelar's excellent post on Custom Entities and then scouring the Forge forums for similar issues, I have been unable to find any solution that enables my mod to naturally spawn in entities. As a last resort, I'm posting here in hopes that someone can shed some light on my issue.

 

CommonProxy.class

public void postInit(FMLPostInitializationEvent e) 
{
EntityManager.registerEntities();
}

 

Note: I originally had it in the preInit method but I read somewhere that maybe what I was accessing hadn't been initialized yet (but not throwing an error?) so I moved it here.

 

EntityManager.class

public static void registerEntities()
{
//Entity.class, Texture Name, Tracking Range, Update Frequency, Should Track, Spawn Prob, Spawn min, Spawn Max
RegistryManager.register(new CustomEntityInfo(Runner.class, "Runner", 80, 3, false, 1000, 1, 7));
}

 

CustomEntityInfo is just a holding object for data I feed into the EntityRegistry. Click the spoiler should you wish to see it.

 

 

CustomEntityInfo.class

public class CustomEntityInfo 
{
private static int mobID = 0;

private final Class<? extends EntityLiving> storedClass;
private final String name;
private final int id;
private final int trackingRange;
private final int updateFreq;
private final boolean shouldTrack;
private final int spawnProbability;
private final int spawnMin;
private final int spawnMax;
private final BiomeGenBase[] spawnBiomes;

public CustomEntityInfo(Class<? extends EntityLiving> storedClass, String name, int trackingRange, int updateFreq, boolean shouldTrack, int spawnProbability, int spawnMin, int spawnMax, BiomeGenBase... spawnBiomes) 
{
	id = mobID++;

	if(id>255)
	{
		throw new IllegalArgumentException("You cant have more than 255 mobs! Go refactor some of them.");
	}

	this.storedClass = storedClass;
	this.name = name;
	this.trackingRange = trackingRange;
	this.updateFreq = updateFreq;
	this.shouldTrack = shouldTrack;
	this.spawnProbability = spawnProbability;
	this.spawnMin = spawnMin;
	this.spawnMax = spawnMax;

	if(spawnBiomes == null)
	{
		Set<BiomeGenBase> temp = new HashSet<BiomeGenBase>();
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.BEACH));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.BEACH));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.COLD));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.CONIFEROUS));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.DEAD));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.DENSE));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.DRY));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.END));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.FOREST));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.HILLS));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.HOT));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.JUNGLE));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.LUSH));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.MAGICAL));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.MESA));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.MOUNTAIN));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.MUSHROOM));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.NETHER));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.PLAINS));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SANDY));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SAVANNA));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SNOWY));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SPARSE));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SPOOKY));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.SWAMP));
		Collections.addAll(temp, BiomeDictionary.getBiomesForType(Type.WASTELAND));

		this.spawnBiomes = temp.toArray(this.spawnBiomes);
	}
	else
		this.spawnBiomes = spawnBiomes;
}

public Class<? extends EntityLiving> getStoredClass()
{
	return storedClass;
}

public String getName()
{
	return name;
}

public int getID()
{
	return id;
}

public int getTrackingRange()
{
	return trackingRange;
}

public int getUpdateFreq()
{
	return updateFreq;
}

public boolean getShouldTrack()
{
	return shouldTrack;
}

public int getSpawnProbability()
{
	return spawnProbability;
}

public int getSpawnMin() 
{
	return spawnMin;
}

public int getSpawnMax() 
{
	return spawnMax;
}

public BiomeGenBase[] getSpawnBiomes() 
{
	if(spawnBiomes == null)
		return BiomeGenBase.getBiomeGenArray();
	return spawnBiomes;
}


}

 

 

 

And finally where the magic happens.

 

RegistryManager.class

public static void register(CustomEntityInfo e) 
{				
EntityRegistry.registerModEntity(e.getStoredClass(), e.getName(), e.getID(), Mod.instance, e.getTrackingRange(), e.getUpdateFreq(), e.getShouldTrack());
EntityRegistry.addSpawn(e.getStoredClass(), e.getSpawnProbability(), e.getSpawnMin(), e.getSpawnMax(), EnumCreatureType.creature, e.getSpawnBiomes());	
}

 

I have tried just about everything. I tried specifying Biomes directly in the EntityRegistry.addSpawn() method and I even tried extending EntityLiving and using EnumCreatureType.Ambient. They only thing I have not tried yet is using EntityRegistry's methods to register a Global ID as that is backwards thinking and there has to be some way to do this without limiting ourselves to only 255 mobs.

 

If you can see where I messed up, a bit of insight would be a great help!

 

#Edit: Realized I forgot to include my entity classes

#Edit^2: Updated code to reflect changes mentioned in third post.

Additional Classes:

 

Runner.class

 

 

public class Runner extends BaseEnemy
{

public Runner(World w)
{
	super(w);
}

@Override
protected void applyEntityAttributes()
{
	super.applyEntityAttributes(); 

	// standard attributes registered to EntityLivingBase
	getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(8.0D);
	getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.9D);
	getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(4.0D);
}

}

 

 

 

BaseEnemy.class

 

 

public abstract class BaseEnemy extends AbstractEntity
{

public BaseEnemy(World w) 
{
	super(w);
}

@Override
void setupTasks() 
{	
	//Clear all inhierited tasks
	this.clearAITasks();

	//Configure Navigator
	this.getNavigator().setAvoidSun(false);
	this.getNavigator().setAvoidsWater(true);
	this.getNavigator().setBreakDoors(true);
	this.getNavigator().setCanSwim(false);
	this.getNavigator().setEnterDoors(false);

	//Set Tasks
        this.tasks.addTask(2, new EntityAIAttackOnCollide(this, 0.5D, false));
        this.tasks.addTask(0, new EntityAIBreakDoor(this));
        this.tasks.addTask(5, new EntityAIMoveTowardsRestriction(this, 0.5D));
        this.tasks.addTask(7, new EntityAIWander(this, 0.5D));
        this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(8, new EntityAILookIdle(this));
        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true));
        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, BaseSoldier.class, 0, true));
}

@Override
protected void applyEntityAttributes()
{
	super.applyEntityAttributes(); 

	getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(40D);
}
}

 

 

 

AbstractEntity.class

 

 

public abstract class AbstractEntity extends EntityLiving
{
public AbstractEntity(World w)
{
	super(w);
	setupTasks();
}

abstract void setupTasks();

@Override
protected boolean isAIEnabled()
{
	return true;
}

@Override
protected boolean canDespawn()
{
	return true;
}

@Override
protected void applyEntityAttributes()
{
	super.applyEntityAttributes();

	if(this.getEntityAttribute(SharedMonsterAttributes.attackDamage)==null)
		getAttributeMap().registerAttribute(SharedMonsterAttributes.attackDamage);
	if(this.getEntityAttribute(SharedMonsterAttributes.followRange)==null)
		getAttributeMap().registerAttribute(SharedMonsterAttributes.followRange);
	if(this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance)==null)
		getAttributeMap().registerAttribute(SharedMonsterAttributes.knockbackResistance);
	if(this.getEntityAttribute(SharedMonsterAttributes.maxHealth)==null)
		getAttributeMap().registerAttribute(SharedMonsterAttributes.maxHealth);
	if(this.getEntityAttribute(SharedMonsterAttributes.movementSpeed)==null)
		getAttributeMap().registerAttribute(SharedMonsterAttributes.movementSpeed);

}

protected void clearAITasks()
{
	tasks.taskEntries.clear();
	targetTasks.taskEntries.clear();
}

}

 

 

 

Link to comment
Share on other sites

There are:

Idiots,

Illuminati believers,

SOPA supporters,

and then...10,000 leagues below all of them, well there's me.

 

Just realized I never replaced the placeholder 0 i had in my CustomEntityInfo.getSpawnProbability() method.

 

After that didn't fix it, I decided on a whim to check the contents of BiomeGenBase.getBiomeGenArray() at runtime...and found its empty.

 

After replacing both of those things with concrete details, I get lovely zombies everywhere. Thanks to MinecraftForge.com for giving me a place to re-examine all of my code all over again. Till the next time I return a 0 instead of an actual value!

 

Link to comment
Share on other sites

Alright so I have half solved my problem. After having my AbstractEntity.class extend EntityLiving and setting my EnumCreatureType as Ambient, I get tons of spawns. However, is there any way to, say, extend EntityMob and set the Enum as Monster? Or even better, where are the controls located to control the finer details in terms of spawning? If anyone knows of a good tutorial/starting point, I would appreciate it!

Link to comment
Share on other sites

I think you can put any EnumCreatureType you want in the addSpawn method. The options are creature, ambient, monster and waterCreature.

 

I'm not sure where the finer controls are specifically, but you could probably just hook into the events that generate the world and do your own spawning code instead.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Hmmm, it should work I think. But the code is a bit convoluted.

 

As far as I can tell, there is a list for each enum type such as spawnableMonsterList, spawnableCreatureList, spawnableWaterCreatureList and spawnableCaveCreatureList (for ambient type).

 

The BiomeGenBase class has the getSpawnableList() method which returns each of those lists based on the enum type.

 

The addSpawn() method seems to add onto the list as provided by the getSpawnableList() method. So if you add spawn with EnumEntityType.creature it should get added to the spawnableCreatureList.

 

The spawning of EnumEntityType.creature is done with the performWorldGenSpawning() method in the SpawnerAnimals class. This is called by the ChunkProvider class' populate() method, depending on what the TerrainGen.populate() method allows. Any terrain that allows ANIMALS should populate creature entity type.

 

Sorry, I don't know what else is wrong. Are you getting any other console errors? Sometimes my entities don't spawn if they have some constructor or reflection error during creation.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

No, no errors of any kind coming from my mod on start up. Though there is one odd thing to note. Every time I start up a world, as I load into it, the constructor for one of my entities is called like clockwork. I never see it (unless it is underground) and no more ever spawn. Just an oddity I noticed a little while back while trouble shooting.

Link to comment
Share on other sites

K see now I'm pissed. It was working good enough (as far I am am concerned). I went fiddling with a couple things and after setting my entities back to inheriting EntityLiving and setting the Enum to Ambient...nothing...happens. Ah, the joy that is Forge.

 

EDIT: And we delve even deeper into this mystery. Turns out all of my entities constructors are being called a couple times right at world initialization. I still never see them and after that, nothing else spawns or attempts too. And this is with the EntityLiving/Ambient setup. I remember reading something like this awhile ago. I'm gonna go see if I can find it again.

 

FINAL EDIT: I'm pretty sure I serve as a cautionary tale for modders to always quintuple check their work. The code block in the constructor of my CustomEntityInfo.class that handled the instantiation of the proper biomeList was failing the if statement because the passed biomeList was never null as I was using that handy BiomeGenBase... parameter.

 

TD:LR (whatever that means): Always, always check your passed biomes to your EntityRegistry.addSpawn() method if nothing is spawning and your spawn eggs still work. Good night and stay classy San Diego

Link to comment
Share on other sites

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

 Share



×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.