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

faster nms

This commit is contained in:
XiaoMoMi
2025-04-02 20:22:11 +08:00
parent e99b924d01
commit 70cf61d9ed
33 changed files with 458 additions and 153 deletions

View File

@@ -108,11 +108,11 @@ public final class CraftEngineBlocks {
boolean playSound) {
boolean success;
try {
Object worldServer = Reflections.field$CraftWorld$ServerLevel.get(location.getWorld());
Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld());
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
Object blockState = block.customBlockState().handle();
Object oldBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos);
success = (boolean) Reflections.method$LevelWriter$setBlock.invoke(worldServer, blockPos, blockState, option.flags());
success = FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState, option.flags());
if (success) {
Reflections.method$BlockStateBase$onPlace.invoke(blockState, worldServer, blockPos, oldBlockState, true);
if (playSound) {

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block;
import io.papermc.paper.event.block.BlockBreakBlockEvent;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.*;
@@ -316,10 +317,10 @@ public class BlockEventListener implements Listener {
Block sourceBlock = event.getSourceBlock();
BlockFace direction = sourceBlock.getFace(block);
if (direction == BlockFace.UP || direction == BlockFace.DOWN) {
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world);
Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel);
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world);
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
Object blockPos = LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, blockPos);
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
if (direction == BlockFace.UP) {
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$UP, blockPos, 0);
} else {

View File

@@ -0,0 +1,121 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.MirrorUtils;
import net.momirealms.craftengine.bukkit.util.RotationUtils;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.util.Mirror;
import net.momirealms.craftengine.core.util.Rotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
public class BukkitBlockBehavior extends AbstractBlockBehavior {
private static final Map<String, BiConsumer<BukkitBlockBehavior, Property<?>>> HARD_CODED_PROPERTY_DATA = new HashMap<>();
static {
HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> {
@SuppressWarnings("unchecked")
Property<Direction.Axis> axisProperty = (Property<Direction.Axis>) property;
behavior.rotateFunction = (thisBlock, blockState, rotation) -> {
Direction.Axis axis = blockState.get(axisProperty);
return switch (rotation) {
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> switch (axis) {
case X -> blockState.with(axisProperty, Direction.Axis.Z).customBlockState().handle();
case Z -> blockState.with(axisProperty, Direction.Axis.X).customBlockState().handle();
default -> blockState.customBlockState().handle();
};
default -> blockState.customBlockState().handle();
};
};
});
HARD_CODED_PROPERTY_DATA.put("facing", (behavior, property) -> {
if (property.valueClass() == HorizontalDirection.class) {
@SuppressWarnings("unchecked")
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property;
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty).toDirection()).toHorizontalDirection())
.customBlockState().handle();
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
Rotation rotation = mirror.getRotation(blockState.get(directionProperty).toDirection());
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
};
} else if (property.valueClass() == Direction.class) {
@SuppressWarnings("unchecked")
Property<Direction> directionProperty = (Property<Direction>) property;
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty)))
.customBlockState().handle();
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
Rotation rotation = mirror.getRotation(blockState.get(directionProperty));
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
};
}
});
HARD_CODED_PROPERTY_DATA.put("facing_clockwise", (behavior, property) -> {
if (property.valueClass() == Direction.class) {
@SuppressWarnings("unchecked")
Property<Direction> directionProperty = (Property<Direction>) property;
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty)))
.customBlockState().handle();
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
Rotation rotation = mirror.getRotation(blockState.get(directionProperty));
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
};
}
});
}
private MirrorFunction mirrorFunction;
private RotateFunction rotateFunction;
public BukkitBlockBehavior(CustomBlock customBlock) {
super(customBlock);
for (Property<?> property : customBlock.properties()) {
Optional.ofNullable(HARD_CODED_PROPERTY_DATA.get(property.name())).ifPresent(
c -> c.accept(this, property)
);
}
}
@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]));
}
return super.mirror(thisBlock, args, superMethod);
}
@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]));
}
return super.rotate(thisBlock, args, superMethod);
}
@FunctionalInterface
interface MirrorFunction {
Object mirror(Object thisBlock, ImmutableBlockState state, Mirror mirror) throws Exception;
}
@FunctionalInterface
interface RotateFunction {
Object rotate(Object thisBlock, ImmutableBlockState state, Rotation rotation) throws Exception;
}
}

View File

