Minecraft Modding: Quick Tips For Entities

Comprehensive Tutorial For Custom Living Entities


See my detailed tutorial: Jabelar's Custom Living Entity Tutorial.

Extending The Player's Weapon Reach


Changing The Drops For A Vanilla Entity


Use the LivingDropsEvent to change drops.  See my tutorial: Jabelar's Change Vanilla Entity Drops Tutorial.

Entity and Player UUIDs (And Usernames)

A UUID is a 128-bit value (two long values) that are combined to created a "universally unique" identifier for something. Minecraft uses these for every entity, including players.

Additionally, entities have an "entity ID" and players have a username. These can be useful, but it they have limitations. The entity ID changes (potentially) every time the world loads, and usernames can now change on the Mojang authentication servers.

This means that if you want to identify a specific entity, it is better to use the UUID instead of the entity ID. Similarly it is better to use the UUID instead of a player's username.

There are a few methods that are useful when dealing with entity/player UUIDS.

First of all, it is useful to understand the data format of a UUID because you may want to store it in an NBT or pass it in a custom packet payload. A UUID consists of two long values, called the "most significant" and "least significant". The UUID class has methods getMostSignificantBits() and getLeastSignificantBits() which can retrieve those, and you can re-construct a UUID by passing those longs back into the UUID constructor. So if you wanted to store a UUID in an NBT, you could retrieve the two longs and store them as longs with an appropriate tag.

Alternatively, you can convert a UUID to and from a string. There is the static methods toString() and fromString() which can provide the conversions. So instead of storing longs in an NBT, you could store the string instead.

To get the UUID of an entity, you should use the Entity#getUniqueID() or Entity#getPersistentID method (they both return same value).

Warning: Do not use the getEntityID() method as that returns the temporary ID that may change on next world load.

Although there is a World method to look up a player by UUID, it is preferable to search across all dimensions. Thanks to diesieben07 for this tip:


public static EntityPlayer getPlayerOnServerFromUUID(UUID parUUID) 
{
    if (parUUID == null) 
    {
        return null;
    }
    List<EntityPlayerMP> allPlayers = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
    for (EntityPlayerMP player : allPlayers) 
    {
        if (player.getUniqueID().equals(parUUID)) 
        {
            return player;
        }
    }
    return null;
}

Note: The above code won't give you a username for an offline player. So in the case that it returns null, you need to further query the Mojang authentication server. See diesieben07's example. here.

Using NBT To Hold Custom Entity Fields, Facilitating Sync As Well As Save


It is likely that any custom fields that you want to save/load you will also want to sync between client and server. The writeToNBT() and readToNBT() are available to aid saving and loading such data but do not take care of syncing between client and server. So I suggest that in your entity class you create an instance NBTTagCompound field that contains all your custom fields and use that for both the saving/loading and the syncing.  The advantage is that while you're coding you'll probably add more custom fields and in this approach you only have to add them in one place (in the NBTTagCompound) to ensure they are both saved and synced.

 Let me explain further. In my custom entity class I might declare an NBTTagCompound as follows:

protected NBTTagCompound extPropsCompound = new NBTTagCompound();

Then in the constructor for the custom entity I put something like this (these are fields I made up for use in my entities, change as appropriate to your case):

extPropsCompound.setFloat("scaleFactor", 1.0F);
extPropsCompound.setInteger("state", STATE_PERCHED);
extPropsCompound.setInteger("stateCounter", 0);
extPropsCompound.setDouble("anchorX", posX);
extPropsCompound.setDouble("anchorY", posY);
extPropsCompound.setDouble("anchorZ", posZ);

Also good practice to create a getter and setter method:

@Override
public NBTTagCompound getExtProps()
{
    return extPropsCompound;
}

@Override 
public void setExtProps(NBTTagCompound parCompound) 
{
    extPropsCompound = parCompound;
}

