9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

添加旧版本slimeworld支持

This commit is contained in:
XiaoMoMi
2025-04-25 03:25:47 +08:00
parent 338639c015
commit bee4ed2767
13 changed files with 317 additions and 23 deletions

View File

@@ -7,6 +7,7 @@ repositories {
maven("https://jitpack.io/") maven("https://jitpack.io/")
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.momirealms.net/releases/") maven("https://repo.momirealms.net/releases/")
maven("https://repo.skriptlang.org/releases/") // skript
mavenCentral() mavenCentral()
} }
@@ -14,6 +15,7 @@ dependencies {
compileOnly(project(":core")) compileOnly(project(":core"))
compileOnly(project(":shared")) compileOnly(project(":shared"))
compileOnly(project(":bukkit:compatibility")) compileOnly(project(":bukkit:compatibility"))
compileOnly(project(":bukkit:compatibility:legacy"))
compileOnly(project(":bukkit:legacy")) compileOnly(project(":bukkit:legacy"))
// Anti Grief // Anti Grief
compileOnly("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") compileOnly("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
@@ -58,6 +60,8 @@ dependencies {
compileOnly("org.bstats:bstats-bukkit:${rootProject.properties["bstats_version"]}") compileOnly("org.bstats:bstats-bukkit:${rootProject.properties["bstats_version"]}")
// Aho-Corasick java implementation // Aho-Corasick java implementation
compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}")
// Skript
compileOnly("com.github.SkriptLang:Skript:2.11.0")
} }
java { java {

View File

@@ -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<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(21)
dependsOn(tasks.clean)
}

View File

@@ -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<String, SlimeWorld> 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);
}
}

View File

@@ -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<com.infernalsuite.aswm.api.world.SlimeWorld> 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<ByteArrayTag> 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<com.flowpowered.nbt.CompoundTag> 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() {
}
}

View File

@@ -68,6 +68,6 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
} }
@Override @Override
public void close() throws IOException { public void close() {
} }
} }

View File

@@ -19,6 +19,7 @@ dependencies {
implementation(project(":bukkit")) implementation(project(":bukkit"))
implementation(project(":bukkit:legacy")) implementation(project(":bukkit:legacy"))
implementation(project(":bukkit:compatibility")) implementation(project(":bukkit:compatibility"))
implementation(project(":bukkit:compatibility:legacy"))
implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}") implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}")
implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
@@ -49,7 +50,7 @@ bukkit {
apiVersion = "1.20" apiVersion = "1.20"
authors = listOf("XiaoMoMi") authors = listOf("XiaoMoMi")
contributors = listOf("jhqwqmc", "iqtesterrr") contributors = listOf("jhqwqmc", "iqtesterrr")
softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit") softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript")
foliaSupported = true foliaSupported = true
} }

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.api.event; 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.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.Location; import org.bukkit.Location;
@@ -18,17 +19,23 @@ public class CustomBlockBreakEvent extends PlayerEvent implements Cancellable {
private final Location location; private final Location location;
private final Block bukkitBlock; private final Block bukkitBlock;
private boolean dropItems; private boolean dropItems;
private final BukkitServerPlayer player;
public CustomBlockBreakEvent(@NotNull Player player, public CustomBlockBreakEvent(@NotNull BukkitServerPlayer player,
@NotNull Location location, @NotNull Location location,
@NotNull Block bukkitBlock, @NotNull Block bukkitBlock,
@NotNull ImmutableBlockState state) { @NotNull ImmutableBlockState state) {
super(player); super(player.platformPlayer());
this.customBlock = state.owner().value(); this.customBlock = state.owner().value();
this.state = state; this.state = state;
this.bukkitBlock = bukkitBlock; this.bukkitBlock = bukkitBlock;
this.location = location; this.location = location;
this.dropItems = true; this.dropItems = true;
this.player = player;
}
public BukkitServerPlayer player() {
return player;
} }
public boolean dropItems() { public boolean dropItems() {
@@ -44,11 +51,6 @@ public class CustomBlockBreakEvent extends PlayerEvent implements Cancellable {
return bukkitBlock; return bukkitBlock;
} }
@NotNull
public Player player() {
return getPlayer();
}
@NotNull @NotNull
public CustomBlock customBlock() { public CustomBlock customBlock() {
return this.customBlock; return this.customBlock;

View File

@@ -120,7 +120,7 @@ public class BlockEventListener implements Listener {
} }
// trigger event // trigger event
CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(event.getPlayer(), location, block, state); CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(serverPlayer, location, block, state);
boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent); boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent);
if (isCancelled) { if (isCancelled) {
event.setCancelled(true); event.setCancelled(true);
@@ -146,14 +146,10 @@ public class BlockEventListener implements Listener {
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
// do not drop if it's not the correct tool // do not drop if it's not the correct tool
BlockSettings settings = state.settings(); if (!BlockStateUtils.isCorrectTool(state, itemInHand)) {
if (settings.requireCorrectTool()) { return;
if (itemInHand == null) return;
if (!settings.isCorrectTool(itemInHand.id()) &&
(!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(itemInHand.getLiteralObject(), state.customBlockState().handle()))) {
return;
}
} }
// drop items // drop items
ContextHolder.Builder builder = ContextHolder.builder(); ContextHolder.Builder builder = ContextHolder.builder();
builder.withParameter(LootParameters.WORLD, world); builder.withParameter(LootParameters.WORLD, world);

View File

@@ -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<String> 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<String>) 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) : "");
}
}

View File

@@ -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.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; 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.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
@@ -165,6 +166,10 @@ public class BukkitCraftEngine extends CraftEngine {
PlaceholderAPIUtils.registerExpansions(this); PlaceholderAPIUtils.registerExpansions(this);
this.hasPlaceholderAPI = true; this.hasPlaceholderAPI = true;
} }
// skript
if (this.isPluginEnabled("Skript")) {
EvtCustomBlock.register();
}
} }
@Override @Override

View File

@@ -2,10 +2,8 @@ package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.block.BlockStateParser; import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.PushReaction;
import net.momirealms.craftengine.core.util.Instrument; import net.momirealms.craftengine.core.util.Instrument;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MapColor; import net.momirealms.craftengine.core.util.MapColor;
@@ -14,6 +12,9 @@ import org.bukkit.Bukkit;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.event.block.BlockPhysicsEvent; 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.IdentityHashMap;
import java.util.List; import java.util.List;
@@ -32,6 +33,18 @@ public class BlockStateUtils {
hasInit = true; hasInit = true;
} }
public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item<ItemStack> 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<Object> getAllBlockStates(String blockState) { public static List<Object> getAllBlockStates(String blockState) {
int index = blockState.indexOf('['); int index = blockState.indexOf('[');
if (index == -1) { if (index == -1) {

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.world; 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.compatibility.slimeworld.SlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
@@ -61,8 +62,23 @@ public class BukkitWorldManager implements WorldManager, Listener {
return; return;
} catch (ClassNotFoundException ignored) { } 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 @Override

View File

@@ -4,6 +4,7 @@ include(":core")
include(":bukkit") include(":bukkit")
include(":bukkit:legacy") include(":bukkit:legacy")
include(":bukkit:compatibility") include(":bukkit:compatibility")
include(":bukkit:compatibility:legacy")
include(":bukkit:loader") include(":bukkit:loader")
include(":server-mod:v1_20_1") include(":server-mod:v1_20_1")
include(":server-mod:v1_20_5") include(":server-mod:v1_20_5")
@@ -18,4 +19,4 @@ pluginManagement {
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
maven("https://maven.fabricmc.net/") maven("https://maven.fabricmc.net/")
} }
} }