@@ -9,7 +9,6 @@ import net.momirealms.craftengine.bukkit.util.Reflections;
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.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.parameter.LootParameters;
@@ -29,14 +28,15 @@ import org.bukkit.Registry;
import java.util.*;
import java.util.concurrent.Callable;
public class BushBlockBehavior extends AbstractBlockBehavior {
public class BushBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
protected final List<Object> tagsCanSurviveOn;
protected final Set<Object> blocksCansSurviveOn;
protected final Set<String> customBlocksCansSurviveOn;
protected final boolean any;
public BushBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
public BushBlockBehavior(CustomBlock block, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
super(block);
this.tagsCanSurviveOn = tagsCanSurviveOn;
this.blocksCansSurviveOn = blocksCansSurviveOn;
this.customBlocksCansSurviveOn = customBlocksCansSurviveOn;
@@ -93,7 +93,7 @@ public class BushBlockBehavior extends AbstractBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new BushBlockBehavior(tuple.left(), tuple.mid(), tuple.right());
return new BushBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right());
}
}

View File

@@ -32,9 +32,9 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior {
private Object defaultBlockState;
private ImmutableBlockState defaultImmutableBlockState;
public ConcretePowderBlockBehavior(float hurtAmount, int maxHurt, Key block) {
super(hurtAmount, maxHurt);
this.targetBlock = block;
public ConcretePowderBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt, Key targetBlock) {
super(block, hurtAmount, maxHurt);
this.targetBlock = targetBlock;
}
public ImmutableBlockState defaultImmutableBlockState() {
@@ -161,7 +161,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior {
if (solidBlock == null) {
throw new IllegalArgumentException("No `solid-block` specified for concrete powder block behavior");
}
return new ConcretePowderBlockBehavior(hurtAmount, hurtMax, Key.of(solidBlock));
return new ConcretePowderBlockBehavior(block, hurtAmount, hurtMax, Key.of(solidBlock));
}
}
}

View File

@@ -29,9 +29,9 @@ public class CropBlockBehavior extends BushBlockBehavior {
private final float growSpeed;
private final int minGrowLight;
public CropBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn,
public CropBlockBehavior(CustomBlock block, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn,
Property<Integer> ageProperty, float growSpeed, int minGrowLight) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
this.ageProperty = (IntegerProperty) ageProperty;
this.growSpeed = growSpeed;
this.minGrowLight = minGrowLight;
@@ -63,7 +63,7 @@ public class CropBlockBehavior extends BushBlockBehavior {
if (currentState != null && !currentState.isEmpty()) {
int age = this.getAge(currentState);
if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
Reflections.method$Level$setBlock.invoke(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
}
}
}
@@ -117,7 +117,7 @@ public class CropBlockBehavior extends BushBlockBehavior {
if (i > maxAge) {
i = maxAge;
}
Reflections.method$Level$setBlock.invoke(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
if (sendParticles) {
World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
@@ -140,7 +140,7 @@ public class CropBlockBehavior extends BushBlockBehavior {
// 存活条件是最小生长亮度-1
int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("light-requirement", 9));
float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.25f));
return new CropBlockBehavior(tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight);
return new CropBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight);
}
}
}

View File

@@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.util.Reflections;
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.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.parameter.LootParameters;
@@ -21,12 +20,13 @@ import net.momirealms.craftengine.shared.block.BlockBehavior;
import java.util.Map;
import java.util.concurrent.Callable;
public class FallingBlockBehavior extends AbstractBlockBehavior {
public class FallingBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final float hurtAmount;
private final int maxHurt;
public FallingBlockBehavior(float hurtAmount, int maxHurt) {
public FallingBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt) {
super(block);
this.hurtAmount = hurtAmount;
this.maxHurt = maxHurt;
}
@@ -131,7 +131,7 @@ public class FallingBlockBehavior extends AbstractBlockBehavior {
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
float hurtAmount = MiscUtils.getAsFloat(arguments.getOrDefault("hurt-amount", -1f));
int hurtMax = MiscUtils.getAsInt(arguments.getOrDefault("max-hurt", -1));
return new FallingBlockBehavior(hurtAmount, hurtMax);
return new FallingBlockBehavior(block, hurtAmount, hurtMax);
}
}
}

View File

@@ -13,8 +13,8 @@ import java.util.Set;
public class HangingBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
public HangingBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
public HangingBlockBehavior(CustomBlock block, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
}
@Override
@@ -32,7 +32,7 @@ public class HangingBlockBehavior extends BushBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new HangingBlockBehavior(tuple.left(), tuple.mid(), tuple.right());
return new HangingBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right());
}
}
}