Lastly, the various packet systems use ByteBuf as the packet payloads.  There is a ByteBufUtils class in Forge that provides methods for directly reading and writing NBTTagCompound to the ByteBuf. So you can process your received packet payload with something like this:

extPropsCompound = ByteBufUtils.readTag(receivedByteBuf);

And you can create your transmit packet payload with something like this:

ByteBufUtils.writeTag(transmitByteBuf, extPropsCompound);

In this way, you can ensure that all your custom fields are both saved and synced without having to code it in two places.

Adding Name For Hover-Over Custom Entities


There is an event that gets fired during rendering of EntityLiving to check for a custom name, if your mouse is hovering over the entity.  You can @Override the setCustomNameTag()method to add such a name, usually in your custom entity's constructor.  Note that adding the EnumChatFormatting (such as colors) to the name string did not seem to have any effect.


Changing The Player Respawn Point


Key Point: There is a difference between the initial spawn and respawns. The initial spawn will be at a spawnable position in an area around the world's default spawn point (and in adventure mode it is exactly on the world's default spawn point, even if that wouldn't normally be considered a spawnable position like up in the air). Once the player starts playing, the player respawn point is the position it initially spawned unless the player sleeps in a bed or uses the /setspawnpoint command, in which case the position of the latest bed (or set spawn point) becomes the new respawn point. If the bed becomes an unspawnable position, or if the bed was destroyed, then the respawn point will return to the player's initial spawn point.

Tip: The player can be forced to respawn somewhere ignoring beds with s boolean that is passed in the EntityPlayer#setSpawnPoint() method.

The respawn dimension is determined by the world type. The game will first try to respawn the player in their current dimension, unless that dimension is specified to not allow respawns (like the Nether and the End). In that case the world type specifies the respawn dimension (in case of the Nether and the End: the Overworld).

So there are actually multiple spawn points -- each dimension's default spawn point and the player's current respawn point. Once the dimension is determined as explained above, the game will try to spawn the player at the player spawn point. But if there is some reason that the player can't spawn at the player spawn point (for example location is obstructed or if the player has forced spawn set).

Warning: There is a WorldServer method called getSpawnCoordinate() but this is only checked if the dimension is the End. So it is not useful for modding.

Anyway, putting this all together:

  • If you make a custom dimension, consider using the World#setSpawnPoint() method to control the initial spawn point.
  • If you want to set or get the player respawn point, use the EntityPlayer#setSpawnPoint() and #getSpawnPoint() methods.

Making Player Fly Like Creative


If you have the player object instance, you can directly set the capabilities with player.capabilities.allowFlying = true.

Making Player Invulnerable Like Creative


If you have the player object instance, you can directly set the capabilities with player.capabilities.disableDamage = true.

Turn Off Player Health Regeneration


Thanks to Choonster for this tip. You can set the value of the naturalRegeneration game rule to false to disable health regeneration. Use World#getGameRules to get the GameRules object for a World, then use GameRules#setOrCreateGameRule() method to set the value for a rule.

Warning: This will affect all players. If you only want to affect one player you need to take a different approach: record the EntityPlayer#foodStats.foodTimer (foodStats is protected and foodTimer is private so you'll have to use reflection to access) at the time the effect starts and then handle the PlayerTickEvent and again use reflection to keep the foodTimer set to that amount.

Adding Velocity To A Player Entity


For most entities, you can add velocity by simply modifying the motionX, motionY, and motionZ for the entities.

However, if you try to do that with a player entity you'll find the results may not work. This is because, to make the player movement have minimal lag, the client has more control of the movement, with the server mostly just making sure that the movement is allowed. Because of this additional synchronization, you need to do two things:
  1. Make sure the motion is added on client side. (It is okay but not necessary to also add it on the server.)
  2. Make sure you set the EntityPlayer#velocityChanged to true.


Set An Entity On Fire


