From 53fca580f3ff3cf9208eb871b5ccb43bf485776c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 12 Oct 2025 23:04:05 +0200 Subject: [PATCH] added IronGolemAnimation --- .../IronGolemAnimation.java | 113 ++++++++++++++++++ .../NaturalIronGolemSpawnEvent.java | 15 +++ 2 files changed, 128 insertions(+) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/IronGolemAnimation.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/NaturalIronGolemSpawnEvent.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/IronGolemAnimation.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/IronGolemAnimation.java new file mode 100644 index 0000000..02e197a --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/IronGolemAnimation.java @@ -0,0 +1,113 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.ironGolemAnimation; + +import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class IronGolemAnimation extends Appliance { + record BlockChange(Block original, BlockData fakeBlock) {} + + public void onGolemSpawn(IronGolem golem) { + this.modifyGolem(golem, false); + Location golemLocation = golem.getLocation(); + + BlockData bodyBlockData = Bukkit.createBlockData(Material.IRON_BLOCK); + BlockData headBlockData = Bukkit.createBlockData( + Material.CARVED_PUMPKIN, + blockData -> ((Directional) blockData).setFacing(golem.getFacing()) + ); + Vector facingVector = golem.getFacing().getDirection().rotateAroundY(Math.toRadians(90)); + Block golemCenterBlock = golemLocation.getBlock().getRelative(BlockFace.UP); + + List buildBlocks = List.of( + new BlockChange(golemCenterBlock.getRelative(BlockFace.DOWN), bodyBlockData), + new BlockChange(golemCenterBlock, bodyBlockData), + new BlockChange(golemCenterBlock.getLocation().add(facingVector).getBlock(), bodyBlockData), + new BlockChange(golemCenterBlock.getLocation().add(facingVector.multiply(-1)).getBlock(), bodyBlockData), + new BlockChange(golemCenterBlock.getRelative(BlockFace.UP), headBlockData) + ); + + Collection viewers = golemLocation.getNearbyPlayers(golemLocation.getWorld().getViewDistance()); + BiConsumer changeBlockForViewers = (location, blockData) -> { + viewers.forEach(player -> player.sendBlockChange(location, blockData)); + golem.getWorld().playSound( + location, + blockData.getSoundGroup().getPlaceSound(), + SoundCategory.BLOCKS, + 1f, + 1f + ); + }; + for(int i = 0; i < buildBlocks.size(); i++) { + BlockChange blockChange = buildBlocks.get(i); + Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> changeBlockForViewers.accept(blockChange.original.getLocation(), blockChange.fakeBlock), + 6L * i + ); + } + + Consumer> restoreBlockChanges = (blocks) -> { + buildBlocks.forEach((blockChange) -> changeBlockForViewers.accept( + blockChange.original().getLocation(), + blockChange.original.getBlockData() + )); + + this.modifyGolem(golem, true); + this.spawnEffect(buildBlocks); + }; + Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> restoreBlockChanges.accept(buildBlocks), + 6L * buildBlocks.size() + 2 + ); + } + + private void spawnEffect(List buildBlocks) { + buildBlocks.forEach((blockChange) -> { + World world = blockChange.original.getLocation().getWorld(); + world.spawnParticle( + Particle.BLOCK, + blockChange.original.getLocation().add(0.5, 0.5, 0.5), + 50, + blockChange.fakeBlock + ); + world.playSound( + blockChange.original.getLocation(), + blockChange.fakeBlock.getSoundGroup().getBreakSound(), + SoundCategory.BLOCKS, + 1f, + 1f + ); + }); + } + + public void modifyGolem(IronGolem golem, boolean setVisible) { + golem.setInvisible(!setVisible); + golem.setInvulnerable(!setVisible); + golem.setAI(setVisible); + golem.setGravity(setVisible); + golem.setCollidable(setVisible); + } + + @Override + protected @NotNull List listeners() { + return List.of( + new NaturalIronGolemSpawnEvent() + ); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/NaturalIronGolemSpawnEvent.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/NaturalIronGolemSpawnEvent.java new file mode 100644 index 0000000..192dc4d --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/ironGolemAnimation/NaturalIronGolemSpawnEvent.java @@ -0,0 +1,15 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.ironGolemAnimation; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.entity.IronGolem; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.CreatureSpawnEvent; + +class NaturalIronGolemSpawnEvent extends ApplianceListener { + @EventHandler + public void onGolemSpawn(CreatureSpawnEvent event) { + if(!(event.getEntity() instanceof IronGolem golem)) return; +// if(event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE) return; + this.getAppliance().onGolemSpawn(golem); + } +}