--- a/net/minecraft/world/level/storage/WorldDataServer.java
+++ b/net/minecraft/world/level/storage/WorldDataServer.java
@@ -40,6 +40,15 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+// CraftBukkit start
+import net.minecraft.network.protocol.game.PacketPlayOutServerDifficulty;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.server.level.WorldServer;
+import org.bukkit.Bukkit;
+import org.bukkit.event.weather.ThunderChangeEvent;
+import org.bukkit.event.weather.WeatherChangeEvent;
+// CraftBukkit end
+
 public class WorldDataServer implements IWorldDataServer, SaveData {
 
     private static final Logger LOGGER = LogManager.getLogger();
@@ -78,6 +87,7 @@
     private final Set<String> knownServerBrands;
     private boolean wasModded;
     private final CustomFunctionCallbackTimerQueue<MinecraftServer> scheduledEvents;
+    public WorldServer world; // CraftBukkit
 
     private WorldDataServer(@Nullable DataFixer datafixer, int i, @Nullable NBTTagCompound nbttagcompound, boolean flag, int j, int k, int l, float f, long i1, long j1, int k1, int l1, int i2, boolean flag1, int j2, boolean flag2, boolean flag3, boolean flag4, WorldBorder.c worldborder_c, int k2, int l2, @Nullable UUID uuid, Set<String> set, CustomFunctionCallbackTimerQueue<MinecraftServer> customfunctioncallbacktimerqueue, @Nullable NBTTagCompound nbttagcompound1, NBTTagCompound nbttagcompound2, WorldSettings worldsettings, GeneratorSettings generatorsettings, Lifecycle lifecycle) {
         this.fixerUpper = datafixer;
@@ -121,7 +131,8 @@
             return (NBTBase) dynamic.get("DimensionData").get("1").get("DragonFight").orElseEmptyMap().getValue();
         });
 
