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

Merge pull request #284 from Xiao-MoMi/dev

0.0.60
This commit is contained in:
XiaoMoMi
2025-07-14 03:02:43 +08:00
committed by GitHub
510 changed files with 8323 additions and 2401 deletions

View File

@@ -58,6 +58,8 @@ dependencies {
compileOnly("org.bstats:bstats-bukkit:${rootProject.properties["bstats_version"]}")
// Aho-Corasick java implementation
compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}")
// authlib
compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}")
}
java {
@@ -96,6 +98,7 @@ tasks {
relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex")
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
}
}

View File

@@ -34,7 +34,7 @@ dependencies {
// ModelEngine
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.8")
// BetterModels
compileOnly("io.github.toxicity188:BetterModel:1.4.2")
compileOnly("io.github.toxicity188:BetterModel:1.7.0")
// MMOItems
compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT")
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")

View File

@@ -210,7 +210,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
Plugin fastAsyncWorldEdit = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit");
String version = VersionHelper.isPaper() ? fastAsyncWorldEdit.getPluginMeta().getVersion() : fastAsyncWorldEdit.getDescription().getVersion();
if (!this.fastAsyncWorldEditVersionCheck(version)) {
if (VersionHelper.isOrAbove1_20_3()) {
this.plugin.logger().severe("");
if (Locale.getDefault() == Locale.SIMPLIFIED_CHINESE) {

View File

@@ -4,20 +4,33 @@ import net.momirealms.craftengine.core.item.ExternalItemProvider;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class CustomFishingProvider implements ExternalItemProvider<ItemStack> {
@Override
public String plugin() {
return "CustomFishing";
}
@SuppressWarnings("UnstableApiUsage")
@Nullable
@Override
public ItemStack build(String id, ItemBuildContext context) {
return BukkitCustomFishingPlugin.getInstance().getItemManager()
.buildInternal(Context.player(((Player) context.player().platformPlayer())), id);
Context<Player> ctx = Context.player(
(Player) Optional.ofNullable(context.player())
.map(net.momirealms.craftengine.core.entity.player.Player::platformPlayer)
.orElse(null)
);
return BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(ctx.arg(ContextKeys.ID, id), id);
}
@Override
public String id(ItemStack item) {
return BukkitCustomFishingPlugin.getInstance().getItemManager().getCustomFishingItemID(item);
}
}

View File

@@ -9,8 +9,6 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
import static java.util.Objects.requireNonNull;
public class MMOItemsProvider implements ExternalItemProvider<ItemStack> {
@@ -23,7 +21,12 @@ public class MMOItemsProvider implements ExternalItemProvider<ItemStack> {
@Override
public @Nullable ItemStack build(String id, ItemBuildContext context) {
String[] split = id.split(":", 2);
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase(Locale.ENGLISH));
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase());
return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build());
}
@Override
public String id(ItemStack item) {
return MMOItems.getType(item) + ":" + MMOItems.getID(item);
}
}

View File

@@ -22,4 +22,12 @@ public class MythicMobsProvider implements ExternalItemProvider<ItemStack> {
}
return mythicBukkit.getItemManager().getItemStack(id);
}
@Override
public String id(ItemStack item) {
if (mythicBukkit == null || mythicBukkit.isClosed()) {
this.mythicBukkit = MythicBukkit.inst();
}
return mythicBukkit.getItemManager().getMythicTypeFromItem(item);
}
}

View File

@@ -19,4 +19,9 @@ public class NeigeItemsProvider implements ExternalItemProvider<ItemStack> {
public ItemStack build(String id, ItemBuildContext context) {
return ItemManager.INSTANCE.getItemStack(id, Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null));
}
@Override
public String id(ItemStack item) {
return ItemManager.INSTANCE.getItemId(item);
}
}

View File

@@ -1,13 +1,13 @@
package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
import kr.toxicity.model.api.BetterModel;
import kr.toxicity.model.api.data.renderer.BlueprintRenderer;
import kr.toxicity.model.api.data.renderer.ModelRenderer;
import org.bukkit.entity.Entity;
public class BetterModelUtils {
public static void bindModel(Entity base, String id) {
BlueprintRenderer renderer = BetterModel.inst().modelManager().renderer(id);
ModelRenderer renderer = BetterModel.plugin().modelManager().renderer(id);
if (renderer == null) {
throw new NullPointerException("Could not find BetterModel blueprint " + id);
}

View File

@@ -29,12 +29,10 @@ public class CraftEngineItemDrop extends ItemDrop implements IItemDrop {
public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem<ItemStack> customItem) {
super(line, config);
this.customItem = customItem;
CraftEngine.instance().debug(() -> "[MM调试] " + customItem.id() + " 注册成功");
}
@Override
public AbstractItemStack getDrop(DropMetadata dropMetadata, double amount) {
CraftEngine.instance().debug(() -> "[MM调试] getDrop() dropMetadata={" + dropMetadata + "}, amount={" + amount + "}");
ItemBuildContext context = ItemBuildContext.EMPTY;
SkillCaster caster = dropMetadata.getCaster();
if (caster != null && caster.getEntity() instanceof AbstractPlayer abstractPlayer) {

View File

@@ -20,7 +20,6 @@ public class MythicMobsListener implements Listener {
public void onMythicDropLoad(MythicDropLoadEvent event) {
if (!event.getDropName().equalsIgnoreCase("craftengine")) return;
String argument = event.getArgument();
plugin.debug(() -> "[MM调试] " + argument);
Key itemId = Key.of(argument);
this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> {
String line = event.getContainer().getConfigLine();

View File

@@ -211,7 +211,6 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
int newStateId = ordinalToIbdID[newBlock.getOrdinal()];
int oldStateId = ordinalToIbdID[oldBlock.getOrdinal()];
this.brokenChunks.add(ChunkPos.of(chunkX, chunkZ));
//CraftEngine.instance().debug(() -> "Processing block at " + blockX + ", " + blockY + ", " + blockZ + ": " + oldStateId + " -> " + newStateId);
if (BlockStateUtils.isVanillaBlock(newStateId) && BlockStateUtils.isVanillaBlock(oldStateId)) return;
try {
CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ))
@@ -231,7 +230,6 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
private void saveAllChunks() {
try {
for (CEChunk ceChunk : this.chunksToSave) {
CraftEngine.instance().debug(() -> "Saving chunk " + ceChunk.chunkPos());
this.ceWorld.worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk);
}
this.chunksToSave.clear();

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.bukkit.util;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.Inventory;
@@ -65,4 +66,8 @@ public class LegacyInventoryUtils {
public static void openWorkbench(Player player) {
player.openWorkbench(null, true);
}
public static Player getPlayerFromInventoryEvent(InventoryEvent event) {
return (Player) event.getView().getPlayer();
}
}

View File

@@ -76,5 +76,6 @@ tasks {
relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream")
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
}
}

View File

@@ -76,7 +76,6 @@ paper {
// external models
register("ModelEngine") { required = false }
register("BetterModel") { required = false }
register("FreeMinecraftModels") { required = false }
// external items
register("NeigeItems") { required = false }
@@ -149,5 +148,6 @@ tasks {
relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream")
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
}
}

View File

@@ -184,7 +184,7 @@ public final class CraftEngineBlocks {
world.playBlockSound(position, state.settings().sounds().breakSound());
}
if (sendParticles) {
FastNMS.INSTANCE.method$Level$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId());
}
FastNMS.INSTANCE.method$Level$removeBlock(world.serverWorld(), LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), isMoving);
return true;

View File

@@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
@@ -276,7 +277,9 @@ public final class CraftEngineFurniture {
.withParameter(DirectContextParameters.FURNITURE, furniture)
.withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null));
if (player != null) {
builder.withParameter(DirectContextParameters.PLAYER, player);
Item<?> itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND);
builder.withParameter(DirectContextParameters.PLAYER, player)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand.isEmpty() ? null : itemInHand);
}
List<Item<ItemStack>> items = lootTable.getRandomItems(builder.build(), world, player);
for (Item<ItemStack> item : items) {

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.api;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.inventory.ItemStack;
@@ -31,7 +31,7 @@ public final class CraftEngineItems {
*/
@Nullable
public static CustomItem<ItemStack> byItemStack(@NotNull ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return null;
if (ItemStackUtils.isEmpty(itemStack)) return null;
return BukkitItemManager.instance().wrap(itemStack).getCustomItem().orElse(null);
}
@@ -42,7 +42,7 @@ public final class CraftEngineItems {
* @return true if it's a custom item
*/
public static boolean isCustomItem(@NotNull ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return false;
if (ItemStackUtils.isEmpty(itemStack)) return false;
return BukkitItemManager.instance().wrap(itemStack).isCustomItem();
}
@@ -54,7 +54,7 @@ public final class CraftEngineItems {
*/
@Nullable
public static Key getCustomItemId(@NotNull ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return null;
if (ItemStackUtils.isEmpty(itemStack)) return null;
return BukkitItemManager.instance().wrap(itemStack).customId().orElse(null);
}
}

View File

@@ -21,6 +21,7 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Cancellable;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.WorldPosition;
@@ -35,7 +36,6 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.world.GenericGameEvent;
import org.bukkit.inventory.ItemStack;
@@ -52,14 +52,6 @@ public final class BlockEventListener implements Listener {
this.enableNoteBlockCheck = enableNoteBlockCheck;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Object packet = this.manager.cachedUpdateTagsPacket;
if (packet != null) {
this.plugin.adapt(event.getPlayer()).sendPacket(packet, false);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerAttack(EntityDamageByEntityEvent event) {
if (!VersionHelper.isOrAbove1_20_5()) {
@@ -125,7 +117,7 @@ public final class BlockEventListener implements Listener {
WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5);
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
if (itemInHand != null) {
if (!ItemUtils.isEmpty(itemInHand)) {
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
if (optionalCustomItem.isPresent()) {
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
@@ -167,7 +159,7 @@ public final class BlockEventListener implements Listener {
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state)
.withParameter(DirectContextParameters.EVENT, cancellable)
.withParameter(DirectContextParameters.POSITION, position)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand)
);
state.owner().value().execute(context, EventTrigger.BREAK);
if (cancellable.isCancelled()) {
@@ -189,7 +181,7 @@ public final class BlockEventListener implements Listener {
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
.withParameter(DirectContextParameters.POSITION, position)
.withParameter(DirectContextParameters.PLAYER, serverPlayer)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand).build();
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand).build();
for (LootTable<?> lootTable : it.lootTables()) {
for (Item<?> item : lootTable.getRandomItems(lootContext, world, serverPlayer)) {
world.dropItemNaturally(position, item);

View File

@@ -94,7 +94,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
private BlockEventListener blockEventListener;
private FallingBlockRemoveListener fallingBlockRemoveListener;
// cached tag packet
Object cachedUpdateTagsPacket;
private Object cachedUpdateTagsPacket;
private final List<Tuple<Object, Key, Boolean>> blocksToDeceive = new ArrayList<>();
@@ -276,7 +276,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
}
private void registerEmptyBlock() {
Holder.Reference<CustomBlock> holder = ((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty")));
Holder.Reference<CustomBlock> holder = ((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty")));
EmptyBlock emptyBlock = new EmptyBlock(Key.withDefaultNamespace("empty"), holder);
holder.bindValue(emptyBlock);
}
@@ -397,6 +397,10 @@ public final class BukkitBlockManager extends AbstractBlockManager {
}
}
public Object cachedUpdateTagsPacket() {
return cachedUpdateTagsPacket;
}
public class BlockParser implements ConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
@@ -500,13 +504,9 @@ public final class BukkitBlockManager extends AbstractBlockManager {
Object clientBoundTags = settings.get("client-bound-tags");
if (clientBoundTags instanceof List<?> list) {
List<String> clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList();
try {
Object nmsBlock = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id));
FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, nmsBlock).ifPresent(i ->
BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags));
} catch (ReflectiveOperationException e) {
BukkitBlockManager.this.plugin.logger().warn("Unable to get block " + id, e);
}
Object nmsBlock = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id));
FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, nmsBlock).ifPresent(i ->
BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags));
}
}
}
@@ -657,7 +657,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
private void recordVanillaNoteBlocks() {
try {
Object resourceLocation = KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK);
Object block = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation);
Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation);
Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(block);
@SuppressWarnings("unchecked")
ImmutableList<Object> states = (ImmutableList<Object>) CoreReflections.field$StateDefinition$states.get(stateDefinition);
@@ -841,8 +841,8 @@ public final class BukkitBlockManager extends AbstractBlockManager {
return FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath(key.namespace(), key.value());
}
private Object getBlockFromRegistry(Object resourceLocation) throws Exception {
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation);
private Object getBlockFromRegistry(Object resourceLocation) {
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation);
}
private Key createRealBlockKey(Key replacedBlock, int index) {

View File

@@ -130,8 +130,8 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance());
CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds()));
// 1.21.2以前要在init cache之前设定 isConditionallyFullOpaque
boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion;
if (!VersionHelper.isOrAbove1_21_2()) {
boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion;
CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque);
}
// init cache
@@ -162,6 +162,9 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
} else {
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle())));
}
if (!isConditionallyFullOpaque) {
CoreReflections.field$BlockStateBase$opacityIfCached.set(nmsState, blockLight);
}
}
// set fluid later
if (settings.fluidState()) {
@@ -251,9 +254,8 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
@Override
public @NotNull CustomBlock build() {
// create or get block holder
Holder.Reference<CustomBlock> holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() ->
((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id)));
return new BukkitCustomBlock(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable);
Holder.Reference<CustomBlock> holder = ((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), this.id));
return new BukkitCustomBlock(this.id, holder, this.properties, this.appearances, this.variantMapper, this.settings, this.events, this.behavior, this.lootTable);
}
}
}

View File

@@ -53,7 +53,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world = args[1];
Object blockPos = args[2];
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2);
}
@Override
@@ -66,7 +66,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
return state;
}
if (this.delay != 0) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, blockPos, thisBlock, this.delay);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, blockPos, thisBlock, this.delay);
return state;
}
if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) {
@@ -75,7 +75,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
world.playBlockSound(position, customState.settings().sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return state;

View File

@@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.MirrorUtils;
import net.momirealms.craftengine.bukkit.util.RotationUtils;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
@@ -154,7 +155,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(args[3]);
if (!immutableBlockState.get(this.waterloggedProperty) && fluidType == MFluids.WATER) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().handle(), 3);
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[0], args[1], fluidType, 5);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[0], args[1], fluidType, 5);
return true;
}
return false;
@@ -172,4 +173,15 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
protected static final int updateShape$blockPos = VersionHelper.isOrAbove1_21_2() ? 3 : 4;
protected static final int updateShape$neighborState = VersionHelper.isOrAbove1_21_2() ? 6 : 2;
protected static final int updateShape$direction = VersionHelper.isOrAbove1_21_2() ? 4 : 1;
protected static final int isPathFindable$type = VersionHelper.isOrAbove1_20_5() ? 1 : 3;
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
if (optionalCustomState.isEmpty()) return false;
BlockStateWrapper vanillaState = optionalCustomState.get().vanillaBlockState();
if (vanillaState == null) return false;
return FastNMS.INSTANCE.method$BlockStateBase$isPathFindable(vanillaState.handle(), VersionHelper.isOrAbove1_20_5() ? null : args[1], VersionHelper.isOrAbove1_20_5() ? null : args[2], args[isPathFindable$type]);
}
}

View File

@@ -26,6 +26,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block");
public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block");
public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block");
public static final Key DOUBLE_BLOCK = Key.from("craftengine:double_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -50,5 +51,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(SLAB_BLOCK, SlabBlockBehavior.FACTORY);
register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY);
register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY);
register(DOUBLE_BLOCK, DoubleBlockBehavior.FACTORY);
}
}

View File

@@ -22,6 +22,7 @@ import net.momirealms.craftengine.core.plugin.context.SimpleContext;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.Vec3d;
@@ -127,7 +128,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem();
if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
return InteractionResult.PASS;
if (isMaxAge(state))
return InteractionResult.PASS;

View File

@@ -1,8 +1,11 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
@@ -15,8 +18,10 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.block.state.properties.DoorHinge;
import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.sound.SoundData;
@@ -32,6 +37,7 @@ import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Door;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import javax.annotation.Nullable;
@@ -111,13 +117,44 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
world.playBlockSound(position, customState.settings().sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return blockState;
}
}
@Override
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object level = args[0];
Object pos = args[1];
Object state = args[2];
Object player = args[3];
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
if (blockState == null || blockState.isEmpty()) return superMethod.call();
org.bukkit.entity.Player bukkitPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player);
BukkitServerPlayer cePlayer = BukkitCraftEngine.instance().adapt(bukkitPlayer);
Item<ItemStack> item = cePlayer.getItemInHand(InteractionHand.MAIN_HAND);
if (cePlayer.canInstabuild() || !BlockStateUtils.isCorrectTool(blockState, item)) {
preventDropFromBottomPart(level, pos, blockState, player);
}
return superMethod.call();
}
private void preventDropFromBottomPart(Object level, Object pos, ImmutableBlockState state, Object player) {
DoubleBlockHalf half = state.get(this.halfProperty);
if (half == DoubleBlockHalf.UPPER) {
Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$DOWN);
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos);
ImmutableBlockState belowState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (belowState == null || belowState.isEmpty()) return;
Optional<DoorBlockBehavior> belowDoorBehavior = belowState.behavior().getAs(DoorBlockBehavior.class);
if (belowDoorBehavior.isEmpty() || belowState.get(this.halfProperty) != DoubleBlockHalf.LOWER) return;
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, MBlocks.AIR$defaultState, UpdateOption.builder().updateSuppressDrops().updateClients().updateNeighbors().build().flags());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, player, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, belowState.customBlockState().registryId());
}
}
@Override
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {

View File

@@ -0,0 +1,90 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.*;
import java.util.Map;
import java.util.concurrent.Callable;
public class DoubleBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<DoubleBlockHalf> halfProperty;
public DoubleBlockBehavior(CustomBlock customBlock, Property<DoubleBlockHalf> halfProperty) {
super(customBlock);
this.halfProperty = halfProperty;
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object level = args[updateShape$level];
Object blockPos = args[updateShape$blockPos];
Object blockState = args[0];
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (customState == null || customState.isEmpty()) return blockState;
DoubleBlockHalf half = customState.get(this.halfProperty);
if (half == null) return blockState;
// 获取另一半
Object anotherHalfPos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos,
half == DoubleBlockHalf.UPPER
? CoreReflections.instance$Direction$DOWN
: CoreReflections.instance$Direction$UP
);
Object anotherHalfState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, anotherHalfPos);
ImmutableBlockState anotherHalfCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(anotherHalfState));
if (anotherHalfCustomState != null && !anotherHalfCustomState.isEmpty()) return blockState;
// 破坏
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
world.playBlockSound(position, customState.settings().sounds().breakSound());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
@Override
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) {
World level = context.getLevel();
BlockPos anotherHalfPos = context.getClickedPos().relative(Direction.UP);
BlockStateWrapper blockStateWrapper = state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState();
FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.handle(), UpdateOption.Flags.UPDATE_CLIENTS);
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
World world = context.getLevel();
BlockPos pos = context.getClickedPos();
if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() && world.getBlockAt(pos.above()).canBeReplaced(context)) {
return state.with(this.halfProperty, DoubleBlockHalf.LOWER);
}
return null;
}
@SuppressWarnings("unchecked")
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<DoubleBlockHalf> half = (Property<DoubleBlockHalf>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.double.missing_half");
return new DoubleBlockBehavior(block, half);
}
}
}

View File

@@ -37,14 +37,14 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world = args[1];
Object blockPos = args[2];
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2);
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world = args[updateShape$level];
Object blockPos = args[updateShape$blockPos];
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2);
return args[0];
}

View File

@@ -83,7 +83,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem();
if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
return InteractionResult.PASS;
BlockPos pos = context.getClickedPos();
BukkitBlockInWorld upper = (BukkitBlockInWorld) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z());
@@ -107,12 +107,11 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
return InteractionResult.SUCCESS;
}
@SuppressWarnings("unchecked")
@Override
public void performBoneMeal(Object thisBlock, Object[] args) throws Exception {
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE);
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE);
if (registry == null) return;
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature()));
Optional<Object> holder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature()));
if (holder.isEmpty()) {
CraftEngine.instance().logger().warn("Placed feature not found: " + boneMealFeature());
return;

View File

@@ -59,7 +59,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
boolean lit = customState.get(this.litProperty);
if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
if (lit) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 4);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 4);
} else {
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
return;

View File

@@ -66,7 +66,7 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
LeavesBlockBehavior behavior = optionalBehavior.get();
int distance = behavior.getDistanceAt(neighborState) + 1;
if (distance != 1 || behavior.getDistance(optionalCustomState.get()) != distance) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 1);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 1);
}
}
}

View File

@@ -86,8 +86,8 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
}
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) {
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, belowPos);
Object fluidStateAbove = FastNMS.INSTANCE.method$Level$getFluidState(world, LocationUtils.above(belowPos));
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, belowPos);
Object fluidStateAbove = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, LocationUtils.above(belowPos));
if (FastNMS.INSTANCE.method$FluidState$getType(fluidStateAbove) != MFluids.EMPTY) {
return false;
}

