9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 12:29:15 +00:00
This commit is contained in:
XiaoMoMi
2025-06-28 03:23:07 +08:00
parent 72108295e1
commit 7da8d75dad
36 changed files with 428 additions and 603 deletions

View File

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

View File

@@ -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,16 +32,13 @@ 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 {
@@ -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);
}
}
} else {
// override vanilla block loots
@@ -254,19 +221,6 @@ public class BlockEventListener implements Listener {
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 {
// override vanilla block loots
this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> {
if (it.override()) {
@@ -326,44 +280,6 @@ public class BlockEventListener implements Listener {
}
}
@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;

View File

@@ -28,7 +28,6 @@ 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 {

View File

@@ -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,15 @@ 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) {
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)));
world.playBlockSound(position, customState.sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
}
world.playBlockSound(position, currentState.sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
}
});
}
}
@@ -69,19 +59,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 +72,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.sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return state;

View File

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

View File

@@ -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;
@@ -85,29 +83,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;

View File

@@ -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();

View File

@@ -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,6 +31,7 @@ import org.bukkit.World;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class CropBlockBehavior extends BukkitBlockBehavior {
@@ -90,13 +89,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 +114,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 +131,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 +147,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 +164,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);
}

View File

@@ -18,11 +18,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;
@@ -83,20 +80,15 @@ 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]));
@@ -117,13 +109,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.sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return blockState;
@@ -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;
}
@@ -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
);

View File

@@ -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];
}
@@ -88,21 +82,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.sounds().destroySound());
}
}

View File

@@ -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;
@@ -93,14 +92,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 +112,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 +135,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 +156,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 +167,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 +177,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 +197,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 +214,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 +222,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)) {

View File

@@ -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;
@@ -15,13 +14,13 @@ 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.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.World;
import org.bukkit.block.Block;
import java.util.Map;
import java.util.Optional;
public class GrassBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
@@ -38,18 +37,19 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
}
@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) {
@@ -80,20 +80,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());

View File

@@ -13,6 +13,7 @@ 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;
public class LampBlockBehavior extends BukkitBlockBehavior {
@@ -34,20 +35,16 @@ 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);
}
}
@@ -63,7 +60,9 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
if (lit) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 4);
} else {
// TODO Call Event
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
return;
}
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);
}
}

View File

@@ -6,25 +6,18 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
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;
@@ -113,16 +106,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 +127,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,7 +154,7 @@ 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)) {

View File

@@ -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);
@@ -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) {

View File

@@ -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();
@@ -59,12 +59,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);

View File

@@ -16,9 +16,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;
@@ -60,30 +57,20 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
@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.sounds().breakSound());
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
return MBlocks.AIR$defaultState;
}
return state;
@@ -205,9 +192,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

View File

@@ -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;
@@ -33,11 +33,11 @@ import java.util.concurrent.Callable;
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 +55,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);
@@ -101,18 +102,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 +150,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());
@@ -177,7 +174,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("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"));
}
}

View File

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

View File

@@ -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;
@@ -54,127 +52,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 {

View File

@@ -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,6 +15,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static final Factory FACTORY = new Factory();
@@ -56,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 {

View File

@@ -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;
@@ -75,10 +74,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;
}
@@ -126,12 +126,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;
}
@@ -139,9 +139,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);
}
}
@@ -149,16 +149,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))) {
@@ -168,7 +169,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);
@@ -185,7 +186,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))
@@ -193,8 +194,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);
}
}

View File

@@ -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) {

View File

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

View File

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

View File

@@ -1,11 +1,8 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import com.saicone.rtag.RtagMirror;
import com.saicone.rtag.item.ItemTagStream;
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.util.ItemUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;

View File

@@ -13,12 +13,23 @@ 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.MItems;
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.CustomBlockStateHolder;
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.ReflectionUtils;
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;
@@ -69,7 +80,37 @@ public final class BlockStateGenerator {
ImmutableBlockState state = ((CustomBlockStateHolder) thisObj).customBlockState();
if (state == null) return List.of();
Object builder = args[0];
return List.of(FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1));
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));
// do not drop if it's not the correct tool
BlockSettings settings = state.settings();
if (settings.requireCorrectTool()) {
if (tool == 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);
}
Object optionalPlayer = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.THIS_ENTITY);
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();
}
}

View File

@@ -1691,10 +1691,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)
);
@@ -2492,10 +2488,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)
@@ -3545,5 +3537,10 @@ public final class CoreReflections {
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"
)
);
}

View File

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

View File

@@ -10,7 +10,6 @@ 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.gui.CraftEngineInventoryHolder;
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders;

View File

@@ -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.CustomBlockStateHolder;
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;
@@ -138,6 +132,14 @@ public class BlockStateUtils {
return vanillaStateSize;
}
public static Optional<ImmutableBlockState> getOptionalCustomBlockState(Object state) {
if (state instanceof CustomBlockStateHolder holder) {
return Optional.ofNullable(holder.customBlockState());
} else {
return Optional.empty();
}
}
public static boolean isBurnable(Object state) {
Object blockOwner = getBlockOwner(state);
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;

View File

@@ -3,7 +3,6 @@ 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 net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;

View File

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