9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-27 10:59:07 +00:00

Merge pull request #143 from Xiao-MoMi/main

更新上游
This commit is contained in:
XiaoMoMi
2025-04-27 03:01:20 +08:00
committed by GitHub
140 changed files with 3617 additions and 1616 deletions

View File

@@ -91,7 +91,7 @@ Given the extensive and intricate nature of plugin configurations, a modular tem
The plugin enables model inheritance and texture overrides through configuration, while supporting [all item models](https://misode.github.io/assets/item/) from version 1.21.4 onward. It incorporates a version migration system that automatically downgrades 1.21.4+ item models to legacy formats with maximum backward compatibility.
### Breaking Changes You Have to Know & Possible Incompatibility with Other Plugins
- CraftEngine injects into PalettedContainer to ensure efficient storage and synchronization of plugin block data. This may cause conflicts with some other plugins that modify the palette. When analyzing server performance using Spark, palette operation overhead will be attributed to the CraftEngine plugin in the profiling results..
- CraftEngine injects into PalettedContainer to ensure efficient storage and synchronization of plugin block data. This may cause conflicts with some other plugins that modify the palette. When analyzing server performance using Spark, palette operation overhead will be attributed to the CraftEngine plugin in the profiling results.
- CraftEngine injects into FurnaceBlockEntity to modify its recipe fetching logic.
- CraftEngine uses real server-side blocks, any plugin relying on Bukkit's Material class will fail to correctly identify custom block types. The proper approach is to use alternatives like BlockState#getBlock (mojmap) instead of the Material class.
- CraftEngine implements 0-tick collision entities by extending certain Minecraft entities, ensuring hard collision works correctly on the server side (e.g., making a pig stand on a chair). However, some anti-cheat plugins do not check entity AABB (Axis-Aligned Bounding Box) properly when detecting player movement, which may lead to false flags.

View File

@@ -13,7 +13,6 @@ repositories {
dependencies {
compileOnly(project(":core"))
compileOnly(project(":shared"))
compileOnly(project(":bukkit:compatibility"))
compileOnly(project(":bukkit:legacy"))
// Anti Grief
compileOnly("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")

View File

@@ -9,11 +9,17 @@ repositories {
maven("https://repo.momirealms.net/releases/")
maven("https://mvn.lumine.io/repository/maven-public/") // model engine
maven("https://nexus.phoenixdevt.fr/repository/maven-public/") // mmoitems
maven("https://repo.viaversion.com") // via
maven("https://repo.skriptlang.org/releases/") // skript
}
dependencies {
compileOnly(project(":core"))
compileOnly(project(":bukkit"))
compileOnly(project(":bukkit:compatibility:legacy"))
compileOnly("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}")
// NMS
compileOnly("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}")
// Platform
compileOnly("io.papermc.paper:paper-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT")
// NeigeItems
@@ -34,6 +40,10 @@ dependencies {
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")
// LuckPerms
compileOnly("net.luckperms:api:5.4")
// viaversion
compileOnly("com.viaversion:viaversion-api:5.3.2")
// Skript
compileOnly("com.github.SkriptLang:Skript:2.11.0")
}
java {

View File

@@ -0,0 +1,31 @@
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.rapture.pw/repository/maven-releases/")
maven("https://repo.momirealms.net/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,80 @@
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.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

@@ -0,0 +1,199 @@
package net.momirealms.craftengine.bukkit.compatibility;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelModel;
import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsProvider;
import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider;
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel;
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils;
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils;
import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners;
import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook;
import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.compatibility.viaversion.ViaVersionUtils;
import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockRegister;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.CompatibilityManager;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldManager;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.util.UUID;
public class BukkitCompatibilityManager implements CompatibilityManager {
private final BukkitCraftEngine plugin;
private boolean hasPlaceholderAPI;
private boolean hasViaVersion;
public BukkitCompatibilityManager(BukkitCraftEngine plugin) {
this.plugin = plugin;
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
this.initSlimeWorldHook();
if (this.isPluginEnabled("PlaceholderAPI")) {
PlaceholderAPIUtils.registerExpansions(this.plugin);
this.hasPlaceholderAPI = true;
logHook("PlaceholderAPI");
}
// skript
if (this.isPluginEnabled("Skript")) {
SkriptHook.register();
logHook("Skript");
Plugin skriptPlugin = getPlugin("Skript");
// This can cause bugs, needs to find a better way
// for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) {
// if (task.getOwner() == skriptPlugin) {
// task.cancel();
// if (VersionHelper.isFolia()) {
// Bukkit.getGlobalRegionScheduler().run(skriptPlugin, (t) -> {
// FastNMS.INSTANCE.getBukkitTaskRunnable(task).run();
// });
// } else {
// Bukkit.getScheduler().runTask(skriptPlugin, FastNMS.INSTANCE.getBukkitTaskRunnable(task));
// }
// }
// }
}
}
@Override
public void onDelayedEnable() {
this.initItemHooks();
// WorldEdit
if (this.isPluginEnabled("FastAsyncWorldEdit")) {
this.initFastAsyncWorldEditHook();
logHook("FastAsyncWorldEdit");
} else if (this.isPluginEnabled("WorldEdit")) {
this.initWorldEditHook();
logHook("WorldEdit");
}
if (this.isPluginEnabled("LuckPerms")) {
this.initLuckPermsHook();
logHook("LuckPerms");
}
}
private void logHook(String plugin) {
this.plugin.logger().info("[Compatibility] " + plugin + " hooked");
}
@Override
public AbstractExternalModel createModelEngineModel(String id) {
return new ModelEngineModel(id);
}
@Override
public AbstractExternalModel createBetterModelModel(String id) {
return new BetterModelModel(id);
}
@Override
public int interactionToBaseEntity(int id) {
return ModelEngineUtils.interactionToBaseEntity(id);
}
private void initLuckPermsHook() {
new LuckPermsEventListeners(plugin.bootstrap(), (uuid) -> {
BukkitFontManager fontManager = (BukkitFontManager) plugin.fontManager();
fontManager.refreshEmojiSuggestions(uuid);
});
}
private void initSlimeWorldHook() {
WorldManager worldManager = this.plugin.worldManager();
if (VersionHelper.isOrAbove1_21_4()) {
try {
Class.forName("com.infernalsuite.asp.api.AdvancedSlimePaperAPI");
SlimeFormatStorageAdaptor adaptor = new SlimeFormatStorageAdaptor(worldManager);
worldManager.setStorageAdaptor(adaptor);
Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap());
logHook("AdvancedSlimePaper");
} catch (ClassNotFoundException ignored) {
}
} else {
try {
Class.forName("com.infernalsuite.aswm.api.SlimePlugin");
LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(worldManager, 1);
worldManager.setStorageAdaptor(adaptor);
Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap());
logHook("AdvancedSlimePaper");
} catch (ClassNotFoundException ignored) {
if (Bukkit.getPluginManager().isPluginEnabled("SlimeWorldPlugin")) {
LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(worldManager, 2);
worldManager.setStorageAdaptor(adaptor);
Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap());
logHook("AdvancedSlimePaper");
}
}
}
}
private void initFastAsyncWorldEditHook() {
new WorldEditBlockRegister(BukkitBlockManager.instance(), true);
}
private void initWorldEditHook() {
WorldEditBlockRegister weBlockRegister = new WorldEditBlockRegister(BukkitBlockManager.instance(), false);
try {
for (Key newBlockId : BukkitBlockManager.instance().blockRegisterOrder()) {
weBlockRegister.register(newBlockId);
}
} catch (Exception e) {
this.plugin.logger().warn("Failed to initialize world edit hook", e);
}
}
private void initItemHooks() {
BukkitItemManager itemManager = BukkitItemManager.instance();
if (this.isPluginEnabled("NeigeItems")) {
itemManager.registerExternalItemProvider(new NeigeItemsProvider());
logHook("NeigeItems");
}
if (this.isPluginEnabled("MMOItems")) {
itemManager.registerExternalItemProvider(new MMOItemsProvider());
logHook("MMOItems");
}
}
private Plugin getPlugin(String name) {
return Bukkit.getPluginManager().getPlugin(name);
}
@Override
public boolean hasPlaceholderAPI() {
return this.hasPlaceholderAPI;
}
@Override
public boolean isPluginEnabled(String plugin) {
return Bukkit.getPluginManager().isPluginEnabled(plugin);
}
@Override
public boolean hasPlugin(String plugin) {
return Bukkit.getPluginManager().getPlugin(plugin) != null;
}
@Override
public String parse(Player player, String text) {
return PlaceholderAPIUtils.parse((org.bukkit.entity.Player) player.platformPlayer(), text);
}
@Override
public int getPlayerProtocolVersion(UUID uuid) {
return ViaVersionUtils.getPlayerProtocolVersion(uuid);
}
}

View File

@@ -16,7 +16,6 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.logging.Level;
public class LuckPermsEventListeners {
private final JavaPlugin plugin;
@@ -42,16 +41,16 @@ public class LuckPermsEventListeners {
this.subscriptions.add(eventBus.subscribe(this.plugin, GroupDataRecalculateEvent.class, this::onGroupPermissionChange));
}
public void unregisterListeners() {
this.subscriptions.forEach(subscription -> {
try {
subscription.close();
} catch (Exception e) {
this.plugin.getLogger().log(Level.WARNING, "Failed to close event subscription", e);
}
});
this.subscriptions.clear();
}
// public void unregisterListeners() {
// this.subscriptions.forEach(subscription -> {
// try {
// subscription.close();
// } catch (Exception e) {
// this.plugin.getLogger().log(Level.WARNING, "Failed to close event subscription", e);
// }
// });
// this.subscriptions.clear();
// }
private void onUserPermissionChange(UserDataRecalculateEvent event) {
CraftEngine.instance().scheduler().async().execute(() -> {

View File

@@ -0,0 +1,34 @@
package net.momirealms.craftengine.bukkit.compatibility.skript;
import net.momirealms.craftengine.bukkit.compatibility.skript.clazz.CraftEngineClasses;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomItem;
import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffRemoveFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomBlock;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomClick;
import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomFurniture;
import net.momirealms.craftengine.bukkit.compatibility.skript.expression.*;
public class SkriptHook {
public static void register() {
CraftEngineClasses.register();
EvtCustomBlock.register();
EvtCustomFurniture.register();
EvtCustomClick.register();
CondIsCustomBlock.register();
CondIsFurniture.register();
CondIsCustomItem.register();
ExprBlockCustomBlockID.register();
ExprItemCustomItemID.register();
ExprBlockCustomBlockState.register();
ExprCustomItem.register();
ExprEntityFurnitureID.register();
EffPlaceCustomBlock.register();
EffPlaceFurniture.register();
EffRemoveFurniture.register();
}
}

View File

@@ -0,0 +1,127 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.clazz;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.classes.Parser;
import ch.njol.skript.classes.Serializer;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.registrations.Classes;
import ch.njol.yggdrasil.Fields;
import net.momirealms.craftengine.core.block.BlockStateParser;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
import org.jetbrains.annotations.Nullable;
import java.io.StreamCorruptedException;
public class CraftEngineClasses {
public static void register() {
Classes.registerClass(new ClassInfo<>(ImmutableBlockState.class, "customblockstate")
.user("custom block state")
.name("Custom Block State")
.serializer(new Serializer<>() {
@Override
public Fields serialize(ImmutableBlockState o) {
Fields f = new Fields();
f.putObject("customblockstate", o.toString());
return f;
}
@Override
public void deserialize(ImmutableBlockState o, Fields f) {
}
@Override
public ImmutableBlockState deserialize(Fields f) throws StreamCorruptedException {
String data = f.getObject("customblockstate", String.class);
assert data != null;
try {
return BlockStateParser.deserialize(data);
} catch (IllegalArgumentException ex) {
throw new StreamCorruptedException("Invalid block data: " + data);
}
}
@Override
public boolean mustSyncDeserialization() {
return true;
}
@Override
protected boolean canBeInstantiated() {
return false;
}
})
.parser(new Parser<>() {
@Override
public String toString(ImmutableBlockState o, int flags) {
return o.toString();
}
@Override
public String toVariableNameString(ImmutableBlockState o) {
return "customblockstate:" + o.toString();
}
@Override
public @Nullable ImmutableBlockState parse(String s, ParseContext context) {
return BlockStateParser.deserialize(s);
}
})
);
Classes.registerClass(new ClassInfo<>(UnsafeBlockStateMatcher.class, "unsafeblockstatematcher")
.user("unsafe block state matcher")
.name("Unsafe Block State Matcher")
.serializer(new Serializer<>() {
@Override
public Fields serialize(UnsafeBlockStateMatcher o) {
Fields f = new Fields();
f.putObject("unsafeblockstatematcher", o.toString());
return f;
}
@Override
public void deserialize(UnsafeBlockStateMatcher o, Fields f) {
}
@Override
public UnsafeBlockStateMatcher deserialize(Fields f) throws StreamCorruptedException {
String data = f.getObject("unsafeblockstatematcher", String.class);
assert data != null;
try {
return UnsafeBlockStateMatcher.deserialize(data);
} catch (IllegalArgumentException ex) {
throw new StreamCorruptedException("Invalid block matcher: " + data);
}
}
@Override
public boolean mustSyncDeserialization() {
return true;
}
@Override
protected boolean canBeInstantiated() {
return false;
}
})
.parser(new Parser<>() {
@Override
public String toString(UnsafeBlockStateMatcher o, int flags) {
return o.toString();
}
@Override
public String toVariableNameString(UnsafeBlockStateMatcher o) {
return "unsafeblockstatematcher:" + o.toString();
}
@Override
public @Nullable UnsafeBlockStateMatcher parse(String s, ParseContext context) {
return UnsafeBlockStateMatcher.deserialize(s);
}
})
);
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.condition;
import ch.njol.skript.Skript;
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
public class CondIsCustomBlock extends Condition {
public static void register() {
Skript.registerCondition(CondIsCustomBlock.class,
"%blocks% (is|are) custom block(s)",
"%blocks% (is|are)(n't| not) custom block(s)");
}
private Expression<Block> blocks;
@Override
public boolean check(Event event) {
return blocks.check(event, CraftEngineBlocks::isCustomBlock, isNegated());
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, blocks, "custom block");
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
blocks = (Expression<Block>) expressions[0];
setNegated(matchedPattern > 1);
return true;
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.condition;
import ch.njol.skript.Skript;
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public class CondIsCustomItem extends Condition {
public static void register() {
Skript.registerCondition(CondIsCustomItem.class,
"%itemstacks% (is|are) custom item(s)",
"%itemstacks% (is|are)(n't| not) custom item(s)");
}
private Expression<ItemStack> items;
@Override
public boolean check(Event event) {
return items.check(event, CraftEngineItems::isCustomItem, isNegated());
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, items, "itemstack");
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
items = (Expression<ItemStack>) expressions[0];
setNegated(matchedPattern > 1);
return true;
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.condition;
import ch.njol.skript.Skript;
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
public class CondIsFurniture extends Condition {
public static void register() {
Skript.registerCondition(CondIsFurniture.class,
"%entities% (is|are) furniture",
"%entities% (is|are)(n't| not) furniture");
}
private Expression<Entity> entities;
@Override
public boolean check(Event event) {
return entities.check(event, CraftEngineFurniture::isFurniture, isNegated());
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, entities, "furniture");
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
entities = (Expression<Entity>) expressions[0];
setNegated(matchedPattern > 1);
return true;
}
}

View File

@@ -0,0 +1,46 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.effect;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.util.Direction;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
public class EffPlaceCustomBlock extends Effect {
public static void register() {
Skript.registerEffect(EffPlaceCustomBlock.class, "place custom block %customblockstates% [%directions% %locations%]");
}
private Expression<ImmutableBlockState> blocks;
private Expression<Location> locations;
@Override
protected void execute(Event e) {
ImmutableBlockState[] os = blocks.getArray(e);
for (Location l : locations.getArray(e)) {
for (ImmutableBlockState o : os) {
CraftEngineBlocks.place(l, o, false);
}
}
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "place custom block " + blocks.toString(event, debug) + " " + locations.toString(event, debug);
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
blocks = (Expression<ImmutableBlockState>) expressions[0];
locations = Direction.combine((Expression<? extends Direction>) expressions[1], (Expression<? extends Location>) expressions[2]);
return true;
}
}

View File

@@ -0,0 +1,46 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.effect;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.util.Direction;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
public class EffPlaceFurniture extends Effect {
public static void register() {
Skript.registerEffect(EffPlaceFurniture.class, "place furniture %strings% [%directions% %locations%]");
}
private Expression<String> furniture;
private Expression<Location> locations;
@Override
protected void execute(Event e) {
String[] os = furniture.getArray(e);
for (Location l : locations.getArray(e)) {
for (String o : os) {
CraftEngineFurniture.place(l, Key.of(o));
}
}
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "place furniture " + furniture.toString(event, debug) + " " + locations.toString(event, debug);
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
furniture = (Expression<String>) expressions[0];
locations = Direction.combine((Expression<? extends Direction>) expressions[1], (Expression<? extends Location>) expressions[2]);
return true;
}
}

View File

@@ -0,0 +1,45 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.effect;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
public class EffRemoveFurniture extends Effect {
public static void register() {
Skript.registerEffect(EffRemoveFurniture.class, "remove furniture %entities%");
}
private Expression<Entity> entities;
@Override
protected void execute(Event e) {
for (Entity entity : entities.getArray(e)) {
if (CraftEngineFurniture.isFurniture(entity)) {
LoadedFurniture loadedFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity);
if (loadedFurniture != null) {
loadedFurniture.destroy();
}
}
}
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "remove furniture " + entities.toString(event, debug);
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
this.entities = (Expression<Entity>) expressions[0];
return true;
}
}

View File

@@ -0,0 +1,69 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.event;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
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.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
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, "(break[ing]|1¦min(e|ing)) [[of] %-unsafeblockstatematchers%]")
.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, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-unsafeblockstatematchers%]")
.description("Called when a player places a custom block.");
}
@Nullable
private Literal<UnsafeBlockStateMatcher> blocks;
private UnsafeBlockStateMatcher[] blockArray;
private boolean mine = false;
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parser) {
if (args[0] != null) {
blocks = ((Literal<UnsafeBlockStateMatcher>) 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;
ImmutableBlockState state;
if (event instanceof CustomBlockBreakEvent customBlockBreakEvent) {
state = customBlockBreakEvent.blockState();
} else if (event instanceof CustomBlockPlaceEvent customBlockPlaceEvent) {
state = customBlockPlaceEvent.blockState();
} else {
return false;
}
return Arrays.stream(blockArray).anyMatch(block -> block.matches(state));
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "break/place" + (blocks != null ? " of " + blocks.toString(event, debug) : "");
}
}

View File

@@ -0,0 +1,110 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.event;
import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.bukkitutil.ClickEventTracker;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.event.Event;
import org.bukkit.inventory.EquipmentSlot;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
public class EvtCustomClick extends SkriptEvent {
private final static int RIGHT = 1, LEFT = 2, ANY = RIGHT | LEFT;
public final static ClickEventTracker interactTracker = new ClickEventTracker(Skript.getInstance());
public static void register() {
Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class},
"[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]",
"[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%");
}
private @Nullable Literal<?> type;
private @Nullable Literal<ItemType> tools;
private int click = ANY;
@Override
public boolean check(Event event) {
ImmutableBlockState block;
String furnitureId;
if (event instanceof CustomBlockInteractEvent interactEvent) {
furnitureId = null;
CustomBlockInteractEvent.Action action = interactEvent.action();
int click;
switch (action) {
case LEFT_CLICK -> click = LEFT;
case RIGHT_CLICK -> click = RIGHT;
default -> {
return false;
}
}
if ((this.click & click) == 0)
return false;
EquipmentSlot hand = interactEvent.hand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND;
if (!interactTracker.checkEvent(interactEvent.getPlayer(), interactEvent, hand)) {
return false;
}
block = interactEvent.blockState();
} else if (event instanceof FurnitureInteractEvent interactEvent) {
furnitureId = interactEvent.furniture().id().toString();
block = null;
if ((this.click & RIGHT) == 0)
return false;
} else {
return false;
}
Predicate<ItemType> checker = itemType -> {
if (event instanceof CustomBlockInteractEvent event1) {
return itemType.isOfType(event1.item());
} else if (event instanceof FurnitureInteractEvent event1) {
return itemType.isOfType(event1.player().getInventory().getItem(event1.hand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND));
} else {
return false;
}
};
if (tools != null && !tools.check(event, checker))
return false;
if (type != null) {
return type.check(event, (Predicate<Object>) object -> {
if (object instanceof String id && furnitureId != null) {
return id.equals(furnitureId);
} else if (object instanceof UnsafeBlockStateMatcher matcher && block != null) {
return matcher.matches(block);
}
return false;
});
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parseResult) {
click = parseResult.mark == 0 ? ANY : parseResult.mark;
type = args[matchedPattern];
tools = (Literal<ItemType>) args[1 - matchedPattern];
return true;
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return switch (click) {
case LEFT -> "left";
case RIGHT -> "right";
default -> "";
} + "click" + (type != null ? " on " + type.toString(event, debug) : "") +
(tools != null ? " holding " + tools.toString(event, debug) : "");
}
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.event;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
@SuppressWarnings({"unchecked"})
public class EvtCustomFurniture extends SkriptEvent {
public static void register() {
Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) [[of] %-strings%]")
.description("Called when a furniture is broken by a player.");
Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-strings%]")
.description("Called when a player places a furniture.");
}
@Nullable
private Literal<String> ids;
private String[] idArray;
@Override
public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parser) {
if (args[0] != null) {
ids = ((Literal<String>) args[0]);
idArray = ids.getAll();
}
return true;
}
@Override
public boolean check(Event event) {
if (ids == null)
return true;
String id;
if (event instanceof FurnitureBreakEvent e) {
id = e.furniture().id().toString();
} else if (event instanceof FurniturePlaceEvent e) {
id = e.furniture().id().toString();
} else {
return false;
}
return Arrays.asList(idArray).contains(id);
}
@Override
public String toString(@Nullable Event event, boolean debug) {
return "break/place" + (ids != null ? " of " + ids.toString(event, debug) : "");
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class ExprBlockCustomBlockID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprBlockCustomBlockID.class, String.class, "custom block id", "blocks/blockdata/customblockstates");
}
@Override
public @Nullable String convert(Object object) {
if (object instanceof ImmutableBlockState immutableBlockState)
return immutableBlockState.owner().value().id().toString();
if (object instanceof CustomBlock customBlock)
return customBlock.id().toString();
if (object instanceof Block block)
return Optional.ofNullable(CraftEngineBlocks.getCustomBlockState(block)).map(it -> it.owner().value().id().toString()).orElse(null);
if (object instanceof BlockData blockData)
return Optional.ofNullable(CraftEngineBlocks.getCustomBlockState(blockData)).map(it -> it.owner().value().id().toString()).orElse(null);
return null;
}
@Override
protected String getPropertyName() {
return "custom block id";
}
@Override
public Class<? extends String> getReturnType() {
return String.class;
}
}

View File

@@ -0,0 +1,34 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
public class ExprBlockCustomBlockState extends SimplePropertyExpression<Object, ImmutableBlockState> {
public static void register() {
register(ExprBlockCustomBlockState.class, ImmutableBlockState.class, "custom block[ ]state", "blocks/blockdata");
}
@Override
public @Nullable ImmutableBlockState convert(Object object) {
if (object instanceof Block block)
return CraftEngineBlocks.getCustomBlockState(block);
if (object instanceof BlockData blockData)
return CraftEngineBlocks.getCustomBlockState(blockData);
return null;
}
@Override
protected String getPropertyName() {
return "custom block state";
}
@Override
public Class<? extends ImmutableBlockState> getReturnType() {
return ImmutableBlockState.class;
}
}

View File

@@ -0,0 +1,56 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.Skript;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class ExprCustomItem extends SimpleExpression<ItemStack> {
public static void register() {
Skript.registerExpression(ExprCustomItem.class, ItemStack.class, ExpressionType.SIMPLE, "[(the|a)] custom item [with id] %string%");
}
private Expression<String> itemId;
@Override
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
itemId = (Expression<String>) exprs[0];
return true;
}
@Override
@Nullable
protected ItemStack[] get(Event e) {
String itemId = this.itemId.getSingle(e);
if (itemId == null)
return null;
return new ItemStack[] {Objects.requireNonNull(CraftEngineItems.byId(Key.of(itemId))).buildItemStack(ItemBuildContext.EMPTY)};
}
@Override
public boolean isSingle() {
return true;
}
@Override
public Class<ItemStack> getReturnType() {
return ItemStack.class;
}
@Override
public String toString(@Nullable Event e, boolean debug) {
return "the custom item with id " + itemId.toString(e, debug);
}
}

View File

@@ -0,0 +1,32 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class ExprEntityFurnitureID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprEntityFurnitureID.class, String.class, "furniture id", "entities");
}
@Override
public @Nullable String convert(Object object) {
if (object instanceof Entity entity && CraftEngineFurniture.isFurniture(entity))
return Objects.requireNonNull(CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity)).id().toString();
return null;
}
@Override
protected String getPropertyName() {
return "furniture id";
}
@Override
public Class<? extends String> getReturnType() {
return String.class;
}
}