-        return new WorldDataServer(datafixer, i, nbttagcompound, dynamic.get("WasModded").asBoolean(false), dynamic.get("SpawnX").asInt(0), dynamic.get("SpawnY").asInt(0), dynamic.get("SpawnZ").asInt(0), dynamic.get("SpawnAngle").asFloat(0.0F), j, dynamic.get("DayTime").asLong(j), levelversion.a(), dynamic.get("clearWeatherTime").asInt(0), dynamic.get("rainTime").asInt(0), dynamic.get("raining").asBoolean(false), dynamic.get("thunderTime").asInt(0), dynamic.get("thundering").asBoolean(false), dynamic.get("initialized").asBoolean(true), dynamic.get("DifficultyLocked").asBoolean(false), WorldBorder.c.a(dynamic, WorldBorder.DEFAULT_SETTINGS), dynamic.get("WanderingTraderSpawnDelay").asInt(0), dynamic.get("WanderingTraderSpawnChance").asInt(0), (UUID) dynamic.get("WanderingTraderId").read(MinecraftSerializableUUID.CODEC).result().orElse((Object) null), (Set) dynamic.get("ServerBrands").asStream().flatMap((dynamic1) -> {
+        // CraftBukkit - decompile error
+        return new WorldDataServer(datafixer, i, nbttagcompound, dynamic.get("WasModded").asBoolean(false), dynamic.get("SpawnX").asInt(0), dynamic.get("SpawnY").asInt(0), dynamic.get("SpawnZ").asInt(0), dynamic.get("SpawnAngle").asFloat(0.0F), j, dynamic.get("DayTime").asLong(j), levelversion.a(), dynamic.get("clearWeatherTime").asInt(0), dynamic.get("rainTime").asInt(0), dynamic.get("raining").asBoolean(false), dynamic.get("thunderTime").asInt(0), dynamic.get("thundering").asBoolean(false), dynamic.get("initialized").asBoolean(true), dynamic.get("DifficultyLocked").asBoolean(false), WorldBorder.c.a(dynamic, WorldBorder.DEFAULT_SETTINGS), dynamic.get("WanderingTraderSpawnDelay").asInt(0), dynamic.get("WanderingTraderSpawnChance").asInt(0), (UUID) dynamic.get("WanderingTraderId").read(MinecraftSerializableUUID.CODEC).result().orElse(null), (Set) dynamic.get("ServerBrands").asStream().flatMap((dynamic1) -> {
             return SystemUtils.a(dynamic1.asString().result());
         }).collect(Collectors.toCollection(Sets::newLinkedHashSet)), new CustomFunctionCallbackTimerQueue<>(CustomFunctionCallbackTimers.SERVER_CALLBACKS, dynamic.get("ScheduledEvents").asStream()), (NBTTagCompound) dynamic.get("CustomBossEvents").orElseEmptyMap().getValue(), nbttagcompound1, worldsettings, generatorsettings, lifecycle);
     }
@@ -141,7 +152,7 @@
 
     private void a(IRegistryCustom iregistrycustom, NBTTagCompound nbttagcompound, @Nullable NBTTagCompound nbttagcompound1) {
         NBTTagList nbttaglist = new NBTTagList();
-        Stream stream = this.knownServerBrands.stream().map(NBTTagString::a);
+        Stream<NBTTagString> stream = this.knownServerBrands.stream().map(NBTTagString::a); // CraftBukkit - decompile error
 
         Objects.requireNonNull(nbttaglist);
         stream.forEach(nbttaglist::add);
@@ -155,11 +166,11 @@
         nbttagcompound.set("Version", nbttagcompound2);
         nbttagcompound.setInt("DataVersion", SharedConstants.getGameVersion().getWorldVersion());
         RegistryWriteOps<NBTBase> registrywriteops = RegistryWriteOps.a(DynamicOpsNBT.INSTANCE, iregistrycustom);
-        DataResult dataresult = GeneratorSettings.CODEC.encodeStart(registrywriteops, this.worldGenSettings);
+        DataResult<NBTBase> dataresult = GeneratorSettings.CODEC.encodeStart(registrywriteops, this.worldGenSettings); // CraftBukkit - decompile error
         Logger logger = WorldDataServer.LOGGER;
 
         Objects.requireNonNull(logger);
-        dataresult.resultOrPartial(SystemUtils.a("WorldGenSettings: ", logger::error)).ifPresent((nbtbase) -> {
+        dataresult.resultOrPartial(SystemUtils.a("WorldGenSettings: ", (java.util.function.Consumer<String>) logger::error)).ifPresent((nbtbase) -> { // CraftBukkit - decompile error
             nbttagcompound.set("WorldGenSettings", nbtbase);
         });
         nbttagcompound.setInt("GameType", this.settings.getGameType().getId());
@@ -203,6 +214,7 @@
             nbttagcompound.a("WanderingTraderId", this.wanderingTraderId);
         }
 
+        nbttagcompound.setString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit
     }
 
     @Override
@@ -320,6 +332,20 @@
 
     @Override
     public void setThundering(boolean flag) {
+        // CraftBukkit start
+        if (this.thundering == flag) {
+            return;
+        }
+
+        org.bukkit.World world = Bukkit.getWorld(getName());
+        if (world != null) {
+            ThunderChangeEvent thunder = new ThunderChangeEvent(world, flag);
+            Bukkit.getServer().getPluginManager().callEvent(thunder);
+            if (thunder.isCancelled()) {
+                return;
+            }
+        }
+        // CraftBukkit end
         this.thundering = flag;
     }
 
@@ -340,6 +366,20 @@
 
     @Override
     public void setStorm(boolean flag) {
+        // CraftBukkit start
+        if (this.raining == flag) {
+            return;
+        }
+
+        org.bukkit.World world = Bukkit.getWorld(getName());
+        if (world != null) {
+            WeatherChangeEvent weather = new WeatherChangeEvent(world, flag);
+            Bukkit.getServer().getPluginManager().callEvent(weather);
+            if (weather.isCancelled()) {
+                return;
+            }
+        }
+        // CraftBukkit end
         this.raining = flag;
     }
 
@@ -406,6 +446,12 @@
     @Override
     public void setDifficulty(EnumDifficulty enumdifficulty) {
         this.settings = this.settings.a(enumdifficulty);
+        // CraftBukkit start
+        PacketPlayOutServerDifficulty packet = new PacketPlayOutServerDifficulty(this.getDifficulty(), this.isDifficultyLocked());
+        for (EntityPlayer player : (java.util.List<EntityPlayer>) (java.util.List) world.getPlayers()) {
+            player.connection.sendPacket(packet);
+        }
+        // CraftBukkit end
     }
 
     @Override
@@ -526,4 +572,12 @@
     public WorldSettings I() {
         return this.settings.h();
     }
+
+    // CraftBukkit start - Check if the name stored in NBT is the correct one
+    public void checkName(String name) {
+        if (!this.settings.levelName.equals(name)) {
+            this.settings.levelName = name;
+        }
+    }
+    // CraftBukkit end
 }
