diff --git a/patches/api/Add-Material-Tags.patch b/patches/api/Add-Material-Tags.patch
index 76ece994a5..ca9d4592c5 100644
--- a/patches/api/Add-Material-Tags.patch
+++ b/patches/api/Add-Material-Tags.patch
@@ -1146,17 +1146,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import io.papermc.paper.tag.BaseTag;
 +import io.papermc.paper.tag.EntityTags;
-+import org.bukkit.Bukkit;
-+import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
-+
 +import java.lang.reflect.Field;
 +import java.lang.reflect.Modifier;
 +import java.util.HashSet;
 +import java.util.Set;
 +import java.util.logging.Level;
++import org.bukkit.Bukkit;
++import org.bukkit.support.AbstractTestingBase;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class MaterialTagsTest extends AbstractTestingBase {
 +
@@ -1179,7 +1178,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    private static void testLocked(Class<?> clazz) {
 +        for (BaseTag<?, ?> tag : collectTags(clazz)) {
-+            assertTrue("Tag " + tag.key() + " is not locked", tag.isLocked());
++            assertTrue(tag.isLocked(), "Tag " + tag.key() + " is not locked");
 +        }
 +    }
 +
@@ -1209,7 +1208,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.logging.Level;
 +import org.bukkit.Bukkit;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
 +public class EntityTagsTest extends AbstractTestingBase {
 +
diff --git a/patches/api/Add-Tick-TemporalUnit.patch b/patches/api/Add-Tick-TemporalUnit.patch
index e5d3ae790d..026a2bd8f0 100644
--- a/patches/api/Add-Tick-TemporalUnit.patch
+++ b/patches/api/Add-Tick-TemporalUnit.patch
@@ -116,10 +116,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.time.Duration;
 +import java.time.Instant;
 +import java.time.temporal.ChronoUnit;
++import org.junit.jupiter.api.Test;
 +
-+import org.junit.Test;
-+
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
 +public class TickTest {
 +
diff --git a/patches/api/Add-missing-effects.patch b/patches/api/Add-missing-effects.patch
index ee39d152d1..3305386976 100644
--- a/patches/api/Add-missing-effects.patch
+++ b/patches/api/Add-missing-effects.patch
@@ -212,8 +212,8 @@ diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/test/java/org/bukkit/EffectTest.java
 +++ b/src/test/java/org/bukkit/EffectTest.java
-@@ -0,0 +0,0 @@ import static org.junit.Assert.*;
- import org.junit.Test;
+@@ -0,0 +0,0 @@ import static org.hamcrest.CoreMatchers.*;
+ import org.junit.jupiter.api.Test;
  
  public class EffectTest {
 +    private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(); // Paper
diff --git a/patches/api/Adventure.patch b/patches/api/Adventure.patch
index df2b50054c..3512bf3ca4 100644
--- a/patches/api/Adventure.patch
+++ b/patches/api/Adventure.patch
@@ -4992,10 +4992,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.Set;
 +import net.kyori.adventure.key.Key;
 +import org.bukkit.NamespacedKey;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class KeyTest {
 +
diff --git a/patches/api/Build-system-changes.patch b/patches/api/Build-system-changes.patch
index dbe5f5e85d..58539e82d1 100644
--- a/patches/api/Build-system-changes.patch
+++ b/patches/api/Build-system-changes.patch
@@ -35,8 +35,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    // Paper end
 +
      testImplementation("org.apache.commons:commons-lang3:3.12.0")
-     testImplementation("junit:junit:4.13.2")
-     testImplementation("org.hamcrest:hamcrest-library:1.3")
+     testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
+     testImplementation("org.hamcrest:hamcrest:2.2")
 @@ -0,0 +0,0 @@ tasks.withType<Javadoc> {
      options.links(
          "https://guava.dev/releases/32.1.2-jre/api/docs/",
diff --git a/patches/api/Convert-project-to-Gradle.patch b/patches/api/Convert-project-to-Gradle.patch
index edd89049a7..5ee7d1a521 100644
--- a/patches/api/Convert-project-to-Gradle.patch
+++ b/patches/api/Convert-project-to-Gradle.patch
@@ -61,8 +61,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    testCompileOnly(annotations)
 +
 +    testImplementation("org.apache.commons:commons-lang3:3.12.0")
-+    testImplementation("junit:junit:4.13.2")
-+    testImplementation("org.hamcrest:hamcrest-library:1.3")
++    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
++    testImplementation("org.hamcrest:hamcrest:2.2")
 +    testImplementation("org.mockito:mockito-core:5.5.0")
 +    testImplementation("org.ow2.asm:asm-tree:9.5")
 +}
@@ -219,15 +219,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -        </dependency>
 -        <!-- testing -->
 -        <dependency>
--            <groupId>junit</groupId>
--            <artifactId>junit</artifactId>
--            <version>4.13.2</version>
+-            <groupId>org.junit.jupiter</groupId>
+-            <artifactId>junit-jupiter</artifactId>
+-            <version>5.10.0</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.hamcrest</groupId>
--            <artifactId>hamcrest-library</artifactId>
--            <version>1.3</version>
+-            <artifactId>hamcrest</artifactId>
+-            <version>2.2</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
@@ -339,6 +339,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -                    </tags>
 -                </configuration>
 -            </plugin>
+-            <plugin>
+-                <groupId>org.apache.maven.plugins</groupId>
+-                <artifactId>maven-surefire-plugin</artifactId>
+-                <version>3.1.0</version>
+-            </plugin>
 -        </plugins>
 -    </build>
 -
diff --git a/patches/api/Fix-Spigot-annotation-mistakes.patch b/patches/api/Fix-Spigot-annotation-mistakes.patch
index e89b82fc4d..bb63105b0a 100644
--- a/patches/api/Fix-Spigot-annotation-mistakes.patch
+++ b/patches/api/Fix-Spigot-annotation-mistakes.patch
@@ -1270,7 +1270,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/test/java/org/bukkit/materials/MaterialDataTest.java
 @@ -0,0 +0,0 @@ import org.bukkit.material.WoodenStep;
  import org.bukkit.material.types.MushroomBlockTexture;
- import org.junit.Test;
+ import org.junit.jupiter.api.Test;
  
 +@Deprecated // Paper
  public class MaterialDataTest {
diff --git a/patches/api/Paper-Plugins.patch b/patches/api/Paper-Plugins.patch
index 5005d5013d..144401fd46 100644
--- a/patches/api/Paper-Plugins.patch
+++ b/patches/api/Paper-Plugins.patch
@@ -2284,14 +2284,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@
 -package org.bukkit.event;
 -
+-import static org.junit.jupiter.api.Assertions.*;
 -import org.bukkit.Bukkit;
 -import org.bukkit.plugin.PluginLoader;
 -import org.bukkit.plugin.SimplePluginManager;
 -import org.bukkit.plugin.TestPlugin;
 -import org.bukkit.plugin.java.JavaPluginLoader;
 -import org.bukkit.support.AbstractTestingBase;
--import org.junit.Assert;
--import org.junit.Test;
+-import org.junit.jupiter.api.Test;
 -
 -public class SyntheticEventTest extends AbstractTestingBase {
 -    @SuppressWarnings("deprecation")
@@ -2312,7 +2312,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -        pluginManager.registerEvents(impl, plugin);
 -        pluginManager.callEvent(event);
 -
--        Assert.assertEquals(1, impl.callCount);
+-        assertEquals(1, impl.callCount);
 -    }
 -
 -    public abstract static class Base<E extends Event> implements Listener {
@@ -2339,15 +2339,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@
 -package org.bukkit.plugin;
 -
+-import static org.bukkit.support.MatcherAssert.*;
 -import static org.hamcrest.Matchers.*;
--import static org.junit.Assert.*;
 -import org.bukkit.Bukkit;
 -import org.bukkit.event.Event;
 -import org.bukkit.event.TestEvent;
 -import org.bukkit.permissions.Permission;
 -import org.bukkit.support.AbstractTestingBase;
--import org.junit.After;
--import org.junit.Test;
+-import org.junit.jupiter.api.AfterEach;
+-import org.junit.jupiter.api.Test;
 -
 -public class PluginManagerTest extends AbstractTestingBase {
 -    private class MutableObject {
@@ -2503,20 +2503,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -    private void testRemovePermissionByName(final String name) {
 -        final Permission perm = new Permission(name);
 -        pm.addPermission(perm);
--        assertThat("Permission \"" + name + "\" was not added", pm.getPermission(name), is(perm));
+-        assertThat(pm.getPermission(name), is(perm), "Permission \"" + name + "\" was not added");
 -        pm.removePermission(name);
--        assertThat("Permission \"" + name + "\" was not removed", pm.getPermission(name), is(nullValue()));
+-        assertThat(pm.getPermission(name), is(nullValue()), "Permission \"" + name + "\" was not removed");
 -    }
 -
 -    private void testRemovePermissionByPermission(final String name) {
 -        final Permission perm = new Permission(name);
 -        pm.addPermission(perm);
--        assertThat("Permission \"" + name + "\" was not added", pm.getPermission(name), is(perm));
+-        assertThat(pm.getPermission(name), is(perm), "Permission \"" + name + "\" was not added");
 -        pm.removePermission(perm);
--        assertThat("Permission \"" + name + "\" was not removed", pm.getPermission(name), is(nullValue()));
+-        assertThat(pm.getPermission(name), is(nullValue()), "Permission \"" + name + "\" was not removed");
 -    }
 -
--    @After
+-    @AfterEach
 -    public void tearDown() {
 -        pm.clearPlugins();
 -        assertThat(pm.getPermissions(), is(empty()));
diff --git a/patches/api/Test-changes.patch b/patches/api/Test-changes.patch
index 9e1db3548c..bef542d982 100644
--- a/patches/api/Test-changes.patch
+++ b/patches/api/Test-changes.patch
@@ -146,8 +146,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            builder.append("\t").append(message).append("\n");
          }
  
--        Assert.fail("There " + errors.size() + " are missing annotation(s)");
-+        Assert.fail(builder.toString());
+-        fail("There " + errors.size() + " are missing annotation(s)");
++        fail(builder.toString());
      }
  
      private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException {
@@ -208,14 +208,14 @@ diff --git a/src/test/java/org/bukkit/BukkitMirrorTest.java b/src/test/java/org/
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/test/java/org/bukkit/BukkitMirrorTest.java
 +++ b/src/test/java/org/bukkit/BukkitMirrorTest.java
-@@ -0,0 +0,0 @@ public class BukkitMirrorTest {
+@@ -0,0 +0,0 @@ import org.junit.jupiter.params.provider.MethodSource;
+ public class BukkitMirrorTest {
  
-     @Parameters(name = "{index}: {1}")
-     public static List<Object[]> data() {
-+        if (true) return List.of(); // Paper
-         return Lists.transform(Arrays.asList(Server.class.getDeclaredMethods()), new Function<Method, Object[]>() {
-             @Override
-             public Object[] apply(Method input) {
+     public static Stream<Arguments> data() {
++        if (true) return Stream.of(); // Paper
+         return Stream.of(Server.class.getDeclaredMethods())
+                 .map(method -> {
+                     try {
 diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/test/java/org/bukkit/support/TestServer.java
diff --git a/patches/server/API-to-get-a-BlockState-without-a-snapshot.patch b/patches/server/API-to-get-a-BlockState-without-a-snapshot.patch
index f6211c960e..97716b7760 100644
--- a/patches/server/API-to-get-a-BlockState-without-a-snapshot.patch
+++ b/patches/server/API-to-get-a-BlockState-without-a-snapshot.patch
@@ -153,8 +153,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
 +++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
 @@ -0,0 +0,0 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
-     public Map<String, Object> serialize() {
-         return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(this.toTagCompound());
+     public String serialize() {
+         return CraftNBTTagConfigSerializer.serialize(this.toTagCompound());
      }
 +
 +    // Paper start
diff --git a/patches/server/Add-PlayerArmorChangeEvent.patch b/patches/server/Add-PlayerArmorChangeEvent.patch
index 71214f825b..22f3a9c6c7 100644
--- a/patches/server/Add-PlayerArmorChangeEvent.patch
+++ b/patches/server/Add-PlayerArmorChangeEvent.patch
@@ -40,6 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
 +import java.util.ArrayList;
 +import java.util.List;
++import java.util.stream.Stream;
 +import net.minecraft.world.entity.EquipmentSlot;
 +import net.minecraft.world.item.Equipable;
 +import net.minecraft.world.item.Item;
@@ -47,45 +48,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.Material;
 +import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.MethodSource;
 +
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
 +
-+@RunWith(Parameterized.class)
 +public class ExtraArmorSlotTypeMaterialTest extends AbstractTestingBase {
 +
-+    @Parameterized.Parameter(0)
-+    public PlayerArmorChangeEvent.SlotType slotType;
-+
-+    @Parameterized.Parameter(1)
-+    public Material item;
-+
-+    @Parameterized.Parameters(name = "{0}: {1}")
-+    public static Iterable<Object[]> parameters() {
++    @MethodSource("parameters")
++    public static Stream<Object[]> parameters() {
 +        final List<Object[]> parameters = new ArrayList<>();
 +        for (final PlayerArmorChangeEvent.SlotType slotType : PlayerArmorChangeEvent.SlotType.values()) {
 +            for (final Material item : slotType.getTypes()) {
 +                parameters.add(new Object[]{ slotType, item });
 +            }
 +        }
-+        return parameters;
++        return parameters.stream();
 +    }
 +
-+    @Test
-+    public void test() {
-+        final Item nmsItem = CraftMagicNumbers.getItem(this.item);
++    @ParameterizedTest
++    @MethodSource("parameters")
++    public void test(PlayerArmorChangeEvent.SlotType slotType, Material item) {
++        final Item nmsItem = CraftMagicNumbers.getItem(item);
 +        final Equipable equipable = Equipable.get(new ItemStack(nmsItem));
-+        assertNotNull(this.item + " isn't equipable", equipable);
-+        final EquipmentSlot slot = switch (this.slotType) {
++        assertNotNull(equipable, item + " isn't equipable");
++        final EquipmentSlot slot = switch (slotType) {
 +            case HEAD -> EquipmentSlot.HEAD;
 +            case CHEST -> EquipmentSlot.CHEST;
 +            case LEGS -> EquipmentSlot.LEGS;
 +            case FEET -> EquipmentSlot.FEET;
 +        };
-+        assertEquals(this.item + " isn't set to the right slot", equipable.getEquipmentSlot(), slot);
++        assertEquals(equipable.getEquipmentSlot(), slot, item + " isn't set to the right slot");
 +    }
 +}
 diff --git a/src/test/java/io/papermc/paper/inventory/item/MissingArmorSlotTypeMaterialTest.java b/src/test/java/io/papermc/paper/inventory/item/MissingArmorSlotTypeMaterialTest.java
@@ -99,6 +93,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
 +import java.util.ArrayList;
 +import java.util.List;
++import java.util.stream.Stream;
 +import net.minecraft.core.registries.BuiltInRegistries;
 +import net.minecraft.world.entity.EquipmentSlot;
 +import net.minecraft.world.item.Equipable;
@@ -106,39 +101,32 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.minecraft.world.item.ItemStack;
 +import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.MethodSource;
 +
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +/**
 + * Test for {@link com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType}
 + */
-+@RunWith(Parameterized.class)
 +public class MissingArmorSlotTypeMaterialTest extends AbstractTestingBase {
 +
-+    @Parameterized.Parameter(0)
-+    public Equipable equipable;
-+
-+    @Parameterized.Parameter(1)
-+    public Item item;
-+
-+    @Parameterized.Parameters(name = "{1}")
-+    public static Iterable<Object[]> parameters() {
++    @MethodSource("parameters")
++    public static Stream<Object[]> parameters() {
 +        final List<Object[]> parameters = new ArrayList<>();
 +        for (final Item item : BuiltInRegistries.ITEM) {
 +            final Equipable equipable = Equipable.get(new ItemStack(item));
 +            if (equipable != null) {
-+                parameters.add(new Object[]{ equipable, item });
++                parameters.add(new Object[]{equipable, item});
 +            }
 +        }
-+        return parameters;
++        return parameters.stream();
 +    }
 +
-+    @Test
-+    public void test() {
-+        final EquipmentSlot equipmentSlot = this.equipable.getEquipmentSlot();
++    @ParameterizedTest
++    @MethodSource("parameters")
++    public void test(Equipable equipable, Item item) {
++        final EquipmentSlot equipmentSlot = equipable.getEquipmentSlot();
 +        PlayerArmorChangeEvent.SlotType slotType = switch (equipmentSlot) {
 +            case HEAD -> PlayerArmorChangeEvent.SlotType.HEAD;
 +            case CHEST -> PlayerArmorChangeEvent.SlotType.CHEST;
@@ -147,7 +135,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            default -> null;
 +        };
 +        if (slotType != null) {
-+            assertTrue("SlotType " + slotType + " doesn't include " + this.item, slotType.getTypes().contains(CraftMagicNumbers.getMaterial(this.item)));
++            assertTrue(slotType.getTypes().contains(CraftMagicNumbers.getMaterial(item)), "SlotType " + slotType + " doesn't include " + item);
 +        }
 +    }
 +}
diff --git a/patches/server/Add-StructuresLocateEvent.patch b/patches/server/Add-StructuresLocateEvent.patch
index bb6c012045..d379cbfb76 100644
--- a/patches/server/Add-StructuresLocateEvent.patch
+++ b/patches/server/Add-StructuresLocateEvent.patch
@@ -110,9 +110,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.NamespacedKey;
 +import org.bukkit.craftbukkit.util.CraftNamespacedKey;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.AfterClass;
-+import org.junit.BeforeClass;
-+import org.junit.Test;
++import org.junit.jupiter.api.AfterAll;
++import org.junit.jupiter.api.BeforeAll;
++import org.junit.jupiter.api.Test;
 +
 +import java.io.PrintStream;
 +import java.lang.reflect.Field;
@@ -121,9 +121,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.Map;
 +import java.util.StringJoiner;
 +
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertNotNull;
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +@Deprecated(forRemoval = true)
 +public class ConfiguredStructureTest extends AbstractTestingBase {
@@ -133,7 +133,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    private static PrintStream out;
 +
-+    @BeforeClass
++    @BeforeAll
 +    public static void collectStructures() throws ReflectiveOperationException {
 +        out = System.out;
 +        System.setOut(Bootstrap.STDOUT);
@@ -153,12 +153,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    @Test
 +    public void testMinecraftToApi() {
 +        Registry<Structure> structureRegistry = AbstractTestingBase.REGISTRY_CUSTOM.registryOrThrow(Registries.STRUCTURE);
-+        assertEquals("configured structure maps should be the same size", BUILT_IN_STRUCTURES.size(), structureRegistry.size());
++        assertEquals(BUILT_IN_STRUCTURES.size(), structureRegistry.size(), "configured structure maps should be the same size");
 +
 +        Map<ResourceLocation, Structure> missing = new LinkedHashMap<>();
 +        for (Structure feature : structureRegistry) {
 +            final ResourceLocation key = structureRegistry.getKey(feature);
-+            assertNotNull("Missing built-in registry key", key);
++            assertNotNull(key, "Missing built-in registry key");
 +            if (key.equals(BuiltinStructures.ANCIENT_CITY.location()) || key.equals(BuiltinStructures.TRAIL_RUINS.location())) {
 +                continue; // TODO remove when upstream adds "jigsaw" StructureType
 +            }
@@ -167,14 +167,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            }
 +        }
 +
-+        assertTrue(printMissing(missing), missing.isEmpty());
++        assertTrue(missing.isEmpty(), printMissing(missing));
 +    }
 +
 +    @Test
 +    public void testApiToMinecraft() {
 +        Registry<Structure> structureRegistry = AbstractTestingBase.REGISTRY_CUSTOM.registryOrThrow(Registries.STRUCTURE);
 +        for (NamespacedKey apiKey : DEFAULT_CONFIGURED_STRUCTURES.keySet()) {
-+            assertTrue(apiKey + " does not have a minecraft counterpart", structureRegistry.containsKey(CraftNamespacedKey.toMinecraft(apiKey)));
++            assertTrue(structureRegistry.containsKey(CraftNamespacedKey.toMinecraft(apiKey)), apiKey + " does not have a minecraft counterpart");
 +        }
 +    }
 +
@@ -188,7 +188,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        return joiner.toString();
 +    }
 +
-+    @AfterClass
++    @AfterAll
 +    public static void after() {
 +        System.setOut(out);
 +    }
diff --git a/patches/server/Add-methods-to-get-translation-keys.patch b/patches/server/Add-methods-to-get-translation-keys.patch
index 565751466b..38fb028ab0 100644
--- a/patches/server/Add-methods-to-get-translation-keys.patch
+++ b/patches/server/Add-methods-to-get-translation-keys.patch
@@ -64,9 +64,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.attribute.Attribute;
 +import org.bukkit.craftbukkit.util.CraftNamespacedKey;
 +import org.bukkit.support.AbstractTestingBase;
- import org.junit.Assert;
-+import org.junit.Ignore;
- import org.junit.Test;
+ import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Disabled;
+ import org.junit.jupiter.api.Test;
  
 -public class TranslationKeyTest {
 +public class TranslationKeyTest extends AbstractTestingBase {
@@ -74,44 +74,44 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      @Test
      public void testChatVisibilityKeys() {
 @@ -0,0 +0,0 @@ public class TranslationKeyTest {
-             Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
+             Assertions.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
          }
      }
 +
 +    @Test
 +    public void testDifficultyKeys() {
 +        for (Difficulty bukkitDifficulty : Difficulty.values()) {
-+            Assert.assertEquals(bukkitDifficulty + "'s translation key doesn't match", ((TranslatableContents) net.minecraft.world.Difficulty.byId(bukkitDifficulty.ordinal()).getDisplayName().getContents()).getKey(), bukkitDifficulty.translationKey());
++            Assertions.assertEquals(bukkitDifficulty + "'s translation key doesn't match", ((TranslatableContents) net.minecraft.world.Difficulty.byId(bukkitDifficulty.ordinal()).getDisplayName().getContents()).getKey(), bukkitDifficulty.translationKey());
 +        }
 +    }
 +
 +    @Test
 +    public void testGameruleKeys() {
 +        for (GameRule<?> rule : GameRule.values()) {
-+            Assert.assertEquals(rule.getName() + "'s translation doesn't match", org.bukkit.craftbukkit.CraftWorld.getGameRulesNMS().get(rule.getName()).getDescriptionId(), rule.translationKey());
++            Assertions.assertEquals(rule.getName() + "'s translation doesn't match", org.bukkit.craftbukkit.CraftWorld.getGameRulesNMS().get(rule.getName()).getDescriptionId(), rule.translationKey());
 +        }
 +    }
 +
 +    @Test
 +    public void testAttributeKeys() {
 +        for (Attribute attribute : Attribute.values()) {
-+            Assert.assertEquals("translation key mismatch for " + attribute, org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraft(attribute).getDescriptionId(), attribute.translationKey());
++            Assertions.assertEquals("translation key mismatch for " + attribute, org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraft(attribute).getDescriptionId(), attribute.translationKey());
 +        }
 +    }
 +
 +    @Test
 +    public void testFireworkEffectType() {
 +        for (FireworkEffect.Type type : FireworkEffect.Type.values()) {
-+            Assert.assertEquals("translation key mismatch for " + type, net.minecraft.world.item.FireworkRocketItem.Shape.byId(org.bukkit.craftbukkit.inventory.CraftMetaFirework.getNBT(type)).getName(), org.bukkit.FireworkEffect.Type.NAMES.key(type));
++            Assertions.assertEquals("translation key mismatch for " + type, net.minecraft.world.item.FireworkRocketItem.Shape.byId(org.bukkit.craftbukkit.inventory.CraftMetaFirework.getNBT(type)).getName(), org.bukkit.FireworkEffect.Type.NAMES.key(type));
 +        }
 +    }
 +
 +    @Test
-+    @Ignore // TODO fix
++    @Disabled // TODO fix
 +    public void testCreativeCategory() {
 +        // for (CreativeModeTab tab : CreativeModeTabs.tabs()) {
 +        //     CreativeCategory category = Objects.requireNonNull(CraftCreativeCategory.fromNMS(tab));
-+        //     Assert.assertEquals("translation key mismatch for " + category, ((TranslatableContents) tab.getDisplayName().getContents()).getKey(), category.translationKey());
++        //     Assertions.assertEquals("translation key mismatch for " + category, ((TranslatableContents) tab.getDisplayName().getContents()).getKey(), category.translationKey());
 +        // }
 +    }
 +
@@ -119,8 +119,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testGameMode() {
 +        for (GameType nms : GameType.values()) {
 +            GameMode bukkit = GameMode.getByValue(nms.getId());
-+            Assert.assertNotNull(bukkit);
-+            Assert.assertEquals("translation key mismatch for " + bukkit, ((TranslatableContents) nms.getLongDisplayName().getContents()).getKey(), bukkit.translationKey());
++            Assertions.assertNotNull(bukkit);
++            Assertions.assertEquals("translation key mismatch for " + bukkit, ((TranslatableContents) nms.getLongDisplayName().getContents()).getKey(), bukkit.translationKey());
 +        }
 +    }
 +
@@ -128,7 +128,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testBiome() {
 +        for (Map.Entry<ResourceKey<Biome>, Biome> nms : AbstractTestingBase.BIOMES.entrySet()) {
 +            org.bukkit.block.Biome bukkit = org.bukkit.block.Biome.valueOf(nms.getKey().location().getPath().toUpperCase());
-+            Assert.assertEquals("translation key mismatch for " + bukkit, nms.getKey().location().toLanguageKey("biome"), bukkit.translationKey());
++            Assertions.assertEquals("translation key mismatch for " + bukkit, nms.getKey().location().toLanguageKey("biome"), bukkit.translationKey());
 +        }
 +    }
 +
@@ -136,8 +136,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testMusicInstrument() {
 +        for (final ResourceLocation nms : BuiltInRegistries.INSTRUMENT.keySet()) {
 +            final MusicInstrument bukkit = MusicInstrument.getByKey(CraftNamespacedKey.fromMinecraft(nms));
-+            Assert.assertNotNull("Missing bukkit instrument for " + nms, bukkit);
-+            Assert.assertEquals("translation key mismatch for " + bukkit, nms.toLanguageKey("instrument"), bukkit.translationKey());
++            Assertions.assertNotNull(bukkit, "Missing bukkit instrument for " + nms);
++            Assertions.assertEquals("translation key mismatch for " + bukkit, nms.toLanguageKey("instrument"), bukkit.translationKey());
 +        }
 +    }
  }
diff --git a/patches/server/Add-missing-structure-set-seed-configs.patch b/patches/server/Add-missing-structure-set-seed-configs.patch
index 9fae4091c2..04517c6500 100644
--- a/patches/server/Add-missing-structure-set-seed-configs.patch
+++ b/patches/server/Add-missing-structure-set-seed-configs.patch
@@ -288,11 +288,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.configuration.file.YamlConfiguration;
 +import org.bukkit.support.AbstractTestingBase;
 +import org.jetbrains.annotations.NotNull;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +import org.spigotmc.SpigotConfig;
 +import org.spigotmc.SpigotWorldConfig;
 +
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
 +public class StructureSeedConfigTest extends AbstractTestingBase {
 +
@@ -340,10 +340,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                final Field field = StructurePlacement.class.getDeclaredField("HIGHLY_ARBITRARY_RANDOM_SALT");
 +                field.trySetAccessible();
 +                assertEquals(0, set.placement().salt);
-+                assertEquals("Mismatched default seed for " + setKey + ". Should be " + field.get(null), field.get(null), salt);
++                assertEquals(field.get(null), salt, "Mismatched default seed for " + setKey + ". Should be " + field.get(null));
 +                continue;
 +            }
-+            assertEquals("Mismatched default seed for " + setKey + ". Should be " + set.placement().salt, set.placement().salt, salt);
++            assertEquals(set.placement().salt, salt, "Mismatched default seed for " + setKey + ". Should be " + set.placement().salt);
 +        }
 +    }
 +}
diff --git a/patches/server/Add-missing-team-sidebar-display-slots.patch b/patches/server/Add-missing-team-sidebar-display-slots.patch
index 1a6b8c6a95..fc42310d39 100644
--- a/patches/server/Add-missing-team-sidebar-display-slots.patch
+++ b/patches/server/Add-missing-team-sidebar-display-slots.patch
@@ -80,9 +80,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import org.bukkit.craftbukkit.scoreboard.CraftScoreboardTranslations;
 +import org.bukkit.scoreboard.DisplaySlot;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
 +
 +public class DisplaySlotTest {
 +
diff --git a/patches/server/Add-more-advancement-API.patch b/patches/server/Add-more-advancement-API.patch
index a442fa71ef..875a60fac0 100644
--- a/patches/server/Add-more-advancement-API.patch
+++ b/patches/server/Add-more-advancement-API.patch
@@ -199,9 +199,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.kyori.adventure.text.format.TextColor;
 +import net.minecraft.advancements.FrameType;
 +import net.minecraft.network.chat.contents.TranslatableContents;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
 +public class AdvancementFrameTest {
 +
@@ -211,8 +211,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            final TextColor expectedColor = PaperAdventure.asAdventure(nmsFrameType.getChatColor());
 +            final String expectedTranslationKey = ((TranslatableContents) nmsFrameType.getDisplayName().getContents()).getKey();
 +            final var frame = PaperAdvancementDisplay.asPaperFrame(nmsFrameType);
-+            assertEquals("The translation keys should be the same", expectedTranslationKey, frame.translationKey());
-+            assertEquals("The frame colors should be the same", expectedColor, frame.color());
++            assertEquals(expectedTranslationKey, frame.translationKey(), "The translation keys should be the same");
++            assertEquals(expectedColor, frame.color(), "The frame colors should be the same");
 +            assertEquals(nmsFrameType.getName(), AdvancementDisplay.Frame.NAMES.key(frame));
 +        }
 +    }
diff --git a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch
index d3446f38ad..dba30578d1 100644
--- a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch
+++ b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch
@@ -324,8 +324,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.HashSet;
 +import java.util.Set;
 +import net.minecraft.world.entity.MobCategory;
-+import org.junit.Assert;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Test;
 +
 +public class MobcapsCommandTest {
 +    @Test
@@ -336,6 +336,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                missing.add(value.getName());
 +            }
 +        }
-+        Assert.assertTrue("MobcapsCommand.MOB_CATEGORY_COLORS map missing TextColors for [" + String.join(", ", missing + "]"), missing.isEmpty());
++        Assertions.assertTrue(missing.isEmpty(), "MobcapsCommand.MOB_CATEGORY_COLORS map missing TextColors for [" + String.join(", ", missing + "]"));
 +    }
 +}
diff --git a/patches/server/Added-missing-default-perms-for-commands.patch b/patches/server/Added-missing-default-perms-for-commands.patch
index 7926bcf618..033d7958d0 100644
--- a/patches/server/Added-missing-default-perms-for-commands.patch
+++ b/patches/server/Added-missing-default-perms-for-commands.patch
@@ -104,9 +104,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.craftbukkit.util.permissions.CraftDefaultPermissions;
 +import org.bukkit.permissions.Permission;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.AfterClass;
-+import org.junit.BeforeClass;
-+import org.junit.Test;
++import org.junit.jupiter.api.AfterAll;
++import org.junit.jupiter.api.BeforeAll;
++import org.junit.jupiter.api.Test;
 +
 +import java.io.PrintStream;
 +import java.util.HashSet;
@@ -115,12 +115,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.Set;
 +import java.util.TreeSet;
 +
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class MinecraftCommandPermissionsTest extends AbstractTestingBase {
 +
 +    private static PrintStream old;
-+    @BeforeClass
++    @BeforeAll
 +    public static void before() {
 +        old = System.out;
 +        System.setOut(Bootstrap.STDOUT);
@@ -143,9 +143,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                foundPerms.add(vanillaPerm);
 +            }
 +        }
-+        assertTrue("Commands missing permissions: \n" + String.join("\n", missing), missing.isEmpty());
++        assertTrue(missing.isEmpty(), "Commands missing permissions: \n" + String.join("\n", missing));
 +        perms.removeAll(foundPerms);
-+        assertTrue("Extra permissions not associated with a command: \n" + String.join("\n", perms), perms.isEmpty());
++        assertTrue(perms.isEmpty(), "Extra permissions not associated with a command: \n" + String.join("\n", perms));
 +    }
 +
 +    private static final List<String> TO_SKIP = List.of(
@@ -165,7 +165,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        return perms;
 +    }
 +
-+    @AfterClass
++    @AfterAll
 +    public static void after() {
 +        if (old != null) {
 +            System.setOut(old);
diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch
index 3e8d62408b..f7873b1077 100644
--- a/patches/server/Adventure.patch
+++ b/patches/server/Adventure.patch
@@ -5070,9 +5070,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.kyori.adventure.text.format.NamedTextColor;
 +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
 +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
 +public class ComponentServicesTest {
 +
diff --git a/patches/server/Bandaid-fix-for-Effect.patch b/patches/server/Bandaid-fix-for-Effect.patch
index 6a6da00421..37a97b8e48 100644
--- a/patches/server/Bandaid-fix-for-Effect.patch
+++ b/patches/server/Bandaid-fix-for-Effect.patch
@@ -85,11 +85,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import java.util.List;
 +import java.util.Map;
 +import net.minecraft.world.level.block.LevelEvent;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertNotNull;
-+import static org.junit.Assert.assertNull;
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertNull;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class EffectTest {
 +
@@ -114,12 +114,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (final Effect effect : Effect.values()) {
 +            if (isNotDeprecated(effect)) {
 +                final Effect put = toId.put(effect.getId(), effect);
-+                assertNull("duplicate API effect: " + put, put);
++                assertNull(put, "duplicate API effect: " + put);
 +            }
 +        }
 +
 +        for (final Integer event : collectNmsLevelEvents()) {
-+            assertNotNull("missing API Effect: " + event, toId.get(event));
++            assertNotNull(toId.get(event), "missing API Effect: " + event);
 +        }
 +    }
 +
@@ -130,13 +130,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (final Effect effect : Effect.values()) {
 +            if (isNotDeprecated(effect)) {
 +                final Effect put = toId.put(effect.getId(), effect);
-+                assertNull("duplicate API effect: " + put, put);
++                assertNull(put, "duplicate API effect: " + put);
 +            }
 +        }
 +
 +        final List<Integer> nmsEvents = collectNmsLevelEvents();
 +        for (final Map.Entry<Integer, Effect> entry : toId.entrySet()) {
-+            assertTrue("Extra API Effect: " + entry.getValue(), nmsEvents.contains(entry.getKey()));
++            assertTrue(nmsEvents.contains(entry.getKey()), "Extra API Effect: " + entry.getValue());
 +        }
 +    }
 +}
diff --git a/patches/server/Build-system-changes.patch b/patches/server/Build-system-changes.patch
index 87f54e4f94..141f76dbf1 100644
--- a/patches/server/Build-system-changes.patch
+++ b/patches/server/Build-system-changes.patch
@@ -27,8 +27,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      runtimeOnly("com.mysql:mysql-connector-j:8.1.0")
 @@ -0,0 +0,0 @@ dependencies {
  
-     testImplementation("junit:junit:4.13.2")
-     testImplementation("org.hamcrest:hamcrest-library:1.3")
+     testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
+     testImplementation("org.hamcrest:hamcrest:2.2")
 +
 +    implementation("io.netty:netty-all:4.1.87.Final"); // Paper - Bump netty
  }
diff --git a/patches/server/Don-t-call-getItemMeta-on-hasItemMeta.patch b/patches/server/Don-t-call-getItemMeta-on-hasItemMeta.patch
index 9b5e953099..67932e8113 100644
--- a/patches/server/Don-t-call-getItemMeta-on-hasItemMeta.patch
+++ b/patches/server/Don-t-call-getItemMeta-on-hasItemMeta.patch
@@ -33,19 +33,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 +    // Paper start
 +    private void testItemMeta(ItemStack stack) {
-+        assertThat("Should not have ItemMeta", stack.hasItemMeta(), is(false));
++        assertThat(stack.hasItemMeta(), is(false), "Should not have ItemMeta");
 +
 +        stack.setDurability((short) 0);
-+        assertThat("ItemStack with zero durability should not have ItemMeta", stack.hasItemMeta(), is(false));
++        assertThat(stack.hasItemMeta(), is(false), "ItemStack with zero durability should not have ItemMeta");
 +
 +        stack.setDurability((short) 2);
-+        assertThat("ItemStack with non-zero durability should have ItemMeta", stack.hasItemMeta(), is(true));
++        assertThat(stack.hasItemMeta(), is(true), "ItemStack with non-zero durability should have ItemMeta");
 +
 +        stack.setLore(java.util.Collections.singletonList("Lore"));
-+        assertThat("ItemStack with lore and durability should have ItemMeta", stack.hasItemMeta(), is(true));
++        assertThat(stack.hasItemMeta(), is(true), "ItemStack with lore and durability should have ItemMeta");
 +
 +        stack.setDurability((short) 0);
-+        assertThat("ItemStack with lore should have ItemMeta", stack.hasItemMeta(), is(true));
++        assertThat(stack.hasItemMeta(), is(true), "ItemStack with lore should have ItemMeta");
 +
 +        stack.setLore(null);
 +    }
diff --git a/patches/server/Fix-regex-mistake-in-CB-NBT-int-deserialization.patch b/patches/server/Fix-regex-mistake-in-CB-NBT-int-deserialization.patch
index 2be4ea33cd..c1023aba3c 100644
--- a/patches/server/Fix-regex-mistake-in-CB-NBT-int-deserialization.patch
+++ b/patches/server/Fix-regex-mistake-in-CB-NBT-int-deserialization.patch
@@ -16,7 +16,7 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializ
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java
 +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNBTTagConfigSerializer.java
-@@ -0,0 +0,0 @@ import net.minecraft.nbt.TagParser;
+@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
  public class CraftNBTTagConfigSerializer {
  
      private static final Pattern ARRAY = Pattern.compile("^\\[.*]");
diff --git a/patches/server/Fix-setPatternColor-on-tropical-fish-bucket-meta.patch b/patches/server/Fix-setPatternColor-on-tropical-fish-bucket-meta.patch
index a0d4cc8668..667abdfb02 100644
--- a/patches/server/Fix-setPatternColor-on-tropical-fish-bucket-meta.patch
+++ b/patches/server/Fix-setPatternColor-on-tropical-fish-bucket-meta.patch
@@ -37,15 +37,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.inventory.ItemStack;
 +import org.bukkit.inventory.meta.TropicalFishBucketMeta;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Assert;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Test;
 +
 +public class CraftMetaTropicalFishBucketTest extends AbstractTestingBase {
 +
 +    @Test
 +    public void testAllCombinations() {
 +        final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta();
-+        Assert.assertTrue("Meta was not a tropical fish bucket", rawMeta instanceof TropicalFishBucketMeta);
++        Assertions.assertTrue(rawMeta instanceof TropicalFishBucketMeta, "Meta was not a tropical fish bucket");
 +
 +        final var meta = (TropicalFishBucketMeta) rawMeta;
 +
@@ -53,16 +53,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            for (final var pattern : TropicalFish.Pattern.values()) {
 +                for (final var patternColor : DyeColor.values()) {
 +                    meta.setBodyColor(bodyColor);
-+                    Assert.assertEquals("Body color did not match post body color!", bodyColor, meta.getBodyColor());
++                    Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post body color!");
 +
 +                    meta.setPattern(pattern);
-+                    Assert.assertEquals("Pattern did not match post pattern!", pattern, meta.getPattern());
-+                    Assert.assertEquals("Body color did not match post pattern!", bodyColor, meta.getBodyColor());
++                    Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern!");
++                    Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern!");
 +
 +                    meta.setPatternColor(patternColor);
-+                    Assert.assertEquals("Pattern did not match post pattern color!", pattern, meta.getPattern());
-+                    Assert.assertEquals("Body color did not match post pattern color!", bodyColor, meta.getBodyColor());
-+                    Assert.assertEquals("Pattern color did not match post pattern color!", patternColor, meta.getPatternColor());
++                    Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern color!");
++                    Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern color!");
++                    Assertions.assertEquals(patternColor, meta.getPatternColor(), "Pattern color did not match post pattern color!");
 +                }
 +            }
 +        }
diff --git a/patches/server/Fix-silent-equipment-change-for-mobs.patch b/patches/server/Fix-silent-equipment-change-for-mobs.patch
index 9ffcfc332e..835510c9af 100644
--- a/patches/server/Fix-silent-equipment-change-for-mobs.patch
+++ b/patches/server/Fix-silent-equipment-change-for-mobs.patch
@@ -78,21 +78,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import io.github.classgraph.ScanResult;
 +import java.util.ArrayList;
 +import java.util.List;
++import java.util.stream.Stream;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.MethodSource;
 +
-+import static org.junit.Assert.fail;
++import static org.junit.jupiter.api.Assertions.fail;
 +
-+@RunWith(Parameterized.class)
 +public class EntitySetItemSlotSilentOverrideTest extends AbstractTestingBase {
 +
-+    @Parameterized.Parameter
-+    public ClassInfo overridesSetItemSlot;
-+
-+    @Parameterized.Parameters(name = "{0}")
-+    public static Iterable<ClassInfo> parameters() {
++    @MethodSource("parameters")
++    public static Stream<ClassInfo> parameters() {
 +        final List<ClassInfo> classInfo = new ArrayList<>();
 +        try (ScanResult scanResult = new ClassGraph()
 +            .enableClassInfo()
@@ -107,12 +103,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                }
 +            }
 +        }
-+        return classInfo;
++        return classInfo.stream();
 +    }
 +
-+    @Test
-+    public void checkSetItemSlotSilentOverrides() {
-+        final MethodInfoList setItemSlot = this.overridesSetItemSlot.getDeclaredMethodInfo("setItemSlot");
++    @ParameterizedTest
++    @MethodSource("parameters")
++    public void checkSetItemSlotSilentOverrides(ClassInfo overridesSetItemSlot) {
++        final MethodInfoList setItemSlot = overridesSetItemSlot.getDeclaredMethodInfo("setItemSlot");
 +        for (final MethodInfo methodInfo : setItemSlot) {
 +            for (final MethodParameterInfo methodParameterInfo : methodInfo.getParameterInfo()) {
 +                if ("boolean".equals(methodParameterInfo.getTypeDescriptor().toStringWithSimpleNames())) {
@@ -120,6 +117,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                }
 +            }
 +        }
-+        fail(this.overridesSetItemSlot.getName() + " needs to override setItemSlot with the boolean silent parameter as well");
++        fail(overridesSetItemSlot.getName() + " needs to override setItemSlot with the boolean silent parameter as well");
 +    }
 +}
diff --git a/patches/server/Fix-upstreams-block-state-factories.patch b/patches/server/Fix-upstreams-block-state-factories.patch
index 3dc5505053..565a5d229a 100644
--- a/patches/server/Fix-upstreams-block-state-factories.patch
+++ b/patches/server/Fix-upstreams-block-state-factories.patch
@@ -419,7 +419,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    @Test
 +    public void testBlockEntityTypes() {
 +        for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) {
-+            org.junit.Assert.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
++            org.junit.jupiter.api.Assertions.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
 +        }
 +    }
 +    // Paper end
diff --git a/patches/server/Get-entity-default-attributes.patch b/patches/server/Get-entity-default-attributes.patch
index 6f36411d9d..da530ff662 100644
--- a/patches/server/Get-entity-default-attributes.patch
+++ b/patches/server/Get-entity-default-attributes.patch
@@ -117,12 +117,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.attribute.AttributeModifier;
 +import org.bukkit.entity.EntityType;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertFalse;
-+import static org.junit.Assert.assertNotNull;
-+import static org.junit.Assert.assertThrows;
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertFalse;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertThrows;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class EntityTypeAttributesTest extends AbstractTestingBase {
 +
diff --git a/patches/server/Implement-Mob-Goal-API.patch b/patches/server/Implement-Mob-Goal-API.patch
index 8f8ea1f9e2..98044dbb03 100644
--- a/patches/server/Implement-Mob-Goal-API.patch
+++ b/patches/server/Implement-Mob-Goal-API.patch
@@ -13,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3")
  
 +    testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
-     testImplementation("junit:junit:4.13.2")
-     testImplementation("org.hamcrest:hamcrest-library:1.3")
+     testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
+     testImplementation("org.hamcrest:hamcrest:2.2")
  
 diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
 new file mode 100644
@@ -815,20 +815,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@
 +package com.destroystokyo.paper.entity.ai;
 +
-+import org.junit.Assert;
-+import org.junit.Test;
-+
++import io.github.classgraph.ClassGraph;
++import io.github.classgraph.ScanResult;
 +import java.lang.reflect.Field;
 +import java.lang.reflect.Modifier;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.List;
 +import java.util.stream.Collectors;
-+
 +import org.bukkit.entity.Mob;
++import org.junit.jupiter.api.Test;
 +
-+import io.github.classgraph.ClassGraph;
-+import io.github.classgraph.ScanResult;
++import static org.junit.jupiter.api.Assertions.assertNotEquals;
++import static org.junit.jupiter.api.Assertions.fail;
 +
 +public class VanillaMobGoalTest {
 +
@@ -874,7 +873,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            System.out.println("Missing from API: ");
 +            for (GoalKey<?> key : missingFromAPI) {
 +                System.out.println("GoalKey<" + key.getEntityClass().getSimpleName() + "> " + key.getNamespacedKey().getKey().toUpperCase() +
-+                                   " = GoalKey.of(" + key.getEntityClass().getSimpleName() + ".class, NamespacedKey.minecraft(\"" + key.getNamespacedKey().getKey() + "\"));");
++                    " = GoalKey.of(" + key.getEntityClass().getSimpleName() + ".class, NamespacedKey.minecraft(\"" + key.getNamespacedKey().getKey() + "\"));");
 +            }
 +            shouldFail = true;
 +        }
@@ -889,7 +888,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            deprecated.forEach(System.out::println);
 +        }
 +
-+        if (shouldFail) Assert.fail("See above");
++        if (shouldFail) {
++            fail("See above");
++        }
 +    }
 +
 +    private static boolean hasNoEnclosingClass(Class<?> clazz) {
@@ -902,7 +903,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft.world.entity").scan()) {
 +            classes = scanResult.getSubclasses("net.minecraft.world.entity.Mob").loadClasses();
 +        }
-+        Assert.assertNotEquals("There are supposed to be more than 0 entity types!", Collections.emptyList(), classes);
++        assertNotEquals(Collections.emptyList(), classes, "There are supposed to be more than 0 entity types!");
 +
 +        boolean shouldFail = false;
 +        for (Class<?> nmsClass : classes) {
@@ -913,6 +914,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            }
 +        }
 +
-+        if (shouldFail) Assert.fail("See above");
++        if (shouldFail) {
++            fail("See above");
++        }
 +    }
 +}
diff --git a/patches/server/Implement-Player-Client-Options-API.patch b/patches/server/Implement-Player-Client-Options-API.patch
index cd41a68b37..cd06414464 100644
--- a/patches/server/Implement-Player-Client-Options-API.patch
+++ b/patches/server/Implement-Player-Client-Options-API.patch
@@ -158,8 +158,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import com.destroystokyo.paper.ClientOption;
 +import net.minecraft.world.entity.player.ChatVisiblity;
 +import org.bukkit.Difficulty;
-+import org.junit.Assert;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Test;
 +
 +public class TranslationKeyTest {
 +
@@ -167,7 +167,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testChatVisibilityKeys() {
 +        for (ClientOption.ChatVisibility chatVisibility : ClientOption.ChatVisibility.values()) {
 +            if (chatVisibility == ClientOption.ChatVisibility.UNKNOWN) continue;
-+            Assert.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
++            Assertions.assertEquals(chatVisibility + "'s translation key doesn't match", ChatVisiblity.valueOf(chatVisibility.name()).getKey(), chatVisibility.translationKey());
 +        }
 +    }
 +}
diff --git a/patches/server/Item-Rarity-API.patch b/patches/server/Item-Rarity-API.patch
index 465af2f235..db24dc99f6 100644
--- a/patches/server/Item-Rarity-API.patch
+++ b/patches/server/Item-Rarity-API.patch
@@ -41,23 +41,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import io.papermc.paper.adventure.PaperAdventure;
 +import net.minecraft.world.item.Rarity;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
 +public class ItemRarityTest {
 +
 +    @Test
 +    public void testConvertFromNmsToBukkit() {
 +        for (Rarity nmsRarity : Rarity.values()) {
-+            assertEquals("rarity names are mis-matched", ItemRarity.values()[nmsRarity.ordinal()].name(), nmsRarity.name());
++            assertEquals(ItemRarity.values()[nmsRarity.ordinal()].name(), nmsRarity.name(), "rarity names are mis-matched");
 +        }
 +    }
 +
 +    @Test
 +    public void testRarityFormatting() {
 +        for (Rarity nmsRarity : Rarity.values()) {
-+            assertEquals("rarity formatting is mis-matched", nmsRarity.color, PaperAdventure.asVanilla(ItemRarity.values()[nmsRarity.ordinal()].color));
++            assertEquals(nmsRarity.color, PaperAdventure.asVanilla(ItemRarity.values()[nmsRarity.ordinal()].color), "rarity formatting is mis-matched");
 +        }
 +    }
 +}
diff --git a/patches/server/ItemStack-repair-check-API.patch b/patches/server/ItemStack-repair-check-API.patch
index 69f1d264c9..fb1bb5e948 100644
--- a/patches/server/ItemStack-repair-check-API.patch
+++ b/patches/server/ItemStack-repair-check-API.patch
@@ -34,11 +34,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.Material;
 +import org.bukkit.inventory.ItemStack;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertFalse;
-+import static org.junit.Assert.assertThrows;
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertFalse;
++import static org.junit.jupiter.api.Assertions.assertThrows;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class ItemStackRepairCheckTest extends AbstractTestingBase {
 +
@@ -46,34 +46,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testIsRepariableBy() {
 +        ItemStack diamondPick = new ItemStack(Material.DIAMOND_PICKAXE);
 +
-+        assertTrue("diamond pick isn't repairable by a diamond", diamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)));
++        assertTrue(diamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "diamond pick isn't repairable by a diamond");
 +    }
 +
 +    @Test
 +    public void testCanRepair() {
 +        ItemStack diamond = new ItemStack(Material.DIAMOND);
 +
-+        assertTrue("diamond can't repair a diamond axe", diamond.canRepair(new ItemStack(Material.DIAMOND_AXE)));
++        assertTrue(diamond.canRepair(new ItemStack(Material.DIAMOND_AXE)), "diamond can't repair a diamond axe");
 +    }
 +
 +    @Test
 +    public void testIsNotRepairableBy() {
 +        ItemStack notDiamondPick = new ItemStack(Material.ACACIA_SAPLING);
 +
-+        assertFalse("acacia sapling is repairable by a diamond", notDiamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)));
++        assertFalse(notDiamondPick.isRepairableBy(new ItemStack(Material.DIAMOND)), "acacia sapling is repairable by a diamond");
 +    }
 +
 +    @Test
 +    public void testCanNotRepair() {
 +        ItemStack diamond = new ItemStack(Material.DIAMOND);
 +
-+        assertFalse("diamond can repair oak button", diamond.canRepair(new ItemStack(Material.OAK_BUTTON)));
++        assertFalse(diamond.canRepair(new ItemStack(Material.OAK_BUTTON)), "diamond can repair oak button");
 +    }
 +
 +    @Test
 +    public void testInvalidItem() {
 +        ItemStack badItemStack = new ItemStack(Material.ACACIA_WALL_SIGN);
 +
-+        assertFalse("acacia wall sign is repairable by diamond", badItemStack.isRepairableBy(new ItemStack(Material.DIAMOND)));
++        assertFalse(badItemStack.isRepairableBy(new ItemStack(Material.DIAMOND)), "acacia wall sign is repairable by diamond");
 +    }
 +}
diff --git a/patches/server/More-Enchantment-API.patch b/patches/server/More-Enchantment-API.patch
index 5d88ba2d7a..d44d49def3 100644
--- a/patches/server/More-Enchantment-API.patch
+++ b/patches/server/More-Enchantment-API.patch
@@ -101,9 +101,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +import net.minecraft.world.item.enchantment.Enchantment.Rarity;
 +import org.bukkit.craftbukkit.enchantments.CraftEnchantment;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
 +
 +public class EnchantmentRarityTest {
 +
@@ -129,13 +129,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.minecraft.world.entity.MobType;
 +import org.bukkit.craftbukkit.entity.CraftLivingEntity;
 +import org.bukkit.entity.EntityCategory;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
 +import java.lang.reflect.Field;
 +import java.util.Map;
 +import java.util.Set;
 +
-+import static org.junit.Assert.assertTrue;
++import static org.junit.jupiter.api.Assertions.assertTrue;
 +
 +public class EntityCategoryTest {
 +
@@ -152,6 +152,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (EntityCategory entityCategory : EntityCategory.values()) {
 +            enumMonsterTypeFieldMap.remove(CraftLivingEntity.fromBukkitEntityCategory(entityCategory));
 +        }
-+        assertTrue(MobType.class.getName() + " instance(s): " + Joiner.on(", ").join(enumMonsterTypeFieldMap.values()) + " do not have bukkit equivalents", enumMonsterTypeFieldMap.size() == 0);
++        assertTrue(enumMonsterTypeFieldMap.size() == 0, MobType.class.getName() + " instance(s): " + Joiner.on(", ").join(enumMonsterTypeFieldMap.values()) + " do not have bukkit equivalents");
 +    }
 +}
diff --git a/patches/server/More-PotionEffectType-API.patch b/patches/server/More-PotionEffectType-API.patch
index 882de5e807..6992b5e226 100644
--- a/patches/server/More-PotionEffectType-API.patch
+++ b/patches/server/More-PotionEffectType-API.patch
@@ -72,17 +72,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.minecraft.world.effect.MobEffectCategory;
 +import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
 +import org.bukkit.potion.PotionEffectType;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertNotNull;
++import static org.junit.jupiter.api.Assertions.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertNotNull;
 +
 +public class EffectCategoryTest {
 +
 +    @Test
 +    public void testEffectCategoriesExist() {
 +        for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
-+            assertNotNull(mobEffectInfo + " is missing a bukkit equivalent", CraftPotionEffectType.fromNMS(mobEffectInfo));
++            assertNotNull(CraftPotionEffectType.fromNMS(mobEffectInfo), mobEffectInfo + " is missing a bukkit equivalent");
 +        }
 +    }
 +
@@ -90,7 +90,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void testCategoryHasEquivalentColors() {
 +        for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
 +            PotionEffectType.Category bukkitEffectCategory = CraftPotionEffectType.fromNMS(mobEffectInfo);
-+            assertEquals(mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor(), bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()));
++            assertEquals(bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()), mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor());
 +        }
 +    }
 +}
diff --git a/patches/server/Paper-Plugins.patch b/patches/server/Paper-Plugins.patch
index 21be113acb..43f152434b 100644
--- a/patches/server/Paper-Plugins.patch
+++ b/patches/server/Paper-Plugins.patch
@@ -7281,7 +7281,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +package io.papermc.paper.plugin;
 +
 +import io.papermc.paper.plugin.entrypoint.dependency.MetaDependencyTree;
-+import org.junit.Test;
++import org.junit.jupiter.api.Test;
 +
 +import java.util.List;
 +
@@ -7351,9 +7351,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
 +import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration;
 +import io.papermc.paper.plugin.provider.PluginProvider;
-+import org.junit.Assert;
-+import org.junit.Before;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.BeforeEach;
++import org.junit.jupiter.api.Test;
 +
 +import java.util.ArrayList;
 +import java.util.HashMap;
@@ -7434,7 +7434,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        setup("RedFire", new String[]{"BrightBlueGrass", "BigPaper"}, new String[]{"BlueFire", "GreenGlass", "BigGrass"}, EMPTY);
 +    }
 +
-+    @Before
++    @BeforeEach
 +    public void loadProviders() {
 +        AtomicInteger currentLoad = new AtomicInteger();
 +        ModernPluginLoadingStrategy<PaperTestPlugin> modernPluginLoadingStrategy = new ModernPluginLoadingStrategy<>(new ProviderConfiguration<>() {
@@ -7458,16 +7458,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (PluginProvider<PaperTestPlugin> provider : REGISTERED_PROVIDERS) {
 +            TestPluginMeta pluginMeta = (TestPluginMeta) provider.getMeta();
 +            String identifier = pluginMeta.getName();
-+            Assert.assertTrue("Provider wasn't loaded! (%s)".formatted(identifier), LOAD_ORDER.containsKey(identifier));
++            Assertions.assertTrue(LOAD_ORDER.containsKey(identifier), "Provider wasn't loaded! (%s)".formatted(identifier));
 +
 +            int index = LOAD_ORDER.get(identifier);
 +
 +            // Hard dependencies should be loaded BEFORE
 +            for (String hardDependency : pluginMeta.getPluginDependencies()) {
-+                Assert.assertTrue("Plugin (%s) is missing hard dependency (%s)".formatted(identifier, hardDependency), LOAD_ORDER.containsKey(hardDependency));
++                Assertions.assertTrue(LOAD_ORDER.containsKey(hardDependency), "Plugin (%s) is missing hard dependency (%s)".formatted(identifier, hardDependency));
 +
 +                int dependencyIndex = LOAD_ORDER.get(hardDependency);
-+                Assert.assertTrue("Plugin (%s) was not loaded BEFORE soft dependency. (%s)".formatted(identifier, hardDependency), index > dependencyIndex);
++                Assertions.assertTrue(index > dependencyIndex, "Plugin (%s) was not loaded BEFORE soft dependency. (%s)".formatted(identifier, hardDependency));
 +            }
 +
 +            for (String softDependency : pluginMeta.getPluginSoftDependencies()) {
@@ -7477,7 +7477,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +                int dependencyIndex = LOAD_ORDER.get(softDependency);
 +
-+                Assert.assertTrue("Plugin (%s) was not loaded BEFORE soft dependency. (%s)".formatted(identifier, softDependency), index > dependencyIndex);
++                Assertions.assertTrue(index > dependencyIndex, "Plugin (%s) was not loaded BEFORE soft dependency. (%s)".formatted(identifier, softDependency));
 +            }
 +
 +            for (String loadBefore : pluginMeta.getLoadBeforePlugins()) {
@@ -7486,7 +7486,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                }
 +
 +                int dependencyIndex = LOAD_ORDER.get(loadBefore);
-+                Assert.assertTrue("Plugin (%s) was NOT loaded BEFORE loadbefore dependency. (%s)".formatted(identifier, loadBefore), index < dependencyIndex);
++                Assertions.assertTrue(index < dependencyIndex, "Plugin (%s) was NOT loaded BEFORE loadbefore dependency. (%s)".formatted(identifier, loadBefore));
 +            }
 +        }
 +    }
@@ -7504,8 +7504,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.permissions.Permission;
 +import org.bukkit.plugin.PluginManager;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.After;
-+import org.junit.Test;
++import org.junit.jupiter.api.AfterEach;
++import org.junit.jupiter.api.Test;
 +
 +import static org.hamcrest.MatcherAssert.assertThat;
 +import static org.hamcrest.Matchers.*;
@@ -7566,7 +7566,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        assertThat("Permission \"" + name + "\" was not removed", pm.getPermission(name), is(nullValue()));
 +    }
 +
-+    @After
++    @AfterEach
 +    public void tearDown() {
 +        pm.clearPlugins();
 +        assertThat(pm.getPermissions(), is(empty()));
@@ -7581,8 +7581,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +package io.papermc.paper.plugin;
 +
 +import io.papermc.paper.plugin.provider.configuration.PaperPluginMeta;
-+import org.junit.Assert;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Test;
 +
 +public class PluginNamingTest {
 +    private static final String TEST_NAME = "Test_Plugin";
@@ -7598,12 +7598,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    @Test
 +    public void testName() {
-+        Assert.assertEquals(TEST_NAME, this.pluginMeta.getName());
++        Assertions.assertEquals(TEST_NAME, this.pluginMeta.getName());
 +    }
 +
 +    @Test
 +    public void testDisplayName() {
-+        Assert.assertEquals(TEST_NAME + " v" + TEST_VERSION, this.pluginMeta.getDisplayName());
++        Assertions.assertEquals(TEST_NAME + " v" + TEST_VERSION, this.pluginMeta.getDisplayName());
 +    }
 +}
 diff --git a/src/test/java/io/papermc/paper/plugin/SyntheticEventTest.java b/src/test/java/io/papermc/paper/plugin/SyntheticEventTest.java
@@ -7619,8 +7619,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.event.Event;
 +import org.bukkit.event.EventHandler;
 +import org.bukkit.event.Listener;
-+import org.junit.Assert;
-+import org.junit.Test;
++import org.junit.jupiter.api.Assertions;
++import org.junit.jupiter.api.Test;
 +
 +public class SyntheticEventTest {
 +
@@ -7635,7 +7635,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        paperPluginManager.registerEvents(impl, paperTestPlugin);
 +        paperPluginManager.callEvent(event);
 +
-+        Assert.assertEquals(1, impl.callCount);
++        Assertions.assertEquals(1, impl.callCount);
 +    }
 +
 +    public abstract static class Base<E extends Event> implements Listener {
diff --git a/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch
index bf2516999e..1effedf53a 100644
--- a/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch
+++ b/patches/server/Properly-handle-BlockBreakEvent-isDropItems.patch
@@ -122,21 +122,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import io.github.classgraph.ScanResult;
 +import java.util.ArrayList;
 +import java.util.List;
++import java.util.stream.Stream;
 +import org.bukkit.support.AbstractTestingBase;
-+import org.junit.Test;
-+import org.junit.runner.RunWith;
-+import org.junit.runners.Parameterized;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.MethodSource;
 +
-+import static org.junit.Assert.assertEquals;
++import static org.junit.jupiter.api.Assertions.assertEquals;
 +
-+@RunWith(Parameterized.class)
 +public class BlockPlayerDestroyOverrideTest extends AbstractTestingBase {
 +
-+    @Parameterized.Parameter
-+    public ClassInfo overridesPlayerDestroy;
-+
-+    @Parameterized.Parameters
-+    public static Iterable<ClassInfo> parameters() {
++    @MethodSource("parameters")
++    public static Stream<ClassInfo> parameters() {
 +        final List<ClassInfo> classInfo = new ArrayList<>();
 +        try (ScanResult scanResult = new ClassGraph()
 +            .enableClassInfo()
@@ -151,15 +147,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                }
 +            }
 +        }
-+        return classInfo;
++        return classInfo.stream();
 +    }
 +
-+    @Test
-+    public void checkPlayerDestroyOverrides() {
-+        final MethodInfoList playerDestroy = this.overridesPlayerDestroy.getDeclaredMethodInfo("playerDestroy");
-+        assertEquals(this.overridesPlayerDestroy.getName() + " has multiple playerDestroy methods", 1, playerDestroy.size());
++    @ParameterizedTest
++    @MethodSource("parameters")
++    public void checkPlayerDestroyOverrides(ClassInfo overridesPlayerDestroy) {
++        final MethodInfoList playerDestroy = overridesPlayerDestroy.getDeclaredMethodInfo("playerDestroy");
++        assertEquals(1, playerDestroy.size(), overridesPlayerDestroy.getName() + " has multiple playerDestroy methods");
 +        final MethodInfo next = playerDestroy.iterator().next();
 +        final MethodParameterInfo[] parameterInfo = next.getParameterInfo();
-+        assertEquals(this.overridesPlayerDestroy.getName() + " needs to change it's override of playerDestroy", "boolean", parameterInfo[parameterInfo.length - 1].getTypeDescriptor().toStringWithSimpleNames());
++        assertEquals(overridesPlayerDestroy.getName() + " needs to change its override of playerDestroy", "boolean", parameterInfo[parameterInfo.length - 1].getTypeDescriptor().toStringWithSimpleNames());
 +    }
 +}
diff --git a/patches/server/Remap-fixes.patch b/patches/server/Remap-fixes.patch
index 6c4101c29d..0bd580edf6 100644
--- a/patches/server/Remap-fixes.patch
+++ b/patches/server/Remap-fixes.patch
@@ -92,29 +92,29 @@ diff --git a/src/test/java/org/bukkit/DyeColorsTest.java b/src/test/java/org/buk
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/test/java/org/bukkit/DyeColorsTest.java
 +++ b/src/test/java/org/bukkit/DyeColorsTest.java
-@@ -0,0 +0,0 @@ import static org.hamcrest.Matchers.*;
- import static org.junit.Assert.*;
- import java.util.ArrayList;
- import java.util.List;
+@@ -0,0 +0,0 @@ package org.bukkit;
+ import static org.bukkit.support.MatcherAssert.*;
+ import static org.hamcrest.Matchers.*;
+ 
 -import net.minecraft.world.item.DyeColor;
  import org.bukkit.support.AbstractTestingBase;
- import org.junit.Test;
- import org.junit.runner.RunWith;
+ import org.junit.jupiter.params.ParameterizedTest;
+ import org.junit.jupiter.params.provider.EnumSource;
 @@ -0,0 +0,0 @@ public class DyeColorsTest extends AbstractTestingBase {
-     @Test
-     public void checkColor() {
-         Color color = this.dye.getColor();
--        float[] nmsColorArray = DyeColor.byId(this.dye.getWoolData()).getTextureDiffuseColors();
-+        float[] nmsColorArray = net.minecraft.world.item.DyeColor.byId(this.dye.getWoolData()).getTextureDiffuseColors(); // Paper - remap fix
+     @EnumSource(DyeColor.class)
+     public void checkColor(DyeColor dye) {
+         Color color = dye.getColor();
+-        float[] nmsColorArray = DyeColor.byId(dye.getWoolData()).getTextureDiffuseColors();
++        float[] nmsColorArray = net.minecraft.world.item.DyeColor.byId(dye.getWoolData()).getTextureDiffuseColors(); // Paper - remap fix
          Color nmsColor = Color.fromRGB((int) (nmsColorArray[0] * 255), (int) (nmsColorArray[1] * 255), (int) (nmsColorArray[2] * 255));
          assertThat(color, is(nmsColor));
      }
 @@ -0,0 +0,0 @@ public class DyeColorsTest extends AbstractTestingBase {
-     @Test
-     public void checkFireworkColor() {
-         Color color = this.dye.getFireworkColor();
--        int nmsColor = DyeColor.byId(this.dye.getWoolData()).getFireworkColor();
-+        int nmsColor = net.minecraft.world.item.DyeColor.byId(this.dye.getWoolData()).getFireworkColor(); // Paper - remap fix
+     @EnumSource(org.bukkit.DyeColor.class)
+     public void checkFireworkColor(org.bukkit.DyeColor dye) {
+         Color color = dye.getFireworkColor();
+-        int nmsColor = DyeColor.byId(dye.getWoolData()).getFireworkColor();
++        int nmsColor = net.minecraft.world.item.DyeColor.byId(dye.getWoolData()).getFireworkColor(); // Paper - remap fix
          assertThat(color, is(Color.fromRGB(nmsColor)));
      }
  }
@@ -153,8 +153,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import net.minecraft.resources.ResourceLocation;
 -import net.minecraft.world.entity.EntityType;
  import org.bukkit.support.AbstractTestingBase;
- import org.junit.Assert;
- import org.junit.Test;
+ import org.junit.jupiter.api.Test;
+ 
 @@ -0,0 +0,0 @@ public class EntityTypesTest extends AbstractTestingBase {
      public void testMaps() {
          Set<EntityType> allBukkit = Arrays.stream(EntityType.values()).filter((b) -> b.getName() != null).collect(Collectors.toSet());
@@ -165,27 +165,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            ResourceLocation key = net.minecraft.world.entity.EntityType.getKey(nms); // Paper - remap fix
  
              org.bukkit.entity.EntityType bukkit = org.bukkit.entity.EntityType.fromName(key.getPath());
-             Assert.assertNotNull("Missing nms->bukkit " + key, bukkit);
+             assertNotNull(bukkit, "Missing nms->bukkit " + key);
 diff --git a/src/test/java/org/bukkit/entity/PandaGeneTest.java b/src/test/java/org/bukkit/entity/PandaGeneTest.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/test/java/org/bukkit/entity/PandaGeneTest.java
 +++ b/src/test/java/org/bukkit/entity/PandaGeneTest.java
-@@ -0,0 +0,0 @@
- package org.bukkit.entity;
+@@ -0,0 +0,0 @@ package org.bukkit.entity;
+ 
+ import static org.junit.jupiter.api.Assertions.*;
  
 -import net.minecraft.world.entity.animal.Panda;
  import org.bukkit.craftbukkit.entity.CraftPanda;
- import org.junit.Assert;
- import org.junit.Test;
+ import org.junit.jupiter.api.Test;
+ 
 @@ -0,0 +0,0 @@ public class PandaGeneTest {
+ 
      @Test
      public void testBukkit() {
-         for (Panda.Gene gene : Panda.Gene.values()) {
+-        for (Panda.Gene gene : Panda.Gene.values()) {
 -            Panda.Gene nms = CraftPanda.toNms(gene);
++        for (Panda.Gene gene : Panda.Gene.values()) { // Paper - remap fix
 +            net.minecraft.world.entity.animal.Panda.Gene nms = CraftPanda.toNms(gene); // Paper - remap fix
  
-             Assert.assertNotNull("NMS gene null for " + gene, nms);
-             Assert.assertEquals("Recessive status did not match " + gene, gene.isRecessive(), nms.isRecessive());
+             assertNotNull(nms, "NMS gene null for " + gene);
+             assertEquals(gene.isRecessive(), nms.isRecessive(), "Recessive status did not match " + gene);
 @@ -0,0 +0,0 @@ public class PandaGeneTest {
  
      @Test
@@ -194,4 +197,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (net.minecraft.world.entity.animal.Panda.Gene gene : net.minecraft.world.entity.animal.Panda.Gene.values()) { // Paper - remap fix
              org.bukkit.entity.Panda.Gene bukkit = CraftPanda.fromNms(gene);
  
-             Assert.assertNotNull("Bukkit gene null for " + gene, bukkit);
+             assertNotNull(bukkit, "Bukkit gene null for " + gene);
diff --git a/patches/server/Setup-Gradle-project.patch b/patches/server/Setup-Gradle-project.patch
index 867bc37ba7..0330582c8d 100644
--- a/patches/server/Setup-Gradle-project.patch
+++ b/patches/server/Setup-Gradle-project.patch
@@ -55,8 +55,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3")
 +    runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3")
 +
-+    testImplementation("junit:junit:4.13.2")
-+    testImplementation("org.hamcrest:hamcrest-library:1.3")
++    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
++    testImplementation("org.hamcrest:hamcrest:2.2")
 +}
 +
 +val craftbukkitPackageVersion = "1_20_R2" // Paper
@@ -402,6 +402,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -            <artifactId>json-simple</artifactId>
 -            <version>1.1.1</version>
 -            <scope>runtime</scope>
+-            <exclusions>
+-                <exclusion>
+-                    <groupId>junit</groupId>
+-                    <artifactId>junit</artifactId>
+-                </exclusion>
+-            </exclusions>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.xerial</groupId>
@@ -443,15 +449,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -        </dependency>
 -        <!-- testing -->
 -        <dependency>
--            <groupId>junit</groupId>
--            <artifactId>junit</artifactId>
--            <version>4.13.2</version>
+-            <groupId>org.junit.jupiter</groupId>
+-            <artifactId>junit-jupiter</artifactId>
+-            <version>5.10.0</version>
 -            <scope>test</scope>
 -        </dependency>
 -        <dependency>
 -            <groupId>org.hamcrest</groupId>
--            <artifactId>hamcrest-library</artifactId>
--            <version>1.3</version>
+-            <artifactId>hamcrest</artifactId>
+-            <version>2.2</version>
 -            <scope>test</scope>
 -        </dependency>
 -    </dependencies>
diff --git a/patches/server/fix-item-meta-for-tadpole-buckets.patch b/patches/server/fix-item-meta-for-tadpole-buckets.patch
index 58904d3ba6..160d162f68 100644
--- a/patches/server/fix-item-meta-for-tadpole-buckets.patch
+++ b/patches/server/fix-item-meta-for-tadpole-buckets.patch
@@ -59,11 +59,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        for (final Item item : BuiltInRegistries.ITEM) {
 +            if (item instanceof net.minecraft.world.item.HangingEntityItem || item instanceof net.minecraft.world.item.MobBucketItem) {
 +                ItemStack stack = new ItemStack(CraftMagicNumbers.getMaterial(item));
-+                assertTrue("missing entity tag meta handling for " + item, ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()));
++                assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item);
 +                stack = CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.STONE);
 +                stack.editMeta(meta -> meta.displayName(net.kyori.adventure.text.Component.text("hello")));
 +                stack.setType(CraftMagicNumbers.getMaterial(item));
-+                assertTrue("missing entity tag meta handling for " + item, ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()));
++                assertTrue(ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()), "missing entity tag meta handling for " + item);
 +            }
 +        }
 +    }
diff --git a/work/Bukkit b/work/Bukkit
index dfe1fb4853..fb23cbb382 160000
--- a/work/Bukkit
+++ b/work/Bukkit
@@ -1 +1 @@
-Subproject commit dfe1fb4853158bd17f6955527ad3bf85f4d5150d
+Subproject commit fb23cbb3829ef866094f45ffc5391d516e6a3c57
diff --git a/work/CraftBukkit b/work/CraftBukkit
index f71a799f03..f0661c3514 160000
--- a/work/CraftBukkit
+++ b/work/CraftBukkit
@@ -1 +1 @@
-Subproject commit f71a799f03aae4277a48b4a1082b478833975682
+Subproject commit f0661c3514a7d8e51e2281f045e1c14d0e733230