For some reason this question gets asked a lot on the forums but the Entity class has a setFire(int numberOfSeconds) method.  Note that if the Entity has fire protection the method takes that into account.

Adding Custom AI To Your Entity


See my detailed tutorial: Jabelar's Custom Entity AI Tutorial

Finding Block Under an Entity (Including Player)


Sometimes it is useful to find the block underneath an entity.  It is pretty simple really, but I see this question asked and some people get confused because the block position uses int versus the double used by entity position, plus entities have some y offsets that need to be considered.

public Block findBlockUnderEntity(Entity parEntity)
{
    int blockX = MathHelper.floor_double(parEntity.posX);
    int blockY = MathHelper.floor_double(parEntity.posY-0.2D - (double)parEntity.yOffset);
    int blockZ = MathHelper.floor_double(parEntity.posZ);
    return parEntity.worldObj.getBlock(blockX, blockY, blockZ);
}

However, for custom entities it is possible that the yOffset isn't properly set.  It may be preferable (suggested by CoolAlias) to use the bounding box instead.  So this version is probably the more trustworthy:

public Block findBlockUnderEntity(Entity parEntity)
{
    int blockX = MathHelper.floor_double(parEntity.posX);
    int blockY = MathHelper.floor_double(parEntity.boundingBox.minY)-1;
    int blockZ = MathHelper.floor_double(parEntity.posZ);
    return parEntity.worldObj.getBlock(blockX, blockY, blockZ);
}

Changing the Bounding (Collision) Box of an Entity


The bounding box of an Entity is used for both path-finding and for collisions (including attacks). Also, the bounding box is always square on the x-z side (i.e. top and bottom) but the height can vary. These restrictions are a bit unfortunate (separate control for each would be nice) but that's just the way it is.

Bonus Tip: You can see the bounding boxes of all the entities in-game by pressing F3+B.  This is extremely useful when you make custom entity models as you'll usually want the bounding box adjusted for both position and size.

Anyway, changing the bounding box is easy.  You use the setSize() method, usually in the constructor of your entity.   setSize() takes two float parameters, width and height respectively.  Remember that "width" also sets "depth" of the box.

You can check out existing entities to see the size set for them to get a feel for this method.

Note: The setSize() does not affect scaling of your model at all. Model scaling is done directly in your model (or can also be done in the preRenderCallback() method of your Renderer class registered to your entity).

Note: Since the bounding box is used for collisions, be cautious in setting the width larger than 1.0F as then it may have trouble finding paths through narrow places.  Of course if your entity is big then that might make sense, but just be aware that the bigger the bounding box, the less ability the Entity will have to find paths.

Finding The General Direction An Entity is Facing


If you just want to know whether an entity is facing North, East, South or West, you can use a formula to convert the rotation yaw into the ordinal directions, like this:

int d = MathHelper.floor_double((double) (entity.rotationYaw * 4.0F / 360) + 0.50) & 3;

For more about how directions and pitch/yaw relate to the x, y, z coordinates in Minecraft, see: Explanation Of Minecraft Coordinate System.

Finding The Block An Entity Or Player Is Looking At


When discussing "looking at" it is important to separate the concept of the player (i.e. the human playing the game looking at the screen) and the player entity (the character representing the human within the game).

Finding The Block (Or Entity) The EntityPlayer Is Looking At


Some people think they should use getLookVec() but while that can be a useful method it simply returns the specific vector indicating the direction (not what is in that direction) you are looking.  The method that actually returns the block or entity that you're looking at is rayTrace() from EntityLivingBase (which calls func_147447_a()that does the real work in World).

Finding The Block (Or Entity) The User Is Looking At


In this case I'm concerned with what the human actually sees (i.e. through the "camera"), and that is best represented by the renderViewEntity rather than the player entity itself.

Key Point: If you're interested in what a custom item is clicked on, you don't need to do any of this. The onItemUse() method provides the block clicked on.

