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

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java
#	core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java
#	gradle.properties
This commit is contained in:
jhqwqmc
2025-06-12 05:23:18 +08:00
44 changed files with 787 additions and 415 deletions

View File

@@ -28,7 +28,6 @@ import org.joml.Vector3f;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.function.Consumer;
public class BukkitFurniture implements Furniture {
private final Key id;
@@ -131,7 +130,6 @@ public class BukkitFurniture implements Furniture {
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld());
for (Collider entity : this.colliderEntities) {
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity.handle());
injectFurnitureEntity(entity.handle());
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity.handle());
bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1);
}
@@ -361,24 +359,4 @@ public class BukkitFurniture implements Furniture {
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
return newLocation;
}
public static void injectFurnitureEntity(Object nmsEntity) {
try {
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity);
Object serverEntity = FastNMS.INSTANCE.field$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
CoreReflections.handle$ServerEntity$broadcastSetter.invokeExact(serverEntity, Handlers.DO_NOTHING);
CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(serverEntity, Integer.MAX_VALUE);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to inject collider", e);
}
}
@FunctionalInterface
public interface Handlers extends Consumer<Object> {
Consumer<Object> DO_NOTHING = doNothing();
static Handlers doNothing() {
return (packet) -> {};
}
}
}

View File

@@ -86,7 +86,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
SoundData data = furniture.settings().sounds().placeSound();
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch());
}
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(furnitureEntity));
return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId());
}
@@ -102,7 +101,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay display) {
handleBaseEntityLoadEarly(display);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(display));
} else if (entity instanceof Interaction interaction) {
handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (entity instanceof Boat boat) {

View File

@@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
@@ -37,7 +36,6 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay));
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}
@@ -50,7 +48,6 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay));
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}
@@ -62,7 +59,6 @@ public class FurnitureEventListener implements Listener {
Entity entity = event.getEntity();
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadLate(itemDisplay, 0);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay));
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadLate(entity, 0);
}

View File

@@ -205,7 +205,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
private void updateProjectileUpdateInterval(int updateInterval) {
if (this.lastInjectedInterval == updateInterval) return;
try {
CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval);
CoreReflections.methodHandle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval);
this.lastInjectedInterval = updateInterval;
} catch (Throwable e) {
BukkitProjectileManager.this.plugin.logger().warn("Failed to update server entity update interval for " + this.projectile.getType().getKey() + "[" + this.projectile.getUniqueId() + "]", e);

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item;
import com.saicone.rtag.item.ItemTagStream;
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener;
@@ -43,6 +44,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
static {
registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS);
registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET);
registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL);
}
private static BukkitItemManager instance;

View File

@@ -8,7 +8,6 @@ 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.core.item.ItemWrapper;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.inventory.ItemStack;
@@ -113,7 +112,6 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
if (value == null) return;
Object componentType = ensureDataComponentType(type);
if (componentType == null) {
TranslationManager.instance().log("warning.config.item.component_notfound", type.toString());
return;
}
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);

View File

