MineLittlePony/src/main/java/com/minelittlepony/client/pony/Pony.java

262 lines
8.6 KiB
Java

package com.minelittlepony.client.pony;
import com.google.common.base.MoreObjects;
import com.minelittlepony.MineLittlePony;
import com.minelittlepony.client.PonyRenderManager;
import com.minelittlepony.client.ducks.IBufferedTexture;
import com.minelittlepony.client.render.IPonyRender;
import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.hdskins.util.ProfileTextureUtil;
import com.minelittlepony.pony.IPony;
import com.minelittlepony.pony.IPonyData;
import com.minelittlepony.pony.meta.Race;
import com.minelittlepony.pony.meta.Size;
import net.minecraft.block.Material;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.Texture;
import net.minecraft.client.texture.MissingSprite;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.client.texture.NativeImageBackedTexture;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ItemStack;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BoundingBox;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
public class Pony implements IPony {
private static final AtomicInteger ponyCount = new AtomicInteger();
private final int ponyId = ponyCount.getAndIncrement();
private final Identifier texture;
private final IPonyData metadata;
public Pony(Identifier resource) {
texture = resource;
metadata = checkSkin(texture);
}
private IPonyData checkSkin(Identifier resource) {
IPonyData data = checkPonyMeta(resource);
if (data != null) {
return data;
}
NativeImage ponyTexture = getBufferedImage(resource);
if (ponyTexture == null) {
ponyTexture = ProfileTextureUtil.getDynamicBufferedImage(16, 16, MissingSprite.getMissingSpriteTexture());
MinecraftClient.getInstance().getTextureManager().registerTexture(resource, new NativeImageBackedTexture(ponyTexture));
}
return checkSkin(ponyTexture);
}
@Nullable
private IPonyData checkPonyMeta(Identifier resource) {
try {
Resource res = MinecraftClient.getInstance().getResourceManager().getResource(resource);
PonyData data = res.getMetadata(PonyData.SERIALISER);
if (data != null) {
return data;
}
} catch (FileNotFoundException e) {
// Ignore uploaded texture
} catch (IOException e) {
MineLittlePony.logger.warn("Unable to read {} metadata", resource, e);
}
return null;
}
@Nullable
public static NativeImage getBufferedImage(@Nullable Identifier resource) {
if (resource == null) {
return null;
}
try {
Resource skin = MinecraftClient.getInstance().getResourceManager().getResource(resource);
NativeImage skinImage = NativeImage.fromInputStream(skin.getInputStream());
MineLittlePony.logger.debug("Obtained skin from resource location {}", resource);
return skinImage;
} catch (IOException ignored) {
}
Texture texture = MinecraftClient.getInstance().getTextureManager().getTexture(resource);
if (texture instanceof NativeImageBackedTexture) {
return ((NativeImageBackedTexture)texture).getImage();
}
if (texture instanceof IBufferedTexture) {
return ((IBufferedTexture) texture).getBufferedImage();
}
return null;
}
private IPonyData checkSkin(NativeImage bufferedimage) {
MineLittlePony.logger.debug("\tStart skin check for pony #{} with image {}.", ponyId, bufferedimage);
return PonyData.parse(bufferedimage);
}
@Override
public boolean isPerformingRainboom(LivingEntity entity) {
Vec3d motion = entity.getVelocity();
double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
return (isFlying(entity) && canFly()) || entity.isFallFlying() & zMotion > 0.4F;
}
@Override
public boolean isCrouching(LivingEntity entity) {
boolean isSneak = entity.isSneaking();
boolean isFlying = isFlying(entity);
boolean isSwimming = isSwimming(entity);
return !isPerformingRainboom(entity) && !isSwimming && isSneak && !isFlying;
}
@Override
public boolean isFlying(LivingEntity entity) {
return !(entity.onGround
|| entity.hasVehicle()
|| (entity.isClimbing() && !(entity instanceof PlayerEntity && ((PlayerEntity)entity).abilities.allowFlying))
|| entity.isInWater()
|| entity.isSleeping());
}
@Override
public boolean isSwimming(LivingEntity entity) {
return entity.isSwimming() || entity.isInSwimmingPose();
}
@Override
public boolean isPartiallySubmerged(LivingEntity entity) {
return entity.isInWater()
|| entity.getEntityWorld().getBlockState(entity.getBlockPos()).getMaterial() == Material.WATER;
}
@Override
public boolean isFullySubmerged(LivingEntity entity) {
return entity.isInWater()
&& entity.getEntityWorld().getBlockState(new BlockPos(getVisualEyePosition(entity))).getMaterial() == Material.WATER;
}
protected Vec3d getVisualEyePosition(LivingEntity entity) {
Size size = entity.isBaby() ? Size.FOAL : metadata.getSize();
return new Vec3d(entity.x, entity.y + (double) entity.getEyeHeight(entity.getPose()) * size.getScaleFactor(), entity.z);
}
@Override
public boolean isWearingHeadgear(LivingEntity entity) {
ItemStack stack = entity.getEquippedStack(EquipmentSlot.HEAD);
if (stack.isEmpty()) {
return false;
}
Item item = stack.getItem();
return !(item instanceof ArmorItem) || ((ArmorItem) item).getSlotType() != EquipmentSlot.HEAD;
}
@Override
public Race getRace(boolean ignorePony) {
return metadata.getRace().getEffectiveRace(ignorePony);
}
@Override
public Identifier getTexture() {
return texture;
}
@Override
public IPonyData getMetadata() {
return metadata;
}
@Override
public boolean isRidingInteractive(LivingEntity entity) {
return PonyRenderManager.getInstance().getPonyRenderer(entity.getVehicle()) != null;
}
@Override
public IPony getMountedPony(LivingEntity entity) {
Entity mount = entity.getVehicle();
IPonyRender<LivingEntity, ?> render = PonyRenderManager.getInstance().getPonyRenderer(mount);
return render == null ? null : render.getEntityPony((LivingEntity)mount);
}
@Override
public Vec3d getAbsoluteRidingOffset(LivingEntity entity) {
IPony ridingPony = getMountedPony(entity);
if (ridingPony != null) {
LivingEntity ridee = (LivingEntity)entity.getVehicle();
Vec3d offset = PonyTransformation.forSize(ridingPony.getMetadata().getSize()).getRiderOffset();
float scale = ridingPony.getMetadata().getSize().getScaleFactor();
return ridingPony.getAbsoluteRidingOffset(ridee)
.add(0, offset.y - ridee.getHeight() * 1/scale, 0);
}
float delta = MinecraftClient.getInstance().getTickDelta();
return new Vec3d(
MathHelper.lerp(delta, entity.prevRenderX, entity.x),
MathHelper.lerp(delta, entity.prevRenderY, entity.y),
MathHelper.lerp(delta, entity.prevRenderZ, entity.z));
}
@Override
public BoundingBox getComputedBoundingBox(LivingEntity entity) {
float scale = getMetadata().getSize().getScaleFactor() + 0.1F;
Vec3d pos = getAbsoluteRidingOffset(entity);
float width = entity.getWidth() * scale;
return new BoundingBox(
- width, (entity.getHeight() * scale), -width,
width, 0, width).offset(pos);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("texture", texture)
.add("metadata", metadata)
.toString();
}
}