001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.bukkit.entity; 020 021import com.plotsquared.core.configuration.Settings; 022import org.apache.logging.log4j.LogManager; 023import org.apache.logging.log4j.Logger; 024import org.bukkit.Art; 025import org.bukkit.DyeColor; 026import org.bukkit.Location; 027import org.bukkit.Rotation; 028import org.bukkit.World; 029import org.bukkit.block.BlockFace; 030import org.bukkit.entity.AbstractHorse; 031import org.bukkit.entity.Ageable; 032import org.bukkit.entity.ArmorStand; 033import org.bukkit.entity.Bat; 034import org.bukkit.entity.Boat; 035import org.bukkit.entity.Breedable; 036import org.bukkit.entity.ChestBoat; 037import org.bukkit.entity.ChestedHorse; 038import org.bukkit.entity.EnderDragon; 039import org.bukkit.entity.Entity; 040import org.bukkit.entity.IronGolem; 041import org.bukkit.entity.Item; 042import org.bukkit.entity.ItemFrame; 043import org.bukkit.entity.LivingEntity; 044import org.bukkit.entity.Painting; 045import org.bukkit.entity.Rabbit; 046import org.bukkit.entity.Sheep; 047import org.bukkit.entity.Tameable; 048import org.bukkit.inventory.EntityEquipment; 049import org.bukkit.inventory.InventoryHolder; 050import org.bukkit.inventory.ItemStack; 051import org.bukkit.util.EulerAngle; 052import org.bukkit.util.Vector; 053 054import java.util.List; 055 056public final class ReplicatingEntityWrapper extends EntityWrapper { 057 058 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + ReplicatingEntityWrapper.class.getSimpleName()); 059 060 private final short depth; 061 private final int hash; 062 private final EntityBaseStats base = new EntityBaseStats(); 063 064 private ItemStack[] inventory; 065 // Extended 066 private ItemStack stack; 067 private byte dataByte; 068 private byte dataByte2; 069 private String dataString; 070 private LivingEntityStats lived; 071 private AgeableStats aged; 072 private TameableStats tamed; 073 private ArmorStandStats stand; 074 private HorseStats horse; 075 private boolean noGravity; 076 077 @SuppressWarnings("deprecation") // Deprecation exists since 1.20, while we support 1.16 onwards 078 public ReplicatingEntityWrapper(Entity entity, short depth) { 079 super(entity); 080 081 this.hash = entity.getEntityId(); 082 this.depth = depth; 083 084 if (depth == 0) { 085 return; 086 } 087 List<Entity> passengers = entity.getPassengers(); 088 if (passengers.size() > 0) { 089 this.base.passenger = new ReplicatingEntityWrapper(passengers.get(0), depth); 090 } 091 this.base.fall = entity.getFallDistance(); 092 this.base.fire = (short) entity.getFireTicks(); 093 this.base.age = entity.getTicksLived(); 094 Vector velocity = entity.getVelocity(); 095 this.base.vX = velocity.getX(); 096 this.base.vY = velocity.getY(); 097 this.base.vZ = velocity.getZ(); 098 if (depth == 1) { 099 return; 100 } 101 if (!entity.hasGravity()) { 102 this.noGravity = true; 103 } 104 switch (entity.getType().toString()) { 105 case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT", 106 "OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> { 107 Boat boat = (Boat) entity; 108 this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType()); 109 return; 110 } 111 case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT", 112 "JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT", 113 "SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> { 114 ChestBoat boat = (ChestBoat) entity; 115 this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType()); 116 storeInventory(boat); 117 } 118 case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "EXPERIENCE_ORB", "FALLING_BLOCK", "FIREBALL", 119 "FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND", "MINECART_MOB_SPAWNER", 120 "MINECART_TNT", "PLAYER", "PRIMED_TNT", "SLIME", "SMALL_FIREBALL", "SNOWBALL", "MINECART_FURNACE", "SPLASH_POTION", 121 "THROWN_EXP_BOTTLE", "WITHER_SKULL", "UNKNOWN", "SPECTRAL_ARROW", "SHULKER_BULLET", "DRAGON_FIREBALL", "AREA_EFFECT_CLOUD", 122 "TRIDENT", "LLAMA_SPIT" -> { 123 // Do this stuff later 124 return; 125 } 126 // MISC // 127 case "DROPPED_ITEM", "ITEM" -> { 128 Item item = (Item) entity; 129 this.stack = item.getItemStack(); 130 return; 131 } 132 case "ITEM_FRAME" -> { 133 this.x = Math.floor(this.getX()); 134 this.y = Math.floor(this.getY()); 135 this.z = Math.floor(this.getZ()); 136 ItemFrame itemFrame = (ItemFrame) entity; 137 this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation()); 138 this.stack = itemFrame.getItem().clone(); 139 return; 140 } 141 case "PAINTING" -> { 142 this.x = Math.floor(this.getX()); 143 this.y = Math.floor(this.getY()); 144 this.z = Math.floor(this.getZ()); 145 Painting painting = (Painting) entity; 146 Art art = painting.getArt(); 147 this.dataByte = getOrdinal(BlockFace.values(), painting.getFacing()); 148 int h = art.getBlockHeight(); 149 if (h % 2 == 0) { 150 this.y -= 1; 151 } 152 this.dataString = art.name(); 153 return; 154 } 155 // END MISC // 156 // INVENTORY HOLDER // 157 case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> { 158 storeInventory((InventoryHolder) entity); 159 return; 160 } 161 // START LIVING ENTITY // 162 // START AGEABLE // 163 // START TAMEABLE // 164 case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> { 165 AbstractHorse horse = (AbstractHorse) entity; 166 this.horse = new HorseStats(); 167 this.horse.jump = horse.getJumpStrength(); 168 if (horse instanceof ChestedHorse horse1) { 169 this.horse.chest = horse1.isCarryingChest(); 170 } 171 //todo these horse features need fixing 172 //this.horse.variant = horse.getVariant(); 173 //this.horse.style = horse.getStyle(); 174 //this.horse.color = horse.getColor(); 175 storeTameable(horse); 176 storeBreedable(horse); 177 storeLiving(horse); 178 storeInventory(horse); 179 return; 180 } 181 // END INVENTORY HOLDER // 182 case "WOLF", "OCELOT", "CAT", "PARROT" -> { 183 storeTameable((Tameable) entity); 184 storeBreedable((Breedable) entity); 185 storeLiving((LivingEntity) entity); 186 return; 187 } 188 // END TAMEABLE // 189 case "SHEEP" -> { 190 Sheep sheep = (Sheep) entity; 191 if (sheep.isSheared()) { 192 this.dataByte = (byte) 1; 193 } else { 194 this.dataByte = (byte) 0; 195 } 196 this.dataByte2 = getOrdinal(DyeColor.values(), sheep.getColor()); 197 storeBreedable(sheep); 198 storeLiving(sheep); 199 return; 200 } 201 case "VILLAGER", "CHICKEN", "COW", "MUSHROOM_COW", "PIG", "TURTLE", "POLAR_BEAR" -> { 202 storeBreedable((Breedable) entity); 203 storeLiving((LivingEntity) entity); 204 return; 205 } 206 case "RABBIT" -> { 207 this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType()); 208 storeBreedable((Breedable) entity); 209 storeLiving((LivingEntity) entity); 210 return; 211 } 212 // END AGEABLE // 213 case "ARMOR_STAND" -> { 214 ArmorStand stand = (ArmorStand) entity; 215 this.inventory = 216 new ItemStack[]{stand.getItemInHand().clone(), stand.getHelmet().clone(), 217 stand.getChestplate().clone(), stand.getLeggings().clone(), 218 stand.getBoots().clone()}; 219 storeLiving(stand); 220 this.stand = new ArmorStandStats(); 221 EulerAngle head = stand.getHeadPose(); 222 this.stand.head[0] = (float) head.getX(); 223 this.stand.head[1] = (float) head.getY(); 224 this.stand.head[2] = (float) head.getZ(); 225 EulerAngle body = stand.getBodyPose(); 226 this.stand.body[0] = (float) body.getX(); 227 this.stand.body[1] = (float) body.getY(); 228 this.stand.body[2] = (float) body.getZ(); 229 EulerAngle leftLeg = stand.getLeftLegPose(); 230 this.stand.leftLeg[0] = (float) leftLeg.getX(); 231 this.stand.leftLeg[1] = (float) leftLeg.getY(); 232 this.stand.leftLeg[2] = (float) leftLeg.getZ(); 233 EulerAngle rightLeg = stand.getRightLegPose(); 234 this.stand.rightLeg[0] = (float) rightLeg.getX(); 235 this.stand.rightLeg[1] = (float) rightLeg.getY(); 236 this.stand.rightLeg[2] = (float) rightLeg.getZ(); 237 EulerAngle leftArm = stand.getLeftArmPose(); 238 this.stand.leftArm[0] = (float) leftArm.getX(); 239 this.stand.leftArm[1] = (float) leftArm.getY(); 240 this.stand.leftArm[2] = (float) leftArm.getZ(); 241 EulerAngle rightArm = stand.getRightArmPose(); 242 this.stand.rightArm[0] = (float) rightArm.getX(); 243 this.stand.rightArm[1] = (float) rightArm.getY(); 244 this.stand.rightArm[2] = (float) rightArm.getZ(); 245 if (stand.hasArms()) { 246 this.stand.arms = true; 247 } 248 if (!stand.hasBasePlate()) { 249 this.stand.noPlate = true; 250 } 251 if (!stand.isVisible()) { 252 this.stand.invisible = true; 253 } 254 if (stand.isSmall()) { 255 this.stand.small = true; 256 } 257 return; 258 } 259 case "ENDERMITE" -> { 260 return; 261 } 262 case "BAT" -> { 263 if (((Bat) entity).isAwake()) { 264 this.dataByte = (byte) 1; 265 } else { 266 this.dataByte = (byte) 0; 267 } 268 return; 269 } 270 case "ENDER_DRAGON" -> { 271 EnderDragon entity1 = (EnderDragon) entity; 272 this.dataByte = (byte) entity1.getPhase().ordinal(); 273 return; 274 } 275 case "SKELETON", "WITHER_SKELETON", "GUARDIAN", "ELDER_GUARDIAN", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN", 276 "ZOMBIFIED_PIGLIN", "PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH", 277 "GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SHULKER", "SNOWMAN", "SNOW_GOLEM" -> { 278 storeLiving((LivingEntity) entity); 279 return; 280 } 281 case "IRON_GOLEM" -> { 282 if (((IronGolem) entity).isPlayerCreated()) { 283 this.dataByte = (byte) 1; 284 } else { 285 this.dataByte = (byte) 0; 286 } 287 storeLiving((LivingEntity) entity); 288 } 289 // END LIVING // 290 } 291 } 292 293 @Override 294 public boolean equals(Object obj) { 295 return this.hash == obj.hashCode(); 296 } 297 298 @Override 299 public int hashCode() { 300 return this.hash; 301 } 302 303 public void storeInventory(InventoryHolder held) { 304 this.inventory = held.getInventory().getContents().clone(); 305 } 306 307 void restoreLiving(LivingEntity entity) { 308 entity.setCanPickupItems(this.lived.loot); 309 if (this.lived.name != null) { 310 entity.setCustomName(this.lived.name); 311 entity.setCustomNameVisible(this.lived.visible); 312 } 313 if (this.lived.potions != null && !this.lived.potions.isEmpty()) { 314 entity.addPotionEffects(this.lived.potions); 315 } 316 entity.setRemainingAir(this.lived.air); 317 entity.setRemoveWhenFarAway(this.lived.persistent); 318 if (this.lived.equipped) { 319 this.restoreEquipment(entity); 320 } 321 if (this.lived.leashed) { 322 // TODO leashes 323 // World world = entity.getWorld(); 324 // Entity leash = world.spawnEntity(new Location(world, Math.floor(x) + 325 // lived.leashX, Math.floor(y) + lived.leashY, Math.floor(z) + lived.leashZ), 326 // EntityType.LEASH_HITCH); 327 // entity.setLeashHolder(leash); 328 } 329 } 330 331 void restoreEquipment(LivingEntity entity) { 332 EntityEquipment equipment = entity.getEquipment(); 333 if (equipment != null) { 334 equipment.setItemInMainHand(this.lived.mainHand); 335 equipment.setItemInOffHand(this.lived.offHand); 336 equipment.setHelmet(this.lived.helmet); 337 equipment.setChestplate(this.lived.chestplate); 338 equipment.setLeggings(this.lived.leggings); 339 equipment.setBoots(this.lived.boots); 340 } 341 } 342 343 private void restoreInventory(InventoryHolder entity) { 344 try { 345 entity.getInventory().setContents(this.inventory); 346 } catch (IllegalArgumentException e) { 347 LOGGER.error("Failed to restore inventory", e); 348 } 349 } 350 351 private void storeLiving(LivingEntity lived) { 352 this.lived = new LivingEntityStats(); 353 this.lived.potions = lived.getActivePotionEffects(); 354 this.lived.loot = lived.getCanPickupItems(); 355 this.lived.name = lived.getCustomName(); 356 this.lived.visible = lived.isCustomNameVisible(); 357 this.lived.health = (float) lived.getHealth(); 358 this.lived.air = (short) lived.getRemainingAir(); 359 this.lived.persistent = lived.getRemoveWhenFarAway(); 360 this.lived.leashed = lived.isLeashed(); 361 if (this.lived.leashed) { 362 Location location = lived.getLeashHolder().getLocation(); 363 this.lived.leashX = (short) (this.getX() - location.getBlockX()); 364 this.lived.leashY = (short) (this.getY() - location.getBlockY()); 365 this.lived.leashZ = (short) (this.getZ() - location.getBlockZ()); 366 } 367 EntityEquipment equipment = lived.getEquipment(); 368 this.lived.equipped = equipment != null; 369 if (this.lived.equipped) { 370 storeEquipment(equipment); 371 } 372 } 373 374 void storeEquipment(EntityEquipment equipment) { 375 this.lived.mainHand = equipment.getItemInMainHand().clone(); 376 this.lived.offHand = equipment.getItemInOffHand().clone(); 377 this.lived.boots = equipment.getBoots().clone(); 378 this.lived.leggings = equipment.getLeggings().clone(); 379 this.lived.chestplate = equipment.getChestplate().clone(); 380 this.lived.helmet = equipment.getHelmet().clone(); 381 } 382 383 private void restoreTameable(Tameable entity) { 384 if (this.tamed.tamed) { 385 if (this.tamed.owner != null) { 386 entity.setTamed(true); 387 entity.setOwner(this.tamed.owner); 388 } 389 } 390 } 391 392 /** 393 * @deprecated Use {@link #restoreBreedable(Breedable)} instead 394 * @since 7.1.0 395 */ 396 @Deprecated(forRemoval = true, since = "7.1.0") 397 private void restoreAgeable(Ageable entity) { 398 if (!this.aged.adult) { 399 entity.setBaby(); 400 } 401 entity.setAgeLock(this.aged.locked); 402 if (this.aged.age > 0) { 403 entity.setAge(this.aged.age); 404 } 405 } 406 407 /** 408 * @deprecated Use {@link #storeBreedable(Breedable)} instead 409 * @since 7.1.0 410 */ 411 @Deprecated(forRemoval = true, since = "7.1.0") 412 public void storeAgeable(Ageable aged) { 413 this.aged = new AgeableStats(); 414 this.aged.age = aged.getAge(); 415 this.aged.locked = aged.getAgeLock(); 416 this.aged.adult = aged.isAdult(); 417 } 418 419 /** 420 * @since 7.1.0 421 */ 422 private void restoreBreedable(Breedable entity) { 423 if (!this.aged.adult) { 424 entity.setBaby(); 425 } 426 entity.setAgeLock(this.aged.locked); 427 if (this.aged.age > 0) { 428 entity.setAge(this.aged.age); 429 } 430 } 431 432 /** 433 * @since 7.1.0 434 */ 435 private void storeBreedable(Breedable breedable) { 436 this.aged = new AgeableStats(); 437 this.aged.age = breedable.getAge(); 438 this.aged.locked = breedable.getAgeLock(); 439 this.aged.adult = breedable.isAdult(); 440 } 441 442 public void storeTameable(Tameable tamed) { 443 this.tamed = new TameableStats(); 444 this.tamed.owner = tamed.getOwner(); 445 this.tamed.tamed = tamed.isTamed(); 446 } 447 448 @SuppressWarnings("deprecation") // Paper deprecation 449 @Override 450 public Entity spawn(World world, int xOffset, int zOffset) { 451 Location location = new Location(world, this.getX() + xOffset, this.getY(), this.z + zOffset); 452 location.setYaw(this.yaw); 453 location.setPitch(this.pitch); 454 if (!this.getType().isSpawnable()) { 455 return null; 456 } 457 Entity entity; 458 switch (this.getType().toString()) { 459 case "DROPPED_ITEM", "ITEM" -> { 460 return world.dropItem(location, this.stack); 461 } 462 case "PLAYER", "LEASH_HITCH" -> { 463 return null; 464 } 465 case "ITEM_FRAME" -> entity = world.spawn(location, ItemFrame.class); 466 case "PAINTING" -> entity = world.spawn(location, Painting.class); 467 default -> entity = world.spawnEntity(location, this.getType()); 468 } 469 if (this.depth == 0) { 470 return entity; 471 } 472 if (this.base.passenger != null) { 473 try { 474 entity.addPassenger(this.base.passenger.spawn(world, xOffset, zOffset)); 475 } catch (Exception ignored) { 476 } 477 } 478 if (this.base.fall != 0) { 479 entity.setFallDistance(this.base.fall); 480 } 481 if (this.base.fire != 0) { 482 entity.setFireTicks(this.base.fire); 483 } 484 if (this.base.age != 0) { 485 entity.setTicksLived(this.base.age); 486 } 487 entity.setVelocity(new Vector(this.base.vX, this.base.vY, this.base.vZ)); 488 if (this.depth == 1) { 489 return entity; 490 } 491 if (this.noGravity) { 492 entity.setGravity(false); 493 } 494 switch (entity.getType().toString()) { 495 case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT", 496 "OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> { 497 Boat boat = (Boat) entity; 498 boat.setBoatType(Boat.Type.values()[dataByte]); 499 return entity; 500 } 501 case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT", 502 "JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT", 503 "SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> { 504 ChestBoat boat = (ChestBoat) entity; 505 boat.setBoatType(Boat.Type.values()[dataByte]); 506 restoreInventory(boat); 507 return entity; 508 } 509 // SLIME is not even stored 510 /* case "SLIME" -> { 511 ((Slime) entity).setSize(this.dataByte); 512 return entity; 513 } */ 514 case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "DROPPED_ITEM", "EXPERIENCE_ORB", "FALLING_BLOCK", 515 "FIREBALL", "FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND", 516 "MINECART_MOB_SPAWNER", "MINECART_TNT", "PLAYER", "PRIMED_TNT", "SMALL_FIREBALL", "SNOWBALL", 517 "SPLASH_POTION", "THROWN_EXP_BOTTLE", "SPECTRAL_ARROW", "SHULKER_BULLET", "AREA_EFFECT_CLOUD", 518 "DRAGON_FIREBALL", "WITHER_SKULL", "MINECART_FURNACE", "LLAMA_SPIT", "TRIDENT", "UNKNOWN" -> { 519 // Do this stuff later 520 return entity; 521 } 522 // MISC // 523 case "ITEM_FRAME" -> { 524 ItemFrame itemframe = (ItemFrame) entity; 525 itemframe.setRotation(Rotation.values()[this.dataByte]); 526 itemframe.setItem(this.stack); 527 return entity; 528 } 529 case "PAINTING" -> { 530 Painting painting = (Painting) entity; 531 painting.setFacingDirection(BlockFace.values()[this.dataByte], true); 532 painting.setArt(Art.getByName(this.dataString), true); 533 return entity; 534 } 535 // END MISC // 536 // INVENTORY HOLDER // 537 case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> { 538 restoreInventory((InventoryHolder) entity); 539 return entity; 540 } 541 // START LIVING ENTITY // 542 // START AGEABLE // 543 // START TAMEABLE // 544 case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> { 545 AbstractHorse horse = (AbstractHorse) entity; 546 horse.setJumpStrength(this.horse.jump); 547 if (horse instanceof ChestedHorse) { 548 ((ChestedHorse) horse).setCarryingChest(this.horse.chest); 549 } 550 //todo broken as of 1.13 551 //horse.setVariant(this.horse.variant); 552 //horse.setStyle(this.horse.style); 553 //horse.setColor(this.horse.color); 554 restoreTameable(horse); 555 restoreBreedable(horse); 556 restoreLiving(horse); 557 restoreInventory(horse); 558 return entity; 559 } 560 // END INVENTORY HOLDER // 561 case "WOLF", "OCELOT", "CAT", "PARROT" -> { 562 restoreTameable((Tameable) entity); 563 restoreBreedable((Breedable) entity); 564 restoreLiving((LivingEntity) entity); 565 return entity; 566 } 567 // END AGEABLE // 568 case "SHEEP" -> { 569 Sheep sheep = (Sheep) entity; 570 if (this.dataByte == 1) { 571 sheep.setSheared(true); 572 } 573 if (this.dataByte2 != 0) { 574 sheep.setColor(DyeColor.values()[this.dataByte2]); 575 } 576 restoreBreedable(sheep); 577 restoreLiving(sheep); 578 return sheep; 579 } 580 case "VILLAGER", "CHICKEN", "COW", "TURTLE", "POLAR_BEAR", "MUSHROOM_COW", "PIG" -> { 581 restoreBreedable((Breedable) entity); 582 restoreLiving((LivingEntity) entity); 583 return entity; 584 } 585 // END AGEABLE // 586 case "RABBIT" -> { 587 if (this.dataByte != 0) { 588 ((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]); 589 } 590 restoreBreedable((Breedable) entity); 591 restoreLiving((LivingEntity) entity); 592 return entity; 593 } 594 case "ARMOR_STAND" -> { 595 // CHECK positions 596 ArmorStand stand = (ArmorStand) entity; 597 if (this.inventory[0] != null) { 598 stand.setItemInHand(this.inventory[0]); 599 } 600 if (this.inventory[1] != null) { 601 stand.setHelmet(this.inventory[1]); 602 } 603 if (this.inventory[2] != null) { 604 stand.setChestplate(this.inventory[2]); 605 } 606 if (this.inventory[3] != null) { 607 stand.setLeggings(this.inventory[3]); 608 } 609 if (this.inventory[4] != null) { 610 stand.setBoots(this.inventory[4]); 611 } 612 if (this.stand.head[0] != 0 || this.stand.head[1] != 0 || this.stand.head[2] != 0) { 613 EulerAngle pose = 614 new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]); 615 stand.setHeadPose(pose); 616 } 617 if (this.stand.body[0] != 0 || this.stand.body[1] != 0 || this.stand.body[2] != 0) { 618 EulerAngle pose = 619 new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]); 620 stand.setBodyPose(pose); 621 } 622 if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0 623 || this.stand.leftLeg[2] != 0) { 624 EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1], 625 this.stand.leftLeg[2] 626 ); 627 stand.setLeftLegPose(pose); 628 } 629 if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0 630 || this.stand.rightLeg[2] != 0) { 631 EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1], 632 this.stand.rightLeg[2] 633 ); 634 stand.setRightLegPose(pose); 635 } 636 if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0 637 || this.stand.leftArm[2] != 0) { 638 EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1], 639 this.stand.leftArm[2] 640 ); 641 stand.setLeftArmPose(pose); 642 } 643 if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0 644 || this.stand.rightArm[2] != 0) { 645 EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1], 646 this.stand.rightArm[2] 647 ); 648 stand.setRightArmPose(pose); 649 } 650 if (this.stand.invisible) { 651 stand.setVisible(false); 652 } 653 if (this.stand.arms) { 654 stand.setArms(true); 655 } 656 if (this.stand.noPlate) { 657 stand.setBasePlate(false); 658 } 659 if (this.stand.small) { 660 stand.setSmall(true); 661 } 662 restoreLiving(stand); 663 return stand; 664 } 665 case "BAT" -> { 666 if (this.dataByte != 0) { 667 ((Bat) entity).setAwake(true); 668 } 669 restoreLiving((LivingEntity) entity); 670 return entity; 671 } 672 case "ENDER_DRAGON" -> { 673 if (this.dataByte != 0) { 674 ((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]); 675 } 676 restoreLiving((LivingEntity) entity); 677 return entity; 678 } 679 case "ENDERMITE", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN", "PIGLIN", "ZOMBIFIED_PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH", "GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SNOWMAN", "SHULKER", "GUARDIAN", "ELDER_GUARDIAN", "SKELETON", "WITHER_SKELETON" -> { 680 restoreLiving((LivingEntity) entity); 681 return entity; 682 } 683 case "IRON_GOLEM" -> { 684 if (this.dataByte != 0) { 685 ((IronGolem) entity).setPlayerCreated(true); 686 } 687 restoreLiving((LivingEntity) entity); 688 return entity; 689 } 690 default -> { 691 if (Settings.DEBUG) { 692 LOGGER.info("Could not identify entity: {}", entity.getType()); 693 } 694 return entity; 695 } 696 // END LIVING 697 } 698 } 699 700 public void saveEntity() { 701 } 702 703 private byte getOrdinal(Object[] list, Object value) { 704 for (byte i = 0; i < list.length; i++) { 705 if (list[i].equals(value)) { 706 return i; 707 } 708 } 709 return 0; 710 } 711 712 713}