View File

@@ -65,8 +65,8 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
return true;
}
}
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, belowPos);
Object fluidStateAbove = FastNMS.INSTANCE.method$Level$getFluidState(world, LocationUtils.above(belowPos));
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, belowPos);
Object fluidStateAbove = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, LocationUtils.above(belowPos));
if (FastNMS.INSTANCE.method$FluidState$getType(fluidStateAbove) != MFluids.EMPTY) {
return false;
}

View File

@@ -70,7 +70,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
world.playBlockSound(position, customState.settings().sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return state;
@@ -106,7 +106,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock);
} else {
// todo 为什么
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime);
}
}
@@ -150,7 +150,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
}
if (isActive) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, pos, thisBlock, this.pressedTime);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.pressedTime);
}
}
@@ -182,6 +182,21 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
}
}
@Override
public void onRemove(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object state = args[0];
Object level = args[1];
Object pos = args[2];
Object newState = args[3];
boolean movedByPiston = (boolean) args[4];
if (!movedByPiston && !FastNMS.INSTANCE.method$BlockStateBase$is(state, FastNMS.INSTANCE.method$BlockState$getBlock(newState))) {
if (this.getSignalForState(state) > 0) {
this.updateNeighbours(level, pos, thisBlock);
}
superMethod.call();
}
}
private void updateNeighbours(Object level, Object pos, Object thisBlock) {
FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, pos, thisBlock);
FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, LocationUtils.below(pos), thisBlock);

View File

@@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
@@ -79,17 +80,16 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
}
private void generateTree(Object world, Object blockPos, Object blockState, Object randomSource) throws Exception {
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE);
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE);
if (registry == null) return;
@SuppressWarnings("unchecked")
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature()));
Optional<Object> holder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature()));
if (holder.isEmpty()) {
CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature());
return;
}
Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world));
Object configuredFeature = CoreReflections.method$Holder$value.invoke(holder.get());
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, blockPos);
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, blockPos);
Object legacyState = CoreReflections.method$FluidState$createLegacyBlock.invoke(fluidState);
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags());
if ((boolean) CoreReflections.method$ConfiguredFeature$place.invoke(configuredFeature, world, chunkGenerator, randomSource, blockPos)) {
@@ -148,7 +148,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem();
if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
return InteractionResult.PASS;
boolean sendSwing = false;
Object visualState = state.vanillaBlockState().handle();

View File

@@ -16,10 +16,7 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.inventory.ItemStack;
@@ -41,7 +38,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
SlabType type = state.get(this.typeProperty);
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
if (type == SlabType.DOUBLE || item == null) return false;
if (type == SlabType.DOUBLE || ItemUtils.isEmpty(item)) return false;
Optional<CustomItem<ItemStack>> itemInHand = item.getCustomItem();
if (itemInHand.isEmpty()) return false;
CustomItem<ItemStack> customItem = itemInHand.get();
@@ -69,7 +66,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
blockState = blockState.with(super.waterloggedProperty, false);
return blockState.with(this.typeProperty, SlabType.DOUBLE);
} else {
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
if (super.waterloggedProperty != null)
state = state.with(super.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
Direction clickedFace = context.getClickedFace();
@@ -98,7 +95,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
if (optionalCustomState.isEmpty()) return blockState;
if (optionalCustomState.get().get(super.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
}
return blockState;
}

View File

@@ -15,6 +15,7 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
@@ -49,7 +50,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
return InteractionResult.PASS;
}
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
if (item == null) {
if (ItemUtils.isEmpty(item)) {
return InteractionResult.PASS;
}
if (!this.items.contains(item.id())) {

View File

@@ -45,7 +45,7 @@ public class StairsBlockBehavior extends BukkitBlockBehavior {
.with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection())
.with(this.halfProperty, clickedFace != Direction.DOWN && (clickedFace == Direction.UP || !(context.getClickLocation().y - clickedPos.y() > 0.5)) ? SingleBlockHalf.BOTTOM : SingleBlockHalf.TOP);
if (super.waterloggedProperty != null) {
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
blockState = blockState.with(this.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
}
return blockState.with(this.shapeProperty, getStairsShape(blockState, context.getLevel().serverWorld(), clickedPos));
@@ -60,7 +60,7 @@ public class StairsBlockBehavior extends BukkitBlockBehavior {
if (optionalCustomState.isEmpty()) return blockState;
ImmutableBlockState customState = optionalCustomState.get();
if (super.waterloggedProperty != null && customState.get(this.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
}
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
StairsShape stairsShape = getStairsShape(customState, level, LocationUtils.fromBlockPos(blockPos));

View File

@@ -77,7 +77,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
if (super.waterloggedProperty != null) {
BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> {
if (customState.get(super.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
}
});
}
@@ -99,7 +99,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
if (FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, clickedPos)) {
state = state.with(this.poweredProperty, true).with(this.openProperty, true);
}
if (this.waterloggedProperty != null && FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$Level$getFluidState(level, clickedPos)) == MFluids.WATER) {
if (this.waterloggedProperty != null && FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, clickedPos)) == MFluids.WATER) {
state = state.with(this.waterloggedProperty, true);
}
return state;
@@ -197,7 +197,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
if (this.waterloggedProperty != null && customState.get(this.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(level, blockPos, MFluids.WATER, 5);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(level, blockPos, MFluids.WATER, 5);
}
}

View File

@@ -188,7 +188,7 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
}
@Override
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.onExplosionHit(thisBlock, args, superMethod);
}
@@ -225,6 +225,13 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
}
}
@Override
public void onRemove(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.onRemove(thisBlock, args, superMethod);
}
}
@Override
public int getSignal(Object thisBlock, Object[] args, Callable<Object> superMethod) {
for (AbstractBlockBehavior behavior : this.behaviors) {
@@ -256,4 +263,23 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
}
return false;
}
@Override
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object previous = args[0];
for (AbstractBlockBehavior behavior : this.behaviors) {
Object processed = behavior.playerWillDestroy(thisBlock, args, superMethod);
if (processed != previous) {
return processed;
}
}
return previous;
}
@Override
public void spawnAfterBreak(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.spawnAfterBreak(thisBlock, args, superMethod);
}
}
}

View File

@@ -137,6 +137,7 @@ public class BukkitFurniture implements Furniture {
@NotNull
public Object spawnPacket(Player player) {
// TODO hasPermission might be slow, can we use a faster way in the future?
// TODO Make it based on conditions. So we can dynamically control which furniture should be sent to the player
if (!this.minimized || player.hasPermission(FurnitureManager.FURNITURE_ADMIN_NODE)) {
return this.cachedSpawnPacket;
} else {

View File

@@ -13,9 +13,6 @@ import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureElement;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.Material;
@@ -72,7 +69,6 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
List<Object> cachedValues = new ArrayList<>(this.commonValues);
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(item(), null);
if (item == null) {
CraftEngine.instance().debug(() -> "Failed to create furniture element because item " + item() + " not found");
item = BukkitItemManager.instance().wrap(new ItemStack(Material.BARRIER));
} else {
if (color != null) {

View File

@@ -92,8 +92,8 @@ public class HappyGhastHitBox extends AbstractHitBox {
double maxX = x + halfSize + offset.x();
double minY = y + offset.y();
double maxY = y + baseSize + offset.y();
double minZ = z - halfSize + offset.z();
double maxZ = z + halfSize + offset.z();
double minZ = z - halfSize - offset.z();
double maxZ = z + halfSize - offset.z();
return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
}
@@ -119,9 +119,9 @@ public class HappyGhastHitBox extends AbstractHitBox {
}
double scale = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("scale", 1), "scale");
boolean hardCollision = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("hard-collision", true), "hard-collision");
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", false), "blocks-building");
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new HappyGhastHitBox(
HitBoxFactory.getSeats(arguments),
MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),

View File

@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.entity.projectile.ProjectileManager;
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -47,11 +48,22 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
@Override
public void delayedInit() {
Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin());
for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities();
for (Entity entity : entities) {
if (entity instanceof Projectile projectile) {
handleProjectileLoad(projectile);
if (VersionHelper.isFolia()) {
for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities();
for (Entity entity : entities) {
if (entity instanceof Projectile projectile) {
projectile.getScheduler().run(this.plugin.javaPlugin(), (t) -> handleProjectileLoad(projectile), () -> {});
}
}
}
} else {
for (World world : Bukkit.getWorlds()) {
List<Entity> entities = world.getEntities();
for (Entity entity : entities) {
if (entity instanceof Projectile projectile) {
handleProjectileLoad(projectile);
}
}
}
}
@@ -108,7 +120,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
return;
}
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(projectileItem);
if (wrapped == null) return;
if (ItemUtils.isEmpty(wrapped)) return;
wrapped.getCustomItem().ifPresent(it -> {
ProjectileMeta meta = it.settings().projectileMeta();
if (meta != null) {
@@ -153,8 +165,13 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
this.cachedServerEntity = serverEntity;
}
if (!CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity) || !this.checkInGround) {
if (!CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity)) {
updateProjectileUpdateInterval(1);
} else if (!this.checkInGround) {
updateProjectileUpdateInterval(1);
if (FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) {
this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0);
}
} else {
boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
if (canSpawnParticle(nmsEntity, inGround)) {

View File

@@ -6,9 +6,10 @@ 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.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.InventoryUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
import net.momirealms.craftengine.core.font.*;
import net.momirealms.craftengine.core.item.Item;
@@ -130,15 +131,8 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
return;
}
ItemStack result = event.getResult();
if (result == null) return;
Player player;
try {
player = (Player) CraftBukkitReflections.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;
}
if (ItemStackUtils.isEmpty(result)) return;
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
String renameText;
if (VersionHelper.isOrAbove1_21_2()) {
AnvilView anvilView = event.getView();
@@ -149,7 +143,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
if (renameText == null || renameText.isEmpty()) return;
Component itemName = Component.text(renameText);
EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, plugin.adapt(player), renameText);
EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, this.plugin.adapt(player), renameText);
if (replaceProcessResult.changed()) {
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(result);
wrapped.customNameJson(AdventureHelper.componentToJson(replaceProcessResult.newText()));

View File

@@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
@@ -21,7 +21,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
private final Object item;
private final Object clientItem;
public BukkitCustomItem(Holder<Key> id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey,
public BukkitCustomItem(UniqueKey id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey,
List<ItemBehavior> behaviors,
List<ItemDataModifier<ItemStack>> modifiers, List<ItemDataModifier<ItemStack>> clientBoundModifiers,
ItemSettings settings,
@@ -64,7 +64,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
}
public static class BuilderImpl implements Builder<ItemStack> {
private Holder<Key> id;
private UniqueKey id;
private Key itemKey;
private final Object item;
private Key clientBoundItemKey;
@@ -81,7 +81,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
}
@Override
public Builder<ItemStack> id(Holder<Key> id) {
public Builder<ItemStack> id(UniqueKey id) {
this.id = id;
return this;
}
@@ -149,6 +149,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
@Override
public CustomItem<ItemStack> build() {
this.modifiers.addAll(this.settings.modifiers());
this.clientBoundModifiers.addAll(this.settings.clientBoundModifiers());
return new BukkitCustomItem(this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors),
List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events);
}

View File

@@ -1,5 +1,9 @@
package net.momirealms.craftengine.bukkit.item;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
@@ -11,31 +15,30 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.*;
import net.momirealms.craftengine.core.item.modifier.IdModifier;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.pack.AbstractPackManager;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceKey;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Optional;
import java.util.Set;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
static {
@@ -50,6 +53,10 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
private final DebugStickListener debugStickListener;
private final ArmorEventListener armorEventListener;
private final NetworkItemHandler<ItemStack> networkItemHandler;
private final Object bedrockItemHolder;
private final Item<ItemStack> emptyItem;
private final UniqueIdItem<ItemStack> emptyUniqueItem;
private Set<Key> lastRegisteredPatterns = Set.of();
public BukkitItemManager(BukkitCraftEngine plugin) {
super(plugin);
@@ -61,6 +68,18 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
this.armorEventListener = new ArmorEventListener();
this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler();
this.registerAllVanillaItems();
this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();;
this.registerCustomTrimMaterial();
this.loadLastRegisteredPatterns();
ItemStack emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY);
this.emptyItem = this.wrap(emptyStack);
this.emptyUniqueItem = new UniqueIdItem<>(UniqueKey.AIR, this.emptyItem);
}
@Override
public UniqueIdItem<ItemStack> uniqueEmptyItem() {
return this.emptyUniqueItem;
}
@Override
@@ -70,6 +89,17 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
Bukkit.getPluginManager().registerEvents(this.armorEventListener, this.plugin.javaPlugin());
}
@Override
public Item<ItemStack> decode(FriendlyByteBuf byteBuf) {
Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf);
return this.wrap(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf));
}
@Override
public void encode(FriendlyByteBuf byteBuf, Item<ItemStack> item) {
FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf), item.getItem());
}
@Override
public NetworkItemHandler<ItemStack> networkItemHandler() {
return this.networkItemHandler;
@@ -79,15 +109,25 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return instance;
}
@Override
public Item<ItemStack> s2c(Item<ItemStack> item, Player player) {
if (item.isEmpty()) return item;
return this.networkItemHandler.s2c(item, player).orElse(item);
}
@Override
public Item<ItemStack> c2s(Item<ItemStack> item) {
if (item.isEmpty()) return item;
return this.networkItemHandler.c2s(item).orElse(item);
}
public Optional<ItemStack> s2c(ItemStack itemStack, Player player) {
try {
Item<ItemStack> wrapped = wrap(itemStack);
if (wrapped == null) return Optional.empty();
if (wrapped.isEmpty()) return Optional.empty();
return this.networkItemHandler.s2c(wrapped, player).map(Item::getItem);
} catch (Throwable e) {
if (Config.debug()) {
this.plugin.logger().warn("Failed to handle s2c items.", e);
}
Debugger.ITEM.warn(() -> "Failed to handle s2c items.", e);
return Optional.empty();
}
}
@@ -95,12 +135,10 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
public Optional<ItemStack> c2s(ItemStack itemStack) {
try {
Item<ItemStack> wrapped = wrap(itemStack);
if (wrapped == null) return Optional.empty();
if (wrapped.isEmpty()) return Optional.empty();
return this.networkItemHandler.c2s(wrapped).map(Item::getItem);
} catch (Throwable e) {
if (Config.debug()) {
this.plugin.logger().warn("Failed to handle c2s items.", e);
}
Debugger.COMMON.warn(() -> "Failed to handle c2s items.", e);
return Optional.empty();
}
}
@@ -116,7 +154,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public int fuelTime(ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return 0;
if (ItemStackUtils.isEmpty(itemStack)) return 0;
Optional<CustomItem<ItemStack>> customItem = wrap(itemStack).getCustomItem();
return customItem.map(it -> it.settings().fuelTime()).orElse(0);
}
@@ -132,6 +170,127 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
HandlerList.unregisterAll(this.itemEventListener);
HandlerList.unregisterAll(this.debugStickListener);
HandlerList.unregisterAll(this.armorEventListener);
this.persistLastRegisteredPatterns();
}
@Override
protected void registerArmorTrimPattern(Collection<Key> equipments) {
if (equipments.isEmpty()) return;
this.lastRegisteredPatterns = new HashSet<>(equipments);
// 可能还没加载
if (Config.sacrificedAssetId() != null)
this.lastRegisteredPatterns.add(Config.sacrificedAssetId());
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN);
try {
CoreReflections.field$MappedRegistry$frozen.set(registry, false);
for (Key assetId : this.lastRegisteredPatterns) {
Object resourceLocation = KeyUtils.toResourceLocation(assetId);
Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation);
if (previous == null) {
Object trimPattern = createTrimPattern(assetId);
Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimPattern);
CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimPattern);
CoreReflections.field$Holder$Reference$tags.set(holder, Set.of());
}
}
} catch (Exception e) {
this.plugin.logger().warn("Failed to register armor trim pattern.", e);
} finally {
try {
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
} catch (ReflectiveOperationException ignored) {
}
}
}
private void persistLastRegisteredPatterns() {
Path persistTrimPatternPath = this.plugin.dataFolderPath()
.resolve("cache")
.resolve("trim_patterns.json");
try {
Files.createDirectories(persistTrimPatternPath.getParent());
JsonObject json = new JsonObject();
JsonArray jsonElements = new JsonArray();
for (Key key : this.lastRegisteredPatterns) {
jsonElements.add(new JsonPrimitive(key.toString()));
}
json.add("patterns", jsonElements);
if (jsonElements.isEmpty()) {
if (Files.exists(persistTrimPatternPath)) {
Files.delete(persistTrimPatternPath);
}
} else {
GsonHelper.writeJsonFile(json, persistTrimPatternPath);
}
} catch (IOException e) {
this.plugin.logger().warn("Failed to persist registered trim patterns.", e);
}
}
// 需要持久化存储上一次注册的新trim类型如果注册晚了加载世界可能导致一些物品损坏
private void loadLastRegisteredPatterns() {
Path persistTrimPatternPath = this.plugin.dataFolderPath()
.resolve("cache")
.resolve("trim_patterns.json");
if (Files.exists(persistTrimPatternPath) && Files.isRegularFile(persistTrimPatternPath)) {
try {
JsonObject cache = GsonHelper.readJsonFile(persistTrimPatternPath).getAsJsonObject();
JsonArray patterns = cache.getAsJsonArray("patterns");
Set<Key> trims = new HashSet<>();
for (JsonElement element : patterns) {
if (element instanceof JsonPrimitive primitive) {
trims.add(Key.of(primitive.getAsString()));
}
}
this.registerArmorTrimPattern(trims);
this.lastRegisteredPatterns = trims;
} catch (IOException e) {
this.plugin.logger().warn("Failed to load registered trim patterns.", e);
}
}
}
private void registerCustomTrimMaterial() {
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_MATERIAL);
Object resourceLocation = KeyUtils.toResourceLocation(Key.of("minecraft", AbstractPackManager.NEW_TRIM_MATERIAL));
Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation);
if (previous == null) {
try {
CoreReflections.field$MappedRegistry$frozen.set(registry, false);
Object trimMaterial = createTrimMaterial();
Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimMaterial);
CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimMaterial);
CoreReflections.field$Holder$Reference$tags.set(holder, Set.of());
} catch (Exception e) {
this.plugin.logger().warn("Failed to register trim material.", e);
} finally {
try {
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
} catch (ReflectiveOperationException ignored) {
}
}
}
}
private Object createTrimPattern(Key key) throws ReflectiveOperationException {
if (VersionHelper.isOrAbove1_21_5()) {
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), CoreReflections.instance$Component$empty, false);
} else if (VersionHelper.isOrAbove1_20_2()) {
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty, false);
} else {
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty);
}
}
private Object createTrimMaterial() throws ReflectiveOperationException {
if (VersionHelper.isOrAbove1_21_5()) {
Object assetGroup = CoreReflections.method$MaterialAssetGroup$create.invoke(null, "custom");
return CoreReflections.constructor$TrimMaterial.newInstance(assetGroup, CoreReflections.instance$Component$empty);
} else if (VersionHelper.isOrAbove1_21_4()) {
return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, Map.of(), CoreReflections.instance$Component$empty);
} else {
return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, 0f, Map.of(), CoreReflections.instance$Component$empty);
}
}
@SuppressWarnings("deprecation")
@@ -142,12 +301,16 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public ItemStack buildCustomItemStack(Key id, Player player) {
return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null);
return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null);
}
@Override
public ItemStack buildItemStack(Key id, @Nullable Player player) {
return Optional.ofNullable(buildCustomItemStack(id, player)).orElseGet(() -> createVanillaItemStack(id));
ItemStack customItem = buildCustomItemStack(id, player);
if (customItem != null) {
return customItem;
}
return createVanillaItemStack(id);
}
@Override
@@ -155,31 +318,30 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItem(player)).orElse(null);
}
private ItemStack createVanillaItemStack(Key id) {
NamespacedKey key = NamespacedKey.fromString(id.toString());
if (key == null) {
this.plugin.logger().warn(id + " is not a valid namespaced key");
return new ItemStack(Material.AIR);
@Override
public Item<ItemStack> createWrappedItem(Key id, @Nullable Player player) {
CustomItem<ItemStack> customItem = this.customItems.get(id);
if (customItem != null) {
return customItem.buildItem(player);
}
ItemStack itemStack = this.createVanillaItemStack(id);
if (itemStack != null) {
return wrap(itemStack);
}
return null;
}
private ItemStack createVanillaItemStack(Key id) {
Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id));
if (item == null) {
this.plugin.logger().warn(id + " is not a valid material");
return new ItemStack(Material.AIR);
return null;
}
return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(item, 1));
}
@Override
public Item<ItemStack> createWrappedItem(Key id, @Nullable Player player) {
return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItem(player)).orElseGet(() -> {
ItemStack itemStack = createVanillaItemStack(id);
return wrap(itemStack);
});
}
@Override
public Item<ItemStack> wrap(ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) return null;
public @NotNull Item<ItemStack> wrap(ItemStack itemStack) {
if (itemStack == null) return this.emptyItem;
return this.factory.wrap(itemStack);
}
@@ -197,7 +359,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
}
@Override
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Holder<Key> id, Key materialId, Key clientBoundMaterialId) {
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(UniqueKey id, Key materialId, Key clientBoundMaterialId) {
Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(materialId));
Object clientBoundItem = materialId == clientBoundMaterialId ? item : FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(clientBoundMaterialId));
if (item == null) {
@@ -220,14 +382,12 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
Key itemKey = KeyUtils.resourceLocationToKey(resourceLocation);
if (itemKey.namespace().equals("minecraft")) {
VANILLA_ITEMS.add(itemKey);
Holder.Reference<Key> holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(itemKey)
.orElseGet(() -> ((WritableRegistry<Key>) BuiltInRegistries.OPTIMIZED_ITEM_ID)
.register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), itemKey), itemKey));
Object mcHolder = ((Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.ITEM, resourceLocation))).get();
UniqueKey uniqueKey = UniqueKey.create(itemKey);
Object mcHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, resourceLocation)).get();
Set<Object> tags = (Set<Object>) CoreReflections.field$Holder$Reference$tags.get(mcHolder);
for (Object tag : tags) {
Key tagId = Key.of(CoreReflections.field$TagKey$location.get(tag).toString());
VANILLA_ITEM_TAGS.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(holder);
VANILLA_ITEM_TAGS.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(uniqueKey);
}
}
}
@@ -235,4 +395,46 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
plugin.logger().warn("Failed to init vanilla items", e);
}
}
// 1.20-1.21.4 template 不为空
// 1.21.5+ pattern 不为空
@Override
public Item<ItemStack> applyTrim(Item<ItemStack> base, Item<ItemStack> addition, Item<ItemStack> template, Key pattern) {
Optional<?> optionalMaterial = FastNMS.INSTANCE.method$TrimMaterials$getFromIngredient(addition.getLiteralObject());
Optional<?> optionalPattern = VersionHelper.isOrAbove1_21_5() ?
FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN), KeyUtils.toResourceLocation(pattern)) :
FastNMS.INSTANCE.method$TrimPatterns$getFromTemplate(template.getLiteralObject());
if (optionalMaterial.isPresent() && optionalPattern.isPresent()) {
Object armorTrim = FastNMS.INSTANCE.constructor$ArmorTrim(optionalMaterial.get(), optionalPattern.get());
Object previousTrim;
if (VersionHelper.isOrAbove1_20_5()) {
previousTrim = base.getExactComponent(ComponentKeys.TRIM);
} else {
try {
previousTrim = VersionHelper.isOrAbove1_20_2() ?
((Optional<?>) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject(), true)).orElse(null) :
((Optional<?>) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject())).orElse(null);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get armor trim", e);
return this.emptyItem;
}
}
if (armorTrim.equals(previousTrim)) {
return this.emptyItem;
}
Item<ItemStack> newItem = base.copyWithCount(1);
if (VersionHelper.isOrAbove1_20_5()) {
newItem.setExactComponent(ComponentKeys.TRIM, armorTrim);
} else {
try {
CoreReflections.method$ArmorTrim$setTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), newItem.getLiteralObject(), armorTrim);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to set armor trim", e);
return this.emptyItem;
}
}
return newItem;
}
return this.emptyItem;
}
}

