diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java index e2580e66..96588b3c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java @@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.model.*; +import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.util.math.MatrixStack; @@ -24,6 +25,7 @@ public class AirBalloonEntityModel extends EntityModel { private boolean isSandbags; private final List ropes; + private final List struts; private final List sandbags; public AirBalloonEntityModel(ModelPart root) { @@ -41,6 +43,11 @@ public class AirBalloonEntityModel extends EntityModel { } else { ropes = List.of(); } + if (isBurner) { + struts = List.of(root.getChild("strut_a"), root.getChild("strut_b")); + } else { + struts = List.of(); + } sandbags = isSandbags ? List.of( root.getChild("sandbag_nw"), root.getChild("sandbag_sw"), @@ -162,6 +169,9 @@ public class AirBalloonEntityModel extends EntityModel { ropes.forEach(rope -> { rope.visible = lifted; }); + struts.forEach(strut -> { + strut.visible = lifted; + }); root.pivotX += burnerWiggleProgress * MathHelper.sin((entity.age + tickDelta)) * 2.5F; root.pivotX += burnerWiggleProgress * MathHelper.cos((entity.age + tickDelta)) * 2.5F; @@ -235,10 +245,10 @@ public class AirBalloonEntityModel extends EntityModel { matrices.push(); matrices.translate(0, 1 * (1 - inflation), 0); matrices.scale(1, MathHelper.lerp(inflation, -0.05F, 1), 1); - root.render(matrices, vertexConsumer, light, overlay, color); + root.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, color); matrices.pop(); } else { - root.render(matrices, vertexConsumer, light, overlay, color); + root.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, color); } } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java index 8bd99835..c4bb76d0 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java @@ -20,6 +20,8 @@ import net.minecraft.item.Items; import net.minecraft.util.Colors; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RotationAxis; public class AirBalloonEntityRenderer extends MobEntityRenderer { public AirBalloonEntityRenderer(EntityRendererFactory.Context context) { @@ -40,13 +42,19 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer 0) { + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(MathHelper.sin(entity.age + tickDelta) * 3)); + } super.render(entity, yaw, tickDelta, matrices, vertices, light); + matrices.pop(); if (MinecraftClient.getInstance().getEntityRenderDispatcher().shouldRenderHitboxes() && !entity.isInvisible() && !MinecraftClient.getInstance().hasReducedDebugInfo()) { MultiBox.forEach(entity.getBoundingBox(), box -> { WorldRenderer.drawBox(matrices, vertices.getBuffer(RenderLayer.getLines()), box.offset(entity.getPos().multiply(-1)), 1, 1, 1, 1); }); } + } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java index d070f311..3b8f7e9c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java @@ -5,6 +5,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.block.entity.FurnaceBlockEntity; import net.minecraft.entity.*; +import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.data.*; import net.minecraft.entity.data.DataTracker.Builder; import net.minecraft.entity.mob.MobEntity; @@ -14,11 +15,14 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; import net.minecraft.network.codec.PacketCodec; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.registry.RegistryKey; import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; @@ -26,6 +30,7 @@ import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.*; import net.minecraft.util.math.random.Random; import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.GameRules; import net.minecraft.world.World; import net.minecraft.world.event.GameEvent; @@ -57,6 +62,7 @@ import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.component.BalloonDesignComponent; import com.minelittlepony.unicopia.item.component.UDataComponentTypes; import com.minelittlepony.unicopia.server.world.WeatherConditions; +import com.minelittlepony.unicopia.util.serialization.NbtSerialisable; import com.minelittlepony.unicopia.util.serialization.PacketCodecUtils; import com.terraformersmc.terraform.boat.api.TerraformBoatType; @@ -80,7 +86,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp private Vec3d manualVelocity = Vec3d.ZERO; private int maxFuel = 10000; - private int fuel; + private int activeFuel; + private List fuelItems = new ArrayList<>(); private final Animatable[] sandbags = IntStream.range(0, 5).mapToObj(Animatable::new).toArray(Animatable[]::new); private final Animatable burner = new Animatable(5); @@ -182,6 +189,18 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp return (float)MathHelper.lerp(tickDelta, prevZDelta, zDelta); } + @Override + @Nullable + protected SoundEvent getHurtSound(DamageSource source) { + return null; + } + + @Override + @Nullable + protected SoundEvent getDeathSound() { + return SoundEvents.BLOCK_BAMBOO_WOOD_BREAK; + } + @Override public void tick() { setAir(getMaxAir()); @@ -209,9 +228,13 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp setInflation(inflation); } - if (fuel > -6 && age % 2 == 0) { - fuel -= boosting ? 50 : 1; - if (fuel <= -6) { + if (activeFuel <= 0 && !fuelItems.isEmpty()) { + activeFuel = FurnaceBlockEntity.createFuelTimeMap().getOrDefault(fuelItems.remove(0).getItem(), 0); + } + + if (activeFuel > -6 && age % 2 == 0) { + activeFuel -= boosting ? 50 : 1; + if (activeFuel <= -6) { setBoostTicks(0); setAscending(false); } @@ -238,7 +261,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp if (hasBurner() && isAscending()) { Vec3d burnerPos = getPos().add(0, 3, 0); for (int i = 0; i < (boosting ? 6 : 1); i++) { - getWorld().addParticle(fuel <= 0 + getWorld().addParticle(activeFuel <= 0 ? ParticleTypes.SMOKE : getStackInHand(Hand.MAIN_HAND).isOf(Items.SOUL_LANTERN) ? ParticleTypes.SOUL_FIRE_FLAME @@ -305,6 +328,28 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp zDelta = getZ() - prevZ; } + @Override + public boolean damage(DamageSource source, float amount) { + if (source.getAttacker() instanceof PlayerEntity player && player.getAbilities().creativeMode) { + dropInventory(); + remove(RemovalReason.KILLED); + return true; + } + if (super.damage(source, amount)) { + hurtTime = 0; + maxHurtTime = 0; + return true; + } + return false; + } + + @Override + protected void updatePostDeath() { + if (!getWorld().isClient() && !isRemoved()) { + remove(Entity.RemovalReason.KILLED); + } + } + @Override public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand hand) { ItemStack stack = player.getStackInHand(hand); @@ -387,8 +432,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp if (stack.isIn(ConventionalItemTags.SHEAR_TOOLS) && hasBalloon()) { stack.damage(1, player, getSlotForHand(hand)); + dropStack(BalloonDesignComponent.set(UItems.GIANT_BALLOON.getDefaultStack(), new BalloonDesignComponent(getDesign(), true))); setDesign(BalloonDesign.NONE); - dropItem(UItems.GIANT_BALLOON); playSound(USounds.ENTITY_HOT_AIR_BALLOON_EQUIP_CANOPY.value(), 1, 1); if (!player.isSneaky()) { getWorld().emitGameEvent(player, GameEvent.EQUIP, getBlockPos()); @@ -414,15 +459,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp if (hasBurner()) { int fuel = FurnaceBlockEntity.createFuelTimeMap().getOrDefault(stack.getItem(), 0); if (fuel > 0) { - if (this.fuel < maxFuel) { - if (this.fuel < 0) { - this.fuel = fuel; - } else { - this.fuel += fuel; - } - if (!player.getAbilities().creativeMode) { - stack.decrement(1); - } + if (fuelItems.size() < 64) { + fuelItems.add(stack.splitUnlessCreative(1, player)); burner.setPulling(); playSound(USounds.Vanilla.ENTITY_VILLAGER_YES, 1, 1); return ActionResult.SUCCESS; @@ -436,10 +474,18 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp @Override protected void dropInventory() { - ItemStack lantern = getStackInHand(Hand.MAIN_HAND); - setStackInHand(Hand.MAIN_HAND, ItemStack.EMPTY); - dropStack(lantern); dropStack(getPickBlockStack()); + if (getWorld().getGameRules().getBoolean(GameRules.DO_ENTITY_DROPS)) { + ItemStack lantern = getStackInHand(Hand.MAIN_HAND); + setStackInHand(Hand.MAIN_HAND, ItemStack.EMPTY); + dropStack(lantern); + if (hasBalloon()) { + dropStack(BalloonDesignComponent.set(UItems.GIANT_BALLOON.getDefaultStack(), new BalloonDesignComponent(getDesign(), true))); + setDesign(BalloonDesign.NONE); + } + fuelItems.forEach(this::dropStack); + fuelItems.clear(); + } } @Override @@ -518,21 +564,23 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp move(MovementType.SELF, getVelocity()); setVelocity(getVelocity().multiply(slipperyness)); } - } else { - Map> collidingEntities = getCollidingEntities(getBoundingBoxes().stream()); - - for (Map.Entry> passengers : collidingEntities.entrySet()) { - for (Entity passenger : passengers.getValue()) { - Living living = Living.living(passenger); - if (living != null) { - living.getTransportation().setVehicle(this); - } - - } - } } updateLimbs(false); } + + if (isAirworthy()) { + Map> collidingEntities = getCollidingEntities(getBoundingBoxes().stream()); + + for (Map.Entry> passengers : collidingEntities.entrySet()) { + for (Entity passenger : passengers.getValue()) { + Living living = Living.living(passenger); + if (living != null) { + living.getTransportation().setVehicle(this); + } + + } + } + } } @Override @@ -714,7 +762,6 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp protected void fall(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) { } - @Override public void readCustomDataFromNbt(NbtCompound compound) { super.readCustomDataFromNbt(compound); @@ -724,7 +771,12 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp setBoostTicks(compound.getInt("boostTicks")); prevInflation = compound.getInt("inflationAmount"); setInflation(prevInflation); - fuel = MathHelper.clamp(compound.getInt("fuel"), 0, maxFuel); + activeFuel = MathHelper.clamp(compound.getInt("fuel"), 0, maxFuel); + fuelItems = compound.contains("fuelItems", NbtElement.LIST_TYPE) ? compound + .getList("fuelItems", NbtElement.COMPOUND_TYPE).stream() + .map(item -> ItemStack.fromNbtOrEmpty(getRegistryManager(), (NbtCompound)item)) + .limit(64) + .collect(Collectors.toList()) : new ArrayList<>(); } @Override @@ -735,7 +787,12 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp compound.putBoolean("burnerActive", isAscending()); compound.putInt("boostTicks", getBoostTicks()); compound.putInt("inflationAmount", getInflation()); - compound.putInt("fuel", fuel); + compound.putInt("fuel", activeFuel); + NbtList fuelItemsNbt = new NbtList(); + fuelItems.forEach(item -> { + fuelItemsNbt.add(NbtSerialisable.encode(ItemStack.OPTIONAL_CODEC, item, getRegistryManager())); + }); + compound.put("fuelItems", fuelItemsNbt); } @Override