View File

@@ -39,8 +39,8 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
@Nullable
private final Property<Boolean> waterloggedProperty;
public LeavesBlockBehavior(int maxDistance, Property<Integer> distanceProperty, Property<Boolean> persistentProperty, @Nullable Property<Boolean> waterloggedProperty) {
super(waterloggedProperty);
public LeavesBlockBehavior(CustomBlock block, int maxDistance, Property<Integer> distanceProperty, Property<Boolean> persistentProperty, @Nullable Property<Boolean> waterloggedProperty) {
super(block, waterloggedProperty);
this.maxDistance = maxDistance;
this.distanceProperty = distanceProperty;
this.persistentProperty = persistentProperty;
@@ -97,7 +97,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
if (blockState == newState.customBlockState().handle()) {
Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512);
} else {
Reflections.method$Level$setBlock.invoke(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
}
}
}
@@ -182,7 +182,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
}
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
int actual = distance.possibleValues().get(distance.possibleValues().size() - 1);
return new LeavesBlockBehavior(actual, distance, persistent, waterlogged);
return new LeavesBlockBehavior(block, actual, distance, persistent, waterlogged);
}
}
}

View File

@@ -16,8 +16,8 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior {
private final boolean onWater;
private final boolean onLava;
public OnLiquidBlockBehavior(boolean onWater, boolean onLava) {
super(List.of(), Set.of(), Set.of());
public OnLiquidBlockBehavior(CustomBlock block, boolean onWater, boolean onLava) {
super(block, List.of(), Set.of(), Set.of());
this.onWater = onWater;
this.onLava = onLava;
}
@@ -34,7 +34,7 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
return new OnLiquidBlockBehavior(liquidTypes.contains("water"), liquidTypes.contains("lava"));
return new OnLiquidBlockBehavior(block, liquidTypes.contains("water"), liquidTypes.contains("lava"));
}
}

View File

@@ -31,8 +31,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior {
private final double boneMealSuccessChance;
private final float growSpeed;
public SaplingBlockBehavior(Key feature, Property<Integer> stageProperty, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
public SaplingBlockBehavior(CustomBlock block, Key feature, Property<Integer> stageProperty, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) {
super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
this.feature = feature;
this.stageProperty = stageProperty;
this.boneMealSuccessChance = boneMealSuccessChance;
@@ -79,18 +79,18 @@ public class SaplingBlockBehavior extends BushBlockBehavior {
CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature());
return;
}
Object chunkGenerator = Reflections.method$ServerChunkCache$getGenerator.invoke(Reflections.field$ServerLevel$chunkSource.get(world));
Object chunkGenerator = Reflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world));
Object configuredFeature = Reflections.method$Holder$value.invoke(holder.get());
Object fluidState = Reflections.method$Level$getFluidState.invoke(world, blockPos);
Object legacyState = Reflections.method$FluidState$createLegacyBlock.invoke(fluidState);
Reflections.method$Level$setBlock.invoke(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags());
if ((boolean) Reflections.method$ConfiguredFeature$place.invoke(configuredFeature, world, chunkGenerator, randomSource, blockPos)) {
if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, blockPos) == legacyState) {
Reflections.method$ServerLevel$sendBlockUpdated.invoke(world, blockPos, blockState, legacyState, 2);
}
} else {
// failed to place, rollback changes
Reflections.method$Level$setBlock.invoke(world, blockPos, blockState, UpdateOption.UPDATE_NONE.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, blockState, UpdateOption.UPDATE_NONE.flags());
}
}
@@ -150,7 +150,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior {
}
double boneMealSuccessChance = MiscUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45));
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new SaplingBlockBehavior(Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance,
return new SaplingBlockBehavior(block, Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance,
MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1.0 / 7.0)));
}
}

View File

@@ -1,18 +1,18 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import java.util.Map;
public class StrippableBlockBehavior extends AbstractBlockBehavior {
public class StrippableBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Key stripped;
public StrippableBlockBehavior(Key stripped) {
public StrippableBlockBehavior(CustomBlock block, Key stripped) {
super(block);
this.stripped = stripped;
}
@@ -28,7 +28,7 @@ public class StrippableBlockBehavior extends AbstractBlockBehavior {
if (stripped == null) {
throw new IllegalArgumentException("stripped is null");
}
return new StrippableBlockBehavior(Key.of(stripped));
return new StrippableBlockBehavior(block, Key.of(stripped));
}
}
}