View File

@@ -8,7 +8,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.ItemWrapper;
import net.momirealms.craftengine.core.util.Key;
@@ -22,12 +22,12 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
private final Object handle;
public ComponentItemWrapper(final ItemStack item) {
this.item = ItemUtils.ensureCraftItemStack(item);
this.item = ItemStackUtils.ensureCraftItemStack(item);
this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item);
}
public ComponentItemWrapper(final ItemStack item, int count) {
this.item = ItemUtils.ensureCraftItemStack(item);
this.item = ItemStackUtils.ensureCraftItemStack(item);
this.item.setAmount(count);
this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item);
}
@@ -72,8 +72,18 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
return getComponentInternal(type, MRegistryOps.NBT);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public Optional<Tag> getSparrowNBTComponent(Object type) {
return getComponentInternal(type, MRegistryOps.SPARROW_NBT);
Object componentType = ensureDataComponentType(type);
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);
try {
Object componentData = FastNMS.INSTANCE.method$ItemStack$getComponent(getLiteralObject(), componentType);
if (componentData == null) return Optional.empty();
DataResult<Tag> result = codec.encodeStart(MRegistryOps.SPARROW_NBT, componentData);
return result.result().map(Tag::copy);
} catch (Throwable t) {
throw new RuntimeException("Cannot read component " + type.toString(), t);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})

View File

@@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.item;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.item.ItemWrapper;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.inventory.ItemStack;
@@ -13,7 +13,7 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
private final ItemStack itemStack;
public LegacyItemWrapper(ItemStack item) {
this.itemStack = ItemUtils.ensureCraftItemStack(item);
this.itemStack = ItemStackUtils.ensureCraftItemStack(item);
this.nmsStack = FastNMS.INSTANCE.field$CraftItemStack$handle(this.itemStack);
}
@@ -72,6 +72,7 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
getItem().setAmount(amount);
}
@SuppressWarnings("DuplicatedCode")
public Object getExactTag(Object... path) {
Object compoundTag = FastNMS.INSTANCE.method$ItemStack$getTag(this.nmsStack);
if (compoundTag == null) return null;

View File

@@ -27,7 +27,7 @@ import java.util.Optional;
import java.util.function.BiConsumer;
@SuppressWarnings("DuplicatedCode")
public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
@Override
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
@@ -45,7 +45,7 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
return Optional.of(wrapped);
}
}
CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG);
CompoundTag networkData = (CompoundTag) wrapped.getTag(NETWORK_ITEM_TAG);
if (networkData == null) return Optional.empty();
wrapped.removeTag(NETWORK_ITEM_TAG);
for (Map.Entry<String, Tag> entry : networkData.entrySet()) {
@@ -74,7 +74,7 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
return new OtherItem(wrapped, hasDifferentMaterial).process();
} else {
CompoundTag tag = new CompoundTag();
Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG);
Tag argumentTag = wrapped.getTag(ArgumentModifier.ARGUMENTS_TAG);
ItemBuildContext context;
if (argumentTag instanceof CompoundTag arguments) {
ContextHolder.Builder builder = ContextHolder.builder();
@@ -87,6 +87,8 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
}
for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) {
modifier.prepareNetworkItem(wrapped, context, tag);
}
for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) {
modifier.apply(wrapped, context);
}
if (Config.interceptItem()) {

View File

@@ -29,7 +29,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
@Override
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA);
Tag customData = wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA);
if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty();
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
boolean hasDifferentMaterial = false;
@@ -75,7 +75,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
return new OtherItem(wrapped, hasDifferentMaterial).process();
} else {
CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag customData = Optional.ofNullable(wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag arguments = customData.getCompound(ArgumentModifier.ARGUMENTS_TAG);
ItemBuildContext context;
if (arguments == null) {
@@ -90,6 +90,8 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
CompoundTag tag = new CompoundTag();
for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) {
modifier.prepareNetworkItem(wrapped, context, tag);
}
for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) {
modifier.apply(wrapped, context);
}
if (Config.interceptItem()) {
@@ -174,7 +176,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernItemName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
Tag nameTag = item.getNBTComponent(ComponentTypes.ITEM_NAME);
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.ITEM_NAME);
if (nameTag == null) return false;
String tagStr = nameTag.getAsString();
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
@@ -187,7 +189,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
Tag nameTag = item.getNBTComponent(ComponentTypes.CUSTOM_NAME);
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.CUSTOM_NAME);
if (nameTag == null) return false;
String tagStr = nameTag.getAsString();
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
@@ -200,7 +202,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernLore(Item<ItemStack> item, Supplier<CompoundTag> tagSupplier) {
Tag loreTag = item.getNBTComponent(ComponentTypes.LORE);
Tag loreTag = item.getSparrowNBTComponent(ComponentTypes.LORE);
boolean changed = false;
if (!(loreTag instanceof ListTag listTag)) {
return false;
@@ -252,7 +254,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
this.globalChanged = true;
}
if (this.globalChanged) {
CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag customData = Optional.ofNullable(this.item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
customData.put(NETWORK_ITEM_TAG, getOrCreateTag());
this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData);
return Optional.of(this.item);

View File

@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.ItemUtils;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
@@ -67,7 +68,7 @@ public class AxeItemBehavior extends ItemBehavior {
Key stripped = behaviorOptional.get().stripped();
Item<ItemStack> offHandItem = (Item<ItemStack>) player.getItemInHand(InteractionHand.OFF_HAND);
// is using a shield
if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && canBlockAttack(offHandItem) && !player.isSecondaryUseActive()) {
if (context.getHand() == InteractionHand.MAIN_HAND && !ItemUtils.isEmpty(offHandItem) && canBlockAttack(offHandItem) && !player.isSecondaryUseActive()) {
return InteractionResult.PASS;
}
@@ -90,6 +91,8 @@ public class AxeItemBehavior extends ItemBehavior {
}
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
// 理论不可能出现
if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL;
BlockPos pos = context.getClickedPos();
context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1);
FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags());

View File

@@ -61,7 +61,7 @@ public class CompostableItemBehavior extends ItemBehavior {
context.getLevel().levelEvent(WorldEvents.COMPOSTER_COMPOSTS, context.getClickedPos(), willRaise ? 1 : 0);
((World) context.getLevel().platformWorld()).sendGameEvent((Entity) context.getPlayer().platformPlayer(), GameEvent.BLOCK_CHANGE, new Vector(block.x() + 0.5, block.y() + 0.5, block.z() + 0.5));
if (currentLevel + 1 == 7) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20);
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20);
}
if (!context.getPlayer().canInstabuild()) {
context.getItem().shrink(1);

View File

@@ -128,6 +128,8 @@ public class FurnitureItemBehavior extends ItemBehavior {
}
Item<?> item = context.getItem();
// 不可能
if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL;
BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place(
furnitureLocation.clone(), customFurniture,

View File

@@ -1,14 +1,19 @@
package net.momirealms.craftengine.bukkit.item.factory;
import com.google.gson.JsonElement;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.util.ItemTags;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.ItemFactory;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.ItemWrapper;
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
@@ -40,7 +45,7 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
case "1.21.4" -> {
return new ComponentItemFactory1_21_4(plugin);
}
case "1.21.5", "1.21.6", "1.22", "1.22.1" -> {
case "1.21.5", "1.21.6", "1.21.7", "1.22", "1.22.1" -> {
return new ComponentItemFactory1_21_5(plugin);
}
default -> throw new IllegalStateException("Unsupported server version: " + plugin.serverVersion());
@@ -55,13 +60,14 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
@Override
protected boolean isBlockItem(W item) {
// todo 这个 isBlockItem 他考虑组件了吗???
return item.getItem().getType().isBlock();
return CoreReflections.clazz$BlockItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()));
}
@Override
protected Key vanillaId(W item) {
return Key.of(item.getItem().getType().getKey().asString());
Object i = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject());
if (i == null) return ItemKeys.AIR;
return KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, i));
}
@Override
@@ -74,6 +80,11 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
return item.getItem();
}
@Override
protected UniqueKey recipeIngredientID(W item) {
return UniqueKey.create(id(item));
}
@Override
protected boolean is(W item, Key itemTag) {
Object literalObject = item.getLiteralObject();
@@ -111,7 +122,12 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
}
@Override
protected Tag getNBTComponent(W item, Object type) {
public Object getNBTComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected Tag getSparrowNBTComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@@ -130,6 +146,11 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected void setExactComponent(W item, Object type, Object value) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected boolean hasComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");

View File

@@ -20,7 +20,10 @@ import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemWrapper> {
@@ -28,6 +31,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
super(plugin);
}
@Override
protected boolean isEmpty(ComponentItemWrapper item) {
return item.getItem().isEmpty();
}
@Override
protected void customId(ComponentItemWrapper item, Key id) {
FastNMS.INSTANCE.setCustomItemId(item.getLiteralObject(), id.toString());
@@ -64,8 +72,29 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
return currentObj;
}
@SuppressWarnings("DuplicatedCode")
@Override
protected Tag getNBTTag(ComponentItemWrapper item, Object... path) {
protected Object getExactTag(ComponentItemWrapper item, Object... path) {
Object customData = getExactComponent(item, ComponentTypes.CUSTOM_DATA);
if (customData == null) return null;
Object currentTag = FastNMS.INSTANCE.method$CustomData$getUnsafe(customData);
for (int i = 0; i < path.length; i++) {
Object pathSegment = path[i];
if (pathSegment == null) return null;
currentTag = FastNMS.INSTANCE.method$CompoundTag$get(currentTag, path[i].toString());
if (currentTag == null) return null;
if (i == path.length - 1) {
return currentTag;
}
if (!CoreReflections.clazz$CompoundTag.isInstance(currentTag)) {
return null;
}
}
return null;
}
@Override
protected Tag getTag(ComponentItemWrapper item, Object... path) {
CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null);
if (rootTag == null) return null;
Tag currentTag = rootTag;
@@ -132,7 +161,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
@Override
protected boolean hasTag(ComponentItemWrapper item, Object... path) {
return getNBTTag(item, path) != null;
return getTag(item, path) != null;
}
@Override
@@ -213,6 +242,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
return item.getComponentExact(type);
}
@Override
protected void setExactComponent(ComponentItemWrapper item, Object type, Object value) {
item.setComponentExact(type, value);
}
@Override
protected Object getJavaComponent(ComponentItemWrapper item, Object type) {
return item.getJavaComponent(type).orElse(null);
@@ -224,7 +258,12 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
}
@Override
protected Tag getNBTComponent(ComponentItemWrapper item, Object type) {
public Object getNBTComponent(ComponentItemWrapper item, Object type) {
return item.getNBTComponent(type).orElse(null);
}
@Override
protected Tag getSparrowNBTComponent(ComponentItemWrapper item, Object type) {
return item.getSparrowNBTComponent(type).orElse(null);
}
@@ -462,8 +501,8 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
item.resetComponent(ComponentTypes.TRIM);
} else {
item.setJavaComponent(ComponentTypes.TRIM, Map.of(
"pattern", trim.pattern(),
"material", trim.material()
"pattern", trim.pattern().asString(),
"material", trim.material().asString()
));
}
}
@@ -476,7 +515,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
}
@SuppressWarnings("unchecked")
Map<String, String> trimMap = (Map<String, String>) trim.get();
return Optional.of(new Trim(trimMap.get("pattern"), trimMap.get("material")));
return Optional.of(new Trim(Key.of(trimMap.get("pattern")), Key.of(trimMap.get("material"))));
}
@SuppressWarnings("unchecked")

View File

@@ -2,9 +2,14 @@ package net.momirealms.craftengine.bukkit.item.factory;
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
import net.momirealms.craftengine.core.entity.EquipmentSlot;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 {
@@ -52,6 +57,18 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 {
@Override
protected Optional<EquipmentData> equippable(ComponentItemWrapper item) {
throw new UnsupportedOperationException("Not implemented yet.");
Optional<Object> optionalData = item.getJavaComponent(ComponentTypes.EQUIPPABLE);
if (optionalData.isEmpty()) return Optional.empty();
Map<String, Object> data = MiscUtils.castToMap(optionalData.get(), false);
String slot = data.get("slot").toString();
return Optional.of(new EquipmentData(
EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH)),
data.containsKey("asset_id") ? Key.of((String) data.get("asset_id")) : null,
(boolean) data.getOrDefault("dispensable", true),
(boolean) data.getOrDefault("swappable", true),
(boolean) data.getOrDefault("damage_on_hurt", true),
(boolean) data.getOrDefault("equip_on_interact", false),
data.containsKey("camera_overlay") ? Key.of((String) data.get("camera_overlay")) : null
));
}
}

View File