Now it is possible that you are interested in some other Entity, but most people are interested in what the player is looking at and there is actually a special entity which tracks the player for purpose of rendering the view: the renderViewEntity instance from the current Minecraft instance is special Entity related to the client view, basically representing the "camera".  Usually tracks the player entity but could be moved by a mod and is of course different in 1st or 3rd person view.

The MovingObjectPosition class is key to various methods that process looking, because they convert a vector (which can represent movement but can also represent a direction something is looking) into a "collision" that returns a Block or Entity (don't forget it can also return null if it hits nothing).

Anyway, here is a code example (thanks to Feldspar for forum post that developed the idea):

MovingObjectPosition mop = Minecraft.getMinecraft().renderViewEntity.rayTrace(200, 1.0F);
if(mop != null)
{
    int blockHitSide = mop.sideHit;
    Block blockLookingAt = worldObj.getBlock(mop.blockX, mop.blockY, mop.blockZ) ; 
}

The 200 defines how far the rayTrace will go.  200 seems to allow it to go basically to the edge of loaded chunks, but you can change the number if it makes sense in your use case. The 1.0F defines the "partial ticks" that I believe is used to filter out execution of the method for those cases where a lot of ray tracing is done and could cause lag.

An alternative way, suggested by CoolAlias is to use Minecraft.getMinecraft().objectMouseOver, which is the current MovingObjectPosition as determined by the EntityRenderer.

Bonus Tip: If you're interested in making the cross-hairs change based on what they are focused on, use it during RenderGameOverlayEvent.Pre for event.type == ElementType.CROSSHAIRS.

Adding Custom Fields To An Entity (Including Vanilla Entities And Player)


Forge provides an interface called IExtendedEntityProperties that uses NBTTagCompound to save and load custom fields for your entity.  I also suggest that you can use the same NBTTagCompound in your client-server sync packet payloads.  See my in-depth tutorial at: Jabelar's Extended Entity Properties Tutorial.

Checking If A Player Is "Opped"


Some players on a server have operator permissions.  This is often called being "opped".  In earlier versions of Minecraft Forge you could check this with:

MinecraftServer.getServer().getConfigurationManager().isPlayerOpped()

but now you can use:

player.canCommandSenderUseCommand(2, "")

Adjust The Rider Position


Depending on your entity, you may want to adjust the rider's relative position.  You can do this in the ridden entity's updateRiderPosition() method, which is by default like this:

public void updateRiderPosition()
{
    if (riddenByEntity != null)
    {
        riddenByEntity.setPosition(posX, posY+getMountedYOffset()
              +riddenByEntity.getYOffset(), posZ);
    }
}

And you can adjust the positions further as needed for your case.

Animated Textures For Entity Models


Blocks and items can have animated textures, but it is actually a bit difficult with Entity models. This is because in the ModelRenderer class, the texture offset is set at creation and there is no method to adjust it thereafter!

It is technically possible to create your own ModelRenderer subclass with texture offset capability, but it is actually pretty involved because it calls further classes that also don't have methods to easily adjust and those would need to be changed too.

Java reflection would also be fairly involved because you'd have to traverse some arrays and couple levels of classes.

So you have two more straight-forward choices for animating the texture:
  1. You can create new ModelRenderer each time the texture offset changes, or 
  2. You can pre-make an array of ModelRenderer with each offset you might use and then select them during the render.
Which approach to use depends on whether you can predict which offsets you'll need to use (in that case use the second one).

Custom Death Messages For New Damage Sources


Thanks to diesieben07 for this tip.

While it is possible to just handle the LivingDeathEvent and figure out messages to print, the more "proper" way to mod this is to create a custom DamageSource to match the new type of damage you'd like to track. Use it when applying damage to entities.

Furthermore, any time you put text in your mod you should properly manage it through the .lang file (see my supplementary tutorial on .lang file) to enable localization (i.e. publishing the mod later in other languages). For that you need two entries in your .lang file:

death.attack.<type>=%s died by whatever
death.attack.<type>.player=%1$s was killed by %2$s using whatever

The first one is for a regular kill, the 2nd one is for being killed by a player (you do not necessarily need this one, the first one will be used if you don't have it).

<type> is a placeholder for your DamageSource name (you pass it to the constructor). It should include your mod id to avoid conflicts with other mods that might happen to create a death message with same name.

Have Your Custom Entity Pick Up An EntityItem


Thanks to TLHPoE for this suggestion.

For some of your custom mobs, you may want them to pick items off the ground either to wield or to put in their inventory.  To do this, you should be able to (untested by me) @Override your custom entity's collideWithNearbyEntities() method in your mob and checking for any EntityItem. If it finds any, code what you want, such as equipping the item in your mob.  Make sure you "kill" the EntityItem by calling its setDead() method.

Checking For Original Damage Source That Killed Entity


When an entity is killed, sometimes you may want to know who/what killed it. However, this can be complicated a bit by indirect damage. For example, if you shoot an arrow technically the arrow is the entity that killed but you probably want to know the player (or skeleton or whatever) that shot the arrow.

In the event parameter passed to the event handler you can check either the direct or indirect source as follows:
  • event.source.getSourceOfDamage() returns ultimate source of damage (player that shot the arrow)
  • event.source.getEntity() returns any entity that dealt it (the arrow)
Note that this still won't indicate truly indirect source, such as if an entity pushes and causes a fall or if it sets something on fire that later burns to death.

Making An Entity Glow (I.e. A Light Source)

I have a tutorial on having light follow the player when holding specific items (like torches). This same technique could be used to make a glowing entity. The only difference would be that instead of checking for holding an item, you'd just make the light happen all the time. Check out: Jabelar's Moving Light Source Tutorial.

How To Put Armor On A Mob


You may want to spawn an EntityZombie with armor already on. To do this use the setCurrentItemOrArmor() method. You can call this before spawning the entity if you want it to start with the armor.

6 comments:

  1. The "ordinal direction" equation seems over-complicated. Is there any particular reason you use this:
    int d = MathHelper.floor_double((double) (entity.rotationYaw * 4.0F / 360) + 0.50) & 3;
    instead of this?
    int d = Math.round(entity.rotationYaw / 90.0F) % 4;
    I did notice that sometimes the client gets a different result than the server, but that is true for both equations...

    ReplyDelete
  2. If you use this: int d = MathHelper.floor_double((double) (entity.rotationYaw * 4.0F / 360) + 0.50) & 3;
    You will get 4 directions (S, W, N and E)

    If you need more precision, you can use this: int d = MathHelper.floor_double((double) (entity.rotationYaw * 8.0F / 360) + 0.50) & 7;
    You will get 8 directions (S, SW, W, NW, N, NE, E and SE)

    Of course you can simplify the equation, but the purpose of keeping it like that is to explain each value

    ReplyDelete
  3. What if I want my custom animal (LivingEntity) to turn and look at a block of my choice? Is there a method that will rotate the head sideways, up & down? Will it also, if necessary, orient the whole animal (do an about-face) if its head can't turn that far? I've tried calling animal.getLookHelper().setLookPosition(x, y, z), but it doesn't do anything (in mc 1.8, Forge b1450).

    ReplyDelete
  4. I need help. Can u show me how to add an enchanted look to mobs plz, like the ones shown on items that have an enchantment, thanks :)

    ReplyDelete
    Replies
    1. this is for the "Enchanted Golden Apple Cow" I wish to create :)

      Delete

  5. 🎮Download Minecraft latest version on link below
    👇
    Minecraft latest version


    💰Get free 250$ on Ysense trusted network without investment

    📢 Join Crypto quantum leap world's famous online Crypto course

    🦷 Read Secret teeth care tips
    About
    Teeth whitening,
    Teeth decay,
    Teethsche,


    ReplyDelete