View File

@@ -38,17 +38,15 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior {
private final boolean nearLava;
private final IntegerProperty ageProperty;
private final float growSpeed;
private final CustomBlock customBlock;
public SugarCaneBlockBehavior(CustomBlock customBlock, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn, Property<Integer> ageProperty,
int maxHeight, boolean nearWater, boolean nearLava, float growSpeed) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
super(customBlock, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
this.nearWater = nearWater;
this.nearLava = nearLava;
this.maxHeight = maxHeight;
this.ageProperty = (IntegerProperty) ageProperty;
this.growSpeed = growSpeed;
this.customBlock = customBlock;
}
@Override
@@ -120,13 +118,13 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior {
if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
Object abovePos = LocationUtils.above(blockPos);
if (VersionHelper.isVersionNewerThan1_21_5()) {
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
} else {
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle());
Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle());
}
Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
} else if (RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
}
}
}
@@ -143,7 +141,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior {
// 如果下方是同种方块
if (!BlockStateUtils.isVanillaBlock(id)) {
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
if (immutableBlockState.owner().value() == this.customBlock) {
if (immutableBlockState.owner().value() == super.customBlock) {
return true;
}
}

View File

@@ -1,7 +1,6 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.shared.block.BlockBehavior;
@@ -9,12 +8,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class WaterLoggedBlockBehavior extends AbstractBlockBehavior {
public class WaterLoggedBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
@Nullable
private final Property<Boolean> waterloggedProperty;
public WaterLoggedBlockBehavior(@Nullable Property<Boolean> waterloggedProperty) {
public WaterLoggedBlockBehavior(CustomBlock block, @Nullable Property<Boolean> waterloggedProperty) {
super(block);
this.waterloggedProperty = waterloggedProperty;
}
@@ -82,7 +82,7 @@ public class WaterLoggedBlockBehavior extends AbstractBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
return new WaterLoggedBlockBehavior(waterlogged);
return new WaterLoggedBlockBehavior(block, waterlogged);
}
}
}

View File

@@ -112,9 +112,9 @@ public class LoadedFurniture {
});
}
try {
this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
if (this.minimized) {
this.cachedMinimizedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(minimizedPackets);
this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e);

View File

@@ -150,7 +150,7 @@ public class BlockItemBehavior extends ItemBehavior {
Object blockState = state.customBlockState().handle();
Object blockPos = LocationUtils.toBlockPos(context.getClickedPos());
Object voxelShape = Reflections.method$CollisionContext$of.invoke(null, player);
Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().platformWorld());
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel((World) context.getLevel().platformWorld());
boolean defaultReturn = ((!this.checkStatePlacement() || (boolean) Reflections.method$BlockStateBase$canSurvive.invoke(blockState, world, blockPos))
&& (boolean) Reflections.method$ServerLevel$checkEntityCollision.invoke(world, blockState, player, voxelShape, blockPos, true));
Block block = FastNMS.INSTANCE.method$CraftBlock$at(world, blockPos);

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item.recipe;
import com.destroystokyo.paper.event.inventory.PrepareResultEvent;
import net.kyori.adventure.text.Component;
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.injector.BukkitInjector;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
@@ -347,7 +348,7 @@ public class RecipeEventListener implements Listener {
BukkitRecipeManager.minecraftRecipeManager(),
Reflections.instance$RecipeType$CAMPFIRE_COOKING,
Reflections.constructor$SingleRecipeInput.newInstance(Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)),
Reflections.field$CraftWorld$ServerLevel.get(event.getPlayer().getWorld()),
FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()),
null
);
if (optionalMCRecipe.isEmpty()) {

View File

@@ -1,9 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import org.bukkit.Location;
@@ -25,11 +22,7 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
Player player = context.sender();
Location location = player.getLocation();
try {
Object level = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld());
Object aabb = FastNMS.INSTANCE.constructor$AABB(location.getBlockX(), location.getBlockY(), location.getBlockZ(),
location.getBlockX() + 1, location.getBlockY() + 1, location.getBlockZ() + 1);
CollisionEntity nmsEntity = FastNMS.INSTANCE.createCollisionEntity(level, aabb, location.getBlockX() + 0.5, location.getBlockY(), location.getBlockZ() + 0.5, false);
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, nmsEntity);
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -174,6 +174,12 @@ public class BukkitInjector {
// getShape
.method(ElementMatchers.is(Reflections.method$BlockBehaviour$getShape))
.intercept(MethodDelegation.to(GetShapeInterceptor.INSTANCE))
// mirror
.method(ElementMatchers.is(Reflections.method$BlockBehaviour$mirror))
.intercept(MethodDelegation.to(MirrorInterceptor.INSTANCE))
// rotate
.method(ElementMatchers.is(Reflections.method$BlockBehaviour$rotate))
.intercept(MethodDelegation.to(RotateInterceptor.INSTANCE))
// tick
.method(ElementMatchers.is(Reflections.method$BlockBehaviour$tick))
.intercept(MethodDelegation.to(TickInterceptor.INSTANCE))
@@ -711,8 +717,8 @@ public class BukkitInjector {
int id = (int) Reflections.field$Direction$data3d.get(direction);
// Y axis
if (id == 0 || id == 1) {
Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel);
Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, blockPos);
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
if (id == 1) {
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$DOWN, blockPos, 0);
} else {
@@ -736,6 +742,36 @@ public class BukkitInjector {
}
}
public static class MirrorInterceptor {
public static final MirrorInterceptor INSTANCE = new MirrorInterceptor();
@RuntimeType
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
try {
return holder.value().mirror(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run mirror", e);
return superMethod.call();
}
}
}
public static class RotateInterceptor {
public static final RotateInterceptor INSTANCE = new RotateInterceptor();
@RuntimeType
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
try {
return holder.value().rotate(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run rotate", e);
return superMethod.call();
}
}
}
public static class RandomTickInterceptor {
public static final RandomTickInterceptor INSTANCE = new RandomTickInterceptor();

View File

@@ -92,31 +92,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
this.registerConsumers();
this.packetsConsumer = ((serverPlayer, packets) -> {
try {
Object bundle = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
Reflections.method$ServerGamePacketListenerImpl$sendPacket.invoke(
Reflections.field$ServerPlayer$connection.get(serverPlayer), bundle);
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to create bundle packet", e);
}
Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
FastNMS.INSTANCE.sendPacket(serverPlayer, bundle);
});
this.delayedPacketConsumer = (serverPlayer, packet) -> {
try {
Reflections.method$ServerGamePacketListenerImpl$sendPacket.invoke(
Reflections.field$ServerPlayer$connection.get(serverPlayer), packet);
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to invoke send packet", e);
}
};
this.delayedPacketConsumer = FastNMS.INSTANCE::sendPacket;
this.immediatePacketConsumer = (serverPlayer, packet) -> {
try {
Reflections.method$Connection$sendPacketImmediate.invoke(Reflections.field$ServerCommonPacketListenerImpl$connection.get(Reflections.field$ServerPlayer$connection.get(serverPlayer)), packet, null, true);
Reflections.method$Connection$sendPacketImmediate.invoke(FastNMS.INSTANCE.field$Player$connection$connection(serverPlayer), packet, null, true);
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to invoke send packet", e);
}
};
this.active = true;
this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null;
hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null;
instance = this;
}
@@ -258,17 +246,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
public Channel getChannel(Player player) {
try {
return (Channel) Reflections.field$Channel.get(
Reflections.field$NetworkManager.get(
Reflections.field$ServerPlayer$connection.get(
FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)
)
)
);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
return (Channel) FastNMS.INSTANCE.field$Player$connection$connection$channel(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player));
}
public void sendPacket(@NotNull Player player, @NotNull Object packet) {

View File

@@ -291,7 +291,7 @@ public class PacketConsumers {
private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception {
Object action = Reflections.field$ServerboundPlayerActionPacket$action.get(packet);
if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) {
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world);
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world);
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos));
int stateId = BlockStateUtils.blockStateToId(blockState);
// not a custom block
@@ -546,7 +546,7 @@ public class PacketConsumers {
};
private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception {
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld());
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos);
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (state == null) return;