@@ -43,10 +43,15 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
}
@Override
protected Tag getNBTTag(LegacyItemWrapper item, Object... path) {
protected Tag getTag(LegacyItemWrapper item, Object... path) {
return item.getNBTTag(path);
}
@Override
protected Object getExactTag(LegacyItemWrapper item, Object... path) {
return item.getExactTag(path);
}
@Override
protected boolean hasTag(LegacyItemWrapper item, Object... path) {
return item.hasTag(path);
@@ -57,6 +62,11 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
return item.remove(path);
}
@Override
protected boolean isEmpty(LegacyItemWrapper item) {
return item.getItem().isEmpty();
}
@Override
protected Optional<Key> customId(LegacyItemWrapper item) {
Object id = item.getJavaTag(IdModifier.CRAFT_ENGINE_ID);
@@ -258,8 +268,8 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
item.remove("Trim");
return;
}
item.setTag(trim.material(), "Trim", "material");
item.setTag(trim.pattern(), "Trim", "pattern");
item.setTag(trim.material().asString(), "Trim", "material");
item.setTag(trim.pattern().asString(), "Trim", "pattern");
}
@Override
@@ -299,7 +309,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
String material = item.getJavaTag("Trim", "material");
String pattern = item.getJavaTag("Trim", "pattern");
if (material == null || pattern == null) return Optional.empty();
return Optional.of(new Trim(material, pattern));
return Optional.of(new Trim(Key.of(material), Key.of(pattern)));
}
@Override

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.item.listener;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Material;
import org.bukkit.entity.Horse;
@@ -60,7 +60,7 @@ public class ArmorEventListener implements Listener {
} else if (event.getClickedInventory() == horseInventory) {
ItemStack itemInCursor = event.getCursor();
if (event.getAction() == InventoryAction.SWAP_WITH_CURSOR || event.getAction() == InventoryAction.PLACE_ALL || event.getAction() == InventoryAction.PLACE_ONE) {
if (!ItemUtils.isEmpty(itemInCursor) && CraftEngineItems.isCustomItem(itemInCursor)) {
if (!ItemStackUtils.isEmpty(itemInCursor) && CraftEngineItems.isCustomItem(itemInCursor)) {
event.setCancelled(true);
return;
}
@@ -69,13 +69,13 @@ public class ArmorEventListener implements Listener {
int slot = event.getHotbarButton();
if (slot != -1) {
ItemStack itemInHotBar = event.getWhoClicked().getInventory().getItem(slot);
if (!ItemUtils.isEmpty(itemInHotBar) && CraftEngineItems.isCustomItem(itemInHotBar)) {
if (!ItemStackUtils.isEmpty(itemInHotBar) && CraftEngineItems.isCustomItem(itemInHotBar)) {
event.setCancelled(true);
return;
}
} else {
ItemStack offHand = event.getWhoClicked().getInventory().getItemInOffHand();
if (!ItemUtils.isEmpty(offHand) && CraftEngineItems.isCustomItem(offHand)) {
if (!ItemStackUtils.isEmpty(offHand) && CraftEngineItems.isCustomItem(offHand)) {
event.setCancelled(true);
return;
}
@@ -92,7 +92,7 @@ public class ArmorEventListener implements Listener {
}
for (Map.Entry<Integer, ItemStack> item : event.getNewItems().entrySet()) {
if (item.getKey() == 0 || item.getKey() == 1) {
if (!ItemUtils.isEmpty(item.getValue()) && CraftEngineItems.isCustomItem(item.getValue())) {
if (!ItemStackUtils.isEmpty(item.getValue()) && CraftEngineItems.isCustomItem(item.getValue())) {
event.setCancelled(true);
return;
}

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkRefl
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
@@ -44,7 +45,7 @@ public class DebugStickListener implements Listener {
Block clickedBlock = event.getClickedBlock();
if (clickedBlock == null) return;
ItemStack itemInHand = event.getItem();
if (itemInHand == null) return;
if (ItemStackUtils.isEmpty(itemInHand)) return;
Material material = itemInHand.getType();
if (material != Material.DEBUG_STICK) return;
Player bukkitPlayer = event.getPlayer();

View File

@@ -71,7 +71,7 @@ public class ItemEventListener implements Listener {
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(hand);
if (itemInHand == null) return;
if (ItemUtils.isEmpty(itemInHand)) return;
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
if (optionalCustomItem.isEmpty()) return;
@@ -158,7 +158,7 @@ public class ItemEventListener implements Listener {
.withParameter(DirectContextParameters.HAND, hand)
.withParameter(DirectContextParameters.EVENT, dummy)
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation()))
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand)
);
if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK);
else customBlock.execute(context, EventTrigger.LEFT_CLICK);
@@ -213,8 +213,8 @@ public class ItemEventListener implements Listener {
}
}
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem();
boolean hasItem = itemInHand != null;
boolean hasItem = !itemInHand.isEmpty();
Optional<CustomItem<ItemStack>> optionalCustomItem = hasItem ? itemInHand.getCustomItem() : Optional.empty();
boolean hasCustomItem = optionalCustomItem.isPresent();
// interact block with items
@@ -342,7 +342,7 @@ public class ItemEventListener implements Listener {
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(hand);
// should never be null
if (itemInHand == null) return;
if (ItemUtils.isEmpty(itemInHand)) return;
// todo 真的需要这个吗
if (cancelEventIfHasInteraction(event, serverPlayer, hand)) {
@@ -384,7 +384,7 @@ public class ItemEventListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onConsumeItem(PlayerItemConsumeEvent event) {
ItemStack consumedItem = event.getItem();
if (ItemUtils.isEmpty(consumedItem)) return;
if (ItemStackUtils.isEmpty(consumedItem)) return;
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(consumedItem);
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isEmpty()) {
@@ -417,7 +417,7 @@ public class ItemEventListener implements Listener {
if (VersionHelper.isOrAbove1_20_5()) return;
if (!(event.getEntity() instanceof Player player)) return;
ItemStack consumedItem = event.getItem();
if (ItemUtils.isEmpty(consumedItem)) return;
if (ItemStackUtils.isEmpty(consumedItem)) return;
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(consumedItem);
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isEmpty()) {
@@ -487,9 +487,9 @@ public class ItemEventListener implements Listener {
ItemStack lazuli = inventory.getSecondary();
if (lazuli != null) return;
ItemStack item = inventory.getItem();
if (item == null) return;
if (ItemStackUtils.isEmpty(item)) return;
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(item);
if (wrapped == null) return;
if (ItemUtils.isEmpty(wrapped)) return;
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isEmpty()) return;
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();

View File

@@ -2,6 +2,9 @@ package net.momirealms.craftengine.bukkit.item.recipe;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.papermc.paper.potion.PotionMix;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.CloneableConstantItem;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
@@ -13,18 +16,14 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOp
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.bukkit.util.MaterialUtils;
import net.momirealms.craftengine.bukkit.util.RecipeUtils;
import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.*;
import net.momirealms.craftengine.core.item.recipe.*;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.item.recipe.vanilla.*;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.HeptaFunction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@@ -135,11 +134,34 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
}
Object finalNmsRecipe = nmsRecipe;
return () -> registerNMSSmithingRecipe(finalNmsRecipe);
} catch (InvalidRecipeIngredientException e) {
throw e;
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to convert smithing transform recipe", e);
return null;
}
});
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRIM, (BukkitRecipeConvertor<CustomSmithingTrimRecipe<ItemStack>>) (id, recipe) -> {
try {
Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe);
if (VersionHelper.isOrAbove1_21_2()) {
nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(
CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe);
} else if (VersionHelper.isOrAbove1_20_2()) {
nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe);
} else {
Object finalNmsRecipe0 = nmsRecipe;
return () -> registerNMSSmithingRecipe(finalNmsRecipe0);
}
Object finalNmsRecipe = nmsRecipe;
return () -> registerNMSSmithingRecipe(finalNmsRecipe);
} catch (InvalidRecipeIngredientException e) {
throw e;
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to convert smithing trim recipe", e);
return null;
}
});
// TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor<CustomShapedRecipe<ItemStack>>) (id, recipe) -> {
ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY));
@@ -220,8 +242,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
});
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.STONECUTTING, (BukkitRecipeConvertor<CustomStoneCuttingRecipe<ItemStack>>) (id, recipe) -> {
List<ItemStack> itemStacks = new ArrayList<>();
for (Holder<Key> item : recipe.ingredient().items()) {
itemStacks.add(BukkitItemManager.instance().buildItemStack(item.value(), null));
for (UniqueKey item : recipe.ingredient().items()) {
itemStacks.add(BukkitItemManager.instance().buildItemStack(item.key(), null));
}
StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe(
new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY),
@@ -252,6 +274,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
private Object stolenFeatureFlagSet;
// Some delayed tasks on main thread
private final List<Runnable> delayedTasksOnMainThread = new ArrayList<>();
private final Map<Key, PotionMix> brewingRecipes = new HashMap<>();
public BukkitRecipeManager(BukkitCraftEngine plugin) {
instance = this;
@@ -303,16 +326,16 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
@Override
public void unload() {
if (!Config.enableRecipeSystem()) return;
super.unload();
if (VersionHelper.isOrAbove1_21_2()) {
this.plugin.scheduler().executeSync(() -> {
try {
CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to unregister recipes", e);
}
});
// 安排卸载任务这些任务会在load后执行。如果没有load说明服务器已经关闭了那就不需要管卸载了。
if (!Bukkit.isStopping()) {
for (Map.Entry<Key, Recipe<ItemStack>> entry : this.byId.entrySet()) {
Key id = entry.getKey();
if (isDataPackRecipe(id)) continue;
boolean isBrewingRecipe = entry.getValue() instanceof CustomBrewingRecipe<ItemStack>;
this.delayedTasksOnMainThread.add(() -> this.unregisterPlatformRecipe(id, isBrewingRecipe));
}
}
super.unload();
}
@Override
@@ -325,6 +348,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
public void disable() {
unload();
CE_RECIPE_2_NMS_HOLDER.clear();
// 不是服务器关闭造成disable那么需要把配方卸载干净
if (!Bukkit.isStopping()) {
for (Runnable task : this.delayedTasksOnMainThread) {
task.run();
}
}
HandlerList.unregisterAll(this.recipeEventListener);
if (this.crafterEventListener != null) {
HandlerList.unregisterAll(this.crafterEventListener);
@@ -332,19 +361,42 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
}
@Override
protected void unregisterPlatformRecipe(Key key) {
unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value()));
protected void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe) {
if (isBrewingRecipe) {
Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value()));
} else {
unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value()));
}
}
@Override
protected void registerPlatformRecipe(Key id, Recipe<ItemStack> recipe) {
try {
Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe);
if (converted != null) {
this.delayedTasksOnMainThread.add(converted);
if (recipe instanceof CustomBrewingRecipe<ItemStack> brewingRecipe) {
PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()),
brewingRecipe.result(ItemBuildContext.EMPTY),
PotionMix.createPredicateChoice(container -> {
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(container);
return brewingRecipe.container().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped));
}),
PotionMix.createPredicateChoice(ingredient -> {
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(ingredient);
return brewingRecipe.ingredient().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped));
})
);
this.delayedTasksOnMainThread.add(() -> {
Bukkit.getPotionBrewer().addPotionMix(potionMix);
});
} else {
try {
Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe);
if (converted != null) {
this.delayedTasksOnMainThread.add(converted);
}
} catch (InvalidRecipeIngredientException e) {
throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", e.ingredient());
} catch (Exception e) {
this.plugin.logger().warn("Failed to convert recipe " + id, e);
}
} catch (Exception e) {
this.plugin.logger().warn("Failed to convert recipe " + id, e);
}
}
@@ -389,11 +441,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
// continue;
// }
if (Config.disableAllVanillaRecipes()) {
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id));
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false));
continue;
}
if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) {
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id));
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false));
continue;
}
markAsDataPackRecipe(id);
@@ -429,6 +481,10 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject);
handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add));
}
case "minecraft:smithing_trim" -> {
VanillaSmithingTrimRecipe recipe = this.recipeReader.readSmithingTrim(jsonObject);
handleDataPackSmithingTrim(id, recipe, (this.delayedTasksOnMainThread::add));
}
case "minecraft:stonecutting" -> {
VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject);
handleDataPackStoneCuttingRecipe(id, recipe);
@@ -494,13 +550,13 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
private void handleDataPackStoneCuttingRecipe(Key id, VanillaStoneCuttingRecipe recipe) {
ItemStack result = createDataPackResultStack(recipe.result());
Set<Holder<Key>> holders = new HashSet<>();
Set<UniqueKey> holders = new HashSet<>();
for (String item : recipe.ingredient()) {
if (item.charAt(0) == '#') {
Key tag = Key.from(item.substring(1));
holders.addAll(this.plugin.itemManager().tagToItems(tag));
} else {
holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow());
holders.add(UniqueKey.create(Key.from(item)));
}
}
CustomStoneCuttingRecipe<ItemStack> ceRecipe = new CustomStoneCuttingRecipe<>(
@@ -516,7 +572,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
boolean hasCustomItemInTag = false;
List<Ingredient<ItemStack>> ingredientList = new ArrayList<>();
for (List<String> list : recipe.ingredients()) {
Set<Holder<Key>> holders = new HashSet<>();
Set<UniqueKey> holders = new HashSet<>();
for (String item : list) {
if (item.charAt(0) == '#') {
Key tag = Key.of(item.substring(1));
@@ -527,7 +583,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
}
holders.addAll(plugin.itemManager().tagToItems(tag));
} else {
holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow());
holders.add(UniqueKey.create(Key.from(item)));
}
}
ingredientList.add(Ingredient.of(holders));
@@ -552,7 +608,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
boolean hasCustomItemInTag = false;
Map<Character, Ingredient<ItemStack>> ingredients = new HashMap<>();
for (Map.Entry<Character, List<String>> entry : recipe.ingredients().entrySet()) {
Set<Holder<Key>> holders = new HashSet<>();
Set<UniqueKey> holders = new HashSet<>();
for (String item : entry.getValue()) {
if (item.charAt(0) == '#') {
Key tag = Key.from(item.substring(1));
@@ -563,7 +619,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
}
holders.addAll(plugin.itemManager().tagToItems(tag));
} else {
holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow());
holders.add(UniqueKey.create(Key.from(item)));
}
}
ingredients.put(entry.getKey(), Ingredient.of(holders));
@@ -589,7 +645,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
Consumer<Runnable> callback) {
NamespacedKey key = new NamespacedKey(id.namespace(), id.value());
ItemStack result = createDataPackResultStack(recipe.result());
Set<Holder<Key>> holders = new HashSet<>();
Set<UniqueKey> holders = new HashSet<>();
boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add);
CustomCookingRecipe<ItemStack> ceRecipe = constructor2.apply(
id, recipe.category(), recipe.group(),
@@ -612,11 +668,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
ItemStack result = createDataPackResultStack(recipe.result());
boolean hasCustomItemInTag;
Set<Holder<Key>> additionHolders = new HashSet<>();
Set<UniqueKey> additionHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add);
Set<Holder<Key>> templateHolders = new HashSet<>();
Set<UniqueKey> templateHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add);
Set<Holder<Key>> baseHolders = new HashSet<>();
Set<UniqueKey> baseHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add);
CustomSmithingTransformRecipe<ItemStack> ceRecipe = new CustomSmithingTransformRecipe<>(
@@ -639,7 +695,36 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
this.registerInternalRecipe(id, ceRecipe);
}
private boolean readVanillaIngredients(boolean hasCustomItemInTag, List<String> ingredients, Consumer<Holder<Key>> holderConsumer) {
private void handleDataPackSmithingTrim(Key id, VanillaSmithingTrimRecipe recipe, Consumer<Runnable> callback) {
NamespacedKey key = new NamespacedKey(id.namespace(), id.value());
boolean hasCustomItemInTag;
Set<UniqueKey> additionHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add);
Set<UniqueKey> templateHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add);
Set<UniqueKey> baseHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add);
CustomSmithingTrimRecipe<ItemStack> ceRecipe = new CustomSmithingTrimRecipe<>(
id,
Ingredient.of(baseHolders),
Ingredient.of(templateHolders),
Ingredient.of(additionHolders),
Optional.ofNullable(recipe.pattern()).map(Key::of).orElse(null)
);
if (hasCustomItemInTag) {
Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe);
callback.accept(() -> {
unregisterNMSRecipe(key);
converted.run();
});
}
this.registerInternalRecipe(id, ceRecipe);
}
private boolean readVanillaIngredients(boolean hasCustomItemInTag, List<String> ingredients, Consumer<UniqueKey> holderConsumer) {
for (String item : ingredients) {
if (item.charAt(0) == '#') {
Key tag = Key.from(item.substring(1));
@@ -648,11 +733,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
hasCustomItemInTag = true;
}
}
for (Holder<Key> holder : this.plugin.itemManager().tagToItems(tag)) {
for (UniqueKey holder : this.plugin.itemManager().tagToItems(tag)) {
holderConsumer.accept(holder);
}
} else {
holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow());
holderConsumer.accept(UniqueKey.create(Key.from(item)));
}
}
return hasCustomItemInTag;
@@ -695,8 +780,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
private static RecipeChoice ingredientToBukkitRecipeChoice(Ingredient<ItemStack> ingredient) {
Set<Material> materials = new HashSet<>();
for (Holder<Key> holder : ingredient.items()) {
materials.add(getMaterialById(holder.value()));
for (UniqueKey holder : ingredient.items()) {
materials.add(getMaterialById(holder.key()));
}
return new RecipeChoice.MaterialChoice(new ArrayList<>(materials));
}
@@ -707,15 +792,21 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
return material;
}
Optional<CustomItem<ItemStack>> optionalItem = BukkitItemManager.instance().getCustomItem(key);
return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElse(null);
return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElseThrow(() -> new InvalidRecipeIngredientException(key.asString()));
}
private static List<Object> getIngredientLooks(List<Holder<Key>> holders) {
private static List<Object> getIngredientLooks(List<UniqueKey> holders) {
List<Object> itemStacks = new ArrayList<>();
for (Holder<Key> holder : holders) {
ItemStack itemStack = BukkitItemManager.instance().getBuildableItem(holder.value()).get().buildItemStack(ItemBuildContext.EMPTY, 1);
Object nmsStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack);
itemStacks.add(nmsStack);
for (UniqueKey holder : holders) {
Optional<? extends BuildableItem<ItemStack>> buildableItem = BukkitItemManager.instance().getBuildableItem(holder.key());
if (buildableItem.isPresent()) {
ItemStack itemStack = buildableItem.get().buildItemStack(ItemBuildContext.EMPTY, 1);
Object nmsStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack);
itemStacks.add(nmsStack);
} else {
Item<ItemStack> barrier = BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null);
barrier.customNameJson(AdventureHelper.componentToJson(Component.text(holder.key().asString()).color(NamedTextColor.RED)));
}
}
return itemStacks;
}
@@ -887,4 +978,35 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
);
}
}
private static Object createMinecraftSmithingTrimRecipe(CustomSmithingTrimRecipe<ItemStack> recipe) throws ReflectiveOperationException {
if (VersionHelper.isOrAbove1_21_5()) {
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN);
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition()),
FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(registry, KeyUtils.toResourceLocation(recipe.pattern())).orElseThrow(() -> new RuntimeException("Pattern " + recipe.pattern() + " doesn't exist."))
);
} else if (VersionHelper.isOrAbove1_21_2()) {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toOptionalMinecraftIngredient(recipe.template()),
toOptionalMinecraftIngredient(recipe.base()),
toOptionalMinecraftIngredient(recipe.addition())
);
} else if (VersionHelper.isOrAbove1_20_2()) {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition())
);
} else {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
KeyUtils.toResourceLocation(recipe.id()),
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition())
);
}
}
}

View File

@@ -1,17 +1,15 @@
package net.momirealms.craftengine.bukkit.item.recipe;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.block.Crafter;
import org.bukkit.event.EventHandler;
@@ -23,10 +21,8 @@ import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class CrafterEventListener implements Listener {
private static final OptimizedIDItem<ItemStack> EMPTY = new OptimizedIDItem<>(null, null);
private final ItemManager<ItemStack> itemManager;
private final BukkitRecipeManager recipeManager;
private final BukkitCraftEngine plugin;
@@ -56,40 +52,33 @@ public class CrafterEventListener implements Listener {
Inventory inventory = crafter.getInventory();
ItemStack[] ingredients = inventory.getStorageContents();
List<OptimizedIDItem<ItemStack>> optimizedIDItems = new ArrayList<>();
List<UniqueIdItem<ItemStack>> uniqueIdItems = new ArrayList<>();
for (ItemStack itemStack : ingredients) {
if (ItemUtils.isEmpty(itemStack)) {
optimizedIDItems.add(EMPTY);
if (ItemStackUtils.isEmpty(itemStack)) {
uniqueIdItems.add(this.itemManager.uniqueEmptyItem());
} else {
Item<ItemStack> wrappedItem = this.itemManager.wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
// an invalid item is used in recipe, we disallow it
event.setCancelled(true);
return;
} else {
optimizedIDItems.add(new OptimizedIDItem<>(idHolder.get(), itemStack));
}
uniqueIdItems.add(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
}
}
CraftingInput<ItemStack> input;
if (ingredients.length == 9) {
input = CraftingInput.of(3, 3, optimizedIDItems);
input = CraftingInput.of(3, 3, uniqueIdItems);
} else if (ingredients.length == 4) {
input = CraftingInput.of(2, 2, optimizedIDItems);
input = CraftingInput.of(2, 2, uniqueIdItems);
} else {
return;
}
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input);
if (ceRecipe != null) {
event.setResult(ceRecipe.result(ItemBuildContext.EMPTY));
event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY));
return;
}
ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input);
if (ceRecipe != null) {
event.setResult(ceRecipe.result(ItemBuildContext.EMPTY));
event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY));
return;
}
// clear result if not met

View File

@@ -12,23 +12,21 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.InventoryUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
import net.momirealms.craftengine.core.item.*;
import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment;
import net.momirealms.craftengine.core.item.recipe.*;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
import net.momirealms.craftengine.core.item.setting.AnvilRepairItem;
import net.momirealms.craftengine.core.item.setting.ItemEquipment;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Pair;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Campfire;
@@ -40,6 +38,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.*;
import org.bukkit.event.inventory.*;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.*;
import org.bukkit.inventory.view.AnvilView;
@@ -51,7 +50,6 @@ import java.util.Optional;
@SuppressWarnings("DuplicatedCode")
public class RecipeEventListener implements Listener {
private static final OptimizedIDItem<ItemStack> EMPTY = new OptimizedIDItem<>(null, null);
private final ItemManager<ItemStack> itemManager;
private final BukkitRecipeManager recipeManager;
private final BukkitCraftEngine plugin;
@@ -74,13 +72,9 @@ public class RecipeEventListener implements Listener {
if (clickedInventory == player.getInventory()) {
if (event.getClick() == ClickType.SHIFT_LEFT || event.getClick() == ClickType.SHIFT_RIGHT) {
ItemStack item = event.getCurrentItem();
if (ItemUtils.isEmpty(item)) return;
if (fuelStack == null || fuelStack.getType() == Material.AIR) {
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(item);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) return;
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), item));
if (ItemStackUtils.isEmpty(item)) return;
if (ItemStackUtils.isEmpty(fuelStack)) {
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(item));
Key recipeType;
if (furnaceInventory.getType() == InventoryType.FURNACE) {
recipeType = RecipeTypes.SMELTING;
@@ -90,16 +84,16 @@ public class RecipeEventListener implements Listener {
recipeType = RecipeTypes.SMOKING;
}
Recipe<ItemStack> ceRecipe = recipeManager.recipeByInput(recipeType, input);
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(recipeType, input);
// The item is an ingredient, we should never consider it as fuel firstly
if (ceRecipe != null) return;
int fuelTime = this.itemManager.fuelTime(item);
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) {
if (ItemStackUtils.isCustomItem(item) && item.getType().isFuel()) {
event.setCancelled(true);
ItemStack smelting = furnaceInventory.getSmelting();
if (ItemUtils.isEmpty(smelting)) {
if (ItemStackUtils.isEmpty(smelting)) {
furnaceInventory.setSmelting(item.clone());
item.setAmount(0);
} else if (smelting.isSimilar(item)) {
@@ -160,11 +154,11 @@ public class RecipeEventListener implements Listener {
} else {
item = player.getInventory().getItem(hotBarSlot);
}
if (item == null) return;
if (ItemStackUtils.isEmpty(item)) return;
int fuelTime = this.plugin.itemManager().fuelTime(item);
// only handle custom items
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) {
if (ItemStackUtils.isCustomItem(item) && item.getType().isFuel()) {
event.setCancelled(true);
}
return;
@@ -187,11 +181,11 @@ public class RecipeEventListener implements Listener {
case LEFT, RIGHT -> {
ItemStack itemOnCursor = event.getCursor();
// pick item
if (ItemUtils.isEmpty(itemOnCursor)) return;
if (ItemStackUtils.isEmpty(itemOnCursor)) return;
int fuelTime = this.plugin.itemManager().fuelTime(itemOnCursor);
// only handle custom items
if (fuelTime == 0) {
if (ItemUtils.isCustomItem(itemOnCursor) && itemOnCursor.getType().isFuel()) {
if (ItemStackUtils.isCustomItem(itemOnCursor) && itemOnCursor.getType().isFuel()) {
event.setCancelled(true);
}
return;
@@ -344,7 +338,7 @@ public class RecipeEventListener implements Listener {
}
ItemStack itemStack = event.getItem();
if (ItemUtils.isEmpty(itemStack)) return;
if (ItemStackUtils.isEmpty(itemStack)) return;
try {
@SuppressWarnings("unchecked")
Optional<Object> optionalMCRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(
@@ -357,12 +351,7 @@ public class RecipeEventListener implements Listener {
if (optionalMCRecipe.isEmpty()) {
return;
}
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
return;
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setCancelled(true);
@@ -387,14 +376,7 @@ public class RecipeEventListener implements Listener {
}
ItemStack itemStack = event.getSource();
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
event.setTotalCookTime(Integer.MAX_VALUE);
return;
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setTotalCookTime(Integer.MAX_VALUE);
@@ -422,14 +404,7 @@ public class RecipeEventListener implements Listener {
}
ItemStack itemStack = event.getSource();
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
event.setCancelled(true);
return;
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setCancelled(true);
@@ -444,87 +419,109 @@ public class RecipeEventListener implements Listener {
public void onPrepareResult(PrepareResultEvent event) {
// if (!ConfigManager.enableRecipeSystem()) return;
if (event.getInventory() instanceof CartographyInventory cartographyInventory) {
if (ItemUtils.hasCustomItem(cartographyInventory.getStorageContents())) {
if (ItemStackUtils.hasCustomItem(cartographyInventory.getStorageContents())) {
event.setResult(new ItemStack(Material.AIR));
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onAnvilCombineItems(PrepareAnvilEvent event) {
public void onAnvilEvent(PrepareAnvilEvent event) {
preProcess(event);
processRepairable(event);
processRename(event);
}
/*
预处理会阻止一些不合理的原版材质造成的合并问题
*/
private void preProcess(PrepareAnvilEvent event) {
AnvilInventory inventory = event.getInventory();
ItemStack first = inventory.getFirstItem();
ItemStack second = inventory.getSecondItem();
if (first == null || second == null) return;
Item<ItemStack> wrappedFirst = BukkitItemManager.instance().wrap(first);
boolean firstCustom = wrappedFirst.isCustomItem();
Optional<CustomItem<ItemStack>> firstCustom = wrappedFirst.getCustomItem();
Item<ItemStack> wrappedSecond = BukkitItemManager.instance().wrap(second);
boolean secondCustom = wrappedSecond.isCustomItem();
// both are vanilla items
if (!firstCustom && !secondCustom) {
Optional<CustomItem<ItemStack>> secondCustom = wrappedFirst.getCustomItem();
// 两个都是原版物品
if (firstCustom.isEmpty() && secondCustom.isEmpty()) {
return;
}
// both of them are custom items
// if the second is an enchanted book, then apply it
// 如果第二个物品是附魔书,那么忽略
if (wrappedSecond.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) {
return;
}
// one of them is vanilla item
if (!firstCustom || !secondCustom) {
if (second.canRepair(first)) return; // 这里需要考虑原版逻辑
// block "vanilla + custom" recipes
event.setResult(null);
return;
// 被修的是自定义,材料不是自定义
if (firstCustom.isPresent() && secondCustom.isEmpty()) {
if (firstCustom.get().settings().respectRepairableComponent()) {
if (second.canRepair(first)) return; // 尊重原版的repairable
} else {
event.setResult(null);
return;
}
}
// not the same item
// 被修的是原版,材料是自定义
if (firstCustom.isEmpty() && secondCustom.isPresent()) {
if (secondCustom.get().settings().respectRepairableComponent()) {
if (second.canRepair(first)) return;
} else {
event.setResult(null);
return;
}
}
// 如果两个物品id不同不能合并
if (!wrappedFirst.customId().equals(wrappedSecond.customId())) {
event.setResult(null);
return;
}
// can not repair
wrappedFirst.getCustomItem().ifPresent(it -> {
// 如果禁止在铁砧使用两个相同物品修复
firstCustom.ifPresent(it -> {
if (!it.settings().canRepair()) {
event.setResult(null);
}
});
}
/*
处理item settings中repair item属性。如果修补材料不是自定义物品则不会参与后续逻辑。
这会忽略preprocess里event.setResult(null);
*/
@SuppressWarnings("UnstableApiUsage")
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onAnvilRepairItems(PrepareAnvilEvent event) {
private void processRepairable(PrepareAnvilEvent event) {
AnvilInventory inventory = event.getInventory();
ItemStack first = inventory.getFirstItem();
ItemStack second = inventory.getSecondItem();
if (first == null || second == null) return;
if (ItemStackUtils.isEmpty(first) || ItemStackUtils.isEmpty(second)) return;
Item<ItemStack> wrappedSecond = BukkitItemManager.instance().wrap(second);
// if the second slot is not a custom item, ignore it
Optional<CustomItem<ItemStack>> customItemOptional = plugin.itemManager().getCustomItem(wrappedSecond.id());
// 如果材料不是自定义的,那么忽略
Optional<CustomItem<ItemStack>> customItemOptional = this.plugin.itemManager().getCustomItem(wrappedSecond.id());
if (customItemOptional.isEmpty()) {
return;
}
CustomItem<ItemStack> customItem = customItemOptional.get();
List<AnvilRepairItem> repairItems = customItem.settings().repairItems();
// if the second slot is not a repair item, ignore it
// 如果材料不支持修复物品,则忽略
if (repairItems.isEmpty()) {
return;
}
// 后续均为修复逻辑
Item<ItemStack> wrappedFirst = BukkitItemManager.instance().wrap(first.clone());
int maxDamage = wrappedFirst.maxDamage();
int damage = wrappedFirst.damage().orElse(0);
// not a repairable item
// 物品无damage属性
if (damage == 0 || maxDamage == 0) return;
Key firstId = wrappedFirst.id();
Optional<CustomItem<ItemStack>> optionalCustomTool = wrappedFirst.getCustomItem();
// can not repair
// 物品无法被修复
if (optionalCustomTool.isPresent() && !optionalCustomTool.get().settings().canRepair()) {
return;
}
@@ -549,7 +546,7 @@ public class RecipeEventListener implements Listener {
}
}
// no repair item matching
// 找不到匹配的修复
if (repairItem == null) {
return;
}
@@ -566,7 +563,7 @@ public class RecipeEventListener implements Listener {
String renameText;
int maxRepairCost;
//int previousCost;
if (VersionHelper.isOrAbove1_21_2()) {
if (VersionHelper.isOrAbove1_21()) {
AnvilView anvilView = event.getView();
renameText = anvilView.getRenameText();
maxRepairCost = anvilView.getMaximumRepairCost();
@@ -623,13 +620,7 @@ public class RecipeEventListener implements Listener {
LegacyInventoryUtils.setRepairCostAmount(inventory, actualConsumedAmount);
}
Player player;
try {
player = (Player) CraftBukkitReflections.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;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
if (finalCost >= maxRepairCost && !plugin.adapt(player).canInstabuild()) {
hasResult = false;
@@ -647,12 +638,14 @@ public class RecipeEventListener implements Listener {
}
}
/*
如果物品不可被重命名,则在最后处理。
*/
@SuppressWarnings("UnstableApiUsage")
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL)
public void onAnvilRenameItem(PrepareAnvilEvent event) {
private void processRename(PrepareAnvilEvent event) {
AnvilInventory inventory = event.getInventory();
ItemStack first = inventory.getFirstItem();
if (ItemUtils.isEmpty(first)) {
if (ItemStackUtils.isEmpty(first)) {
return;
}
if (event.getResult() == null) {
@@ -662,7 +655,7 @@ public class RecipeEventListener implements Listener {
wrappedFirst.getCustomItem().ifPresent(item -> {
if (!item.settings().renameable()) {
String renameText;
if (VersionHelper.isOrAbove1_21_2()) {
if (VersionHelper.isOrAbove1_21()) {
AnvilView anvilView = event.getView();
renameText = anvilView.getRenameText();
} else {
@@ -695,7 +688,7 @@ public class RecipeEventListener implements Listener {
if (!(recipe instanceof ComplexRecipe complexRecipe))
return;
CraftingInventory inventory = event.getInventory();
boolean hasCustomItem = ItemUtils.hasCustomItem(inventory.getMatrix());
boolean hasCustomItem = ItemStackUtils.hasCustomItem(inventory.getMatrix());
if (!hasCustomItem) {
return;
}
@@ -733,13 +726,7 @@ public class RecipeEventListener implements Listener {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
Optional<CustomItem<ItemStack>> customItemOptional = plugin.itemManager().getCustomItem(left.id());
if (customItemOptional.isEmpty()) {
@@ -809,10 +796,10 @@ public class RecipeEventListener implements Listener {
boolean hasReplacement = false;
for (int i = 0; i < usedItems.length; i++) {
ItemStack usedItem = usedItems[i];
if (ItemUtils.isEmpty(usedItem)) continue;
if (ItemStackUtils.isEmpty(usedItem)) continue;
if (usedItem.getAmount() != 1) continue;
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(usedItem);
if (wrapped == null) continue;
if (ItemUtils.isEmpty(wrapped)) continue;
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
@@ -861,46 +848,28 @@ public class RecipeEventListener implements Listener {
CraftingInventory inventory = event.getInventory();
ItemStack[] ingredients = inventory.getMatrix();
List<OptimizedIDItem<ItemStack>> optimizedIDItems = new ArrayList<>();
List<UniqueIdItem<ItemStack>> uniqueIdItems = new ArrayList<>();
for (ItemStack itemStack : ingredients) {
if (ItemUtils.isEmpty(itemStack)) {
optimizedIDItems.add(EMPTY);
} else {
Item<ItemStack> wrappedItem = this.itemManager.wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
// an invalid item is used in recipe, we disallow it
inventory.setResult(null);
return;
} else {
optimizedIDItems.add(new OptimizedIDItem<>(idHolder.get(), itemStack));
}
}
uniqueIdItems.add(getUniqueIdItem(itemStack));
}
CraftingInput<ItemStack> input;
if (ingredients.length == 9) {
input = CraftingInput.of(3, 3, optimizedIDItems);
input = CraftingInput.of(3, 3, uniqueIdItems);
} else if (ingredients.length == 4) {
input = CraftingInput.of(2, 2, optimizedIDItems);
input = CraftingInput.of(2, 2, uniqueIdItems);
} else {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
BukkitServerPlayer serverPlayer = this.plugin.adapt(player);
Key lastRecipe = serverPlayer.lastUsedRecipe();
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe);
if (ceRecipe != null) {
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
serverPlayer.setLastUsedRecipe(ceRecipe.id());
if (!ceRecipe.id().equals(recipeId)) {
correctCraftingRecipeUsed(inventory, ceRecipe);
@@ -909,7 +878,7 @@ public class RecipeEventListener implements Listener {
}
ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe);
if (ceRecipe != null) {
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
serverPlayer.setLastUsedRecipe(ceRecipe.id());
if (!ceRecipe.id().equals(recipeId)) {
correctCraftingRecipeUsed(inventory, ceRecipe);
@@ -933,6 +902,54 @@ public class RecipeEventListener implements Listener {
}
}
@EventHandler(ignoreCancelled = true)
public void onSmithingTrim(PrepareSmithingEvent event) {
SmithingInventory inventory = event.getInventory();
if (!(inventory.getRecipe() instanceof SmithingTrimRecipe recipe)) return;
ItemStack equipment = inventory.getInputEquipment();
if (!ItemStackUtils.isEmpty(equipment)) {
Item<ItemStack> wrappedEquipment = this.itemManager.wrap(equipment);
Optional<CustomItem<ItemStack>> optionalCustomItem = wrappedEquipment.getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
ItemEquipment itemEquipmentSettings = customItem.settings().equipment();
if (itemEquipmentSettings != null && itemEquipmentSettings.equipment() instanceof TrimBasedEquipment) {
// 不允许trim类型的盔甲再次被使用trim
event.setResult(null);
return;
}
}
}
Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value());
boolean isCustom = this.recipeManager.isCustomRecipe(recipeId);
// Maybe it's recipe from other plugins, then we ignore it
if (!isCustom) {
return;
}
SmithingInput<ItemStack> input = new SmithingInput<>(
getUniqueIdItem(inventory.getInputEquipment()),
getUniqueIdItem(inventory.getInputTemplate()),
getUniqueIdItem(inventory.getInputMineral())
);
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRIM, input);
if (ceRecipe == null) {
event.setResult(null);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
CustomSmithingTrimRecipe<ItemStack> trimRecipe = (CustomSmithingTrimRecipe<ItemStack>) ceRecipe;
ItemStack result = trimRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY));
event.setResult(result);
if (!ceRecipe.id().equals(recipeId)) {
correctSmithingRecipeUsed(inventory, ceRecipe);
}
}
@EventHandler(ignoreCancelled = true)
public void onSmithingTransform(PrepareSmithingEvent event) {
if (!Config.enableRecipeSystem()) return;
@@ -951,9 +968,9 @@ public class RecipeEventListener implements Listener {
ItemStack addition = inventory.getInputMineral();
SmithingInput<ItemStack> input = new SmithingInput<>(
getOptimizedIDItem(base),
getOptimizedIDItem(template),
getOptimizedIDItem(addition)
getUniqueIdItem(base),
getUniqueIdItem(template),
getUniqueIdItem(addition)
);
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input);
@@ -962,16 +979,10 @@ public class RecipeEventListener implements Listener {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
CustomSmithingTransformRecipe<ItemStack> transformRecipe = (CustomSmithingTransformRecipe<ItemStack>) ceRecipe;
ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base));
ItemStack processed = transformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY));
event.setResult(processed);
if (!ceRecipe.id().equals(recipeId)) {
correctSmithingRecipeUsed(inventory, ceRecipe);
@@ -991,13 +1002,12 @@ public class RecipeEventListener implements Listener {
}
}
private OptimizedIDItem<ItemStack> getOptimizedIDItem(@Nullable ItemStack itemStack) {
if (ItemUtils.isEmpty(itemStack)) {
return EMPTY;
private UniqueIdItem<ItemStack> getUniqueIdItem(@Nullable ItemStack itemStack) {
if (ItemStackUtils.isEmpty(itemStack)) {
return this.itemManager.uniqueEmptyItem();
} else {
Item<ItemStack> wrappedItem = this.itemManager.wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
return idHolder.map(keyReference -> new OptimizedIDItem<>(keyReference, itemStack)).orElse(EMPTY);
return new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem);
}
}
}

View File

@@ -54,6 +54,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
HandlerList.unregisterAll(this);
}
@SuppressWarnings("UnstableApiUsage")
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onEntityDeath(EntityDeathEvent event) {
Entity entity = event.getEntity();
@@ -90,7 +91,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
}
public class VanillaLootParser implements ConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"};
public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "vanilla_loots", "vanilla_loot"};
@Override
public int loadingSequence() {

View File

@@ -5,13 +5,11 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.ResourcePackUtils;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.pack.AbstractPackManager;
import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData;
import net.momirealms.craftengine.core.pack.host.impl.NoneHost;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -25,11 +23,9 @@ import org.bukkit.event.player.PlayerJoinEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class BukkitPackManager extends AbstractPackManager implements Listener {
public static final String FAKE_URL = "https://127.0.0.1:65536";
private final BukkitCraftEngine plugin;
public BukkitPackManager(BukkitCraftEngine plugin) {
@@ -58,25 +54,6 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
public void load() {
if (ReloadCommand.RELOAD_PACK_FLAG || CraftEngine.instance().isInitializing()) {
super.load();
if (Config.sendPackOnJoin() && VersionHelper.isOrAbove1_20_2() && !(resourcePackHost() instanceof NoneHost)) {
this.modifyServerSettings();
}
}
}
public void modifyServerSettings() {
try {
Object settings = CoreReflections.field$DedicatedServer$settings.get(CoreReflections.method$MinecraftServer$getServer.invoke(null));
Object properties = CoreReflections.field$DedicatedServerSettings$properties.get(settings);
Object info;
if (VersionHelper.isOrAbove1_20_3()) {
info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(new UUID(0, 0), FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt()));
} else {
info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt()));
}
CoreReflections.field$DedicatedServerProperties$serverResourcePackInfo.set(properties, Optional.of(info));
} catch (Exception e) {
this.plugin.logger().warn("Failed to update resource pack settings", e);
}
}

View File

@@ -138,6 +138,7 @@ public class BukkitCraftEngine extends CraftEngine {
super.onPluginLoad();
super.blockManager.init();
super.networkManager = new BukkitNetworkManager(this);
super.itemManager = new BukkitItemManager(this);
this.successfullyLoaded = true;
super.compatibilityManager().onLoad();
}
@@ -182,7 +183,6 @@ public class BukkitCraftEngine extends CraftEngine {
PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize());
super.packManager = new BukkitPackManager(this);
super.senderFactory = new BukkitSenderFactory(this);
super.itemManager = new BukkitItemManager(this);
super.recipeManager = new BukkitRecipeManager(this);
super.commandManager = new BukkitCommandManager(this);
super.itemBrowserManager = new ItemBrowserManagerImpl(this);
@@ -270,7 +270,7 @@ public class BukkitCraftEngine extends CraftEngine {
@Override
public String serverVersion() {
return Bukkit.getServer().getBukkitVersion().split("-")[0];
return VersionHelper.MINECRAFT_VERSION.version();
}
@Override

View File

@@ -4,7 +4,6 @@ import com.google.gson.JsonElement;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.Platform;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.sparrow.nbt.CompoundTag;
@@ -28,7 +27,6 @@ public class BukkitPlatform implements Platform {
Map<String, Object> map = (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
return map.get("root");
} catch (CommandSyntaxException e) {
CraftEngine.instance().debug(e::getMessage);
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt);
}
}
@@ -45,7 +43,6 @@ public class BukkitPlatform implements Platform {
CompoundTag map = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, tag);
return map.get("root");
} catch (CommandSyntaxException e) {
CraftEngine.instance().debug(e::getMessage);
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt);
}
}

View File

@@ -41,6 +41,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new DebugGetBlockInternalIdCommand(this, plugin),
new DebugAppearanceStateUsageCommand(this, plugin),
new DebugClearCooldownCommand(this, plugin),
new DebugEntityIdCommand(this, plugin),
new DebugRealStateUsageCommand(this, plugin),
new DebugItemDataCommand(this, plugin),
new DebugSetBlockCommand(this, plugin),

View File

@@ -0,0 +1,42 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.parser.WorldParser;
import org.incendo.cloud.parser.standard.IntegerParser;
public class DebugEntityIdCommand extends BukkitCommandFeature<CommandSender> {
public DebugEntityIdCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.required("world", WorldParser.worldParser())
.required("entityId", IntegerParser.integerParser())
.handler(context -> {
World world = context.get("world");
int entityId = context.get("entityId");
Object entityLookup = FastNMS.INSTANCE.method$ServerLevel$getEntityLookup(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world));
Object entity = FastNMS.INSTANCE.method$EntityLookup$get(entityLookup, entityId);
if (entity == null) {
context.sender().sendMessage("entity not found");
return;
}
context.sender().sendMessage(entity.toString());
});
}
@Override
public String getFeatureID() {
return "debug_entity_id";
}
}

View File

@@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.util.AdventureHelper;
@@ -26,7 +26,7 @@ public class DebugItemDataCommand extends BukkitCommandFeature<CommandSender> {
.senderType(Player.class)
.handler(context -> {
ItemStack itemInHand = context.sender().getInventory().getItemInMainHand();
if (ItemUtils.isEmpty(itemInHand)) {
if (ItemStackUtils.isEmpty(itemInHand)) {
return;
}
Map<String, Object> readableMap = toMap(itemInHand);

View File

@@ -30,7 +30,7 @@ public class SearchUsagePlayerCommand extends BukkitCommandFeature<CommandSender
Player player = context.sender();
BukkitServerPlayer serverPlayer = plugin().adapt(player);
Item<?> item = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
if (item == null) {
if (item.isEmpty()) {
handleFeedback(context, MessageConstants.COMMAND_SEARCH_USAGE_NO_ITEM);
return;
}

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.gui;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.gui.Click;
@@ -71,7 +71,7 @@ public class BukkitClick implements Click {
@Override
public Item<?> itemOnCursor() {
ItemStack itemStack = this.event.getCursor();
if (ItemUtils.isEmpty(itemStack)) return null;
if (ItemStackUtils.isEmpty(itemStack)) return null;
return BukkitItemManager.instance().wrap(itemStack);
}

View File

@@ -148,7 +148,7 @@ public final class BlockGenerator {
// onExplosionHit 1.21+
.method(ElementMatchers.returns(void.class)
.and(ElementMatchers.takesArgument(0, CoreReflections.clazz$BlockState))
.and(ElementMatchers.takesArgument(1, CoreReflections.clazz$ServerLevel))
.and(ElementMatchers.takesArgument(1, VersionHelper.isOrAbove1_21_2() ? CoreReflections.clazz$ServerLevel : CoreReflections.clazz$Level))
.and(ElementMatchers.takesArgument(2, CoreReflections.clazz$BlockPos))
.and(ElementMatchers.takesArgument(3, CoreReflections.clazz$Explosion))
.and(ElementMatchers.takesArgument(4, BiConsumer.class))
@@ -177,11 +177,21 @@ public final class BlockGenerator {
.intercept(MethodDelegation.to(GetDirectSignalInterceptor.INSTANCE))
// isSignalSource
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$isSignalSource))
.intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE));
.intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE))
// playerWillDestroy
.method(ElementMatchers.is(CoreReflections.method$Block$playerWillDestroy))
.intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE))
// spawnAfterBreak
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$spawnAfterBreak))
.intercept(MethodDelegation.to(SpawnAfterBreakInterceptor.INSTANCE));
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) {
builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval))
.intercept(MethodDelegation.to(AffectNeighborsAfterRemovalInterceptor.INSTANCE));
}
if (CoreReflections.method$BlockBehaviour$onRemove != null) {
builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onRemove))
.intercept(MethodDelegation.to(OnRemoveInterceptor.INSTANCE));
}
Class<?> clazz$CraftEngineBlock = builder.make().load(BlockGenerator.class.getClassLoader()).getLoaded();
constructor$CraftEngineBlock = MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
@@ -225,15 +235,9 @@ public final class BlockGenerator {
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
DelegatingBlock indicator = (DelegatingBlock) thisObj;
// todo chain updater
if (indicator.isNoteBlock()) {
if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
startNoteBlockChain(args);
}
} else if (indicator.isTripwire()) {
if (CoreReflections.clazz$ServerLevel.isInstance(args[posIndex])) {
}
// todo better chain updater
if (indicator.isNoteBlock() && CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
startNoteBlockChain(args);
}
try {
return holder.value().updateShape(thisObj, args, superMethod);
@@ -501,6 +505,7 @@ public final class BlockGenerator {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().onExplosionHit(thisObj, args, superMethod);
superMethod.call();
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run onExplosionHit", e);
}
@@ -611,6 +616,20 @@ public final class BlockGenerator {
}
}
public static class OnRemoveInterceptor {
public static final OnRemoveInterceptor INSTANCE = new OnRemoveInterceptor();
@RuntimeType
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().onRemove(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run onRemove", e);
}
}
}
public static class EntityInsideInterceptor {
public static final EntityInsideInterceptor INSTANCE = new EntityInsideInterceptor();
@@ -624,4 +643,33 @@ public final class BlockGenerator {
}
}
}
public static class PlayerWillDestroyInterceptor {
public static final PlayerWillDestroyInterceptor INSTANCE = new PlayerWillDestroyInterceptor();
@RuntimeType
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
return holder.value().playerWillDestroy(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run playerWillDestroy", e);
return superMethod.call();
}
}
}
public static class SpawnAfterBreakInterceptor {
public static final SpawnAfterBreakInterceptor INSTANCE = new SpawnAfterBreakInterceptor();
@RuntimeType
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().spawnAfterBreak(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run spawnAfterBreak", e);
}
}
}
}

View File

@@ -100,6 +100,9 @@ public final class BlockStateGenerator {
Object tool = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.TOOL);
Item<ItemStack> item = BukkitItemManager.instance().wrap(tool == null || FastNMS.INSTANCE.method$ItemStack$isEmpty(tool) ? null : FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(tool));
Object optionalPlayer = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.THIS_ENTITY);
if (!CoreReflections.clazz$Player.isInstance(optionalPlayer)) {
optionalPlayer = null;
}
// do not drop if it's not the correct tool
BlockSettings settings = state.settings();
@@ -115,7 +118,7 @@ public final class BlockStateGenerator {
World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel));
ContextHolder.Builder lootBuilder = new ContextHolder.Builder()
.withParameter(DirectContextParameters.POSITION, new WorldPosition(world, FastNMS.INSTANCE.field$Vec3$x(vec3), FastNMS.INSTANCE.field$Vec3$y(vec3), FastNMS.INSTANCE.field$Vec3$z(vec3)));
if (item != null) {
if (!item.isEmpty()) {
lootBuilder.withParameter(DirectContextParameters.ITEM_IN_HAND, item);
}

View File

@@ -20,11 +20,9 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
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.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -135,12 +133,7 @@ public class RecipeInjector {
);
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
return Optional.empty();
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -186,12 +179,7 @@ public class RecipeInjector {
}
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
return Optional.empty();
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -232,12 +220,7 @@ public class RecipeInjector {
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
return Optional.empty();
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -282,12 +265,7 @@ public class RecipeInjector {
// 获取唯一内存地址id
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
if (idHolder.isEmpty()) {
return Optional.empty();
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
// 这个ce配方并不存在那么应该返回空
if (ceRecipe == null) {

View File

@@ -1,6 +1,5 @@
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;
@@ -19,6 +18,7 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.CooldownData;
import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.plugin.network.*;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
@@ -43,8 +43,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
private static BukkitNetworkManager instance;
private static final Map<Class<?>, TriConsumer<NetWorkUser, NMSPacketEvent, Object>> NMS_PACKET_HANDLERS = new HashMap<>();
// only for game stage for the moment
private static BiConsumer<NetWorkUser, ByteBufPacketEvent>[] S2C_BYTE_BUFFER_PACKET_HANDLERS;
private static BiConsumer<NetWorkUser, ByteBufPacketEvent>[] C2S_BYTE_BUFFER_PACKET_HANDLERS;
private static BiConsumer<NetWorkUser, ByteBufPacketEvent>[] S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS;
private static BiConsumer<NetWorkUser, ByteBufPacketEvent>[] C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS;
private static void registerNMSPacketConsumer(final TriConsumer<NetWorkUser, NMSPacketEvent, Object> function, @Nullable Class<?> packet) {
if (packet == null) return;
@@ -53,18 +53,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
private static void registerS2CByteBufPacketConsumer(final BiConsumer<NetWorkUser, ByteBufPacketEvent> function, int id) {
if (id == -1) return;
if (id < 0 || id >= S2C_BYTE_BUFFER_PACKET_HANDLERS.length) {
if (id < 0 || id >= S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) {
throw new IllegalArgumentException("Invalid packet id: " + id);
}
S2C_BYTE_BUFFER_PACKET_HANDLERS[id] = function;
S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function;
}
private static void registerC2SByteBufPacketConsumer(final BiConsumer<NetWorkUser, ByteBufPacketEvent> function, int id) {
if (id == -1) return;
if (id < 0 || id >= C2S_BYTE_BUFFER_PACKET_HANDLERS.length) {
if (id < 0 || id >= C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) {
throw new IllegalArgumentException("Invalid packet id: " + id);
}
C2S_BYTE_BUFFER_PACKET_HANDLERS[id] = function;
C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function;
}
private final BiConsumer<ChannelHandler, Object> packetConsumer;
@@ -92,10 +92,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
@SuppressWarnings("unchecked")
public BukkitNetworkManager(BukkitCraftEngine plugin) {
instance = this;
S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId()];
C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId()];
Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING);
Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING);
S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.s2cGamePackets()];
C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.c2sGamePackets()];
Arrays.fill(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING);
Arrays.fill(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING);
hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null;
hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null;
this.plugin = plugin;
@@ -117,8 +117,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
// set up mod channel
this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL, this);
this.plugin.javaPlugin().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL);
// 配置via频道
this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), VIA_CHANNEL, this);
// Inject server channel
try {
Object server = CoreReflections.method$MinecraftServer$getServer.invoke(null);
@@ -152,15 +150,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket);
registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, NetworkReflections.clazz$ServerboundEditBookPacket);
registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, NetworkReflections.clazz$ServerboundCustomPayloadPacket);
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_PUSH, NetworkReflections.clazz$ClientboundResourcePackPushPacket);
registerNMSPacketConsumer(PacketConsumers.HANDSHAKE_C2S, NetworkReflections.clazz$ClientIntentionPacket);
registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, NetworkReflections.clazz$ServerboundLoginAcknowledgedPacket);
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket);
registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket);
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot);
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket);
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket);
registerNMSPacketConsumer(PacketConsumers.FINISH_CONFIGURATION, NetworkReflections.clazz$ClientboundFinishConfigurationPacket);
registerNMSPacketConsumer(PacketConsumers.LOGIN_FINISHED, NetworkReflections.clazz$ClientboundLoginFinishedPacket);
registerNMSPacketConsumer(PacketConsumers.UPDATE_TAGS, NetworkReflections.clazz$ClientboundUpdateTagsPacket);
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
@@ -176,6 +174,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket());
registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1);
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_RECIPE_BOOK, this.packetIds.clientboundRecipeBookAddPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.PLACE_GHOST_RECIPE, this.packetIds.clientboundPlaceGhostRecipePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_RECIPES, this.packetIds.clientboundUpdateRecipesPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_ADVANCEMENTS, this.packetIds.clientboundUpdateAdvancementsPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());
@@ -204,7 +206,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
this.resetUserArray();
if (VersionHelper.isFolia()) {
player.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> user.tick(),
() -> plugin.debug(() -> "Player " + player.getName() + "'s entity scheduler is retired"), 1, 1);
() -> {}, 1, 1);
}
}
}
@@ -242,14 +244,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {
if (channel.equals(VIA_CHANNEL)) {
BukkitServerPlayer user = this.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
@@ -653,6 +647,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
private void onNMSPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) {
Debugger.PACKET.debug(() -> "[C->S]" + packet.getClass());
handleNMSPacket(user, event, packet);
}
@@ -663,6 +658,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
onNMSPacketSend(player, event, p);
}
} else {
Debugger.PACKET.debug(() -> "[S->C]" + packet.getClass());
handleNMSPacket(player, event, packet);
}
}
@@ -674,13 +670,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) {
int packetID = event.packetID();
Optional.ofNullable(S2C_BYTE_BUFFER_PACKET_HANDLERS[packetID])
Optional.ofNullable(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID])
.ifPresent(function -> function.accept(user, event));
}
protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) {
int packetID = event.packetID();
Optional.ofNullable(C2S_BYTE_BUFFER_PACKET_HANDLERS[packetID])
Optional.ofNullable(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID])
.ifPresent(function -> function.accept(user, event));
}

View File

@@ -1,6 +1,8 @@
package net.momirealms.craftengine.bukkit.plugin.network;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -21,7 +23,6 @@ import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManag
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.pack.BukkitPackManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor;
import net.momirealms.craftengine.bukkit.plugin.network.handler.*;
@@ -34,6 +35,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.core.advancement.network.AdvancementHolder;
import net.momirealms.craftengine.core.advancement.network.AdvancementProgress;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.font.FontManager;
@@ -42,6 +45,9 @@ import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipeHolder;
import net.momirealms.craftengine.core.item.recipe.network.modern.RecipeBookEntry;
import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay;
import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData;
import net.momirealms.craftengine.core.pack.host.ResourcePackHost;
import net.momirealms.craftengine.core.plugin.CraftEngine;
@@ -50,6 +56,7 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.plugin.network.*;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.BlockHitResult;
@@ -64,7 +71,6 @@ import net.momirealms.craftengine.core.world.collision.AABB;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@@ -127,8 +133,8 @@ public class PacketConsumers {
ADD_ENTITY_HANDLERS[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true);
ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true);
ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true);
@@ -1254,9 +1260,6 @@ public class PacketConsumers {
player.setConnectionState(ConnectionState.PLAY);
Object dimensionKey;
if (!VersionHelper.isOrAbove1_20_2()) {
if (BukkitNetworkManager.hasViaVersion()) {
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid()));
}
dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet);
} else {
Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
@@ -1281,7 +1284,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 (user.protocolVersion().isVersionNewerThan(ProtocolVersion.V1_21_4)) return;
if (VersionHelper.isOrAbove1_21_4()) return;
if (!user.isOnline()) return;
BukkitServerPlayer player = (BukkitServerPlayer) user;
if (VersionHelper.isFolia()) {
@@ -1307,7 +1310,7 @@ public class PacketConsumers {
int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet);
if (slot < 36 || slot > 44) return;
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet));
if (ItemUtils.isEmpty(item)) return;
if (ItemStackUtils.isEmpty(item)) return;
if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) {
return;
}
@@ -1323,11 +1326,14 @@ public class PacketConsumers {
Key itemId = state.settings().itemId();
// no item available
if (itemId == null) return;
BlockData data = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle());
// compare item
if (data == null || !data.getMaterial().equals(item.getType())) return;
Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().handle());
Object vanillaBlockItem = FastNMS.INSTANCE.method$Block$asItem(vanillaBlock);
if (vanillaBlockItem == null) return;
Key addItemId = KeyUtils.namespacedKey2Key(item.getType().getKey());
Key blockItemId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, vanillaBlockItem));
if (!addItemId.equals(blockItemId)) return;
ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, player);
if (ItemUtils.isEmpty(itemStack)) {
if (ItemStackUtils.isEmpty(itemStack)) {
CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item");
return;
}
@@ -1336,7 +1342,7 @@ public class PacketConsumers {
int emptySlot = -1;
for (int i = 0; i < 9 + 27; i++) {
ItemStack invItem = inventory.getItem(i);
if (ItemUtils.isEmpty(invItem)) {
if (ItemStackUtils.isEmpty(invItem)) {
if (emptySlot == -1 && i < 9) emptySlot = i;
continue;
}
@@ -1359,7 +1365,7 @@ public class PacketConsumers {
}
} else {
if (item.getAmount() == 1) {
if (ItemUtils.isEmpty(inventory.getItem(slot - 36))) {
if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) {
BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack));
return;
}
@@ -1929,24 +1935,21 @@ public class PacketConsumers {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isPresent()) {
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))));
isChanged = true;
break;
}
}
if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue;
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))));
isChanged = true;
break;
}
if (isChanged) {
event.setChanged(true);
@@ -2093,7 +2096,13 @@ public class PacketConsumers {
int stateId = buf.readVarInt();
int slot = buf.readShort();
Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf);
ItemStack itemStack;
try {
itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf);
} catch (Exception e) {
// 其他插件干的比如某ty*****er不要赖到ce头上
return;
}
BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> {
event.setChanged(true);
buf.clear();
@@ -2117,11 +2126,11 @@ public class PacketConsumers {
ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf);
if (VersionHelper.isOrAbove1_21_5()) {
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(itemStack);
if (wrapped != null && wrapped.isCustomItem()) {
if (!wrapped.isEmpty() && wrapped.isCustomItem()) {
Object containerMenu = FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer.serverPlayer());
if (containerMenu != null) {
ItemStack carried = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.method$AbstractContainerMenu$getCarried(containerMenu));
if (ItemUtils.isEmpty(carried)) {
if (ItemStackUtils.isEmpty(carried)) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
@@ -2280,73 +2289,55 @@ public class PacketConsumers {
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RESOURCE_PACK_PUSH = (user, event, packet) -> {
try {
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)) {
return;
}
event.setCancelled(true);
UUID packUUID = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$uuid(packet);
ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost();
host.requestResourcePackDownloadLink(user.uuid()).thenAccept(dataList -> {
if (dataList.isEmpty()) {
user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID));
return;
}
for (ResourcePackDownloadData data : dataList) {
Object newPacket = ResourcePackUtils.createPacket(data.uuid(), data.url(), data.sha1());
user.sendPacket(newPacket, true);
user.addResourcePackUUID(data.uuid());
}
}).exceptionally(throwable -> {
CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", throwable);
user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID));
return null;
});
} catch (Exception e) {
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 = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet);
user.setProtocolVersion(protocolVersion);
} catch (Throwable 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 = NetworkReflections.methodHandle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet);
if (action == null) return;
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED
|| action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) {
Object kickPacket = NetworkReflections.constructor$ClientboundDisconnectPacket.newInstance(
ComponentUtils.adventureToMinecraft(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")));
user.sendPacket(kickPacket, true);
user.nettyChannel().disconnect();
Object action = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$action(packet);
if (VersionHelper.isOrAbove1_20_3()) {
UUID uuid = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$id(packet);
if (!user.isResourcePackLoading(uuid)) {
// 不是CraftEngine发送的资源包,不管
return;
}
}
if (action == null) {
user.kick(Component.text("Corrupted ResourcePackResponse Packet"));
return;
}
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) {
user.setSentResourcePack(true);
// 检查是否是拒绝
if (Config.kickOnDeclined()) {
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DISCARDED) {
user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
return;
}
}
// 检查是否失败
if (Config.kickOnFailedApply()) {
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD
|| (VersionHelper.isOrAbove1_20_3() && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$INVALID_URL)) {
user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
return;
}
}
boolean isTerminal = action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$ACCEPTED && action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$DOWNLOADED;
if (isTerminal && VersionHelper.isOrAbove1_20_2()) {
event.setCancelled(true);
Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection());
if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) return;
// 主线程上处理这个包
CraftEngine.instance().scheduler().executeSync(() -> {
try {
// 当客户端发出多次成功包的时候finish会报错我们忽略他
NetworkReflections.methodHandle$ServerCommonPacketListener$handleResourcePackResponse.invokeExact(packetListener, packet);
CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$ServerResourcePackConfigurationTask$TYPE);
} catch (Throwable e) {
Debugger.RESOURCE_PACK.warn(() -> "Cannot finish current task", e);
}
});
}
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e);
@@ -2417,4 +2408,176 @@ public class PacketConsumers {
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e);
}
};
// 这个包是由 JoinWorldTask 发出的,客户端收到后会返回 ServerboundFinishConfigurationPacket
@SuppressWarnings("unchecked")
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> FINISH_CONFIGURATION = (user, event, packet) -> {
try {
if (!VersionHelper.isOrAbove1_20_2() || !Config.sendPackOnJoin()) {
// 防止后期调试进配置阶段造成问题
user.setShouldProcessFinishConfiguration(false);
return;
}
if (!user.shouldProcessFinishConfiguration()) return;
Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection());
if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) {
return;
}
// 防止后续加入的JoinWorldTask再次处理
user.setShouldProcessFinishConfiguration(false);
// 取消 ClientboundFinishConfigurationPacket让客户端发呆并结束掉当前的进入世界任务
event.setCancelled(true);
try {
CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$JoinWorldTask$TYPE);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to finish current task for " + user.name(), e);
}
if (VersionHelper.isOrAbove1_20_5()) {
// 1.20.5+开始会检查是否结束需要重新设置回去不然不会发keepAlive包
CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false);
}
// 请求资源包
ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost();
host.requestResourcePackDownloadLink(user.uuid()).whenComplete((dataList, t) -> {
if (t != null) {
CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t);
FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener);
return;
}
if (dataList.isEmpty()) {
FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener);
return;
}
Queue<Object> configurationTasks;
try {
configurationTasks = (Queue<Object>) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to get configuration tasks for player " + user.name(), e);
FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener);
return;
}
// 向配置阶段连接的任务重加入资源包的任务
for (ResourcePackDownloadData data : dataList) {
configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask(ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1())));
user.addResourcePackUUID(data.uuid());
}
// 最后再加入一个 JoinWorldTask 并开始资源包任务
FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener);
});
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundFinishConfigurationPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> LOGIN_FINISHED = (user, event, packet) -> {
try {
GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet);
user.setName(gameProfile.getName());
user.setUUID(gameProfile.getId());
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginFinishedPacket", e);
}
};
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> ADD_RECIPE_BOOK = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
List<RecipeBookEntry> entries = buf.readCollection(ArrayList::new, byteBuf -> {
RecipeBookEntry entry = RecipeBookEntry.read(byteBuf);
entry.applyClientboundData((BukkitServerPlayer) user);
return entry;
});
boolean replace = buf.readBoolean();
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeCollection(entries, ((byteBuf, recipeBookEntry) -> recipeBookEntry.write(byteBuf)));
buf.writeBoolean(replace);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundRecipeBookAddPacket", e);
}
};
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> PLACE_GHOST_RECIPE = (user, event) -> {
try {
if (!VersionHelper.isOrAbove1_21_2()) return;
FriendlyByteBuf buf = event.getBuffer();
int containerId = buf.readContainerId();
RecipeDisplay display = RecipeDisplay.read(buf);
display.applyClientboundData((BukkitServerPlayer) user);
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeContainerId(containerId);
display.write(buf);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundPlaceGhostRecipePacket", e);
}
};
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> UPDATE_RECIPES = (user, event) -> {
try {
if (VersionHelper.isOrAbove1_21_2()) return;
FriendlyByteBuf buf = event.getBuffer();
List<LegacyRecipeHolder> holders = buf.readCollection(ArrayList::new, byteBuf -> {
LegacyRecipeHolder holder = LegacyRecipeHolder.read(byteBuf);
holder.recipe().applyClientboundData((BukkitServerPlayer) user);
return holder;
});
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeCollection(holders, ((byteBuf, recipeHolder) -> recipeHolder.write(byteBuf)));
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateRecipesPacket", e);
}
};
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> UPDATE_ADVANCEMENTS = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
boolean reset = buf.readBoolean();
List<AdvancementHolder> added = buf.readCollection(ArrayList::new, byteBuf -> {
AdvancementHolder holder = AdvancementHolder.read(byteBuf);
holder.applyClientboundData((BukkitServerPlayer) user);
return holder;
});
Set<Key> removed = buf.readCollection(Sets::newLinkedHashSetWithExpectedSize, FriendlyByteBuf::readKey);
Map<Key, AdvancementProgress> progress = buf.readMap(FriendlyByteBuf::readKey, AdvancementProgress::read);
boolean showAdvancement = false;
if (VersionHelper.isOrAbove1_21_5()) {
showAdvancement = buf.readBoolean();
}
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeBoolean(reset);
buf.writeCollection(added, (byteBuf, advancementHolder) -> advancementHolder.write(byteBuf));
buf.writeCollection(removed, FriendlyByteBuf::writeKey);
buf.writeMap(progress, FriendlyByteBuf::writeKey, (byteBuf, advancementProgress) -> advancementProgress.write(byteBuf));
if (VersionHelper.isOrAbove1_21_5()) {
buf.writeBoolean(showAdvancement);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateAdvancementsPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> UPDATE_TAGS = (user, event, packet) -> {
try {
Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket();
if (packet.equals(modifiedPacket) || modifiedPacket == null) return;
event.replacePacket(modifiedPacket);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateTagsPacket", e);
}
};
}

View File

@@ -54,9 +54,17 @@ public interface PacketIds {
int clientboundBlockEventPacket();
int clientboundRecipeBookAddPacket();
int clientboundPlaceGhostRecipePacket();
int clientboundUpdateAdvancementsPacket();
int serverboundContainerClickPacket();
int serverboundSetCreativeModeSlotPacket();
int serverboundInteractPacket();
int clientboundUpdateRecipesPacket();
}

View File

@@ -32,25 +32,22 @@ public class ArmorStandPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isPresent()) {
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))));
isChanged = true;
break;
}
}
if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue;
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))));
isChanged = true;
break;
}
if (isChanged) {
event.setChanged(true);

View File

@@ -47,22 +47,20 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler {
} else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isPresent()) {
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
}
if (isChanged) {

View File

@@ -17,6 +17,7 @@ import java.util.Optional;
public class CommonItemPacketHandler implements EntityPacketHandler {
public static final CommonItemPacketHandler INSTANCE = new CommonItemPacketHandler();
private static long lastWarningTime = 0;
@Override
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
@@ -27,25 +28,28 @@ public class CommonItemPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.ITEM_DATA_ID) {
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
// TODO 检查为什么会导致问题难道是其他插件乱发entity id
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
CraftEngine.instance().logger().warn("Invalid item data for entity " + id);
continue;
}
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isPresent()) {
isChanged = true;
itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)
));
break;
if (entityDataId != EntityDataUtils.ITEM_DATA_ID) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
long time = System.currentTimeMillis();
if (time - lastWarningTime > 5000) {
BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user;
CraftEngine.instance().logger().severe("An issue was detected while applying item-related entity data for '" + serverPlayer.name() +
"'. Please execute the command '/ce debug entity-id " + serverPlayer.world().name() + " " + id + "' and provide a screenshot for further investigation.");
lastWarningTime = time;
}
continue;
}
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isEmpty()) continue;
isChanged = true;
itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)
));
break;
}
if (isChanged) {
event.setChanged(true);

View File

@@ -25,20 +25,18 @@ public class ItemDisplayPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.DISPLAYED_ITEM_DATA_ID) {
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isPresent()) {
isChanged = true;
itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)
));
break;
}
}
if (entityDataId != EntityDataUtils.DISPLAYED_ITEM_DATA_ID) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isEmpty()) continue;
isChanged = true;
itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)
));
break;
}
if (isChanged) {
event.setChanged(true);

View File

@@ -0,0 +1,62 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Optional;
public class ItemFramePacketHandler implements EntityPacketHandler {
public static final ItemFramePacketHandler INSTANCE = new ItemFramePacketHandler();
private static long lastWarningTime = 0;
@Override
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.ITEM_FRAME_DATA_ID) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
long time = System.currentTimeMillis();
if (time - lastWarningTime > 5000) {
BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user;
CraftEngine.instance().logger().severe("An issue was detected while applying item-related entity data for '" + serverPlayer.name() +
"'. Please execute the command '/ce debug entity-id " + serverPlayer.world().name() + " " + id + "' and provide a screenshot for further investigation.");
lastWarningTime = time;
}
continue;
}
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isEmpty()) continue;
isChanged = true;
itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)
));
break;
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
}
}
}

View File

@@ -31,22 +31,20 @@ public class TextDisplayPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.TEXT_DATA_ID) {
Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (textComponent == CoreReflections.instance$Component$empty) break;
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component)));
isChanged = true;
break;
}
if (entityDataId != EntityDataUtils.TEXT_DATA_ID) continue;
Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (textComponent == CoreReflections.instance$Component$empty) break;
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component)));
isChanged = true;
break;
}
if (isChanged) {
event.setChanged(true);

View File

@@ -21,8 +21,8 @@ public class PacketIdFinder {
if (VersionHelper.isOrAbove1_21()) {
Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null);
JsonElement jsonElement = (JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport);
var play = jsonElement.getAsJsonObject().get("play");
for (var entry : play.getAsJsonObject().entrySet()) {
JsonElement play = jsonElement.getAsJsonObject().get("play");
for (Map.Entry<String, JsonElement> entry : play.getAsJsonObject().entrySet()) {
Map<String, Integer> ids = new HashMap<>();
gamePacketIdsByName.put(entry.getKey(), ids);
for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) {
@@ -40,6 +40,7 @@ public class PacketIdFinder {
maxS2CPacketId = calculateMaxId("clientbound");
maxC2SPacketId = calculateMaxId("serverbound");
}
private static int calculateMaxId(String direction) {
if (VersionHelper.isOrAbove1_20_5()) {
return gamePacketIdsByName.getOrDefault(direction, Collections.emptyMap()).size();
@@ -48,11 +49,11 @@ public class PacketIdFinder {
}
}
public static int maxC2SPacketId() {
public static int c2sGamePackets() {
return maxC2SPacketId;
}
public static int maxS2CPacketId() {
public static int s2cGamePackets() {
return maxS2CPacketId;
}

View File

@@ -149,4 +149,24 @@ public class PacketIds1_20 implements PacketIds {
public int serverboundInteractPacket() {
return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket);
}
@Override
public int clientboundRecipeBookAddPacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket);
}
@Override
public int clientboundPlaceGhostRecipePacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket);
}
@Override
public int clientboundUpdateRecipesPacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket);
}
@Override
public int clientboundUpdateAdvancementsPacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket);
}
}

View File

@@ -134,6 +134,26 @@ public class PacketIds1_20_5 implements PacketIds {
return PacketIdFinder.clientboundByName("minecraft:block_event");
}
@Override
public int clientboundRecipeBookAddPacket() {
return PacketIdFinder.clientboundByName("minecraft:recipe_book_add");
}
@Override
public int clientboundPlaceGhostRecipePacket() {
return PacketIdFinder.clientboundByName("minecraft:place_ghost_recipe");
}
@Override
public int clientboundUpdateRecipesPacket() {
return PacketIdFinder.clientboundByName("minecraft:update_recipes");
}
@Override
public int clientboundUpdateAdvancementsPacket() {
return PacketIdFinder.clientboundByName("minecraft:update_advancements");
}
@Override
public int serverboundContainerClickPacket() {
return PacketIdFinder.serverboundByName("minecraft:container_click");

View File

@@ -262,7 +262,7 @@ public final class CraftBukkitReflections {
);
public static final Field field$CraftBlockEntityState$tileEntity = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$CraftBlockEntityState, 0)
ReflectionUtils.getInstanceDeclaredField(clazz$CraftBlockEntityState, 0)
);
public static final Method method$CraftInventory$getInventory = requireNonNull(

View File

@@ -9,6 +9,7 @@ import io.netty.channel.ChannelFuture;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -289,11 +290,11 @@ public final class CoreReflections {
)).getInterfaces()[0]
);
public static final Method method$RegistryAccess$registryOrThrow = requireNonNull(
ReflectionUtils.getMethod(
clazz$RegistryAccess, clazz$Registry, clazz$ResourceKey
)
);
// public static final Method method$RegistryAccess$registryOrThrow = requireNonNull(
// ReflectionUtils.getMethod(
// clazz$RegistryAccess, clazz$Registry, clazz$ResourceKey
// )
// );
public static final Method method$Registry$register = requireNonNull(
ReflectionUtils.getStaticMethod(
@@ -328,58 +329,52 @@ public final class CoreReflections {
)
);
public static final Method method$Registry$getKey = requireNonNull(
ReflectionUtils.getMethod(clazz$Registry, clazz$ResourceLocation, Object.class)
);
// public static final Method method$Registry$getKey = requireNonNull(
// ReflectionUtils.getMethod(clazz$Registry, clazz$ResourceLocation, Object.class)
// );
public static final Method method$Registry$get = requireNonNull(
ReflectionUtils.getMethods(
clazz$Registry, Object.class, clazz$ResourceLocation
).stream().filter(m -> m.getReturnType() != Optional.class).findAny().orElse(null)
);
// use ResourceLocation
public static final Method method$Registry$getHolder0;
// use ResourceKey
public static final Method method$Registry$getHolder1;
static {
List<Method> methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceLocation);
Method theMethod1 = null;
for (Method method : methods) {
Type returnType = method.getGenericReturnType();
if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceLocation) {
if (returnType instanceof ParameterizedType parameterizedType) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (actualTypeArguments.length == 1) {
if (actualTypeArguments[0] instanceof ParameterizedType) {
theMethod1 = method;
}
}
}
}
}
method$Registry$getHolder0 = theMethod1;
}
static {
List<Method> methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceKey);
Method theMethod1 = null;
for (Method method : methods) {
Type returnType = method.getGenericReturnType();
if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceKey) {
if (returnType instanceof ParameterizedType parameterizedType) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (actualTypeArguments.length == 1) {
if (actualTypeArguments[0] instanceof ParameterizedType) {
theMethod1 = method;
}
}
}
}
}
method$Registry$getHolder1 = theMethod1;
}
// // use ResourceLocation
// public static final Method method$Registry$getHolder0;
// // use ResourceKey
// public static final Method method$Registry$getHolder1;
//
// static {
// List<Method> methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceLocation);
// Method theMethod1 = null;
// for (Method method : methods) {
// Type returnType = method.getGenericReturnType();
// if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceLocation) {
// if (returnType instanceof ParameterizedType parameterizedType) {
// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
// if (actualTypeArguments.length == 1) {
// if (actualTypeArguments[0] instanceof ParameterizedType) {
// theMethod1 = method;
// }
// }
// }
// }
// }
// method$Registry$getHolder0 = theMethod1;
// }
//
// static {
// List<Method> methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceKey);
// Method theMethod1 = null;
// for (Method method : methods) {
// Type returnType = method.getGenericReturnType();
// if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceKey) {
// if (returnType instanceof ParameterizedType parameterizedType) {
// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
// if (actualTypeArguments.length == 1) {
// if (actualTypeArguments[0] instanceof ParameterizedType) {
// theMethod1 = method;
// }
// }
// }
// }
// }
// method$Registry$getHolder1 = theMethod1;
// }
public static final Class<?> clazz$BlockPos = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
@@ -1328,6 +1323,10 @@ public final class CoreReflections {
public static final Field field$BlockStateBase$lightBlock =
ReflectionUtils.getInstanceDeclaredField(clazz$BlockStateBase, int.class, 1);
// 1.20-1.21.1
public static final Field field$BlockStateBase$opacityIfCached =
ReflectionUtils.getInstanceDeclaredField(clazz$BlockStateBase, int.class, 1);
public static final Class<?> clazz$AABB = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.phys.AxisAlignedBB",
@@ -1825,18 +1824,10 @@ public final class CoreReflections {
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 2)
);
public static final Field field$Abilities$instabuild = requireNonNull(
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 3)
);
public static final Field field$Abilities$mayBuild = requireNonNull(
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 4)
);
public static final Field field$Player$abilities = requireNonNull(
ReflectionUtils.getInstanceDeclaredField(clazz$Player, clazz$Abilities, 0)
);
public static final Class<?> clazz$FlowingFluid = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.material.FluidTypeFlowing",
@@ -2299,12 +2290,26 @@ public final class CoreReflections {
public static final Constructor<?> constructor$SmithingTransformRecipe = requireNonNull(
VersionHelper.isOrAbove1_21_5()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult)
: VersionHelper.isOrAbove1_21_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack)
: VersionHelper.isOrAbove1_20_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
: ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult)
: VersionHelper.isOrAbove1_21_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack)
: VersionHelper.isOrAbove1_20_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
: ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
);
public static final Class<?> clazz$SmithingTrimRecipe = requireNonNull(
ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("world.item.crafting.SmithingTrimRecipe"))
);
public static final Constructor<?> constructor$SmithingTrimRecipe = requireNonNull(
VersionHelper.isOrAbove1_21_5() ?
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$Holder) :
VersionHelper.isOrAbove1_21_2() ?
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, Optional.class, Optional.class, Optional.class) :
VersionHelper.isOrAbove1_20_2() ?
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient) :
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient)
);
public static final Method method$RecipeManager$addRecipe = requireNonNull(
@@ -3588,4 +3593,241 @@ public final class CoreReflections {
"nbt.CompoundTag"
)
);
public static final Class<?> clazz$TrimPattern = requireNonNull(
VersionHelper.isOrAbove1_21_2() ?
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.equipment.trim.TrimPattern",
"world.item.equipment.trim.TrimPattern"
) :
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.armortrim.TrimPattern",
"world.item.armortrim.TrimPattern"
)
);
public static final Class<?> clazz$TrimMaterial = requireNonNull(
VersionHelper.isOrAbove1_21_2() ?
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.equipment.trim.TrimMaterial",
"world.item.equipment.trim.TrimMaterial"
) :
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.armortrim.TrimMaterial",
"world.item.armortrim.TrimMaterial"
)
);
public static final Class<?> clazz$MaterialAssetGroup = BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.equipment.trim.MaterialAssetGroup",
"world.item.equipment.trim.MaterialAssetGroup"
);
public static final Method method$MaterialAssetGroup$create = Optional.ofNullable(clazz$MaterialAssetGroup)
.map(it -> ReflectionUtils.getStaticMethod(it, it, String.class)).orElse(null);
public static final Constructor<?> constructor$TrimPattern = requireNonNull(
VersionHelper.isOrAbove1_21_5() ?
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Component, boolean.class) :
VersionHelper.isOrAbove1_20_2() ?
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component, boolean.class) :
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component)
);
public static final Constructor<?> constructor$TrimMaterial = requireNonNull(
VersionHelper.isOrAbove1_21_5() ?
ReflectionUtils.getConstructor(clazz$TrimMaterial, clazz$MaterialAssetGroup, clazz$Component) :
VersionHelper.isOrAbove1_21_4() ?
ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, Map.class, clazz$Component) :
ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, float.class, Map.class, clazz$Component)
);
public static final Class<?> clazz$ServerConfigurationPacketListenerImpl = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("server.network.ServerConfigurationPacketListenerImpl")
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Field field$ServerConfigurationPacketListenerImpl$configurationTasks = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl)
.map(it -> ReflectionUtils.getDeclaredField(it, Queue.class, 0))
.orElse(null);
public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter;
static {
try {
if (VersionHelper.isOrAbove1_20_2()) {
methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter =
ReflectionUtils.unreflectGetter(field$ServerConfigurationPacketListenerImpl$configurationTasks)
.asType(MethodType.methodType(Queue.class, Object.class));
} else {
methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter = null;
}
} catch (IllegalAccessException e) {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
public static final Class<?> clazz$JoinWorldTask = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("server.network.config.JoinWorldTask")
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Constructor<?> constructor$JoinWorldTask = Optional.ofNullable(clazz$JoinWorldTask)
.map(ReflectionUtils::getTheOnlyConstructor)
.orElse(null);
public static final Class<?> clazz$ConfigurationTask$Type = MiscUtils.requireNonNullIf(
BukkitReflectionUtils.findReobfOrMojmapClass(
"server.network.ConfigurationTask$a",
"server.network.ConfigurationTask$Type"
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Field field$JoinWorldTask$TYPE = Optional.ofNullable(clazz$JoinWorldTask)
.map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0))
.orElse(null);
public static final Class<?> clazz$ServerResourcePackConfigurationTask = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("server.network.config.ServerResourcePackConfigurationTask")
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Field field$ServerResourcePackConfigurationTask$TYPE = Optional.ofNullable(clazz$ServerResourcePackConfigurationTask)
.map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0))
.orElse(null);
public static final Object instance$JoinWorldTask;
public static final Object instance$JoinWorldTask$TYPE;
public static final Object instance$ServerResourcePackConfigurationTask$TYPE;
static {
try {
if (VersionHelper.isOrAbove1_20_2()) {
instance$JoinWorldTask = constructor$JoinWorldTask.newInstance();
instance$JoinWorldTask$TYPE = field$JoinWorldTask$TYPE.get(null);
instance$ServerResourcePackConfigurationTask$TYPE = field$ServerResourcePackConfigurationTask$TYPE.get(null);
} else {
instance$JoinWorldTask = null;
instance$JoinWorldTask$TYPE = null;
instance$ServerResourcePackConfigurationTask$TYPE = null;
}
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
// 注释的这些说不定以后调试有用
// public static final Class<?> clazz$ConfigurationTask = MiscUtils.requireNonNullIf(
// ReflectionUtils.getClazz(
// BukkitReflectionUtils.assembleMCClass("server.network.ConfigurationTask")
// ),
// VersionHelper.isOrAbove1_20_2()
// );
//
// public static final Field field$ServerConfigurationPacketListenerImpl$currentTask = MiscUtils.requireNonNullIf(
// ReflectionUtils.getDeclaredField(clazz$ServerConfigurationPacketListenerImpl, clazz$ConfigurationTask, 0),
// VersionHelper.isOrAbove1_20_2()
// );
// 1.20.2+
public static final Method method$ServerConfigurationPacketListenerImpl$finishCurrentTask = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl)
.map(it -> ReflectionUtils.getDeclaredMethod(it, void.class, clazz$ConfigurationTask$Type))
.orElse( null);
public static final Field field$ServerCommonPacketListenerImpl$closed = MiscUtils.requireNonNullIf(
ReflectionUtils.getDeclaredField(clazz$ServerCommonPacketListenerImpl, boolean.class, VersionHelper.isOrAbove1_21_6() ? 1 : 2),
VersionHelper.isOrAbove1_20_5()
);
public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask;
public static final MethodHandle methodHandle$ServerCommonPacketListenerImpl$closedSetter;
static {
try {
if (VersionHelper.isOrAbove1_20_2()) {
methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask =
ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask)
.asType(MethodType.methodType(void.class, Object.class, Object.class));
methodHandle$ServerCommonPacketListenerImpl$closedSetter =
ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed)
.asType(MethodType.methodType(void.class, Object.class, boolean.class));
} else {
methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null;
methodHandle$ServerCommonPacketListenerImpl$closedSetter = null;
}
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
public static final Method method$Block$playerWillDestroy = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$Block,
VersionHelper.isOrAbove1_20_3() ? clazz$BlockState : void.class,
clazz$Level, clazz$BlockPos, clazz$BlockState, clazz$Player
)
);
public static final Class<?> clazz$BlockItem = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.ItemBlock",
"world.item.BlockItem"
)
);
public static final Class<?> clazz$ArmorTrim = requireNonNull(
ReflectionUtils.getClazz(
VersionHelper.isOrAbove1_21_2() ?
BukkitReflectionUtils.assembleMCClass("world.item.equipment.trim.ArmorTrim") :
BukkitReflectionUtils.assembleMCClass("world.item.armortrim.ArmorTrim")
)
);
public static final Field field$ArmorTrim$CODEC = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$ArmorTrim, Codec.class, 0)
);
public static final Codec<?> instance$ArmorTrim$CODEC;
static {
try {
instance$ArmorTrim$CODEC = (Codec<?>) field$ArmorTrim$CODEC.get(null);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize ArmorTrim CODEC", e);
}
}
public static final Method method$ArmorTrim$setTrim = ReflectionUtils.getStaticMethod(
clazz$ArmorTrim, boolean.class, clazz$RegistryAccess, clazz$ItemStack, clazz$ArmorTrim
);
public static final Method method$ArmorTrim$getTrim =
VersionHelper.isOrAbove1_20_2() ?
ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack, boolean.class) :
ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack);
public static final Method method$BlockBehaviour$spawnAfterBreak = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$ItemStack, boolean.class
)
);
// 1.20~1.21.4
public static final Method method$BlockBehaviour$onRemove = MiscUtils.requireNonNullIf(
ReflectionUtils.getDeclaredMethod(
clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$BlockState, boolean.class
),
!VersionHelper.isOrAbove1_21_5()
);
}

View File

