Started re-adding boat entities

This commit is contained in:
Forstride 2019-05-21 22:37:23 -04:00
parent fbe6213f7e
commit c0739d8f43
9 changed files with 1358 additions and 27 deletions

View File

@ -12,4 +12,5 @@ import net.minecraft.entity.EntityType;
public class BOPEntities
{
public static EntityType<?> mudball;
public static EntityType<?> boat_bop;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
package biomesoplenty.common.entity.item;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.model.IMultipassModel;
import net.minecraft.client.renderer.entity.model.ModelBase;
import net.minecraft.client.renderer.entity.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class ModelBoatBOP extends ModelBase implements IMultipassModel {
private final ModelRenderer[] boatSides = new ModelRenderer[5];
private final ModelRenderer[] paddles = new ModelRenderer[2];
/**
* An invisible layer that is rendered to make it seem like there's no water in the boat.
*
* @see https://redd.it/3qufgo
* @see https://bugs.mojang.com/browse/MC-47636
*/
private final ModelRenderer noWater;
public ModelBoatBOP() {
this.boatSides[0] = (new ModelRenderer(this, 0, 0)).setTextureSize(128, 64);
this.boatSides[1] = (new ModelRenderer(this, 0, 19)).setTextureSize(128, 64);
this.boatSides[2] = (new ModelRenderer(this, 0, 27)).setTextureSize(128, 64);
this.boatSides[3] = (new ModelRenderer(this, 0, 35)).setTextureSize(128, 64);
this.boatSides[4] = (new ModelRenderer(this, 0, 43)).setTextureSize(128, 64);
int i = 32;
int j = 6;
int k = 20;
int l = 4;
int i1 = 28;
this.boatSides[0].addBox(-14.0F, -9.0F, -3.0F, 28, 16, 3, 0.0F);
this.boatSides[0].setRotationPoint(0.0F, 3.0F, 1.0F);
this.boatSides[1].addBox(-13.0F, -7.0F, -1.0F, 18, 6, 2, 0.0F);
this.boatSides[1].setRotationPoint(-15.0F, 4.0F, 4.0F);
this.boatSides[2].addBox(-8.0F, -7.0F, -1.0F, 16, 6, 2, 0.0F);
this.boatSides[2].setRotationPoint(15.0F, 4.0F, 0.0F);
this.boatSides[3].addBox(-14.0F, -7.0F, -1.0F, 28, 6, 2, 0.0F);
this.boatSides[3].setRotationPoint(0.0F, 4.0F, -9.0F);
this.boatSides[4].addBox(-14.0F, -7.0F, -1.0F, 28, 6, 2, 0.0F);
this.boatSides[4].setRotationPoint(0.0F, 4.0F, 9.0F);
this.boatSides[0].rotateAngleX = ((float)Math.PI / 2F);
this.boatSides[1].rotateAngleY = ((float)Math.PI * 1.5F);
this.boatSides[2].rotateAngleY = ((float)Math.PI / 2F);
this.boatSides[3].rotateAngleY = (float)Math.PI;
this.paddles[0] = this.makePaddle(true);
this.paddles[0].setRotationPoint(3.0F, -5.0F, 9.0F);
this.paddles[1] = this.makePaddle(false);
this.paddles[1].setRotationPoint(3.0F, -5.0F, -9.0F);
this.paddles[1].rotateAngleY = (float)Math.PI;
this.paddles[0].rotateAngleZ = 0.19634955F;
this.paddles[1].rotateAngleZ = 0.19634955F;
this.noWater = (new ModelRenderer(this, 0, 0)).setTextureSize(128, 64);
this.noWater.addBox(-14.0F, -9.0F, -3.0F, 28, 16, 3, 0.0F);
this.noWater.setRotationPoint(0.0F, -3.0F, 1.0F);
this.noWater.rotateAngleX = ((float)Math.PI / 2F);
}
/**
* Sets the models various rotation angles then renders the model.
*/
public void render(Entity entityIn, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale) {
GlStateManager.rotatef(90.0F, 0.0F, 1.0F, 0.0F);
EntityBoatBOP entityboat = (EntityBoatBOP)entityIn;
this.setRotationAngles(limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale, entityIn);
for(int i = 0; i < 5; ++i) {
this.boatSides[i].render(scale);
}
this.renderPaddle(entityboat, 0, scale, limbSwing);
this.renderPaddle(entityboat, 1, scale, limbSwing);
}
public void renderMultipass(Entity entityIn, float partialTicks, float p_187054_3_, float p_187054_4_, float p_187054_5_, float p_187054_6_, float scale) {
GlStateManager.rotatef(90.0F, 0.0F, 1.0F, 0.0F);
GlStateManager.colorMask(false, false, false, false);
this.noWater.render(scale);
GlStateManager.colorMask(true, true, true, true);
}
protected ModelRenderer makePaddle(boolean p_187056_1_) {
ModelRenderer modelrenderer = (new ModelRenderer(this, 62, p_187056_1_ ? 0 : 20)).setTextureSize(128, 64);
int i = 20;
int j = 7;
int k = 6;
float f = -5.0F;
modelrenderer.addBox(-1.0F, 0.0F, -5.0F, 2, 2, 18);
modelrenderer.addBox(p_187056_1_ ? -1.001F : 0.001F, -3.0F, 8.0F, 1, 6, 7);
return modelrenderer;
}
protected void renderPaddle(EntityBoatBOP boat, int paddle, float scale, float limbSwing) {
float f = boat.getRowingTime(paddle, limbSwing);
ModelRenderer modelrenderer = this.paddles[paddle];
modelrenderer.rotateAngleX = (float)MathHelper.clampedLerp((double)(-(float)Math.PI / 3F), (double)-0.2617994F, (double)((MathHelper.sin(-f) + 1.0F) / 2.0F));
modelrenderer.rotateAngleY = (float)MathHelper.clampedLerp((double)(-(float)Math.PI / 4F), (double)((float)Math.PI / 4F), (double)((MathHelper.sin(-f + 1.0F) + 1.0F) / 2.0F));
if (paddle == 1) {
modelrenderer.rotateAngleY = (float)Math.PI - modelrenderer.rotateAngleY;
}
modelrenderer.render(scale);
}
}

View File

@ -0,0 +1,90 @@
package biomesoplenty.common.entity.item;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.model.IMultipassModel;
import net.minecraft.client.renderer.entity.model.ModelBase;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class RenderBoatBOP extends Render<EntityBoatBOP> {
private static final ResourceLocation[] BOAT_TEXTURES = new ResourceLocation[]{new ResourceLocation("biomesoplenty:textures/entity/boat/fir.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/redwood.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/cherry.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/mahogany.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/jacaranda.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/palm.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/willow.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/dead.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/magic.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/umbran.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/hellbark.png"), new ResourceLocation("biomesoplenty:textures/entity/boat/ethereal.png")};
/** instance of ModelBoat for rendering */
protected ModelBase modelBoat = new ModelBoatBOP();
public RenderBoatBOP(RenderManager renderManagerIn) {
super(renderManagerIn);
this.shadowSize = 0.5F;
}
/**
* Renders the desired {@code T} type Entity.
*/
public void doRender(EntityBoatBOP entity, double x, double y, double z, float entityYaw, float partialTicks) {
GlStateManager.pushMatrix();
this.setupTranslation(x, y, z);
this.setupRotation(entity, entityYaw, partialTicks);
this.bindEntityTexture(entity);
if (this.renderOutlines) {
GlStateManager.enableColorMaterial();
GlStateManager.enableOutlineMode(this.getTeamColor(entity));
}
this.modelBoat.render(entity, partialTicks, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
if (this.renderOutlines) {
GlStateManager.disableOutlineMode();
GlStateManager.disableColorMaterial();
}
GlStateManager.popMatrix();
super.doRender(entity, x, y, z, entityYaw, partialTicks);
}
public void setupRotation(EntityBoatBOP entityIn, float entityYaw, float partialTicks) {
GlStateManager.rotatef(180.0F - entityYaw, 0.0F, 1.0F, 0.0F);
float f = (float)entityIn.getTimeSinceHit() - partialTicks;
float f1 = entityIn.getDamageTaken() - partialTicks;
if (f1 < 0.0F) {
f1 = 0.0F;
}
if (f > 0.0F) {
GlStateManager.rotatef(MathHelper.sin(f) * f * f1 / 10.0F * (float)entityIn.getForwardDirection(), 1.0F, 0.0F, 0.0F);
}
float f2 = entityIn.func_203056_b(partialTicks);
if (!MathHelper.epsilonEquals(f2, 0.0F)) {
GlStateManager.rotatef(entityIn.func_203056_b(partialTicks), 1.0F, 0.0F, 1.0F);
}
GlStateManager.scalef(-1.0F, -1.0F, 1.0F);
}
public void setupTranslation(double x, double y, double z) {
GlStateManager.translatef((float)x, (float)y + 0.375F, (float)z);
}
/**
* Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
*/
protected ResourceLocation getEntityTexture(EntityBoatBOP entity) {
return BOAT_TEXTURES[entity.getBoatType().ordinal()];
}
public boolean isMultipass() {
return true;
}
public void renderMultipass(EntityBoatBOP entityIn, double x, double y, double z, float entityYaw, float partialTicks) {
GlStateManager.pushMatrix();
this.setupTranslation(x, y, z);
this.setupRotation(entityIn, entityYaw, partialTicks);
this.bindEntityTexture(entityIn);
((IMultipassModel)this.modelBoat).renderMultipass(entityIn, partialTicks, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
GlStateManager.popMatrix();
}
}

View File

@ -0,0 +1,106 @@
/*******************************************************************************
* Copyright 2014-2019, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.item;
import java.util.List;
import biomesoplenty.common.entity.item.EntityBoatBOP;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.StatList;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceFluidMode;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class ItemBoatBOP extends Item
{
private final EntityBoatBOP.Type type;
public ItemBoatBOP(EntityBoatBOP.Type typeIn, Item.Properties properties)
{
super(properties);
this.type = typeIn;
}
/**
* Called to trigger the item's "innate" right click behavior. To handle when this item is used on a Block, see
* {@link #onItemUse}.
*/
public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn) {
ItemStack itemstack = playerIn.getHeldItem(handIn);
float f = 1.0F;
float f1 = playerIn.prevRotationPitch + (playerIn.rotationPitch - playerIn.prevRotationPitch) * 1.0F;
float f2 = playerIn.prevRotationYaw + (playerIn.rotationYaw - playerIn.prevRotationYaw) * 1.0F;
double d0 = playerIn.prevPosX + (playerIn.posX - playerIn.prevPosX) * 1.0D;
double d1 = playerIn.prevPosY + (playerIn.posY - playerIn.prevPosY) * 1.0D + (double)playerIn.getEyeHeight();
double d2 = playerIn.prevPosZ + (playerIn.posZ - playerIn.prevPosZ) * 1.0D;
Vec3d vec3d = new Vec3d(d0, d1, d2);
float f3 = MathHelper.cos(-f2 * ((float)Math.PI / 180F) - (float)Math.PI);
float f4 = MathHelper.sin(-f2 * ((float)Math.PI / 180F) - (float)Math.PI);
float f5 = -MathHelper.cos(-f1 * ((float)Math.PI / 180F));
float f6 = MathHelper.sin(-f1 * ((float)Math.PI / 180F));
float f7 = f4 * f5;
float f8 = f3 * f5;
double d3 = 5.0D;
Vec3d vec3d1 = vec3d.add((double)f7 * 5.0D, (double)f6 * 5.0D, (double)f8 * 5.0D);
RayTraceResult raytraceresult = worldIn.rayTraceBlocks(vec3d, vec3d1, RayTraceFluidMode.ALWAYS);
if (raytraceresult == null) {
return new ActionResult<>(EnumActionResult.PASS, itemstack);
} else {
Vec3d vec3d2 = playerIn.getLook(1.0F);
boolean flag = false;
List<Entity> list = worldIn.getEntitiesWithinAABBExcludingEntity(playerIn, playerIn.getBoundingBox().expand(vec3d2.x * 5.0D, vec3d2.y * 5.0D, vec3d2.z * 5.0D).grow(1.0D));
for(int i = 0; i < list.size(); ++i) {
Entity entity = list.get(i);
if (entity.canBeCollidedWith()) {
AxisAlignedBB axisalignedbb = entity.getBoundingBox().grow((double)entity.getCollisionBorderSize());
if (axisalignedbb.contains(vec3d)) {
flag = true;
}
}
}
if (flag) {
return new ActionResult<>(EnumActionResult.PASS, itemstack);
} else if (raytraceresult.type == RayTraceResult.Type.BLOCK) {
BlockPos blockpos = raytraceresult.getBlockPos();
Block block = worldIn.getBlockState(blockpos).getBlock();
EntityBoatBOP entityboat = new EntityBoatBOP(worldIn, raytraceresult.hitVec.x, raytraceresult.hitVec.y, raytraceresult.hitVec.z);
entityboat.setBoatType(this.type);
entityboat.rotationYaw = playerIn.rotationYaw;
if (!worldIn.isCollisionBoxesEmpty(entityboat, entityboat.getBoundingBox().grow(-0.1D))) {
return new ActionResult<>(EnumActionResult.FAIL, itemstack);
} else {
if (!worldIn.isRemote) {
worldIn.spawnEntity(entityboat);
}
if (!playerIn.abilities.isCreativeMode) {
itemstack.shrink(1);
}
playerIn.addStat(StatList.ITEM_USED.get(this));
return new ActionResult<>(EnumActionResult.SUCCESS, itemstack);
}
} else {
return new ActionResult<>(EnumActionResult.PASS, itemstack);
}
}
}
}

View File

@ -12,9 +12,9 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemRecord;
import net.minecraft.util.SoundEvent;
public class ItemBOPRecord extends ItemRecord
public class ItemRecordBOP extends ItemRecord
{
public ItemBOPRecord(SoundEvent record)
public ItemRecordBOP(SoundEvent record)
{
super(0, record, new Item.Properties().group(ItemGroupBOP.instance));
}

View File

@ -7,28 +7,28 @@
******************************************************************************/
package biomesoplenty.init;
import biomesoplenty.common.entity.projectile.EntityMudball;
import static biomesoplenty.api.entity.BOPEntities.*;
import java.util.function.Function;
import com.mojang.datafixers.DataFixUtils;
import com.mojang.datafixers.types.Type;
import biomesoplenty.common.entity.item.EntityBoatBOP;
import biomesoplenty.common.entity.projectile.EntityMudball;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.monster.EntitySpider;
import net.minecraft.item.Item;
import net.minecraft.util.SharedConstants;
import net.minecraft.util.datafix.DataFixesManager;
import net.minecraft.util.datafix.TypeReferences;
import net.minecraft.world.World;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.function.Function;
import static biomesoplenty.api.entity.BOPEntities.*;
public class ModEntities
{
public static void init()
{
mudball = registerEntity(FixedEntityTypeBuilder.create(EntityMudball.class, EntityMudball::new), "mudball");
boat_bop = registerEntity(FixedEntityTypeBuilder.create(EntityBoatBOP.class, EntityBoatBOP::new), "boat_bop");
}
public static <T extends Entity> EntityType<T> registerEntity(FixedEntityTypeBuilder<T> typeBuilder, String name)

View File

@ -7,10 +7,29 @@
******************************************************************************/
package biomesoplenty.init;
import static biomesoplenty.api.item.BOPItems.*;
import static biomesoplenty.api.item.BOPItems.bop_icon;
import static biomesoplenty.api.item.BOPItems.cherry_boat;
import static biomesoplenty.api.item.BOPItems.chunk_of_flesh;
import static biomesoplenty.api.item.BOPItems.dead_boat;
import static biomesoplenty.api.item.BOPItems.ethereal_boat;
import static biomesoplenty.api.item.BOPItems.fir_boat;
import static biomesoplenty.api.item.BOPItems.hellbark_boat;
import static biomesoplenty.api.item.BOPItems.jacaranda_boat;
import static biomesoplenty.api.item.BOPItems.magic_boat;
import static biomesoplenty.api.item.BOPItems.mahogany_boat;
import static biomesoplenty.api.item.BOPItems.mud_brick;
import static biomesoplenty.api.item.BOPItems.mudball;
import static biomesoplenty.api.item.BOPItems.palm_boat;
import static biomesoplenty.api.item.BOPItems.pile_of_ashes;
import static biomesoplenty.api.item.BOPItems.record_wanderer;
import static biomesoplenty.api.item.BOPItems.redwood_boat;
import static biomesoplenty.api.item.BOPItems.umbran_boat;
import static biomesoplenty.api.item.BOPItems.willow_boat;
import biomesoplenty.api.sound.BOPSounds;
import biomesoplenty.common.item.ItemBOPRecord;
import biomesoplenty.common.entity.item.EntityBoatBOP;
import biomesoplenty.common.item.ItemRecordBOP;
import biomesoplenty.common.item.ItemBoatBOP;
import biomesoplenty.common.item.ItemMudball;
import biomesoplenty.common.util.inventory.ItemGroupBOP;
import net.minecraft.item.Item;
@ -25,21 +44,20 @@ public class ModItems
pile_of_ashes = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "pile_of_ashes");
chunk_of_flesh = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "chunk_of_flesh");
record_wanderer = registerItem(new ItemBOPRecord(BOPSounds.records_wanderer), "record_wanderer");
record_wanderer = registerItem(new ItemRecordBOP(BOPSounds.records_wanderer), "record_wanderer");
// TODO: These all need to be associated with their entities
fir_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "fir_boat");
redwood_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "redwood_boat");
cherry_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "cherry_boat");
mahogany_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "mahogany_boat");
jacaranda_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "jacaranda_boat");
palm_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "palm_boat");
willow_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "willow_boat");
dead_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "dead_boat");
magic_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "magic_boat");
umbran_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "umbran_boat");
hellbark_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "hellbark_boat");
ethereal_boat = registerItem(new Item(new Item.Properties().group(ItemGroupBOP.instance)), "ethereal_boat");
fir_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.FIR, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "fir_boat");
redwood_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.REDWOOD, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "redwood_boat");
cherry_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.CHERRY, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "cherry_boat");
mahogany_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.MAHOGANY, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "mahogany_boat");
jacaranda_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.JACARANDA, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "jacaranda_boat");
palm_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.PALM, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "palm_boat");
willow_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.WILLOW, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "willow_boat");
dead_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.DEAD, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "dead_boat");
magic_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.MAGIC, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "magic_boat");
umbran_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.UMBRAN, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "umbran_boat");
hellbark_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.HELLBARK, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "hellbark_boat");
ethereal_boat = registerItem(new ItemBoatBOP(EntityBoatBOP.Type.ETHEREAL, (new Item.Properties()).maxStackSize(1).group(ItemGroupBOP.instance)), "ethereal_boat");
bop_icon = registerItem(new Item(new Item.Properties()), "bop_icon");
}

View File

@ -350,5 +350,5 @@
"commands.biomesoplenty.tpbiome.error": "Couldn't find biome %s!",
"entity.biomesoplenty.mudball": "Mudball",
"entity.biomesoplenty.bop_boat": "Boat"
"entity.biomesoplenty.boat_bop": "Boat"
}