View File

@@ -40,4 +40,13 @@ public class DirectionUtils {
case EAST -> Reflections.instance$Direction$EAST;
};
}
public static Direction fromNMSDirection(Object direction) {
try {
int index = (int) Reflections.method$Direction$ordinal.invoke(direction);
return Direction.values()[index];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import org.bukkit.World;
@@ -11,30 +12,25 @@ public class LightUtils {
private LightUtils() {}
@SuppressWarnings("unchecked")
public static void updateChunkLight(World world, Map<Long, BitSet> sectionPosSet) {
try {
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world);
Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel);
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world);
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
for (Map.Entry<Long, BitSet> entry : sectionPosSet.entrySet()) {
long chunkKey = entry.getKey();
Object chunkHolder = Reflections.method$ServerChunkCache$getVisibleChunkIfPresent.invoke(chunkSource, chunkKey);
Object chunkHolder = FastNMS.INSTANCE.method$ServerChunkCache$getVisibleChunkIfPresent(chunkSource, chunkKey);
if (chunkHolder == null) continue;
List<Object> players;
if (Reflections.method$ChunkHolder$getPlayers != null) {
players = (List<Object>) Reflections.method$ChunkHolder$getPlayers.invoke(chunkHolder, false);
} else {
Object chunkHolder$PlayerProvider = Reflections.field$ChunkHolder$playerProvider.get(chunkHolder);
players = (List<Object>) Reflections.method$ChunkHolder$PlayerProvider$getPlayers.invoke(chunkHolder$PlayerProvider, false);
}
List<Object> players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(chunkHolder);
if (players.isEmpty()) continue;
Object lightEngine = Reflections.field$ChunkHolder$lightEngine.get(chunkHolder);
BitSet blockChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$blockChangedLightSectionFilter.get(chunkHolder);
blockChangedLightSectionFilter.or(entry.getValue());
BitSet skyChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$skyChangedLightSectionFilter.get(chunkHolder);
Object chunkPos = Reflections.constructor$ChunkPos.newInstance((int) chunkKey, (int) (chunkKey >> 32));
Object lightPacket = Reflections.constructor$ClientboundLightUpdatePacket.newInstance(chunkPos, lightEngine, skyChangedLightSectionFilter, blockChangedLightSectionFilter);
Reflections.method$ChunkHolder$broadcast.invoke(chunkHolder, players, lightPacket);
Object chunkPos = FastNMS.INSTANCE.constructor$ChunkPos((int) chunkKey, (int) (chunkKey >> 32));
Object lightPacket = FastNMS.INSTANCE.constructor$ClientboundLightUpdatePacket(chunkPos, lightEngine, skyChangedLightSectionFilter, blockChangedLightSectionFilter);
for (Object player : players) {
FastNMS.INSTANCE.sendPacket(player, lightPacket);
}
blockChangedLightSectionFilter.clear();
skyChangedLightSectionFilter.clear();
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.Mirror;
public class MirrorUtils {
private MirrorUtils() {}
public static Mirror fromNMSMirror(Object mirror) {
try {
int index = (int) Reflections.method$Mirror$ordinal.invoke(mirror);
return Mirror.values()[index];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static Object toNMSMirror(Mirror mirror) {
switch (mirror) {
case FRONT_BACK -> {
return Reflections.instance$Mirror$FRONT_BACK;
}
case LEFT_RIGHT -> {
return Reflections.instance$Mirror$LEFT_RIGHT;
}
default -> {
return Reflections.instance$Mirror$NONE;
}
}
}
}

View File

@@ -12,7 +12,7 @@ public class NoteBlockChainUpdateUtils {
Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction);
Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos);
if (BlockStateUtils.isClientSideNoteBlock(state)) {
Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, relativePos);
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, relativePos);
noteBlockChainUpdate(level, chunkSource, direction, relativePos, times+1);
}
}

View File

@@ -421,9 +421,9 @@ public class Reflections {
)
);
public static final Constructor<?> constructor$ClientboundBundlePacket = requireNonNull(
ReflectionUtils.getConstructor(clazz$ClientboundBundlePacket, Iterable.class)
);
// public static final Constructor<?> constructor$ClientboundBundlePacket = requireNonNull(
// ReflectionUtils.getConstructor(clazz$ClientboundBundlePacket, Iterable.class)
// );
public static final Class<?> clazz$Packet = requireNonNull(
ReflectionUtils.getClazz(
@@ -494,12 +494,6 @@ public class Reflections {
)
);
public static final Field field$NetworkManager = requireNonNull(
VersionHelper.isVersionNewerThan1_20_2() ?
ReflectionUtils.getDeclaredField(clazz$ServerGamePacketListenerImpl.getSuperclass(), clazz$Connection, 0) :
ReflectionUtils.getDeclaredField(clazz$ServerGamePacketListenerImpl, clazz$Connection, 0)
);
public static final Field field$Channel = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$Connection, Channel.class, 0
@@ -1053,11 +1047,12 @@ public class Reflections {
)
);
public static final Field field$CraftWorld$ServerLevel = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$CraftWorld, clazz$ServerLevel, 0
)
);
// @Deprecated
// public static final Field field$CraftWorld$ServerLevel = requireNonNull(
// ReflectionUtils.getDeclaredField(
// clazz$CraftWorld, clazz$ServerLevel, 0
// )
// );
public static final Method method$ServerLevel$getNoiseBiome = requireNonNull(
ReflectionUtils.getMethod(
@@ -1806,17 +1801,18 @@ public class Reflections {
)
);
public static final Field field$ServerLevel$chunkSource = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerLevel, clazz$ServerChunkCache, 0
)
);
@Deprecated
// public static final Field field$ServerLevel$chunkSource = requireNonNull(
// ReflectionUtils.getDeclaredField(
// clazz$ServerLevel, clazz$ServerChunkCache, 0
// )
// );
public static final Method method$ServerChunkCache$blockChanged = requireNonNull(
ReflectionUtils.getMethod(
clazz$ServerChunkCache, void.class, clazz$BlockPos
)
);
// public static final Method method$ServerChunkCache$blockChanged = requireNonNull(
// ReflectionUtils.getMethod(
// clazz$ServerChunkCache, void.class, clazz$BlockPos
// )
// );
// public static final Method method$ServerChunkCache$getChunkAtIfLoadedMainThread = requireNonNull(
// ReflectionUtils.getMethod(
@@ -2644,6 +2640,7 @@ public class Reflections {
)
);
@Deprecated
public static final Constructor<?> constructor$ChunkPos = requireNonNull(
ReflectionUtils.getConstructor(
clazz$ChunkPos, int.class, int.class
@@ -2695,7 +2692,7 @@ public class Reflections {
)
);
// 1.20 ~ 1.21.4
// 1.20 ~ 1.21.4 moonrise
public static final Method method$ChunkHolder$getPlayers =
ReflectionUtils.getMethod(
clazz$ChunkHolder, List.class, boolean.class
@@ -2725,6 +2722,7 @@ public class Reflections {
)
);
@Deprecated
public static final Method method$ServerChunkCache$getVisibleChunkIfPresent = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$ServerChunkCache, clazz$ChunkHolder, long.class
@@ -3577,12 +3575,6 @@ public class Reflections {
)
);
public static final Method method$Level$setBlock = requireNonNull(
ReflectionUtils.getMethod(
clazz$Level, boolean.class, clazz$BlockPos, clazz$BlockState, int.class
)
);
public static final Method method$Block$updateFromNeighbourShapes = requireNonNull(
ReflectionUtils.getStaticMethod(
clazz$Block, clazz$BlockState, clazz$BlockState, clazz$LevelAccessor, clazz$BlockPos
@@ -3735,6 +3727,7 @@ public class Reflections {
)
);
@Deprecated
public static final Method method$LevelWriter$setBlock = requireNonNull(
ReflectionUtils.getMethod(
clazz$LevelWriter, boolean.class, clazz$BlockPos, clazz$BlockState, int.class
@@ -5963,4 +5956,86 @@ public class Reflections {
clazz$ClientboundSetEntityMotionPacket, int.class, 0
)
);
public static final Class<?> clazz$Rotation = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.block.Rotation"),
BukkitReflectionUtils.assembleMCClass("world.level.block.EnumBlockRotation")
)
);
public static final Method method$Rotation$values = requireNonNull(
ReflectionUtils.getStaticMethod(
clazz$Rotation, clazz$Rotation.arrayType()
)
);
public static final Object instance$Rotation$NONE;
public static final Object instance$Rotation$CLOCKWISE_90;
public static final Object instance$Rotation$CLOCKWISE_180;
public static final Object instance$Rotation$COUNTERCLOCKWISE_90;
static {
try {
Object[] values = (Object[]) method$Rotation$values.invoke(null);
instance$Rotation$NONE = values[0];
instance$Rotation$CLOCKWISE_90 = values[1];
instance$Rotation$CLOCKWISE_180 = values[2];
instance$Rotation$COUNTERCLOCKWISE_90 = values[3];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static final Method method$Rotation$ordinal = requireNonNull(
ReflectionUtils.getMethod(
clazz$Rotation, int.class, new String[]{"ordinal"}
)
);
public static final Class<?> clazz$Mirror = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.block.Mirror"),
BukkitReflectionUtils.assembleMCClass("world.level.block.EnumBlockMirror")
)
);
public static final Method method$Mirror$values = requireNonNull(
ReflectionUtils.getStaticMethod(
clazz$Mirror, clazz$Mirror.arrayType()
)
);
public static final Object instance$Mirror$NONE;
public static final Object instance$Mirror$LEFT_RIGHT;
public static final Object instance$Mirror$FRONT_BACK;
static {
try {
Object[] values = (Object[]) method$Mirror$values.invoke(null);
instance$Mirror$NONE = values[0];
instance$Mirror$LEFT_RIGHT = values[1];
instance$Mirror$FRONT_BACK = values[2];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static final Method method$Mirror$ordinal = requireNonNull(
ReflectionUtils.getMethod(
clazz$Mirror, int.class, new String[]{"ordinal"}
)
);
public static final Method method$BlockBehaviour$rotate = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$Rotation
)
);
public static final Method method$BlockBehaviour$mirror = requireNonNull(
ReflectionUtils.getDeclaredMethod(
clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$Mirror
)
);
}

