mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-04 15:41:38 +00:00
@@ -39,7 +39,6 @@ This project draws inspiration and refers to some implementations from the follo
|
||||
### Core Dependencies
|
||||
The implementation relies on these fundamental libraries:
|
||||
+ [cloud-minecraft](https://github.com/Incendo/cloud-minecraft)
|
||||
+ [rtag](https://github.com/saicone/rtag)
|
||||
+ [adventure](https://github.com/KyoriPowered/adventure)
|
||||
+ [byte-buddy](https://github.com/raphw/byte-buddy)
|
||||
|
||||
@@ -63,7 +62,7 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre
|
||||
### 💖 Support the Developer
|
||||
Help sustain CraftEngine's development by going Premium!
|
||||
|
||||
- **Polymart**: [None]
|
||||
- **Polymart**: [Support via Polymart](https://polymart.org/product/7624/craftengine)
|
||||
- **BuiltByBit**: [None]
|
||||
- **Afdian**: [Support via Afdian](https://afdian.com/@xiaomomi/)
|
||||
|
||||
@@ -76,7 +75,7 @@ repositories {
|
||||
```
|
||||
```kotlin
|
||||
dependencies {
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.57")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.57")
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.59")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.59")
|
||||
}
|
||||
```
|
||||
@@ -46,9 +46,6 @@ dependencies {
|
||||
compileOnly("org.incendo:cloud-paper:${rootProject.properties["cloud_paper_version"]}")
|
||||
// YAML
|
||||
compileOnly(files("${rootProject.rootDir}/libs/boosted-yaml-${rootProject.properties["boosted_yaml_version"]}.jar"))
|
||||
// Item Tag
|
||||
compileOnly("com.saicone.rtag:rtag:${rootProject.properties["rtag_version"]}")
|
||||
compileOnly("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
|
||||
// Adventure
|
||||
compileOnly("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
|
||||
@@ -89,7 +86,6 @@ tasks {
|
||||
relocate("net.kyori", "net.momirealms.craftengine.libraries")
|
||||
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
|
||||
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
|
||||
relocate("com.saicone.rtag", "net.momirealms.craftengine.libraries.tag")
|
||||
relocate("org.incendo", "net.momirealms.craftengine.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
|
||||
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")
|
||||
|
||||
@@ -6,9 +6,9 @@ import ch.njol.skript.classes.Serializer;
|
||||
import ch.njol.skript.lang.ParseContext;
|
||||
import ch.njol.skript.registrations.Classes;
|
||||
import ch.njol.yggdrasil.Fields;
|
||||
import net.momirealms.craftengine.core.block.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.StreamCorruptedException;
|
||||
|
||||
@@ -55,10 +55,9 @@ public class ExprItemCustomItemID extends SimplePropertyExpression<Object, Strin
|
||||
Item<ItemStack> item1 = BukkitItemManager.instance().wrap(itemStack);
|
||||
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
|
||||
item1.merge(item2);
|
||||
item1.load();
|
||||
} else if (item instanceof ItemType itemType) {
|
||||
Item<ItemStack> item2 = BukkitItemManager.instance().createWrappedItem(id, null);
|
||||
itemType.setItemMeta(item2.load().getItemMeta());
|
||||
itemType.setItemMeta(item2.getItem().getItemMeta());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import net.momirealms.craftengine.core.block.AbstractBlockManager;
|
||||
import net.momirealms.craftengine.core.block.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import org.bukkit.Material;
|
||||
|
||||
@@ -21,7 +21,6 @@ dependencies {
|
||||
implementation(project(":bukkit:compatibility:legacy"))
|
||||
implementation(project(":common-files"))
|
||||
|
||||
implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
|
||||
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
|
||||
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
|
||||
implementation("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}")
|
||||
@@ -48,7 +47,7 @@ bukkit {
|
||||
name = "CraftEngine"
|
||||
apiVersion = "1.20"
|
||||
authors = listOf("XiaoMoMi")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon")
|
||||
softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript")
|
||||
foliaSupported = true
|
||||
}
|
||||
@@ -64,7 +63,6 @@ tasks {
|
||||
relocate("net.kyori", "net.momirealms.craftengine.libraries")
|
||||
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
|
||||
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
|
||||
relocate("com.saicone.rtag", "net.momirealms.craftengine.libraries.tag")
|
||||
relocate("org.incendo", "net.momirealms.craftengine.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
|
||||
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")
|
||||
|
||||
@@ -23,7 +23,6 @@ dependencies {
|
||||
implementation(project(":bukkit:compatibility:legacy"))
|
||||
implementation(project(":common-files"))
|
||||
|
||||
implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
|
||||
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
|
||||
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
|
||||
implementation("net.momirealms:craft-engine-nms-helper-mojmap:${rootProject.properties["nms_helper_version"]}")
|
||||
@@ -51,7 +50,7 @@ paper {
|
||||
name = "CraftEngine"
|
||||
apiVersion = "1.20"
|
||||
authors = listOf("XiaoMoMi")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon")
|
||||
foliaSupported = true
|
||||
serverDependencies {
|
||||
register("PlaceholderAPI") {
|
||||
@@ -137,7 +136,6 @@ tasks {
|
||||
relocate("net.kyori", "net.momirealms.craftengine.libraries")
|
||||
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")
|
||||
relocate("net.momirealms.antigrieflib", "net.momirealms.craftengine.libraries.antigrieflib")
|
||||
relocate("com.saicone.rtag", "net.momirealms.craftengine.libraries.tag")
|
||||
relocate("org.incendo", "net.momirealms.craftengine.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.craftengine.libraries")
|
||||
relocate("org.bstats", "net.momirealms.craftengine.libraries.bstats")
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package net.momirealms.craftengine.bukkit.advancement;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.core.advancement.AbstractAdvancementManager;
|
||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.GsonHelper;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@@ -53,9 +51,6 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager {
|
||||
if (advancements.containsKey(id)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.advancement.duplicate", path, id);
|
||||
}
|
||||
JsonElement jsonTree = GsonHelper.get().toJsonTree(section);
|
||||
FastNMS.INSTANCE.registerAdvancement(id.decompose(), jsonTree);
|
||||
advancements.put(id, jsonTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.SoundCategory;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -117,7 +116,7 @@ public final class CraftEngineBlocks {
|
||||
if (success) {
|
||||
FastNMS.INSTANCE.method$BlockStateBase$onPlace(blockState, worldServer, blockPos, oldBlockState, false);
|
||||
if (playSound) {
|
||||
SoundData data = block.sounds().placeSound();
|
||||
SoundData data = block.settings().sounds().placeSound();
|
||||
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get());
|
||||
}
|
||||
}
|
||||
@@ -131,22 +130,20 @@ public final class CraftEngineBlocks {
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Block block) {
|
||||
if (!isCustomBlock(block)) return false;
|
||||
block.setType(Material.AIR, true);
|
||||
return true;
|
||||
return remove(block, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a block from the world if it's custom
|
||||
*
|
||||
* @param block block to remove
|
||||
* @param applyPhysics whether to apply physics
|
||||
* @param isMoving is moving
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Block block,
|
||||
boolean applyPhysics) {
|
||||
boolean isMoving) {
|
||||
if (!isCustomBlock(block)) return false;
|
||||
block.setType(Material.AIR, applyPhysics);
|
||||
FastNMS.INSTANCE.method$Level$removeBlock(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()), isMoving);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -155,15 +152,15 @@ public final class CraftEngineBlocks {
|
||||
*
|
||||
* @param block block to remove
|
||||
* @param player player who breaks the block
|
||||
* @param applyPhysics whether to apply physics
|
||||
* @param dropLoot whether to drop block loots
|
||||
* @param isMoving is moving
|
||||
* @param playSound whether to play break sounds
|
||||
* @param sendParticles whether to send break particles
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Block block,
|
||||
@Nullable Player player,
|
||||
boolean applyPhysics,
|
||||
boolean isMoving,
|
||||
boolean dropLoot,
|
||||
boolean playSound,
|
||||
boolean sendParticles) {
|
||||
@@ -184,12 +181,12 @@ public final class CraftEngineBlocks {
|
||||
}
|
||||
}
|
||||
if (playSound) {
|
||||
world.playBlockSound(position, state.sounds().breakSound());
|
||||
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());
|
||||
}
|
||||
block.setType(Material.AIR, applyPhysics);
|
||||
FastNMS.INSTANCE.method$Level$removeBlock(world.serverWorld(), LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), isMoving);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -200,9 +197,8 @@ public final class CraftEngineBlocks {
|
||||
* @return is custom block or not
|
||||
*/
|
||||
public static boolean isCustomBlock(@NotNull Block block) {
|
||||
BlockData blockData = block.getBlockData();
|
||||
int stateId = BlockStateUtils.blockDataToId(blockData);
|
||||
return !BlockStateUtils.isVanillaBlock(stateId);
|
||||
Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()));
|
||||
return BlockStateUtils.isCustomBlock(state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,9 +209,8 @@ public final class CraftEngineBlocks {
|
||||
*/
|
||||
@Nullable
|
||||
public static ImmutableBlockState getCustomBlockState(@NotNull Block block) {
|
||||
BlockData blockData = block.getBlockData();
|
||||
int stateId = BlockStateUtils.blockDataToId(blockData);
|
||||
return BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()));
|
||||
return BlockStateUtils.getOptionalCustomBlockState(state).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,8 +221,8 @@ public final class CraftEngineBlocks {
|
||||
*/
|
||||
@Nullable
|
||||
public static ImmutableBlockState getCustomBlockState(@NotNull BlockData blockData) {
|
||||
int stateId = BlockStateUtils.blockDataToId(blockData);
|
||||
return BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
Object state = BlockStateUtils.blockDataToBlockState(blockData);
|
||||
return BlockStateUtils.getOptionalCustomBlockState(state).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -24,7 +23,6 @@ import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextPar
|
||||
import net.momirealms.craftengine.core.util.Cancellable;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -34,19 +32,16 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.world.GenericGameEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BlockEventListener implements Listener {
|
||||
public final class BlockEventListener implements Listener {
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final boolean enableNoteBlockCheck;
|
||||
private final BukkitBlockManager manager;
|
||||
@@ -153,7 +148,7 @@ public class BlockEventListener implements Listener {
|
||||
ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId);
|
||||
if (!state.isEmpty()) {
|
||||
// double check adventure mode to prevent dupe
|
||||
if (!FastNMS.INSTANCE.mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) {
|
||||
if (!FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -179,36 +174,8 @@ public class BlockEventListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle waterlogged blocks
|
||||
@SuppressWarnings("unchecked")
|
||||
Property<Boolean> waterloggedProperty = (Property<Boolean>) state.owner().value().getProperty("waterlogged");
|
||||
if (waterloggedProperty != null) {
|
||||
boolean waterlogged = state.get(waterloggedProperty);
|
||||
if (waterlogged) {
|
||||
location.getWorld().setBlockData(location, Material.WATER.createBlockData());
|
||||
}
|
||||
}
|
||||
|
||||
// play sound
|
||||
world.playBlockSound(position, state.sounds().breakSound());
|
||||
if (player.getGameMode() == GameMode.CREATIVE || !customBreakEvent.dropItems()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do not drop if it's not the correct tool
|
||||
if (!BlockStateUtils.isCorrectTool(state, itemInHand)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// drop items
|
||||
ContextHolder.Builder lootContext = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.PLAYER, serverPlayer)
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand);
|
||||
for (Item<Object> item : state.getDrops(lootContext, world, serverPlayer)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, state.settings().sounds().breakSound());
|
||||
}
|
||||
} else {
|
||||
// override vanilla block loots
|
||||
@@ -251,24 +218,10 @@ public class BlockEventListener implements Listener {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onBlockBreakBlock(BlockBreakBlockEvent event) {
|
||||
Block block = event.getBlock();
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
// custom blocks
|
||||
ImmutableBlockState immutableBlockState = this.manager.getImmutableBlockStateUnsafe(stateId);
|
||||
if (!immutableBlockState.isEmpty()) {
|
||||
Location location = block.getLocation();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(block.getWorld());
|
||||
WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5);
|
||||
for (Item<?> item : immutableBlockState.getDrops(ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)), world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()));
|
||||
if (BlockStateUtils.isVanillaBlock(blockState)) {
|
||||
// override vanilla block loots
|
||||
this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> {
|
||||
this.plugin.vanillaLootManager().getBlockLoot(BlockStateUtils.blockStateToId(blockState)).ifPresent(it -> {
|
||||
if (it.override()) {
|
||||
event.getDrops().clear();
|
||||
event.setExpToDrop(0);
|
||||
@@ -295,12 +248,12 @@ public class BlockEventListener implements Listener {
|
||||
if (!(entity instanceof Player player)) return;
|
||||
BlockPos pos = EntityUtils.getOnPos(player);
|
||||
Block block = player.getWorld().getBlockAt(pos.x(), pos.y(), pos.z());
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
Location location = player.getLocation();
|
||||
ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId);
|
||||
Cancellable cancellable = Cancellable.dummy();
|
||||
ImmutableBlockState state = optionalCustomState.get();
|
||||
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
|
||||
state.owner().value().execute(PlayerOptionalContext.of(this.plugin.adapt(player), ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(event.getWorld()), LocationUtils.toVec3d(location)))
|
||||
@@ -308,62 +261,23 @@ public class BlockEventListener implements Listener {
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state)
|
||||
), EventTrigger.STEP);
|
||||
if (cancellable.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
player.playSound(location, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume().get(), state.sounds().stepSound().pitch().get());
|
||||
player.playSound(location, state.settings().sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.settings().sounds().stepSound().volume().get(), state.settings().sounds().stepSound().pitch().get());
|
||||
} else if (Config.enableSoundSystem()) {
|
||||
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
|
||||
if (manager.isBlockSoundRemoved(ownerBlock)) {
|
||||
if (this.manager.isBlockSoundRemoved(ownerBlock)) {
|
||||
try {
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
|
||||
Object stepSound = CoreReflections.field$SoundType$stepSound.get(soundType);
|
||||
player.playSound(player.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(stepSound).toString(), SoundCategory.BLOCKS, 0.15f, 1f);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to get sound type", e);
|
||||
this.plugin.logger().warn("Failed to get sound type", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onEntityExplode(EntityExplodeEvent event) {
|
||||
if (VersionHelper.isOrAbove1_21()) {
|
||||
if (!ExplosionUtils.isDroppingItems(event)) return;
|
||||
}
|
||||
handleExplodeEvent(event.blockList(), new BukkitWorld(event.getEntity().getWorld()), event.getYield());
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onBlockExplode(BlockExplodeEvent event) {
|
||||
if (VersionHelper.isOrAbove1_21()) {
|
||||
if (!ExplosionUtils.isDroppingItems(event)) return;
|
||||
}
|
||||
handleExplodeEvent(event.blockList(), new BukkitWorld(event.getBlock().getWorld()), event.getYield());
|
||||
}
|
||||
|
||||
private void handleExplodeEvent(List<org.bukkit.block.Block> blocks, net.momirealms.craftengine.core.world.World world, float yield) {
|
||||
for (int i = blocks.size() - 1; i >= 0; i--) {
|
||||
Block block = blocks.get(i);
|
||||
Location location = block.getLocation();
|
||||
BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||
ImmutableBlockState state = this.manager.getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData()));
|
||||
if (state != null && !state.isEmpty()) {
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(blockPos));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block));
|
||||
if (yield < 1f) {
|
||||
builder.withParameter(DirectContextParameters.EXPLOSION_RADIUS, 1.0f / yield);
|
||||
}
|
||||
for (Item<Object> item : state.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, state.sounds().breakSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onBlockPhysics(BlockPhysicsEvent event) {
|
||||
if (!this.enableNoteBlockCheck) return;
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
@@ -25,6 +24,8 @@ import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.RegistryUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.TagUtils;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.block.properties.Properties;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
@@ -32,7 +33,6 @@ import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.pack.ResourceLocation;
|
||||
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
@@ -65,7 +65,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BukkitBlockManager extends AbstractBlockManager {
|
||||
public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
private static BukkitBlockManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final BlockParser blockParser;
|
||||
@@ -75,6 +75,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
// Minecraft objects
|
||||
// Cached new blocks $ holders
|
||||
private Map<Key, Integer> internalId2StateId;
|
||||
private Map<Key, DelegatingBlock> registeredBlocks;
|
||||
private Map<Integer, Object> stateId2BlockHolder;
|
||||
// This map is used to change the block states that are not necessarily needed into a certain block state
|
||||
private Map<Integer, Integer> blockAppearanceMapper;
|
||||
@@ -93,7 +94,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private BlockEventListener blockEventListener;
|
||||
private FallingBlockRemoveListener fallingBlockRemoveListener;
|
||||
// cached tag packet
|
||||
protected Object cachedUpdateTagsPacket;
|
||||
Object cachedUpdateTagsPacket;
|
||||
|
||||
private final List<Tuple<Object, Key, Boolean>> blocksToDeceive = new ArrayList<>();
|
||||
|
||||
@@ -144,6 +145,12 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
super.unload();
|
||||
if (EmptyBlock.STATE != null)
|
||||
Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.STATE);
|
||||
for (DelegatingBlock block : this.registeredBlocks.values()) {
|
||||
block.behaviorDelegate().bindValue(EmptyBlockBehavior.INSTANCE);
|
||||
block.shapeDelegate().bindValue(BukkitBlockShape.STONE);
|
||||
DelegatingBlockState state = (DelegatingBlockState) FastNMS.INSTANCE.method$Block$defaultState(block);
|
||||
state.setBlockState(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,7 +208,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Nullable
|
||||
public Object getMinecraftBlockHolder(int stateId) {
|
||||
return stateId2BlockHolder.get(stateId);
|
||||
return this.stateId2BlockHolder.get(stateId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -297,6 +304,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
ImmutableMap.Builder<Key, Integer> builder1 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Integer, Object> builder2 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Key, List<Integer>> builder3 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Key, DelegatingBlock> builder4 = ImmutableMap.builder();
|
||||
Set<Object> affectedBlockSounds = new HashSet<>();
|
||||
Map<Object, Pair<SoundData, SoundData>> affectedDoors = new IdentityHashMap<>();
|
||||
Set<Object> affectedBlocks = new HashSet<>();
|
||||
@@ -306,7 +314,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
int counter = 0;
|
||||
for (Map.Entry<Key, Integer> baseBlockAndItsCount : this.registeredRealBlockSlots.entrySet()) {
|
||||
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, affectedBlockSounds, order);
|
||||
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, builder4, affectedBlockSounds, order);
|
||||
}
|
||||
|
||||
freezeRegistry();
|
||||
@@ -315,12 +323,13 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
this.internalId2StateId = builder1.build();
|
||||
this.stateId2BlockHolder = builder2.build();
|
||||
this.realBlockArranger = builder3.build();
|
||||
this.registeredBlocks = builder4.build();
|
||||
this.blockRegisterOrder = ImmutableList.copyOf(order);
|
||||
|
||||
for (Object block : (Iterable<Object>) MBuiltInRegistries.BLOCK) {
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block);
|
||||
if (affectedBlockSounds.contains(soundType)) {
|
||||
Object state = getOnlyBlockState(block);
|
||||
Object state = FastNMS.INSTANCE.method$Block$defaultState(block);
|
||||
if (BlockStateUtils.isVanillaBlock(state)) {
|
||||
affectedBlocks.add(block);
|
||||
}
|
||||
@@ -420,7 +429,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
// read states
|
||||
Map<String, Property<?>> properties;
|
||||
Map<String, Integer> appearances;
|
||||
Map<String, VariantState> variants;
|
||||
Map<String, BlockStateVariant> variants;
|
||||
|
||||
Map<String, Object> stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true);
|
||||
boolean singleState = !stateSection.containsKey("properties");
|
||||
@@ -435,7 +444,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (internalBlockRegistryId == -1) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(vanillaBlock.type()) - 1));
|
||||
}
|
||||
variants = Map.of("", new VariantState("", settings, internalBlockRegistryId));
|
||||
variants = Map.of("", new BlockStateVariant("", settings, internalBlockRegistryId));
|
||||
} else {
|
||||
// properties
|
||||
properties = getProperties(MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), true));
|
||||
@@ -467,7 +476,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1));
|
||||
}
|
||||
Map<String, Object> anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true);
|
||||
variants.put(variantNBT, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId));
|
||||
variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,6 +553,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return new VanillaBlockState(blockId, propertyNBT, vanillaBlockStateRegistryId);
|
||||
}
|
||||
|
||||
public record VanillaBlockState(Key type, String properties, int registryId) {
|
||||
}
|
||||
|
||||
private JsonObject getVariantModel(Map<String, Object> singleModelMap) {
|
||||
JsonObject json = new JsonObject();
|
||||
String modelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(singleModelMap.get("path"), "warning.config.block.state.model.missing_path");
|
||||
@@ -555,7 +567,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x"));
|
||||
if (singleModelMap.containsKey("y"))
|
||||
json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y"));
|
||||
if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", (boolean) singleModelMap.get("uvlock"));
|
||||
if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(singleModelMap.get("uvlock"), "uvlock"));
|
||||
if (singleModelMap.containsKey("weight"))
|
||||
json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight"));
|
||||
Map<String, Object> generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true);
|
||||
@@ -614,12 +626,16 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (!Files.exists(mappingsFile)) {
|
||||
this.plugin.saveResource("mappings.yml");
|
||||
}
|
||||
Path additionalFile = this.plugin.dataFolderPath().resolve("additional-real-blocks.yml");
|
||||
if (!Files.exists(additionalFile)) {
|
||||
this.plugin.saveResource("additional-real-blocks.yml");
|
||||
}
|
||||
Yaml yaml = new Yaml(new StringKeyConstructor(mappingsFile, new LoaderOptions()));
|
||||
try (InputStream inputStream = Files.newInputStream(mappingsFile)) {
|
||||
Map<String, String> blockStateMappings = loadBlockStateMappings(yaml.load(inputStream));
|
||||
Map<Key, Integer> blockTypeCounter = new LinkedHashMap<>();
|
||||
try (InputStream is = Files.newInputStream(mappingsFile)) {
|
||||
Map<String, String> blockStateMappings = loadBlockStateMappings(yaml.load(is));
|
||||
this.validateBlockStateMappings(mappingsFile, blockStateMappings);
|
||||
Map<Integer, String> stateMap = new Int2ObjectOpenHashMap<>();
|
||||
Map<Key, Integer> blockTypeCounter = new LinkedHashMap<>();
|
||||
Map<Integer, Integer> appearanceMapper = new Int2IntOpenHashMap();
|
||||
Map<Key, List<Integer>> appearanceArranger = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : blockStateMappings.entrySet()) {
|
||||
@@ -628,11 +644,14 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
this.blockAppearanceMapper = ImmutableMap.copyOf(appearanceMapper);
|
||||
this.blockAppearanceArranger = ImmutableMap.copyOf(appearanceArranger);
|
||||
this.plugin.logger().info("Freed " + this.blockAppearanceMapper.size() + " block state appearances.");
|
||||
YamlDocument additionalYaml = Config.instance().loadOrCreateYamlData("additional-real-blocks.yml");
|
||||
this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to init mappings.yml", e);
|
||||
}
|
||||
try (InputStream is = Files.newInputStream(additionalFile)) {
|
||||
this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, yaml.load(is));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to init additional-real-blocks.yml", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void recordVanillaNoteBlocks() {
|
||||
@@ -737,11 +756,11 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedHashMap<Key, Integer> buildRegisteredRealBlockSlots(Map<Key, Integer> counter, YamlDocument additionalYaml) {
|
||||
private LinkedHashMap<Key, Integer> buildRegisteredRealBlockSlots(Map<Key, Integer> counter, Map<String, Object> additionalYaml) {
|
||||
LinkedHashMap<Key, Integer> map = new LinkedHashMap<>();
|
||||
for (Map.Entry<Key, Integer> entry : counter.entrySet()) {
|
||||
String id = entry.getKey().toString();
|
||||
int additionalStates = additionalYaml.getInt(id, 0);
|
||||
int additionalStates = (int) additionalYaml.getOrDefault(id, 0);
|
||||
int internalIds = entry.getValue() + additionalStates;
|
||||
plugin.logger().info("Loaded " + id + " with " + entry.getValue() + " appearances and " + internalIds + " real block states");
|
||||
map.put(entry.getKey(), internalIds);
|
||||
@@ -763,6 +782,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
ImmutableMap.Builder<Key, Integer> builder1,
|
||||
ImmutableMap.Builder<Integer, Object> builder2,
|
||||
ImmutableMap.Builder<Key, List<Integer>> builder3,
|
||||
ImmutableMap.Builder<Key, DelegatingBlock> builder4,
|
||||
Set<Object> affectSoundTypes,
|
||||
List<Key> order) throws Exception {
|
||||
Key clientSideBlockType = blockWithCount.getKey();
|
||||
@@ -792,7 +812,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, newRealBlock);
|
||||
CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of());
|
||||
|
||||
newBlockState = getOnlyBlockState(newRealBlock);
|
||||
newBlockState = FastNMS.INSTANCE.method$Block$defaultState(newRealBlock);
|
||||
CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState);
|
||||
|
||||
if (isNoteBlock) {
|
||||
@@ -803,6 +823,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
builder1.put(realBlockKey, stateId);
|
||||
builder2.put(stateId, blockHolder);
|
||||
builder4.put(realBlockKey, (DelegatingBlock) newRealBlock);
|
||||
stateIds.add(stateId);
|
||||
|
||||
this.blocksToDeceive.add(Tuple.of(newRealBlock, clientSideBlockType, isNoteBlock));
|
||||
@@ -838,13 +859,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return blockProperties;
|
||||
}
|
||||
|
||||
private Object getOnlyBlockState(Object newBlock) throws IllegalAccessException {
|
||||
Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(newBlock);
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableList<Object> states = (ImmutableList<Object>) CoreReflections.field$StateDefinition$states.get(stateDefinition);
|
||||
return states.get(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void deceiveBukkit() {
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package net.momirealms.craftengine.bukkit.block;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.core.block.BlockShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class BukkitBlockShape implements BlockShape {
|
||||
public final class BukkitBlockShape implements BlockShape {
|
||||
public static final BukkitBlockShape STONE = new BukkitBlockShape(MBlocks.STONE$defaultState, null);
|
||||
private final Object rawBlockState;
|
||||
private final Object supportBlockState;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.momirealms.craftengine.bukkit.util.SoundUtils;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviors;
|
||||
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
@@ -28,19 +29,18 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
private static final Object ALWAYS_FALSE = FastNMS.INSTANCE.method$StatePredicate$always(false);
|
||||
private static final Object ALWAYS_TRUE = FastNMS.INSTANCE.method$StatePredicate$always(true);
|
||||
|
||||
protected BukkitCustomBlock(
|
||||
private BukkitCustomBlock(
|
||||
@NotNull Key id,
|
||||
@NotNull Holder.Reference<CustomBlock> holder,
|
||||
@NotNull Map<String, Property<?>> properties,
|
||||
@NotNull Map<String, Integer> appearances,
|
||||
@NotNull Map<String, VariantState> variantMapper,
|
||||
@NotNull Map<String, BlockStateVariant> variantMapper,
|
||||
@NotNull BlockSettings settings,
|
||||
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
|
||||
@Nullable List<Map<String, Object>> behavior,
|
||||
@@ -51,10 +51,10 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
|
||||
@Override
|
||||
protected BlockBehavior setupBehavior(List<Map<String, Object>> behaviorConfig) {
|
||||
if (behaviorConfig.isEmpty()) {
|
||||
if (behaviorConfig == null || behaviorConfig.isEmpty()) {
|
||||
return new EmptyBlockBehavior();
|
||||
} else if (behaviorConfig.size() == 1) {
|
||||
return BlockBehaviors.fromMap(this, behaviorConfig.get(0));
|
||||
return BlockBehaviors.fromMap(this, behaviorConfig.getFirst());
|
||||
} else {
|
||||
List<AbstractBlockBehavior> behaviors = new ArrayList<>();
|
||||
for (Map<String, Object> config : behaviorConfig) {
|
||||
@@ -74,77 +74,49 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
@Override
|
||||
protected void applyPlatformSettings() {
|
||||
try {
|
||||
for (ImmutableBlockState state : variantProvider().states()) {
|
||||
if (state.vanillaBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find vanilla block state for " + state + ". This might cause errors!");
|
||||
for (ImmutableBlockState immutableBlockState : variantProvider().states()) {
|
||||
if (immutableBlockState.vanillaBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find vanilla block immutableBlockState for " + immutableBlockState + ". This might cause errors!");
|
||||
continue;
|
||||
} else if (state.customBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find custom block state for " + state + ". This might cause errors!");
|
||||
} else if (immutableBlockState.customBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find custom block immutableBlockState for " + immutableBlockState + ". This might cause errors!");
|
||||
continue;
|
||||
}
|
||||
Object mcBlockState = state.customBlockState().handle();
|
||||
BlockSettings settings = state.settings();
|
||||
// set block state properties
|
||||
BlockStateUtils.setInstrument(mcBlockState, settings.instrument());
|
||||
BlockStateUtils.setMapColor(mcBlockState, settings.mapColor());
|
||||
BlockStateUtils.setLightEmission(mcBlockState, settings.luminance());
|
||||
BlockStateUtils.setBurnable(mcBlockState, settings.burnable());
|
||||
BlockStateUtils.setHardness(mcBlockState, settings.hardness());
|
||||
BlockStateUtils.setPushReaction(mcBlockState, settings.pushReaction());
|
||||
BlockStateUtils.setReplaceable(mcBlockState, settings.replaceable());
|
||||
boolean canOcclude;
|
||||
if (settings.canOcclude() == Tristate.TRUE) {
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, true);
|
||||
canOcclude = true;
|
||||
} else if (settings.canOcclude() == Tristate.FALSE) {
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, false);
|
||||
canOcclude = false;
|
||||
} else {
|
||||
canOcclude = BlockStateUtils.isOcclude(state.vanillaBlockState().handle());
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, canOcclude);
|
||||
}
|
||||
boolean useShapeForLightOcclusion;
|
||||
if (settings.useShapeForLightOcclusion() == Tristate.TRUE) {
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, true);
|
||||
useShapeForLightOcclusion = true;
|
||||
} else if (settings.useShapeForLightOcclusion() == Tristate.FALSE) {
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, false);
|
||||
useShapeForLightOcclusion = false;
|
||||
} else {
|
||||
useShapeForLightOcclusion = CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(state.vanillaBlockState().handle());
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, useShapeForLightOcclusion);
|
||||
}
|
||||
if (settings.isRedstoneConductor() == Tristate.TRUE) {
|
||||
BlockStateUtils.setIsRedstoneConductor(mcBlockState, ALWAYS_TRUE);
|
||||
} else if (settings.isRedstoneConductor() == Tristate.FALSE) {
|
||||
BlockStateUtils.setIsRedstoneConductor(mcBlockState, ALWAYS_FALSE);
|
||||
}
|
||||
if (settings.isSuffocating() == Tristate.TRUE) {
|
||||
BlockStateUtils.setIsSuffocating(mcBlockState, ALWAYS_TRUE);
|
||||
} else if (settings.isSuffocating() == Tristate.FALSE) {
|
||||
BlockStateUtils.setIsSuffocating(mcBlockState, ALWAYS_FALSE);
|
||||
}
|
||||
if (settings.isViewBlocking() == Tristate.TRUE) {
|
||||
BlockStateUtils.setIsViewBlocking(mcBlockState, ALWAYS_TRUE);
|
||||
} else if (settings.isViewBlocking() == Tristate.FALSE) {
|
||||
BlockStateUtils.setIsViewBlocking(mcBlockState, ALWAYS_FALSE);
|
||||
} else {
|
||||
if (settings.isSuffocating() == Tristate.TRUE) {
|
||||
BlockStateUtils.setIsViewBlocking(mcBlockState, ALWAYS_TRUE);
|
||||
} else if (settings.isSuffocating() == Tristate.FALSE) {
|
||||
BlockStateUtils.setIsViewBlocking(mcBlockState, ALWAYS_FALSE);
|
||||
}
|
||||
}
|
||||
DelegatingBlockState nmsState = (DelegatingBlockState) immutableBlockState.customBlockState().handle();
|
||||
nmsState.setBlockState(immutableBlockState);
|
||||
BlockSettings settings = immutableBlockState.settings();
|
||||
|
||||
// set block properties
|
||||
CoreReflections.field$BlockStateBase$lightEmission.set(nmsState, settings.luminance());
|
||||
CoreReflections.field$BlockStateBase$burnable.set(nmsState, settings.burnable());
|
||||
CoreReflections.field$BlockStateBase$hardness.set(nmsState, settings.hardness());
|
||||
CoreReflections.field$BlockStateBase$replaceable.set(nmsState, settings.replaceable());
|
||||
Object mcMapColor = CoreReflections.method$MapColor$byId.invoke(null, settings.mapColor().id);
|
||||
CoreReflections.field$BlockStateBase$mapColor.set(nmsState, mcMapColor);
|
||||
Object mcInstrument = ((Object[]) CoreReflections.method$NoteBlockInstrument$values.invoke(null))[settings.instrument().ordinal()];
|
||||
CoreReflections.field$BlockStateBase$instrument.set(nmsState, mcInstrument);
|
||||
Object pushReaction = ((Object[]) CoreReflections.method$PushReaction$values.invoke(null))[settings.pushReaction().ordinal()];
|
||||
CoreReflections.field$BlockStateBase$pushReaction.set(nmsState, pushReaction);
|
||||
|
||||
boolean canOcclude = settings.canOcclude() == Tristate.UNDEFINED ? BlockStateUtils.isOcclude(immutableBlockState.vanillaBlockState().handle()) : settings.canOcclude().asBoolean();
|
||||
CoreReflections.field$BlockStateBase$canOcclude.set(nmsState, canOcclude);
|
||||
|
||||
boolean useShapeForLightOcclusion = settings.useShapeForLightOcclusion() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(immutableBlockState.vanillaBlockState().handle()) : settings.useShapeForLightOcclusion().asBoolean();
|
||||
CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(nmsState, useShapeForLightOcclusion);
|
||||
|
||||
CoreReflections.field$BlockStateBase$isRedstoneConductor.set(nmsState, settings.isRedstoneConductor().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE);
|
||||
CoreReflections.field$BlockStateBase$isSuffocating.set(nmsState, settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE);
|
||||
CoreReflections.field$BlockStateBase$isViewBlocking.set(nmsState, settings.isViewBlocking() == Tristate.UNDEFINED ? settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE : (settings.isViewBlocking().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE));
|
||||
|
||||
// set parent block properties
|
||||
Object mcBlock = BlockStateUtils.getBlockOwner(mcBlockState);
|
||||
// bind shape
|
||||
Field shapeField = mcBlock.getClass().getField("shapeHolder");
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectHolder<BukkitBlockShape> shapeHolder = (ObjectHolder<BukkitBlockShape>) shapeField.get(mcBlock);
|
||||
shapeHolder.bindValue(new BukkitBlockShape(state.vanillaBlockState().handle(), Optional.ofNullable(state.settings().supportShapeBlockState()).map(it -> {
|
||||
DelegatingBlock nmsBlock = (DelegatingBlock) BlockStateUtils.getBlockOwner(nmsState);
|
||||
ObjectHolder<BlockShape> shapeHolder = nmsBlock.shapeDelegate();
|
||||
shapeHolder.bindValue(new BukkitBlockShape(immutableBlockState.vanillaBlockState().handle(), Optional.ofNullable(immutableBlockState.settings().supportShapeBlockState()).map(it -> {
|
||||
try {
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(it));
|
||||
if (!BlockStateUtils.isVanillaBlock(blockState)) return null;
|
||||
if (!BlockStateUtils.isVanillaBlock(blockState)) {
|
||||
throw new IllegalArgumentException("BlockState is not a Vanilla block");
|
||||
}
|
||||
return blockState;
|
||||
} catch (IllegalArgumentException e) {
|
||||
CraftEngine.instance().logger().warn("Illegal shape block state: " + it, e);
|
||||
@@ -152,36 +124,34 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
}
|
||||
}).orElse(null)));
|
||||
// bind behavior
|
||||
Field behaviorField = mcBlock.getClass().getField("behaviorHolder");
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectHolder<BlockBehavior> behaviorHolder = (ObjectHolder<BlockBehavior>) behaviorField.get(mcBlock);
|
||||
ObjectHolder<BlockBehavior> behaviorHolder = nmsBlock.behaviorDelegate();
|
||||
behaviorHolder.bindValue(super.behavior);
|
||||
// set block side properties
|
||||
CoreReflections.field$BlockBehaviour$explosionResistance.set(mcBlock, settings.resistance());
|
||||
CoreReflections.field$BlockBehaviour$soundType.set(mcBlock, SoundUtils.toSoundType(settings.sounds()));
|
||||
CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance());
|
||||
CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds()));
|
||||
// 1.21.2以前要在init cache之前设定 isConditionallyFullOpaque
|
||||
if (!VersionHelper.isOrAbove1_21_2()) {
|
||||
boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion;
|
||||
CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(mcBlockState, isConditionallyFullOpaque);
|
||||
CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque);
|
||||
}
|
||||
// init cache
|
||||
CoreReflections.method$BlockStateBase$initCache.invoke(mcBlockState);
|
||||
CoreReflections.method$BlockStateBase$initCache.invoke(nmsState);
|
||||
// modify cache
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(state.vanillaBlockState().handle());
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(immutableBlockState.vanillaBlockState().handle());
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, blockLight);
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(nmsState, blockLight);
|
||||
// set propagates skylight
|
||||
if (settings.propagatesSkylightDown() == Tristate.TRUE) {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, true);
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, true);
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, false);
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(state.vanillaBlockState().handle()));
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(immutableBlockState.vanillaBlockState().handle()));
|
||||
}
|
||||
} else {
|
||||
Object cache = CoreReflections.field$BlockStateBase$cache.get(mcBlockState);
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(state.vanillaBlockState().handle()));
|
||||
Object cache = CoreReflections.field$BlockStateBase$cache.get(nmsState);
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle()));
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight);
|
||||
// set propagates skylight
|
||||
@@ -190,19 +160,19 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(state.vanillaBlockState().handle())));
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle())));
|
||||
}
|
||||
}
|
||||
// set fluid later
|
||||
if (settings.fluidState()) {
|
||||
CoreReflections.field$BlockStateBase$fluidState.set(mcBlockState, CoreReflections.method$FlowingFluid$getSource.invoke(MFluids.WATER, false));
|
||||
CoreReflections.field$BlockStateBase$fluidState.set(nmsState, CoreReflections.method$FlowingFluid$getSource.invoke(MFluids.WATER, false));
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$fluidState.set(mcBlockState, MFluids.EMPTY$defaultState);
|
||||
CoreReflections.field$BlockStateBase$fluidState.set(nmsState, MFluids.EMPTY$defaultState);
|
||||
}
|
||||
// set random tick later
|
||||
BlockStateUtils.setIsRandomlyTicking(mcBlockState, settings.isRandomlyTicking());
|
||||
CoreReflections.field$BlockStateBase$isRandomlyTicking.set(nmsState, settings.isRandomlyTicking());
|
||||
// bind tags
|
||||
Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId());
|
||||
Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(immutableBlockState.customBlockState().registryId());
|
||||
Set<Object> tags = new HashSet<>();
|
||||
for (Key tag : settings.tags()) {
|
||||
tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(tag)));
|
||||
@@ -210,9 +180,8 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
CoreReflections.field$Holder$Reference$tags.set(holder, tags);
|
||||
// set burning properties
|
||||
if (settings.burnable()) {
|
||||
CoreReflections.method$FireBlock$setFlammable.invoke(MBlocks.FIRE, mcBlock, settings.burnChance(), settings.fireSpreadChance());
|
||||
CoreReflections.method$FireBlock$setFlammable.invoke(MBlocks.FIRE, nmsBlock, settings.burnChance(), settings.fireSpreadChance());
|
||||
}
|
||||
CoreReflections.field$BlockStateBase$requiresCorrectToolForDrops.set(mcBlockState, settings.requireCorrectTool());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to init block settings", e);
|
||||
@@ -227,7 +196,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
protected final Key id;
|
||||
protected Map<String, Property<?>> properties;
|
||||
protected Map<String, Integer> appearances;
|
||||
protected Map<String, VariantState> variantMapper;
|
||||
protected Map<String, BlockStateVariant> variantMapper;
|
||||
protected BlockSettings settings;
|
||||
protected List<Map<String, Object>> behavior;
|
||||
protected LootTable<?> lootTable;
|
||||
@@ -274,7 +243,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder variantMapper(Map<String, VariantState> variantMapper) {
|
||||
public Builder variantMapper(Map<String, BlockStateVariant> variantMapper) {
|
||||
this.variantMapper = variantMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@ import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class FallingBlockRemoveListener implements Listener {
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public final class FallingBlockRemoveListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onFallingBlockBreak(org.bukkit.event.entity.EntityRemoveEvent event) {
|
||||
@@ -24,21 +27,21 @@ public class FallingBlockRemoveListener implements Listener {
|
||||
boolean cancelDrop = (boolean) CoreReflections.field$FallingBlockEntity$cancelDrop.get(fallingBlockEntity);
|
||||
if (cancelDrop) return;
|
||||
Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity);
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(fallingBlock.getWorld());
|
||||
WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FALLING_BLOCK, true)
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
for (Item<Object> item : customState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity);
|
||||
boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT);
|
||||
if (!isSilent) {
|
||||
world.playBlockSound(position, immutableBlockState.sounds().destroySound());
|
||||
world.playBlockSound(position, customState.settings().sounds().destroySound());
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle EntityRemoveEvent", e);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
@@ -8,15 +7,12 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavior {
|
||||
@@ -34,21 +30,14 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
if (!canSurvive(thisBlock, args, () -> true)) {
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (currentState != null && !currentState.isEmpty() && currentState.owner().value() == this.customBlock) {
|
||||
// break the crop
|
||||
FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false);
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : currentState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> {
|
||||
if (!customState.isEmpty() && customState.owner().value() == this.customBlock) {
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)));
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$destroyBlock(level, blockPos, true);
|
||||
}
|
||||
world.playBlockSound(position, currentState.sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,19 +58,11 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level;
|
||||
Object blockPos;
|
||||
Object level = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Object state = args[0];
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
int stateId = BlockStateUtils.blockStateToId(state);
|
||||
ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (previousState == null || previousState.isEmpty()) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return state;
|
||||
}
|
||||
if (this.delay != 0) {
|
||||
@@ -90,15 +71,11 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
}
|
||||
if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) {
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : previousState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, previousState.sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.MFluids;
|
||||
@@ -96,9 +95,9 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
@Override
|
||||
public Object mirror(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
if (this.mirrorFunction != null) {
|
||||
int id = BlockStateUtils.blockStateToId(args[0]);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(id);
|
||||
return this.mirrorFunction.mirror(thisBlock, state, MirrorUtils.fromNMSMirror(args[1]));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
|
||||
if (optionalCustomState.isEmpty()) return args[0];
|
||||
return this.mirrorFunction.mirror(thisBlock, optionalCustomState.get(), MirrorUtils.fromNMSMirror(args[1]));
|
||||
}
|
||||
return super.mirror(thisBlock, args, superMethod);
|
||||
}
|
||||
@@ -106,9 +105,9 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
@Override
|
||||
public Object rotate(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
if (this.rotateFunction != null) {
|
||||
int id = BlockStateUtils.blockStateToId(args[0]);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(id);
|
||||
return this.rotateFunction.rotate(thisBlock, state, RotationUtils.fromNMSRotation(args[1]));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
|
||||
if (optionalCustomState.isEmpty()) return args[0];
|
||||
return this.rotateFunction.rotate(thisBlock, optionalCustomState.get(), RotationUtils.fromNMSRotation(args[1]));
|
||||
}
|
||||
return super.rotate(thisBlock, args, superMethod);
|
||||
}
|
||||
@@ -135,12 +134,12 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
Object blockState = args[pickupBlock$blockState];
|
||||
Object world = args[pickupBlock$world];
|
||||
Object pos = args[pickupBlock$pos];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState != null) {
|
||||
if (immutableBlockState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().handle(), 3);
|
||||
return FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1);
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return CoreReflections.instance$ItemStack$EMPTY;
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
if (immutableBlockState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().handle(), 3);
|
||||
return FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1);
|
||||
}
|
||||
return CoreReflections.instance$ItemStack$EMPTY;
|
||||
}
|
||||
@@ -149,14 +148,14 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.waterloggedProperty == null) return false;
|
||||
Object blockState = args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState != null) {
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -168,4 +167,9 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
if (this.waterloggedProperty == null) return false;
|
||||
return args[canPlaceLiquid$liquid] == MFluids.WATER;
|
||||
}
|
||||
|
||||
protected static final int updateShape$level = VersionHelper.isOrAbove1_21_2() ? 1 : 3;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.core.block.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviors;
|
||||
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
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.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockTags;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
@@ -42,9 +40,9 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, false);
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false);
|
||||
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
|
||||
return new BushBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right());
|
||||
}
|
||||
}
|
||||
@@ -75,6 +73,7 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
return new Tuple<>(mcTags, mcBlocks, customBlocks);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception {
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
|
||||
@@ -85,29 +84,27 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
return mayPlaceOn(belowState, world, belowPos);
|
||||
}
|
||||
|
||||
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException {
|
||||
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) {
|
||||
for (Object tag : this.tagsCanSurviveOn) {
|
||||
if ((boolean) CoreReflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) {
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$is(belowState, tag)) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
}
|
||||
int id = BlockStateUtils.blockStateToId(belowState);
|
||||
if (BlockStateUtils.isVanillaBlock(id)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
if (!this.blockStatesCanSurviveOn.isEmpty() && this.blockStatesCanSurviveOn.contains(belowState)) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
} else {
|
||||
ImmutableBlockState belowCustomState = BukkitBlockManager.instance().getImmutableBlockState(id);
|
||||
if (belowCustomState != null && !belowCustomState.isEmpty()) {
|
||||
if (belowCustomState.owner().value() == super.customBlock) {
|
||||
return this.stackable;
|
||||
}
|
||||
if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
ImmutableBlockState belowCustomState = optionalCustomState.get();
|
||||
if (belowCustomState.owner().value() == super.customBlock) {
|
||||
return this.stackable;
|
||||
}
|
||||
if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) {
|
||||
return !this.blacklistMode;
|
||||
}
|
||||
}
|
||||
return this.blacklistMode;
|
||||
|
||||
@@ -16,7 +16,6 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
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 org.bukkit.block.BlockState;
|
||||
import org.bukkit.event.block.BlockFormEvent;
|
||||
|
||||
@@ -94,17 +93,11 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level;
|
||||
Object pos;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
pos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
pos = args[4];
|
||||
}
|
||||
Object level = args[updateShape$level];
|
||||
Object pos = args[updateShape$blockPos];
|
||||
if (touchesLiquid(level, pos)) {
|
||||
if (!CoreReflections.clazz$Level.isInstance(level)) {
|
||||
return getDefaultBlockState();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.util.BlockStateUtils;
|
||||
@@ -18,7 +17,6 @@ import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
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.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.SimpleContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
|
||||
@@ -33,8 +31,10 @@ import org.bukkit.World;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final IntegerProperty ageProperty;
|
||||
@@ -90,13 +90,12 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
Object level = args[1];
|
||||
Object pos = args[2];
|
||||
if (getRawBrightness(level, pos) >= this.minGrowLight) {
|
||||
ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (currentState != null && !currentState.isEmpty()) {
|
||||
int age = this.getAge(currentState);
|
||||
BlockStateUtils.getOptionalCustomBlockState(state).ifPresent(customState -> {
|
||||
int age = this.getAge(customState);
|
||||
if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,12 +115,8 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) {
|
||||
if (!this.isBoneMealTarget) return false;
|
||||
Object state = args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState != null && !immutableBlockState.isEmpty()) {
|
||||
return getAge(immutableBlockState) != this.ageProperty.max;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
return optionalState.filter(immutableBlockState -> getAge(immutableBlockState) != this.ageProperty.max).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,20 +132,15 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
if (isMaxAge(state))
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
try {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} else {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e);
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
sendSwing = true;
|
||||
}
|
||||
if (sendSwing) {
|
||||
context.getPlayer().swingHand(context.getHand());
|
||||
@@ -158,14 +148,15 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private void performBoneMeal(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
private void performBoneMeal(Object level, Object pos, Object state) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
boolean sendParticles = false;
|
||||
Object visualState = immutableBlockState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, pos, visualState);
|
||||
if (!is) {
|
||||
@@ -174,24 +165,21 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
} else {
|
||||
sendParticles = true;
|
||||
}
|
||||
|
||||
World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(pos);
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(pos);
|
||||
int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt(
|
||||
SimpleContext.of(
|
||||
ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
|
||||
int i = this.getAge(customState) + this.boneMealBonus.getInt(
|
||||
SimpleContext.of(ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, customState)
|
||||
.withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(world), Vec3d.atCenterOf(new Vec3i(x, y, z))))
|
||||
.build()
|
||||
)
|
||||
.build())
|
||||
);
|
||||
int maxAge = this.ageProperty.max;
|
||||
if (i > maxAge) {
|
||||
i = maxAge;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
if (sendParticles) {
|
||||
world.spawnParticle(ParticleUtils.HAPPY_VILLAGER, x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25);
|
||||
}
|
||||
@@ -205,7 +193,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
Property<Integer> ageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.crop.missing_age");
|
||||
int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement");
|
||||
float growSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.125f), "grow-speed");
|
||||
boolean isBoneMealTarget = (boolean) arguments.getOrDefault("is-bone-meal-target", true);
|
||||
boolean isBoneMealTarget = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("is-bone-meal-target", true), "is-bone-meal-target");
|
||||
NumberProvider boneMealAgeBonus = NumberProviders.fromObject(arguments.getOrDefault("bone-meal-age-bonus", 1));
|
||||
return new CropBlockBehavior(block, ageProperty, growSpeed, minGrowLight, isBoneMealTarget, boneMealAgeBonus);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -18,11 +17,8 @@ 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.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.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
@@ -43,6 +39,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<DoubleBlockHalf> halfProperty;
|
||||
@@ -83,26 +80,22 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level;
|
||||
Object blockPos;
|
||||
Object level = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Object blockState = args[0];
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return blockState;
|
||||
}
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
DoubleBlockHalf half = immutableBlockState.get(this.halfProperty);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
DoubleBlockHalf half = customState.get(this.halfProperty);
|
||||
Object direction = VersionHelper.isOrAbove1_21_2() ? args[4] : args[1];
|
||||
if (DirectionUtils.isYAxis(direction) && half == DoubleBlockHalf.LOWER == (direction == CoreReflections.instance$Direction$UP)) {
|
||||
ImmutableBlockState neighborState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(VersionHelper.isOrAbove1_21_2() ? args[6] : args[2]));
|
||||
if (neighborState == null || neighborState.isEmpty()) {
|
||||
Optional<ImmutableBlockState> optionalNeighborState = BlockStateUtils.getOptionalCustomBlockState(args[updateShape$neighborState]);
|
||||
if (optionalNeighborState.isEmpty()) {
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
ImmutableBlockState neighborState = optionalNeighborState.get();
|
||||
Optional<DoorBlockBehavior> anotherDoorBehavior = neighborState.behavior().getAs(DoorBlockBehavior.class);
|
||||
if (anotherDoorBehavior.isEmpty()) {
|
||||
return MBlocks.AIR$defaultState;
|
||||
@@ -117,13 +110,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
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));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, immutableBlockState.sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return blockState;
|
||||
@@ -133,8 +121,9 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState state = optionalCustomState.get();
|
||||
if (state.get(this.poweredProperty)) return;
|
||||
if (state.get(this.halfProperty) == DoubleBlockHalf.LOWER) {
|
||||
this.setOpen(null, args[1], state, LocationUtils.fromBlockPos(args[2]), !this.isOpen(state));
|
||||
@@ -206,15 +195,13 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
}
|
||||
|
||||
private boolean isAnotherDoor(Object blockState) {
|
||||
int id = BlockStateUtils.blockStateToId(blockState);
|
||||
if (BlockStateUtils.isVanillaBlock(id)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
BlockData blockData = BlockStateUtils.fromBlockData(blockState);
|
||||
return blockData instanceof Door door && door.getHalf() == Bisected.Half.BOTTOM;
|
||||
} else {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
|
||||
if (state.isEmpty()) return false;
|
||||
Optional<DoorBlockBehavior> optional = state.behavior().getAs(DoorBlockBehavior.class);
|
||||
return optional.isPresent() && state.get(optional.get().halfProperty) == DoubleBlockHalf.LOWER;
|
||||
Optional<DoorBlockBehavior> optional = optionalCustomState.get().behavior().getAs(DoorBlockBehavior.class);
|
||||
return optional.isPresent() && optionalCustomState.get().get(optional.get().halfProperty) == DoubleBlockHalf.LOWER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +221,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
@@ -246,10 +233,10 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
|
||||
return state.get(this.openProperty);
|
||||
return optionalCustomState.get().get(this.openProperty);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -260,18 +247,19 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
Object blockPos = args[2];
|
||||
Object level = args[1];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Object anotherHalfPos = immutableBlockState.get(this.halfProperty) == DoubleBlockHalf.LOWER ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Object anotherHalfPos = customState.get(this.halfProperty) == DoubleBlockHalf.LOWER ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos);
|
||||
Block bukkitBlock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
|
||||
Block anotherBukkitBlock = FastNMS.INSTANCE.method$CraftBlock$at(level, anotherHalfPos);
|
||||
int power = Math.max(bukkitBlock.getBlockPower(), anotherBukkitBlock.getBlockPower());
|
||||
int oldPower = immutableBlockState.get(this.poweredProperty) ? 15 : 0;
|
||||
int oldPower = customState.get(this.poweredProperty) ? 15 : 0;
|
||||
if (oldPower == 0 ^ power == 0) {
|
||||
BlockRedstoneEvent event = new BlockRedstoneEvent(bukkitBlock, oldPower, power);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
boolean flag = event.getNewCurrent() > 0;
|
||||
if (flag != immutableBlockState.get(this.openProperty)) {
|
||||
if (flag != customState.get(this.openProperty)) {
|
||||
org.bukkit.World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
|
||||
world.sendGameEvent(null, flag ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()));
|
||||
SoundData soundData = flag ? this.openSound : this.closeSound;
|
||||
@@ -282,25 +270,24 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
);
|
||||
}
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception {
|
||||
ImmutableBlockState customBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (customBlockState == null || customBlockState.isEmpty()) return false;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos) - 1;
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos);
|
||||
Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos);
|
||||
if (customBlockState.get(this.halfProperty) == DoubleBlockHalf.UPPER) {
|
||||
ImmutableBlockState belowCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(belowState));
|
||||
if (belowCustomState == null || belowCustomState.isEmpty()) return false;
|
||||
return belowCustomState.owner().value() == super.customBlock;
|
||||
if (optionalCustomState.get().get(this.halfProperty) == DoubleBlockHalf.UPPER) {
|
||||
Optional<ImmutableBlockState> belowCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
return belowCustomState.filter(immutableBlockState -> immutableBlockState.owner().value() == super.customBlock).isPresent();
|
||||
} else {
|
||||
return (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(
|
||||
belowState, world, belowPos, CoreReflections.instance$Direction$UP,
|
||||
CoreReflections.instance$SupportType$FULL
|
||||
);
|
||||
@@ -316,8 +303,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
Property<DoorHinge> hinge = (Property<DoorHinge>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("hinge"), "warning.config.block.behavior.door.missing_hinge");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.door.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.door.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
@@ -41,15 +42,8 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object world;
|
||||
Object blockPos;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
world = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
world = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
Object world = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);
|
||||
return args[0];
|
||||
}
|
||||
@@ -79,6 +73,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception {
|
||||
// Use EntityRemoveEvent for 1.20.3+
|
||||
@@ -88,21 +83,21 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
boolean cancelDrop = (boolean) CoreReflections.field$FallingBlockEntity$cancelDrop.get(fallingBlockEntity);
|
||||
if (cancelDrop) return;
|
||||
Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity);
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FALLING_BLOCK, true)
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
for (Item<Object> item : customState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity);
|
||||
boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT);
|
||||
if (!isSilent) {
|
||||
world.playBlockSound(position, immutableBlockState.sounds().destroySound());
|
||||
world.playBlockSound(position, customState.settings().sounds().destroySound());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +114,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
if (!isSilent) {
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.sounds().landSound());
|
||||
world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.settings().sounds().landSound());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
@@ -43,6 +42,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
@@ -83,7 +83,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
|
||||
public boolean isWall(Object state) {
|
||||
if (state == null) return false;
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isTagKeyBlock(state, MTagKeys.Block$WALLS);
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$is(state, MTagKeys.Block$WALLS);
|
||||
}
|
||||
|
||||
private Object getBlockState(Object level, BlockPos blockPos) {
|
||||
@@ -93,14 +93,15 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return blockState;
|
||||
if (state.get(this.facingProperty).toDirection().clockWise().axis() != direction.axis()) {
|
||||
Direction direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return blockState;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
if (customState.get(this.facingProperty).toDirection().clockWise().axis() != direction.axis()) {
|
||||
return superMethod.call();
|
||||
}
|
||||
Object neighborState = VersionHelper.isOrAbove1_21_2() ? args[6] : args[2];
|
||||
Object level = VersionHelper.isOrAbove1_21_2() ? args[1] : args[3];
|
||||
Object neighborState = args[updateShape$neighborState];
|
||||
Object level = args[updateShape$level];
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(VersionHelper.isOrAbove1_21_2() ? args[3] : args[4]);
|
||||
Object relativeState = getBlockState(level, blockPos.relative(direction.opposite()));
|
||||
boolean neighborStateIsWall = this.isWall(neighborState);
|
||||
@@ -112,7 +113,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
if (relativeStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
return state.with(this.inWallProperty, flag).customBlockState().handle();
|
||||
return customState.with(this.inWallProperty, flag).customBlockState().handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,19 +136,12 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
if (context.getItem() == null) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS;
|
||||
} else if (!context.getPlayer().isSecondaryUseActive()) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
} else {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -163,10 +157,10 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
|
||||
return isOpen(state);
|
||||
return isOpen(optionalCustomState.get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -174,9 +168,9 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
this.toggle(state, new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
this.toggle(optionalCustomState.get(), new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,16 +178,17 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, blockPos);
|
||||
if (hasSignal == immutableBlockState.get(this.poweredProperty)) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
if (hasSignal == customState.get(this.poweredProperty)) return;
|
||||
|
||||
Block bblock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
|
||||
int power = bblock.getBlockPower();
|
||||
int oldPower = isOpen(immutableBlockState) ? 15 : 0;
|
||||
int oldPower = isOpen(customState) ? 15 : 0;
|
||||
Object neighborBlock = args[3];
|
||||
|
||||
if (oldPower == 0 ^ power == 0 || FastNMS.INSTANCE.method$BlockStateBase$isSignalSource(FastNMS.INSTANCE.method$Block$defaultState(neighborBlock))) {
|
||||
@@ -203,7 +198,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
boolean changed = isOpen(immutableBlockState) != hasSignal;
|
||||
boolean changed = isOpen(customState) != hasSignal;
|
||||
if (hasSignal && changed) {
|
||||
Object abovePos = LocationUtils.above(blockPos);
|
||||
Object aboveBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, abovePos);
|
||||
@@ -220,7 +215,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
immutableBlockState = immutableBlockState.with(this.openProperty, hasSignal);
|
||||
customState = customState.with(this.openProperty, hasSignal);
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null,
|
||||
hasSignal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos), FastNMS.INSTANCE.field$Vec3i$z(blockPos))
|
||||
@@ -228,8 +223,9 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
|
||||
private void toggle(ImmutableBlockState state, World world, BlockPos pos, @Nullable Player player) {
|
||||
ImmutableBlockState newState;
|
||||
if (state.get(this.openProperty)) {
|
||||
@@ -275,8 +271,8 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
Property<Boolean> inWall = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("in_wall"), "warning.config.block.behavior.fence_gate.missing_in_wall");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.fence_gate.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.fence_gate.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
|
||||
@@ -1,9 +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.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.FeatureUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
@@ -16,38 +18,49 @@ 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.VersionHelper;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Key feature;
|
||||
|
||||
public GrassBlockBehavior(CustomBlock block) {
|
||||
public GrassBlockBehavior(CustomBlock block, Key feature) {
|
||||
super(block);
|
||||
this.feature = feature;
|
||||
}
|
||||
|
||||
public Key boneMealFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) {
|
||||
return FastNMS.INSTANCE.method$GrassBlock$isValidBonemealTarget(args[0], args[1], args[2]);
|
||||
Object above = LocationUtils.above(args[1]);
|
||||
Object aboveState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[0], above);
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isAir(aboveState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception {
|
||||
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) {
|
||||
if (!VersionHelper.isOrAbove1_20_2()) return true;
|
||||
Object level = args[0];
|
||||
Object blockPos = args[2];
|
||||
Object blockState = args[3];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean sendParticles = false;
|
||||
Object visualState = immutableBlockState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, blockPos, visualState);
|
||||
if (!is) {
|
||||
@@ -78,20 +91,15 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
if (!block.isEmpty())
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
try {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} else {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e);
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
sendSwing = true;
|
||||
}
|
||||
if (sendSwing) {
|
||||
context.getPlayer().swingHand(context.getHand());
|
||||
@@ -99,15 +107,58 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void performBoneMeal(Object thisBlock, Object[] args) {
|
||||
FastNMS.INSTANCE.method$GrassBlock$performBoneMeal(args[0], args[1], args[2], args[3], thisBlock);
|
||||
public void performBoneMeal(Object thisBlock, Object[] args) throws Exception {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE);
|
||||
if (registry == null) return;
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature()));
|
||||
if (holder.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("Placed feature not found: " + boneMealFeature());
|
||||
return;
|
||||
}
|
||||
BlockPos grassPos = LocationUtils.fromBlockPos(args[2]);
|
||||
Object world = args[0];
|
||||
Object random = args[1];
|
||||
BlockPos topPos = grassPos.above();
|
||||
out:
|
||||
for (int i = 0; i < 128; i++) {
|
||||
BlockPos currentPos = topPos;
|
||||
for (int j = 0; j < i / 16; ++j) {
|
||||
currentPos = currentPos.offset(
|
||||
RandomUtils.generateRandomInt(-1, 2), RandomUtils.generateRandomInt(-1, 2) * RandomUtils.generateRandomInt(0, 3) / 2, RandomUtils.generateRandomInt(-1, 2)
|
||||
);
|
||||
BlockPos belowPos = currentPos.relative(Direction.DOWN);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, LocationUtils.toBlockPos(belowPos));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
continue out;
|
||||
}
|
||||
if (optionalCustomState.get().owner().value() != super.customBlock) {
|
||||
continue out;
|
||||
}
|
||||
Object nmsCurrentPos = LocationUtils.toBlockPos(currentPos);
|
||||
Object currentState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, nmsCurrentPos);
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(currentState, world, nmsCurrentPos)) {
|
||||
continue out;
|
||||
}
|
||||
if (BlockStateUtils.getBlockOwner(currentState) == MBlocks.SHORT_GRASS && RandomUtils.generateRandomInt(0, 10) == 0) {
|
||||
CoreReflections.method$BonemealableBlock$performBonemeal.invoke(MBlocks.SHORT_GRASS, world, random, nmsCurrentPos, currentState);
|
||||
}
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$isAir(currentState)) {
|
||||
Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world));
|
||||
Object placedFeature = CoreReflections.method$Holder$value.invoke(holder.get());
|
||||
CoreReflections.method$PlacedFeature$place.invoke(placedFeature, world, chunkGenerator, random, nmsCurrentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
return new GrassBlockBehavior(block);
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "feature", "placed-feature"), "warning.config.block.behavior.grass.missing_feature");
|
||||
return new GrassBlockBehavior(block, Key.of(feature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ public class HangingBlockBehavior extends BushBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, true);
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false);
|
||||
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
|
||||
return new HangingBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
@@ -13,8 +12,10 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class LampBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<Boolean> litProperty;
|
||||
@@ -34,37 +35,36 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public void tick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
if (state.get(this.litProperty)) {
|
||||
if (!FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
|
||||
// TODO Call Event
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
}
|
||||
} else {
|
||||
if (FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
|
||||
// TODO Call Event
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
if (customState.get(this.litProperty) && !FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
|
||||
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
|
||||
return;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
boolean lit = state.get(this.litProperty);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
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);
|
||||
} else {
|
||||
// TODO Call Event
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
|
||||
return;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
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.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockTags;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
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.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.block.LeavesDecayEvent;
|
||||
|
||||
@@ -64,26 +55,17 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object world;
|
||||
Object blockPos;
|
||||
Object neighborState;
|
||||
Object world = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Object neighborState = args[updateShape$neighborState];
|
||||
Object blockState = args[0];
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
world = args[1];
|
||||
neighborState = args[6];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
world = args[3];
|
||||
blockPos = args[4];
|
||||
neighborState = args[2];
|
||||
}
|
||||
ImmutableBlockState thisState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (thisState != null) {
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = thisState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = optionalCustomState.get().behavior().getAs(LeavesBlockBehavior.class);
|
||||
if (optionalBehavior.isPresent()) {
|
||||
LeavesBlockBehavior behavior = optionalBehavior.get();
|
||||
int distance = behavior.getDistanceAt(neighborState) + 1;
|
||||
if (distance != 1 || behavior.getDistance(thisState) != distance) {
|
||||
if (distance != 1 || behavior.getDistance(optionalCustomState.get()) != distance) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 1);
|
||||
}
|
||||
}
|
||||
@@ -96,13 +78,14 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
Object blockState = args[0];
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (currentState != null && !currentState.isEmpty()) {
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = currentState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = customState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
if (optionalBehavior.isPresent()) {
|
||||
LeavesBlockBehavior behavior = optionalBehavior.get();
|
||||
ImmutableBlockState newState = behavior.updateDistance(currentState, level, blockPos);
|
||||
if (newState != currentState) {
|
||||
ImmutableBlockState newState = behavior.updateDistance(customState, level, blockPos);
|
||||
if (newState != customState) {
|
||||
if (blockState == newState.customBlockState().handle()) {
|
||||
CoreReflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512);
|
||||
} else {
|
||||
@@ -113,16 +96,18 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public void randomTick(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (immutableBlockState != null) {
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = immutableBlockState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> {
|
||||
// 可能是另一种树叶
|
||||
Optional<LeavesBlockBehavior> optionalBehavior = customState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
if (optionalBehavior.isPresent()) {
|
||||
LeavesBlockBehavior behavior = optionalBehavior.get();
|
||||
if (behavior.isDecaying(immutableBlockState)) {
|
||||
if (behavior.isDecaying(customState)) {
|
||||
World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
// call bukkit event
|
||||
@@ -132,19 +117,10 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
return;
|
||||
}
|
||||
FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false);
|
||||
if (isWaterLogged(immutableBlockState)) {
|
||||
bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData());
|
||||
}
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld);
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
FastNMS.INSTANCE.method$Block$dropResources(blockState, level, blockPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isDecaying(ImmutableBlockState blockState) {
|
||||
@@ -168,16 +144,16 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
private int getDistanceAt(Object blockState) throws ReflectiveOperationException {
|
||||
boolean isLog = (boolean) CoreReflections.method$BlockStateBase$hasTag.invoke(blockState, LOG_TAG);
|
||||
boolean isLog = FastNMS.INSTANCE.method$BlockStateBase$is(blockState, LOG_TAG);
|
||||
if (isLog) return 0;
|
||||
int id = BlockStateUtils.blockStateToId(blockState);
|
||||
if (BlockStateUtils.isVanillaBlock(id)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
Object distanceProperty = CoreReflections.field$LeavesBlock$DISTANCE.get(null);
|
||||
boolean hasDistanceProperty = (boolean) CoreReflections.method$StateHolder$hasProperty.invoke(blockState, distanceProperty);
|
||||
if (!hasDistanceProperty) return this.maxDistance;
|
||||
return (int) CoreReflections.method$StateHolder$getValue.invoke(blockState, distanceProperty);
|
||||
} else {
|
||||
ImmutableBlockState anotherBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
|
||||
ImmutableBlockState anotherBlockState = optionalCustomState.get();
|
||||
Optional<LeavesBlockBehavior> optionalAnotherBehavior = anotherBlockState.behavior().getAs(LeavesBlockBehavior.class);
|
||||
return optionalAnotherBehavior.map(leavesBlockBehavior -> leavesBlockBehavior.getDistance(anotherBlockState)).orElse(this.maxDistance);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
@@ -16,6 +15,7 @@ import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
private static final List<Object> WATER = List.of(MFluids.WATER, MFluids.FLOWING_WATER);
|
||||
@@ -46,7 +46,7 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
List<String> positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of()));
|
||||
if (positionsToCheck.isEmpty()) {
|
||||
@@ -70,12 +70,9 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
if (this.stackable) {
|
||||
Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos);
|
||||
int id = BlockStateUtils.blockStateToId(belowState);
|
||||
if (!BlockStateUtils.isVanillaBlock(id)) {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
|
||||
if (immutableBlockState.owner().value() == super.customBlock) {
|
||||
return true;
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalBelowCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
if (optionalBelowCustomState.isPresent() && optionalBelowCustomState.get().owner().value() == super.customBlock) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (BlockPos pos : positions) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
@@ -15,6 +14,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
@@ -41,12 +41,13 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
return new OnLiquidBlockBehavior(block, delay, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) {
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
|
||||
@@ -59,12 +60,9 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
|
||||
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) {
|
||||
if (this.stackable) {
|
||||
int id = BlockStateUtils.blockStateToId(belowState);
|
||||
if (!BlockStateUtils.isVanillaBlock(id)) {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
|
||||
if (immutableBlockState.owner().value() == super.customBlock) {
|
||||
return true;
|
||||
}
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
if (optionalCustomState.isPresent() && optionalCustomState.get().owner().value() == super.customBlock) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, belowPos);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import io.papermc.paper.event.entity.EntityInsideBlockEvent;
|
||||
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;
|
||||
@@ -16,9 +15,6 @@ import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.PressurePlateSensitivity;
|
||||
@@ -39,48 +35,42 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
private final SoundData onSound;
|
||||
private final SoundData offSound;
|
||||
private final PressurePlateSensitivity pressurePlateSensitivity;
|
||||
private final int pressedTime;
|
||||
|
||||
public PressurePlateBlockBehavior(
|
||||
CustomBlock block,
|
||||
Property<Boolean> poweredProperty,
|
||||
SoundData onSound,
|
||||
SoundData offSound,
|
||||
PressurePlateSensitivity pressurePlateSensitivity
|
||||
PressurePlateSensitivity pressurePlateSensitivity,
|
||||
int pressedTime
|
||||
) {
|
||||
super(block);
|
||||
this.poweredProperty = poweredProperty;
|
||||
this.onSound = onSound;
|
||||
this.offSound = offSound;
|
||||
this.pressurePlateSensitivity = pressurePlateSensitivity;
|
||||
this.pressedTime = pressedTime;
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object state = args[0];
|
||||
Object level;
|
||||
Object blockPos;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
Object level = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
if (direction == Direction.DOWN && !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state, level, blockPos)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
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));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
int stateId = BlockStateUtils.blockStateToId(state);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return MBlocks.AIR$defaultState;
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, immutableBlockState.sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return state;
|
||||
@@ -115,7 +105,8 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
if (signalForState == 0) {
|
||||
this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock);
|
||||
} else {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(args[1], args[2], thisBlock, 20);
|
||||
// todo 为什么
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +116,13 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
case MOBS -> CoreReflections.clazz$LivingEntity;
|
||||
};
|
||||
Object box = FastNMS.INSTANCE.method$AABB$move(CoreReflections.instance$BasePressurePlateBlock$TOUCH_AABB, pos);
|
||||
return FastNMS.INSTANCE.method$BasePressurePlateBlock$getEntityCount(level, box, clazz) > 0 ? 15 : 0;
|
||||
return FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass(level, box, clazz) > 0 ? 15 : 0;
|
||||
}
|
||||
|
||||
private Object setSignalForState(Object state, int strength) {
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return state;
|
||||
return blockState.with(this.poweredProperty, strength > 0).customBlockState().handle();
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) return state;
|
||||
return optionalCustomState.get().with(this.poweredProperty, strength > 0).customBlockState().handle();
|
||||
}
|
||||
|
||||
private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal, Object thisBlock) {
|
||||
@@ -159,7 +150,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
if (isActive) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, pos, thisBlock, 20);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, pos, thisBlock, this.pressedTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,9 +193,8 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
private int getSignalForState(Object state) {
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return 0;
|
||||
return blockState.get(this.poweredProperty) ? 15 : 0;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
return optionalCustomState.filter(immutableBlockState -> immutableBlockState.get(this.poweredProperty)).map(immutableBlockState -> 15).orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -225,6 +215,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.pressure_plate.missing_powered");
|
||||
PressurePlateSensitivity pressurePlateSensitivity = PressurePlateSensitivity.byName(arguments.getOrDefault("sensitivity", "everything").toString());
|
||||
int pressedTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("pressed-time", 20), "pressed-time");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData onSound = null;
|
||||
SoundData offSound = null;
|
||||
@@ -232,7 +223,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
onSound = Optional.ofNullable(sounds.get("on")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
offSound = Optional.ofNullable(sounds.get("off")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new PressurePlateBlockBehavior(block, powered, onSound, offSound, pressurePlateSensitivity);
|
||||
return new PressurePlateBlockBehavior(block, powered, onSound, offSound, pressurePlateSensitivity, pressedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
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.MRegistries;
|
||||
@@ -14,6 +13,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.IntegerProperty;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -30,14 +30,15 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Key feature;
|
||||
private final Property<Integer> stageProperty;
|
||||
private final IntegerProperty stageProperty;
|
||||
private final double boneMealSuccessChance;
|
||||
private final float growSpeed;
|
||||
|
||||
public SaplingBlockBehavior(CustomBlock block, Key feature, Property<Integer> stageProperty, double boneMealSuccessChance, float growSpeed) {
|
||||
public SaplingBlockBehavior(CustomBlock block, Key feature, IntegerProperty stageProperty, double boneMealSuccessChance, float growSpeed) {
|
||||
super(block);
|
||||
this.feature = feature;
|
||||
this.stageProperty = stageProperty;
|
||||
@@ -55,17 +56,18 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
Object blockPos = args[2];
|
||||
Object blockState = args[0];
|
||||
Object aboveBlockPos = LocationUtils.above(blockPos);
|
||||
if ((int) CoreReflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && RandomUtils.generateRandomFloat(0, 1) < growSpeed) {
|
||||
if ((int) CoreReflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
increaseStage(world, blockPos, blockState, args[3]);
|
||||
}
|
||||
}
|
||||
|
||||
private void increaseStage(Object world, Object blockPos, Object blockState, Object randomSource) throws Exception {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
int currentStage = immutableBlockState.get(this.stageProperty);
|
||||
if (currentStage != this.stageProperty.possibleValues().get(this.stageProperty.possibleValues().size() - 1)) {
|
||||
ImmutableBlockState nextStage = immutableBlockState.cycle(this.stageProperty);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
int currentStage = customState.get(this.stageProperty);
|
||||
if (currentStage != this.stageProperty.max) {
|
||||
ImmutableBlockState nextStage = customState.cycle(this.stageProperty);
|
||||
World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(world);
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
|
||||
@@ -80,7 +82,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE);
|
||||
if (registry == null) return;
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createFeatureKey(treeFeature()));
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature()));
|
||||
if (holder.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature());
|
||||
return;
|
||||
@@ -101,18 +103,19 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception {
|
||||
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) {
|
||||
boolean success = RandomUtils.generateRandomDouble(0d, 1d) < this.boneMealSuccessChance;
|
||||
Object level = args[0];
|
||||
Object blockPos = args[2];
|
||||
Object blockState = args[3];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
boolean sendParticles = false;
|
||||
Object visualState = immutableBlockState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, blockPos, visualState);
|
||||
if (!is) {
|
||||
@@ -148,20 +151,15 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
try {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = CoreReflections.method$BlockStateBase$getBlock.invoke(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} else {
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
if (!is) {
|
||||
sendSwing = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e);
|
||||
return InteractionResult.FAIL;
|
||||
} else {
|
||||
sendSwing = true;
|
||||
}
|
||||
if (sendSwing) {
|
||||
context.getPlayer().swingHand(context.getHand());
|
||||
@@ -174,10 +172,10 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("feature"), "warning.config.block.behavior.sapling.missing_feature");
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "feature", "configured-feature"), "warning.config.block.behavior.sapling.missing_feature");
|
||||
Property<Integer> stageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("stage"), "warning.config.block.behavior.sapling.missing_stage");
|
||||
double boneMealSuccessChance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45), "bone-meal-success-chance");
|
||||
return new SaplingBlockBehavior(block, Key.of(feature), stageProperty, boneMealSuccessChance,
|
||||
return new SaplingBlockBehavior(block, Key.of(feature), (IntegerProperty) stageProperty, boneMealSuccessChance,
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1.0 / 7.0), "grow-speed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.MFluids;
|
||||
@@ -81,26 +80,24 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
|
||||
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.placeLiquid(thisBlock, args, superMethod);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
return optionalCustomState.filter(state -> state.get(this.typeProperty) != SlabType.DOUBLE && super.placeLiquid(thisBlock, args, superMethod)).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = VersionHelper.isOrAbove1_20_2() ? args[3] : args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
|
||||
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.canPlaceLiquid(thisBlock, args, superMethod);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
return optionalCustomState.filter(state -> state.get(this.typeProperty) != SlabType.DOUBLE && super.canPlaceLiquid(thisBlock, args, superMethod)).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
if (super.waterloggedProperty == null) return blockState;
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
if (immutableBlockState.get(super.waterloggedProperty)) {
|
||||
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);
|
||||
}
|
||||
return blockState;
|
||||
@@ -110,10 +107,10 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$WATER) {
|
||||
return super.waterloggedProperty != null && state.get(this.typeProperty) != SlabType.DOUBLE && state.get(super.waterloggedProperty);
|
||||
return super.waterloggedProperty != null && optionalCustomState.get().get(this.typeProperty) != SlabType.DOUBLE && optionalCustomState.get().get(super.waterloggedProperty);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
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.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
@@ -25,6 +23,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class StairsBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
@@ -54,127 +53,76 @@ public class StairsBlockBehavior extends BukkitBlockBehavior {
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level;
|
||||
Object blockPos;
|
||||
Object level = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Object blockState = args[0];
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
if (super.waterloggedProperty != null && immutableBlockState.get(this.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);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
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);
|
||||
}
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
StairsShape stairsShape = getStairsShape(immutableBlockState, level, LocationUtils.fromBlockPos(blockPos));
|
||||
StairsShape stairsShape = getStairsShape(customState, level, LocationUtils.fromBlockPos(blockPos));
|
||||
return direction.axis().isHorizontal()
|
||||
? immutableBlockState.with(this.shapeProperty, stairsShape).customBlockState().handle()
|
||||
? customState.with(this.shapeProperty, stairsShape).customBlockState().handle()
|
||||
: superMethod.call();
|
||||
}
|
||||
|
||||
private StairsShape getStairsShape(ImmutableBlockState state, Object level, BlockPos pos) {
|
||||
Direction direction = state.get(this.facingProperty).toDirection();
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction)));
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState != null && !immutableBlockState.isEmpty()) {
|
||||
if (isStairs(blockState) && state.get(this.halfProperty) == immutableBlockState.get(this.halfProperty)) {
|
||||
Direction direction1 = immutableBlockState.get(this.facingProperty).toDirection();
|
||||
if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1.opposite())) {
|
||||
if (direction1 == direction.counterClockWise()) {
|
||||
return StairsShape.OUTER_LEFT;
|
||||
Object relativeBlockState1 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction)));
|
||||
Optional<ImmutableBlockState> optionalCustomState1 = BlockStateUtils.getOptionalCustomBlockState(relativeBlockState1);
|
||||
if (optionalCustomState1.isPresent()) {
|
||||
ImmutableBlockState customState1 = optionalCustomState1.get();
|
||||
Optional<StairsBlockBehavior> optionalStairsBlockBehavior = customState1.behavior().getAs(StairsBlockBehavior.class);
|
||||
if (optionalStairsBlockBehavior.isPresent()) {
|
||||
StairsBlockBehavior stairsBlockBehavior = optionalStairsBlockBehavior.get();
|
||||
if (state.get(this.halfProperty) == customState1.get(stairsBlockBehavior.halfProperty)) {
|
||||
Direction direction1 = customState1.get(stairsBlockBehavior.facingProperty).toDirection();
|
||||
if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1.opposite())) {
|
||||
if (direction1 == direction.counterClockWise()) {
|
||||
return StairsShape.OUTER_LEFT;
|
||||
}
|
||||
return StairsShape.OUTER_RIGHT;
|
||||
}
|
||||
return StairsShape.OUTER_RIGHT;
|
||||
}
|
||||
}
|
||||
} else if (isStairs(blockState)) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (state.get(this.halfProperty).equals(half)) {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction1 = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1.opposite())) {
|
||||
// if (direction1 == direction.counterClockWise()) {
|
||||
// return StairsShape.OUTER_LEFT;
|
||||
// }
|
||||
// return StairsShape.OUTER_RIGHT;
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to get facing from blockState", e);
|
||||
// }
|
||||
}
|
||||
|
||||
Object blockState1 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction.opposite())));
|
||||
int stateId1 = BlockStateUtils.blockStateToId(blockState1);
|
||||
ImmutableBlockState immutableBlockState1 = BukkitBlockManager.instance().getImmutableBlockState(stateId1);
|
||||
if (immutableBlockState1 != null && !immutableBlockState1.isEmpty()) {
|
||||
if (isStairs(blockState1) && state.get(this.halfProperty) == immutableBlockState1.get(this.halfProperty)) {
|
||||
Direction direction2 = immutableBlockState1.get(this.facingProperty).toDirection();
|
||||
if (direction2.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction2)) {
|
||||
if (direction2 == direction.counterClockWise()) {
|
||||
return StairsShape.INNER_LEFT;
|
||||
Object relativeBlockState2 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction.opposite())));
|
||||
Optional<ImmutableBlockState> optionalCustomState2 = BlockStateUtils.getOptionalCustomBlockState(relativeBlockState2);
|
||||
if (optionalCustomState2.isPresent()) {
|
||||
ImmutableBlockState customState2 = optionalCustomState2.get();
|
||||
Optional<StairsBlockBehavior> optionalStairsBlockBehavior = customState2.behavior().getAs(StairsBlockBehavior.class);
|
||||
if (optionalStairsBlockBehavior.isPresent()) {
|
||||
StairsBlockBehavior stairsBlockBehavior = optionalStairsBlockBehavior.get();
|
||||
if (state.get(this.halfProperty) == customState2.get(stairsBlockBehavior.halfProperty)) {
|
||||
Direction direction2 = customState2.get(stairsBlockBehavior.facingProperty).toDirection();
|
||||
if (direction2.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction2)) {
|
||||
if (direction2 == direction.counterClockWise()) {
|
||||
return StairsShape.INNER_LEFT;
|
||||
}
|
||||
return StairsShape.INNER_RIGHT;
|
||||
}
|
||||
return StairsShape.INNER_RIGHT;
|
||||
}
|
||||
}
|
||||
} else if (isStairs(blockState1)) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState1, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (state.get(this.halfProperty).equals(half)) {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState1, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction1 = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1)) {
|
||||
// if (direction1 == direction.counterClockWise()) {
|
||||
// return StairsShape.INNER_LEFT;
|
||||
// }
|
||||
// return StairsShape.INNER_RIGHT;
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to get facing from blockState", e);
|
||||
// }
|
||||
}
|
||||
|
||||
return StairsShape.STRAIGHT;
|
||||
}
|
||||
|
||||
private boolean isStairs(Object state) {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
return FastNMS.INSTANCE.method$BlockState$getBlock(state).equals(CoreReflections.clazz$StairBlock);
|
||||
}
|
||||
Optional<StairsBlockBehavior> optionalBehavior = immutableBlockState.behavior().getAs(StairsBlockBehavior.class);
|
||||
return optionalBehavior.isPresent();
|
||||
}
|
||||
|
||||
private boolean canTakeShape(ImmutableBlockState state, Object level, BlockPos pos, Direction face) {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(face)));
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction != state.get(this.facingProperty).toDirection()) return true;
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (half != state.get(this.halfProperty)) return true;
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to handle canTakeShape", e);
|
||||
// }
|
||||
return !isStairs(blockState);
|
||||
Optional<ImmutableBlockState> optionalAnotherState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalAnotherState.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return !isStairs(blockState) || immutableBlockState.get(this.facingProperty) != state.get(this.facingProperty) || immutableBlockState.get(this.halfProperty) != state.get(this.halfProperty);
|
||||
ImmutableBlockState anotherState = optionalAnotherState.get();
|
||||
Optional<StairsBlockBehavior> optionalBehavior = anotherState.behavior().getAs(StairsBlockBehavior.class);
|
||||
if (optionalBehavior.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
StairsBlockBehavior anotherBehavior = optionalBehavior.get();
|
||||
return anotherState.get(anotherBehavior.facingProperty) != state.get(this.facingProperty) || anotherState.get(anotherBehavior.halfProperty) != state.get(this.halfProperty);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.util.BlockStateUtils;
|
||||
@@ -16,8 +15,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
@@ -58,9 +56,8 @@ public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
if (!this.stackable) {
|
||||
return false;
|
||||
}
|
||||
ImmutableBlockState targetCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (targetCustomState == null || targetCustomState.isEmpty()) return false;
|
||||
return targetCustomState.owner().value() == super.customBlock;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
return optionalCustomState.filter(immutableBlockState -> immutableBlockState.owner().value() == super.customBlock).isPresent();
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@@ -69,7 +66,7 @@ public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
Direction direction = Direction.valueOf(arguments.getOrDefault("direction", "down").toString().toUpperCase(Locale.ENGLISH));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
List<String> supportTypes = MiscUtils.getAsStringList(arguments.getOrDefault("support-types", List.of("full")));
|
||||
return new SturdyBaseBlockBehavior(block, delay, direction, stackable, supportTypes.contains("full"), supportTypes.contains("rigid"), supportTypes.contains("center"));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
@@ -24,10 +23,7 @@ import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
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 net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
@@ -43,6 +39,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<SingleBlockHalf> halfProperty;
|
||||
@@ -78,10 +75,11 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
if (super.waterloggedProperty != null) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state != null && !state.isEmpty() && state.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);
|
||||
}
|
||||
BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> {
|
||||
if (customState.get(super.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
|
||||
}
|
||||
});
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
@@ -129,12 +127,12 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
|
||||
return state.get(this.openProperty);
|
||||
return optionalCustomState.get().get(this.openProperty);
|
||||
} else if (type == CoreReflections.instance$PathComputationType$WATER) {
|
||||
return state.get(super.waterloggedProperty);
|
||||
return optionalCustomState.get().get(super.waterloggedProperty);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -142,9 +140,9 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
this.toggle(state, new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
this.toggle(optionalCustomState.get(), new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,16 +150,17 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, blockPos);
|
||||
if (hasSignal == immutableBlockState.get(this.poweredProperty)) return;
|
||||
if (hasSignal == customState.get(this.poweredProperty)) return;
|
||||
|
||||
Block bblock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
|
||||
int power = bblock.getBlockPower();
|
||||
int oldPower = immutableBlockState.get(this.openProperty) ? 15 : 0;
|
||||
int oldPower = customState.get(this.openProperty) ? 15 : 0;
|
||||
Object neighborBlock = args[3];
|
||||
|
||||
if (oldPower == 0 ^ power == 0 || FastNMS.INSTANCE.method$BlockStateBase$isSignalSource(FastNMS.INSTANCE.method$Block$defaultState(neighborBlock))) {
|
||||
@@ -171,7 +170,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
boolean changed = immutableBlockState.get(this.openProperty) != hasSignal;
|
||||
boolean changed = customState.get(this.openProperty) != hasSignal;
|
||||
if (hasSignal && changed) {
|
||||
Object abovePos = LocationUtils.above(blockPos);
|
||||
Object aboveBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, abovePos);
|
||||
@@ -188,7 +187,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
immutableBlockState = immutableBlockState.with(this.openProperty, hasSignal);
|
||||
customState = customState.with(this.openProperty, hasSignal);
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null,
|
||||
hasSignal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos), FastNMS.INSTANCE.field$Vec3i$z(blockPos))
|
||||
@@ -196,8 +195,8 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
if (this.waterloggedProperty != null && immutableBlockState.get(this.waterloggedProperty)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -234,9 +233,9 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.trapdoor.missing_facing");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.trapdoor.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.trapdoor.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = MiscUtils.castToMap(arguments.get("sounds"), true);
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
@@ -19,6 +18,7 @@ import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class VerticalCropBlockBehavior extends BukkitBlockBehavior {
|
||||
@@ -42,26 +42,25 @@ public class VerticalCropBlockBehavior extends BukkitBlockBehavior {
|
||||
Object blockState = args[0];
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
Optional<ImmutableBlockState> optionalCurrentState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCurrentState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ImmutableBlockState currentState = optionalCurrentState.get();
|
||||
// above block is empty
|
||||
if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, (this.direction ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos))) == MBlocks.AIR$defaultState) {
|
||||
int currentHeight = 1;
|
||||
BlockPos currentPos = LocationUtils.fromBlockPos(blockPos);
|
||||
ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (currentState != null && !currentState.isEmpty()) {
|
||||
while (true) {
|
||||
Object nextPos = LocationUtils.toBlockPos(currentPos.x(), this.direction ? currentPos.y() - currentHeight : currentPos.y() + currentHeight, currentPos.z());
|
||||
Object nextState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, nextPos);
|
||||
ImmutableBlockState belowImmutableState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nextState));
|
||||
if (belowImmutableState != null && !belowImmutableState.isEmpty() && belowImmutableState.owner() == currentState.owner()) {
|
||||
currentHeight++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
while (true) {
|
||||
Object nextPos = LocationUtils.toBlockPos(currentPos.x(), this.direction ? currentPos.y() - currentHeight : currentPos.y() + currentHeight, currentPos.z());
|
||||
Object nextState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, nextPos);
|
||||
Optional<ImmutableBlockState> optionalBelowCustomState = BlockStateUtils.getOptionalCustomBlockState(nextState);
|
||||
if (optionalBelowCustomState.isPresent() && optionalBelowCustomState.get().owner().value() == super.customBlock) {
|
||||
currentHeight++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentHeight < this.maxHeight) {
|
||||
int age = currentState.get(ageProperty);
|
||||
if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
|
||||
@@ -89,11 +89,10 @@ public class BukkitFurniture implements Furniture {
|
||||
List<Object> minimizedPackets = new ArrayList<>();
|
||||
List<Collider> colliders = new ArrayList<>();
|
||||
WorldPosition position = position();
|
||||
Integer dyedColor = this.extraData.dyedColor().orElse(null);
|
||||
for (FurnitureElement element : placement.elements()) {
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
fakeEntityIds.add(entityId);
|
||||
element.initPackets(entityId, position, conjugated, dyedColor, packet -> {
|
||||
element.initPackets(this, entityId, conjugated, packet -> {
|
||||
packets.add(packet);
|
||||
if (this.minimized) minimizedPackets.add(packet);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.furniture;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
@@ -8,14 +9,19 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
|
||||
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;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
@@ -45,16 +51,24 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPackets(int entityId, @NotNull WorldPosition position, @NotNull Quaternionf conjugated, Integer dyedColor, Consumer<Object> packets) {
|
||||
public void initPackets(Furniture furniture, int entityId, @NotNull Quaternionf conjugated, Consumer<Object> packets) {
|
||||
WorldPosition position = furniture.position();
|
||||
Vector3f offset = conjugated.transform(new Vector3f(position()));
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(),
|
||||
MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
));
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(dyedColor)));
|
||||
if (applyDyedColor()) {
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(
|
||||
furniture.extraData().dyedColor().orElse(null),
|
||||
furniture.extraData().fireworkExplosionColors().orElse(null)
|
||||
)));
|
||||
} else {
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(null, null)));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized List<Object> getCachedValues(Integer color) {
|
||||
private synchronized List<Object> getCachedValues(@Nullable Integer color, int @Nullable [] colors) {
|
||||
List<Object> cachedValues = new ArrayList<>(this.commonValues);
|
||||
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(item(), null);
|
||||
if (item == null) {
|
||||
@@ -63,7 +77,15 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
|
||||
} else {
|
||||
if (color != null) {
|
||||
item.dyedColor(color);
|
||||
item.load();
|
||||
}
|
||||
if (colors != null) {
|
||||
item.fireworkExplosion(new FireworkExplosion(
|
||||
FireworkExplosion.Shape.SMALL_BALL,
|
||||
new IntArrayList(colors),
|
||||
new IntArrayList(),
|
||||
false,
|
||||
false
|
||||
));
|
||||
}
|
||||
}
|
||||
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), cachedValues);
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -171,7 +170,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
BukkitFurniture furniture = this.furnitureByRealEntityId.remove(id);
|
||||
if (furniture != null) {
|
||||
Location location = entity.getLocation();
|
||||
boolean isPreventing = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
boolean isPreventing = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
if (!isPreventing) {
|
||||
furniture.destroySeats();
|
||||
}
|
||||
@@ -202,7 +201,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
|
||||
Location location = display.getLocation();
|
||||
boolean above1_20_1 = VersionHelper.isOrAbove1_20_2();
|
||||
boolean preventChange = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
boolean preventChange = FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
if (above1_20_1) {
|
||||
if (!preventChange) {
|
||||
BukkitFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
@@ -243,7 +242,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
World world = location.getWorld();
|
||||
int chunkX = location.getBlockX() >> 4;
|
||||
int chunkZ = location.getBlockZ() >> 4;
|
||||
if (!FastNMS.INSTANCE.isPreventingStatusUpdates(world, chunkX, chunkZ)) {
|
||||
if (!FastNMS.INSTANCE.method$ServerLevel$isPreventingStatusUpdates(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world), chunkX, chunkZ)) {
|
||||
entity.remove();
|
||||
return;
|
||||
}
|
||||
@@ -381,7 +380,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
int z = location.getBlockZ();
|
||||
if (!world.getBlockAt(x, y - 1, z).getType().isSolid()) return false;
|
||||
if (!world.getBlockAt(x, y, z).isPassable()) return false;
|
||||
if (isEntityBlocking(location)) return false;
|
||||
return world.getBlockAt(x, y + 1, z).isPassable();
|
||||
}
|
||||
|
||||
@@ -403,18 +401,4 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isEntityBlocking(Location location) {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return true;
|
||||
try {
|
||||
Collection<Entity> nearbyEntities = world.getNearbyEntities(location, 0.38, 2, 0.38);
|
||||
for (Entity bukkitEntity : nearbyEntities) {
|
||||
if (bukkitEntity instanceof Player) continue;
|
||||
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(bukkitEntity);
|
||||
return FastNMS.INSTANCE.method$Entity$canBeCollidedWith(nmsEntity);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class CustomHitBox extends AbstractHitBox {
|
||||
try {
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId[0], UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(),
|
||||
FastNMS.INSTANCE.toNMSEntityType(this.entityType), 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
FastNMS.INSTANCE.method$CraftEntityType$toNMSEntityType(this.entityType), 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true);
|
||||
if (VersionHelper.isOrAbove1_20_5() && this.scale != 1) {
|
||||
@@ -91,8 +91,8 @@ public class CustomHitBox extends AbstractHitBox {
|
||||
if (entityType == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.custom.invalid_entity", new IllegalArgumentException("EntityType not found: " + type), type);
|
||||
}
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
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", true), "blocks-building");
|
||||
return new CustomHitBox(HitBoxFactory.getSeats(arguments), position, entityType, scale, blocksBuilding, canBeHitByProjectile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ public class HappyGhastHitBox extends AbstractHitBox {
|
||||
throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+");
|
||||
}
|
||||
double scale = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("scale", 1), "scale");
|
||||
boolean hardCollision = (boolean) arguments.getOrDefault("hard-collision", true);
|
||||
boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", false);
|
||||
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");
|
||||
return new HappyGhastHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),
|
||||
|
||||
@@ -104,10 +104,10 @@ public class InteractionHitBox extends AbstractHitBox {
|
||||
width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", "1"), "width");
|
||||
height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", "1"), "height");
|
||||
}
|
||||
boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false);
|
||||
boolean interactive = (boolean) arguments.getOrDefault("interactive", true);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on");
|
||||
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
|
||||
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", true), "blocks-building");
|
||||
return new InteractionHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
position,
|
||||
|
||||
@@ -284,11 +284,11 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale");
|
||||
byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek");
|
||||
Direction directionEnum = Optional.ofNullable(arguments.get("direction")).map(it -> Direction.valueOf(it.toString().toUpperCase(Locale.ENGLISH))).orElse(Direction.UP);
|
||||
boolean interactive = (boolean) arguments.getOrDefault("interactive", true);
|
||||
boolean interactionEntity = (boolean) arguments.getOrDefault("interaction-entity", true);
|
||||
boolean canUseItemOn = (boolean) arguments.getOrDefault("can-use-item-on", true);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", true);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
|
||||
boolean interactionEntity = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interaction-entity", true), "interaction-entity");
|
||||
boolean canUseItemOn = 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 ShulkerHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
position, directionEnum,
|
||||
|
||||
@@ -2,8 +2,6 @@ package net.momirealms.craftengine.bukkit.entity.projectile;
|
||||
|
||||
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
|
||||
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
|
||||
import io.papermc.paper.event.player.PlayerStopUsingItemEvent;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
@@ -11,25 +9,24 @@ import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask;
|
||||
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileManager;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileType;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.ThrowableProjectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityPortalEvent;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.event.world.EntitiesLoadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -122,41 +119,6 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerConsume(PlayerItemConsumeEvent event) {
|
||||
ProjectileType type = getCustomProjectileType(event.getItem());
|
||||
if (type == ProjectileType.TRIDENT) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerStopUsingItem(PlayerStopUsingItemEvent event) {
|
||||
ItemStack item = event.getItem();
|
||||
ProjectileType type = getCustomProjectileType(item);
|
||||
if (type == null) return;
|
||||
int ticksHeldFor = event.getTicksHeldFor();
|
||||
Player player = event.getPlayer();
|
||||
if (type == ProjectileType.TRIDENT) {
|
||||
if (ticksHeldFor < 10) return;
|
||||
Object nmsItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(item);
|
||||
Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
|
||||
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player);
|
||||
TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProjectileType getCustomProjectileType(ItemStack item) {
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(item);
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) return null;
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
ProjectileMeta meta = customItem.settings().projectileMeta();
|
||||
if (meta == null) return null;
|
||||
return meta.type();
|
||||
}
|
||||
|
||||
public class ProjectileInjectTask implements Runnable {
|
||||
private final Projectile projectile;
|
||||
private final SchedulerTask task;
|
||||
|
||||
@@ -1,514 +0,0 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.projectile;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MSoundEvents;
|
||||
import net.momirealms.craftengine.core.util.MCUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class TridentRelease {
|
||||
|
||||
private TridentRelease() {}
|
||||
|
||||
public static boolean releaseUsing(Object stack, Object level, Object entity) {
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
return releaseUsing_1_21_2(stack, level, entity);
|
||||
} else if (VersionHelper.isOrAbove1_21()) {
|
||||
return releaseUsing_1_21(stack, level, entity);
|
||||
} else if (VersionHelper.isOrAbove1_20_5()) {
|
||||
return releaseUsing_1_20_5(stack, level, entity);
|
||||
} else if (VersionHelper.isOrAbove1_20_3()) {
|
||||
return releaseUsing_1_20_3(stack, level, entity);
|
||||
} else if (VersionHelper.isOrAbove1_20()) {
|
||||
return releaseUsing_1_20(stack, level, entity);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean releaseUsing_1_21_2(Object stack, Object level, Object entity) {
|
||||
Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false;
|
||||
float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity);
|
||||
if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) {
|
||||
return false;
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
|
||||
Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack);
|
||||
|
||||
if (spinStrength == 0.0F) {
|
||||
Object projectile = FastNMS.INSTANCE.method$Projectile$ThrownTrident$spawnProjectileFromRotationDelayed(
|
||||
level,
|
||||
copyStack,
|
||||
entity,
|
||||
0.0F,
|
||||
2.5F,
|
||||
1.0F
|
||||
);
|
||||
PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent(
|
||||
(Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack),
|
||||
(Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile))
|
||||
);
|
||||
|
||||
if (!event.callEvent() || !FastNMS.INSTANCE.method$Projectile$Delayed$attemptSpawn(projectile)) {
|
||||
FastNMS.INSTANCE.method$AbstractContainerMenu$sendAllDataToRemote(FastNMS.INSTANCE.field$Player$containerMenu(entity));
|
||||
return false;
|
||||
}
|
||||
|
||||
Object trident = FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile);
|
||||
if (event.shouldConsume()) {
|
||||
FastNMS.INSTANCE.method$ItemStack$hurtWithoutBreaking(stack, 1, entity);
|
||||
FastNMS.INSTANCE.method$ItemStack$consume(stack, 1, entity);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(trident, copyStack);
|
||||
if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) {
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickup(trident, CoreReflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
trident,
|
||||
FastNMS.INSTANCE.method$Holder$value(sound),
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity);
|
||||
float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity);
|
||||
float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD);
|
||||
float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
|
||||
float length = MCUtils.sqrt(x * x + y * y + z * z);
|
||||
x = x / length * spinStrength;
|
||||
y = y / length * spinStrength;
|
||||
z = z / length * spinStrength;
|
||||
|
||||
FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z);
|
||||
FastNMS.INSTANCE.method$Entity$push(entity, x, y, z);
|
||||
FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true);
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack);
|
||||
|
||||
if (FastNMS.INSTANCE.method$Entity$onGround(entity)) {
|
||||
FastNMS.INSTANCE.method$Entity$move(entity, CoreReflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D));
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Holder$value(sound),
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean releaseUsing_1_21(Object stack, Object level, Object entity) {
|
||||
Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false;
|
||||
|
||||
float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity);
|
||||
|
||||
if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) {
|
||||
return false;
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
|
||||
Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack);
|
||||
|
||||
if (spinStrength == 0.0F) {
|
||||
Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack);
|
||||
FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation(
|
||||
entitythrowntrident,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Entity$getXRot(entity),
|
||||
FastNMS.INSTANCE.method$Entity$getYRot(entity),
|
||||
0.0F, 2.5F, 1.0F
|
||||
);
|
||||
if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) {
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, CoreReflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY);
|
||||
}
|
||||
|
||||
PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent(
|
||||
(Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack),
|
||||
(Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident)
|
||||
);
|
||||
if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) {
|
||||
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
|
||||
if (bukkitEntity instanceof Player player) {
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.shouldConsume()) {
|
||||
FastNMS.INSTANCE.method$ItemStack$hurtAndBreak(
|
||||
stack, 1, entity,
|
||||
FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity))
|
||||
);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack);
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entitythrowntrident,
|
||||
FastNMS.INSTANCE.method$Holder$value(sound),
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) {
|
||||
FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity);
|
||||
float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity);
|
||||
float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD);
|
||||
float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
|
||||
float length = MCUtils.sqrt(x * x + y * y + z * z);
|
||||
x = x / length * spinStrength;
|
||||
y = y / length * spinStrength;
|
||||
z = z / length * spinStrength;
|
||||
|
||||
FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z);
|
||||
FastNMS.INSTANCE.method$Entity$push(entity, x, y, z);
|
||||
FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true);
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack);
|
||||
|
||||
if (FastNMS.INSTANCE.method$Entity$onGround(entity)) {
|
||||
FastNMS.INSTANCE.method$Entity$move(entity, CoreReflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D));
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Holder$value(sound),
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean releaseUsing_1_20_5(Object stack, Object level, Object entity) {
|
||||
Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false;
|
||||
|
||||
float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity);
|
||||
|
||||
if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) {
|
||||
return false;
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
|
||||
if (spinStrength == 0.0F) {
|
||||
Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack);
|
||||
FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation(
|
||||
entitythrowntrident,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Entity$getXRot(entity),
|
||||
FastNMS.INSTANCE.method$Entity$getYRot(entity),
|
||||
0.0F, 2.5F, 1.0F
|
||||
);
|
||||
if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) {
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, CoreReflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY);
|
||||
}
|
||||
|
||||
PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent(
|
||||
(Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack),
|
||||
(Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident)
|
||||
);
|
||||
if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) {
|
||||
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
|
||||
if (bukkitEntity instanceof Player player) {
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.shouldConsume()) {
|
||||
FastNMS.INSTANCE.method$ItemStack$hurtAndBreak(
|
||||
stack, 1, entity,
|
||||
FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity))
|
||||
);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack);
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entitythrowntrident,
|
||||
MSoundEvents.TRIDENT_THROW,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) {
|
||||
FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity);
|
||||
float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity);
|
||||
float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD);
|
||||
float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
|
||||
float length = MCUtils.sqrt(x * x + y * y + z * z);
|
||||
x = x / length * spinStrength;
|
||||
y = y / length * spinStrength;
|
||||
z = z / length * spinStrength;
|
||||
|
||||
FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z);
|
||||
FastNMS.INSTANCE.method$Entity$push(entity, x, y, z);
|
||||
FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true);
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null);
|
||||
|
||||
if (FastNMS.INSTANCE.method$Entity$onGround(entity)) {
|
||||
FastNMS.INSTANCE.method$Entity$move(entity, CoreReflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D));
|
||||
}
|
||||
|
||||
Object soundeffect;
|
||||
if (spinStrength >= 3) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_3;
|
||||
} else if (spinStrength == 2) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_2;
|
||||
} else {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_1;
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entity,
|
||||
soundeffect,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean releaseUsing_1_20_3(Object stack, Object level, Object entity) {
|
||||
Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false;
|
||||
|
||||
float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity);
|
||||
|
||||
if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) {
|
||||
return false;
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
|
||||
if (spinStrength == 0.0F) {
|
||||
Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack);
|
||||
FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation(
|
||||
entitythrowntrident,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Entity$getXRot(entity),
|
||||
FastNMS.INSTANCE.method$Entity$getYRot(entity),
|
||||
0.0F, 2.5F, 1.0F
|
||||
);
|
||||
if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) {
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, CoreReflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY);
|
||||
}
|
||||
|
||||
PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent(
|
||||
(Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack),
|
||||
(Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident)
|
||||
);
|
||||
if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) {
|
||||
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
|
||||
if (bukkitEntity instanceof Player player) {
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.shouldConsume()) {
|
||||
FastNMS.INSTANCE.method$ItemStack$hurtAndBreak(
|
||||
stack, 1, entity,
|
||||
(player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity))
|
||||
);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack);
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entitythrowntrident,
|
||||
MSoundEvents.TRIDENT_THROW,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) {
|
||||
FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity);
|
||||
float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity);
|
||||
float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD);
|
||||
float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
|
||||
float length = MCUtils.sqrt(x * x + y * y + z * z);
|
||||
x = x / length * spinStrength;
|
||||
y = y / length * spinStrength;
|
||||
z = z / length * spinStrength;
|
||||
|
||||
FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z);
|
||||
FastNMS.INSTANCE.method$Entity$push(entity, x, y, z);
|
||||
FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true);
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null);
|
||||
|
||||
if (FastNMS.INSTANCE.method$Entity$onGround(entity)) {
|
||||
FastNMS.INSTANCE.method$Entity$move(entity, CoreReflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D));
|
||||
}
|
||||
|
||||
Object soundeffect;
|
||||
if (spinStrength >= 3) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_3;
|
||||
} else if (spinStrength == 2) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_2;
|
||||
} else {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_1;
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entity,
|
||||
soundeffect,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean releaseUsing_1_20(Object stack, Object level, Object entity) {
|
||||
Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false;
|
||||
|
||||
float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity);
|
||||
|
||||
if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) {
|
||||
return false;
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
|
||||
if (spinStrength == 0.0F) {
|
||||
Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack);
|
||||
FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation(
|
||||
entitythrowntrident,
|
||||
entity,
|
||||
FastNMS.INSTANCE.method$Entity$getXRot(entity),
|
||||
FastNMS.INSTANCE.method$Entity$getYRot(entity),
|
||||
0.0F, 2.5F, 1.0F
|
||||
);
|
||||
if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) {
|
||||
FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, CoreReflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY);
|
||||
}
|
||||
|
||||
PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent(
|
||||
(Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack),
|
||||
(Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident)
|
||||
);
|
||||
if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) {
|
||||
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
|
||||
if (bukkitEntity instanceof Player player) {
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.shouldConsume()) {
|
||||
FastNMS.INSTANCE.method$ItemStack$hurtAndBreak(
|
||||
stack, 1, entity,
|
||||
(player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity))
|
||||
);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.field$ThrownTrident$tridentItem(entitythrowntrident, copyStack);
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entitythrowntrident,
|
||||
MSoundEvents.TRIDENT_THROW,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) {
|
||||
FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity);
|
||||
float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity);
|
||||
float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD);
|
||||
float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD);
|
||||
|
||||
float length = MCUtils.sqrt(x * x + y * y + z * z);
|
||||
x = x / length * spinStrength;
|
||||
y = y / length * spinStrength;
|
||||
z = z / length * spinStrength;
|
||||
|
||||
FastNMS.INSTANCE.method$Entity$push(entity, x, y, z);
|
||||
FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true);
|
||||
FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1);
|
||||
FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null);
|
||||
|
||||
if (FastNMS.INSTANCE.method$Entity$onGround(entity)) {
|
||||
FastNMS.INSTANCE.method$Entity$move(entity, CoreReflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D));
|
||||
}
|
||||
|
||||
Object soundeffect;
|
||||
if (spinStrength >= 3) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_3;
|
||||
} else if (spinStrength == 2) {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_2;
|
||||
} else {
|
||||
soundeffect = MSoundEvents.TRIDENT_RIPTIDE_1;
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$Level$playSound(
|
||||
level,
|
||||
null,
|
||||
entity,
|
||||
soundeffect,
|
||||
CoreReflections.instance$SoundSource$PLAYERS,
|
||||
1.0F, 1.0F
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
|
||||
if (replaceProcessResult.changed()) {
|
||||
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(result);
|
||||
wrapped.customNameJson(AdventureHelper.componentToJson(replaceProcessResult.newText()));
|
||||
event.setResult(wrapped.load());
|
||||
event.setResult(wrapped.getItem());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
for (ItemDataModifier<ItemStack> modifier : this.modifiers) {
|
||||
modifier.apply(wrapped, context);
|
||||
}
|
||||
return wrapped.load();
|
||||
return wrapped.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +48,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
for (ItemDataModifier<ItemStack> modifier : dataModifiers()) {
|
||||
modifier.apply(wrapped, context);
|
||||
}
|
||||
return BukkitCraftEngine.instance().itemManager().wrap(wrapped.load());
|
||||
return BukkitCraftEngine.instance().itemManager().wrap(wrapped.getItem());
|
||||
}
|
||||
|
||||
public Object clientItem() {
|
||||
|
||||
@@ -83,7 +83,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
try {
|
||||
Item<ItemStack> wrapped = wrap(itemStack);
|
||||
if (wrapped == null) return Optional.empty();
|
||||
return this.networkItemHandler.s2c(wrapped, player).map(Item::load);
|
||||
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);
|
||||
@@ -96,7 +96,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
try {
|
||||
Item<ItemStack> wrapped = wrap(itemStack);
|
||||
if (wrapped == null) return Optional.empty();
|
||||
return this.networkItemHandler.c2s(wrapped).map(Item::load);
|
||||
return this.networkItemHandler.c2s(wrapped).map(Item::getItem);
|
||||
} catch (Throwable e) {
|
||||
if (Config.debug()) {
|
||||
this.plugin.logger().warn("Failed to handle c2s items.", e);
|
||||
@@ -215,14 +215,14 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerAllVanillaItems() {
|
||||
try {
|
||||
for (NamespacedKey item : FastNMS.INSTANCE.getAllVanillaItems()) {
|
||||
if (item.getNamespace().equals("minecraft")) {
|
||||
Key id = KeyUtils.namespacedKey2Key(item);
|
||||
VANILLA_ITEMS.add(id);
|
||||
Holder.Reference<Key> holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id)
|
||||
for (Object item : (Iterable<?>) MBuiltInRegistries.ITEM) {
|
||||
Object resourceLocation = FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, item);
|
||||
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(), id), id));
|
||||
Object resourceLocation = KeyUtils.toResourceLocation(id.namespace(), id.value());
|
||||
.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();
|
||||
Set<Object> tags = (Set<Object>) CoreReflections.field$Holder$Reference$tags.get(mcHolder);
|
||||
for (Object tag : tags) {
|
||||
|
||||
@@ -6,7 +6,10 @@ import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
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.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.ItemWrapper;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
@@ -19,22 +22,26 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
private final Object handle;
|
||||
|
||||
public ComponentItemWrapper(final ItemStack item) {
|
||||
this.item = FastNMS.INSTANCE.ensureCraftItemStack(item);
|
||||
this.item = ItemUtils.ensureCraftItemStack(item);
|
||||
this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item);
|
||||
}
|
||||
|
||||
public ComponentItemWrapper(final ItemStack item, int count) {
|
||||
this.item = FastNMS.INSTANCE.ensureCraftItemStack(item);
|
||||
this.item = ItemUtils.ensureCraftItemStack(item);
|
||||
this.item.setAmount(count);
|
||||
this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item);
|
||||
}
|
||||
|
||||
public void removeComponent(Object type) {
|
||||
FastNMS.INSTANCE.removeComponent(this.getLiteralObject(), ensureDataComponentType(type));
|
||||
FastNMS.INSTANCE.method$ItemStack$removeComponent(this.getLiteralObject(), ensureDataComponentType(type));
|
||||
}
|
||||
|
||||
public void resetComponent(Object type) {
|
||||
FastNMS.INSTANCE.resetComponent(this.getLiteralObject(), ensureDataComponentType(type));
|
||||
Object item = FastNMS.INSTANCE.method$ItemStack$getItem(this.getLiteralObject());
|
||||
Object componentMap = FastNMS.INSTANCE.method$Item$components(item);
|
||||
Object componentType = ensureDataComponentType(type);
|
||||
Object defaultComponent = FastNMS.INSTANCE.method$DataComponentMap$get(componentMap, componentType);
|
||||
FastNMS.INSTANCE.method$ItemStack$setComponent(this.getLiteralObject(), componentType, defaultComponent);
|
||||
}
|
||||
|
||||
public void setComponent(Object type, final Object value) {
|
||||
@@ -50,7 +57,7 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
}
|
||||
|
||||
public Object getComponentExact(Object type) {
|
||||
return FastNMS.INSTANCE.getComponent(getLiteralObject(), ensureDataComponentType(type));
|
||||
return FastNMS.INSTANCE.method$ItemStack$getComponent(getLiteralObject(), ensureDataComponentType(type));
|
||||
}
|
||||
|
||||
public <T> Optional<T> getJavaComponent(Object type) {
|
||||
@@ -74,7 +81,7 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
Object componentType = ensureDataComponentType(type);
|
||||
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);
|
||||
try {
|
||||
Object componentData = FastNMS.INSTANCE.getComponent(getLiteralObject(), componentType);
|
||||
Object componentData = FastNMS.INSTANCE.method$ItemStack$getComponent(getLiteralObject(), componentType);
|
||||
if (componentData == null) return Optional.empty();
|
||||
DataResult<Object> result = codec.encodeStart(ops, componentData);
|
||||
return (Optional<T>) result.result();
|
||||
@@ -84,11 +91,11 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
}
|
||||
|
||||
public boolean hasComponent(Object type) {
|
||||
return FastNMS.INSTANCE.hasComponent(getLiteralObject(), ensureDataComponentType(type));
|
||||
return FastNMS.INSTANCE.method$ItemStack$hasComponent(getLiteralObject(), ensureDataComponentType(type));
|
||||
}
|
||||
|
||||
public void setComponentExact(Object type, final Object value) {
|
||||
FastNMS.INSTANCE.setComponent(this.getLiteralObject(), ensureDataComponentType(type), value);
|
||||
FastNMS.INSTANCE.method$ItemStack$setComponent(this.getLiteralObject(), ensureDataComponentType(type), value);
|
||||
}
|
||||
|
||||
public void setJavaComponent(Object type, Object value) {
|
||||
@@ -120,7 +127,7 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
if (result.isError()) {
|
||||
throw new IllegalArgumentException(result.toString());
|
||||
}
|
||||
result.result().ifPresent(it -> FastNMS.INSTANCE.setComponent(this.getLiteralObject(), componentType, it));
|
||||
result.result().ifPresent(it -> FastNMS.INSTANCE.method$ItemStack$setComponent(this.getLiteralObject(), componentType, it));
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Cannot parse component " + type.toString(), t);
|
||||
}
|
||||
@@ -129,7 +136,7 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
private Object ensureDataComponentType(Object type) {
|
||||
if (!CoreReflections.clazz$DataComponentType.isInstance(type)) {
|
||||
Key key = Key.of(type.toString());
|
||||
return FastNMS.INSTANCE.getComponentType(key.namespace(), key.value());
|
||||
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.DATA_COMPONENT_TYPE, KeyUtils.toResourceLocation(key));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -146,11 +153,6 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack load() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getLiteralObject() {
|
||||
return this.handle;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.ComponentKeys;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
@@ -27,11 +29,12 @@ public class ComponentTypes {
|
||||
public static final Object PROFILE = getComponentType(ComponentKeys.PROFILE);
|
||||
public static final Object DYED_COLOR = getComponentType(ComponentKeys.DYED_COLOR);
|
||||
public static final Object DEATH_PROTECTION = getComponentType(ComponentKeys.DEATH_PROTECTION);
|
||||
public static final Object FIREWORK_EXPLOSION = getComponentType(ComponentKeys.FIREWORK_EXPLOSION);
|
||||
|
||||
private ComponentTypes() {}
|
||||
|
||||
private static Object getComponentType(Key key) {
|
||||
if (!VersionHelper.isOrAbove1_20_5()) return null;
|
||||
return FastNMS.INSTANCE.getComponentType(key.namespace(), key.value());
|
||||
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.DATA_COMPONENT_TYPE, KeyUtils.toResourceLocation(key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,60 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import com.saicone.rtag.RtagItem;
|
||||
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.core.item.ItemWrapper;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
private final RtagItem rtagItem;
|
||||
private final Object nmsStack;
|
||||
private final ItemStack itemStack;
|
||||
|
||||
public LegacyItemWrapper(RtagItem rtagItem) {
|
||||
this.rtagItem = rtagItem;
|
||||
public LegacyItemWrapper(ItemStack item) {
|
||||
this.itemStack = ItemUtils.ensureCraftItemStack(item);
|
||||
this.nmsStack = FastNMS.INSTANCE.field$CraftItemStack$handle(this.itemStack);
|
||||
}
|
||||
|
||||
public boolean setTag(Object value, Object... path) {
|
||||
Object finalNMSTag;
|
||||
if (value instanceof Tag tag) {
|
||||
return this.rtagItem.set(MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.NBT, tag), path);
|
||||
finalNMSTag = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.NBT, tag);
|
||||
} else {
|
||||
return this.rtagItem.set(value, path);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(Object value, Object... path) {
|
||||
if (value instanceof Tag tag) {
|
||||
return this.rtagItem.add(MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.NBT, tag), path);
|
||||
} else {
|
||||
return this.rtagItem.add(value, path);
|
||||
finalNMSTag = MRegistryOps.JAVA.convertTo(MRegistryOps.NBT, value);
|
||||
}
|
||||
|
||||
Object currentTag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(this.nmsStack);
|
||||
if (path == null || path.length == 0) {
|
||||
if (CoreReflections.clazz$CompoundTag.isInstance(finalNMSTag)) {
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(this.nmsStack, finalNMSTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return false;
|
||||
Object childTag = FastNMS.INSTANCE.method$CompoundTag$get(currentTag, pathSegment.toString());
|
||||
if (!CoreReflections.clazz$CompoundTag.isInstance(childTag)) {
|
||||
childTag = FastNMS.INSTANCE.constructor$CompoundTag();
|
||||
FastNMS.INSTANCE.method$CompoundTag$put(currentTag, pathSegment.toString(), childTag);
|
||||
}
|
||||
currentTag = childTag;
|
||||
}
|
||||
|
||||
String finalKey = path[path.length - 1].toString();
|
||||
FastNMS.INSTANCE.method$CompoundTag$put(currentTag, finalKey, finalNMSTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V getJavaTag(Object... path) {
|
||||
return this.rtagItem.get(path);
|
||||
Object tag = getExactTag(path);
|
||||
if (tag == null) return null;
|
||||
return (V) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
|
||||
}
|
||||
|
||||
public Tag getNBTTag(Object... path) {
|
||||
@@ -49,41 +73,73 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
}
|
||||
|
||||
public Object getExactTag(Object... path) {
|
||||
return this.rtagItem.getExact(path);
|
||||
Object compoundTag = FastNMS.INSTANCE.method$ItemStack$getTag(this.nmsStack);
|
||||
if (compoundTag == null) return null;
|
||||
Object currentTag = compoundTag;
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean remove(Object... path) {
|
||||
return this.rtagItem.remove(path);
|
||||
Object compoundTag = FastNMS.INSTANCE.method$ItemStack$getTag(this.nmsStack);
|
||||
if (compoundTag == null || path == null || path.length == 0) return false;
|
||||
|
||||
if (path.length == 1) {
|
||||
String key = path[0].toString();
|
||||
if (FastNMS.INSTANCE.method$CompoundTag$get(compoundTag, key) != null) {
|
||||
FastNMS.INSTANCE.method$CompoundTag$remove(compoundTag, key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Object currentTag = compoundTag;
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return false;
|
||||
currentTag = FastNMS.INSTANCE.method$CompoundTag$get(currentTag, path[i].toString());
|
||||
if (!CoreReflections.clazz$CompoundTag.isInstance(currentTag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String finalKey = path[path.length - 1].toString();
|
||||
if (FastNMS.INSTANCE.method$CompoundTag$get(currentTag, finalKey) != null) {
|
||||
FastNMS.INSTANCE.method$CompoundTag$remove(currentTag, finalKey);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasTag(Object... path) {
|
||||
return this.rtagItem.hasTag(path);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
this.rtagItem.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack load() {
|
||||
return this.rtagItem.load();
|
||||
return getExactTag(path) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
return this.rtagItem.getItem();
|
||||
return this.itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getLiteralObject() {
|
||||
return this.rtagItem.getLiteralObject();
|
||||
return this.nmsStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemWrapper<ItemStack> copyWithCount(int count) {
|
||||
ItemStack copied = this.rtagItem.loadCopy();
|
||||
ItemStack copied = this.itemStack.clone();
|
||||
copied.setAmount(count);
|
||||
return new LegacyItemWrapper(new RtagItem(copied));
|
||||
return new LegacyItemWrapper(copied);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,6 @@ import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
@@ -58,15 +57,12 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
BukkitBlockInWorld block = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BlockData blockData = block.block().getBlockData();
|
||||
int stateId = BlockStateUtils.blockDataToId(blockData);
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) return InteractionResult.PASS;
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return InteractionResult.PASS;
|
||||
|
||||
ImmutableBlockState customBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (customBlockState == null || customBlockState.isEmpty()) return InteractionResult.PASS;
|
||||
|
||||
Optional<StrippableBlockBehavior> behaviorOptional = customBlockState.behavior().getAs(StrippableBlockBehavior.class);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Optional<StrippableBlockBehavior> behaviorOptional = customState.behavior().getAs(StrippableBlockBehavior.class);
|
||||
if (behaviorOptional.isEmpty()) return InteractionResult.PASS;
|
||||
Key stripped = behaviorOptional.get().stripped();
|
||||
Item<ItemStack> offHandItem = (Item<ItemStack>) player.getItemInHand(InteractionHand.OFF_HAND);
|
||||
@@ -81,7 +77,7 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
CustomBlock newCustomBlock = optionalNewCustomBlock.get();
|
||||
CompoundTag compoundTag = customBlockState.propertiesNbt();
|
||||
CompoundTag compoundTag = customState.propertiesNbt();
|
||||
ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag);
|
||||
|
||||
org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());
|
||||
@@ -103,7 +99,7 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
|
||||
// resend swing if it's not interactable on client side
|
||||
if (!InteractUtils.isInteractable(
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(customBlockState.vanillaBlockState().handle()),
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(customState.vanillaBlockState().handle()),
|
||||
context.getHitResult(), item
|
||||
) || player.isSecondaryUseActive()) {
|
||||
player.swingHand(context.getHand());
|
||||
|
||||
@@ -99,13 +99,13 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
|
||||
if (player.isAdventureMode()) {
|
||||
Object againstBlockState = BlockStateUtils.blockDataToBlockState(againstBlock.getBlockData());
|
||||
int stateId = BlockStateUtils.blockStateToId(againstBlockState);
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(againstBlockState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
if (!AdventureModeUtils.canPlace(context.getItem(), context.getLevel(), againstPos, againstBlockState)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
} else {
|
||||
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
// custom block
|
||||
if (!AdventureModeUtils.canPlace(context.getItem(), context.getLevel(), againstPos, Config.simplifyAdventurePlaceCheck() ? customState.vanillaBlockState().handle() : againstBlockState)) {
|
||||
return InteractionResult.FAIL;
|
||||
@@ -157,13 +157,12 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
if (!player.isCreativeMode()) {
|
||||
Item<?> item = context.getItem();
|
||||
item.count(item.count() - 1);
|
||||
item.load();
|
||||
}
|
||||
|
||||
block.setPlacedBy(context, blockStateToPlace);
|
||||
|
||||
player.swingHand(context.getHand());
|
||||
context.getLevel().playBlockSound(position, blockStateToPlace.sounds().placeSound());
|
||||
context.getLevel().playBlockSound(position, blockStateToPlace.settings().sounds().placeSound());
|
||||
world.sendGameEvent(bukkitPlayer, GameEvent.BLOCK_PLACE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
if (!BukkitCraftEngine.instance().antiGrief().canPlace(bukkitPlayer, furnitureLocation)) {
|
||||
if (!BukkitCraftEngine.instance().antiGriefProvider().canPlace(bukkitPlayer, furnitureLocation)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
.item(item.copyWithCount(1))
|
||||
.anchorType(anchorType)
|
||||
.dyedColor(item.dyedColor().orElse(null))
|
||||
.fireworkExplosionColors(item.fireworkExplosion().map(explosion -> explosion.colors().toIntArray()).orElse(null))
|
||||
.build(), false);
|
||||
|
||||
FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand());
|
||||
@@ -158,7 +159,6 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
|
||||
if (!player.isCreativeMode()) {
|
||||
item.count(item.count() - 1);
|
||||
item.load();
|
||||
}
|
||||
|
||||
context.getLevel().playBlockSound(finalPlacePosition, customFurniture.settings().sounds().placeSound());
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
|
||||
import net.momirealms.craftengine.bukkit.util.ItemTags;
|
||||
import net.momirealms.craftengine.core.item.ItemFactory;
|
||||
import net.momirealms.craftengine.core.item.ItemWrapper;
|
||||
import net.momirealms.craftengine.core.item.JukeboxPlayable;
|
||||
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;
|
||||
@@ -69,11 +69,6 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
|
||||
return customId(item).orElse(vanillaId(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack load(W item) {
|
||||
return item.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getItem(W item) {
|
||||
return item.getItem();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.item.factory;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
@@ -9,18 +10,17 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInReg
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.bukkit.util.EnchantmentUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.Trim;
|
||||
import net.momirealms.craftengine.core.item.data.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
|
||||
import net.momirealms.craftengine.core.item.data.Trim;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemWrapper> {
|
||||
|
||||
@@ -52,8 +52,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return null;
|
||||
String key = pathSegment.toString();
|
||||
currentObj = ((Map<String, Object>) currentObj).get(key);
|
||||
currentObj = ((Map<String, Object>) currentObj).get(pathSegment.toString());
|
||||
if (currentObj == null) return null;
|
||||
if (i == path.length - 1) {
|
||||
return currentObj;
|
||||
@@ -74,8 +73,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return null;
|
||||
CompoundTag t = (CompoundTag) currentTag;
|
||||
String key = pathSegment.toString();
|
||||
currentTag = t.get(key);
|
||||
currentTag = t.get(pathSegment.toString());
|
||||
if (currentTag == null) return null;
|
||||
if (i == path.length - 1) {
|
||||
return currentTag;
|
||||
@@ -424,30 +422,6 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEnchantment(ComponentItemWrapper item, Enchantment enchantment) {
|
||||
Object enchant = item.getComponentExact(ComponentTypes.ENCHANTMENTS);
|
||||
try {
|
||||
Map<String, Integer> map = EnchantmentUtils.toMap(enchant);
|
||||
map.put(enchantment.id().toString(), enchantment.level());
|
||||
item.setJavaComponent(ComponentTypes.ENCHANTMENTS, map);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to add enchantment", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addStoredEnchantment(ComponentItemWrapper item, Enchantment enchantment) {
|
||||
Object enchant = item.getComponentExact(ComponentTypes.STORED_ENCHANTMENTS);
|
||||
try {
|
||||
Map<String, Integer> map = EnchantmentUtils.toMap(enchant);
|
||||
map.put(enchantment.id().toString(), enchantment.level());
|
||||
item.setJavaComponent(ComponentTypes.STORED_ENCHANTMENTS, map);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to add stored enchantment", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void itemFlags(ComponentItemWrapper item, List<String> flags) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
@@ -505,6 +479,41 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
return Optional.of(new Trim(trimMap.get("pattern"), trimMap.get("material")));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Optional<FireworkExplosion> fireworkExplosion(ComponentItemWrapper item) {
|
||||
Optional<Object> optionalExplosion = item.getJavaComponent(ComponentTypes.FIREWORK_EXPLOSION);
|
||||
if (optionalExplosion.isEmpty()) return Optional.empty();
|
||||
Map<String, Object> explosions = MiscUtils.castToMap(optionalExplosion.get(), false);
|
||||
FireworkExplosion.Shape shape = Optional.ofNullable(FireworkExplosion.Shape.byName((String) explosions.get("shape"))).orElse(FireworkExplosion.Shape.SMALL_BALL);
|
||||
boolean hasTrail = (boolean) explosions.getOrDefault("has_trail", false);
|
||||
boolean hasTwinkler = (boolean) explosions.getOrDefault("has_twinkle", false);
|
||||
List<Integer> colors = (List<Integer>) Optional.ofNullable(explosions.get("colors")).orElse(new IntArrayList());
|
||||
List<Integer> fadeColors = (List<Integer>) Optional.ofNullable(explosions.get("fade_colors")).orElse(new IntArrayList());
|
||||
return Optional.of(new FireworkExplosion(
|
||||
shape,
|
||||
new IntArrayList(colors),
|
||||
new IntArrayList(fadeColors),
|
||||
hasTrail,
|
||||
hasTwinkler
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireworkExplosion(ComponentItemWrapper item, FireworkExplosion explosion) {
|
||||
if (explosion == null) {
|
||||
item.resetComponent(ComponentTypes.FIREWORK_EXPLOSION);
|
||||
} else {
|
||||
item.setJavaComponent(ComponentTypes.FIREWORK_EXPLOSION, Map.of(
|
||||
"shape", explosion.shape().getName(),
|
||||
"has_trail", explosion.hasTrail(),
|
||||
"has_twinkle", explosion.hasTwinkle(),
|
||||
"colors", explosion.colors(),
|
||||
"fade_colors", explosion.fadeColors()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentItemWrapper mergeCopy(ComponentItemWrapper item1, ComponentItemWrapper item2) {
|
||||
Object itemStack1 = item1.getLiteralObject();
|
||||
|
||||
@@ -2,7 +2,7 @@ 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.item.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 {
|
||||
if (data == null) {
|
||||
item.resetComponent(ComponentTypes.EQUIPPABLE);
|
||||
} else {
|
||||
item.setJavaComponent(ComponentTypes.EQUIPPABLE, data.toMap());
|
||||
item.setSparrowNBTComponent(ComponentTypes.EQUIPPABLE, data.toNBT());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@ package net.momirealms.craftengine.bukkit.item.factory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.saicone.rtag.data.ComponentType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.core.item.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.GsonHelper;
|
||||
@@ -17,7 +16,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 {
|
||||
|
||||
public ComponentItemFactory1_21_5(CraftEngine plugin) {
|
||||
@@ -116,9 +114,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 {
|
||||
@Override
|
||||
protected Optional<JukeboxPlayable> jukeboxSong(ComponentItemWrapper item) {
|
||||
if (!item.hasComponent(ComponentTypes.JUKEBOX_PLAYABLE)) return Optional.empty();
|
||||
String song = (String) ComponentType.encodeJava(
|
||||
ComponentTypes.JUKEBOX_PLAYABLE,
|
||||
item.getComponentExact(ComponentTypes.JUKEBOX_PLAYABLE)).orElse(null);
|
||||
String song = (String) item.getJavaComponent(ComponentTypes.JUKEBOX_PLAYABLE).orElse(null);
|
||||
if (song == null) return Optional.empty();
|
||||
return Optional.of(new JukeboxPlayable(song, true));
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package net.momirealms.craftengine.bukkit.item.factory;
|
||||
|
||||
import com.saicone.rtag.RtagItem;
|
||||
import com.saicone.rtag.item.ItemObject;
|
||||
import com.saicone.rtag.tag.TagBase;
|
||||
import com.saicone.rtag.tag.TagCompound;
|
||||
import com.saicone.rtag.tag.TagList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.Trim;
|
||||
import net.momirealms.craftengine.core.item.data.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
|
||||
import net.momirealms.craftengine.core.item.data.Trim;
|
||||
import net.momirealms.craftengine.core.item.modifier.IdModifier;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -32,7 +29,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper wrapInternal(ItemStack item) {
|
||||
return new LegacyItemWrapper(new RtagItem(item));
|
||||
return new LegacyItemWrapper(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,38 +209,6 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
item.setTag(tags, "StoredEnchantments");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEnchantment(LegacyItemWrapper item, Enchantment enchantment) {
|
||||
Object enchantments = item.getExactTag("Enchantments");
|
||||
if (enchantments != null) {
|
||||
for (Object enchant : TagList.getValue(enchantments)) {
|
||||
if (TagBase.getValue(TagCompound.get(enchant, "id")).equals(enchant.toString())) {
|
||||
TagCompound.set(enchant, "lvl", TagBase.newTag(enchantment.level()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "Enchantments");
|
||||
} else {
|
||||
item.setTag(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "Enchantments");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addStoredEnchantment(LegacyItemWrapper item, Enchantment enchantment) {
|
||||
Object enchantments = item.getExactTag("StoredEnchantments");
|
||||
if (enchantments != null) {
|
||||
for (Object enchant : TagList.getValue(enchantments)) {
|
||||
if (TagBase.getValue(TagCompound.get(enchant, "id")).equals(enchant.toString())) {
|
||||
TagCompound.set(enchant, "lvl", TagBase.newTag(enchantment.level()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "StoredEnchantments");
|
||||
} else {
|
||||
item.setTag(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "StoredEnchantments");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected Optional<Enchantment> getEnchantment(LegacyItemWrapper item, Key key) {
|
||||
@@ -297,6 +262,38 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
item.setTag(trim.pattern(), "Trim", "pattern");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<FireworkExplosion> fireworkExplosion(LegacyItemWrapper item) {
|
||||
Map<String, Object> explosionObj = item.getJavaTag("Explosion");
|
||||
if (explosionObj == null) return Optional.empty();
|
||||
IntArrayList colors = (IntArrayList) explosionObj.get("Colors");
|
||||
IntArrayList fadeColors = (IntArrayList) explosionObj.get("FadeColors");
|
||||
return Optional.of(
|
||||
new FireworkExplosion(
|
||||
FireworkExplosion.Shape.byId((Integer) explosionObj.getOrDefault("Type", 0)),
|
||||
colors == null ? new IntArrayList() : new IntArrayList(colors),
|
||||
fadeColors == null ? new IntArrayList() : new IntArrayList(fadeColors),
|
||||
(boolean) explosionObj.getOrDefault("Trail", false),
|
||||
(boolean) explosionObj.getOrDefault("Flicker", false)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireworkExplosion(LegacyItemWrapper item, FireworkExplosion explosion) {
|
||||
if (explosion == null) {
|
||||
item.remove("Explosion");
|
||||
} else {
|
||||
item.setTag(Map.of(
|
||||
"Type", explosion.shape().id(),
|
||||
"Colors", explosion.colors(),
|
||||
"FadeColors", explosion.fadeColors(),
|
||||
"Trail", explosion.hasTrail(),
|
||||
"Flicker", explosion.hasTwinkle()
|
||||
), "Explosion");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<Trim> trim(LegacyItemWrapper item) {
|
||||
String material = item.getJavaTag("Trim", "material");
|
||||
@@ -307,33 +304,33 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper mergeCopy(LegacyItemWrapper item1, LegacyItemWrapper item2) {
|
||||
Object itemStack = ItemObject.copy(item2.getLiteralObject());
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(itemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject())));
|
||||
// one more step than vanilla
|
||||
TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(itemStack), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true);
|
||||
return new LegacyItemWrapper(new RtagItem(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)));
|
||||
Object copied = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$ItemStack$getItem(item2.getLiteralObject()), item2.count());
|
||||
Object copiedTag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(copied);
|
||||
FastNMS.INSTANCE.method$CompoundTag$merge(copiedTag, FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject()));
|
||||
FastNMS.INSTANCE.method$CompoundTag$merge(copiedTag, FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()));
|
||||
return new LegacyItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(copied));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void merge(LegacyItemWrapper item1, LegacyItemWrapper item2) {
|
||||
// load previous changes on nms items
|
||||
item1.load();
|
||||
TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject()), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true);
|
||||
// update wrapped item
|
||||
item1.update();
|
||||
Object item1Tag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject());
|
||||
Object item2Tag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject());
|
||||
FastNMS.INSTANCE.method$CompoundTag$merge(item1Tag, item2Tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper transmuteCopy(LegacyItemWrapper item, Key newItem, int amount) {
|
||||
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
|
||||
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)));
|
||||
Object copied = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
|
||||
Object copiedTag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(copied);
|
||||
Object thisTag = FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject());
|
||||
FastNMS.INSTANCE.method$CompoundTag$merge(copiedTag, thisTag);
|
||||
return new LegacyItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(copied));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper unsafeTransmuteCopy(LegacyItemWrapper item, Object newItem, int amount) {
|
||||
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(newItem, amount);
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
|
||||
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)));
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, FastNMS.INSTANCE.method$CompoundTag$copy(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
|
||||
return new LegacyItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(newItemStack));
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@ package net.momirealms.craftengine.bukkit.item.listener;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
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.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
@@ -58,13 +59,11 @@ public class DebugStickListener implements Listener {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData());
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(clickedBlock.getWorld()), LocationUtils.toBlockPos(clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()));
|
||||
BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> {
|
||||
event.setCancelled(true);
|
||||
boolean update = event.getAction() == Action.RIGHT_CLICK_BLOCK;
|
||||
ImmutableBlockState clickedCustomBlock = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
CustomBlock block = clickedCustomBlock.owner().value();
|
||||
CustomBlock block = customState.owner().value();
|
||||
Collection<Property<?>> properties = block.properties();
|
||||
String blockId = block.id().toString();
|
||||
try {
|
||||
@@ -84,7 +83,7 @@ public class DebugStickListener implements Listener {
|
||||
currentProperty = properties.iterator().next();
|
||||
}
|
||||
if (update) {
|
||||
ImmutableBlockState nextState = cycleState(clickedCustomBlock, currentProperty, player.isSecondaryUseActive());
|
||||
ImmutableBlockState nextState = cycleState(customState, currentProperty, player.isSecondaryUseActive());
|
||||
CraftEngineBlocks.place(clickedBlock.getLocation(), nextState, new UpdateOption.Builder().updateClients().updateKnownShape().build(), false);
|
||||
Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance(
|
||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update")
|
||||
@@ -97,21 +96,20 @@ public class DebugStickListener implements Listener {
|
||||
currentProperty = getRelative(properties, currentProperty, player.isSecondaryUseActive());
|
||||
data.put(blockId, currentProperty.name());
|
||||
wrapped.setTag(data, "craftengine:debug_stick_state");
|
||||
wrapped.load();
|
||||
Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance(
|
||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.select")
|
||||
.arguments(
|
||||
Component.text(currentProperty.name()),
|
||||
Component.text(getNameHelper(clickedCustomBlock, currentProperty))
|
||||
Component.text(getNameHelper(customState, currentProperty))
|
||||
)), true);
|
||||
player.sendPacket(systemChatPacket, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to send system chat packet", e);
|
||||
this.plugin.logger().warn("Failed to send system chat packet", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> ImmutableBlockState cycleState(ImmutableBlockState state, Property<T> property, boolean inverse) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.item.listener;
|
||||
|
||||
import io.papermc.paper.event.block.CompostItemEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitCustomItem;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
@@ -112,8 +111,7 @@ public class ItemEventListener implements Listener {
|
||||
Block block = Objects.requireNonNull(event.getClickedBlock());
|
||||
BlockData blockData = block.getBlockData();
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(blockData);
|
||||
ImmutableBlockState immutableBlockState = null;
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null);
|
||||
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(hand);
|
||||
Location interactionPoint = event.getInteractionPoint();
|
||||
|
||||
@@ -126,8 +124,7 @@ public class ItemEventListener implements Listener {
|
||||
}
|
||||
|
||||
// 处理自定义方块
|
||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
if (immutableBlockState != null) {
|
||||
// call the event if it's custom
|
||||
CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent(
|
||||
player,
|
||||
|
||||
@@ -130,7 +130,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
} else if (VersionHelper.isOrAbove1_20_2()) {
|
||||
nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe);
|
||||
} else {
|
||||
return () -> {};
|
||||
Object finalNmsRecipe0 = nmsRecipe;
|
||||
return () -> registerNMSSmithingRecipe(finalNmsRecipe0);
|
||||
}
|
||||
Object finalNmsRecipe = nmsRecipe;
|
||||
return () -> registerNMSSmithingRecipe(finalNmsRecipe);
|
||||
|
||||
@@ -643,7 +643,7 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
afterPenalty = calculateIncreasedRepairCost(afterPenalty);
|
||||
wrappedFirst.repairCost(afterPenalty);
|
||||
event.setResult(wrappedFirst.load());
|
||||
event.setResult(wrappedFirst.getItem());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,8 +757,8 @@ public class RecipeEventListener implements Listener {
|
||||
int remainingDurability = totalMaxDamage - totalDamage;
|
||||
int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability);
|
||||
newItem.damage(newItemDamage);
|
||||
inventory.setResult(newItem.load());
|
||||
} else if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) {
|
||||
inventory.setResult(newItem.getItem());
|
||||
} else if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe) || CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) {
|
||||
ItemStack[] itemStacks = inventory.getMatrix();
|
||||
for (ItemStack itemStack : itemStacks) {
|
||||
if (itemStack == null) continue;
|
||||
|
||||
@@ -111,7 +111,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new LocalizedResourceConfigException("warning.config.vanilla_loot.invalid_type", type, EnumUtils.toString(VanillaLoot.Type.values()));
|
||||
}
|
||||
boolean override = (boolean) section.getOrDefault("override", false);
|
||||
boolean override = ResourceConfigUtils.getAsBoolean(section.getOrDefault("override", false), "override");
|
||||
List<String> targets = MiscUtils.getAsStringList(section.getOrDefault("target", List.of()));
|
||||
LootTable<?> lootTable = LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), false));
|
||||
switch (typeEnum) {
|
||||
|
||||
@@ -108,6 +108,7 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
if (super.blockManager != null) return;
|
||||
try {
|
||||
BlockGenerator.init();
|
||||
BlockStateGenerator.init();
|
||||
super.blockManager = new BukkitBlockManager(this);
|
||||
} catch (Exception e) {
|
||||
throw new InjectionException("Error injecting blocks", e);
|
||||
@@ -365,7 +366,7 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
);
|
||||
}
|
||||
|
||||
public AntiGriefLib antiGrief() {
|
||||
public AntiGriefLib antiGriefProvider() {
|
||||
if (this.antiGrief == null) {
|
||||
this.antiGrief = AntiGriefLib.builder(this.javaPlugin)
|
||||
.ignoreOP(true)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin;
|
||||
|
||||
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;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -19,14 +22,36 @@ public class BukkitPlatform implements Platform {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object nbt2Java(String nbt) {
|
||||
public Object snbtToJava(String nbt) {
|
||||
try {
|
||||
Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}");
|
||||
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.template.argument.default_value.invalid_syntax", e, nbt);
|
||||
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag jsonToSparrowNBT(JsonElement json) {
|
||||
return MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag snbtToSparrowNBT(String nbt) {
|
||||
try {
|
||||
Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag javaToSparrowNBT(Object object) {
|
||||
return MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
||||
new DebugIsSectionInjectedCommand(this, plugin),
|
||||
new DebugMigrateTemplatesCommand(this, plugin),
|
||||
new DebugIsChunkPersistentLoadedCommand(this, plugin),
|
||||
new DebugEntityId2UUIDCommand(this, plugin),
|
||||
new TotemAnimationCommand(this, plugin),
|
||||
new EnableResourceCommand(this, plugin),
|
||||
new DisableResourceCommand(this, plugin),
|
||||
|
||||
@@ -42,7 +42,9 @@ public class BukkitSenderFactory extends SenderFactory<BukkitCraftEngine, Comman
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// we can safely send async for players and the console - otherwise, send it sync
|
||||
if (sender instanceof Player player) {
|
||||
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(message), false));
|
||||
FastNMS.INSTANCE.method$Connection$send(
|
||||
FastNMS.INSTANCE.field$ServerGamePacketListenerImpl$connection(FastNMS.INSTANCE.field$Player$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player))),
|
||||
FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(message), false));
|
||||
} else if (sender instanceof ConsoleCommandSender commandSender) {
|
||||
commandSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message));
|
||||
} else if (sender instanceof RemoteConsoleCommandSender commandSender) {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
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.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
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 DebugEntityId2UUIDCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugEntityId2UUIDCommand(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");
|
||||
Entity entity = FastNMS.INSTANCE.getBukkitEntityById(world, entityId);
|
||||
if (entity == null) {
|
||||
context.sender().sendMessage("entity not found");
|
||||
return;
|
||||
}
|
||||
Location location = entity.getLocation();
|
||||
context.sender().sendMessage(
|
||||
String.format(
|
||||
"""
|
||||
===========================
|
||||
uuid: %s
|
||||
name: %s
|
||||
location: %s,%s,%s
|
||||
type: %s
|
||||
===========================
|
||||
""",
|
||||
entity.getUniqueId(),
|
||||
entity.getName(),
|
||||
location.x(), location.y(), location.z(),
|
||||
entity.getType()
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_entity_id_to_uuid";
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.plugin.command.FlagKeys;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import com.saicone.rtag.RtagMirror;
|
||||
import com.saicone.rtag.tag.TagCompound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
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.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
@@ -30,11 +27,9 @@ public class DebugItemDataCommand extends BukkitCommandFeature<CommandSender> {
|
||||
.handler(context -> {
|
||||
ItemStack itemInHand = context.sender().getInventory().getItemInMainHand();
|
||||
if (ItemUtils.isEmpty(itemInHand)) {
|
||||
plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("Please hold an item").color(NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
Map<String, Object> readableMap = toReadableMap(itemInHand);
|
||||
readableMap.remove("rtagDataVersion");
|
||||
Map<String, Object> readableMap = toMap(itemInHand);
|
||||
List<String> readableList = mapToList(readableMap);
|
||||
StringJoiner joiner = new StringJoiner("<newline><reset>");
|
||||
for (String text : readableList) {
|
||||
@@ -49,13 +44,10 @@ public class DebugItemDataCommand extends BukkitCommandFeature<CommandSender> {
|
||||
return "debug_item_data";
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, Object> toReadableMap(ItemStack item) {
|
||||
return toMap(item);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> toMap(ItemStack object) {
|
||||
return TagCompound.getValue(RtagMirror.INSTANCE, FastNMS.INSTANCE.itemStackToCompoundTag(object));
|
||||
Object tag = FastNMS.INSTANCE.method$itemStack$save(FastNMS.INSTANCE.field$CraftItemStack$handle(object), FastNMS.INSTANCE.constructor$CompoundTag());
|
||||
return (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
|
||||
}
|
||||
|
||||
private List<String> mapToList(Map<String, Object> readableDataMap) {
|
||||
|
||||
@@ -2,9 +2,9 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.core.block.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import org.bukkit.Location;
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.parser.standard.EnumParser;
|
||||
@@ -75,7 +76,7 @@ public class ReloadCommand extends BukkitCommandFeature<CommandSender> {
|
||||
} else if (argument == ReloadArgument.ALL) {
|
||||
RELOAD_PACK_FLAG = true;
|
||||
try {
|
||||
plugin().reloadPlugin(plugin().scheduler().async(), r -> plugin().scheduler().sync().run(r), true).thenAcceptAsync(reloadResult -> {
|
||||
plugin().reloadPlugin(plugin().scheduler().async(), r -> plugin().scheduler().sync().run(r), !VersionHelper.isFolia()).thenAcceptAsync(reloadResult -> {
|
||||
try {
|
||||
long time1 = System.currentTimeMillis();
|
||||
plugin().packManager().generateResourcePack();
|
||||
|
||||
@@ -79,7 +79,7 @@ public class TotemAnimationCommand extends BukkitCommandFeature<CommandSender> {
|
||||
item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of());
|
||||
}
|
||||
}
|
||||
ItemStack totemItem = item.load();
|
||||
ItemStack totemItem = item.getItem();
|
||||
MultiplePlayerSelector selector = context.get("players");
|
||||
for (Player player : selector.values()) {
|
||||
PlayerUtils.sendTotemAnimation(player, totemItem);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.injector;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.ClassFileVersion;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
@@ -17,7 +18,11 @@ 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.NoteBlockChainUpdateUtils;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.BlockKeys;
|
||||
import net.momirealms.craftengine.core.block.BlockShape;
|
||||
import net.momirealms.craftengine.core.block.DelegatingBlock;
|
||||
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -30,6 +35,7 @@ import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BlockGenerator {
|
||||
private static final BukkitBlockShape STONE_SHAPE =
|
||||
@@ -53,16 +59,14 @@ public final class BlockGenerator {
|
||||
.defineField("isClientSideNoteBlock", boolean.class, Visibility.PUBLIC)
|
||||
.defineField("isClientSideTripwire", boolean.class, Visibility.PUBLIC)
|
||||
// should always implement this interface
|
||||
.implement(DelegatingBlock.class)
|
||||
.implement(CoreReflections.clazz$Fallable)
|
||||
.implement(CoreReflections.clazz$BonemealableBlock)
|
||||
.implement(CoreReflections.clazz$SimpleWaterloggedBlock)
|
||||
// internal interfaces
|
||||
.implement(BehaviorHolder.class)
|
||||
.implement(ShapeHolder.class)
|
||||
.implement(ChainUpdateBlockIndicator.class)
|
||||
.method(ElementMatchers.named("getBehaviorHolder"))
|
||||
.method(ElementMatchers.named("behaviorDelegate"))
|
||||
.intercept(FieldAccessor.ofField("behaviorHolder"))
|
||||
.method(ElementMatchers.named("getShapeHolder"))
|
||||
.method(ElementMatchers.named("shapeDelegate"))
|
||||
.intercept(FieldAccessor.ofField("shapeHolder"))
|
||||
.method(ElementMatchers.named("isNoteBlock"))
|
||||
.intercept(FieldAccessor.ofField("isClientSideNoteBlock"))
|
||||
@@ -201,6 +205,12 @@ public final class BlockGenerator {
|
||||
field$CraftEngineBlock$shape.set(newBlockInstance, shapeHolder);
|
||||
field$CraftEngineBlock$isNoteBlock.set(newBlockInstance, replacedBlock.equals(BlockKeys.NOTE_BLOCK));
|
||||
field$CraftEngineBlock$isTripwire.set(newBlockInstance, replacedBlock.equals(BlockKeys.TRIPWIRE));
|
||||
|
||||
Object stateDefinitionBuilder = CoreReflections.constructor$StateDefinition$Builder.newInstance(newBlockInstance);
|
||||
Object stateDefinition = CoreReflections.method$StateDefinition$Builder$create.invoke(stateDefinitionBuilder,
|
||||
(Function<Object, Object>) FastNMS.INSTANCE::method$Block$defaultState, BlockStateGenerator.instance$StateDefinition$Factory);
|
||||
CoreReflections.field$Block$StateDefinition.set(newBlockInstance, stateDefinition);
|
||||
CoreReflections.field$Block$defaultBlockState.set(newBlockInstance, ((ImmutableList<?>) CoreReflections.field$StateDefinition$states.get(stateDefinition)).getFirst());
|
||||
return newBlockInstance;
|
||||
}
|
||||
|
||||
@@ -210,10 +220,11 @@ public final class BlockGenerator {
|
||||
public static final int directionIndex = VersionHelper.isOrAbove1_21_2() ? 4 : 1;
|
||||
public static final int posIndex = VersionHelper.isOrAbove1_21_2() ? 3 : 4;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ChainUpdateBlockIndicator indicator = (ChainUpdateBlockIndicator) thisObj;
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
DelegatingBlock indicator = (DelegatingBlock) thisObj;
|
||||
// todo chain updater
|
||||
if (indicator.isNoteBlock()) {
|
||||
if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
|
||||
@@ -254,7 +265,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockShape> holder = ((ShapeHolder) thisObj).getShapeHolder();
|
||||
ObjectHolder<BlockShape> holder = ((DelegatingBlock) thisObj).shapeDelegate();
|
||||
try {
|
||||
return holder.value().getShape(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -269,7 +280,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockShape> holder = ((ShapeHolder) thisObj).getShapeHolder();
|
||||
ObjectHolder<BlockShape> holder = ((DelegatingBlock) thisObj).shapeDelegate();
|
||||
try {
|
||||
return holder.value().getCollisionShape(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -284,7 +295,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockShape> holder = ((ShapeHolder) thisObj).getShapeHolder();
|
||||
ObjectHolder<BlockShape> holder = ((DelegatingBlock) thisObj).shapeDelegate();
|
||||
try {
|
||||
return holder.value().getSupportShape(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -299,7 +310,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().isPathFindable(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -314,7 +325,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().mirror(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -329,7 +340,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().rotate(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -344,7 +355,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().randomTick(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -358,7 +369,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().tick(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -372,7 +383,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().onPlace(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -386,7 +397,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().onLand(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -400,7 +411,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().onBrokenAfterFall(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -414,7 +425,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().canSurvive(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -429,7 +440,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().isBoneMealSuccess(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -444,7 +455,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().isValidBoneMealTarget(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -459,7 +470,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().performBoneMeal(thisObj, args);
|
||||
} catch (Exception e) {
|
||||
@@ -473,7 +484,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().neighborChanged(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -487,7 +498,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().onExplosionHit(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -501,7 +512,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().pickupBlock(thisObj, args, () -> CoreReflections.instance$ItemStack$EMPTY);
|
||||
} catch (Exception e) {
|
||||
@@ -516,7 +527,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().placeLiquid(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -531,7 +542,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().canPlaceLiquid(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -546,7 +557,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public int intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().getDirectSignal(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -561,7 +572,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public int intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().getSignal(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -576,7 +587,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().isSignalSource(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -591,7 +602,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().affectNeighborsAfterRemoval(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -605,7 +616,7 @@ public final class BlockGenerator {
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
holder.value().entityInside(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.injector;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.ClassFileVersion;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bind.annotation.AllArguments;
|
||||
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
|
||||
import net.bytebuddy.implementation.bind.annotation.This;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
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.MBlockStateProperties;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.BlockSettings;
|
||||
import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.List;
|
||||
|
||||
public final class BlockStateGenerator {
|
||||
private static MethodHandle constructor$CraftEngineBlockState;
|
||||
public static Object instance$StateDefinition$Factory;
|
||||
|
||||
public static void init() throws ReflectiveOperationException {
|
||||
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
|
||||
String packageWithName = BlockStateGenerator.class.getName();
|
||||
String generatedStateClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineBlockState";
|
||||
DynamicType.Builder<?> stateBuilder = byteBuddy
|
||||
.subclass(CoreReflections.clazz$BlockState, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
||||
.name(generatedStateClassName)
|
||||
.defineField("immutableBlockState", ImmutableBlockState.class, Visibility.PUBLIC)
|
||||
.implement(DelegatingBlockState.class)
|
||||
.method(ElementMatchers.named("blockState"))
|
||||
.intercept(FieldAccessor.ofField("immutableBlockState"))
|
||||
.method(ElementMatchers.named("setBlockState"))
|
||||
.intercept(FieldAccessor.ofField("immutableBlockState"))
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockStateBase$getDrops))
|
||||
.intercept(MethodDelegation.to(GetDropsInterceptor.INSTANCE))
|
||||
.method(ElementMatchers.is(CoreReflections.method$StateHolder$hasProperty))
|
||||
.intercept(MethodDelegation.to(HasPropertyInterceptor.INSTANCE))
|
||||
.method(ElementMatchers.is(CoreReflections.method$StateHolder$getValue))
|
||||
.intercept(MethodDelegation.to(GetPropertyValueInterceptor.INSTANCE))
|
||||
.method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue))
|
||||
.intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE));
|
||||
Class<?> clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded();
|
||||
constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ?
|
||||
MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
|
||||
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class))
|
||||
.asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) :
|
||||
MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
|
||||
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class))
|
||||
.asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class));
|
||||
|
||||
String generatedFactoryClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineStateFactory";
|
||||
DynamicType.Builder<?> factoryBuilder = byteBuddy
|
||||
.subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
||||
.name(generatedFactoryClassName)
|
||||
.implement(CoreReflections.clazz$StateDefinition$Factory)
|
||||
.method(ElementMatchers.named("create"))
|
||||
.intercept(MethodDelegation.to(CreateStateInterceptor.INSTANCE));
|
||||
|
||||
Class<?> clazz$Factory = factoryBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded();
|
||||
instance$StateDefinition$Factory = ReflectionUtils.getTheOnlyConstructor(clazz$Factory).newInstance();
|
||||
}
|
||||
|
||||
public static class GetDropsInterceptor {
|
||||
public static final GetDropsInterceptor INSTANCE = new GetDropsInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
ImmutableBlockState state = ((DelegatingBlockState) thisObj).blockState();
|
||||
if (state == null) return List.of();
|
||||
Object builder = args[0];
|
||||
Object vec3 = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.ORIGIN);
|
||||
if (vec3 == null) return List.of();
|
||||
|
||||
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);
|
||||
|
||||
// do not drop if it's not the correct tool
|
||||
BlockSettings settings = state.settings();
|
||||
if (optionalPlayer != null && settings.requireCorrectTool()) {
|
||||
if (item == null) return List.of();
|
||||
if (!settings.isCorrectTool(item.id()) &&
|
||||
(!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(tool, state.customBlockState().handle()))) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
Object serverLevel = FastNMS.INSTANCE.method$LootParams$Builder$getLevel(builder);
|
||||
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) {
|
||||
lootBuilder.withParameter(DirectContextParameters.ITEM_IN_HAND, item);
|
||||
}
|
||||
|
||||
BukkitServerPlayer player = optionalPlayer != null ? BukkitCraftEngine.instance().adapt(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(optionalPlayer)) : null;
|
||||
Float radius = (Float) FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.EXPLOSION_RADIUS);
|
||||
if (radius != null) {
|
||||
lootBuilder.withParameter(DirectContextParameters.EXPLOSION_RADIUS, radius);
|
||||
}
|
||||
return state.getDrops(lootBuilder, world, player).stream().map(Item::getLiteralObject).toList();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HasPropertyInterceptor {
|
||||
public static final HasPropertyInterceptor INSTANCE = new HasPropertyInterceptor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
Object property = args[0];
|
||||
if (property != MBlockStateProperties.WATERLOGGED) return false;
|
||||
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
|
||||
ImmutableBlockState state = customState.blockState();
|
||||
if (state == null) return false;
|
||||
Property<Boolean> waterloggedProperty = (Property<Boolean>) state.owner().value().getProperty("waterlogged");
|
||||
return waterloggedProperty != null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetPropertyValueInterceptor {
|
||||
public static final GetPropertyValueInterceptor INSTANCE = new GetPropertyValueInterceptor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
Object property = args[0];
|
||||
if (property != MBlockStateProperties.WATERLOGGED) return null;
|
||||
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
|
||||
ImmutableBlockState state = customState.blockState();
|
||||
if (state == null) return null;
|
||||
Property<Boolean> waterloggedProperty = (Property<Boolean>) state.owner().value().getProperty("waterlogged");
|
||||
if (waterloggedProperty == null) return null;
|
||||
return state.get(waterloggedProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetPropertyValueInterceptor {
|
||||
public static final SetPropertyValueInterceptor INSTANCE = new SetPropertyValueInterceptor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
Object property = args[0];
|
||||
if (property != MBlockStateProperties.WATERLOGGED) return thisObj;
|
||||
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
|
||||
ImmutableBlockState state = customState.blockState();
|
||||
if (state == null) return thisObj;
|
||||
Property<Boolean> waterloggedProperty = (Property<Boolean>) state.owner().value().getProperty("waterlogged");
|
||||
if (waterloggedProperty == null) return thisObj;
|
||||
return state.with(waterloggedProperty, (boolean) args[1]).customBlockState().handle();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateStateInterceptor {
|
||||
public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) throws Throwable {
|
||||
return constructor$CraftEngineBlockState.invoke(args[0], args[1], args[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import net.bytebuddy.implementation.bind.annotation.SuperCall;
|
||||
import net.bytebuddy.implementation.bind.annotation.This;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
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.util.BlockStateUtils;
|
||||
@@ -34,6 +33,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -217,10 +217,10 @@ public class WorldStorageInjector {
|
||||
|
||||
protected static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) {
|
||||
try {
|
||||
int stateId = BlockStateUtils.blockStateToId(newState);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(newState);
|
||||
CESection section = holder.ceSection();
|
||||
// 如果是原版方块
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
// 那么应该清空自定义块
|
||||
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
|
||||
// 处理 自定义块 -> 原版块
|
||||
@@ -235,7 +235,7 @@ public class WorldStorageInjector {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState);
|
||||
if (previousImmutableBlockState == immutableBlockState) return;
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
|
||||
@@ -104,7 +104,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
// register packet handlers
|
||||
this.registerPacketHandlers();
|
||||
// set up packet senders
|
||||
this.packetConsumer = FastNMS.INSTANCE::sendPacket;
|
||||
this.packetConsumer = FastNMS.INSTANCE::method$Connection$send;
|
||||
this.packetsConsumer = ((connection, packets) -> {
|
||||
Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
|
||||
this.packetConsumer.accept(connection, bundle);
|
||||
@@ -114,7 +114,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
|
||||
this.immediatePacketConsumer.accept(channel, bundle);
|
||||
};
|
||||
// todo 可以删除吗
|
||||
// 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);
|
||||
@@ -302,7 +301,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
}
|
||||
|
||||
public Channel getChannel(Player player) {
|
||||
return (Channel) FastNMS.INSTANCE.field$Player$connection$connection$channel(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player));
|
||||
return FastNMS.INSTANCE.field$Connection$channel(
|
||||
FastNMS.INSTANCE.field$ServerGamePacketListenerImpl$connection(
|
||||
FastNMS.INSTANCE.field$Player$connection(
|
||||
FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslationArgument;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
|
||||
@@ -994,7 +995,7 @@ public class PacketConsumers {
|
||||
float zDist = buf.readFloat();
|
||||
float maxSpeed = buf.readFloat();
|
||||
int count = buf.readInt();
|
||||
Object option = FastNMS.INSTANCE.method$ParticleTypes$STREAM_CODEC$decode(buf);
|
||||
Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf);
|
||||
if (option == null) return;
|
||||
if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return;
|
||||
Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option);
|
||||
@@ -1016,7 +1017,7 @@ public class PacketConsumers {
|
||||
buf.writeFloat(zDist);
|
||||
buf.writeFloat(maxSpeed);
|
||||
buf.writeInt(count);
|
||||
FastNMS.INSTANCE.method$ParticleTypes$STREAM_CODEC$encode(buf, remappedOption);
|
||||
FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e);
|
||||
}
|
||||
@@ -1034,7 +1035,7 @@ public class PacketConsumers {
|
||||
float zDist = buf.readFloat();
|
||||
float maxSpeed = buf.readFloat();
|
||||
int count = buf.readInt();
|
||||
Object option = FastNMS.INSTANCE.method$ParticleTypes$STREAM_CODEC$decode(buf);
|
||||
Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf);
|
||||
if (option == null) return;
|
||||
if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return;
|
||||
Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option);
|
||||
@@ -1055,7 +1056,7 @@ public class PacketConsumers {
|
||||
buf.writeFloat(zDist);
|
||||
buf.writeFloat(maxSpeed);
|
||||
buf.writeInt(count);
|
||||
FastNMS.INSTANCE.method$ParticleTypes$STREAM_CODEC$encode(buf, remappedOption);
|
||||
FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e);
|
||||
}
|
||||
@@ -1316,7 +1317,7 @@ public class PacketConsumers {
|
||||
if (result == null) return;
|
||||
Block hitBlock = result.getHitBlock();
|
||||
if (hitBlock == null) return;
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(hitBlock.getBlockData()));
|
||||
ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(hitBlock);
|
||||
// not a custom block
|
||||
if (state == null || state.isEmpty()) return;
|
||||
Key itemId = state.settings().itemId();
|
||||
@@ -1550,7 +1551,7 @@ public class PacketConsumers {
|
||||
if (EventUtils.fireAndCheckCancel(preBreakEvent))
|
||||
return;
|
||||
|
||||
if (!BukkitCraftEngine.instance().antiGrief().canBreak(platformPlayer, location))
|
||||
if (!BukkitCraftEngine.instance().antiGriefProvider().canBreak(platformPlayer, location))
|
||||
return;
|
||||
|
||||
FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture);
|
||||
@@ -1646,11 +1647,13 @@ public class PacketConsumers {
|
||||
LocationUtils.toBlockPos(hitResult.blockPos())
|
||||
);
|
||||
} else {
|
||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
||||
if (furniture.tryOccupySeat(seatPos)) {
|
||||
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos);
|
||||
}
|
||||
});
|
||||
if (!serverPlayer.isSecondaryUseActive()) {
|
||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
||||
if (furniture.tryOccupySeat(seatPos)) {
|
||||
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if (actionType == 0) {
|
||||
@@ -1722,7 +1725,7 @@ public class PacketConsumers {
|
||||
Optional<Object> optionalSound = FastNMS.INSTANCE.method$IdMap$byId(MBuiltInRegistries.SOUND_EVENT, id - 1);
|
||||
if (optionalSound.isEmpty()) return;
|
||||
Object soundEvent = optionalSound.get();
|
||||
Key soundId = Key.of(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent));
|
||||
Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent));
|
||||
int source = buf.readVarInt();
|
||||
int x = buf.readInt();
|
||||
int y = buf.readInt();
|
||||
|
||||
@@ -147,15 +147,4 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
onGround
|
||||
);
|
||||
}
|
||||
|
||||
private Object convertCustomProjectileTeleportPacket(Object packet, int entityId) {
|
||||
float xRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xRot(packet));
|
||||
float yRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$yRot(packet));
|
||||
boolean onGround = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$onGround(packet);
|
||||
return FastNMS.INSTANCE.constructor$ClientboundTeleportEntityPacket(
|
||||
entityId, this.projectile.projectile().x(), this.projectile.projectile().y(), this.projectile.projectile().z(),
|
||||
MCUtils.packDegrees(-yRot), MCUtils.packDegrees(MCUtils.clamp(-xRot, -90.0F, 90.0F)),
|
||||
onGround
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ public class PacketIdFinder {
|
||||
}
|
||||
}
|
||||
} else if (VersionHelper.isOrAbove1_20_5()) {
|
||||
gamePacketIdsByName.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByName());
|
||||
gamePacketIdsByName.putAll(FastNMS.INSTANCE.gamePacketIdsByName());
|
||||
} else {
|
||||
gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByClazz());
|
||||
gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.gamePacketIdsByClazz());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to get packets", e);
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -494,6 +495,13 @@ public final class CoreReflections {
|
||||
}).orElseThrow()
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ParticleTypes = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"core.particles.Particles",
|
||||
"core.particles.ParticleTypes"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$MappedRegistry = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"core.RegistryMaterials",
|
||||
@@ -1152,6 +1160,28 @@ public final class CoreReflections {
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$StateDefinition$Builder = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.BlockStateList$a",
|
||||
"world.level.block.state.StateDefinition$Builder"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$StateDefinition$Factory = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.BlockStateList$b",
|
||||
"world.level.block.state.StateDefinition$Factory"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Constructor<?> constructor$StateDefinition$Builder = requireNonNull(
|
||||
ReflectionUtils.getTheOnlyConstructor(clazz$StateDefinition$Builder)
|
||||
);
|
||||
|
||||
public static final Method method$StateDefinition$Builder$create = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$StateDefinition$Builder, clazz$StateDefinition, Function.class, clazz$StateDefinition$Factory)
|
||||
);
|
||||
|
||||
public static final Field field$Block$StateDefinition = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$Block, clazz$StateDefinition, 0)
|
||||
);
|
||||
@@ -1290,7 +1320,6 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 8)
|
||||
);
|
||||
|
||||
|
||||
public static final Field field$BlockStateBase$lightEmission = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, int.class, 0)
|
||||
);
|
||||
@@ -1572,8 +1601,8 @@ public final class CoreReflections {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Method method$Block$defaultBlockState = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$Block, clazz$BlockState)
|
||||
public static final Field field$Block$defaultBlockState = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$Block, clazz$BlockState, 0)
|
||||
);
|
||||
|
||||
public static final Method method$Entity$getOnPos = requireNonNull(
|
||||
@@ -1661,10 +1690,6 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Entity, double.class, 2)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$hasTag = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$TagKey)
|
||||
);
|
||||
|
||||
public static final Method method$Level$removeBlock = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$Level, boolean.class, clazz$BlockPos, boolean.class)
|
||||
);
|
||||
@@ -1690,6 +1715,10 @@ public final class CoreReflections {
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$Property$name = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$Property, String.class, 0)
|
||||
);
|
||||
|
||||
public static final Field field$LeavesBlock$DISTANCE = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$LeavesBlock, clazz$IntegerProperty, 0)
|
||||
);
|
||||
@@ -1702,6 +1731,9 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getMethod(clazz$StateHolder, Object.class, new String[] {"getValue", "c"}, clazz$Property)
|
||||
);
|
||||
|
||||
public static final Method method$StateHolder$setValue = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$StateHolder, Object.class, new String[] {"setValue", VersionHelper.isOrAbove1_21_2() ? "b" : "a"}, clazz$Property, Comparable.class)
|
||||
);
|
||||
|
||||
public static final Method method$Block$updateFromNeighbourShapes = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$Block, clazz$BlockState, clazz$BlockState, clazz$LevelAccessor, clazz$BlockPos)
|
||||
@@ -2117,6 +2149,10 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getMethod(clazz$ConfiguredFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$PlacedFeature$place = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$PlacedFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$BonemealableBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.IBlockFragilePlantElement",
|
||||
@@ -2221,6 +2257,27 @@ public final class CoreReflections {
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$FireworkRocketRecipe = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.crafting.RecipeFireworks",
|
||||
"world.item.crafting.FireworkRocketRecipe"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$FireworkStarRecipe = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.crafting.RecipeFireworksStar",
|
||||
"world.item.crafting.FireworkStarRecipe"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$FireworkStarFadeRecipe = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.crafting.RecipeFireworksFade",
|
||||
"world.item.crafting.FireworkStarFadeRecipe"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$AnvilMenu = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.inventory.ContainerAnvil",
|
||||
@@ -2462,10 +2519,6 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockInWorld, clazz$BlockState, 0)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$getBlock = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, clazz$Block)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$getDescriptionId = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2()
|
||||
? ReflectionUtils.getMethod(clazz$BlockBehaviour, String.class)
|
||||
@@ -3503,4 +3556,36 @@ public final class CoreReflections {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$LootParams$Builder = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.storage.loot.LootParams$a",
|
||||
"world.level.storage.loot.LootParams$Builder"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$getDrops = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, List.class, clazz$LootParams$Builder)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$LootContextParams = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.storage.loot.parameters.LootContextParameters",
|
||||
"world.level.storage.loot.parameters.LootContextParams"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$BlockStateProperties = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.properties.BlockProperties",
|
||||
"world.level.block.state.properties.BlockStateProperties"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$CompoundTag = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"nbt.NBTTagCompound",
|
||||
"nbt.CompoundTag"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public final class MBlockStateProperties {
|
||||
public static final Object WATERLOGGED;
|
||||
|
||||
static {
|
||||
try {
|
||||
Object waterlogged = null;
|
||||
for (Field field : CoreReflections.clazz$BlockStateProperties.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) {
|
||||
Object instance = field.get(null);
|
||||
if (CoreReflections.clazz$Property.isInstance(instance) && CoreReflections.field$Property$name.get(instance).equals("waterlogged")) {
|
||||
waterlogged = instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
WATERLOGGED = requireNonNull(waterlogged);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init MBlockStateProperties", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,14 @@ public final class MBlocks {
|
||||
static {
|
||||
try {
|
||||
AIR = getById("air");
|
||||
AIR$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(AIR);
|
||||
AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
|
||||
FIRE = getById("fire");
|
||||
SOUL_FIRE = getById("soul_fire");
|
||||
STONE = getById("stone");
|
||||
STONE$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(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 = CoreReflections.method$Block$defaultBlockState.invoke(SHORT_GRASS);
|
||||
SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
|
||||
SHULKER_BOX = getById("shulker_box");
|
||||
COMPOSTER = getById("composter");
|
||||
} catch (ReflectiveOperationException e) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -18,6 +20,7 @@ public final class MBuiltInRegistries {
|
||||
public static final Object FLUID;
|
||||
public static final Object RECIPE_TYPE;
|
||||
public static final Object PARTICLE_TYPE;
|
||||
public static final Object DATA_COMPONENT_TYPE;
|
||||
|
||||
static {
|
||||
Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields();
|
||||
@@ -31,6 +34,7 @@ public final class MBuiltInRegistries {
|
||||
Object registries$Item = null;
|
||||
Object registries$Fluid = null;
|
||||
Object registries$RecipeType = null;
|
||||
Object registries$DataComponentType = null;
|
||||
for (Field field : fields) {
|
||||
Type fieldType = field.getGenericType();
|
||||
if (fieldType instanceof ParameterizedType paramType) {
|
||||
@@ -43,6 +47,8 @@ public final class MBuiltInRegistries {
|
||||
registries$EntityType = field.get(null);
|
||||
} else if (rawType == CoreReflections.clazz$RecipeType) {
|
||||
registries$RecipeType = field.get(null);
|
||||
} else if (rawType == CoreReflections.clazz$DataComponentType && registries$DataComponentType == null) {
|
||||
registries$DataComponentType = field.get(null);
|
||||
}
|
||||
} else {
|
||||
if (type == CoreReflections.clazz$Block) {
|
||||
@@ -70,8 +76,9 @@ public final class MBuiltInRegistries {
|
||||
ENTITY_TYPE = requireNonNull(registries$EntityType);
|
||||
FLUID = requireNonNull(registries$Fluid);
|
||||
RECIPE_TYPE = requireNonNull(registries$RecipeType);
|
||||
DATA_COMPONENT_TYPE = registries$DataComponentType;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new ReflectionInitException("Failed to init BuiltInRegistries", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public final class MLootContextParams {
|
||||
public static final Object THIS_ENTITY;
|
||||
public static final Object ORIGIN;
|
||||
public static final Object TOOL;
|
||||
public static final Object EXPLOSION_RADIUS;
|
||||
|
||||
static {
|
||||
try {
|
||||
Object params$THIS_ENTITY = null;
|
||||
Object params$ORIGIN = null;
|
||||
Object params$TOOL = null;
|
||||
Object params$EXPLOSION_RADIUS = null;
|
||||
Field[] fields = CoreReflections.clazz$LootContextParams.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
Type fieldType = field.getGenericType();
|
||||
if (fieldType instanceof ParameterizedType paramType) {
|
||||
Type type = paramType.getActualTypeArguments()[0];
|
||||
if (type == CoreReflections.clazz$Entity && params$THIS_ENTITY == null) {
|
||||
params$THIS_ENTITY = field.get(null);
|
||||
} else if (type == CoreReflections.clazz$ItemStack) {
|
||||
params$TOOL = field.get(null);
|
||||
} else if (type == CoreReflections.clazz$Vec3) {
|
||||
params$ORIGIN = field.get(null);
|
||||
} else if (type == Float.class) {
|
||||
params$EXPLOSION_RADIUS = field.get(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
THIS_ENTITY = requireNonNull(params$THIS_ENTITY);
|
||||
TOOL = requireNonNull(params$TOOL);
|
||||
ORIGIN = requireNonNull(params$ORIGIN);
|
||||
EXPLOSION_RADIUS = requireNonNull(params$EXPLOSION_RADIUS);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init LootContextParams", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public final class MRegistryOps {
|
||||
// 1.20.1-1.20.4
|
||||
JAVA = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, LegacyJavaOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
} else {
|
||||
JAVA = null;
|
||||
throw new ReflectionInitException("Could not find JavaOps");
|
||||
}
|
||||
NBT = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, ReflectionUtils.getDeclaredField(clazz$NbtOps, clazz$NbtOps, 0).get(null), FastNMS.INSTANCE.registryAccess());
|
||||
JSON = (DynamicOps<JsonElement>) CoreReflections.method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
|
||||
@@ -99,7 +99,6 @@ public final class NetworkReflections {
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
public static final Field field$ClientboundBossEventPacket$AddOperation$name = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$ClientboundBossEventPacket$AddOperation, 0)
|
||||
);
|
||||
@@ -397,7 +396,6 @@ public final class NetworkReflections {
|
||||
ReflectionUtils.getDeclaredField(clazz$ClientboundLevelChunkWithLightPacket, clazz$ClientboundLevelChunkPacketData, 0)
|
||||
);
|
||||
|
||||
|
||||
public static final Field field$ClientboundLevelChunkWithLightPacket$x = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$ClientboundLevelChunkWithLightPacket, int.class, 0)
|
||||
);
|
||||
@@ -1484,4 +1482,19 @@ public final class NetworkReflections {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$StreamCodec = BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"network.codec.StreamCodec",
|
||||
"network.codec.StreamCodec"
|
||||
);
|
||||
|
||||
public static final Object instance$ParticleTypes$STREAM_CODEC;
|
||||
|
||||
static {
|
||||
try {
|
||||
instance$ParticleTypes$STREAM_CODEC = !VersionHelper.isOrAbove1_20_5() ? null :
|
||||
ReflectionUtils.getDeclaredField(CoreReflections.clazz$ParticleTypes, clazz$StreamCodec, 0).get(null);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to initialize ParticleTypes$STREAM_CODEC", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ public class FoliaExecutor implements RegionExecutor<World> {
|
||||
public SchedulerTask runLater(Runnable runnable, long delay, World world, int x, int z) {
|
||||
if (world == null) {
|
||||
if (delay <= 0) {
|
||||
return new FoliaTask(Bukkit.getGlobalRegionScheduler().runDelayed(plugin.javaPlugin(), scheduledTask -> runnable.run(), delay));
|
||||
} else {
|
||||
return new FoliaTask(Bukkit.getGlobalRegionScheduler().run(plugin.javaPlugin(), scheduledTask -> runnable.run()));
|
||||
} else {
|
||||
return new FoliaTask(Bukkit.getGlobalRegionScheduler().runDelayed(plugin.javaPlugin(), scheduledTask -> runnable.run(), delay));
|
||||
}
|
||||
} else {
|
||||
if (delay <= 0) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
@@ -450,15 +450,15 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
return;
|
||||
}
|
||||
int stateId = BlockStateUtils.blockDataToId(hitBlock.getBlockData());
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
ImmutableBlockState nextBlock = CraftEngineBlocks.getCustomBlockState(hitBlock);
|
||||
if (nextBlock == null) {
|
||||
if (!this.clientSideCanBreak) {
|
||||
setClientSideCanBreakBlock(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.clientSideCanBreak) {
|
||||
setClientSideCanBreakBlock(false);
|
||||
} else {
|
||||
if (this.clientSideCanBreak) {
|
||||
setClientSideCanBreakBlock(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,10 +612,10 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
|
||||
float progressToAdd = getDestroyProgress(destroyedState, hitPos);
|
||||
int id = BlockStateUtils.blockStateToId(destroyedState);
|
||||
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(id);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(destroyedState);
|
||||
// double check custom block
|
||||
if (customState != null && !customState.isEmpty()) {
|
||||
if (optionalCustomState.isPresent()) {
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
BlockSettings blockSettings = customState.settings();
|
||||
if (blockSettings.requireCorrectTool()) {
|
||||
if (item != null) {
|
||||
@@ -655,10 +655,10 @@ public class BukkitServerPlayer extends Player {
|
||||
if (canBreak(hitPos, customState.vanillaBlockState().handle())) {
|
||||
// Error might occur so we use try here
|
||||
try {
|
||||
FastNMS.INSTANCE.setMayBuild(serverPlayer, true);
|
||||
FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer, true);
|
||||
CoreReflections.method$ServerPlayerGameMode$destroyBlock.invoke(gameMode, blockPos);
|
||||
} finally {
|
||||
FastNMS.INSTANCE.setMayBuild(serverPlayer, false);
|
||||
FastNMS.INSTANCE.field$Player$mayBuild(serverPlayer, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -666,7 +666,7 @@ public class BukkitServerPlayer extends Player {
|
||||
CoreReflections.method$ServerPlayerGameMode$destroyBlock.invoke(gameMode, blockPos);
|
||||
}
|
||||
// send break particle + (removed sounds)
|
||||
sendPacket(FastNMS.INSTANCE.constructor$ClientboundLevelEventPacket(WorldEvents.BLOCK_BREAK_EFFECT, blockPos, id, false), false);
|
||||
sendPacket(FastNMS.INSTANCE.constructor$ClientboundLevelEventPacket(WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId(), false), false);
|
||||
this.lastSuccessfulBreak = currentTick;
|
||||
this.destroyPos = null;
|
||||
this.setIsDestroyingBlock(false, false);
|
||||
@@ -691,7 +691,14 @@ public class BukkitServerPlayer extends Player {
|
||||
double d1 = (double) hitPos.y() - otherLocation.getY();
|
||||
double d2 = (double) hitPos.z() - otherLocation.getZ();
|
||||
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
||||
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(other)), packet);
|
||||
FastNMS.INSTANCE.method$Connection$send(
|
||||
FastNMS.INSTANCE.field$ServerGamePacketListenerImpl$connection(
|
||||
FastNMS.INSTANCE.field$Player$connection(
|
||||
FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)
|
||||
)
|
||||
),
|
||||
packet
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,7 +708,7 @@ public class BukkitServerPlayer extends Player {
|
||||
if (this.lastUpdateInteractionRangeTick + 20 > gameTicks()) {
|
||||
return this.cachedInteractionRange;
|
||||
}
|
||||
this.cachedInteractionRange = FastNMS.INSTANCE.getInteractionRange(serverPlayer());
|
||||
this.cachedInteractionRange = FastNMS.INSTANCE.method$Player$getInteractionRange(serverPlayer());
|
||||
this.lastUpdateInteractionRangeTick = gameTicks();
|
||||
return this.cachedInteractionRange;
|
||||
}
|
||||
@@ -807,7 +814,9 @@ public class BukkitServerPlayer extends Player {
|
||||
if (this.connection == null) {
|
||||
Object serverPlayer = serverPlayer();
|
||||
if (serverPlayer != null) {
|
||||
this.connection = (ChannelHandler) FastNMS.INSTANCE.field$Player$connection$connection(serverPlayer);
|
||||
this.connection = (ChannelHandler) FastNMS.INSTANCE.field$ServerGamePacketListenerImpl$connection(
|
||||
FastNMS.INSTANCE.field$Player$connection(serverPlayer)
|
||||
);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot init or find connection instance for player " + name());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.sound;
|
||||
|
||||
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.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
@@ -19,7 +20,10 @@ public class BukkitSoundManager extends AbstractSoundManager {
|
||||
|
||||
public BukkitSoundManager(CraftEngine plugin) {
|
||||
super(plugin);
|
||||
VANILLA_SOUND_EVENTS.addAll(FastNMS.INSTANCE.getAllVanillaSounds().stream().map(it -> Key.of(it.getNamespace(), it.getKey())).toList());
|
||||
for (Object soundEvent : (Iterable<?>) MBuiltInRegistries.SOUND_EVENT) {
|
||||
Object resourceLocation = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
|
||||
VANILLA_SOUND_EVENTS.add(KeyUtils.resourceLocationToKey(resourceLocation));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,7 +29,7 @@ public class AdventureModeUtils {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return FastNMS.INSTANCE.canBreakInAdventureMode(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack), blockInWorld);
|
||||
return FastNMS.INSTANCE.method$ItemStack$canBreakInAdventureMode(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack), blockInWorld);
|
||||
}
|
||||
|
||||
public static boolean canPlace(Item<?> itemStack, World world, BlockPos pos, Object state) {
|
||||
@@ -44,7 +44,7 @@ public class AdventureModeUtils {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return FastNMS.INSTANCE.canPlaceInAdventureMode(item, blockInWorld);
|
||||
return FastNMS.INSTANCE.method$ItemStack$canPlaceInAdventureMode(item, blockInWorld);
|
||||
}
|
||||
|
||||
public static boolean canPlace(ItemStack itemStack, Location pos, Object state) {
|
||||
@@ -58,6 +58,6 @@ public class AdventureModeUtils {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return FastNMS.INSTANCE.canPlaceInAdventureMode(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack), blockInWorld);
|
||||
return FastNMS.INSTANCE.method$ItemStack$canPlaceInAdventureMode(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack), blockInWorld);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
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.*;
|
||||
import net.momirealms.craftengine.core.block.BlockSettings;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.util.Instrument;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MapColor;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -65,34 +59,6 @@ public class BlockStateUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Object> getAllBlockStates(String blockState) {
|
||||
int index = blockState.indexOf('[');
|
||||
if (index == -1) {
|
||||
return getAllBlockStates(Key.of(blockState));
|
||||
} else {
|
||||
String blockTypeString = blockState.substring(0, index);
|
||||
Key block = Key.of(blockTypeString);
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(block);
|
||||
if (optionalCustomBlock.isPresent()) {
|
||||
ImmutableBlockState state = BlockStateParser.deserialize(blockState);
|
||||
if (state == null) {
|
||||
return List.of();
|
||||
} else {
|
||||
return List.of(state.customBlockState().handle());
|
||||
}
|
||||
} else {
|
||||
BlockData blockData = Bukkit.createBlockData(blockState);
|
||||
return List.of(blockDataToBlockState(blockData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Object> getAllBlockStates(Key block) {
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(block);
|
||||
return optionalCustomBlock.map(customBlock -> customBlock.variantProvider().states().stream().map(it -> it.customBlockState().handle()).toList())
|
||||
.orElseGet(() -> getAllVanillaBlockStates(block));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Object> getAllVanillaBlockStates(Key block) {
|
||||
try {
|
||||
@@ -104,14 +70,6 @@ public class BlockStateUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static Object createBlockUpdatePacket(BlockPos pos, ImmutableBlockState state) {
|
||||
try {
|
||||
return NetworkReflections.constructor$ClientboundBlockUpdatePacket.newInstance(LocationUtils.toBlockPos(pos), state.customBlockState().handle());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockData fromBlockData(Object blockState) {
|
||||
return FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState);
|
||||
}
|
||||
@@ -120,28 +78,14 @@ public class BlockStateUtils {
|
||||
return blockStateToId(blockDataToBlockState(blockData));
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerId(Block block) {
|
||||
return getBlockOwnerIdFromData(block.getBlockData());
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerIdFromData(BlockData block) {
|
||||
Object blockState = blockDataToBlockState(block);
|
||||
return getBlockOwnerIdFromState(blockState);
|
||||
return getBlockOwnerIdFromState(blockDataToBlockState(block));
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerIdFromState(Object blockState) {
|
||||
return getBlockOwnerIdFromString(blockState.toString());
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerIdFromString(String id) {
|
||||
int first = id.indexOf('{');
|
||||
int last = id.indexOf('}');
|
||||
if (first != -1 && last != -1 && last > first) {
|
||||
String blockId = id.substring(first + 1, last);
|
||||
return Key.of(blockId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid block ID format: " + id);
|
||||
}
|
||||
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState);
|
||||
Object resourceLocation = FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.BLOCK, blockOwner);
|
||||
return KeyUtils.resourceLocationToKey(resourceLocation);
|
||||
}
|
||||
|
||||
public static Object blockDataToBlockState(BlockData blockData) {
|
||||
@@ -160,86 +104,12 @@ public class BlockStateUtils {
|
||||
return FastNMS.INSTANCE.method$BlockState$getBlock(blockState);
|
||||
}
|
||||
|
||||
public static int physicsEventToId(BlockPhysicsEvent event) throws ReflectiveOperationException {
|
||||
Object blockData = CraftBukkitReflections.field$BlockPhysicsEvent$changed.get(event);
|
||||
Object blockState = CraftBukkitReflections.field$CraftBlockData$data.get(blockData);
|
||||
return FastNMS.INSTANCE.method$IdMapper$getId(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, blockState);
|
||||
}
|
||||
|
||||
public static Object physicsEventToState(BlockPhysicsEvent event) throws ReflectiveOperationException {
|
||||
Object blockData = CraftBukkitReflections.field$BlockPhysicsEvent$changed.get(event);
|
||||
return CraftBukkitReflections.field$CraftBlockData$data.get(blockData);
|
||||
}
|
||||
|
||||
public static void setLightEmission(Object state, int emission) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$lightEmission.set(state, emission);
|
||||
}
|
||||
|
||||
public static int getLightEmission(Object state) {
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$getLightEmission(state);
|
||||
}
|
||||
|
||||
public static void setMapColor(Object state, MapColor color) throws ReflectiveOperationException {
|
||||
Object mcMapColor = CoreReflections.method$MapColor$byId.invoke(null, color.id);
|
||||
CoreReflections.field$BlockStateBase$mapColor.set(state, mcMapColor);
|
||||
}
|
||||
|
||||
public static void setInstrument(Object state, Instrument instrument) throws ReflectiveOperationException {
|
||||
Object mcInstrument = ((Object[]) CoreReflections.method$NoteBlockInstrument$values.invoke(null))[instrument.ordinal()];
|
||||
CoreReflections.field$BlockStateBase$instrument.set(state, mcInstrument);
|
||||
}
|
||||
|
||||
public static void setHardness(Object state, float hardness) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$hardness.set(state, hardness);
|
||||
}
|
||||
|
||||
public static void setBurnable(Object state, boolean burnable) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$burnable.set(state, burnable);
|
||||
}
|
||||
|
||||
public static void setUseShapeForLightOcclusion(Object state, boolean useShapeForLightOcclusion) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(state, useShapeForLightOcclusion);
|
||||
}
|
||||
|
||||
public static void setPushReaction(Object state, PushReaction reaction) throws ReflectiveOperationException {
|
||||
Object pushReaction = ((Object[]) CoreReflections.method$PushReaction$values.invoke(null))[reaction.ordinal()];
|
||||
CoreReflections.field$BlockStateBase$pushReaction.set(state, pushReaction);
|
||||
}
|
||||
|
||||
public static void setIsRandomlyTicking(Object state, boolean randomlyTicking) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$isRandomlyTicking.set(state, randomlyTicking);
|
||||
}
|
||||
|
||||
public static void setReplaceable(Object state, boolean replaceable) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$replaceable.set(state, replaceable);
|
||||
}
|
||||
|
||||
public static boolean isReplaceable(Object state) {
|
||||
try {
|
||||
return (boolean) CoreReflections.field$BlockStateBase$replaceable.get(state);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to get replaceable property", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCanOcclude(Object state, boolean canOcclude) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$canOcclude.set(state, canOcclude);
|
||||
}
|
||||
|
||||
public static boolean isOcclude(Object state) {
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$canOcclude(state);
|
||||
}
|
||||
|
||||
public static void setIsRedstoneConductor(Object state, Object predicate) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$isRedstoneConductor.set(state, predicate);
|
||||
}
|
||||
|
||||
public static void setIsSuffocating(Object state, Object predicate) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$isSuffocating.set(state, predicate);
|
||||
}
|
||||
|
||||
public static void setIsViewBlocking(Object state, Object predicate) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$isViewBlocking.set(state, predicate);
|
||||
public static boolean isReplaceable(Object state) {
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isReplaceable(state);
|
||||
}
|
||||
|
||||
public static boolean isClientSideNoteBlock(Object state) {
|
||||
@@ -247,8 +117,11 @@ public class BlockStateUtils {
|
||||
}
|
||||
|
||||
public static boolean isVanillaBlock(Object state) {
|
||||
int id = blockStateToId(state);
|
||||
return id >= 0 && id < vanillaStateSize;
|
||||
return !(state instanceof DelegatingBlockState);
|
||||
}
|
||||
|
||||
public static boolean isCustomBlock(Object state) {
|
||||
return state instanceof DelegatingBlockState;
|
||||
}
|
||||
|
||||
public static boolean isVanillaBlock(int id) {
|
||||
@@ -259,6 +132,14 @@ public class BlockStateUtils {
|
||||
return vanillaStateSize;
|
||||
}
|
||||
|
||||
public static Optional<ImmutableBlockState> getOptionalCustomBlockState(Object state) {
|
||||
if (state instanceof DelegatingBlockState holder) {
|
||||
return Optional.ofNullable(holder.blockState());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBurnable(Object state) {
|
||||
Object blockOwner = getBlockOwner(state);
|
||||
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
@@ -8,11 +8,11 @@ public class FeatureUtils {
|
||||
|
||||
private FeatureUtils() {}
|
||||
|
||||
public static Object createFeatureKey(Key id) {
|
||||
try {
|
||||
return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
public static Object createConfiguredFeatureKey(Key id) {
|
||||
return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
}
|
||||
|
||||
public static Object createPlacedFeatureKey(Key id) {
|
||||
return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.PLACED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -33,4 +35,12 @@ public class ItemUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ItemStack ensureCraftItemStack(ItemStack itemStack) {
|
||||
if (CraftBukkitReflections.clazz$CraftItemStack.isInstance(itemStack)) {
|
||||
return itemStack;
|
||||
} else {
|
||||
return FastNMS.INSTANCE.method$CraftItemStack$asCraftCopy(itemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
public class KeyUtils {
|
||||
|
||||
public final class KeyUtils {
|
||||
private KeyUtils() {}
|
||||
|
||||
public static Key resourceLocationToKey(Object resourceLocation) {
|
||||
return Key.of(FastNMS.INSTANCE.method$ResourceLocation$namespace(resourceLocation), FastNMS.INSTANCE.method$ResourceLocation$path(resourceLocation));
|
||||
}
|
||||
|
||||
public static Key namespacedKey2Key(NamespacedKey key) {
|
||||
return Key.of(key.getNamespace(), key.getKey());
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ public class LightUtils {
|
||||
Object chunkPos = FastNMS.INSTANCE.constructor$ChunkPos((int) chunkKey, (int) (chunkKey >> 32));
|
||||
Object lightPacket = FastNMS.INSTANCE.constructor$ClientboundLightUpdatePacket(chunkPos, lightEngine, entry.getValue(), entry.getValue());
|
||||
for (Object player : players) {
|
||||
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(player), lightPacket);
|
||||
FastNMS.INSTANCE.method$ServerPlayerConnection$send(
|
||||
FastNMS.INSTANCE.field$Player$connection(player),
|
||||
lightPacket);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
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.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
@@ -38,14 +36,9 @@ public final class ParticleUtils {
|
||||
@Nullable
|
||||
public static Particle getParticle(Key particle) {
|
||||
return CACHE.computeIfAbsent(particle, k -> {
|
||||
try {
|
||||
Object nmsParticle = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.PARTICLE_TYPE, KeyUtils.toResourceLocation(particle));
|
||||
if (nmsParticle == null) return null;
|
||||
return FastNMS.INSTANCE.method$CraftParticle$toBukkit(nmsParticle);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to get particle: " + particle, e);
|
||||
return null;
|
||||
}
|
||||
Object nmsParticle = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.PARTICLE_TYPE, KeyUtils.toResourceLocation(particle));
|
||||
if (nmsParticle == null) return null;
|
||||
return FastNMS.INSTANCE.method$CraftParticle$toBukkit(nmsParticle);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package net.momirealms.craftengine.bukkit.world;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
@@ -23,7 +21,7 @@ public class BukkitBlockInWorld implements BlockInWorld {
|
||||
|
||||
@Override
|
||||
public boolean canBeReplaced(BlockPlaceContext context) {
|
||||
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(this.block.getBlockData()));
|
||||
ImmutableBlockState customState = CraftEngineBlocks.getCustomBlockState(this.block);
|
||||
if (customState != null && !customState.isEmpty()) {
|
||||
return customState.behavior().canBeReplaced(context, customState);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user