@@ -10,6 +10,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item");
public static void init() {
register(EMPTY, EmptyItemBehavior.FACTORY);
@@ -18,5 +19,6 @@ public class BukkitItemBehaviors extends ItemBehaviors {
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);
register(BUCKET_ITEM, BucketItemBehavior.FACTORY);
register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,167 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.InteractUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
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.sound.SoundSource;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.nio.file.Path;
import java.util.Map;
public class FlintAndSteelItemBehavior extends ItemBehavior {
public static final FlintAndSteelItemBehavior INSTANCE = new FlintAndSteelItemBehavior();
public static final Factory FACTORY = new Factory();
private static final Key FLINT_SOUND = Key.of("item.flintandsteel.use");
@SuppressWarnings("unchecked")
@Override
public InteractionResult useOnBlock(UseOnContext context) {
BlockPos clickedPos = context.getClickedPos();
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos);
Block block = clicked.block();
BlockPos firePos = clickedPos.relative(context.getClickedFace());
Direction direction = context.getHorizontalDirection();
// 最基础的判断能不能着火,不能着火都是扯蛋
try {
if (!(boolean) CoreReflections.method$BaseFireBlock$canBePlacedAt.invoke(null, context.getLevel().serverWorld(), LocationUtils.toBlockPos(firePos), DirectionUtils.toNMSDirection(direction))) {
return InteractionResult.PASS;
}
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to call BaseFireBlock$canBePlacedAt", e);
return InteractionResult.PASS;
}
// 判断点击的方块是否可燃
BlockData clickedBlockData = block.getBlockData();
Object clickedBlockState = BlockStateUtils.blockDataToBlockState(clickedBlockData);
boolean isClickedBlockBurnable;
try {
isClickedBlockBurnable = BlockStateUtils.isBurnable(clickedBlockState) ||
(context.getClickedFace() == Direction.UP && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
clickedBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL));
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
return InteractionResult.PASS;
}
net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer();
// 点击对象直接可燃,则忽略
if (isClickedBlockBurnable) {
int stateId = BlockStateUtils.blockStateToId(clickedBlockState);
if (BlockStateUtils.isVanillaBlock(stateId)) {
return InteractionResult.PASS;
} else {
// 点击对象为自定义方块
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
// 原版外观也可燃
if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) {
return InteractionResult.PASS;
}
BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle());
// 点击的是方块上面则只需要判断shift和可交互
if (direction == Direction.UP) {
// 客户端层面必须可交互
if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState,
context.getHitResult(), (Item<ItemStack>) context.getItem())) {
return InteractionResult.PASS;
}
// 且没有shift
if (!player.isSecondaryUseActive()) {
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
}
} else {
// 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音
BlockPos belowFirePos = firePos.relative(Direction.DOWN);
BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos);
boolean belowCanBurn;
try {
Block belowBlock = belowFireBlock.block();
belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) ||
(boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL);
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
return InteractionResult.PASS;
}
// 客户端觉得这玩意可交互,就会忽略声音
if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item<ItemStack>) context.getItem())) {
// 如果按住了shift则代表尝试对侧面方块点火
if (player.isSecondaryUseActive()) {
// 如果底部不能燃烧,则燃烧点位为侧面,需要补发
if (!belowCanBurn) {
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
player.swingHand(context.getHand());
}
} else {
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
}
} else {
// 如果底部方块不可燃烧才补发
if (!belowCanBurn) {
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
player.swingHand(context.getHand());
}
}
}
}
} else {
// 如果点击的方块不可燃烧,但是服务端却认为可以放置火源,则可燃烧的方块一定位于火源的六个方向之一。
Direction relativeDirection = direction.opposite();
for (Direction dir : Direction.values()) {
if (dir == relativeDirection) continue;
BlockPos relPos = firePos.relative(dir);
BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos);
BlockData nearbyBlockData = nearByBlock.block().getBlockData();
Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData);
int stateID = BlockStateUtils.blockStateToId(nearbyBlockState);
if (BlockStateUtils.isVanillaBlock(stateID)) {
if (BlockStateUtils.isBurnable(nearbyBlockState)) {
return InteractionResult.PASS;
}
try {
if (dir == Direction.DOWN && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
nearbyBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(relPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)) {
return InteractionResult.PASS;
}
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
return InteractionResult.PASS;
}
}
}
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
player.swingHand(context.getHand());
}
return InteractionResult.PASS;
}
public static class Factory implements ItemBehaviorFactory {
@Override
public ItemBehavior create(Pack pack, Path path, Key id, Map<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -34,6 +34,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;

View File

@@ -33,6 +33,7 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Campfire;
import org.bukkit.block.Furnace;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -790,6 +791,48 @@ public class RecipeEventListener implements Listener {
return new Pair<>(first, second);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onCraft(CraftItemEvent event) {
org.bukkit.inventory.Recipe recipe = event.getRecipe();
if (!(recipe instanceof ShapelessRecipe) && !(recipe instanceof ShapedRecipe)) return;
HumanEntity humanEntity = event.getWhoClicked();
if (!(humanEntity instanceof Player player)) return;
CraftingInventory inventory = event.getInventory();
ItemStack result = inventory.getResult();
if (result == null) return;
ItemStack[] usedItems = inventory.getMatrix();
ItemStack[] replacements = new ItemStack[usedItems.length];
boolean hasReplacement = false;
for (int i = 0; i < usedItems.length; i++) {
ItemStack usedItem = usedItems[i];
if (ItemUtils.isEmpty(usedItem)) continue;
if (usedItem.getAmount() != 1) continue;
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(usedItem);
if (wrapped == null) continue;
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
Key remainingItem = customItem.settings().craftRemainder();
if (remainingItem != null) {
replacements[i] = BukkitItemManager.instance().buildItemStack(remainingItem, this.plugin.adapt(player));
hasReplacement = true;
}
}
}
if (!hasReplacement) return;
Runnable delayedTask = () -> {
for (int i = 0; i < replacements.length; i++) {
if (replacements[i] == null) continue;
inventory.setItem(i + 1, replacements[i]);
}
};
if (VersionHelper.isFolia()) {
player.getScheduler().run(this.plugin.javaPlugin(), (t) -> delayedTask.run(), () -> {});
} else {
this.plugin.scheduler().sync().runDelayed(delayedTask);
}
}
@EventHandler(ignoreCancelled = true)
public void onCraftingRecipe(PrepareItemCraftEvent event) {
if (!Config.enableRecipeSystem()) return;

View File

@@ -48,6 +48,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new DebugSpawnFurnitureCommand(this, plugin),
new DebugTargetBlockCommand(this, plugin),
new DebugIsSectionInjectedCommand(this, plugin),
new DebugMigrateTemplatesCommand(this, plugin),
new DebugEntityId2UUIDCommand(this, plugin),
new TotemAnimationCommand(this, plugin),
new EnableResourceCommand(this, plugin),

View File

@@ -0,0 +1,60 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.util.FileUtils;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DebugMigrateTemplatesCommand extends BukkitCommandFeature<CommandSender> {
private static final Pattern PATTERN = Pattern.compile("(?<!\\$)\\{([^}]+)}");
public DebugMigrateTemplatesCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.handler(context -> {
for (Pack pack : BukkitCraftEngine.instance().packManager().loadedPacks()) {
for (Path file : FileUtils.getYmlConfigsDeeply(pack.configurationFolder())) {
try {
Files.writeString(file, replacePlaceholders(Files.readString(file)));
} catch (IOException e) {
e.printStackTrace();
}
}
}
context.sender().sendMessage("Done");
});
}
@Override
public String getFeatureID() {
return "debug_migrate_templates";
}
private static String replacePlaceholders(String input) {
if (input == null) {
return null;
}
Matcher matcher = PATTERN.matcher(input);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
// 将 {xxx} 替换为 ${xxx}
matcher.appendReplacement(sb, "\\${" + matcher.group(1) + "}");
}
matcher.appendTail(sb);
return sb.toString();
}
}

View File

@@ -82,7 +82,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
private static final String CONNECTION_HANDLER_NAME = "craftengine_connection_handler";
private static final String SERVER_CHANNEL_HANDLER_NAME = "craftengine_server_channel_handler";
private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_packet_handler";
private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_channel_handler";
private static final String PACKET_ENCODER = "craftengine_encoder";
private static final String PACKET_DECODER = "craftengine_decoder";
@@ -159,6 +159,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
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);
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());

