diff --git a/src/main/java/de/ellpeck/naturesaura/items/ItemPetReviver.java b/src/main/java/de/ellpeck/naturesaura/items/ItemPetReviver.java new file mode 100644 index 00000000..5b99b0cc --- /dev/null +++ b/src/main/java/de/ellpeck/naturesaura/items/ItemPetReviver.java @@ -0,0 +1,123 @@ +package de.ellpeck.naturesaura.items; + +import de.ellpeck.naturesaura.NaturesAura; +import de.ellpeck.naturesaura.api.NaturesAuraAPI; +import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk; +import de.ellpeck.naturesaura.packet.PacketHandler; +import de.ellpeck.naturesaura.packet.PacketParticles; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.passive.TameableEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.entity.player.SpawnLocationHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Optional; +import java.util.UUID; + +public class ItemPetReviver extends ItemImpl { + public ItemPetReviver() { + super("pet_reviver"); + MinecraftForge.EVENT_BUS.register(new Events()); + } + + private static class Events { + + // we need to use the event since the item doesn't receive the interaction for tamed pets.. + @SubscribeEvent + public void onEntityInteract(PlayerInteractEvent.EntityInteractSpecific event) { + Entity target = event.getTarget(); + if (!(target instanceof TameableEntity)) + return; + if (target.getPersistentData().getBoolean(NaturesAura.MOD_ID + ":pet_reviver")) + return; + ItemStack stack = event.getPlayer().getHeldItem(event.getHand()); + if (stack.getItem() != ModItems.PET_REVIVER) + return; + target.getPersistentData().putBoolean(NaturesAura.MOD_ID + ":pet_reviver", true); + stack.shrink(1); + event.setCancellationResult(ActionResultType.SUCCESS); + event.setCanceled(true); + } + + // we want to be sure that the pet is really dying, so we want to receive the event last + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onLivingDeath(LivingDeathEvent event) { + LivingEntity entity = event.getEntityLiving(); + if (entity.world.isRemote || !(entity instanceof TameableEntity)) + return; + TameableEntity tameable = (TameableEntity) entity; + if (!tameable.isTamed() || !tameable.getPersistentData().getBoolean(NaturesAura.MOD_ID + ":pet_reviver")) + return; + + // get the overworld, and the overworld's spawn point, by default + ServerWorld spawnWorld = tameable.world.getServer().func_241755_D_(); + Vector3d spawn = Vector3d.copyCenteredHorizontally(spawnWorld.func_241135_u_()); + + // check if the owner is online, and respawn at the bed if they are + LivingEntity owner = tameable.getOwner(); + if (owner instanceof ServerPlayerEntity) { + ServerPlayerEntity player = (ServerPlayerEntity) owner; + + // I'm not really sure what this means, but I got it from PlayerList.func_232644_a_ haha + BlockPos pos = player.func_241140_K_(); + if (pos != null) { + float f = player.func_242109_L(); + boolean b = player.func_241142_M_(); + Optional bed = PlayerEntity.func_242374_a((ServerWorld) player.world, pos, f, b, false); + if (bed.isPresent()) { + spawnWorld = (ServerWorld) player.world; + spawn = bed.get(); + } + } + } + + PacketHandler.sendToAllAround(tameable.world, tameable.getPosition(), 32, new PacketParticles((float) tameable.getPosX(), (float) tameable.getPosYEye(), (float) tameable.getPosZ(), PacketParticles.Type.PET_REVIVER, 0xc2461d)); + + TameableEntity spawnedPet = tameable; + if (tameable.world != spawnWorld) { + ((ServerWorld) tameable.world).removeEntity(tameable, true); + spawnedPet = (TameableEntity) tameable.getType().create(spawnWorld); + } + // respawn (a copy of) the pet + spawnedPet.copyDataFromOld(tameable); + spawnedPet.setMotion(0, 0, 0); + spawnedPet.setLocationAndAngles(spawn.x, spawn.y, spawn.z, tameable.rotationYaw, tameable.rotationPitch); + while (!spawnWorld.hasNoCollisions(spawnedPet)) + spawnedPet.setPosition(spawnedPet.getPosX(), spawnedPet.getPosY() + 1, spawnedPet.getPosZ()); + spawnedPet.setHealth(spawnedPet.getMaxHealth()); + spawnedPet.getNavigator().clearPath(); + // sit down (on the server side!) + spawnedPet.func_233687_w_(true); + spawnedPet.setJumping(false); + spawnedPet.setAttackTarget(null); + if (tameable.world != spawnWorld) { + spawnWorld.addEntity(spawnedPet); + tameable.remove(false); + } + + // drain aura + BlockPos auraPos = IAuraChunk.getHighestSpot(spawnWorld, spawnedPet.getPosition(), 35, spawnedPet.getPosition()); + IAuraChunk.getAuraChunk(spawnWorld, auraPos).drainAura(auraPos, 200000); + + PacketHandler.sendToAllAround(spawnedPet.world, spawnedPet.getPosition(), 32, new PacketParticles((float) spawnedPet.getPosX(), (float) spawnedPet.getPosYEye(), (float) spawnedPet.getPosZ(), PacketParticles.Type.PET_REVIVER, 0x4dba2f)); + + if (owner instanceof PlayerEntity) + owner.sendMessage(new TranslationTextComponent("info." + NaturesAura.MOD_ID + ".pet_reviver", spawnedPet.getDisplayName()).mergeStyle(TextFormatting.ITALIC, TextFormatting.GRAY), UUID.randomUUID()); + event.setCanceled(true); + } + } +} diff --git a/src/main/java/de/ellpeck/naturesaura/items/ModItems.java b/src/main/java/de/ellpeck/naturesaura/items/ModItems.java index d5ed7c1f..558cbed4 100644 --- a/src/main/java/de/ellpeck/naturesaura/items/ModItems.java +++ b/src/main/java/de/ellpeck/naturesaura/items/ModItems.java @@ -61,4 +61,5 @@ public final class ModItems { public static Item FORTRESS_FINDER; public static Item END_CITY_FINDER; public static Item BREAK_PREVENTION; + public static Item PET_REVIVER; } diff --git a/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java b/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java index 0a63d4ac..85a66454 100644 --- a/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java +++ b/src/main/java/de/ellpeck/naturesaura/packet/PacketParticles.java @@ -566,6 +566,17 @@ public class PacketParticles { message.posY + (float) world.rand.nextGaussian() * 0.5F, message.posZ + (float) world.rand.nextGaussian() * 0.5F, x + 0.5F, y + 0.5F, z + 0.5F, 0.2F, color, world.rand.nextFloat() + 1); + }), + PET_REVIVER((message, world) -> { + for (int i = world.rand.nextInt(50) + 150; i >= 0; i--) + NaturesAuraAPI.instance().spawnMagicParticle( + message.posX + (float) world.rand.nextGaussian() * 0.4F, + message.posY + (float) world.rand.nextGaussian() * 0.4F, + message.posZ + (float) world.rand.nextGaussian() * 0.4F, + world.rand.nextGaussian() * 0.002F, + world.rand.nextFloat() * 0.001F + 0.002F, + world.rand.nextGaussian() * 0.002F, + message.data[0], world.rand.nextFloat() * 2 + 1, world.rand.nextInt(50) + 50, 0, false, true); }); public final BiConsumer action; diff --git a/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java b/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java index 7f5b8edb..e2f5ed80 100644 --- a/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java +++ b/src/main/java/de/ellpeck/naturesaura/reg/ModRegistry.java @@ -222,7 +222,8 @@ public final class ModRegistry { new ItemArmor("sky_shoes", ModArmorMaterial.SKY, EquipmentSlotType.FEET), new ItemStructureFinder("fortress_finder", Structure.field_236378_n_, 0xba2800), new ItemStructureFinder("end_city_finder", Structure.field_236379_o_, 0xca5cd6), - new ItemBreakPrevention() + new ItemBreakPrevention(), + new ItemPetReviver() ); Helper.populateObjectHolders(ModItems.class, event.getRegistry()); } diff --git a/src/main/resources/assets/naturesaura/lang/en_us.json b/src/main/resources/assets/naturesaura/lang/en_us.json index 6d315ca1..dc5a3aa4 100644 --- a/src/main/resources/assets/naturesaura/lang/en_us.json +++ b/src/main/resources/assets/naturesaura/lang/en_us.json @@ -131,6 +131,7 @@ "item.naturesaura.fortress_finder": "Eye of the Blaze", "item.naturesaura.end_city_finder": "Eye of the Shulker", "item.naturesaura.break_prevention": "Eir's Token", + "item.naturesaura.pet_reviver": "Token of Undying Friendship", "container.naturesaura:tree_ritual.name": "Ritual of the Forest", "container.naturesaura:altar.name": "Natural Altar Infusion", "container.naturesaura:offering.name": "Offering to the Gods", @@ -156,6 +157,7 @@ "info.naturesaura.broken": " (Broken)", "info.naturesaura.required_aura_type.naturesaura:overworld": "Requires Natural Altar", "info.naturesaura.required_aura_type.naturesaura:nether": "Requires Crimson Altar", + "info.naturesaura.pet_reviver": "Your pet %s was in distress and has been sent home.", "advancement.naturesaura.root": "Nature's Aura", "advancement.naturesaura.root.desc": "Becoming a magical botanist", "advancement.naturesaura.get_book": "Pages of Discovery",