View File

@@ -0,0 +1,65 @@
package net.momirealms.craftengine.bukkit.compatibility.skript.expression;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.Changer;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import ch.njol.util.coll.CollectionUtils;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class ExprItemCustomItemID extends SimplePropertyExpression<Object, String> {
public static void register() {
register(ExprItemCustomItemID.class, String.class, "custom item id", "itemstacks/itemtypes");
}
@Override
public @Nullable String convert(Object object) {
if (object instanceof ItemStack itemStack)
return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null);
if (object instanceof ItemType itemType) {
ItemStack itemStack = new ItemStack(itemType.getMaterial());
itemStack.setItemMeta(itemType.getItemMeta());
return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null);
}
return null;
}
@Override
protected String getPropertyName() {
return "custom item id";
}
@Override
public Class<? extends String> getReturnType() {
return String.class;
}
@Override
public Class<?>[] acceptChange(Changer.ChangeMode mode) {
return CollectionUtils.array(String.class);
}
@Override
public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) {
Key id = Key.of((String) delta[0]);
for (Object item : getExpr().getArray(e)) {
if (item instanceof ItemStack itemStack) {
Item<ItemStack> item1 = BukkitItemManager.instance().wrap(itemStack);
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
item1.merge(item2);
item1.load();
} else if (item instanceof ItemType itemType) {
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
itemType.setItemMeta(item2.load().getItemMeta());
}
}
}
}

View File

@@ -2,13 +2,15 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld;
import com.infernalsuite.asp.api.world.SlimeChunk;
import com.infernalsuite.asp.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.Nullable;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map;
@@ -25,15 +27,16 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
return slimeWorld.get();
}
@Nullable
@Override
public CompoundTag readChunkTagAt(ChunkPos pos) {
public @NotNull CEChunk readChunkAt(@NotNull CEWorld world, @NotNull ChunkPos pos) {
SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z);
if (slimeChunk == null) return null;
if (slimeChunk == null) return new CEChunk(world, pos);
Object tag = slimeChunk.getExtraData().get("craftengine");
if (tag == null) return null;
if (tag == null) return new CEChunk(world, pos);
try {
return NBT.fromBytes(adaptor.byteArrayTagToBytes(tag));
CompoundTag compoundTag = NBT.fromBytes(adaptor.byteArrayTagToBytes(tag));
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);
}
@@ -41,9 +44,10 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
@SuppressWarnings("unchecked")
@Override
public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) {
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().remove("craftengine");
} else {
@@ -63,6 +67,6 @@ public class SlimeWorldDataStorage implements WorldDataStorage {
}
@Override
public void close() throws IOException {
public void close() {
}
}

View File

@@ -0,0 +1,14 @@
package net.momirealms.craftengine.bukkit.compatibility.viaversion;
import com.viaversion.viaversion.api.Via;
import java.util.UUID;
public final class ViaVersionUtils {
private ViaVersionUtils() {}
public static int getPlayerProtocolVersion(UUID uuid) {
return Via.getAPI().getPlayerProtocolVersion(uuid).getVersion();
}
}

View File

@@ -25,7 +25,7 @@ public class WorldEditBlockRegister {
private final boolean isFAWE;
public WorldEditBlockRegister(AbstractBlockManager manager, boolean isFAWE) {
field$BlockType$blockMaterial = ReflectionUtils.getDeclaredField(BlockType.class, "blockMaterial");
this.field$BlockType$blockMaterial = ReflectionUtils.getDeclaredField(BlockType.class, "blockMaterial");
this.manager = manager;
this.isFAWE = isFAWE;
CEBlockParser blockParser = new CEBlockParser(WorldEdit.getInstance());
@@ -34,7 +34,7 @@ public class WorldEditBlockRegister {
public void register(Key id) throws ReflectiveOperationException {
BlockType blockType = new BlockType(id.toString(), blockState -> blockState);
field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE)));
this.field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE)));
BlockType.REGISTRY.register(id.toString(), blockType);
}

View File

@@ -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
}

View File

@@ -343,6 +343,8 @@ light-system:
force-update-light: false
chunk-system:
# Unloaded chunks may be loaded soon. Delaying serialization can improve performance, especially for those double-dimension mob farms.
delay-serialization: 20 # seconds -1 = disable
# 1 = NONE | Compression Speed | Decompress Speed | Compression Ratio | Memory Usage |
# 2 = DEFLATE | Medium-Slow Medium Moderate Low |
# 3 = GZIP | Medium-Slow Medium Moderate Low |