View File

@@ -162,6 +162,7 @@ public class PacketConsumers {
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id);
if (furniture != null) {
event.setCancelled(true);
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
}
};
ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> {
@@ -172,6 +173,7 @@ public class PacketConsumers {
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id);
if (furniture != null) {
event.setCancelled(true);
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
}
};
}
@@ -1169,14 +1171,14 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HELLO_C2S = (user, event, packet) -> {
try {
BukkitServerPlayer player = (BukkitServerPlayer) user;
String name = (String) NetworkReflections.handle$ServerboundHelloPacket$nameGetter.invokeExact(packet);
String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet);
player.setName(name);
if (VersionHelper.isOrAbove1_20_2()) {
UUID uuid = (UUID) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
player.setUUID(uuid);
} else {
@SuppressWarnings("unchecked")
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
if (uuid.isPresent()) {
player.setUUID(uuid.get());
} else {
@@ -1220,10 +1222,10 @@ public class PacketConsumers {
player.clearView();
Object dimensionKey;
if (!VersionHelper.isOrAbove1_20_2()) {
dimensionKey = NetworkReflections.handle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet);
dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet);
} else {
Object commonInfo = NetworkReflections.handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
}
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
@@ -1248,10 +1250,10 @@ public class PacketConsumers {
if (BukkitNetworkManager.hasViaVersion()) {
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid()));
}
dimensionKey = NetworkReflections.handle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet);
dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet);
} else {
Object commonInfo = NetworkReflections.handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
}
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
@@ -1295,9 +1297,9 @@ public class PacketConsumers {
Player bukkitPlayer = player.platformPlayer();
if (bukkitPlayer == null) return;
if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return;
int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet);
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.handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet));
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet));
if (ItemUtils.isEmpty(item)) return;
if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) {
return;
@@ -1370,7 +1372,7 @@ public class PacketConsumers {
if (!user.isOnline()) return;
Player player = (Player) user.platformPlayer();
if (player == null) return;
Object pos = NetworkReflections.handle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet);
Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet);
if (VersionHelper.isFolia()) {
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
int z = FastNMS.INSTANCE.field$Vec3i$z(pos);
@@ -1408,7 +1410,7 @@ public class PacketConsumers {
// 1.21.4+
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> PICK_ITEM_FROM_ENTITY = (user, event, packet) -> {
try {
int entityId = (int) NetworkReflections.handle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet);
int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet);
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
if (furniture == null) return;
Player player = (Player) user.platformPlayer();
@@ -1450,11 +1452,11 @@ public class PacketConsumers {
assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null;
if (VersionHelper.isOrAbove1_21_5()) {
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true);
} else {
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
}
}
@@ -1747,14 +1749,14 @@ public class PacketConsumers {
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) {
return;
}
String message = (String) NetworkReflections.handle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet);
String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet);
if (message != null && !message.isEmpty()) {
// check bypass
FontManager manager = CraftEngine.instance().fontManager();
IllegalCharacterProcessResult result = manager.processIllegalCharacters(message);
if (result.has()) {
try {
NetworkReflections.handle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text());
NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text());
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to replace chat", e);
}
@@ -1773,7 +1775,7 @@ public class PacketConsumers {
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) {
return;
}
String[] lines = (String[]) NetworkReflections.handle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet);
String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet);
FontManager manager = CraftEngine.instance().fontManager();
if (!manager.isDefaultFontInUse()) return;
for (int i = 0; i < lines.length; i++) {
@@ -1804,9 +1806,9 @@ public class PacketConsumers {
boolean changed = false;
List<String> pages = (List<String>) NetworkReflections.handleServerboundEditBookPacket$pagesGetter.invokeExact(packet);
List<String> pages = (List<String>) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet);
List<String> newPages = new ArrayList<>(pages.size());
Optional<String> title = (Optional<String>) NetworkReflections.handle$ServerboundEditBookPacket$titleGetter.invokeExact(packet);
Optional<String> title = (Optional<String>) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet);
Optional<String> newTitle;
if (title.isPresent()) {
@@ -1830,7 +1832,7 @@ public class PacketConsumers {
if (changed) {
Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance(
(int) NetworkReflections.handle$ServerboundEditBookPacket$slotGetter.invokeExact(packet),
(int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet),
newPages,
newTitle
);
@@ -1863,7 +1865,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
try {
if (!VersionHelper.isOrAbove1_20_5()) return;
Object payload = NetworkReflections.handle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet);
Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet);
if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) {
Payload discardedPayload = DiscardedPayload.from(payload);
if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY))
@@ -2282,7 +2284,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HANDSHAKE_C2S = (user, event, packet) -> {
try {
if (BukkitNetworkManager.hasViaVersion()) return;
int protocolVersion = (int) NetworkReflections.handle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet);
int protocolVersion = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet);
user.setProtocolVersion(protocolVersion);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e);
@@ -2302,7 +2304,7 @@ public class PacketConsumers {
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.handle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet);
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) {
@@ -2324,9 +2326,9 @@ public class PacketConsumers {
try {
Object player = user.serverPlayer();
if (player == null) return;
int entityId = (int) NetworkReflections.handle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet);
int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet);
if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return;
byte eventId = (byte) NetworkReflections.handle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet);
byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet);
if (eventId >= 24 && eventId <= 28) {
CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid());
}
@@ -2346,4 +2348,16 @@ public class PacketConsumers {
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_ENTITY = (user, event, packet) -> {
try {
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);
EntityPacketHandler handler = user.entityPacketHandlers().get(entityId);
if (handler != null) {
handler.handleMove(user, event, packet);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e);
}
};
}

