mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Fixed crystal heart health not syncing to the client and implement health/destruction and animations for the crystal shards
This commit is contained in:
parent
e923882ebf
commit
543adefd6d
6 changed files with 164 additions and 62 deletions
|
@ -1,5 +1,7 @@
|
|||
package com.minelittlepony.unicopia.client.render.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.mob.CrystalShardsEntity;
|
||||
|
||||
import net.minecraft.client.model.Dilation;
|
||||
|
@ -12,12 +14,15 @@ import net.minecraft.client.model.TexturedModelData;
|
|||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.entity.model.EntityModel;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class CrystalShardsEntityModel extends EntityModel<CrystalShardsEntity> {
|
||||
private final ModelPart part;
|
||||
private final List<ModelPart> crystals;
|
||||
|
||||
public CrystalShardsEntityModel(ModelPart root) {
|
||||
this.part = root;
|
||||
this.crystals = List.of(part.getChild("west"), part.getChild("north"), part.getChild("south"), part.getChild("east"), part.getChild("primary"));
|
||||
}
|
||||
|
||||
public static TexturedModelData getTexturedModelData() {
|
||||
|
@ -33,6 +38,22 @@ public class CrystalShardsEntityModel extends EntityModel<CrystalShardsEntity> {
|
|||
|
||||
@Override
|
||||
public void setAngles(CrystalShardsEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||
|
||||
float offset = 0;
|
||||
float amplitude = 0.02F;
|
||||
|
||||
for (ModelPart part : crystals) {
|
||||
part.resetTransform();
|
||||
|
||||
if (entity.isShaking()) {
|
||||
float animationTime = (entity.age + ++offset) * 122F;
|
||||
float sin = MathHelper.sin(animationTime) * amplitude;
|
||||
|
||||
part.pitch += sin;
|
||||
part.yaw += MathHelper.cos(animationTime) * amplitude;
|
||||
part.roll += -sin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,8 +9,10 @@ import net.minecraft.client.render.OverlayTexture;
|
|||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||
import net.minecraft.client.render.model.ModelLoader;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
|
||||
public class CrystalShardsEntityRenderer extends EntityRenderer<CrystalShardsEntity> {
|
||||
|
@ -37,6 +39,11 @@ public class CrystalShardsEntityRenderer extends EntityRenderer<CrystalShardsEnt
|
|||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
|
||||
|
||||
model.setAngles(entity, 0, 0, 0, 0, 0);
|
||||
|
||||
int destructionStage = (int)(MathHelper.clamp(1F - (entity.getHealth() / entity.getMaxHealth()), 0F, 1F) * (ModelLoader.field_32983 - 1F));
|
||||
|
||||
vertices = FloatingArtefactEntityRenderer.getDestructionOverlayProvider(matrices, vertices, destructionStage);
|
||||
|
||||
model.render(matrices, vertices.getBuffer(model.getLayer(getTexture(entity))), light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
matrices.pop();
|
||||
super.render(entity, yaw, tickDelta, matrices, vertices, light);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class FloatingArtefactEntityRenderer extends EntityRenderer<FloatingArtef
|
|||
matrices.translate(0, verticalOffset + variance * modelScaleY, 0);
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.getRotation(timeDelta)));
|
||||
|
||||
int destructionStage = (int)(MathHelper.clamp(1 - (entity.getHealth() / entity.getMaxHealth()), 0, 1) * (ModelLoader.field_32983 - 1));
|
||||
int destructionStage = (int)(MathHelper.clamp(1F - (entity.getHealth() / entity.getMaxHealth()), 0F, 1F) * (ModelLoader.field_32983 - 1F));
|
||||
|
||||
itemRenderer.renderItem(stack, ModelTransformationMode.GROUND, false, matrices, getDestructionOverlayProvider(matrices, vertices, destructionStage), lightUv, OverlayTexture.DEFAULT_UV, model);
|
||||
|
||||
|
|
|
@ -6,13 +6,10 @@ import java.util.Set;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
|
||||
import net.minecraft.block.SideShapeType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
|
@ -27,16 +24,16 @@ import net.minecraft.util.math.Direction;
|
|||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class CrystalShardsEntity extends Entity implements MagicImmune {
|
||||
public class CrystalShardsEntity extends StationaryObjectEntity {
|
||||
static final byte SHAKE = 1;
|
||||
|
||||
static final int FULL_GROWTH_AGE = 25;
|
||||
|
||||
private static final Set<Direction> ALL_DIRECTIONS = Set.of(Direction.values());
|
||||
private static final TrackedData<Direction> ATTACHMENT_FACE = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.FACING);
|
||||
private static final TrackedData<Integer> GROWTH = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final TrackedData<Boolean> DECAYING = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Boolean> CORRUPT = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Direction> ATTACHMENT_FACE = DataTracker.registerData(CrystalShardsEntity.class, TrackedDataHandlerRegistry.FACING);
|
||||
private static final TrackedData<Integer> GROWTH = DataTracker.registerData(CrystalShardsEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final TrackedData<Boolean> DECAYING = DataTracker.registerData(CrystalShardsEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Boolean> CORRUPT = DataTracker.registerData(CrystalShardsEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
|
||||
public static boolean infestBlock(ServerWorld world, BlockPos pos) {
|
||||
if (world.isAir(pos) || !world.getFluidState(pos).isOf(Fluids.EMPTY)) {
|
||||
|
@ -89,12 +86,18 @@ public class CrystalShardsEntity extends Entity implements MagicImmune {
|
|||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
dataTracker.startTracking(ATTACHMENT_FACE, Direction.UP);
|
||||
dataTracker.startTracking(GROWTH, 0);
|
||||
dataTracker.startTracking(DECAYING, false);
|
||||
dataTracker.startTracking(CORRUPT, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxHealth() {
|
||||
return 15F;
|
||||
}
|
||||
|
||||
public float getGrowth(float tickDelta) {
|
||||
int age = getGrowth();
|
||||
float lerped = MathHelper.clamp(MathHelper.lerp(tickDelta, prevAge, age), 0, FULL_GROWTH_AGE) / (float)FULL_GROWTH_AGE;
|
||||
|
@ -157,19 +160,22 @@ public class CrystalShardsEntity extends Entity implements MagicImmune {
|
|||
|
||||
super.tick();
|
||||
|
||||
if (getGrowth() < FULL_GROWTH_AGE) {
|
||||
playSound(USounds.Vanilla.BLOCK_AMETHYST_BLOCK_CHIME, 1, 1);
|
||||
if (ticksShaking > 0 || getGrowth() < FULL_GROWTH_AGE) {
|
||||
if (age % random.nextBetween(2, 5) == 0) {
|
||||
playSound(USounds.Vanilla.BLOCK_AMETHYST_BLOCK_HIT, 1,
|
||||
1 - MathHelper.clamp(getGrowth(1), 0, 1) * 0.5F);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInvalid(getWorld(), getBlockPos(), getAttachmentFace())) {
|
||||
if (isDead() || isInvalid(getWorld(), getBlockPos(), getAttachmentFace())) {
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean damage(DamageSource source, float amount) {
|
||||
protected void onHurt() {
|
||||
getWorld().sendEntityStatus(this, SHAKE);
|
||||
return super.damage(source, amount);
|
||||
ticksShaking = 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -185,7 +191,7 @@ public class CrystalShardsEntity extends Entity implements MagicImmune {
|
|||
public void handleStatus(byte status) {
|
||||
switch (status) {
|
||||
case SHAKE:
|
||||
ticksShaking = 30;
|
||||
ticksShaking = 10;
|
||||
break;
|
||||
default:
|
||||
super.handleStatus(status);
|
||||
|
@ -194,7 +200,8 @@ public class CrystalShardsEntity extends Entity implements MagicImmune {
|
|||
|
||||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound nbt) {
|
||||
nbt.putFloat("yaw", this.getYaw());
|
||||
super.writeCustomDataToNbt(nbt);
|
||||
nbt.putFloat("yaw", getYaw());
|
||||
nbt.putInt("growth", getGrowth());
|
||||
nbt.putString("face", getAttachmentFace().getName());
|
||||
nbt.putBoolean("decaying", isDecaying());
|
||||
|
@ -203,6 +210,7 @@ public class CrystalShardsEntity extends Entity implements MagicImmune {
|
|||
|
||||
@Override
|
||||
public void readCustomDataFromNbt(NbtCompound nbt) {
|
||||
super.readCustomDataFromNbt(nbt);
|
||||
setYaw(nbt.getFloat("yaw"));
|
||||
setGrowth(nbt.getInt("growth"));
|
||||
setAttachmentFace(Direction.byName(nbt.getString("face")));
|
||||
|
|
|
@ -3,12 +3,9 @@ package com.minelittlepony.unicopia.entity.mob;
|
|||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.entity.damage.UDamageSources;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.server.world.Altar;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
|
@ -21,7 +18,7 @@ import net.minecraft.util.math.MathHelper;
|
|||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class FloatingArtefactEntity extends Entity implements UDamageSources, MagicImmune {
|
||||
public class FloatingArtefactEntity extends StationaryObjectEntity {
|
||||
private static final TrackedData<ItemStack> ITEM = DataTracker.registerData(FloatingArtefactEntity.class, TrackedDataHandlerRegistry.ITEM_STACK);
|
||||
private static final TrackedData<Byte> STATE = DataTracker.registerData(FloatingArtefactEntity.class, TrackedDataHandlerRegistry.BYTE);
|
||||
private static final TrackedData<Float> TARGET_ROTATION_SPEED = DataTracker.registerData(FloatingArtefactEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
|
@ -40,7 +37,6 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
|
||||
private int boostDuration;
|
||||
|
||||
private float health;
|
||||
private int ticksUntilRegen;
|
||||
public final float positionSeed;
|
||||
|
||||
|
@ -50,11 +46,11 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
super(entityType, world);
|
||||
|
||||
positionSeed = (float)(Math.random() * Math.PI * 2);
|
||||
health = getMaxHealth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
dataTracker.startTracking(ITEM, ItemStack.EMPTY);
|
||||
dataTracker.startTracking(STATE, (byte)0);
|
||||
dataTracker.startTracking(TARGET_ROTATION_SPEED, 1F);
|
||||
|
@ -93,16 +89,9 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
return MathHelper.lerp(tickDelta, prevRotationSpeed, rotationSpeed);
|
||||
}
|
||||
|
||||
public int getMaxHealth() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
this.health = MathHelper.clamp(health, 0, getMaxHealth());
|
||||
}
|
||||
|
||||
public float getHealth() {
|
||||
return health;
|
||||
@Override
|
||||
public float getMaxHealth() {
|
||||
return 20F;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -163,16 +152,17 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
|
||||
@Override
|
||||
protected void readCustomDataFromNbt(NbtCompound compound) {
|
||||
super.readCustomDataFromNbt(compound);
|
||||
setStack(ItemStack.fromNbt(compound.getCompound("Item")));
|
||||
setState(State.valueOf(compound.getInt("State")));
|
||||
setRotationSpeed(compound.getFloat("spin"), compound.getInt("spinDuration"));
|
||||
setHealth(compound.getFloat("health"));
|
||||
ticksUntilRegen = compound.getInt("regen");
|
||||
altar = Altar.SERIALIZER.readOptional("altar", compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeCustomDataToNbt(NbtCompound compound) {
|
||||
super.writeCustomDataToNbt(compound);
|
||||
ItemStack stack = getStack();
|
||||
if (!stack.isEmpty()) {
|
||||
compound.put("Item", stack.writeNbt(new NbtCompound()));
|
||||
|
@ -180,46 +170,46 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
compound.putInt("State", getState().ordinal());
|
||||
compound.putFloat("spin", getRotationSpeed());
|
||||
compound.putInt("spinDuration", boostDuration);
|
||||
compound.putFloat("health", getHealth());
|
||||
compound.putInt("regen", ticksUntilRegen);
|
||||
Altar.SERIALIZER.writeOptional("altar", compound, altar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean damage(DamageSource damageSource, float amount) {
|
||||
public boolean damage(DamageSource source, float damage) {
|
||||
|
||||
if (getWorld().isClient || isInvulnerable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isInvulnerableTo(damageSource) || !getStack().getItem().damage(damageSource)) {
|
||||
if (isInvulnerableTo(source) || !getStack().getItem().damage(source)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (damageSource.isSourceCreativePlayer()) {
|
||||
health = 0;
|
||||
} else {
|
||||
health -= amount;
|
||||
ticksUntilRegen = REGEN_PAUSE_TICKS;
|
||||
ticksUntilRegen = REGEN_PAUSE_TICKS;
|
||||
|
||||
if (source.isSourceCreativePlayer()) {
|
||||
damage = getHealth();
|
||||
}
|
||||
|
||||
if (health <= 0) {
|
||||
remove(RemovalReason.KILLED);
|
||||
return super.damage(source, damage);
|
||||
}
|
||||
|
||||
ItemStack stack = getStack();
|
||||
@Override
|
||||
protected void onKilled(DamageSource source) {
|
||||
ItemStack stack = getStack();
|
||||
|
||||
if (altar.isEmpty()) {
|
||||
if (!(stack.getItem() instanceof Artifact) || ((Artifact)stack.getItem()).onArtifactDestroyed(this) != ActionResult.SUCCESS) {
|
||||
if (!damageSource.isSourceCreativePlayer()) {
|
||||
dropStack(stack);
|
||||
}
|
||||
if (altar.isEmpty()) {
|
||||
if (!(stack.getItem() instanceof Artifact) || ((Artifact)stack.getItem()).onArtifactDestroyed(this) != ActionResult.SUCCESS) {
|
||||
if (!source.isSourceCreativePlayer()) {
|
||||
dropStack(stack);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
playSound(USounds.ITEM_ICARUS_WINGS_WARN, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@Override
|
||||
protected void onHurt() {
|
||||
playSound(USounds.ITEM_ICARUS_WINGS_WARN, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -228,16 +218,6 @@ public class FloatingArtefactEntity extends Entity implements UDamageSources, Ma
|
|||
altar.ifPresent(altar -> altar.tearDown(this, getWorld()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World asWorld() {
|
||||
return getWorld();
|
||||
}
|
||||
|
||||
public enum State {
|
||||
INITIALISING,
|
||||
RUNNING,
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.minelittlepony.unicopia.entity.mob;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.entity.damage.UDamageSources;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class StationaryObjectEntity extends Entity implements UDamageSources, MagicImmune {
|
||||
private static final TrackedData<Float> HEALTH = DataTracker.registerData(StationaryObjectEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
|
||||
public StationaryObjectEntity(EntityType<?> entityType, World world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
dataTracker.startTracking(HEALTH, getMaxHealth());
|
||||
}
|
||||
|
||||
public abstract float getMaxHealth();
|
||||
|
||||
public final float setHealth(float health) {
|
||||
health = MathHelper.clamp(health, 0, getMaxHealth());
|
||||
dataTracker.set(HEALTH, health);
|
||||
return health;
|
||||
}
|
||||
|
||||
public final float getHealth() {
|
||||
return dataTracker.get(HEALTH);
|
||||
}
|
||||
|
||||
public final boolean isDead() {
|
||||
return isRemoved() || getHealth() <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean damage(DamageSource source, float damage) {
|
||||
if (!isDead()) {
|
||||
if (setHealth(getHealth() - damage) <= 0) {
|
||||
kill();
|
||||
onKilled(source);
|
||||
} else {
|
||||
onHurt();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onKilled(DamageSource source) {
|
||||
|
||||
}
|
||||
|
||||
protected void onHurt() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readCustomDataFromNbt(NbtCompound compound) {
|
||||
if (compound.contains("health", NbtElement.FLOAT_TYPE)) {
|
||||
setHealth(compound.getFloat("health"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeCustomDataToNbt(NbtCompound compound) {
|
||||
compound.putFloat("health", getHealth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean canHit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final World asWorld() {
|
||||
return getWorld();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue