diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index aba60a7a3..096dc6dd2 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -7,6 +7,7 @@ repositories { maven("https://jitpack.io/") maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.momirealms.net/releases/") + maven("https://repo.skriptlang.org/releases/") // skript mavenCentral() } @@ -14,6 +15,7 @@ dependencies { compileOnly(project(":core")) compileOnly(project(":shared")) compileOnly(project(":bukkit:compatibility")) + compileOnly(project(":bukkit:compatibility:legacy")) compileOnly(project(":bukkit:legacy")) // Anti Grief compileOnly("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") @@ -58,6 +60,8 @@ dependencies { compileOnly("org.bstats:bstats-bukkit:${rootProject.properties["bstats_version"]}") // Aho-Corasick java implementation compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") + // Skript + compileOnly("com.github.SkriptLang:Skript:2.11.0") } java { diff --git a/bukkit/compatibility/legacy/build.gradle.kts b/bukkit/compatibility/legacy/build.gradle.kts new file mode 100644 index 000000000..a74b0d102 --- /dev/null +++ b/bukkit/compatibility/legacy/build.gradle.kts @@ -0,0 +1,30 @@ +repositories { + mavenCentral() + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.rapture.pw/repository/maven-releases/") + maven("https://repo.infernalsuite.com/repository/maven-snapshots/") +} + +dependencies { + compileOnly(project(":core")) + // NBT + compileOnly("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}") + // Platform + compileOnly("io.papermc.paper:paper-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") + compileOnly("com.infernalsuite.aswm:api:1.20.4-R0.1-SNAPSHOT") +} + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + withSourcesJar() +} + +tasks.withType { + options.encoding = "UTF-8" + options.release.set(21) + dependsOn(tasks.clean) +} \ No newline at end of file diff --git a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java new file mode 100644 index 000000000..872e50bf8 --- /dev/null +++ b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeFormatStorageAdaptor.java @@ -0,0 +1,74 @@ +package net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld; + +import com.infernalsuite.aswm.api.events.LoadSlimeWorldEvent; +import com.infernalsuite.aswm.api.world.SlimeWorld; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldManager; +import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Method; +import java.util.function.Function; + +public class LegacySlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener { + private final WorldManager worldManager; + private final Function SLIME_WORLD_GETTER; + + @EventHandler + public void onWorldLoad(LoadSlimeWorldEvent event) { + org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); + this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), new LegacySlimeWorldDataStorage(event.getSlimeWorld()))); + } + + public LegacySlimeFormatStorageAdaptor(WorldManager worldManager, int version) { + this.worldManager = worldManager; + try { + if (version == 1) { + Plugin plugin = Bukkit.getPluginManager().getPlugin("SlimeWorldManager"); + Class slimeClass = Class.forName("com.infernalsuite.aswm.api.SlimePlugin"); + Method method = slimeClass.getMethod("getWorld", String.class); + this.SLIME_WORLD_GETTER = (name) -> { + try { + return (SlimeWorld) method.invoke(plugin, name); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + }; + } else if (version == 2) { + Class apiClass = Class.forName("com.infernalsuite.aswm.api.AdvancedSlimePaperAPI"); + Object apiInstance = apiClass.getMethod("instance").invoke(null); + Method method = apiClass.getMethod("getLoadedWorld", String.class); + this.SLIME_WORLD_GETTER = (name) -> { + try { + return (SlimeWorld) method.invoke(apiInstance, name); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + }; + } else { + throw new IllegalArgumentException("Unsupported version: " + version); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public SlimeWorld getWorld(String name) { + return this.SLIME_WORLD_GETTER.apply(name); + } + + // 请注意,在加载事件的时候,无法通过AdvancedSlimePaperAPI.instance().getLoadedWorld来判断是否为slime世界 + @Override + public @NotNull WorldDataStorage adapt(@NotNull World world) { + SlimeWorld slimeWorld = getWorld(world.name()); + if (slimeWorld == null) { + return super.adapt(world); + } + return new LegacySlimeWorldDataStorage(slimeWorld); + } +} diff --git a/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java new file mode 100644 index 000000000..1ac65bd73 --- /dev/null +++ b/bukkit/compatibility/legacy/src/main/java/net/momirealms/craftengine/bukkit/compatibility/legacy/slimeworld/LegacySlimeWorldDataStorage.java @@ -0,0 +1,81 @@ +package net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld; + +import com.flowpowered.nbt.ByteArrayTag; +import com.flowpowered.nbt.CompoundMap; +import com.infernalsuite.aswm.api.world.SlimeChunk; +import com.infernalsuite.aswm.api.world.SlimeWorld; +import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.ChunkPos; +import net.momirealms.craftengine.core.world.chunk.CEChunk; +import net.momirealms.craftengine.core.world.chunk.serialization.DefaultChunkSerializer; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.Optional; + +public class LegacySlimeWorldDataStorage implements WorldDataStorage { + private final WeakReference slimeWorld; + + public LegacySlimeWorldDataStorage(SlimeWorld slimeWorld) { + this.slimeWorld = new WeakReference<>(slimeWorld); + } + + public SlimeWorld getWorld() { + return slimeWorld.get(); + } + + @Override + public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return new CEChunk(world, pos); + Optional tag = slimeChunk.getExtraData().getAsByteArrayTag("craftengine"); + if (tag.isEmpty()) return new CEChunk(world, pos); + try { + CompoundTag compoundTag = NBT.fromBytes(tag.get().getValue()); + if (compoundTag == null) return new CEChunk(world, pos); + return DefaultChunkSerializer.deserialize(world, pos, compoundTag); + } catch (Exception e) { + throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e); + } + } + + private CompoundMap createOrGetDataMap(SlimeWorld world) { + Optional optionalCompoundTag = world.getExtraData().getAsCompoundTag("craftengine"); + CompoundMap ccDataMap; + if (optionalCompoundTag.isEmpty()) { + ccDataMap = new CompoundMap(); + world.getExtraData().getValue().put(new com.flowpowered.nbt.CompoundTag("customcrops", ccDataMap)); + } else { + ccDataMap = optionalCompoundTag.get().getValue(); + } + return ccDataMap; + } + + @Override + public void writeChunkAt(@NotNull ChunkPos pos, @NotNull CEChunk chunk, boolean immediately) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return; + CompoundTag nbt = DefaultChunkSerializer.serialize(chunk); + if (nbt == null) { + slimeChunk.getExtraData().getValue().remove("craftengine"); + } else { + try { + slimeChunk.getExtraData().getValue().put("craftengine", new ByteArrayTag("craftengine", NBT.toBytes(nbt))); + } catch (Exception e) { + throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); + } + } + } + + @Override + public void flush() { + } + + @Override + public void close() { + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java index 1f249dde5..6ef0fd560 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java @@ -68,6 +68,6 @@ public class SlimeWorldDataStorage implements WorldDataStorage { } @Override - public void close() throws IOException { + public void close() { } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index d228f285e..a373bbeff 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { implementation(project(":bukkit")) implementation(project(":bukkit:legacy")) implementation(project(":bukkit:compatibility")) + implementation(project(":bukkit:compatibility:legacy")) implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}") implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") @@ -49,7 +50,7 @@ bukkit { apiVersion = "1.20" authors = listOf("XiaoMoMi") contributors = listOf("jhqwqmc", "iqtesterrr") - softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit") + softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript") foliaSupported = true } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CustomBlockBreakEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CustomBlockBreakEvent.java index 03c0cc3b3..2fb9abd73 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CustomBlockBreakEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CustomBlockBreakEvent.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import org.bukkit.Location; @@ -18,17 +19,23 @@ public class CustomBlockBreakEvent extends PlayerEvent implements Cancellable { private final Location location; private final Block bukkitBlock; private boolean dropItems; + private final BukkitServerPlayer player; - public CustomBlockBreakEvent(@NotNull Player player, + public CustomBlockBreakEvent(@NotNull BukkitServerPlayer player, @NotNull Location location, @NotNull Block bukkitBlock, @NotNull ImmutableBlockState state) { - super(player); + super(player.platformPlayer()); this.customBlock = state.owner().value(); this.state = state; this.bukkitBlock = bukkitBlock; this.location = location; this.dropItems = true; + this.player = player; + } + + public BukkitServerPlayer player() { + return player; } public boolean dropItems() { @@ -44,11 +51,6 @@ public class CustomBlockBreakEvent extends PlayerEvent implements Cancellable { return bukkitBlock; } - @NotNull - public Player player() { - return getPlayer(); - } - @NotNull public CustomBlock customBlock() { return this.customBlock; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index f60b5d7f5..ee04f6ba5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -120,7 +120,7 @@ public class BlockEventListener implements Listener { } // trigger event - CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(event.getPlayer(), location, block, state); + CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(serverPlayer, location, block, state); boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent); if (isCancelled) { event.setCancelled(true); @@ -146,14 +146,10 @@ public class BlockEventListener implements Listener { Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); // do not drop if it's not the correct tool - BlockSettings settings = state.settings(); - if (settings.requireCorrectTool()) { - if (itemInHand == null) return; - if (!settings.isCorrectTool(itemInHand.id()) && - (!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(itemInHand.getLiteralObject(), state.customBlockState().handle()))) { - return; - } + if (!BlockStateUtils.isCorrectTool(state, itemInHand)) { + return; } + // drop items ContextHolder.Builder builder = ContextHolder.builder(); builder.withParameter(LootParameters.WORLD, world); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/EvtCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/EvtCustomBlock.java new file mode 100644 index 000000000..5494b584f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/EvtCustomBlock.java @@ -0,0 +1,71 @@ +package net.momirealms.craftengine.bukkit.compatibility.skript; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptEvent; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.StringUtils; +import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; + +@SuppressWarnings({"unchecked"}) +public class EvtCustomBlock extends SkriptEvent { + + public static void register() { + Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "[customblock] (break[ing]|1¦min(e|ing)) [[of] %-strings%]") + .description("Called when a custom block is broken by a player. If you use 'on mine', only events where the broken block dropped something will call the trigger."); + Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "[customblock] (plac(e|ing)|build[ing]) [[of] %-strings%]") + .description("Called when a player places a custom block."); + } + + @Nullable + private Literal blocks; + private String[] blockArray; + private boolean mine = false; + + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parser) { + if (args[0] != null) { + blocks = ((Literal) args[0]); + blockArray = blocks.getAll(); + } + mine = parser.mark == 1; + return true; + } + + @Override + public boolean check(Event event) { + if (mine && event instanceof CustomBlockBreakEvent customBlockBreakEvent) { + if (!BlockStateUtils.isCorrectTool(customBlockBreakEvent.blockState(), customBlockBreakEvent.player().getItemInHand(InteractionHand.MAIN_HAND))) { + return false; + } + } + if (blocks == null) + return true; + + String blockType; + String blockState; + if (event instanceof CustomBlockBreakEvent customBlockBreakEvent) { + blockType = customBlockBreakEvent.customBlock().id().toString(); + blockState = customBlockBreakEvent.blockState().toString(); + } else if (event instanceof CustomBlockPlaceEvent customBlockPlaceEvent) { + blockType = customBlockPlaceEvent.customBlock().id().toString(); + blockState = customBlockPlaceEvent.blockState().toString(); + } else { + return false; + } + + return Arrays.stream(blockArray).anyMatch(block -> StringUtils.equals(blockType, block, true) || StringUtils.equals(blockState, block, true)); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "break/place" + (blocks != null ? " of " + blocks.toString(event, debug) : ""); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 6c8d8ff1b..764474e18 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.api.event.CraftEngineReloadEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; +import net.momirealms.craftengine.bukkit.compatibility.skript.EvtCustomBlock; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.font.BukkitFontManager; @@ -165,6 +166,10 @@ public class BukkitCraftEngine extends CraftEngine { PlaceholderAPIUtils.registerExpansions(this); this.hasPlaceholderAPI = true; } + // skript + if (this.isPluginEnabled("Skript")) { + EvtCustomBlock.register(); + } } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index bbce5ef50..515fdfc63 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -2,10 +2,8 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.core.block.BlockStateParser; -import net.momirealms.craftengine.core.block.CustomBlock; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.PushReaction; +import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Instrument; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MapColor; @@ -14,6 +12,9 @@ import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.IdentityHashMap; import java.util.List; @@ -32,6 +33,18 @@ public class BlockStateUtils { hasInit = true; } + public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item itemInHand) { + BlockSettings settings = state.settings(); + if (settings.requireCorrectTool()) { + if (itemInHand == null) return false; + if (!settings.isCorrectTool(itemInHand.id()) && + (!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(itemInHand.getLiteralObject(), state.customBlockState().handle()))) { + return false; + } + } + return true; + } + public static List getAllBlockStates(String blockState) { int index = blockState.indexOf('['); if (index == -1) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index c77d28879..6f2f3c9bd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -61,8 +62,23 @@ public class BukkitWorldManager implements WorldManager, Listener { return; } catch (ClassNotFoundException ignored) { } + } else { + try { + Class.forName("com.infernalsuite.aswm.api.SlimePlugin"); + LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(this, 1); + this.storageAdaptor = adaptor; + Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap()); + } catch (ClassNotFoundException ignored) { + if (Bukkit.getPluginManager().isPluginEnabled("SlimeWorldPlugin")) { + LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(this, 2); + this.storageAdaptor = adaptor; + Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap()); + } + } + } + if (this.storageAdaptor == null) { + this.storageAdaptor = new DefaultStorageAdaptor(); } - this.storageAdaptor = new DefaultStorageAdaptor(); } @Override diff --git a/settings.gradle.kts b/settings.gradle.kts index d75ce83fd..19bcd7ced 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,7 @@ include(":core") include(":bukkit") include(":bukkit:legacy") include(":bukkit:compatibility") +include(":bukkit:compatibility:legacy") include(":bukkit:loader") include(":server-mod:v1_20_1") include(":server-mod:v1_20_5") @@ -18,4 +19,4 @@ pluginManagement { maven("https://repo.papermc.io/repository/maven-public/") maven("https://maven.fabricmc.net/") } -} +} \ No newline at end of file