View File

@@ -0,0 +1,32 @@
package net.momirealms.craftengine.bukkit.api;
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public final class BukkitAdaptors {
private BukkitAdaptors() {}
public static BukkitServerPlayer adapt(final Player player) {
return BukkitCraftEngine.instance().adapt(player);
}
public static BukkitWorld adapt(final World world) {
return new BukkitWorld(world);
}
public static BukkitEntity adapt(final Entity entity) {
return new BukkitEntity(entity);
}
public static BukkitWorldBlock adapt(final Block block) {
return new BukkitWorldBlock(block);
}
}

View File

@@ -30,6 +30,8 @@ import org.jetbrains.annotations.Nullable;
public final class CraftEngineBlocks {
private CraftEngineBlocks() {}
/**
* Gets a custom block by ID
*
@@ -122,7 +124,7 @@ public final class CraftEngineBlocks {
}
/**
* Removes a block from the world if it's a custom one
* Removes a block from the world if it's custom
*
* @param block block to remove
* @return success or not
@@ -134,7 +136,7 @@ public final class CraftEngineBlocks {
}
/**
* Removes a block from the world if it's a custom one
* Removes a block from the world if it's custom
*
* @param block block to remove
* @param applyPhysics whether to apply physics
@@ -148,7 +150,7 @@ public final class CraftEngineBlocks {
}
/**
* Removes a block from the world if it's a custom one
* Removes a block from the world if it's custom
*
* @param block block to remove
* @param player player who breaks the block
@@ -191,7 +193,7 @@ public final class CraftEngineBlocks {
}
/**
* Checks if a block is a custom one
* Checks if a block is custom
*
* @param block block
* @return is custom block or not
@@ -234,7 +236,7 @@ public final class CraftEngineBlocks {
* @return bukkit block data
*/
@NotNull
public static BlockData createBukkitBlockData(@NotNull ImmutableBlockState blockState) {
public static BlockData getBukkitBlockData(@NotNull ImmutableBlockState blockState) {
return BlockStateUtils.fromBlockData(blockState.customBlockState().handle());
}
}

View File

@@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.api;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
@@ -25,7 +27,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public class CraftEngineFurniture {
public final class CraftEngineFurniture {
private CraftEngineFurniture() {}
/**
* Gets custom furniture by ID
@@ -120,6 +124,17 @@ public class CraftEngineFurniture {
return furnitureId != null;
}
/**
* Check if an entity is a collision entity
*
* @param entity entity to check
* @return is collision entity or not
*/
public static boolean isCollisionEntity(@NotNull Entity entity) {
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(entity);
return nmsEntity instanceof CollisionEntity;
}
/**
* Check if an entity is a seat
*

View File

@@ -8,7 +8,9 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CraftEngineItems {
public final class CraftEngineItems {
private CraftEngineItems() {}
/**
* Gets a custom item by ID

View File

@@ -1,10 +1,10 @@
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;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
@@ -18,17 +18,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 +50,6 @@ public class CustomBlockBreakEvent extends PlayerEvent implements Cancellable {
return bukkitBlock;
}
@NotNull
public Player player() {
return getPlayer();
}
@NotNull
public CustomBlock customBlock() {
return this.customBlock;

View File

@@ -10,6 +10,8 @@ import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,6 +26,7 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
private final InteractionHand hand;
private final Action action;
private final BlockFace clickedFace;
private final ItemStack item;
public CustomBlockInteractEvent(@NotNull Player player,
@NotNull Location location,
@@ -32,7 +35,8 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
@NotNull Block bukkitBlock,
@NotNull BlockFace clickedFace,
@NotNull InteractionHand hand,
@NotNull Action action) {
@NotNull Action action,
@Nullable ItemStack item) {
super(player);
this.customBlock = state.owner().value();
this.bukkitBlock = bukkitBlock;
@@ -42,6 +46,7 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
this.hand = hand;
this.action = action;
this.clickedFace = clickedFace;
this.item = item;
}
@NotNull
@@ -89,6 +94,12 @@ public class CustomBlockInteractEvent extends PlayerEvent implements Cancellable
return this.state;
}
@ApiStatus.Experimental
@NotNull
public ItemStack item() {
return this.item;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLER_LIST;

View File

@@ -7,7 +7,6 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.block.BlockSettings;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
@@ -52,7 +51,7 @@ public class BlockEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerAttack(EntityDamageByEntityEvent event) {
if (!VersionHelper.isVersionNewerThan1_20_5()) {
if (!VersionHelper.isOrAbove1_20_5()) {
if (event.getDamager() instanceof Player player) {
BukkitServerPlayer serverPlayer = plugin.adapt(player);
serverPlayer.setClientSideCanBreakBlock(true);
@@ -120,7 +119,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 +145,10 @@ public class BlockEventListener implements Listener {
Item<ItemStack> 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);
@@ -311,7 +306,7 @@ public class BlockEventListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onEntityExplode(EntityExplodeEvent event) {
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
if (!ExplosionUtils.isDroppingItems(event)) return;
}
handleExplodeEvent(event.blockList(), new BukkitWorld(event.getEntity().getWorld()), event.getYield());
@@ -319,7 +314,7 @@ public class BlockEventListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onBlockExplode(BlockExplodeEvent event) {
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
if (!ExplosionUtils.isDroppingItems(event)) return;
}
handleExplodeEvent(event.blockList(), new BukkitWorld(event.getBlock().getWorld()), event.getYield());

View File

@@ -7,7 +7,6 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.dejvokep.boostedyaml.YamlDocument;
import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockRegister;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector;
@@ -108,7 +107,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
if (enableNoteBlocks) {
this.recordVanillaNoteBlocks();
}
if (VersionHelper.isVersionNewerThan1_20_3()) {
if (VersionHelper.isOrAbove1_20_3()) {
this.fallingBlockRemoveListener = new FallingBlockRemoveListener();
} else this.fallingBlockRemoveListener = null;
this.stateId2ImmutableBlockStates = new ImmutableBlockState[customBlockCount];
@@ -117,6 +116,10 @@ public class BukkitBlockManager extends AbstractBlockManager {
this.resetPacketConsumers();
}
public List<Key> blockRegisterOrder() {
return Collections.unmodifiableList(this.blockRegisterOrder);
}
public static BukkitBlockManager instance() {
return instance;
}
@@ -127,12 +130,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
if (this.fallingBlockRemoveListener != null) {
Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, plugin.bootstrap());
}
// WorldEdit
if (this.plugin.isPluginEnabled("FastAsyncWorldEdit")) {
this.initFastAsyncWorldEditHook();
} else if (this.plugin.isPluginEnabled("WorldEdit")) {
this.initWorldEditHook();
}
}
@Override
@@ -171,20 +168,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
this.tempVanillaBlockStateModels.clear();
}
public void initFastAsyncWorldEditHook() {
new WorldEditBlockRegister(this, true);
}
public void initWorldEditHook() {
WorldEditBlockRegister weBlockRegister = new WorldEditBlockRegister(this, false);
try {
for (Key newBlockId : this.blockRegisterOrder) {
weBlockRegister.register(newBlockId);
}
} catch (Exception e) {
this.plugin.logger().warn("Failed to initialize world edit hook", e);
}
}
@Nullable
public Object getMinecraftBlockHolder(int stateId) {

View File

@@ -107,7 +107,7 @@ public class BukkitCustomBlock extends CustomBlock {
Reflections.method$BlockStateBase$initCache.invoke(mcBlockState);
// set block light
if (settings.blockLight() != -1) {
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Reflections.field$BlockStateBase$lightBlock.set(mcBlockState, settings.blockLight());
} else {
Object cache = Reflections.field$BlockStateBase$cache.get(mcBlockState);

View File

@@ -56,7 +56,7 @@ public class BushBlockBehavior extends BukkitBlockBehavior {
Object level;
Object blockPos;
Object state = args[0];
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
level = args[1];
blockPos = args[3];
} else {

View File

@@ -99,7 +99,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior {
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object level;
Object pos;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
level = args[1];
pos = args[3];
} else {

View File

@@ -42,7 +42,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object world;
Object blockPos;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
world = args[1];
blockPos = args[3];
} else {
@@ -81,7 +81,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
@Override
public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception {
// Use EntityRemoveEvent for 1.20.3+
if (VersionHelper.isVersionNewerThan1_20_3()) return;
if (VersionHelper.isOrAbove1_20_3()) return;
Object level = args[0];
Object fallingBlockEntity = args[2];
boolean cancelDrop = (boolean) Reflections.field$FallingBlockEntity$cancelDrop.get(fallingBlockEntity);

View File

@@ -66,7 +66,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
Object blockPos;
Object neighborState;
Object blockState = args[0];
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
world = args[1];
neighborState = args[6];
blockPos = args[3];

View File

@@ -79,7 +79,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior {
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object world;
Object blockPos;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
world = args[1];
blockPos = args[3];
} else {
@@ -120,7 +120,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior {
int age = currentState.get(ageProperty);
if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
Object abovePos = LocationUtils.above(blockPos);
if (VersionHelper.isVersionNewerThan1_21_5()) {
if (VersionHelper.isOrAbove1_21_5()) {
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
} else {
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle());

View File

@@ -38,6 +38,6 @@ public class DisplayEntityData<T> extends BaseEntityData<T> {
}
public DisplayEntityData(int id, Object serializer, T defaultValue) {
super(!VersionHelper.isVersionNewerThan1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
super(!VersionHelper.isOrAbove1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
}
}

View File

@@ -60,15 +60,15 @@ public class EntityDataValue {
Serializers$OPTIONAL_BLOCK_STATE = initSerializersByName("OPTIONAL_BLOCK_STATE");
Serializers$BOOLEAN = initSerializersByName("BOOLEAN");
Serializers$PARTICLE = initSerializersByName("PARTICLE");
if (VersionHelper.isVersionNewerThan1_20_5()) Serializers$PARTICLES = initSerializersByName("PARTICLES");
if (VersionHelper.isOrAbove1_20_5()) Serializers$PARTICLES = initSerializersByName("PARTICLES");
else Serializers$PARTICLES = null;
Serializers$ROTATIONS = initSerializersByName("ROTATIONS");
Serializers$BLOCK_POS = initSerializersByName("BLOCK_POS");
Serializers$OPTIONAL_BLOCK_POS = initSerializersByName("OPTIONAL_BLOCK_POS");
Serializers$DIRECTION = initSerializersByName("DIRECTION");
if (!VersionHelper.isVersionNewerThan1_21_5()) Serializers$OPTIONAL_UUID = initSerializersByName("OPTIONAL_UUID");
if (!VersionHelper.isOrAbove1_21_5()) Serializers$OPTIONAL_UUID = initSerializersByName("OPTIONAL_UUID");
else Serializers$OPTIONAL_UUID = null;
if (VersionHelper.isVersionNewerThan1_21_5()) Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = initSerializersByName("OPTIONAL_LIVING_ENTITY_REFERENCE");
if (VersionHelper.isOrAbove1_21_5()) Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = initSerializersByName("OPTIONAL_LIVING_ENTITY_REFERENCE");
else Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = null;
Serializers$OPTIONAL_GLOBAL_POS = initSerializersByName("OPTIONAL_GLOBAL_POS");
Serializers$COMPOUND_TAG = initSerializersByName("COMPOUND_TAG");
@@ -76,11 +76,11 @@ public class EntityDataValue {
Serializers$OPTIONAL_UNSIGNED_INT = initSerializersByName("OPTIONAL_UNSIGNED_INT");
Serializers$POSE = initSerializersByName("POSE");
Serializers$CAT_VARIANT = initSerializersByName("CAT_VARIANT");
if (VersionHelper.isVersionNewerThan1_20_5()) Serializers$WOLF_VARIANT = initSerializersByName("WOLF_VARIANT");
if (VersionHelper.isOrAbove1_20_5()) Serializers$WOLF_VARIANT = initSerializersByName("WOLF_VARIANT");
else Serializers$WOLF_VARIANT = null;
Serializers$FROG_VARIANT = initSerializersByName("FROG_VARIANT");
Serializers$PAINTING_VARIANT = initSerializersByName("PAINTING_VARIANT");
if (VersionHelper.isVersionNewerThan1_20_5()) Serializers$ARMADILLO_STATE = initSerializersByName("ARMADILLO_STATE");
if (VersionHelper.isOrAbove1_20_5()) Serializers$ARMADILLO_STATE = initSerializersByName("ARMADILLO_STATE");
else Serializers$ARMADILLO_STATE = null;
Serializers$SNIFFER_STATE = initSerializersByName("SNIFFER_STATE");
Serializers$VECTOR3 = initSerializersByName("VECTOR3");

View File

@@ -13,6 +13,6 @@ public class InteractionEntityData<T> extends BaseEntityData<T> {
}
public InteractionEntityData(int id, Object serializer, T defaultValue) {
super(!VersionHelper.isVersionNewerThan1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
super(!VersionHelper.isOrAbove1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
}
}

View File

@@ -1,7 +1,5 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelModel;
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
@@ -60,7 +58,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
this.plugin = plugin;
this.furnitureParser = new FurnitureParser();
this.furnitureEventListener = new FurnitureEventListener(this);
this.dismountListener = VersionHelper.isVersionNewerThan1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount);
this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount);
}
@Override
@@ -149,9 +147,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
// external model providers
Optional<ExternalModel> externalModel;
if (placementArguments.containsKey("model-engine")) {
externalModel = Optional.of(new ModelEngineModel(placementArguments.get("model-engine").toString()));
externalModel = Optional.of(plugin.compatibilityManager().createModelEngineModel(placementArguments.get("model-engine").toString()));
} else if (placementArguments.containsKey("better-model")) {
externalModel = Optional.of(new BetterModelModel(placementArguments.get("better-model").toString()));
externalModel = Optional.of(plugin.compatibilityManager().createBetterModelModel(placementArguments.get("better-model").toString()));
} else {
externalModel = Optional.empty();
}
@@ -294,7 +292,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
if (previous != null) return;
Location location = display.getLocation();
boolean above1_20_1 = VersionHelper.isVersionNewerThan1_20_2();
boolean above1_20_1 = VersionHelper.isOrAbove1_20_2();
boolean preventChange = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
if (above1_20_1) {
if (!preventChange) {
@@ -453,7 +451,11 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
}
targetLocation.setYaw(player.getLocation().getYaw());
targetLocation.setPitch(player.getLocation().getPitch());
player.teleport(targetLocation);
if (VersionHelper.isFolia()) {
player.teleportAsync(targetLocation);
} else {
player.teleport(targetLocation);
}
}
protected boolean isSeatCarrierType(Entity entity) {

View File

@@ -297,9 +297,9 @@ public class LoadedFurniture implements Furniture {
public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) {
Location location = this.calculateSeatLocation(seat);
Entity seatEntity = seat.limitPlayerRotation() ?
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isVersionNewerThan1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> {
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> {
ArmorStand armorStand = (ArmorStand) entity;
if (VersionHelper.isVersionNewerThan1_21_3()) {
if (VersionHelper.isOrAbove1_21_3()) {
Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01);
} else {
LegacyAttributeUtils.setMaxHealth(armorStand);
@@ -316,7 +316,7 @@ public class LoadedFurniture implements Furniture {
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
}) :
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isVersionNewerThan1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> {
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay itemDisplay = (ItemDisplay) entity;
itemDisplay.setPersistent(false);
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());

View File

@@ -57,7 +57,7 @@ public class CustomHitBox extends AbstractHitBox {
FastNMS.INSTANCE.toNMSEntityType(this.entityType), 0, Reflections.instance$Vec3$Zero, 0
), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true);
if (VersionHelper.isVersionNewerThan1_20_5() && this.scale != 1) {
if (VersionHelper.isOrAbove1_20_5() && this.scale != 1) {
Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Holder$Attribute$scale, (Consumer<?>) (o) -> {});
Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale);
packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityId[0], Collections.singletonList(attributeInstance)), false);

View File

@@ -223,7 +223,7 @@ public class ShulkerHitBox extends AbstractHitBox {
), false);
}
// set shulker scale
if (VersionHelper.isVersionNewerThan1_20_5() && this.scale != 1) {
if (VersionHelper.isOrAbove1_20_5() && this.scale != 1) {
Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Holder$Attribute$scale, (Consumer<?>) (o) -> {});
Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale);
packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance)), false);

View File

@@ -5,7 +5,6 @@ import com.google.gson.JsonObject;
import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent;
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
@@ -35,7 +34,6 @@ import java.util.*;
public class BukkitFontManager extends AbstractFontManager implements Listener {
private final BukkitCraftEngine plugin;
private LuckPermsEventListeners luckPermsEventListeners;
public BukkitFontManager(BukkitCraftEngine plugin) {
super(plugin);
@@ -44,9 +42,6 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
@Override
public void delayedInit() {
if (this.plugin.isPluginEnabled("LuckPerms")) {
luckPermsEventListeners = new LuckPermsEventListeners(plugin.bootstrap(), this::refreshEmojiSuggestions);
}
Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap());
}
@@ -54,9 +49,6 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
public void disable() {
super.disable();
HandlerList.unregisterAll(this);
if (luckPermsEventListeners != null && this.plugin.isPluginEnabled("LuckPerms")) {
luckPermsEventListeners.unregisterListeners();
}
}
@Override
@@ -76,7 +68,8 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
plugin.scheduler().async().execute(() -> this.addEmojiSuggestions(event.getPlayer(), getEmojiSuggestion(event.getPlayer())));
}
private void refreshEmojiSuggestions(UUID uuid) {
@Override
public void refreshEmojiSuggestions(UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
if (player == null) return;
removeEmojiSuggestions(player);
@@ -138,14 +131,14 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
if (result == null) return;
Player player;
try {
player = (Player) Reflections.method$InventoryView$getPlayer.invoke(VersionHelper.isVersionNewerThan1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
player = (Player) Reflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
String renameText;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
AnvilView anvilView = event.getView();
renameText = anvilView.getRenameText();
} else {

View File

@@ -1,7 +1,5 @@
package net.momirealms.craftengine.bukkit.item;
import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsProvider;
import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider;
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.BoneMealItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
@@ -131,16 +129,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
public void delayedInit() {
Bukkit.getPluginManager().registerEvents(this.itemEventListener, this.plugin.bootstrap());
Bukkit.getPluginManager().registerEvents(this.debugStickListener, this.plugin.bootstrap());
this.hookExternalPlugins();
}
private void hookExternalPlugins() {
if (this.plugin.isPluginEnabled("NeigeItems")) {
registerExternalItemProvider(new NeigeItemsProvider());
}
if (this.plugin.isPluginEnabled("MMOItems")) {
registerExternalItemProvider(new MMOItemsProvider());
}
}
public static BukkitItemManager instance() {
@@ -289,7 +277,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData));
}
// Requires the item to have model before apply item-model
else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isVersionNewerThan1_21_2()) {
else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_21_2()) {
// check server version here because components require 1.21.2+
// customize or use the id
itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString());

View File

@@ -22,6 +22,10 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
this.item.setAmount(count);
}
public void removeComponent(Object type) {
FastNMS.INSTANCE.removeComponent(this.getLiteralObject(), ensureDataComponentType(type));
}
public void resetComponent(Object type) {
FastNMS.INSTANCE.resetComponent(this.getLiteralObject(), ensureDataComponentType(type));
}

View File

@@ -29,7 +29,7 @@ public class ComponentTypes {
private ComponentTypes() {}
private static Object getComponentType(Key key) {
if (!VersionHelper.isVersionNewerThan1_20_5()) return null;
if (!VersionHelper.isOrAbove1_20_5()) return null;
return FastNMS.INSTANCE.getComponentType(key.namespace(), key.value());
}
}

View File

@@ -70,7 +70,8 @@ public class ItemEventListener implements Listener {
block,
event.getBlockFace(),
event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND,
action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK,
event.getItem()
);
if (EventUtils.fireAndCheckCancel(interactEvent)) {
event.setCancelled(true);

View File

@@ -96,7 +96,7 @@ public class AxeItemBehavior extends ItemBehavior {
player.swingHand(context.getHand());
}
// shrink item amount
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
Object itemStack = item.getLiteralObject();
Object serverPlayer = player.serverPlayer();
Object equipmentSlot = context.getHand() == InteractionHand.MAIN_HAND ? Reflections.instance$EquipmentSlot$MAINHAND : Reflections.instance$EquipmentSlot$OFFHAND;

View File

@@ -93,7 +93,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
@Override
protected void removeComponent(ComponentItemWrapper item, Object type) {
item.resetComponent(type);
item.removeComponent(type);
}
@Override

View File

@@ -123,10 +123,10 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRANSFORM, (BukkitRecipeConvertor<CustomSmithingTransformRecipe<ItemStack>>) (id, recipe) -> {
try {
Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe);
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
nmsRecipe = Reflections.constructor$RecipeHolder.newInstance(
Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe);
} else if (VersionHelper.isVersionNewerThan1_20_2()) {
} else if (VersionHelper.isOrAbove1_20_2()) {
nmsRecipe = Reflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe);
} else {
return () -> {};
@@ -255,7 +255,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
instance = this;
this.plugin = plugin;
this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager());
this.crafterEventListener = VersionHelper.isVersionNewerThan1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null;
this.crafterEventListener = VersionHelper.isOrAbove1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null;
try {
nmsRecipeManager = Reflections.method$MinecraftServer$getRecipeManager.invoke(Reflections.method$MinecraftServer$getServer.invoke(null));
} catch (ReflectiveOperationException e) {
@@ -286,7 +286,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
@Override
public void load() {
if (!Config.enableRecipeSystem()) return;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
try {
this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(nmsRecipeManager);
Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, null);
@@ -301,7 +301,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
if (!Config.enableRecipeSystem()) return;
super.unload();
try {
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
}
} catch (ReflectiveOperationException e) {
@@ -349,7 +349,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
private void unregisterNMSRecipe(NamespacedKey key) {
try {
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Object recipeMap = Reflections.field$RecipeManager$recipes.get(nmsRecipeManager);
Reflections.method$RecipeMap$removeRecipe.invoke(recipeMap, Reflections.method$CraftRecipe$toMinecraft.invoke(null, key));
} else {
@@ -363,7 +363,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
@SuppressWarnings("unchecked")
private void injectDataPackRecipes() {
try {
Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isVersionNewerThan1_21() ? "recipe" : "recipes");
Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isOrAbove1_21() ? "recipe" : "recipes");
Object minecraftServer = Reflections.method$MinecraftServer$getServer.invoke(null);
Object packRepository = Reflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer);
List<Object> selected = (List<Object>) Reflections.field$PackRepository$selected.get(packRepository);
@@ -446,13 +446,13 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
this.delayedTasksOnMainThread.clear();
// give flags back on 1.21.2+
if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) {
if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) {
Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager(), this.stolenFeatureFlagSet);
this.stolenFeatureFlagSet = null;
}
// refresh recipes
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager());
}
@@ -460,11 +460,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Reflections.method$DedicatedPlayerList$reloadRecipes.invoke(Reflections.field$CraftServer$playerList.get(Bukkit.getServer()));
// now we need to remove the fake `exact`
if (VersionHelper.isVersionNewerThan1_21_4()) {
if (VersionHelper.isOrAbove1_21_4()) {
for (Object ingredient : injectedIngredients) {
Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null);
}
} else if (VersionHelper.isVersionNewerThan1_21_2()) {
} else if (VersionHelper.isOrAbove1_21_2()) {
for (Object ingredient : injectedIngredients) {
Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null);
}
@@ -711,11 +711,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Object shapedRecipe = getNMSRecipe(id);
recipeToMcRecipeHolder.put(recipe, shapedRecipe);
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
shapedRecipe = Reflections.field$RecipeHolder$recipe.get(shapedRecipe);
}
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Reflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null);
}
@@ -732,11 +732,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Object shapelessRecipe = getNMSRecipe(id);
recipeToMcRecipeHolder.put(recipe, shapelessRecipe);
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
shapelessRecipe = Reflections.field$RecipeHolder$recipe.get(shapelessRecipe);
}
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Reflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null);
}
@SuppressWarnings("unchecked")
@@ -752,12 +752,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Ingredient<ItemStack> actualIngredient = recipe.ingredient();
Object smeltingRecipe = getNMSRecipe(id);
recipeToMcRecipeHolder.put(recipe, smeltingRecipe);
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
smeltingRecipe = Reflections.field$RecipeHolder$recipe.get(smeltingRecipe);
}
Object ingredient;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
ingredient = Reflections.field$SingleItemRecipe$input.get(smeltingRecipe);
} else {
ingredient = Reflections.field$AbstractCookingRecipe$input.get(smeltingRecipe);
@@ -771,7 +771,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
// 获取nms配方请注意1.20.1获取配方本身而1.20.2+获取的是配方的holder
// recipe on 1.20.1 and holder on 1.20.2+
private static Object getNMSRecipe(Key id) throws ReflectiveOperationException {
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
Object resourceKey = Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value()));
@SuppressWarnings("unchecked")
Optional<Object> optional = (Optional<Object>) Reflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey);
@@ -800,9 +800,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Object ingredient = fakeIngredients.get(i);
Ingredient<ItemStack> actualIngredient = actualIngredients.get(i);
List<Object> items = getIngredientLooks(actualIngredient.items());
if (VersionHelper.isVersionNewerThan1_21_4()) {
if (VersionHelper.isOrAbove1_21_4()) {
Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, new HashSet<>(items));
} else if (VersionHelper.isVersionNewerThan1_21_2()) {
} else if (VersionHelper.isOrAbove1_21_2()) {
Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, items);
} else {
Object itemStackArray = Array.newInstance(Reflections.clazz$ItemStack, items.size());
@@ -845,21 +845,21 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
// create nms smithing recipe for different versions
private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe<ItemStack> recipe) throws ReflectiveOperationException {
if (VersionHelper.isVersionNewerThan1_21_5()) {
if (VersionHelper.isOrAbove1_21_5()) {
return Reflections.constructor$SmithingTransformRecipe.newInstance(
toOptionalMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toOptionalMinecraftIngredient(recipe.addition()),
toTransmuteResult(recipe.result(ItemBuildContext.EMPTY))
);
} else if (VersionHelper.isVersionNewerThan1_21_2()) {
} else if (VersionHelper.isOrAbove1_21_2()) {
return Reflections.constructor$SmithingTransformRecipe.newInstance(
toOptionalMinecraftIngredient(recipe.template()),
toOptionalMinecraftIngredient(recipe.base()),
toOptionalMinecraftIngredient(recipe.addition()),
FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(recipe.result(ItemBuildContext.EMPTY))
);
} else if (VersionHelper.isVersionNewerThan1_20_2()) {
} else if (VersionHelper.isOrAbove1_20_2()) {
return Reflections.constructor$SmithingTransformRecipe.newInstance(
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),

View File

@@ -279,7 +279,7 @@ public class RecipeEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
if (!Config.enableRecipeSystem()) return;
if (VersionHelper.isVersionNewerThan1_21_2()) return;
if (VersionHelper.isOrAbove1_21_2()) return;
Block block = event.getBlock();
Material material = block.getType();
if (material == Material.CAMPFIRE) {
@@ -308,7 +308,7 @@ public class RecipeEventListener implements Listener {
plugin.logger().warn("Failed to inject cooking block entity", e);
}
}
} else if (!VersionHelper.isVersionNewerThan1_21_2() && material == Material.CAMPFIRE) {
} else if (!VersionHelper.isOrAbove1_21_2() && material == Material.CAMPFIRE) {
if (block.getState() instanceof Campfire campfire) {
try {
Object blockEntity = Reflections.field$CraftBlockEntityState$tileEntity.get(campfire);
@@ -324,13 +324,13 @@ public class RecipeEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPutItemOnCampfire(PlayerInteractEvent event) {
if (!Config.enableRecipeSystem()) return;
if (!VersionHelper.isVersionNewerThan1_21_2()) return;
if (!VersionHelper.isOrAbove1_21_2()) return;
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
Block clicked = event.getClickedBlock();
if (clicked == null) return;
Material type = clicked.getType();
if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return;
if (!VersionHelper.isVersionNewerThan1_21_2()) {
if (!VersionHelper.isOrAbove1_21_2()) {
if (clicked.getState() instanceof Campfire campfire) {
try {
Object blockEntity = Reflections.field$CraftBlockEntityState$tileEntity.get(campfire);
@@ -375,7 +375,7 @@ public class RecipeEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onCampfireCook(CampfireStartEvent event) {
if (!Config.enableRecipeSystem()) return;
if (!VersionHelper.isVersionNewerThan1_21_2()) return;
if (!VersionHelper.isOrAbove1_21_2()) return;
CampfireRecipe recipe = event.getRecipe();
Key recipeId = new Key(recipe.getKey().namespace(), recipe.getKey().value());
@@ -406,7 +406,7 @@ public class RecipeEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onCampfireCook(BlockCookEvent event) {
if (!Config.enableRecipeSystem()) return;
if (!VersionHelper.isVersionNewerThan1_21_2()) return;
if (!VersionHelper.isOrAbove1_21_2()) return;
Material type = event.getBlock().getType();
if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return;
CampfireRecipe recipe = (CampfireRecipe) event.getRecipe();
@@ -563,7 +563,7 @@ public class RecipeEventListener implements Listener {
String renameText;
int maxRepairCost;
//int previousCost;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
AnvilView anvilView = event.getView();
renameText = anvilView.getRenameText();
maxRepairCost = anvilView.getMaximumRepairCost();
@@ -588,10 +588,10 @@ public class RecipeEventListener implements Listener {
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to get hover name", e);
}
} else if (VersionHelper.isVersionNewerThan1_20_5() && wrappedFirst.hasComponent(ComponentTypes.CUSTOM_NAME)) {
} else if (VersionHelper.isOrAbove1_20_5() && wrappedFirst.hasComponent(ComponentTypes.CUSTOM_NAME)) {
repairCost += 1;
wrappedFirst.customName(null);
} else if (!VersionHelper.isVersionNewerThan1_20_5() && wrappedFirst.hasTag("display", "Name")) {
} else if (!VersionHelper.isOrAbove1_20_5() && wrappedFirst.hasTag("display", "Name")) {
repairCost += 1;
wrappedFirst.customName(null);
}
@@ -601,7 +601,7 @@ public class RecipeEventListener implements Listener {
// To fix some client side visual issues
try {
Object anvilMenu;
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
anvilMenu = Reflections.field$CraftInventoryView$container.get(event.getView());
} else {
anvilMenu = Reflections.field$CraftInventoryAnvil$menu.get(inventory);
@@ -611,7 +611,7 @@ public class RecipeEventListener implements Listener {
this.plugin.logger().warn("Failed to broadcast changes", e);
}
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
AnvilView anvilView = event.getView();
anvilView.setRepairCost(finalCost);
anvilView.setRepairItemCountCost(actualConsumedAmount);
@@ -622,7 +622,7 @@ public class RecipeEventListener implements Listener {
Player player;
try {
player = (Player) Reflections.method$InventoryView$getPlayer.invoke(VersionHelper.isVersionNewerThan1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
player = (Player) Reflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to get inventory viewer", e);
return;
@@ -659,7 +659,7 @@ public class RecipeEventListener implements Listener {
wrappedFirst.getCustomItem().ifPresent(item -> {
if (!item.settings().renameable()) {
String renameText;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
AnvilView anvilView = event.getView();
renameText = anvilView.getRenameText();
} else {

View File

@@ -72,7 +72,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
ContextHolder.Builder builder = ContextHolder.builder();
builder.withParameter(LootParameters.WORLD, world);
builder.withParameter(LootParameters.LOCATION, vec3d);
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
if (event.getDamageSource().getCausingEntity() instanceof Player player) {
BukkitServerPlayer serverPlayer = this.plugin.adapt(player);
builder.withParameter(LootParameters.PLAYER, serverPlayer);

View File

@@ -21,7 +21,6 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerResourcePackStatusEvent;
import java.util.ArrayList;
import java.util.List;
@@ -49,27 +48,17 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(PlayerJoinEvent event) {
if (Config.sendPackOnJoin() && !VersionHelper.isVersionNewerThan1_20_2()) {
if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) {
Player player = plugin.adapt(event.getPlayer());
this.sendResourcePack(player);
}
}
@EventHandler(priority = EventPriority.LOW)
public void onResourcePackStatus(PlayerResourcePackStatusEvent event) {
// for 1.20.1 servers, not recommended to use
if (Config.sendPackOnJoin() && Config.kickOnDeclined() && !VersionHelper.isVersionNewerThan1_20_2()) {
if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED || event.getStatus() == PlayerResourcePackStatusEvent.Status.FAILED_DOWNLOAD) {
event.getPlayer().kick();
}
}
}
@Override
public void load() {
if (ReloadCommand.RELOAD_PACK_FLAG || CraftEngine.instance().isInitializing()) {
super.load();
if (Config.sendPackOnJoin() && VersionHelper.isVersionNewerThan1_20_2() && !(resourcePackHost() instanceof NoneHost)) {
if (Config.sendPackOnJoin() && VersionHelper.isOrAbove1_20_2() && !(resourcePackHost() instanceof NoneHost)) {
this.modifyServerSettings();
}
}
@@ -80,7 +69,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
Object settings = Reflections.field$DedicatedServer$settings.get(Reflections.method$MinecraftServer$getServer.invoke(null));
Object properties = Reflections.field$DedicatedServerSettings$properties.get(settings);
Object info;
if (VersionHelper.isVersionNewerThan1_20_3()) {
if (VersionHelper.isOrAbove1_20_3()) {
info = Reflections.constructor$ServerResourcePackInfo.newInstance(new UUID(0, 0), FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt()));
} else {
info = Reflections.constructor$ServerResourcePackInfo.newInstance(FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt()));
@@ -95,7 +84,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
public void unload() {
super.unload();
if (ReloadCommand.RELOAD_PACK_FLAG) {
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
this.resetServerSettings();
}
}

View File

@@ -5,7 +5,6 @@ import net.momirealms.craftengine.bukkit.advancement.BukkitAdvancementManager;
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.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
@@ -25,8 +24,8 @@ import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.plugin.CompatibilityManager;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.classpath.ReflectionClassPathAppender;
import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory;
@@ -51,10 +50,12 @@ import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@SuppressWarnings("unchecked")
public class BukkitCraftEngine extends CraftEngine {
private static final String COMPATIBILITY_CLASS = "net.momirealms.craftengine.bukkit.compatibility.BukkitCompatibilityManager";
private static BukkitCraftEngine instance;
private final JavaPlugin bootstrap;
private SchedulerTask tickTask;
@@ -63,7 +64,6 @@ public class BukkitCraftEngine extends CraftEngine {
private boolean requiresRestart = false;
private boolean hasMod = false;
private AntiGriefLib antiGrief;
private boolean hasPlaceholderAPI;
public BukkitCraftEngine(JavaPlugin bootstrap) {
super((p) -> {
@@ -85,6 +85,12 @@ public class BukkitCraftEngine extends CraftEngine {
} catch (Exception ignore) {
}
}
Class<?> compatibilityClass = Objects.requireNonNull(ReflectionUtils.getClazz(COMPATIBILITY_CLASS), "Compatibility class not found");
try {
super.compatibilityManager = (CompatibilityManager) Objects.requireNonNull(ReflectionUtils.getConstructor(compatibilityClass, 0)).newInstance(this);
} catch (ReflectiveOperationException e) {
logger().warn("Compatibility class could not be instantiated: " + compatibilityClass.getName());
}
}
@Override
@@ -96,6 +102,7 @@ public class BukkitCraftEngine extends CraftEngine {
super.blockManager = new BukkitBlockManager(this);
super.furnitureManager = new BukkitFurnitureManager(this);
this.successfullyLoaded = true;
super.compatibilityManager().onLoad();
}
@Override
@@ -159,12 +166,7 @@ public class BukkitCraftEngine extends CraftEngine {
super.fontManager = new BukkitFontManager(this);
super.advancementManager = new BukkitAdvancementManager(this);
super.onPluginEnable();
// compatibility
// register expansion
if (this.isPluginEnabled("PlaceholderAPI")) {
PlaceholderAPIUtils.registerExpansions(this);
this.hasPlaceholderAPI = true;
}
super.compatibilityManager().onEnable();
}
@Override
@@ -204,6 +206,7 @@ public class BukkitCraftEngine extends CraftEngine {
}
}, 1, 1);
}
super.compatibilityManager().onDelayedEnable();
}
@Override
@@ -270,21 +273,6 @@ public class BukkitCraftEngine extends CraftEngine {
return instance;
}
@Override
public boolean hasPlaceholderAPI() {
return this.hasPlaceholderAPI;
}
@Override
public boolean isPluginEnabled(String plugin) {
return Bukkit.getPluginManager().isPluginEnabled(plugin);
}
@Override
public String parse(Player player, String text) {
return PlaceholderAPIUtils.parse((org.bukkit.entity.Player) player.platformPlayer(), text);
}
@Override
public BukkitNetworkManager networkManager() {
return (BukkitNetworkManager) networkManager;

View File

@@ -43,7 +43,7 @@ public class BukkitGuiManager implements GuiManager, Listener {
if (VersionHelper.isFolia()) {
for (Player player : Bukkit.getOnlinePlayers()) {
this.plugin.scheduler().sync().run(() -> {
org.bukkit.inventory.Inventory top = !VersionHelper.isVersionNewerThan1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory();
org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory();
if (top.getHolder() instanceof CraftEngineInventoryHolder holder) {
holder.gui().onTimer();
}
@@ -51,7 +51,7 @@ public class BukkitGuiManager implements GuiManager, Listener {
}
} else {
for (Player player : Bukkit.getOnlinePlayers()) {
org.bukkit.inventory.Inventory top = !VersionHelper.isVersionNewerThan1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory();
org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory();
if (top.getHolder() instanceof CraftEngineInventoryHolder holder) {
holder.gui().onTimer();
}

View File

@@ -318,11 +318,11 @@ public class BukkitInjector {
.intercept(FieldAccessor.ofField("lastCustomRecipe"))
.method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a")))
.intercept(MethodDelegation.to(
VersionHelper.isVersionNewerThan1_21_2() ?
VersionHelper.isOrAbove1_21_2() ?
GetRecipeForMethodInterceptor1_21_2.INSTANCE :
(VersionHelper.isVersionNewerThan1_21() ?
(VersionHelper.isOrAbove1_21() ?
GetRecipeForMethodInterceptor1_21.INSTANCE :
VersionHelper.isVersionNewerThan1_20_5() ?
VersionHelper.isOrAbove1_20_5() ?
GetRecipeForMethodInterceptor1_20_5.INSTANCE :
GetRecipeForMethodInterceptor1_20.INSTANCE)
))
@@ -346,7 +346,7 @@ public class BukkitInjector {
InjectedCacheCheck injectedChecker = (InjectedCacheCheck) Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker);
injectedChecker.recipeType(recipeType);
Reflections.field$AbstractFurnaceBlockEntity$quickCheck.set(entity, injectedChecker);
} else if (!VersionHelper.isVersionNewerThan1_21_2() && Reflections.clazz$CampfireBlockEntity.isInstance(entity)) {
} else if (!VersionHelper.isOrAbove1_21_2() && Reflections.clazz$CampfireBlockEntity.isInstance(entity)) {
Object quickCheck = Reflections.field$CampfireBlockEntity$quickCheck.get(entity);
if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected
InjectedCacheCheck injectedChecker = (InjectedCacheCheck) Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker);
@@ -368,6 +368,22 @@ public class BukkitInjector {
}
}
// public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
// try {
// Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
// if (!(container instanceof InjectedPalettedContainerHolder)) {
// InjectedPalettedContainerHolder injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container);
// injectedObject.ceSection(ceSection);
// injectedObject.ceWorld(ceWorld);
// injectedObject.cePos(pos);
// Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container));
// Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject);
// }
// } catch (Exception e) {
// CraftEngine.instance().logger().severe("Failed to inject chunk section", e);
// }
// }
public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
try {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
@@ -385,7 +401,7 @@ public class BukkitInjector {
}
}
public static void uninjectLevelChunkSection(Object section) {
public synchronized static void uninjectLevelChunkSection(Object section) {
try {
Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
if (states instanceof InjectedPalettedContainerHolder holder) {
@@ -750,7 +766,7 @@ public class BukkitInjector {
Object direction;
Object serverLevel;
Object blockPos;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
direction = args[4];
serverLevel = args[1];
blockPos = args[3];

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.network;
import com.google.gson.JsonObject;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.handler.codec.MessageToMessageDecoder;
@@ -16,10 +17,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.plugin.network.NetworkManager;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.ListMonitor;
import net.momirealms.craftengine.core.util.TriConsumer;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -72,10 +70,12 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
private static final String PACKET_DECODER = "craftengine_decoder";
private static boolean hasModelEngine;
private static boolean hasViaVersion;
public BukkitNetworkManager(BukkitCraftEngine plugin) {
instance = this;
hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null;
hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null;
this.plugin = plugin;
// set up packet id
this.packetIds = setupPacketIds();
@@ -101,6 +101,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
// set up mod channel
this.plugin.bootstrap().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL, this);
this.plugin.bootstrap().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL);
// 配置via频道
this.plugin.bootstrap().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.bootstrap(), VIA_CHANNEL, this);
// Inject server channel
try {
Object server = Reflections.method$MinecraftServer$getServer.invoke(null);
@@ -119,7 +121,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
private PacketIds setupPacketIds() {
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
return new PacketIds1_20_5();
} else {
return new PacketIds1_20();
@@ -127,7 +129,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
private void registerPacketHandlers() {
registerNMSPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, Reflections.clazz$ClientboundLevelChunkWithLightPacket);
registerNMSPacketConsumer(PacketConsumers.PLAYER_INFO_UPDATE, Reflections.clazz$ClientboundPlayerInfoUpdatePacket);
registerNMSPacketConsumer(PacketConsumers.PLAYER_ACTION, Reflections.clazz$ServerboundPlayerActionPacket);
registerNMSPacketConsumer(PacketConsumers.SWING_HAND, Reflections.clazz$ServerboundSwingPacket);
@@ -147,20 +148,24 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket);
registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, Reflections.clazz$ServerboundCustomPayloadPacket);
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_PUSH, Reflections.clazz$ClientboundResourcePackPushPacket);
registerNMSPacketConsumer(PacketConsumers.HANDSHAKE_C2S, Reflections.clazz$ClientIntentionPacket);
registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket);
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket);
registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_21_3() ? PacketConsumers.LEVEL_PARTICLE_1_21_3 : (VersionHelper.isVersionNewerThan1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_21_3() ? PacketConsumers.LEVEL_PARTICLE_1_21_3 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket());
registerByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket());
registerByteBufPacketConsumer(VersionHelper.isVersionNewerThan1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket());
registerByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isVersionNewerThan1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1);
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket());
registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket());
registerByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1);
registerByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket());
registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());
@@ -202,9 +207,17 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
return this.onlineUserArray;
}
// 保留仅注册入频道用
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {}
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {
if (channel.equals(VIA_CHANNEL)) {
BukkitServerPlayer user = plugin.adapt(player);
if (user != null) {
JsonObject payload = GsonHelper.get().fromJson(new String(message), JsonObject.class);
int version = payload.get("version").getAsInt();
user.setProtocolVersion(version);
}
}
}
@Override
public void init() {
@@ -289,6 +302,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
return hasModelEngine;
}
public static boolean hasViaVersion() {
return hasViaVersion;
}
public void simulatePacket(@NotNull NetWorkUser player, Object packet) {
Channel channel = player.nettyChannel();
if (channel.isOpen()) {

View File

@@ -9,7 +9,6 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior;
@@ -41,6 +40,7 @@ import net.momirealms.craftengine.core.world.EntityHitResult;
import net.momirealms.craftengine.core.world.WorldEvents;
import net.momirealms.craftengine.core.world.chunk.Palette;
import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData;
import net.momirealms.craftengine.core.world.chunk.packet.MCSection;
import net.momirealms.craftengine.core.world.collision.AABB;
import net.momirealms.sparrow.nbt.Tag;
@@ -63,7 +63,6 @@ public class PacketConsumers {
private static int[] mappingsMOD;
private static IntIdentityList BLOCK_LIST;
private static IntIdentityList BIOME_LIST;
private static final UUID EMPTY_UUID = new UUID(0, 0);
public static void init(Map<Integer, Integer> map, int registrySize) {
mappings = new int[registrySize];
@@ -94,15 +93,53 @@ public class PacketConsumers {
return mappingsMOD[stateId];
}
// TODO Use bytebuffer?
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> LEVEL_CHUNK_WITH_LIGHT = (user, event, packet) -> {
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> LEVEL_CHUNK_WITH_LIGHT = (user, event) -> {
try {
BukkitServerPlayer player = (BukkitServerPlayer) user;
FriendlyByteBuf buf = event.getBuffer();
int chunkX = buf.readInt();
int chunkZ = buf.readInt();
boolean named = !VersionHelper.isOrAbove1_20_2();
// ClientboundLevelChunkPacketData
int heightmapsCount = 0;
Map<Integer, long[]> heightmapsMap = null;
Tag heightmaps = null;
if (VersionHelper.isOrAbove1_21_5()) {
heightmapsMap = new HashMap<>();
heightmapsCount = buf.readVarInt();
for (int i = 0; i < heightmapsCount; i++) {
int key = buf.readVarInt();
long[] value = buf.readLongArray();
heightmapsMap.put(key, value);
}
} else {
heightmaps = buf.readNbt(named);
}
int varInt = buf.readVarInt();
byte[] buffer = new byte[varInt];
buf.readBytes(buffer);
int blockEntitiesDataCount = buf.readVarInt();
List<BlockEntityData> blockEntitiesData = new ArrayList<>();
for (int i = 0; i < blockEntitiesDataCount; i++) {
byte packedXZ = buf.readByte();
short y = buf.readShort();
int type = buf.readVarInt();
Tag tag = buf.readNbt(named);
BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag);
blockEntitiesData.add(blockEntityData);
}
// ClientboundLightUpdatePacketData
BitSet skyYMask = buf.readBitSet();
BitSet blockYMask = buf.readBitSet();
BitSet emptySkyYMask = buf.readBitSet();
BitSet emptyBlockYMask = buf.readBitSet();
List<byte[]> skyUpdates = buf.readByteArrayList(2048);
List<byte[]> blockUpdates = buf.readByteArrayList(2048);
// 开始处理
if (user.clientModEnabled()) {
BukkitServerPlayer player = (BukkitServerPlayer) user;
Object chunkData = FastNMS.INSTANCE.field$ClientboundLevelChunkWithLightPacket$chunkData(packet);
byte[] buffer = (byte[]) Reflections.field$ClientboundLevelChunkPacketData$buffer.get(chunkData);
ByteBuf buf = Unpooled.copiedBuffer(buffer);
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
ByteBuf byteBuf = Unpooled.copiedBuffer(buffer);
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf);
FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer());
for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) {
try {
@@ -126,13 +163,10 @@ public class PacketConsumers {
break;
}
}
Reflections.field$ClientboundLevelChunkPacketData$buffer.set(chunkData, newBuf.array());
buffer = newBuf.array();
} else {
BukkitServerPlayer player = (BukkitServerPlayer) user;
Object chunkData = FastNMS.INSTANCE.field$ClientboundLevelChunkWithLightPacket$chunkData(packet);
byte[] buffer = (byte[]) Reflections.field$ClientboundLevelChunkPacketData$buffer.get(chunkData);
ByteBuf buf = Unpooled.copiedBuffer(buffer);
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
ByteBuf byteBuf = Unpooled.copiedBuffer(buffer);
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf);
FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer());
for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) {
try {
@@ -156,8 +190,38 @@ public class PacketConsumers {
break;
}
}
Reflections.field$ClientboundLevelChunkPacketData$buffer.set(chunkData, newBuf.array());
buffer = newBuf.array();
}
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeInt(chunkX);
buf.writeInt(chunkZ);
if (VersionHelper.isOrAbove1_21_5()) {
buf.writeVarInt(heightmapsCount);
assert heightmapsMap != null;
for (Map.Entry<Integer, long[]> entry : heightmapsMap.entrySet()) {
buf.writeVarInt(entry.getKey());
buf.writeLongArray(entry.getValue());
}
} else {
buf.writeNbt(heightmaps, named);
}
buf.writeVarInt(buffer.length);
buf.writeBytes(buffer);
buf.writeVarInt(blockEntitiesDataCount);
for (BlockEntityData blockEntityData : blockEntitiesData) {
buf.writeByte(blockEntityData.packedXZ());
buf.writeShort(blockEntityData.y());
buf.writeVarInt(blockEntityData.type());
buf.writeNbt(blockEntityData.tag(), named);
}
buf.writeBitSet(skyYMask);
buf.writeBitSet(blockYMask);
buf.writeBitSet(emptySkyYMask);
buf.writeBitSet(emptyBlockYMask);
buf.writeByteArrayList(skyUpdates);
buf.writeByteArrayList(blockUpdates);
event.setChanged(true);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelChunkWithLightPacket", e);
}
@@ -1174,7 +1238,7 @@ public class PacketConsumers {
BukkitServerPlayer player = (BukkitServerPlayer) user;
String name = (String) Reflections.field$ServerboundHelloPacket$name.get(packet);
player.setName(name);
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
UUID uuid = (UUID) Reflections.field$ServerboundHelloPacket$uuid.get(packet);
player.setUUID(uuid);
} else {
@@ -1222,7 +1286,7 @@ public class PacketConsumers {
BukkitServerPlayer player = (BukkitServerPlayer) user;
player.clearView();
Object dimensionKey;
if (!VersionHelper.isVersionNewerThan1_20_2()) {
if (!VersionHelper.isOrAbove1_20_2()) {
dimensionKey = Reflections.field$ClientboundRespawnPacket$dimension.get(packet);
} else {
Object commonInfo = Reflections.field$ClientboundRespawnPacket$commonPlayerSpawnInfo.get(packet);
@@ -1247,7 +1311,10 @@ public class PacketConsumers {
BukkitServerPlayer player = (BukkitServerPlayer) user;
player.setConnectionState(ConnectionState.PLAY);
Object dimensionKey;
if (!VersionHelper.isVersionNewerThan1_20_2()) {
if (!VersionHelper.isOrAbove1_20_2()) {
if (BukkitNetworkManager.hasViaVersion()) {
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid()));
}
dimensionKey = Reflections.field$ClientboundLoginPacket$dimension.get(packet);
} else {
Object commonInfo = Reflections.field$ClientboundLoginPacket$commonPlayerSpawnInfo.get(packet);
@@ -1272,7 +1339,7 @@ public class PacketConsumers {
// When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue.
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SET_CREATIVE_SLOT = (user, event, packet) -> {
try {
if (VersionHelper.isVersionNewerThan1_21_4()) return;
if (VersionHelper.isOrAbove1_21_4()) return;
if (!user.isOnline()) return;
BukkitServerPlayer player = (BukkitServerPlayer) user;
if (VersionHelper.isFolia()) {
@@ -1295,7 +1362,7 @@ public class PacketConsumers {
Player bukkitPlayer = player.platformPlayer();
if (bukkitPlayer == null) return;
if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return;
int slot = VersionHelper.isVersionNewerThan1_20_5() ? Reflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getShort(packet) : Reflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getInt(packet);
int slot = VersionHelper.isOrAbove1_20_5() ? Reflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getShort(packet) : Reflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getInt(packet);
if (slot < 36 || slot > 44) return;
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(Reflections.field$ServerboundSetCreativeModeSlotPacket$itemStack.get(packet));
if (ItemUtils.isEmpty(item)) return;
@@ -1585,7 +1652,7 @@ public class PacketConsumers {
int entityId;
if (BukkitNetworkManager.hasModelEngine()) {
int fakeId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet);
entityId = ModelEngineUtils.interactionToBaseEntity(fakeId);
entityId = CraftEngine.instance().compatibilityManager().interactionToBaseEntity(fakeId);
} else {
entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet);
}
@@ -1867,7 +1934,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
try {
if (!VersionHelper.isVersionNewerThan1_20_5()) return;
if (!VersionHelper.isOrAbove1_20_5()) return;
Object payload = Reflections.field$ServerboundCustomPayloadPacket$payload.get(packet);
if (payload.getClass().equals(Reflections.clazz$DiscardedPayload)) {
Object type = Reflections.method$CustomPacketPayload$type.invoke(payload);
@@ -2149,7 +2216,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RESOURCE_PACK_PUSH = (user, event, packet) -> {
try {
if (!VersionHelper.isVersionNewerThan1_20_2()) return;
if (!VersionHelper.isOrAbove1_20_2()) return;
// we should only handle fake urls
String url = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$url(packet);
if (!url.equals(BukkitPackManager.FAKE_URL)) {
@@ -2178,4 +2245,45 @@ public class PacketConsumers {
CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HANDSHAKE_C2S = (user, event, packet) -> {
try {
if (BukkitNetworkManager.hasViaVersion()) return;
int protocolVersion = Reflections.field$ClientIntentionPacket$protocolVersion.getInt(packet);
user.setProtocolVersion(protocolVersion);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> LOGIN_ACKNOWLEDGED = (user, event, packet) -> {
try {
if (BukkitNetworkManager.hasViaVersion()) {
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(user.uuid()));
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundLoginAcknowledgedPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RESOURCE_PACK_RESPONSE = (user, event, packet) -> {
try {
if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return;
Object action = Reflections.field$ServerboundResourcePackPacket$action.get(packet);
if (action == null) return;
if (action == Reflections.instance$ServerboundResourcePackPacket$Action$DECLINED
|| action == Reflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) {
Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance(
ComponentUtils.adventureToMinecraft(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")));
user.nettyChannel().writeAndFlush(kickPacket);
user.nettyChannel().disconnect();
return;
}
if (action == Reflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) {
user.setSentResourcePack(true);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e);
}
};
}

View File

@@ -15,7 +15,7 @@ public class PacketIdFinder {
static {
try {
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
Object packetReport = Reflections.constructor$PacketReport.newInstance((Object) null);
JsonElement jsonElement = (JsonElement) Reflections.method$PacketReport$serializePackets.invoke(packetReport);
var play = jsonElement.getAsJsonObject().get("play");
@@ -26,7 +26,7 @@ public class PacketIdFinder {
ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt());
}
}
} else if (VersionHelper.isVersionNewerThan1_20_5()) {
} else if (VersionHelper.isOrAbove1_20_5()) {
gamePacketIdsByName.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByName());
} else {
gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByClazz());

View File

@@ -18,6 +18,7 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.ProtocolVersion;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -39,6 +40,8 @@ import java.util.concurrent.ConcurrentHashMap;
public class BukkitServerPlayer extends Player {
private final BukkitCraftEngine plugin;
// handshake
private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN;
// connection state
private final Channel channel;
private String name;
@@ -46,6 +49,7 @@ public class BukkitServerPlayer extends Player {
private ConnectionState decoderState;
private ConnectionState encoderState;
private final Set<UUID> resourcePackUUID = Collections.synchronizedSet(new HashSet<>());
private boolean sentResourcePack = !Config.sendPackOnJoin();
// some references
private Reference<org.bukkit.entity.Player> playerRef;
private Reference<Object> serverPlayerRef;
@@ -411,7 +415,7 @@ public class BukkitServerPlayer extends Player {
}
this.clientSideCanBreak = canBreak;
if (canBreak) {
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
Object serverPlayer = serverPlayer();
Object attributeInstance = Reflections.method$ServerPlayer$getAttribute.invoke(serverPlayer, Reflections.instance$Holder$Attribute$block_break_speed);
Object newPacket = Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityID(), Lists.newArrayList(attributeInstance));
@@ -421,8 +425,8 @@ public class BukkitServerPlayer extends Player {
resetEffect(Reflections.instance$MobEffecr$haste);
}
} else {
if (VersionHelper.isVersionNewerThan1_20_5()) {
Object attributeModifier = VersionHelper.isVersionNewerThan1_21() ?
if (VersionHelper.isOrAbove1_20_5()) {
Object attributeModifier = VersionHelper.isOrAbove1_21() ?
Reflections.constructor$AttributeModifier.newInstance(KeyUtils.toResourceLocation("craftengine", "custom_hardness"), -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE) :
Reflections.constructor$AttributeModifier.newInstance(UUID.randomUUID(), "craftengine:custom_hardness", -9999d, Reflections.instance$AttributeModifier$Operation$ADD_VALUE);
Object attributeSnapshot = Reflections.constructor$ClientboundUpdateAttributesPacket$AttributeSnapshot.newInstance(Reflections.instance$Holder$Attribute$block_break_speed, 1d, Lists.newArrayList(attributeModifier));
@@ -516,7 +520,7 @@ public class BukkitServerPlayer extends Player {
// creative mode + invalid item in hand
if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK
|| itemMaterial == Material.TRIDENT
|| (VersionHelper.isVersionNewerThan1_20_5() && itemMaterial == MaterialUtils.MACE)
|| (VersionHelper.isOrAbove1_20_5() && itemMaterial == MaterialUtils.MACE)
|| item.is(ItemTags.SWORDS))) {
return;
}
@@ -753,11 +757,31 @@ public class BukkitServerPlayer extends Player {
@Override
public void addResourcePackUUID(UUID uuid) {
if (VersionHelper.isVersionNewerThan1_20_3()) {
if (VersionHelper.isOrAbove1_20_3()) {
this.resourcePackUUID.add(uuid);
}
}
@Override
public ProtocolVersion protocolVersion() {
return this.protocolVersion;
}
@Override
public void setProtocolVersion(int protocolVersion) {
this.protocolVersion = ProtocolVersion.getById(protocolVersion);
}
@Override
public boolean sentResourcePack() {
return this.sentResourcePack;
}
@Override
public void setSentResourcePack(boolean sentResourcePack) {
this.sentResourcePack = sentResourcePack;
}
@Override
public void clearView() {
this.entityTypeView.clear();
@@ -766,7 +790,7 @@ public class BukkitServerPlayer extends Player {
@Override
public void unloadCurrentResourcePack() {
if (!VersionHelper.isVersionNewerThan1_20_3()) {
if (!VersionHelper.isOrAbove1_20_3()) {
return;
}
if (decoderState() == ConnectionState.PLAY && !this.resourcePackUUID.isEmpty()) {

View File

@@ -33,7 +33,7 @@ public class BukkitSoundManager extends AbstractSoundManager {
Object soundId = KeyUtils.toResourceLocation(jukeboxSong.sound());
Object song = Reflections.method$Registry$get.invoke(Reflections.instance$InternalRegistries$JUKEBOX_SONG, resourceLocation);
Object soundEvent = VersionHelper.isVersionNewerThan1_21_2() ?
Object soundEvent = VersionHelper.isOrAbove1_21_2() ?
Reflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) :
Reflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false);
Object soundHolder = Reflections.method$Holder$direct.invoke(null, soundEvent);

View File

@@ -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<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) {
int index = blockState.indexOf('[');
if (index == -1) {

View File

@@ -1,10 +1,13 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Bukkit;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
public final class BukkitReflectionUtils {
private static final String PREFIX_MC = "net.minecraft.";
@@ -66,4 +69,42 @@ public final class BukkitReflectionUtils {
public static String assembleMCClass(String className) {
return PREFIX_MC + className;
}
public static Class<?> findReobfOrMojmapClass(String reobf, String mojmap) {
return findReobfOrMojmapClass(reobf, mojmap, BukkitReflectionUtils::assembleMCClass);
}
public static Class<?> findReobfOrMojmapClass(String reobf, String mojmap, Function<String, String> classDecorator) {
if (VersionHelper.isMojmap()) return ReflectionUtils.getClazz(classDecorator.apply(mojmap));
else return ReflectionUtils.getClazz(classDecorator.apply(reobf));
}
public static Class<?> findReobfOrMojmapClass(List<String> reobf, String mojmap) {
return findReobfOrMojmapClass(reobf, mojmap, BukkitReflectionUtils::assembleMCClass);
}
public static Class<?> findReobfOrMojmapClass(List<String> reobf, String mojmap, Function<String, String> classDecorator) {
if (VersionHelper.isMojmap()) return ReflectionUtils.getClazz(classDecorator.apply(mojmap));
else return ReflectionUtils.getClazz(reobf.stream().map(classDecorator).toList().toArray(new String[0]));
}
public static Class<?> findReobfOrMojmapClass(String reobf, List<String> mojmap) {
return findReobfOrMojmapClass(reobf, mojmap, BukkitReflectionUtils::assembleMCClass);
}
public static Class<?> findReobfOrMojmapClass(String reobf, List<String> mojmap, Function<String, String> classDecorator) {
if (VersionHelper.isMojmap()) return ReflectionUtils.getClazz(mojmap.stream().map(classDecorator).toList().toArray(new String[0]));
else return ReflectionUtils.getClazz(classDecorator.apply(reobf));
}
public static Class<?> findReobfOrMojmapClass(List<String> reobf, List<String> mojmap) {
return findReobfOrMojmapClass(reobf, mojmap, BukkitReflectionUtils::assembleMCClass);
}
public static Class<?> findReobfOrMojmapClass(List<String> reobf, List<String> mojmap, Function<String, String> classDecorator) {
String[] classes = VersionHelper.isMojmap()
? mojmap.stream().map(classDecorator).toList().toArray(new String[0])
: reobf.stream().map(classDecorator).toList().toArray(new String[0]);
return ReflectionUtils.getClazz(classes);
}
}

View File

@@ -11,8 +11,8 @@ public class EntityDataUtils {
private static final int USE_DEFAULT_BACKGROUND = 0x04; // 4
private static final int LEFT_ALIGNMENT = 0x08; // 8
private static final int RIGHT_ALIGNMENT = 0x10; // 16
public static final int BLOCK_STATE_DATA_ID = VersionHelper.isVersionNewerThan1_20_2() ? 23 : 22;
public static final int TEXT_DATA_ID = VersionHelper.isVersionNewerThan1_20_2() ? 23 : 22;
public static final int BLOCK_STATE_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22;
public static final int TEXT_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22;
public static final int CUSTOM_NAME_DATA_ID = 2;
public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) {

View File

@@ -27,7 +27,7 @@ public class EntityUtils {
}
public static Entity spawnEntity(World world, Location loc, EntityType type, Consumer<Entity> function) {
if (VersionHelper.isVersionNewerThan1_20_2()) {
if (VersionHelper.isOrAbove1_20_2()) {
return world.spawnEntity(loc, type, CreatureSpawnEvent.SpawnReason.CUSTOM, function);
} else {
return LegacyEntityUtils.spawnEntity(world, loc, type, function);

View File

@@ -15,9 +15,9 @@ public class RecipeUtils {
public static List<Object> getIngredientsFromShapedRecipe(Object recipe) {
List<Object> ingredients = new ArrayList<>();
try {
if (VersionHelper.isVersionNewerThan1_20_3()) {
if (VersionHelper.isOrAbove1_20_3()) {
Object pattern = Reflections.field$1_20_3$ShapedRecipe$pattern.get(recipe);
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
List<Optional<Object>> optionals = (List<Optional<Object>>) Reflections.field$ShapedRecipePattern$ingredients1_21_2.get(pattern);
for (Optional<Object> optional : optionals) {
optional.ifPresent(ingredients::add);

View File

@@ -74,7 +74,7 @@ public class BukkitWorld implements World {
public void dropItemNaturally(Vec3d location, Item<?> item) {
ItemStack itemStack = (ItemStack) item.load();
if (ItemUtils.isEmpty(itemStack)) return;
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
platformWorld().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem());
} else {
platformWorld().dropItemNaturally(new Location(null, location.x() - 0.5, location.y() - 0.5, location.z() - 0.5), (ItemStack) item.getItem());

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector;
@@ -10,18 +9,15 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.CEWorld;
import net.momirealms.craftengine.core.world.ChunkPos;
import net.momirealms.craftengine.core.world.SectionPos;
import net.momirealms.craftengine.core.world.WorldManager;
import net.momirealms.craftengine.core.world.chunk.CEChunk;
import net.momirealms.craftengine.core.world.chunk.CESection;
import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer;
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage;
import net.momirealms.sparrow.nbt.CompoundTag;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
@@ -29,10 +25,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.event.world.*;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -57,16 +50,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
instance = this;
this.plugin = plugin;
this.worlds = new HashMap<>();
if (VersionHelper.isVersionNewerThan1_21_4()) {
try {
Class.forName("com.infernalsuite.asp.api.AdvancedSlimePaperAPI");
SlimeFormatStorageAdaptor adaptor = new SlimeFormatStorageAdaptor(this);
this.storageAdaptor = adaptor;
Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap());
return;
} catch (ClassNotFoundException ignored) {
}
}
this.storageAdaptor = new DefaultStorageAdaptor();
}
@@ -148,6 +131,11 @@ public class BukkitWorldManager implements WorldManager, Listener {
for (Chunk chunk : world.getLoadedChunks()) {
handleChunkUnload(ceWorld, chunk);
}
try {
ceWorld.worldDataStorage().close();
} catch (IOException e) {
this.plugin.logger().warn("Error unloading world: " + world.getName(), e);
}
}
this.worlds.clear();
}
@@ -198,6 +186,13 @@ public class BukkitWorldManager implements WorldManager, Listener {
unloadWorld(new BukkitWorld(event.getWorld()));
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onWorldSave(WorldSaveEvent event) {
for (CEWorld world : this.worldArray) {
world.save();
}
}
@Override
public void unloadWorld(net.momirealms.craftengine.core.world.World world) {
CEWorld ceWorld;
@@ -270,10 +265,9 @@ public class BukkitWorldManager implements WorldManager, Listener {
CEChunk ceChunk = world.getChunkAtIfLoaded(chunk.getX(), chunk.getZ());
if (ceChunk != null) {
try {
world.worldDataStorage().writeChunkTagAt(pos, ChunkSerializer.serialize(ceChunk));
world.worldDataStorage().writeChunkAt(pos, ceChunk, false);
} catch (IOException e) {
plugin.logger().warn("Failed to write chunk tag at " + chunk.getX() + " " + chunk.getZ(), e);
return;
this.plugin.logger().warn("Failed to write chunk tag at " + chunk.getX() + " " + chunk.getZ(), e);
} finally {
if (Config.restoreVanillaBlocks()) {
CESection[] ceSections = ceChunk.sections();
@@ -308,12 +302,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
if (ceWorld.isChunkLoaded(pos.longKey)) return;
CEChunk ceChunk;
try {
CompoundTag chunkNbt = ceWorld.worldDataStorage().readChunkTagAt(pos);
if (chunkNbt != null) {
ceChunk = ChunkSerializer.deserialize(ceWorld, pos, chunkNbt);
} else {
ceChunk = new CEChunk(ceWorld, pos);
}
ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, pos);
try {
CESection[] ceSections = ceChunk.sections();
Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk);

View File

@@ -12,7 +12,7 @@ public class BlockNbtParser {
@Nullable
public static CompoundTag deserialize(@NotNull CustomBlock block, @NotNull String data) {
StringReader reader = new StringReader(data);
StringReader reader = StringReader.simple(data);
CompoundTag properties = new CompoundTag();
while (reader.canRead()) {
String propertyName = reader.readUnquotedString();

View File

@@ -48,16 +48,11 @@ public class BlockStateHolder {
return propertyMap.entrySet().stream()
.map(entry -> {
Property<?> property = entry.getKey();
return property.name() + "=" + formatValue(property, entry.getValue());
return property.name() + "=" + Property.formatValue(property, entry.getValue());
})
.collect(Collectors.joining(","));
}
@SuppressWarnings("unchecked")
private static <T extends Comparable<T>> String formatValue(Property<T> property, Comparable<?> value) {
return property.valueName((T) value);
}
public Collection<Property<?>> getProperties() {
return Collections.unmodifiableSet(propertyMap.keySet());
}

View File

@@ -0,0 +1,108 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Pair;
import net.momirealms.craftengine.core.util.StringReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class BlockStateMatcher {
private final List<Pair<Property<?>, Comparable<?>>> properties;
private final Key id;
public BlockStateMatcher(Key id, List<Pair<Property<?>, Comparable<?>>> properties) {
this.properties = properties;
this.id = id;
}
public boolean matches(ImmutableBlockState state) {
if (!state.owner().value().id.equals(this.id)) {
return false;
}
for (Pair<Property<?>, Comparable<?>> pair : this.properties) {
if (!state.get(pair.left()).equals(pair.right())) {
return false;
}
}
return true;
}
@Override
public String toString() {
if (properties.isEmpty()) {
return id.toString();
}
return id + "[" + getPropertiesAsString() + "]";
}
public String getPropertiesAsString() {
return properties.stream()
.map(entry -> {
Property<?> property = entry.left();
return property.name() + "=" + Property.formatValue(property, entry.right());
})
.collect(Collectors.joining(","));
}
@SuppressWarnings("DuplicatedCode")
@Nullable
public static BlockStateMatcher deserialize(@NotNull String data) {
StringReader reader = StringReader.simple(data);
String blockIdString = reader.readUnquotedString();
if (reader.canRead() && reader.peek() == ':') {
reader.skip();
blockIdString = blockIdString + ":" + reader.readUnquotedString();
}
Optional<Holder.Reference<CustomBlock>> optional = BuiltInRegistries.BLOCK.get(Key.from(blockIdString));
if (optional.isEmpty()) {
return null;
}
Holder<CustomBlock> holder = optional.get();
List<Pair<Property<?>, Comparable<?>>> properties = new ArrayList<>();
if (reader.canRead() && reader.peek() == '[') {
reader.skip();
while (reader.canRead()) {
reader.skipWhitespace();
if (reader.peek() == ']') break;
String propertyName = reader.readUnquotedString();
reader.skipWhitespace();
if (!reader.canRead() || reader.peek() != '=') {
return null;
}
reader.skip();
reader.skipWhitespace();
String propertyValue = reader.readUnquotedString();
Property<?> property = holder.value().getProperty(propertyName);
if (property != null) {
Optional<?> optionalValue = property.optional(propertyValue);
if (optionalValue.isEmpty()) {
return null;
} else {
properties.add(Pair.of(property, (Comparable<?>) optionalValue.get()));
}
} else {
return null;
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ',') {
reader.skip();
}
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ']') {
reader.skip();
} else {
return null;
}
}
return new BlockStateMatcher(holder.value().id(), properties);
}
}

View File

@@ -31,7 +31,7 @@ public class BlockStateParser {
private Property<?> property;
public BlockStateParser(String data, int cursor) {
this.reader = new StringReader(data.toLowerCase());
this.reader = StringReader.simple(data.toLowerCase());
this.reader.setCursor(cursor);
this.cursor = cursor;
this.replaceCursor = cursor;
@@ -188,7 +188,7 @@ public class BlockStateParser {
@Nullable
public static ImmutableBlockState deserialize(@NotNull String data) {
StringReader reader = new StringReader(data);
StringReader reader = StringReader.simple(data);
String blockIdString = reader.readUnquotedString();
if (reader.canRead() && reader.peek() == ':') {
reader.skip();

View File

@@ -0,0 +1,98 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Pair;
import net.momirealms.craftengine.core.util.StringReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class UnsafeBlockStateMatcher {
private final List<Pair<String, String>> matchers;
private final Key id;
public UnsafeBlockStateMatcher(Key id, List<Pair<String, String>> matchers) {
this.id = id;
this.matchers = matchers;
}
public boolean matches(ImmutableBlockState state) {
if (!state.owner().value().id.equals(this.id)) {
return false;
}
CustomBlock customBlock = state.owner().value();
for (Pair<String, String> matcher : matchers) {
Property<?> property = customBlock.getProperty(matcher.left());
if (property == null) {
return false;
}
Comparable<?> value = state.get(property);
String valueStr = Property.formatValue(property, value);
if (!matcher.right().equals(valueStr)) {
return false;
}
}
return true;
}
@Override
public String toString() {
if (matchers.isEmpty()) {
return id.toString();
}
return id + "[" + matchers.stream()
.map(entry -> entry.left() + "=" + entry.right())
.collect(Collectors.joining(",")) + "]";
}
@SuppressWarnings("DuplicatedCode")
@Nullable
public static UnsafeBlockStateMatcher deserialize(@NotNull String data) {
StringReader reader = StringReader.simple(data);
String blockIdString = reader.readUnquotedString();
if (reader.canRead() && reader.peek() == ':') {
reader.skip();
blockIdString = blockIdString + ":" + reader.readUnquotedString();
}
Optional<Holder.Reference<CustomBlock>> optional = BuiltInRegistries.BLOCK.get(Key.from(blockIdString));
if (optional.isEmpty()) {
return null;
}
Holder<CustomBlock> holder = optional.get();
List<Pair<String, String>> properties = new ArrayList<>();
if (reader.canRead() && reader.peek() == '[') {
reader.skip();
while (reader.canRead()) {
reader.skipWhitespace();
if (reader.peek() == ']') break;
String propertyName = reader.readUnquotedString();
reader.skipWhitespace();
if (!reader.canRead() || reader.peek() != '=') {
return null;
}
reader.skip();
reader.skipWhitespace();
String propertyValue = reader.readUnquotedString();
properties.add(new Pair<>(propertyName, propertyValue));
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ',') {
reader.skip();
}
}
reader.skipWhitespace();
if (reader.canRead() && reader.peek() == ']') {
reader.skip();
} else {
return null;
}
}
return new UnsafeBlockStateMatcher(holder.value().id(), properties);
}
}

View File

@@ -162,4 +162,9 @@ public abstract class Property<T extends Comparable<T>> {
.map(it -> it.apply(property))
.orElse(((context, state) -> ImmutableBlockState.with(state, property, property.defaultValue())));
}
@SuppressWarnings("unchecked")
public static <T extends Comparable<T>> String formatValue(Property<T> property, Comparable<?> value) {
return property.valueName((T) value);
}
}

View File

@@ -384,7 +384,12 @@ public abstract class AbstractFontManager implements FontManager {
Key imageId = new Key(split[0], split[1]);
Optional<BitmapImage> bitmapImage = bitmapImageByImageId(imageId);
if (bitmapImage.isPresent()) {
image = bitmapImage.get().miniMessage(Integer.parseInt(split[2]), Integer.parseInt(split[3]));
try {
image = bitmapImage.get().miniMessage(Integer.parseInt(split[2]), Integer.parseInt(split[3]));
} catch (ArrayIndexOutOfBoundsException e) {
TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage);
return;
}
} else {
TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage);
return;
@@ -462,15 +467,20 @@ public abstract class AbstractFontManager implements FontManager {
}
}).toList();
} else {
String character = (String) section.get("char");
if (character == null) {
Object c = section.get("char");
if (c == null) {
TranslationManager.instance().log("warning.config.image.lack_char", path.toString(), id.toString());
return;
}
if (character.length() == 1) {
chars = List.of(character.toCharArray());
if (c instanceof Integer integer) {
chars = List.of(new char[]{(char) integer.intValue()});
} else {
chars = List.of(CharacterUtils.decodeUnicodeToChars(character));
String character = c.toString();
if (character.length() == 1) {
chars = List.of(character.toCharArray());
} else {
chars = List.of(CharacterUtils.decodeUnicodeToChars(character));
}
}
}
@@ -492,6 +502,10 @@ public abstract class AbstractFontManager implements FontManager {
return;
}
}
if (codepoints.length == 0) {
TranslationManager.instance().log("warning.config.image.lack_char", path.toString(), id.toString());
return;
}
codepointGrid[i] = codepoints;
if (size == -1) size = codepoints.length;
if (size != codepoints.length) {

View File

@@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public interface FontManager extends Manageable {
Key DEFAULT_FONT = Key.of("minecraft:default");
@@ -103,4 +104,6 @@ public interface FontManager extends Manageable {
}
Map<String, Component> matchTags(String json);
void refreshEmojiSuggestions(UUID uuid);
}

View File

@@ -229,25 +229,29 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH);
return new TrimModifier<>(material, pattern);
}, "trim");
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
registerDataFunction((obj) -> {
Map<String, Object> data = MiscUtils.castToMap(obj, false);
return new ComponentModifier<>(data);
}, "components", "component");
registerDataFunction((obj) -> {
List<String> data = MiscUtils.getAsStringList(obj);
return new RemoveComponentModifier<>(data);
}, "remove-components", "remove-component");
}
if (VersionHelper.isVersionNewerThan1_21()) {
if (VersionHelper.isOrAbove1_21()) {
registerDataFunction((obj) -> {
String song = obj.toString();
return new JukeboxSongModifier<>(new JukeboxPlayable(song, true));
}, "jukebox-playable");
}
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
registerDataFunction((obj) -> {
String id = obj.toString();
return new TooltipStyleModifier<>(Key.of(id));
}, "tooltip-style");
}
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
registerDataFunction((obj) -> {
Map<String, Object> data = MiscUtils.castToMap(obj, false);
return new EquippableModifier<>(EquipmentData.fromMap(data));

View File

@@ -104,7 +104,7 @@ public class EquipmentData {
map.put("dispensable", this.dispensable);
map.put("swappable", this.swappable);
map.put("damage_on_hurt", this.damageOnHurt);
if (VersionHelper.isVersionNewerThan1_21_5()) {
if (VersionHelper.isOrAbove1_21_5()) {
map.put("equip_on_interact", this.equipOnInteract);
}
if (this.cameraOverlay != null) {

View File

@@ -25,7 +25,7 @@ public class ItemSettings {
public <I> List<ItemDataModifier<I>> modifiers() {
ArrayList<ItemDataModifier<I>> modifiers = new ArrayList<>();
if (VersionHelper.isVersionNewerThan1_21_2() && this.equipment != null && this.equipment.modernData() != null) modifiers.add(new EquippableModifier<>(this.equipment.modernData()));
if (VersionHelper.isOrAbove1_21_2() && this.equipment != null && this.equipment.modernData() != null) modifiers.add(new EquippableModifier<>(this.equipment.modernData()));
// TODO 1.20 leather armor
return modifiers;
}
@@ -172,7 +172,7 @@ public class ItemSettings {
registerFactory("equippable", (value -> {
Map<String, Object> args = MiscUtils.castToMap(value, false);
EquipmentData data;
if (VersionHelper.isVersionNewerThan1_21_2() && args.containsKey("slot")) data = EquipmentData.fromMap(args);
if (VersionHelper.isOrAbove1_21_2() && args.containsKey("slot")) data = EquipmentData.fromMap(args);
else data = null;
EquipmentGeneration equipment = new EquipmentGeneration(
EquipmentGeneration.Layer.fromConfig(args.get("humanoid")),

View File

@@ -0,0 +1,36 @@
package net.momirealms.craftengine.core.item.modifier;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import java.util.Collections;
import java.util.List;
public class RemoveComponentModifier<I> implements ItemDataModifier<I> {
private final List<String> arguments;
public RemoveComponentModifier(List<String> arguments) {
this.arguments = arguments;
}
public List<String> arguments() {
return Collections.unmodifiableList(this.arguments);
}
@Override
public String name() {
return "remove-components";
}
@Override
public void apply(Item<I> item, ItemBuildContext context) {
for (String argument : arguments) {
item.removeComponent(argument);
}
}
@Override
public void remove(Item<I> item) {
// I can't guess
}
}

View File

@@ -40,9 +40,9 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
}
private VanillaRecipeReader initVanillaRecipeReader() {
if (VersionHelper.isVersionNewerThan1_21_2()) {
if (VersionHelper.isOrAbove1_21_2()) {
return new VanillaRecipeReader1_21_2();
} else if (VersionHelper.isVersionNewerThan1_20_5()) {
} else if (VersionHelper.isOrAbove1_20_5()) {
return new VanillaRecipeReader1_20_5();
} else {
return new VanillaRecipeReader1_20();

View File

@@ -161,7 +161,7 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
public static final Key KEEP_TAGS = Key.of("craftengine:keep_tags");
static {
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isOrAbove1_20_5()) {
register(KEEP_COMPONENTS, KeepComponents.FACTORY);
} else {
register(KEEP_TAGS, KeepTags.FACTORY);

View File

@@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.loot.function.LootFunction;
import net.momirealms.craftengine.core.loot.function.LootFunctions;
import net.momirealms.craftengine.core.loot.number.NumberProvider;
import net.momirealms.craftengine.core.util.MCUtils;
import org.apache.commons.lang3.mutable.MutableInt;
import net.momirealms.craftengine.core.util.MutableInt;
import java.util.List;
import java.util.Random;
@@ -64,7 +64,7 @@ public class LootPool<T> {
private void addRandomItem(Consumer<Item<T>> lootConsumer, LootContext context) {
Random randomSource = context.randomSource();
List<LootEntry<T>> list = Lists.newArrayList();
MutableInt mutableInt = new MutableInt();
MutableInt mutableInt = new MutableInt(0);
for (LootEntryContainer<T> lootPoolEntryContainer : this.entryContainers) {
lootPoolEntryContainer.expand(context, (choice) -> {
int i = choice.getWeight(context.luck());

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.core.plugin;
import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel;
import net.momirealms.craftengine.core.entity.player.Player;
import java.util.UUID;
public interface CompatibilityManager {
void onLoad();
void onEnable();
void onDelayedEnable();
AbstractExternalModel createModelEngineModel(String id);
AbstractExternalModel createBetterModelModel(String id);
int interactionToBaseEntity(int id);
boolean hasPlaceholderAPI();
boolean isPluginEnabled(String plugin);
boolean hasPlugin(String plugin);
String parse(Player player, String text);
int getPlayerProtocolVersion(UUID uuid);
}

View File

@@ -29,7 +29,6 @@ import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter;
import net.momirealms.craftengine.core.plugin.network.NetworkManager;
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter;
import net.momirealms.craftengine.core.sound.SoundManager;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
@@ -68,6 +67,7 @@ public abstract class CraftEngine implements Plugin {
protected SoundManager soundManager;
protected VanillaLootManager vanillaLootManager;
protected AdvancementManager advancementManager;
protected CompatibilityManager compatibilityManager;
private final Consumer<CraftEngine> reloadEventDispatcher;
private boolean isReloading;
@@ -82,7 +82,6 @@ public abstract class CraftEngine implements Plugin {
protected CraftEngine(Consumer<CraftEngine> reloadEventDispatcher) {
instance = this;
this.reloadEventDispatcher = reloadEventDispatcher;
VersionHelper.init(serverVersion());
}
public static CraftEngine instance() {
@@ -371,8 +370,6 @@ public abstract class CraftEngine implements Plugin {
return isInitializing;
}
public abstract boolean hasPlaceholderAPI();
@Override
public DependencyManager dependencyManager() {
return dependencyManager;
@@ -460,4 +457,9 @@ public abstract class CraftEngine implements Plugin {
public VanillaLootManager vanillaLootManager() {
return vanillaLootManager;
}
@Override
public CompatibilityManager compatibilityManager() {
return compatibilityManager;
}
}

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin;
import net.momirealms.craftengine.core.advancement.AdvancementManager;
import net.momirealms.craftengine.core.block.BlockManager;
import net.momirealms.craftengine.core.entity.furniture.FurnitureManager;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.font.FontManager;
import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.item.recipe.RecipeManager;
@@ -90,7 +89,5 @@ public interface Plugin {
void debug(Supplier<String> message);
boolean isPluginEnabled(String plugin);
String parse(Player player, String text);
CompatibilityManager compatibilityManager();
}

View File

@@ -98,6 +98,7 @@ public class Config {
protected boolean chunk_system$restore_vanilla_blocks_on_chunk_unload;
protected boolean chunk_system$restore_custom_blocks_on_chunk_load;
protected boolean chunk_system$sync_custom_blocks_on_chunk_load;
protected int chunk_system$delay_serialization;
protected boolean furniture$handle_invalid_furniture_on_chunk_load$enable;
protected Map<String, String> furniture$handle_invalid_furniture_on_chunk_load$mapping;
@@ -265,6 +266,7 @@ public class Config {
chunk_system$restore_vanilla_blocks_on_chunk_unload = config.getBoolean("chunk-system.restore-vanilla-blocks-on-chunk-unload", true);
chunk_system$restore_custom_blocks_on_chunk_load = config.getBoolean("chunk-system.restore-custom-blocks-on-chunk-load", true);
chunk_system$sync_custom_blocks_on_chunk_load = config.getBoolean("chunk-system.sync-custom-blocks-on-chunk-load", false);
chunk_system$delay_serialization = config.getInt("chunk-system.delay-serialization", 20);
// furniture
furniture$handle_invalid_furniture_on_chunk_load$enable = config.getBoolean("furniture.handle-invalid-furniture-on-chunk-load.enable", false);
@@ -683,6 +685,10 @@ public class Config {
return instance.furniture$collision_entity_type;
}
public static int delaySerialization() {
return instance.chunk_system$delay_serialization;
}
public YamlDocument loadOrCreateYamlData(String fileName) {
File file = new File(this.plugin.dataFolderFile(), fileName);
if (!file.exists()) {

View File

@@ -406,7 +406,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
@@ -415,7 +415,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -489,7 +489,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -498,7 +498,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}));
@@ -522,7 +522,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -531,7 +531,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}));
@@ -555,7 +555,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -564,7 +564,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}));
@@ -613,7 +613,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
@@ -622,7 +622,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -649,7 +649,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -658,7 +658,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -746,7 +746,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
@@ -755,7 +755,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -788,7 +788,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -797,7 +797,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -891,7 +891,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, result, e.gui(), 0);
}
@@ -900,7 +900,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}))
@@ -983,7 +983,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -992,7 +992,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}));
@@ -1026,7 +1026,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
} else if (canOpenNoRecipePage) {
openNoRecipePage(player, e.item().id(), e.gui(), 0);
}
@@ -1035,7 +1035,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
if (inRecipes == recipes) return;
player.playSound(Constants.SOUND_CLICK_BUTTON);
if (!inRecipes.isEmpty()) {
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage);
openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, canOpenNoRecipePage);
}
}
}));

View File

@@ -51,4 +51,12 @@ public interface NetWorkUser {
void setClientModState(boolean enable);
void addResourcePackUUID(UUID uuid);
ProtocolVersion protocolVersion();
void setProtocolVersion(int protocolVersion);
boolean sentResourcePack();
void setSentResourcePack(boolean sentResourcePack);
}

View File

@@ -9,6 +9,7 @@ import java.util.List;
public interface NetworkManager extends Manageable {
String MOD_CHANNEL = "craftengine:payload";
String VIA_CHANNEL = "vv:proxy_details";
void setUser(Channel channel, NetWorkUser user);

View File

@@ -0,0 +1,52 @@
package net.momirealms.craftengine.core.plugin.network;
public enum ProtocolVersion {
UNKNOWN(-1, "Unknown"),
V1_20(763, "1.20"),
V1_20_1(763, "1.20.1"),
V1_20_2(764, "1.20.2"),
V1_20_3(765, "1.20.3"),
V1_20_4(765, "1.20.4"),
V1_20_5(766, "1.20.5"),
V1_20_6(766, "1.20.6"),
V1_21(767, "1.21"),
V1_21_1(767, "1.21.1"),
V1_21_2(768, "1.21.2"),
V1_21_3(768, "1.21.3"),
V1_21_4(769, "1.21.4"),
V1_21_5(770, "1.21.5");
private final int id;
private final String name;
ProtocolVersion(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static ProtocolVersion getByName(String name) {
for (ProtocolVersion version : values()) {
if (version.getName().equals(name)) {
return version;
}
}
return UNKNOWN;
}
public static ProtocolVersion getById(int id) {
for (ProtocolVersion version : values()) {
if (version.getId() == id) {
return version;
}
}
return UNKNOWN;
}
}

Some files were not shown because too many files have changed in this diff Show More