@@ -3,8 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.Optional;
public final class MAttributeHolders {
private MAttributeHolders() {}
@@ -12,26 +10,20 @@ public final class MAttributeHolders {
public static final Object BLOCK_INTERACTION_RANGE;
public static final Object SCALE;
@SuppressWarnings("unchecked")
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
Optional<Object> optionalHolder = (Optional<Object>) CoreReflections.method$Registry$getHolder0.invoke(MBuiltInRegistries.ATTRIBUTE, rl);
return optionalHolder.orElse(null);
return FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(MBuiltInRegistries.ATTRIBUTE, rl).get();
}
static {
try {
if (VersionHelper.isOrAbove1_20_5()) {
BLOCK_BREAK_SPEED = getById(VersionHelper.isOrAbove1_21_2() ? "block_break_speed" : "player.block_break_speed");
BLOCK_INTERACTION_RANGE = getById(VersionHelper.isOrAbove1_21_2() ? "block_interaction_range" : "player.block_interaction_range");
SCALE = getById(VersionHelper.isOrAbove1_21_2() ? "scale" : "generic.scale");
} else {
BLOCK_BREAK_SPEED = null;
BLOCK_INTERACTION_RANGE = null;
SCALE = null;
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
if (VersionHelper.isOrAbove1_20_5()) {
BLOCK_BREAK_SPEED = getById(VersionHelper.isOrAbove1_21_2() ? "block_break_speed" : "player.block_break_speed");
BLOCK_INTERACTION_RANGE = getById(VersionHelper.isOrAbove1_21_2() ? "block_interaction_range" : "player.block_interaction_range");
SCALE = getById(VersionHelper.isOrAbove1_21_2() ? "scale" : "generic.scale");
} else {
BLOCK_BREAK_SPEED = null;
BLOCK_INTERACTION_RANGE = null;
SCALE = null;
}
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.core.util.VersionHelper;
public final class MBlocks {
@@ -19,26 +18,22 @@ public final class MBlocks {
public static final Object SHULKER_BOX;
public static final Object COMPOSTER;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, rl);
}
static {
try {
AIR = getById("air");
AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
FIRE = getById("fire");
SOUL_FIRE = getById("soul_fire");
STONE = getById("stone");
STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE);
ICE = getById("ice");
SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
SHULKER_BOX = getById("shulker_box");
COMPOSTER = getById("composter");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init Blocks", e);
}
AIR = getById("air");
AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
FIRE = getById("fire");
SOUL_FIRE = getById("soul_fire");
STONE = getById("stone");
STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE);
ICE = getById("ice");
SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
SHULKER_BOX = getById("shulker_box");
COMPOSTER = getById("composter");
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.core.util.VersionHelper;
public final class MEntityTypes {
@@ -60,72 +59,68 @@ public final class MEntityTypes {
public static final Object PLAYER;
public static final int PLAYER$registryId;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.ENTITY_TYPE, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ENTITY_TYPE, rl);
}
private static int getRegistryId(Object type) throws ReflectiveOperationException {
private static int getRegistryId(Object type) {
if (type == null) return -1;
return (int) CoreReflections.method$Registry$getId.invoke(MBuiltInRegistries.ENTITY_TYPE, type);
return FastNMS.INSTANCE.method$Registry$getId(MBuiltInRegistries.ENTITY_TYPE, type);
}
static {
try {
TEXT_DISPLAY = getById("text_display");
TEXT_DISPLAY$registryId = getRegistryId(TEXT_DISPLAY);
ITEM_DISPLAY = getById("item_display");
ITEM_DISPLAY$registryId = getRegistryId(ITEM_DISPLAY);
BLOCK_DISPLAY = getById("block_display");
BLOCK_DISPLAY$registryId = getRegistryId(BLOCK_DISPLAY);
FALLING_BLOCK = getById("falling_block");
FALLING_BLOCK$registryId = getRegistryId(FALLING_BLOCK);
INTERACTION = getById("interaction");
INTERACTION$registryId = getRegistryId(INTERACTION);
SHULKER = getById("shulker");
SHULKER$registryId = getRegistryId(SHULKER);
ARMOR_STAND = getById("armor_stand");
ARMOR_STAND$registryId = getRegistryId(ARMOR_STAND);
OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat");
OAK_BOAT$registryId = getRegistryId(OAK_BOAT);
TRIDENT = getById("trident");
TRIDENT$registryId = getRegistryId(TRIDENT);
SNOWBALL = getById("snowball");
SNOWBALL$registryId = getRegistryId(SNOWBALL);
FIREBALL = getById("fireball");
FIREBALL$registryId = getRegistryId(FIREBALL);
EYE_OF_ENDER = getById("eye_of_ender");
EYE_OF_ENDER$registryId = getRegistryId(EYE_OF_ENDER);
FIREWORK_ROCKET = getById("firework_rocket");
FIREWORK_ROCKET$registryId = getRegistryId(FIREWORK_ROCKET);
ITEM = getById("item");
ITEM$registryId = getRegistryId(ITEM);
ITEM_FRAME = getById("item_frame");
ITEM_FRAME$registryId = getRegistryId(ITEM_FRAME);
GLOW_ITEM_FRAME = getById("glow_item_frame");
GLOW_ITEM_FRAME$registryId = getRegistryId(GLOW_ITEM_FRAME);
SMALL_FIREBALL = getById("small_fireball");
SMALL_FIREBALL$registryId = getRegistryId(SMALL_FIREBALL);
EGG = getById("egg");
EGG$registryId = getRegistryId(EGG);
ENDER_PEARL = getById("ender_pearl");
ENDER_PEARL$registryId = getRegistryId(ENDER_PEARL);
EXPERIENCE_BOTTLE = getById("experience_bottle");
EXPERIENCE_BOTTLE$registryId = getRegistryId(EXPERIENCE_BOTTLE);
POTION = getById("potion");
POTION$registryId = getRegistryId(POTION);
OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null;
OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(OMINOUS_ITEM_SPAWNER);
HAPPY_GHAST = VersionHelper.isOrAbove1_21_6() ? getById("happy_ghast") : null;
HAPPY_GHAST$registryId = getRegistryId(HAPPY_GHAST);
PLAYER = getById("player");
PLAYER$registryId = getRegistryId(PLAYER);
ARROW = getById("arrow");
ARROW$registryId = getRegistryId(ARROW);
SPECTRAL_ARROW = getById("spectral_arrow");
SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init EntityTypes", e);
}
TEXT_DISPLAY = getById("text_display");
TEXT_DISPLAY$registryId = getRegistryId(TEXT_DISPLAY);
ITEM_DISPLAY = getById("item_display");
ITEM_DISPLAY$registryId = getRegistryId(ITEM_DISPLAY);
BLOCK_DISPLAY = getById("block_display");
BLOCK_DISPLAY$registryId = getRegistryId(BLOCK_DISPLAY);
FALLING_BLOCK = getById("falling_block");
FALLING_BLOCK$registryId = getRegistryId(FALLING_BLOCK);
INTERACTION = getById("interaction");
INTERACTION$registryId = getRegistryId(INTERACTION);
SHULKER = getById("shulker");
SHULKER$registryId = getRegistryId(SHULKER);
ARMOR_STAND = getById("armor_stand");
ARMOR_STAND$registryId = getRegistryId(ARMOR_STAND);
OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat");
OAK_BOAT$registryId = getRegistryId(OAK_BOAT);
TRIDENT = getById("trident");
TRIDENT$registryId = getRegistryId(TRIDENT);
SNOWBALL = getById("snowball");
SNOWBALL$registryId = getRegistryId(SNOWBALL);
FIREBALL = getById("fireball");
FIREBALL$registryId = getRegistryId(FIREBALL);
EYE_OF_ENDER = getById("eye_of_ender");
EYE_OF_ENDER$registryId = getRegistryId(EYE_OF_ENDER);
FIREWORK_ROCKET = getById("firework_rocket");
FIREWORK_ROCKET$registryId = getRegistryId(FIREWORK_ROCKET);
ITEM = getById("item");
ITEM$registryId = getRegistryId(ITEM);
ITEM_FRAME = getById("item_frame");
ITEM_FRAME$registryId = getRegistryId(ITEM_FRAME);
GLOW_ITEM_FRAME = getById("glow_item_frame");
GLOW_ITEM_FRAME$registryId = getRegistryId(GLOW_ITEM_FRAME);
SMALL_FIREBALL = getById("small_fireball");
SMALL_FIREBALL$registryId = getRegistryId(SMALL_FIREBALL);
EGG = getById("egg");
EGG$registryId = getRegistryId(EGG);
ENDER_PEARL = getById("ender_pearl");
ENDER_PEARL$registryId = getRegistryId(ENDER_PEARL);
EXPERIENCE_BOTTLE = getById("experience_bottle");
EXPERIENCE_BOTTLE$registryId = getRegistryId(EXPERIENCE_BOTTLE);
POTION = getById("potion");
POTION$registryId = getRegistryId(POTION);
OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null;
OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(OMINOUS_ITEM_SPAWNER);
HAPPY_GHAST = VersionHelper.isOrAbove1_21_6() ? getById("happy_ghast") : null;
HAPPY_GHAST$registryId = getRegistryId(HAPPY_GHAST);
PLAYER = getById("player");
PLAYER$registryId = getRegistryId(PLAYER);
ARROW = getById("arrow");
ARROW$registryId = getRegistryId(ARROW);
SPECTRAL_ARROW = getById("spectral_arrow");
SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW);
}
}

View File

@@ -15,7 +15,7 @@ public final class MFluids {
private static Object getById(String id) throws ReflectiveOperationException {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.FLUID, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.FLUID, rl);
}
static {

View File

@@ -1,25 +1,22 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
public final class MItems {
private MItems() {}
public static final Object AIR;
public static final Object WATER_BUCKET;
public static final Object BARRIER;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.ITEM, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, rl);
}
static {
try {
AIR = getById("air");
WATER_BUCKET = getById("water_bucket");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init Items", e);
}
AIR = getById("air");
WATER_BUCKET = getById("water_bucket");
BARRIER = getById("barrier");
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
public final class MMobEffects {
private MMobEffects() {}
@@ -10,19 +9,15 @@ public final class MMobEffects {
public static final Object HASTE;
public static final Object INVISIBILITY;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.MOB_EFFECT, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.MOB_EFFECT, rl);
}
// for 1.20.1-1.20.4
static {
try {
MINING_FATIGUE = getById("mining_fatigue");
HASTE = getById("haste");
INVISIBILITY = getById("invisibility");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init MobEffects", e);
}
MINING_FATIGUE = getById("mining_fatigue");
HASTE = getById("haste");
INVISIBILITY = getById("invisibility");
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
public final class MRecipeTypes {
private MRecipeTypes() {}
@@ -14,22 +13,18 @@ public final class MRecipeTypes {
public static final Object STONECUTTING;
public static final Object SMITHING;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.RECIPE_TYPE, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.RECIPE_TYPE, rl);
}
static {
try {
CRAFTING = getById("crafting");
SMELTING = getById("smelting");
BLASTING = getById("blasting");
SMOKING = getById("smoking");
CAMPFIRE_COOKING = getById("campfire_cooking");
STONECUTTING = getById("stonecutting");
SMITHING = getById("smithing");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init RecipeTypes", e);
}
CRAFTING = getById("crafting");
SMELTING = getById("smelting");
BLASTING = getById("blasting");
SMOKING = getById("smoking");
CAMPFIRE_COOKING = getById("campfire_cooking");
STONECUTTING = getById("stonecutting");
SMITHING = getById("smithing");
}
}

View File

@@ -23,6 +23,8 @@ public final class MRegistries {
public static final Object DIMENSION_TYPE;
public static final Object CONFIGURED_FEATURE;
public static final Object PLACED_FEATURE;
public static final Object TRIM_PATTERN;
public static final Object TRIM_MATERIAL;
@Nullable // 1.21+
public static final Object JUKEBOX_SONG;
@Nullable // 1.21+
@@ -46,6 +48,8 @@ public final class MRegistries {
Object registries$PlacedFeature = null;
Object registries$JukeboxSong = null;
Object registries$Recipe = null;
Object registries$TrimPattern = null;
Object registries$TrimMaterial = null;
for (Field field : fields) {
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType paramType) {
@@ -87,6 +91,10 @@ public final class MRegistries {
registries$JukeboxSong = field.get(null);
} else if (type == CoreReflections.clazz$PlacedFeature) {
registries$PlacedFeature = field.get(null);
} else if (type == CoreReflections.clazz$TrimPattern) {
registries$TrimPattern = field.get(null);
} else if (type == CoreReflections.clazz$TrimMaterial) {
registries$TrimMaterial = field.get(null);
}
}
}
@@ -106,6 +114,8 @@ public final class MRegistries {
RECIPE_TYPE = requireNonNull(registries$RecipeType);
CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature);
PLACED_FEATURE = requireNonNull(registries$PlacedFeature);
TRIM_PATTERN = requireNonNull(registries$TrimPattern);
TRIM_MATERIAL = requireNonNull(registries$TrimMaterial);
JUKEBOX_SONG = registries$JukeboxSong;
RECIPE = registries$Recipe;
} catch (ReflectiveOperationException e) {

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
public final class MSoundEvents {
private MSoundEvents() {}
@@ -12,20 +11,16 @@ public final class MSoundEvents {
public static final Object TRIDENT_RIPTIDE_3;
public static final Object TRIDENT_THROW;
private static Object getById(String id) throws ReflectiveOperationException {
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.SOUND_EVENT, rl);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.SOUND_EVENT, rl);
}
static {
try {
EMPTY = getById("intentionally_empty");
TRIDENT_RIPTIDE_1 = getById("item.trident_riptide_1");
TRIDENT_RIPTIDE_2 = getById("item.trident_riptide_2");
TRIDENT_RIPTIDE_3 = getById("item.trident.riptide_3");
TRIDENT_THROW = getById("item.trident.throw");
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init SoundEvents", e);
}
EMPTY = getById("intentionally_empty");
TRIDENT_RIPTIDE_1 = getById("item.trident_riptide_1");
TRIDENT_RIPTIDE_2 = getById("item.trident_riptide_2");
TRIDENT_RIPTIDE_3 = getById("item.trident.riptide_3");
TRIDENT_THROW = getById("item.trident.throw");
}
}

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import io.netty.buffer.ByteBuf;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -1315,7 +1316,6 @@ public final class NetworkReflections {
public static final MethodHandle methodHandle$ServerboundEditBookPacket$pagesGetter;
public static final MethodHandle methodHandle$ServerboundEditBookPacket$titleGetter;
public static final MethodHandle methodHandle$ServerboundEditBookPacket$slotGetter;
public static final MethodHandle methodHandle$ServerboundResourcePackPacket$actionGetter;
public static final MethodHandle methodHandle$ClientboundEntityEventPacket$entityIdGetter;
public static final MethodHandle methodHandle$ClientboundEntityEventPacket$eventIdGetter;
public static final MethodHandle methodHandle$ClientIntentionPacket$protocolVersionGetter;
@@ -1385,10 +1385,6 @@ public final class NetworkReflections {
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot)
.asType(MethodType.methodType(int.class, Object.class))
);
methodHandle$ServerboundResourcePackPacket$actionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action)
.asType(MethodType.methodType(Object.class, Object.class))
);
methodHandle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId)
.asType(MethodType.methodType(int.class, Object.class))
@@ -1497,4 +1493,105 @@ public final class NetworkReflections {
throw new ReflectionInitException("Failed to initialize ParticleTypes$STREAM_CODEC", e);
}
}
public static final Class<?> clazz$ClientboundFinishConfigurationPacket = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.configuration.ClientboundFinishConfigurationPacket")
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Constructor<?> constructor$ClientboundFinishConfigurationPacket = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket)
.map(ReflectionUtils::getConstructor)
.orElse(null);
// 1.20.5+
public static final Field field$ClientboundFinishConfigurationPacket$INSTANCE = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket)
.map(it -> ReflectionUtils.getDeclaredField(it, it, 0))
.orElse(null);
public static final Object instance$ClientboundFinishConfigurationPacket$INSTANCE;
static {
try {
if (VersionHelper.isOrAbove1_20_2()) {
instance$ClientboundFinishConfigurationPacket$INSTANCE = VersionHelper.isOrAbove1_20_5()
? field$ClientboundFinishConfigurationPacket$INSTANCE.get(null)
: constructor$ClientboundFinishConfigurationPacket.newInstance();
} else {
instance$ClientboundFinishConfigurationPacket$INSTANCE = null;
}
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize ClientboundFinishConfigurationPacket$INSTANCE", e);
}
}
public static final Class<?> clazz$ServerCommonPacketListener = MiscUtils.requireNonNullIf(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerCommonPacketListener")
),
VersionHelper.isOrAbove1_20_2()
);
// 1.20.2+
public static final Method method$ServerCommonPacketListener$handleResourcePackResponse = Optional.ofNullable(clazz$ServerCommonPacketListener)
.map(it -> ReflectionUtils.getMethod(it, void.class, clazz$ServerboundResourcePackPacket))
.orElse(null);
public static final MethodHandle methodHandle$ServerCommonPacketListener$handleResourcePackResponse;
static {
try {
if (VersionHelper.isOrAbove1_20_2()) {
methodHandle$ServerCommonPacketListener$handleResourcePackResponse =
ReflectionUtils.unreflectMethod(method$ServerCommonPacketListener$handleResourcePackResponse)
.asType(MethodType.methodType(void.class, Object.class, Object.class));
} else {
methodHandle$ServerCommonPacketListener$handleResourcePackResponse = null;
}
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize ServerCommonPacketListener$handleResourcePackResponse", e);
}
}
public static final Class<?> clazz$ClientboundLoginFinishedPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.login.PacketLoginOutSuccess",
List.of("network.protocol.login.ClientboundLoginFinishedPacket", "network.protocol.login.ClientboundGameProfilePacket")
)
);
public static final Class<?> clazz$ClientboundRecipeBookAddPacket = MiscUtils.requireNonNullIf(BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.ClientboundRecipeBookAddPacket",
"network.protocol.game.ClientboundRecipeBookAddPacket"
), VersionHelper.isOrAbove1_21_2());
public static final Class<?> clazz$ClientboundPlaceGhostRecipePacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.PacketPlayOutAutoRecipe",
"network.protocol.game.ClientboundPlaceGhostRecipePacket"
)
);
public static final Class<?> clazz$ClientboundUpdateRecipesPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.PacketPlayOutRecipeUpdate",
"network.protocol.game.ClientboundUpdateRecipesPacket"
)
);
public static final Class<?> clazz$ClientboundUpdateAdvancementsPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.PacketPlayOutAdvancements",
"network.protocol.game.ClientboundUpdateAdvancementsPacket"
)
);
public static final Class<?> clazz$ClientboundUpdateTagsPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
List.of("network.protocol.common.ClientboundUpdateTagsPacket", "network.protocol.game.PacketPlayOutTags"),
List.of("network.protocol.common.ClientboundUpdateTagsPacket", "network.protocol.game.ClientboundUpdateTagsPacket")
)
);
}

View File

@@ -29,7 +29,6 @@ import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.context.CooldownData;
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.ProtocolVersion;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
@@ -48,6 +47,7 @@ import org.bukkit.persistence.PersistentDataType;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.RayTraceResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -58,8 +58,7 @@ 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 ChannelHandler connection;
@@ -67,8 +66,8 @@ public class BukkitServerPlayer extends Player {
private UUID uuid;
private ConnectionState decoderState;
private ConnectionState encoderState;
private boolean shouldProcessFinishConfiguration = true;
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;
@@ -252,13 +251,8 @@ public class BukkitServerPlayer extends Player {
@Override
public boolean canInstabuild() {
try {
Object abilities = CoreReflections.field$Player$abilities.get(serverPlayer());
return (boolean) CoreReflections.field$Abilities$instabuild.get(abilities);
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to get canInstabuild for " + name(), e);
return false;
}
Object abilities = FastNMS.INSTANCE.field$Player$abilities(serverPlayer());
return FastNMS.INSTANCE.field$Abilities$instabuild(abilities);
}
@Override
@@ -600,7 +594,7 @@ public class BukkitServerPlayer extends Player {
CoreReflections.field$ServerPlayerGameMode$isDestroyingBlock.set(gameMode, false);
// check item in hand
Item<ItemStack> item = this.getItemInHand(InteractionHand.MAIN_HAND);
if (item != null) {
if (!item.isEmpty()) {
Material itemMaterial = item.getItem().getType();
// creative mode + invalid item in hand
if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK
@@ -618,7 +612,7 @@ public class BukkitServerPlayer extends Player {
ImmutableBlockState customState = optionalCustomState.get();
BlockSettings blockSettings = customState.settings();
if (blockSettings.requireCorrectTool()) {
if (item != null) {
if (!item.isEmpty()) {
// it's correct on plugin side
if (blockSettings.isCorrectTool(item.id())) {
// but not on serverside
@@ -770,7 +764,7 @@ public class BukkitServerPlayer extends Player {
return DirectionUtils.toDirection(platformPlayer().getFacing());
}
@Nullable
@NotNull
@Override
public Item<ItemStack> getItemInHand(InteractionHand hand) {
PlayerInventory inventory = platformPlayer().getInventory();
@@ -874,23 +868,18 @@ public class BukkitServerPlayer extends Player {
}
@Override
public ProtocolVersion protocolVersion() {
return this.protocolVersion;
public boolean isResourcePackLoading(UUID uuid) {
return this.resourcePackUUID.contains(uuid);
}
@Override
public void setProtocolVersion(int protocolVersion) {
this.protocolVersion = ProtocolVersion.getById(protocolVersion);
public void setShouldProcessFinishConfiguration(boolean shouldProcess) {
this.shouldProcessFinishConfiguration = shouldProcess;
}
@Override
public boolean sentResourcePack() {
return this.sentResourcePack;
}
@Override
public void setSentResourcePack(boolean sentResourcePack) {
this.sentResourcePack = sentResourcePack;
public boolean shouldProcessFinishConfiguration() {
return this.shouldProcessFinishConfiguration;
}
@Override

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