View File

@@ -0,0 +1,19 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
public class FurnitureCollisionPacketHandler implements EntityPacketHandler {
public static final FurnitureCollisionPacketHandler INSTANCE = new FurnitureCollisionPacketHandler();
@Override
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
@Override
public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
}

View File

@@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import java.util.List;
@@ -17,4 +19,14 @@ public class FurniturePacketHandler implements EntityPacketHandler {
entityIds.addAll(this.fakeEntities);
return true;
}
@Override
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
@Override
public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
}

View File

@@ -5,6 +5,7 @@ import com.google.gson.JsonElement;
import com.mojang.serialization.DynamicOps;
import io.netty.buffer.ByteBuf;
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.ReflectionUtils;
@@ -3274,21 +3275,21 @@ public final class CoreReflections {
)
);
public static final MethodHandle handle$ServerEntity$broadcastSetter;
public static final MethodHandle handle$ServerEntity$updateIntervalSetter;
public static final MethodHandle handle$ServerPlayer$connectionGetter;
public static final MethodHandle methodHandle$ServerEntity$broadcastSetter;
public static final MethodHandle methodHandle$ServerEntity$updateIntervalSetter;
public static final MethodHandle methodHandle$ServerPlayer$connectionGetter;
static {
try {
handle$ServerEntity$broadcastSetter = requireNonNull(
methodHandle$ServerEntity$broadcastSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast)
.asType(MethodType.methodType(void.class, Object.class, Consumer.class))
);
handle$ServerEntity$updateIntervalSetter = requireNonNull(
methodHandle$ServerEntity$updateIntervalSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval)
.asType(MethodType.methodType(void.class, Object.class, int.class))
);
handle$ServerPlayer$connectionGetter = requireNonNull(
methodHandle$ServerPlayer$connectionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerPlayer$connection)
.asType(MethodType.methodType(Object.class, Object.class))
);
@@ -3296,4 +3297,19 @@ public final class CoreReflections {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
public static final Class<?> clazz$BaseFireBlock = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.block.BlockFireAbstract",
"world.level.block.BaseFireBlock"
)
);
public static final Method method$BaseFireBlock$canBePlacedAt = requireNonNull(
ReflectionUtils.getStaticMethod(clazz$BaseFireBlock, boolean.class, clazz$Level, clazz$BlockPos, clazz$Direction)
);
public static final Field field$FireBlock$igniteOdds = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0)
);
}

