From 080253d4f4dcd0970bf9a755f50391a63521be86 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 13 Apr 2025 10:19:02 +1000 Subject: [PATCH] SPIGOT-8040: Fire SpawnChangeEvent in all cases and include old angle --- .../minecraft/server/level/WorldServer.patch | 79 +++++++++++-------- .../org/bukkit/craftbukkit/CraftWorld.java | 9 +-- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/nms-patches/net/minecraft/server/level/WorldServer.patch b/nms-patches/net/minecraft/server/level/WorldServer.patch index 694b356e6..b34c10722 100644 --- a/nms-patches/net/minecraft/server/level/WorldServer.patch +++ b/nms-patches/net/minecraft/server/level/WorldServer.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/WorldServer.java +++ b/net/minecraft/server/level/WorldServer.java -@@ -169,6 +169,24 @@ +@@ -169,6 +169,26 @@ import net.minecraft.world.ticks.TickListServer; import org.slf4j.Logger; @@ -15,17 +15,19 @@ +import org.bukkit.WeatherType; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; ++import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.craftbukkit.util.WorldUUID; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.server.MapInitializeEvent; +import org.bukkit.event.weather.LightningStrikeEvent; ++import org.bukkit.event.world.SpawnChangeEvent; +import org.bukkit.event.world.TimeSkipEvent; +// CraftBukkit end + public class WorldServer extends World implements ServerEntityGetter, GeneratorAccessSeed { public static final BlockPosition END_SPAWN_POINT = new BlockPosition(100, 50, 0); -@@ -182,7 +200,7 @@ +@@ -182,7 +202,7 @@ final List players = Lists.newArrayList(); private final ChunkProviderServer chunkSource; private final MinecraftServer server; @@ -34,7 +36,7 @@ private int lastSpawnChunkRadius; final EntityTickList entityTickList = new EntityTickList(); public final PersistentEntitySectionManager entityManager; -@@ -209,13 +227,47 @@ +@@ -209,13 +229,47 @@ private final boolean tickTime; private final RandomSequences randomSequences; @@ -84,7 +86,7 @@ boolean flag2 = minecraftserver.forceSynchronousWrites(); DataFixer datafixer = minecraftserver.getFixerUpper(); EntityPersistentStorage entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver); -@@ -243,9 +295,9 @@ +@@ -243,9 +297,9 @@ long l = minecraftserver.getWorldData().worldGenOptions().seed(); this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), minecraftserver.getStructureManager(), resourcekey, chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer); @@ -97,7 +99,7 @@ } else { this.dragonFight = null; } -@@ -255,6 +307,7 @@ +@@ -255,6 +309,7 @@ this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomsequences, () -> { return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.TYPE); }); @@ -105,7 +107,7 @@ } /** @deprecated */ -@@ -299,13 +352,22 @@ +@@ -299,13 +354,22 @@ int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { @@ -130,7 +132,7 @@ if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) { this.resetWeatherCycle(); } -@@ -341,7 +403,7 @@ +@@ -341,7 +405,7 @@ this.handlingTick = false; gameprofilerfiller.pop(); @@ -139,7 +141,7 @@ if (flag1) { this.resetEmptyTime(); -@@ -421,7 +483,7 @@ +@@ -421,7 +485,7 @@ private void wakeUpAllPlayers() { this.sleepStatus.removeAllSleepers(); @@ -148,7 +150,7 @@ entityplayer.stopSleepInBed(false, false); }); } -@@ -498,7 +560,7 @@ +@@ -498,7 +562,7 @@ entityhorseskeleton.setTrap(true); entityhorseskeleton.setAge(0); entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); @@ -157,7 +159,7 @@ } } -@@ -507,7 +569,7 @@ +@@ -507,7 +571,7 @@ if (entitylightning != null) { entitylightning.snapTo(Vec3D.atBottomCenterOf(blockposition)); entitylightning.setVisualOnly(flag1); @@ -166,7 +168,7 @@ } } } -@@ -522,7 +584,7 @@ +@@ -522,7 +586,7 @@ BiomeBase biomebase = (BiomeBase) this.getBiome(blockposition1).value(); if (biomebase.shouldFreeze(this, blockposition2)) { @@ -175,7 +177,7 @@ } if (this.isRaining()) { -@@ -538,10 +600,10 @@ +@@ -538,10 +602,10 @@ IBlockData iblockdata1 = (IBlockData) iblockdata.setValue(BlockSnow.LAYERS, j + 1); Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1); @@ -188,7 +190,7 @@ } } -@@ -698,6 +760,7 @@ +@@ -698,6 +762,7 @@ this.rainLevel = MathHelper.clamp(this.rainLevel, 0.0F, 1.0F); } @@ -196,7 +198,7 @@ if (this.oRainLevel != this.rainLevel) { this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, this.rainLevel), this.dimension()); } -@@ -716,15 +779,48 @@ +@@ -716,15 +781,48 @@ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, this.rainLevel)); this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel)); } @@ -247,7 +249,7 @@ } public void resetEmptyTime() { -@@ -760,6 +856,7 @@ +@@ -760,6 +858,7 @@ }); gameprofilerfiller.incrementCounter("tickNonPassenger"); entity.tick(); @@ -255,7 +257,7 @@ gameprofilerfiller.pop(); for (Entity entity1 : entity.getPassengers()) { -@@ -780,6 +877,7 @@ +@@ -780,6 +879,7 @@ }); gameprofilerfiller.incrementCounter("tickPassenger"); entity1.rideTick(); @@ -263,7 +265,7 @@ gameprofilerfiller.pop(); for (Entity entity2 : entity1.getPassengers()) { -@@ -811,6 +909,7 @@ +@@ -811,6 +911,7 @@ ChunkProviderServer chunkproviderserver = this.getChunkSource(); if (!flag1) { @@ -271,7 +273,7 @@ if (iprogressupdate != null) { iprogressupdate.progressStartNoAbort(IChatBaseComponent.translatable("menu.savingLevel")); } -@@ -828,11 +927,19 @@ +@@ -828,11 +929,19 @@ } } @@ -292,7 +294,7 @@ } WorldPersistentData worldpersistentdata = this.getChunkSource().getDataStorage(); -@@ -901,18 +1008,40 @@ +@@ -901,18 +1010,40 @@ @Override public boolean addFreshEntity(Entity entity) { @@ -336,7 +338,7 @@ } } -@@ -937,24 +1066,37 @@ +@@ -937,24 +1068,37 @@ this.entityManager.addNewEntity(entityplayer); } @@ -378,7 +380,7 @@ return true; } } -@@ -965,17 +1107,45 @@ +@@ -965,17 +1109,45 @@ } public void removePlayerImmediately(EntityPlayer entityplayer, Entity.RemovalReason entity_removalreason) { @@ -425,7 +427,7 @@ if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { entityplayer.connection.send(new PacketPlayOutBlockBreakAnimation(i, blockposition, j)); } -@@ -1078,8 +1248,21 @@ +@@ -1078,8 +1250,21 @@ if (VoxelShapes.joinIsNotEmpty(voxelshape, voxelshape1, OperatorBoolean.NOT_SAME)) { List list = new ObjectArrayList(); @@ -448,7 +450,7 @@ NavigationAbstract navigationabstract = entityinsentient.getNavigation(); if (navigationabstract.shouldRecomputePath(blockposition)) { -@@ -1142,6 +1325,12 @@ +@@ -1142,6 +1327,12 @@ @Override public void explode(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, World.a world_a, ParticleParam particleparam, ParticleParam particleparam1, Holder holder) { @@ -461,7 +463,7 @@ Explosion.Effect explosion_effect; switch (world_a) { -@@ -1160,6 +1349,11 @@ +@@ -1160,6 +1351,11 @@ case TRIGGER: explosion_effect = Explosion.Effect.TRIGGER_BLOCK; break; @@ -473,7 +475,7 @@ default: throw new MatchException((String) null, (Throwable) null); } -@@ -1169,6 +1363,11 @@ +@@ -1169,6 +1365,11 @@ ServerExplosion serverexplosion = new ServerExplosion(this, entity, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1); serverexplosion.explode(); @@ -485,7 +487,7 @@ ParticleParam particleparam2 = serverexplosion.isSmall() ? particleparam : particleparam1; for (EntityPlayer entityplayer : this.players) { -@@ -1179,6 +1378,7 @@ +@@ -1179,6 +1380,7 @@ } } @@ -493,7 +495,7 @@ } private Explosion.Effect getDestroyType(GameRules.GameRuleKey gamerules_gamerulekey) { -@@ -1239,15 +1439,22 @@ +@@ -1239,15 +1441,22 @@ } public int sendParticles(T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) { @@ -517,7 +519,7 @@ if (this.sendParticles(entityplayer, flag, d0, d1, d2, packetplayoutworldparticles)) { ++j; -@@ -1300,7 +1507,7 @@ +@@ -1300,7 +1509,7 @@ @Nullable public BlockPosition findNearestMapStructure(TagKey tagkey, BlockPosition blockposition, int i, boolean flag) { @@ -526,7 +528,7 @@ return null; } else { Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(tagkey); -@@ -1342,10 +1549,21 @@ +@@ -1342,10 +1551,21 @@ @Nullable @Override public WorldMap getMapData(MapId mapid) { @@ -549,7 +551,18 @@ this.getServer().overworld().getDataStorage().set(WorldMap.type(mapid), worldmap); } -@@ -1557,12 +1775,12 @@ +@@ -1359,6 +1579,10 @@ + + if (!blockposition1.equals(blockposition) || f1 != f) { + this.levelData.setSpawn(blockposition, f); ++ // CraftBukkit start - Notify anyone who's listening. ++ SpawnChangeEvent event = new SpawnChangeEvent(getWorld(), CraftLocation.toBukkit(blockposition, getWorld(), f1, 0.0F)); ++ getCraftServer().getPluginManager().callEvent(event); ++ // CraftBukkit end + this.getServer().getPlayerList().broadcastAll(new PacketPlayOutSpawnPosition(blockposition, f)); + } + +@@ -1557,12 +1781,12 @@ } public boolean isFlat() { @@ -564,7 +577,7 @@ } @Nullable -@@ -1592,7 +1810,7 @@ +@@ -1592,7 +1816,7 @@ object2intopenhashmap.addTo(s, 1); } @@ -573,7 +586,7 @@ String s1 = (String) entry.getKey(); return s1 + ":" + entry.getIntValue(); -@@ -1754,6 +1972,8 @@ +@@ -1754,6 +1978,8 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -582,7 +595,7 @@ } public void onTrackingEnd(Entity entity) { -@@ -1780,6 +2000,14 @@ +@@ -1780,6 +2006,14 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 285acb1c5..f21946418 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -132,7 +132,6 @@ import org.bukkit.entity.TippedArrow; import org.bukkit.entity.Trident; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.weather.LightningStrikeEvent; -import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.world.TimeSkipEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; @@ -203,13 +202,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean setSpawnLocation(int x, int y, int z, float angle) { try { - Location previousLocation = getSpawnLocation(); - world.levelData.setSpawn(new BlockPosition(x, y, z), angle); - - // Notify anyone who's listening. - SpawnChangeEvent event = new SpawnChangeEvent(this, previousLocation); - server.getPluginManager().callEvent(event); - + world.setDefaultSpawnPos(new BlockPosition(x, y, z), angle); return true; } catch (Exception e) { return false;