From b9a7ab8445092cd6fa9166f286425aa04432d58e Mon Sep 17 00:00:00 2001
From: Patrick Miller <apickledwalrus@gmail.com>
Date: Thu, 6 Jun 2024 12:28:02 -0400
Subject: [PATCH 1/6] Fix PotionData NPE (#6757)

---
 .../classes/data/BukkitEventValues.java       | 32 +++------------
 .../njol/skript/util/PotionEffectUtils.java   | 41 ++++++-------------
 ...756-potion missing base type causes npe.sk |  3 ++
 3 files changed, 22 insertions(+), 54 deletions(-)
 create mode 100644 src/test/skript/tests/regressions/6756-potion missing base type causes npe.sk

diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
index d026bc55a19..d8e9ea0b94e 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
@@ -18,9 +18,6 @@
  */
 package ch.njol.skript.classes.data;
 
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -662,34 +659,17 @@ public LivingEntity[] get(AreaEffectCloudApplyEvent event) {
 			}
 		}, EventValues.TIME_NOW);
 		EventValues.registerEventValue(AreaEffectCloudApplyEvent.class, PotionEffectType.class, new Getter<PotionEffectType, AreaEffectCloudApplyEvent>() {
-			@Nullable
-			private final MethodHandle BASE_POTION_DATA_HANDLE;
-
-			{
-				MethodHandle basePotionDataHandle = null;
-				if (Skript.methodExists(AreaEffectCloud.class, "getBasePotionData")) {
-					try {
-						basePotionDataHandle = MethodHandles.lookup().findVirtual(AreaEffectCloud.class, "getBasePotionData", MethodType.methodType(PotionData.class));
-					} catch (NoSuchMethodException | IllegalAccessException e) {
-						Skript.exception(e, "Failed to load legacy potion data support. Potions may not work as expected.");
-					}
-				}
-				BASE_POTION_DATA_HANDLE = basePotionDataHandle;
-			}
-
+			private final boolean HAS_POTION_TYPE_METHOD = Skript.methodExists(AreaEffectCloud.class, "getBasePotionType");
 			@Override
 			@Nullable
 			public PotionEffectType get(AreaEffectCloudApplyEvent e) {
-				if (BASE_POTION_DATA_HANDLE != null) {
-					try {
-						return ((PotionData) BASE_POTION_DATA_HANDLE.invoke(e.getEntity())).getType().getEffectType();
-					} catch (Throwable ex) {
-						throw Skript.exception(ex, "An error occurred while trying to invoke legacy area effect cloud potion effect support.");
-					}
-				} else {
+				// TODO needs to be reworked to support multiple values (there can be multiple potion effects)
+				if (HAS_POTION_TYPE_METHOD) {
 					PotionType base = e.getEntity().getBasePotionType();
-					if (base != null) // TODO this is deprecated... this should become a multi-value event value
+					if (base != null)
 						return base.getEffectType();
+				} else {
+					return e.getEntity().getBasePotionData().getType().getEffectType();
 				}
 				return null;
 			}
diff --git a/src/main/java/ch/njol/skript/util/PotionEffectUtils.java b/src/main/java/ch/njol/skript/util/PotionEffectUtils.java
index bc72f768ae6..88f4bfbfe7c 100644
--- a/src/main/java/ch/njol/skript/util/PotionEffectUtils.java
+++ b/src/main/java/ch/njol/skript/util/PotionEffectUtils.java
@@ -18,9 +18,6 @@
  */
 package ch.njol.skript.util;
 
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -346,20 +343,7 @@ else if (HAS_SUSPICIOUS_META && meta instanceof SuspiciousStewMeta)
 		itemType.setItemMeta(meta);
 	}
 
-	@Nullable
-	private static final MethodHandle BASE_POTION_DATA_HANDLE;
-
-	static {
-		MethodHandle basePotionDataHandle = null;
-		if (Skript.methodExists(PotionMeta.class, "getBasePotionData")) {
-			try {
-				basePotionDataHandle = MethodHandles.lookup().findVirtual(PotionMeta.class, "getBasePotionData", MethodType.methodType(PotionData.class));
-			} catch (NoSuchMethodException | IllegalAccessException e) {
-				Skript.exception(e, "Failed to load legacy potion data support. Potions may not work as expected.");
-			}
-		}
-		BASE_POTION_DATA_HANDLE = basePotionDataHandle;
-	}
+	private static final boolean HAS_POTION_TYPE_METHOD = Skript.methodExists(PotionMeta.class, "hasBasePotionType");
 
 	/**
 	 * Get all the PotionEffects of an ItemType
@@ -374,21 +358,22 @@ public static List<PotionEffect> getEffects(ItemType itemType) {
 		ItemMeta meta = itemType.getItemMeta();
 		if (meta instanceof PotionMeta) {
 			PotionMeta potionMeta = ((PotionMeta) meta);
-			effects.addAll(potionMeta.getCustomEffects());
-			if (BASE_POTION_DATA_HANDLE != null) {
-				try {
-					effects.addAll(PotionDataUtils.getPotionEffects((PotionData) BASE_POTION_DATA_HANDLE.invoke(meta)));
-				} catch (Throwable e) {
-					throw Skript.exception(e, "An error occurred while trying to invoke legacy potion data support.");
+			if (potionMeta.hasCustomEffects())
+				effects.addAll(potionMeta.getCustomEffects());
+			if (HAS_POTION_TYPE_METHOD) {
+				if (potionMeta.hasBasePotionType()) {
+					//noinspection ConstantConditions - checked via hasBasePotionType
+					effects.addAll(potionMeta.getBasePotionType().getPotionEffects());
+				}
+			} else { // use deprecated method
+				PotionData data = potionMeta.getBasePotionData();
+				if (data != null) {
+					effects.addAll(PotionDataUtils.getPotionEffects(data));
 				}
-			} else if (potionMeta.hasBasePotionType()) {
-				//noinspection ConstantConditions - checked via hasBasePotionType
-				effects.addAll(potionMeta.getBasePotionType().getPotionEffects());
 			}
-
 		} else if (HAS_SUSPICIOUS_META && meta instanceof SuspiciousStewMeta)
 			effects.addAll(((SuspiciousStewMeta) meta).getCustomEffects());
 		return effects;
 	}
-	
+
 }
diff --git a/src/test/skript/tests/regressions/6756-potion missing base type causes npe.sk b/src/test/skript/tests/regressions/6756-potion missing base type causes npe.sk
new file mode 100644
index 00000000000..8ffa025b5e6
--- /dev/null
+++ b/src/test/skript/tests/regressions/6756-potion missing base type causes npe.sk	
@@ -0,0 +1,3 @@
+test "potion missing base type":
+
+	assert potion effects of (plain potion of mundane) is not set with "it should not have any effects"

From 23cc26ba1328bc48c8a65154cdc329638ea43b82 Mon Sep 17 00:00:00 2001
From: Patrick Miller <apickledwalrus@gmail.com>
Date: Thu, 6 Jun 2024 12:50:28 -0400
Subject: [PATCH 2/6] Fix Command Syncing CME (#6763)

---
 .../njol/skript/structures/StructCommand.java | 23 ++++++++++++++-----
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/main/java/ch/njol/skript/structures/StructCommand.java b/src/main/java/ch/njol/skript/structures/StructCommand.java
index 5947a66ca52..e50476e5a8e 100644
--- a/src/main/java/ch/njol/skript/structures/StructCommand.java
+++ b/src/main/java/ch/njol/skript/structures/StructCommand.java
@@ -80,6 +80,9 @@
 @Since("1.0")
 public class StructCommand extends Structure {
 
+	// Paper versions with the new command system need a delay before syncing commands or a CME will occur.
+	private static final boolean DELAY_COMMAND_SYNCING = Skript.classExists("io.papermc.paper.command.brigadier.Commands");
+
 	public static final Priority PRIORITY = new Priority(500);
 
 	private static final Pattern COMMAND_PATTERN = Pattern.compile("(?i)^command\\s+/?(\\S+)\\s*(\\s+(.+))?$");
@@ -315,7 +318,7 @@ public boolean load() {
 
 	@Override
 	public boolean postLoad() {
-		attemptCommandSync();
+		scheduleCommandSync();
 		return true;
 	}
 
@@ -328,20 +331,28 @@ public void unload() {
 
 	@Override
 	public void postUnload() {
-		attemptCommandSync();
+		scheduleCommandSync();
 	}
 
-	private void attemptCommandSync() {
+	private void scheduleCommandSync() {
 		if (SYNC_COMMANDS.get()) {
 			SYNC_COMMANDS.set(false);
-			if (CommandReloader.syncCommands(Bukkit.getServer())) {
-				Skript.debug("Commands synced to clients");
+			if (DELAY_COMMAND_SYNCING) {
+				Bukkit.getScheduler().runTask(Skript.getInstance(), this::forceCommandSync);
 			} else {
-				Skript.debug("Commands changed but not synced to clients (normal on 1.12 and older)");
+				forceCommandSync();
 			}
 		}
 	}
 
+	private void forceCommandSync() {
+		if (CommandReloader.syncCommands(Bukkit.getServer())) {
+			Skript.debug("Commands synced to clients");
+		} else {
+			Skript.debug("Commands changed but not synced to clients (normal on 1.12 and older)");
+		}
+	}
+
 	@Override
 	public Priority getPriority() {
 		return PRIORITY;

From aa7955c2663f5623213b529b6d331909e00cac36 Mon Sep 17 00:00:00 2001
From: Patrick Miller <apickledwalrus@gmail.com>
Date: Sat, 15 Jun 2024 12:59:10 -0400
Subject: [PATCH 3/6] Fix Particle Definition Conflicts (#6760)

---
 .../skript/classes/data/SkriptClasses.java    |  1 +
 src/main/resources/lang/default.lang          | 38 +++++++++----------
 .../pull-6760-particle itemtype conflicts.sk  |  5 +++
 .../tests/syntaxes/effects/EffVisualEffect.sk |  6 +--
 4 files changed, 28 insertions(+), 22 deletions(-)
 create mode 100644 src/test/skript/tests/regressions/pull-6760-particle itemtype conflicts.sk

diff --git a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java
index 39dc6447fa5..6f92502cd2a 100644
--- a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java
+++ b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java
@@ -661,6 +661,7 @@ public String toVariableNameString(final Experience xp) {
 				.usage(VisualEffects.getAllNames())
 				.since("2.1")
 				.user("(visual|particle) effects?")
+				.after("itemtype")
 				.parser(new Parser<VisualEffect>() {
 					@Override
 					@Nullable
diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang
index 9f7df2c9e4c..90a37eb9e32 100644
--- a/src/main/resources/lang/default.lang
+++ b/src/main/resources/lang/default.lang
@@ -1473,13 +1473,13 @@ visual effects:
 
 		block_marker: # added in 1.18
 			name: block marker @a
-			pattern: (barrierbm:barrier|lightbm:light|%-blockdata/itemtype% block marker)
+			pattern: (barrierbm:barrier [particle]|lightbm:light [particle]|%-blockdata/itemtype% block marker)
 		barrier:
 			name: barrier @a
-			pattern: barrier
+			pattern: barrier [particle]
 		light: # added in 1.17
 			name: light @-
-			pattern: light
+			pattern: light [particle]
 
 		bubble: # added in 1.20.5
 			name: bubble @-
@@ -1534,7 +1534,7 @@ visual effects:
 
 		dolphin: # added in 1.13
 			name: dolphin @-
-			pattern: dolphin
+			pattern: dolphin [particle]
 
 		dragon_breath: # added in 1.14
 			name: dragon breath @-
@@ -1602,10 +1602,10 @@ visual effects:
 
 		elder_guardian: # added in 1.20.5
 			name: elder guardian @-
-			pattern: (elder guardian|mob appearance|guardian ghost)
+			pattern: (elder guardian particle|mob appearance|guardian ghost)
 		mob_appearance: # for versions below 1.20.5
 			name: mob appearance @-
-			pattern: (elder guardian|mob appearance|guardian ghost)
+			pattern: (elder guardian particle|mob appearance|guardian ghost)
 
 		electric_spark:
 			name: electric spark @-
@@ -1627,7 +1627,7 @@ visual effects:
 
 		end_rod:
 			name: end rod @-
-			pattern: end rod
+			pattern: end rod [particle]
 
 		entity_effect: # added in 1.20.5
 			name: entity effect @an
@@ -1693,10 +1693,10 @@ visual effects:
 
 		firework: # added in 1.20.5
 			name: firework @-
-			pattern: (firework|firework['s] spark)
+			pattern: (firework particle|firework['s] spark)
 		fireworks_spark: # for versions below 1.20.5
 			name: firework's spark @-
-			pattern: (firework|firework['s] spark)
+			pattern: (firework particle|firework['s] spark)
 
 		fishing: # added in 1.20.5
 			name: water wake @-
@@ -1764,24 +1764,24 @@ visual effects:
 
 		item_cobweb: # added in 1.20.5 (for 1.21)
 			name: cobweb @-
-			pattern: cobweb
+			pattern: cobweb [item|particle]
 
 		item_slime: # added in 1.20.5
 			name: slime @-
-			pattern: slime
+			pattern: slime [item|particle]
 		slime: # for versions below 1.20.5
 			name: slime @-
-			pattern: slime
+			pattern: slime [item|particle]
 
 		item_snowball: # added in 1.20.5
 			name: snowball @-
-			pattern: (snowball [break]|snow shovel|snow(man| golem) spawn)
+			pattern: (snowball [item|break|particle]|snow shovel|snow(man| golem) spawn)
 		snowball: # for versions below 1.20.5
 			name: snowball break @-
 			pattern: snowball break
 		snow_shovel: # for versions below 1.20.5
 			name: snow shovel @-
-			pattern: (snowball|snow shovel|snow(man| golem) spawn)
+			pattern: (snowball [item|particle]|snow shovel|snow(man| golem) spawn)
 
 		landing_honey: # added in 1.15
 			name: landing honey @-
@@ -1808,7 +1808,7 @@ visual effects:
 
 		mycelium: # previously town_aura, changed in 1.20.5
 			name: mycelium @-
-			pattern: (mycelium|small smoke|town aura)
+			pattern: (mycelium [particle]|small smoke|town aura)
 		town_aura:
 			name: small smoke @-
 			pattern: (mycelium|small smoke|town aura)
@@ -1931,10 +1931,10 @@ visual effects:
 
 		totem_of_undying: # added in 1.20.5
 			name: totem of undying @a
-			pattern: totem [of undying]
+			pattern: totem [of undying] [particle]
 		totem: # for versions below 1.20.5
 			name: totem @a
-			pattern: totem [of undying]
+			pattern: totem [of undying] [particle]
 
 		trial omen: # added in 1.20.5 (for 1.21)
 			name: trial omen @a
@@ -1989,10 +1989,10 @@ visual effects:
 
 		witch: # added in 1.20.5
 			name: witch @a
-			pattern: (witch [magic|spell]|purple spark)
+			pattern: (witch (magic|spell|particle)|purple spark)
 		spell_witch: # for versions below 1.20.5
 			name: witch spell @a
-			pattern: (witch [magic|spell]|purple spark)
+			pattern: (witch (magic|spell|particle)|purple spark)
 
 # -- Inventory Actions --
 inventory actions:
diff --git a/src/test/skript/tests/regressions/pull-6760-particle itemtype conflicts.sk b/src/test/skript/tests/regressions/pull-6760-particle itemtype conflicts.sk
new file mode 100644
index 00000000000..d4cac535c18
--- /dev/null
+++ b/src/test/skript/tests/regressions/pull-6760-particle itemtype conflicts.sk	
@@ -0,0 +1,5 @@
+test "particle itemtype conflicts":
+
+	# itemtype parsing should take priority over visual effects
+	assert totem of undying is an itemtype with "totem of undying is not an itemtype"
+	assert mycelium is an itemtype with "mycelium is not an itemtype"
diff --git a/src/test/skript/tests/syntaxes/effects/EffVisualEffect.sk b/src/test/skript/tests/syntaxes/effects/EffVisualEffect.sk
index b8631e79cf2..a4791d1752a 100644
--- a/src/test/skript/tests/syntaxes/effects/EffVisualEffect.sk
+++ b/src/test/skript/tests/syntaxes/effects/EffVisualEffect.sk
@@ -16,7 +16,7 @@ test "visual effects":
 	play dripping water at {_}
 	play white dust with size 2 at {_}
 	play effect at {_}
-	play elder guardian at {_}
+	play elder guardian particle at {_}
 	play enchant at {_}
 	play enchanted hit at {_}
 	play end rod at {_}
@@ -26,7 +26,7 @@ test "visual effects":
 	play large explosion at {_}
 	play explosion emitter at {_}
 	play falling dust of air at {_}
-	play firework at {_}
+	play firework spark at {_}
 	play fishing at {_}
 	play flame at {_}
 	play happy villager at {_}
@@ -51,7 +51,7 @@ test "visual effects":
 	play totem of undying at {_}
 	play suspended at {_}
 	play void fog at {_}
-	play witch at {_}
+	play witch particle at {_}
 	parse if running minecraft "1.14.4":
 		play campfire cosy smoke at {_}
 		play campfire signal smoke at {_}

From 2627c950d1734e45c5ad8e366ee2161fd44fba32 Mon Sep 17 00:00:00 2001
From: Shane Bee <shanebolenback@me.com>
Date: Sat, 15 Jun 2024 10:42:35 -0700
Subject: [PATCH 4/6] ExprStringCase - include expression in toString (#6777)

---
 .../skript/expressions/ExprStringCase.java    | 22 ++++++++++++-------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/main/java/ch/njol/skript/expressions/ExprStringCase.java b/src/main/java/ch/njol/skript/expressions/ExprStringCase.java
index af963a333af..7a21357dca8 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprStringCase.java
+++ b/src/main/java/ch/njol/skript/expressions/ExprStringCase.java
@@ -153,22 +153,28 @@ public Class<? extends String> getReturnType() {
 	}
 
 	@Override
-	public String toString(@Nullable Event e, boolean debug) {
+	public String toString(@Nullable Event event, boolean debug) {
+		String mode = "";
 		switch (type) {
 			case 0: // Basic Case Change 
-				return (casemode == 1) ? "uppercase" : "lowercase";
+				mode = (casemode == 1) ? "uppercase" : "lowercase";
+				break;
 			case 1: // Proper Case 
-				return ((casemode == 3) ? "strict" : "lenient") + " proper case";
+				mode = ((casemode == 3) ? "strict" : "lenient") + " proper case";
+				break;
 			case 2: // Camel Case 
-				return ((casemode == 3) ? "strict" : "lenient") + " camel case";
+				mode = ((casemode == 3) ? "strict" : "lenient") + " camel case";
+				break;
 			case 3: // Pascal Case 
-				return ((casemode == 3) ? "strict" : "lenient") + " pascal case";
+				mode = ((casemode == 3) ? "strict" : "lenient") + " pascal case";
+				break;
 			case 4: // Snake Case 
-				return ((casemode == 0) ? "" : ((casemode == 1)) ? "upper " : "lower ") + "snake case";
+				mode = ((casemode == 0) ? "" : ((casemode == 1)) ? "upper " : "lower ") + "snake case";
+				break;
 			case 5: // Kebab Case 
-				return ((casemode == 0) ? "" : ((casemode == 1)) ? "upper " : "lower ") + "kebab case";
+				mode = ((casemode == 0) ? "" : ((casemode == 1)) ? "upper " : "lower ") + "kebab case";
 		}
-		return ""; // Shouldn't reach here anyways 
+		return mode + " " + expr.toString(event, debug);
 	}
 	
 	@SuppressWarnings("null")

From c6b0bfa71179259a1c21f735588c02548d8d4d8d Mon Sep 17 00:00:00 2001
From: Patrick Miller <apickledwalrus@gmail.com>
Date: Sat, 15 Jun 2024 14:06:55 -0400
Subject: [PATCH 5/6] Fix firework spawning (#6764)

---
 .../njol/skript/entity/SimpleEntityData.java  | 36 ++++++++++++++-----
 .../regressions/6762-cant spawn a firework.sk |  4 +++
 2 files changed, 31 insertions(+), 9 deletions(-)
 create mode 100644 src/test/skript/tests/regressions/6762-cant spawn a firework.sk

diff --git a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java
index 6cad5ec1a2c..504c4449dc7 100644
--- a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java
+++ b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java
@@ -23,6 +23,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import ch.njol.util.Kleenean;
+import org.bukkit.World;
 import org.bukkit.entity.AbstractHorse;
 import org.bukkit.entity.Allay;
 import org.bukkit.entity.Animals;
@@ -155,15 +157,13 @@ public final static class SimpleEntityDataInfo {
 		final String codeName;
 		final Class<? extends Entity> c;
 		final boolean isSupertype;
+		final Kleenean allowSpawning;
 		
-		SimpleEntityDataInfo(final String codeName, final Class<? extends Entity> c) {
-			this(codeName, c, false);
-		}
-		
-		SimpleEntityDataInfo(final String codeName, final Class<? extends Entity> c, final boolean isSupertype) {
+		SimpleEntityDataInfo(String codeName, Class<? extends Entity> c, boolean isSupertype, Kleenean allowSpawning) {
 			this.codeName = codeName;
 			this.c = c;
 			this.isSupertype = isSupertype;
+			this.allowSpawning = allowSpawning;
 		}
 		
 		@Override
@@ -191,11 +191,18 @@ public boolean equals(final @Nullable Object obj) {
 	private final static List<SimpleEntityDataInfo> types = new ArrayList<>();
 
 	private static void addSimpleEntity(String codeName, Class<? extends Entity> entityClass) {
-		types.add(new SimpleEntityDataInfo(codeName, entityClass));
+		addSimpleEntity(codeName, entityClass, Kleenean.UNKNOWN);
+	}
+
+	/**
+	 * @param allowSpawning Whether to override the default {@link #canSpawn(World)} behavior and allow this entity to be spawned.
+	 */
+	private static void addSimpleEntity(String codeName, Class<? extends Entity> entityClass, Kleenean allowSpawning) {
+		types.add(new SimpleEntityDataInfo(codeName, entityClass, false, allowSpawning));
 	}
 
 	private static void addSuperEntity(String codeName, Class<? extends Entity> entityClass) {
-		types.add(new SimpleEntityDataInfo(codeName, entityClass, true));
+		types.add(new SimpleEntityDataInfo(codeName, entityClass, true, Kleenean.UNKNOWN));
 	}
 	static {
 		// Simple Entities
@@ -238,7 +245,9 @@ private static void addSuperEntity(String codeName, Class<? extends Entity> enti
 		addSimpleEntity("witch", Witch.class);
 		addSimpleEntity("wither", Wither.class);
 		addSimpleEntity("wither skull", WitherSkull.class);
-		addSimpleEntity("firework", Firework.class);
+		// bukkit marks fireworks as not spawnable
+		// see https://hub.spigotmc.org/jira/browse/SPIGOT-7677
+		addSimpleEntity("firework", Firework.class, Kleenean.TRUE);
 		addSimpleEntity("endermite", Endermite.class);
 		addSimpleEntity("armor stand", ArmorStand.class);
 		addSimpleEntity("shulker", Shulker.class);
@@ -449,7 +458,16 @@ protected boolean equals_i(final EntityData<?> obj) {
 		final SimpleEntityData other = (SimpleEntityData) obj;
 		return info.equals(other.info);
 	}
-	
+
+	@Override
+	public boolean canSpawn(@Nullable World world) {
+		if (info.allowSpawning.isUnknown()) // unspecified, refer to default behavior
+			return super.canSpawn(world);
+		if (world == null)
+			return false;
+		return info.allowSpawning.isTrue();
+	}
+
 	@Override
 	public Fields serialize() throws NotSerializableException {
 		final Fields f = super.serialize();
diff --git a/src/test/skript/tests/regressions/6762-cant spawn a firework.sk b/src/test/skript/tests/regressions/6762-cant spawn a firework.sk
new file mode 100644
index 00000000000..f272e0bc8e0
--- /dev/null
+++ b/src/test/skript/tests/regressions/6762-cant spawn a firework.sk	
@@ -0,0 +1,4 @@
+test "can't spawn a firework":
+
+	spawn a firework at spawn of world "world"
+	assert last spawned firework is set with "firework did not spawn"

From 7fc699e17299763523942d99524216480d426295 Mon Sep 17 00:00:00 2001
From: APickledWalrus <apickledwalrus@gmail.com>
Date: Sat, 15 Jun 2024 14:40:33 -0400
Subject: [PATCH 6/6] Prepare For Release (2.8.7)

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 0b5b23f30d5..f78ae1766eb 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,7 +5,7 @@ org.gradle.parallel=true
 
 groupid=ch.njol
 name=skript
-version=2.8.6
+version=2.8.7
 jarName=Skript.jar
 testEnv=java21/paper-1.20.6
 testEnvJavaVersion=21