View File

@@ -1304,165 +1304,165 @@ public final class NetworkReflections {
)
);
public static final MethodHandle handle$ServerboundRenameItemPacket$nameGetter;
public static final MethodHandle handle$ServerboundRenameItemPacket$nameSetter;
public static final MethodHandle handle$ServerboundHelloPacket$nameGetter;
public static final MethodHandle handle$ServerboundHelloPacket$uuidGetter;
public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter;
public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter;
public static final MethodHandle handle$ServerboundInteractPacket$actionGetter;
public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter;
public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter;
public static final MethodHandle handle$ServerboundSignUpdatePacket$linesGetter;
public static final MethodHandle handleServerboundEditBookPacket$pagesGetter;
public static final MethodHandle handle$ServerboundEditBookPacket$titleGetter;
public static final MethodHandle handle$ServerboundEditBookPacket$slotGetter;
public static final MethodHandle handle$ServerboundResourcePackPacket$actionGetter;
public static final MethodHandle handle$ClientboundEntityEventPacket$entityIdGetter;
public static final MethodHandle handle$ClientboundEntityEventPacket$eventIdGetter;
public static final MethodHandle handle$ClientIntentionPacket$protocolVersionGetter;
public static final MethodHandle handle$ClientboundRespawnPacket$dimensionGetter;
public static final MethodHandle handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle handle$CommonPlayerSpawnInfo$dimensionGetter;
public static final MethodHandle handle$ClientboundLoginPacket$dimensionGetter;
public static final MethodHandle handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle handle$ServerboundPickItemFromBlockPacket$posGetter;
public static final MethodHandle handle$ServerboundPickItemFromEntityPacket$idGetter;
public static final MethodHandle handle$ServerboundCustomPayloadPacket$payloadGetter;
public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameGetter;
public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameSetter;
public static final MethodHandle methodHandle$ServerboundHelloPacket$nameGetter;
public static final MethodHandle methodHandle$ServerboundHelloPacket$uuidGetter;
public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter;
public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter;
public static final MethodHandle methodHandle$ServerboundInteractPacket$actionGetter;
public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter;
public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter;
public static final MethodHandle methodHandle$ServerboundSignUpdatePacket$linesGetter;
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;
public static final MethodHandle methodHandle$ClientboundRespawnPacket$dimensionGetter;
public static final MethodHandle methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle methodHandle$CommonPlayerSpawnInfo$dimensionGetter;
public static final MethodHandle methodHandle$ClientboundLoginPacket$dimensionGetter;
public static final MethodHandle methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle methodHandle$ServerboundPickItemFromBlockPacket$posGetter;
public static final MethodHandle methodHandle$ServerboundPickItemFromEntityPacket$idGetter;
public static final MethodHandle methodHandle$ServerboundCustomPayloadPacket$payloadGetter;
static {
try {
handle$ServerboundRenameItemPacket$nameGetter = requireNonNull(
methodHandle$ServerboundRenameItemPacket$nameGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundRenameItemPacket$name)
.asType(MethodType.methodType(String.class, Object.class))
);
handle$ServerboundRenameItemPacket$nameSetter = requireNonNull(
methodHandle$ServerboundRenameItemPacket$nameSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerboundRenameItemPacket$name)
.asType(MethodType.methodType(void.class, Object.class, String.class))
);
handle$ServerboundHelloPacket$nameGetter = requireNonNull(
methodHandle$ServerboundHelloPacket$nameGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$name)
.asType(MethodType.methodType(String.class, Object.class))
);
handle$ServerboundHelloPacket$uuidGetter = requireNonNull(
methodHandle$ServerboundHelloPacket$uuidGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$uuid)
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_2() ? UUID.class : Optional.class, Object.class))
);
handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull(
methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$itemStack)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull(
methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$slotNum)
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_5() ? short.class : int.class, Object.class))
);
handle$ServerboundInteractPacket$actionGetter = requireNonNull(
methodHandle$ServerboundInteractPacket$actionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$action)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull(
methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$hand)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull(
methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$location)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundSignUpdatePacket$linesGetter = requireNonNull(
methodHandle$ServerboundSignUpdatePacket$linesGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSignUpdatePacket$lines)
.asType(MethodType.methodType(String[].class, Object.class))
);
handleServerboundEditBookPacket$pagesGetter = requireNonNull(
methodHandle$ServerboundEditBookPacket$pagesGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$pages)
.asType(MethodType.methodType(List.class, Object.class))
);
handle$ServerboundEditBookPacket$titleGetter = requireNonNull(
methodHandle$ServerboundEditBookPacket$titleGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$title)
.asType(MethodType.methodType(Optional.class, Object.class))
);
handle$ServerboundEditBookPacket$slotGetter = requireNonNull(
methodHandle$ServerboundEditBookPacket$slotGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot)
.asType(MethodType.methodType(int.class, Object.class))
);
handle$ServerboundResourcePackPacket$actionGetter = requireNonNull(
methodHandle$ServerboundResourcePackPacket$actionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull(
methodHandle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId)
.asType(MethodType.methodType(int.class, Object.class))
);
handle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull(
methodHandle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$eventId)
.asType(MethodType.methodType(byte.class, Object.class))
);
handle$ClientIntentionPacket$protocolVersionGetter = requireNonNull(
methodHandle$ClientIntentionPacket$protocolVersionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientIntentionPacket$protocolVersion)
.asType(MethodType.methodType(int.class, Object.class))
);
if (field$ServerboundCustomPayloadPacket$payload != null) {
handle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull(
methodHandle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundCustomPayloadPacket$payload)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ServerboundCustomPayloadPacket$payloadGetter = null;
methodHandle$ServerboundCustomPayloadPacket$payloadGetter = null;
}
if (field$ServerboundPickItemFromEntityPacket$id != null) {
handle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull(
methodHandle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromEntityPacket$id)
.asType(MethodType.methodType(int.class, Object.class))
);
} else {
handle$ServerboundPickItemFromEntityPacket$idGetter = null;
methodHandle$ServerboundPickItemFromEntityPacket$idGetter = null;
}
if (field$ServerboundPickItemFromBlockPacket$pos != null) {
handle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull(
methodHandle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromBlockPacket$pos)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ServerboundPickItemFromBlockPacket$posGetter = null;
methodHandle$ServerboundPickItemFromBlockPacket$posGetter = null;
}
if (field$ClientboundLoginPacket$commonPlayerSpawnInfo != null) {
handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull(
methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$commonPlayerSpawnInfo)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null;
methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null;
}
if (field$ClientboundLoginPacket$dimension != null) {
handle$ClientboundLoginPacket$dimensionGetter = requireNonNull(
methodHandle$ClientboundLoginPacket$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundLoginPacket$dimensionGetter = null;
methodHandle$ClientboundLoginPacket$dimensionGetter = null;
}
if (field$CommonPlayerSpawnInfo$dimension != null) {
handle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull(
methodHandle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$CommonPlayerSpawnInfo$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$CommonPlayerSpawnInfo$dimensionGetter = null;
methodHandle$CommonPlayerSpawnInfo$dimensionGetter = null;
}
if (field$ClientboundRespawnPacket$commonPlayerSpawnInfo != null) {
handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull(
methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$commonPlayerSpawnInfo)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null;
methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null;
}
if (field$ClientboundRespawnPacket$dimension != null) {
handle$ClientboundRespawnPacket$dimensionGetter = requireNonNull(
methodHandle$ClientboundRespawnPacket$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundRespawnPacket$dimensionGetter = null;
methodHandle$ClientboundRespawnPacket$dimensionGetter = null;
}
} catch (Throwable e) {
throw new ReflectionInitException("Failed to initialize reflection", e);

View File

@@ -30,10 +30,12 @@ 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;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Position;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldEvents;
import org.bukkit.*;
@@ -283,8 +285,13 @@ public class BukkitServerPlayer extends Player {
}
@Override
public void playSound(Key sound, float volume, float pitch) {
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundCategory.MASTER, volume, pitch);
public void playSound(Key sound, SoundSource source, float volume, float pitch) {
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
}
@Override
public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) {
platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
}
@Override

View File

@@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.block.*;
@@ -22,18 +24,26 @@ import org.jetbrains.annotations.Nullable;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class BlockStateUtils {
public static final IdentityHashMap<Object, Object> CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>();
private static int vanillaStateSize;
private static boolean hasInit;
public static Map<Object, Integer> IGNITE_ODDS;
@SuppressWarnings("unchecked")
public static void init(int size) {
if (hasInit) {
throw new IllegalStateException("BlockStateUtils has already been initialized");
}
vanillaStateSize = size;
try {
IGNITE_ODDS = (Map<Object, Integer>) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e);
}
hasInit = true;
}
@@ -248,4 +258,9 @@ public class BlockStateUtils {
public static int vanillaStateSize() {
return vanillaStateSize;
}
public static boolean isBurnable(Object state) {
Object blockOwner = getBlockOwner(state);
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;
}
}