View File

@@ -0,0 +1,34 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.Rotation;
public class RotationUtils {
private RotationUtils() {}
public static Rotation fromNMSRotation(Object rotation) {
try {
int index = (int) Reflections.method$Rotation$ordinal.invoke(rotation);
return Rotation.values()[index];
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static Object toNMSRotation(Rotation rotation) {
switch (rotation) {
case CLOCKWISE_90 -> {
return Reflections.instance$Rotation$CLOCKWISE_90;
}
case CLOCKWISE_180 -> {
return Reflections.instance$Rotation$CLOCKWISE_180;
}
case COUNTERCLOCKWISE_90 -> {
return Reflections.instance$Rotation$COUNTERCLOCKWISE_90;
}
default -> {
return Reflections.instance$Rotation$NONE;
}
}
}
}

View File

@@ -1,8 +1,8 @@
package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -36,7 +36,7 @@ public class BukkitWorld implements World {
@Override
public Object serverWorld() {
try {
return Reflections.field$CraftWorld$ServerLevel.get(platformWorld());
return FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformWorld());
} catch (Exception e) {
throw new RuntimeException("Failed to get server world", e);
}

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
@@ -51,7 +52,7 @@ public class BukkitWorldBlock implements WorldBlock {
public boolean isWaterSource(BlockPlaceContext blockPlaceContext) {
try {
Location location = block.getLocation();
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(block.getWorld());
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld());
Object fluidData = Reflections.method$Level$getFluidState.invoke(serverLevel, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
if (fluidData == null) return false;
return (boolean) Reflections.method$FluidState$isSource.invoke(fluidData);

View File

@@ -1,10 +1,16 @@
package net.momirealms.craftengine.core.block.behavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.shared.block.BlockBehavior;
public abstract class AbstractBlockBehavior extends BlockBehavior {
protected CustomBlock customBlock;
public AbstractBlockBehavior(CustomBlock customBlock) {
this.customBlock = customBlock;
}
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
return state;

View File

@@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18
byte_buddy_version=1.15.11
snake_yaml_version=2.3
anti_grief_version=0.13
nms_helper_version=0.29
nms_helper_version=0.32
# Ignite Dependencies
mixinextras_version=0.4.1
mixin_version=0.15.2+mixin.0.8.7

View File

@@ -10,10 +10,7 @@ import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.ScheduledTickAccess;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.Fallable;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
@@ -68,10 +65,30 @@ public class CraftEngineBlock
}
}
@Override
protected @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) {
try {
return (BlockState) this.behaviorHolder.value().rotate(this, new Object[]{state, rotation}, () -> super.rotate(state, rotation));
} catch (Exception e) {
e.printStackTrace();
return super.rotate(state, rotation);
}
}
@Override
protected @NotNull BlockState mirror(@NotNull BlockState state, @NotNull Mirror mirror) {
try {
return (BlockState) this.behaviorHolder.value().mirror(this, new Object[]{state, mirror}, () -> super.mirror(state, mirror));
} catch (Exception e) {
e.printStackTrace();
return super.mirror(state, mirror);
}
}
@Override
protected void tick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) {
try {
behaviorHolder.value().tick(this, new Object[]{state, level, pos, random}, () -> {
this.behaviorHolder.value().tick(this, new Object[]{state, level, pos, random}, () -> {
super.tick(state, level, pos, random);
return null;
});

View File

@@ -4,6 +4,14 @@ import java.util.concurrent.Callable;
public abstract class BlockBehavior {
public Object rotate(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return superMethod.call();
}
public Object mirror(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return superMethod.call();
}
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return superMethod.call();
}