mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
添加1.20.1 mod
This commit is contained in:
@@ -167,7 +167,7 @@ furniture:
|
||||
- "xxx:invalid_furniture"
|
||||
# Converts the invalid furniture to a valid one
|
||||
convert:
|
||||
"xxx:invalid_furniture": "xxx:valid_furniture"
|
||||
"namespace:furniture_a": "namespace:furniture_b"
|
||||
|
||||
# Hide technical entities used for storing furniture metadata.
|
||||
# NOTE:
|
||||
|
||||
@@ -342,25 +342,21 @@ public class BlockEventListener implements Listener {
|
||||
if (!this.enableNoteBlockCheck) return;
|
||||
// for vanilla blocks
|
||||
if (event.getChangedType() == Material.NOTE_BLOCK) {
|
||||
try {
|
||||
Block block = event.getBlock();
|
||||
World world = block.getWorld();
|
||||
Location location = block.getLocation();
|
||||
Block sourceBlock = event.getSourceBlock();
|
||||
BlockFace direction = sourceBlock.getFace(block);
|
||||
if (direction == BlockFace.UP || direction == BlockFace.DOWN) {
|
||||
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());
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
|
||||
if (direction == BlockFace.UP) {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$UP, blockPos, 0);
|
||||
} else {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$DOWN, blockPos, 0);
|
||||
}
|
||||
Block block = event.getBlock();
|
||||
World world = block.getWorld();
|
||||
Location location = block.getLocation();
|
||||
Block sourceBlock = event.getSourceBlock();
|
||||
BlockFace direction = sourceBlock.getFace(block);
|
||||
if (direction == BlockFace.UP || direction == BlockFace.DOWN) {
|
||||
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());
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
|
||||
if (direction == BlockFace.UP) {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$UP, blockPos, 0);
|
||||
} else {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$DOWN, blockPos, 0);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to sync note block states", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,7 +794,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
newBlockState = getOnlyBlockState(newRealBlock);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> optionalHolder = (Optional<Object>) Reflections.method$Registry$getHolder0.invoke(Reflections.instance$BuiltInRegistries$BLOCK, resourceLocation);
|
||||
Optional<Object> optionalHolder = (Optional<Object>) Reflections.method$Registry$getHolder1.invoke(Reflections.instance$BuiltInRegistries$BLOCK, Reflections.method$ResourceKey$create.invoke(null, Reflections.instance$Registries$BLOCK, resourceLocation));
|
||||
blockHolder = optionalHolder.get();
|
||||
} else {
|
||||
try {
|
||||
|
||||
@@ -142,7 +142,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior {
|
||||
if (direction != Reflections.instance$Direction$DOWN || canSolidify(blockState)) {
|
||||
Reflections.method$MutableBlockPos$setWithOffset.invoke(mutablePos, pos, direction);
|
||||
blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, mutablePos);
|
||||
if (canSolidify(blockState) && !(boolean) Reflections.method$BlockStateBase$isFaceSturdy.invoke(blockState, level, pos, Reflections.getOppositeDirection(direction), Reflections.instance$SupportType$FULL)) {
|
||||
if (canSolidify(blockState) && !(boolean) Reflections.method$BlockStateBase$isFaceSturdy.invoke(blockState, level, pos, FastNMS.INSTANCE.method$Direction$getOpposite(direction), Reflections.instance$SupportType$FULL)) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
this.debugStickListener = new DebugStickListener(plugin);
|
||||
this.itemParser = new ItemParser();
|
||||
this.registerAllVanillaItems();
|
||||
if (plugin.hasMod() && VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
if (plugin.hasMod()) {
|
||||
Class<?> clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec");
|
||||
if (clazz$CustomStreamCodec != null) {
|
||||
Field s2cProcessor = ReflectionUtils.getDeclaredField(clazz$CustomStreamCodec, Function.class, 0);
|
||||
|
||||
@@ -7,9 +7,9 @@ public class NoteBlockChainUpdateUtils {
|
||||
|
||||
private NoteBlockChainUpdateUtils() {}
|
||||
|
||||
public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) throws ReflectiveOperationException {
|
||||
public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) {
|
||||
if (times >= Config.maxChainUpdate()) return;
|
||||
Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction);
|
||||
Object relativePos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, direction);
|
||||
Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos);
|
||||
if (BlockStateUtils.isClientSideNoteBlock(state)) {
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, relativePos);
|
||||
|
||||
@@ -1522,7 +1522,6 @@ public class Reflections {
|
||||
public static final Object instance$Direction$WEST;
|
||||
public static final Object instance$Direction$EAST;
|
||||
public static final Object[] instance$Directions;
|
||||
private static final Map<Object, Object> oppositeDirections = new HashMap<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -1533,20 +1532,14 @@ public class Reflections {
|
||||
instance$Direction$SOUTH = instance$Directions[3];
|
||||
instance$Direction$WEST = instance$Directions[4];
|
||||
instance$Direction$EAST = instance$Directions[5];
|
||||
oppositeDirections.put(instance$Direction$DOWN, instance$Direction$UP);
|
||||
oppositeDirections.put(instance$Direction$UP, instance$Direction$DOWN);
|
||||
oppositeDirections.put(instance$Direction$NORTH, instance$Direction$SOUTH);
|
||||
oppositeDirections.put(instance$Direction$SOUTH, instance$Direction$NORTH);
|
||||
oppositeDirections.put(instance$Direction$WEST, instance$Direction$EAST);
|
||||
oppositeDirections.put(instance$Direction$EAST, instance$Direction$WEST);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object getOppositeDirection(Object direction) {
|
||||
return oppositeDirections.get(direction);
|
||||
}
|
||||
// public static Object getOppositeDirection(Object direction) {
|
||||
// return oppositeDirections.get(direction);
|
||||
// }
|
||||
|
||||
public static final Class<?> clazz$CraftBlock = requireNonNull(
|
||||
ReflectionUtils.getClazz(
|
||||
|
||||
@@ -40,7 +40,7 @@ tasks.remapJar {
|
||||
inputFile.set(tasks.shadowJar.get().archiveFile)
|
||||
|
||||
destinationDirectory.set(file("$rootDir/target"))
|
||||
archiveFileName.set("${base.archivesName.get()}-${project.version}+${rootProject.properties["latest_minecraft_version"]}.jar")
|
||||
archiveFileName.set("${base.archivesName.get()}-${project.version}+mc${rootProject.properties["latest_minecraft_version"]}.jar")
|
||||
}
|
||||
|
||||
loom {
|
||||
|
||||
@@ -51,7 +51,7 @@ byte_buddy_version=1.17.5
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.4
|
||||
anti_grief_version=0.13
|
||||
nms_helper_version=0.58.8
|
||||
nms_helper_version=0.59
|
||||
# Ignite Dependencies
|
||||
mixinextras_version=0.4.1
|
||||
mixin_version=0.15.2+mixin.0.8.7
|
||||
|
||||
46
server-mod/v1_20_1/build.gradle.kts
Normal file
46
server-mod/v1_20_1/build.gradle.kts
Normal file
@@ -0,0 +1,46 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("com.gradleup.shadow") version "9.0.0-beta11"
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.16"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://maven.fabricmc.net/")
|
||||
maven("https://oss.sonatype.org/content/groups/public/")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://repo.spongepowered.org/maven/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":shared"))
|
||||
remapper("net.fabricmc:tiny-remapper:${rootProject.properties["tiny_remapper_version"]}:fat")
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.1-R0.1-SNAPSHOT")
|
||||
compileOnly("space.vectrix.ignite:ignite-api:${rootProject.properties["ignite_version"]}")
|
||||
compileOnly("net.fabricmc:sponge-mixin:${rootProject.properties["mixin_version"]}")
|
||||
compileOnly("io.github.llamalad7:mixinextras-common:${rootProject.properties["mixinextras_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(21)
|
||||
dependsOn(tasks.clean)
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives(tasks.reobfJar)
|
||||
}
|
||||
|
||||
tasks {
|
||||
reobfJar {
|
||||
outputJar.set(file("$rootDir/target/${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.20.1-reobf.jar"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package net.momirealms.craftengine.mod;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class CraftEnginePlugin implements IMixinConfigPlugin {
|
||||
public static final Logger LOGGER = Logger.getLogger(CraftEnginePlugin.class.getName());
|
||||
private static int vanillaRegistrySize;
|
||||
private static boolean isSuccessfullyRegistered = false;
|
||||
private static int maxChainUpdate = 32;
|
||||
|
||||
public static void setVanillaRegistrySize(int vanillaRegistrySize) {
|
||||
CraftEnginePlugin.vanillaRegistrySize = vanillaRegistrySize;
|
||||
}
|
||||
|
||||
public static void setIsSuccessfullyRegistered(boolean isSuccessfullyRegistered) {
|
||||
CraftEnginePlugin.isSuccessfullyRegistered = isSuccessfullyRegistered;
|
||||
}
|
||||
|
||||
public static int maxChainUpdate() {
|
||||
return maxChainUpdate;
|
||||
}
|
||||
|
||||
public static void setMaxChainUpdate(int maxChainUpdate) {
|
||||
CraftEnginePlugin.maxChainUpdate = maxChainUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(final @NotNull String mixinPackage) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(@NotNull String targetClassName,
|
||||
@NotNull String mixinClassName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(@NotNull Set<String> myTargets,
|
||||
@NotNull Set<String> otherTargets) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> getMixins() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(@NotNull String targetClassName,
|
||||
@NotNull ClassNode targetClass,
|
||||
@NotNull String mixinClassName,
|
||||
@NotNull IMixinInfo mixinInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(@NotNull String targetClassName,
|
||||
@NotNull ClassNode targetClass,
|
||||
@NotNull String mixinClassName,
|
||||
@NotNull IMixinInfo mixinInfo) {
|
||||
}
|
||||
|
||||
public static Path getPluginFolderPath() {
|
||||
ProtectionDomain protectionDomain = CraftEnginePlugin.class.getProtectionDomain();
|
||||
CodeSource codeSource = protectionDomain.getCodeSource();
|
||||
URL jarUrl = codeSource.getLocation();
|
||||
try {
|
||||
return Paths.get(jarUrl.toURI()).getParent().getParent().resolve("plugins");
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Path getCraftEngineMappingsPath() {
|
||||
return getPluginFolderPath()
|
||||
.resolve("CraftEngine")
|
||||
.resolve("mappings.yml");
|
||||
}
|
||||
|
||||
public static Path getCraftEngineAdditionalBlocksPath() {
|
||||
return getPluginFolderPath()
|
||||
.resolve("CraftEngine")
|
||||
.resolve("additional-real-blocks.yml");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package net.momirealms.craftengine.mod.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
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;
|
||||
import net.momirealms.craftengine.mod.CraftEnginePlugin;
|
||||
import net.momirealms.craftengine.mod.util.NoteBlockUtils;
|
||||
import net.momirealms.craftengine.shared.ObjectHolder;
|
||||
import net.momirealms.craftengine.shared.block.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CraftEngineBlock
|
||||
extends Block
|
||||
implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock
|
||||
//TODO , SimpleWaterloggedBlock
|
||||
{
|
||||
private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState());
|
||||
private boolean isNoteBlock;
|
||||
public ObjectHolder<BlockBehavior> behaviorHolder;
|
||||
public ObjectHolder<BlockShape> shapeHolder;
|
||||
public boolean isClientSideNoteBlock;
|
||||
|
||||
public CraftEngineBlock(Properties properties) {
|
||||
super(properties);
|
||||
this.behaviorHolder = new ObjectHolder<>(EmptyBlockBehavior.INSTANCE);
|
||||
this.shapeHolder = new ObjectHolder<>(STONE);
|
||||
}
|
||||
|
||||
public void setNoteBlock(boolean noteBlock) {
|
||||
isNoteBlock = noteBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectHolder<BlockBehavior> getBehaviorHolder() {
|
||||
return behaviorHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectHolder<BlockShape> getShapeHolder() {
|
||||
return shapeHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNoteBlock() {
|
||||
return isClientSideNoteBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) {
|
||||
try {
|
||||
return (VoxelShape) shapeHolder.value().getShape(this, new Object[]{state, level, pos, context});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return super.getShape(state, level, pos, context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @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
|
||||
public @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
|
||||
public void tick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) {
|
||||
try {
|
||||
this.behaviorHolder.value().tick(this, new Object[]{state, level, pos, random}, () -> {
|
||||
super.tick(state, level, pos, random);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
super.tick(state, level, pos, random);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) {
|
||||
try {
|
||||
behaviorHolder.value().randomTick(this, new Object[]{state, level, pos, random}, () -> {
|
||||
super.randomTick(state, level, pos, random);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
super.randomTick(state, level, pos, random);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState oldState, boolean movedByPiston) {
|
||||
try {
|
||||
behaviorHolder.value().onPlace(this, new Object[]{state, level, pos, oldState, movedByPiston}, () -> {
|
||||
super.onPlace(state, level, pos, oldState, movedByPiston);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
super.onPlace(state, level, pos, oldState, movedByPiston);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrokenAfterFall(@NotNull Level level, @NotNull BlockPos pos, @NotNull FallingBlockEntity fallingBlock) {
|
||||
try {
|
||||
behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Fallable.super.onBrokenAfterFall(level, pos, fallingBlock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) {
|
||||
try {
|
||||
return behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return super.canSurvive(state, level, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(@NotNull BlockState state,
|
||||
@NotNull Direction direction,
|
||||
@NotNull BlockState neighborState,
|
||||
@NotNull LevelAccessor world,
|
||||
@NotNull BlockPos pos,
|
||||
@NotNull BlockPos neighborPos) {
|
||||
try {
|
||||
if (isNoteBlock && world instanceof ServerLevel serverLevel) {
|
||||
startNoteBlockChain(direction, serverLevel, pos);
|
||||
}
|
||||
return (BlockState) behaviorHolder.value().updateShape(this, new Object[]{state, direction, neighborState, world, pos, neighborPos}, () -> super.updateShape(state, direction, neighborState, world, pos, neighborPos));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return super.updateShape(state, direction, neighborState, world, pos, neighborPos);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startNoteBlockChain(Direction direction, ServerLevel serverLevel, BlockPos blockPos) {
|
||||
int id = direction.get3DDataValue();
|
||||
// Y axis
|
||||
if (id == 0 || id == 1) {
|
||||
ServerChunkCache chunkSource = serverLevel.chunkSource;
|
||||
chunkSource.blockChanged(blockPos);
|
||||
if (id == 1) {
|
||||
noteBlockChainUpdate(serverLevel, chunkSource, Direction.DOWN, blockPos, 0);
|
||||
} else {
|
||||
noteBlockChainUpdate(serverLevel, chunkSource, Direction.UP, blockPos, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void noteBlockChainUpdate(ServerLevel level, ServerChunkCache chunkSource, Direction direction, BlockPos blockPos, int times) {
|
||||
if (times >= CraftEnginePlugin.maxChainUpdate()) return;
|
||||
BlockPos relativePos = blockPos.relative(direction);
|
||||
BlockState state = level.getBlockState(relativePos);
|
||||
if (NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.contains(state)) {
|
||||
chunkSource.blockChanged(relativePos);
|
||||
noteBlockChainUpdate(level, chunkSource, direction, relativePos, times+1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidBonemealTarget(@NotNull LevelReader world, @NotNull BlockPos pos, @NotNull BlockState state, boolean isClient) {
|
||||
try {
|
||||
return behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{world, pos, state, isClient});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBonemealSuccess(@NotNull Level level, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) {
|
||||
try {
|
||||
return behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performBonemeal(@NotNull ServerLevel serverLevel, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) {
|
||||
try {
|
||||
behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLand(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull BlockState replaceableState, @NotNull FallingBlockEntity fallingBlock) {
|
||||
try {
|
||||
behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean canPlaceLiquid(@Nullable Player player, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Fluid fluid) {
|
||||
// try {
|
||||
// return behaviorHolder.value().canPlaceLiquid(this, new Object[]{player, level, pos, state, fluid}, () -> SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean placeLiquid(@NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull FluidState fluidState) {
|
||||
// try {
|
||||
// return behaviorHolder.value().placeLiquid(this, new Object[]{level, pos, state, fluidState}, () -> SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// @Override
|
||||
// public ItemStack pickupBlock(@Nullable Player player, @NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state) {
|
||||
// try {
|
||||
// return (ItemStack) behaviorHolder.value().pickupBlock(this, new Object[]{player, level, pos, state}, () -> SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package net.momirealms.craftengine.mod.block;
|
||||
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.momirealms.craftengine.mod.CraftEnginePlugin;
|
||||
import net.momirealms.craftengine.mod.util.NoteBlockUtils;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomBlocks {
|
||||
|
||||
public static void register() {
|
||||
CraftEnginePlugin.setVanillaRegistrySize(Block.BLOCK_STATE_REGISTRY.size());
|
||||
ResourceLocation noteBlock = new ResourceLocation("minecraft", "note_block");
|
||||
Map<ResourceLocation, Integer> map = loadMappingsAndAdditionalBlocks();
|
||||
for (Map.Entry<ResourceLocation, Integer> entry : map.entrySet()) {
|
||||
ResourceLocation replacedBlockId = entry.getKey();
|
||||
boolean isNoteBlock = replacedBlockId.equals(noteBlock);
|
||||
Block replacedBlock = BuiltInRegistries.BLOCK.get(replacedBlockId);
|
||||
for (int i = 0; i < entry.getValue(); i++) {
|
||||
ResourceLocation location = new ResourceLocation("craftengine", replacedBlockId.getPath() + "_" + i);
|
||||
ResourceKey<Block> resourceKey = ResourceKey.create(Registries.BLOCK, location);
|
||||
BlockBehaviour.Properties properties = BlockBehaviour.Properties.of();
|
||||
if (!replacedBlock.hasCollision) {
|
||||
properties.noCollission();
|
||||
}
|
||||
CraftEngineBlock block = new CraftEngineBlock(properties);
|
||||
if (isNoteBlock) {
|
||||
block.setNoteBlock(true);
|
||||
NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.add(block.defaultBlockState());
|
||||
}
|
||||
Registry.register(BuiltInRegistries.BLOCK, location, block);
|
||||
Block.BLOCK_STATE_REGISTRY.add(block.defaultBlockState());
|
||||
}
|
||||
}
|
||||
NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.addAll(net.minecraft.world.level.block.Blocks.NOTE_BLOCK.getStateDefinition().getPossibleStates());
|
||||
if (!map.isEmpty()) {
|
||||
CraftEnginePlugin.setIsSuccessfullyRegistered(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<ResourceLocation, Integer> loadMappingsAndAdditionalBlocks() {
|
||||
Path mappingPath = CraftEnginePlugin.getCraftEngineMappingsPath();
|
||||
if (!Files.exists(mappingPath)) return Map.of();
|
||||
YamlConfiguration mappings = YamlConfiguration.loadConfiguration(mappingPath.toFile());
|
||||
Map<String, String> blockStateMappings = loadBlockStateMappings(mappings);
|
||||
validateBlockStateMappings(blockStateMappings);
|
||||
Map<ResourceLocation, Integer> blockTypeCounter = new LinkedHashMap<>();
|
||||
Map<Integer, Integer> appearanceMapper = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : blockStateMappings.entrySet()) {
|
||||
processBlockStateMapping(entry, appearanceMapper, blockTypeCounter);
|
||||
}
|
||||
YamlConfiguration additionalYaml = YamlConfiguration.loadConfiguration(CraftEnginePlugin.getCraftEngineAdditionalBlocksPath().toFile());
|
||||
return buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml);
|
||||
}
|
||||
|
||||
private static Map<String, String> loadBlockStateMappings(YamlConfiguration mappings) {
|
||||
Map<String, String> blockStateMappings = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> entry : mappings.getValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof String afterValue) {
|
||||
blockStateMappings.put(entry.getKey(), afterValue);
|
||||
}
|
||||
}
|
||||
return blockStateMappings;
|
||||
}
|
||||
|
||||
private static void validateBlockStateMappings(Map<String, String> blockStateMappings) {
|
||||
Map<String, String> temp = new HashMap<>(blockStateMappings);
|
||||
for (Map.Entry<String, String> entry : temp.entrySet()) {
|
||||
String state = entry.getValue();
|
||||
blockStateMappings.remove(state);
|
||||
}
|
||||
}
|
||||
|
||||
private static LinkedHashMap<ResourceLocation, Integer> buildRegisteredRealBlockSlots(Map<ResourceLocation, Integer> counter, YamlConfiguration additionalYaml) {
|
||||
LinkedHashMap<ResourceLocation, Integer> map = new LinkedHashMap<>();
|
||||
for (Map.Entry<ResourceLocation, Integer> entry : counter.entrySet()) {
|
||||
String id = entry.getKey().toString();
|
||||
int additionalStates = additionalYaml.getInt(id, 0);
|
||||
int internalIds = entry.getValue() + additionalStates;
|
||||
map.put(entry.getKey(), internalIds);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void processBlockStateMapping(Map.Entry<String, String> entry, Map<Integer, Integer> mapper, Map<ResourceLocation, Integer> counter) {
|
||||
BlockState before = createBlockData(entry.getKey());
|
||||
BlockState after = createBlockData(entry.getValue());
|
||||
if (before == null || after == null) return;
|
||||
|
||||
int beforeId = Block.BLOCK_STATE_REGISTRY.getId(before);
|
||||
int afterId = Block.BLOCK_STATE_REGISTRY.getId(after);
|
||||
|
||||
Integer previous = mapper.put(beforeId, afterId);
|
||||
if (previous == null) {
|
||||
counter.compute(BuiltInRegistries.BLOCK.getKey(before.getBlock()), (k, count) -> count == null ? 1 : count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockState createBlockData(String blockState) {
|
||||
try {
|
||||
BlockStateParser.BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), blockState, false);
|
||||
return result.blockState();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.momirealms.craftengine.mod.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.momirealms.craftengine.shared.block.BlockShape;
|
||||
|
||||
public class StoneBlockShape implements BlockShape {
|
||||
private final BlockState rawBlockState;
|
||||
|
||||
public StoneBlockShape(BlockState rawBlockState) {
|
||||
this.rawBlockState = rawBlockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getShape(Object thisObj, Object[] args) {
|
||||
return rawBlockState.getShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.momirealms.craftengine.mod.item;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CustomStreamCodec {
|
||||
public static Function<ItemStack, ItemStack> clientBoundDataProcessor;
|
||||
public static Function<ItemStack, ItemStack> serverBoundDataProcessor;
|
||||
|
||||
public static @NotNull ItemStack s2c(@NotNull ItemStack itemStack) {
|
||||
if (clientBoundDataProcessor != null) {
|
||||
itemStack = clientBoundDataProcessor.apply(itemStack);
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public static @NotNull ItemStack c2s(@NotNull ItemStack itemStack) {
|
||||
if (serverBoundDataProcessor != null) {
|
||||
itemStack = serverBoundDataProcessor.apply(itemStack);
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.momirealms.craftengine.mod.mixin;
|
||||
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.momirealms.craftengine.mod.block.CustomBlocks;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = Blocks.class)
|
||||
public abstract class BlocksMixin {
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("RETURN"))
|
||||
private static void onBlocksInit(CallbackInfo ci) {
|
||||
CustomBlocks.register();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.momirealms.craftengine.mod.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.momirealms.craftengine.mod.item.CustomStreamCodec;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(value = FriendlyByteBuf.class)
|
||||
public class FriendlyByteBufMixin {
|
||||
|
||||
@ModifyVariable(
|
||||
method = "a(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/network/PacketDataSerializer;",
|
||||
at = @At("HEAD"),
|
||||
argsOnly = true
|
||||
)
|
||||
private ItemStack modifyWriteItemParam(ItemStack stack) {
|
||||
return stack.isEmpty() ? stack : CustomStreamCodec.s2c(stack);
|
||||
}
|
||||
|
||||
@ModifyReturnValue(
|
||||
method = "r()Lnet/minecraft/world/item/ItemStack;",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private ItemStack modifyReadItemStack(ItemStack original) {
|
||||
return original.isEmpty() ? original : CustomStreamCodec.c2s(original);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.momirealms.craftengine.mod.util;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class NoteBlockUtils {
|
||||
|
||||
public static final Set<BlockState> CLIENT_SIDE_NOTE_BLOCKS = new HashSet<>();
|
||||
}
|
||||
7
server-mod/v1_20_1/src/main/resources/ignite.mod.json
Normal file
7
server-mod/v1_20_1/src/main/resources/ignite.mod.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"id": "craftengine",
|
||||
"version": "${project_version}",
|
||||
"mixins": [
|
||||
"mixins.craftengine.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8.7",
|
||||
"package": "net.momirealms.craftengine.mod.mixin",
|
||||
"plugin": "net.momirealms.craftengine.mod.CraftEnginePlugin",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"server": [
|
||||
"BlocksMixin",
|
||||
"FriendlyByteBufMixin"
|
||||
]
|
||||
}
|
||||
@@ -11,10 +11,8 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.momirealms.craftengine.mod.CraftEnginePlugin;
|
||||
import net.momirealms.craftengine.mod.util.NoteBlockUtils;
|
||||
import net.momirealms.craftengine.mod.util.Reflections;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
@@ -30,28 +28,22 @@ public class CustomBlocks {
|
||||
for (Map.Entry<ResourceLocation, Integer> entry : map.entrySet()) {
|
||||
ResourceLocation replacedBlockId = entry.getKey();
|
||||
boolean isNoteBlock = replacedBlockId.equals(noteBlock);
|
||||
try {
|
||||
Block replacedBlock = (Block) Reflections.method$DefaultedRegistry$get.invoke(BuiltInRegistries.BLOCK, replacedBlockId);
|
||||
for (int i = 0; i < entry.getValue(); i++) {
|
||||
ResourceLocation location = ResourceLocation.fromNamespaceAndPath("craftengine", replacedBlockId.getPath() + "_" + i);
|
||||
ResourceKey<Block> resourceKey = ResourceKey.create(Registries.BLOCK, location);
|
||||
BlockBehaviour.Properties properties = BlockBehaviour.Properties.of();
|
||||
if (Reflections.field$BlockBehaviour$Properties$id != null) {
|
||||
Reflections.field$BlockBehaviour$Properties$id.set(properties, resourceKey);
|
||||
}
|
||||
if (!replacedBlock.hasCollision) {
|
||||
properties.noCollission();
|
||||
}
|
||||
CraftEngineBlock block = new CraftEngineBlock(properties);
|
||||
if (isNoteBlock) {
|
||||
block.setNoteBlock(true);
|
||||
NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.add(block.defaultBlockState());
|
||||
}
|
||||
Registry.register(BuiltInRegistries.BLOCK, location, block);
|
||||
Block.BLOCK_STATE_REGISTRY.add(block.defaultBlockState());
|
||||
Block replacedBlock = BuiltInRegistries.BLOCK.getValue(replacedBlockId);
|
||||
for (int i = 0; i < entry.getValue(); i++) {
|
||||
ResourceLocation location = ResourceLocation.fromNamespaceAndPath("craftengine", replacedBlockId.getPath() + "_" + i);
|
||||
ResourceKey<Block> resourceKey = ResourceKey.create(Registries.BLOCK, location);
|
||||
BlockBehaviour.Properties properties = BlockBehaviour.Properties.of();
|
||||
properties.setId(resourceKey);
|
||||
if (!replacedBlock.hasCollision) {
|
||||
properties.noCollission();
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
CraftEngineBlock block = new CraftEngineBlock(properties);
|
||||
if (isNoteBlock) {
|
||||
block.setNoteBlock(true);
|
||||
NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.add(block.defaultBlockState());
|
||||
}
|
||||
Registry.register(BuiltInRegistries.BLOCK, location, block);
|
||||
Block.BLOCK_STATE_REGISTRY.add(block.defaultBlockState());
|
||||
}
|
||||
}
|
||||
NoteBlockUtils.CLIENT_SIDE_NOTE_BLOCKS.addAll(net.minecraft.world.level.block.Blocks.NOTE_BLOCK.getStateDefinition().getPossibleStates());
|
||||
@@ -120,11 +112,7 @@ public class CustomBlocks {
|
||||
|
||||
private static BlockState createBlockData(String blockState) {
|
||||
try {
|
||||
Object holderLookUp = BuiltInRegistries.BLOCK;
|
||||
if (Reflections.method$Registry$asLookup != null) {
|
||||
holderLookUp = Reflections.method$Registry$asLookup.invoke(holderLookUp);
|
||||
}
|
||||
BlockStateParser.BlockResult result = (BlockStateParser.BlockResult) Reflections.method$BlockStateParser$parseForBlock.invoke(null, holderLookUp, blockState, false);
|
||||
BlockStateParser.BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, blockState, false);
|
||||
return result.blockState();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package net.momirealms.craftengine.mod.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class BukkitReflectionUtils {
|
||||
private static final String PREFIX_MC = "net.minecraft.";
|
||||
private static final String PREFIX_CRAFTBUKKIT = "org.bukkit.craftbukkit";
|
||||
private static final String CRAFT_SERVER = "CraftServer";
|
||||
private static final String CB_PKG_VERSION;
|
||||
public static final int MAJOR_REVISION;
|
||||
|
||||
private BukkitReflectionUtils() {}
|
||||
|
||||
static {
|
||||
final Class<?> serverClass;
|
||||
if (Bukkit.getServer() == null) {
|
||||
// Paper plugin Bootstrapper 1.20.6+
|
||||
serverClass = Objects.requireNonNull(ReflectionUtils.getClazz("org.bukkit.craftbukkit.CraftServer"));
|
||||
} else {
|
||||
serverClass = Bukkit.getServer().getClass();
|
||||
}
|
||||
final String pkg = serverClass.getPackage().getName();
|
||||
final String nmsVersion = pkg.substring(pkg.lastIndexOf(".") + 1);
|
||||
if (!nmsVersion.contains("_")) {
|
||||
int fallbackVersion = -1;
|
||||
if (Bukkit.getServer() != null) {
|
||||
try {
|
||||
final Method getMinecraftVersion = serverClass.getDeclaredMethod("getMinecraftVersion");
|
||||
fallbackVersion = Integer.parseInt(getMinecraftVersion.invoke(Bukkit.getServer()).toString().split("\\.")[1]);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
} else {
|
||||
// Paper plugin bootstrapper 1.20.6+
|
||||
try {
|
||||
final Class<?> sharedConstants = Objects.requireNonNull(ReflectionUtils.getClazz("net.minecraft.SharedConstants"));
|
||||
final Method getCurrentVersion = sharedConstants.getDeclaredMethod("getCurrentVersion");
|
||||
final Object currentVersion = getCurrentVersion.invoke(null);
|
||||
final Method getName = currentVersion.getClass().getDeclaredMethod("getName");
|
||||
final String versionName = (String) getName.invoke(currentVersion);
|
||||
try {
|
||||
fallbackVersion = Integer.parseInt(versionName.split("\\.")[1]);
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
MAJOR_REVISION = fallbackVersion;
|
||||
} else {
|
||||
MAJOR_REVISION = Integer.parseInt(nmsVersion.split("_")[1]);
|
||||
}
|
||||
String name = serverClass.getName();
|
||||
name = name.substring(PREFIX_CRAFTBUKKIT.length());
|
||||
name = name.substring(0, name.length() - CRAFT_SERVER.length());
|
||||
CB_PKG_VERSION = name;
|
||||
}
|
||||
|
||||
public static String assembleCBClass(String className) {
|
||||
return PREFIX_CRAFTBUKKIT + CB_PKG_VERSION + className;
|
||||
}
|
||||
|
||||
public static String assembleMCClass(String className) {
|
||||
return PREFIX_MC + className;
|
||||
}
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
package net.momirealms.craftengine.mod.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ReflectionUtils {
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
private ReflectionUtils() {}
|
||||
|
||||
public static Class<?> getClazz(String... classes) {
|
||||
for (String className : classes) {
|
||||
Class<?> clazz = getClazz(className);
|
||||
if (clazz != null) {
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Class<?> getClazz(String clazz) {
|
||||
try {
|
||||
return Class.forName(clazz);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean classExists(@NotNull final String clazz) {
|
||||
try {
|
||||
Class.forName(clazz);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean methodExists(@NotNull final Class<?> clazz, @NotNull final String method, @NotNull final Class<?>... parameterTypes) {
|
||||
try {
|
||||
clazz.getMethod(method, parameterTypes);
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getDeclaredField(final Class<?> clazz, final String field) {
|
||||
try {
|
||||
return setAccessible(clazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Field getDeclaredField(@NotNull Class<?> clazz, @NotNull String... possibleNames) {
|
||||
List<String> possibleNameList = Arrays.asList(possibleNames);
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (possibleNameList.contains(field.getName())) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Class " + clazz.getName() + " does not contain a field with possible names " + Arrays.toString(possibleNames));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getDeclaredField(final Class<?> clazz, final int index) {
|
||||
int i = 0;
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
if (index == i) {
|
||||
return setAccessible(field);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getInstanceDeclaredField(final Class<?> clazz, final int index) {
|
||||
int i = 0;
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
if (index == i) {
|
||||
return setAccessible(field);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getDeclaredField(final Class<?> clazz, final Class<?> type, int index) {
|
||||
int i = 0;
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == type) {
|
||||
if (index == i) {
|
||||
return setAccessible(field);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getDeclaredFieldBackwards(final Class<?> clazz, final Class<?> type, int index) {
|
||||
int i = 0;
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (int j = fields.length - 1; j >= 0; j--) {
|
||||
Field field = fields[j];
|
||||
if (field.getType() == type) {
|
||||
if (index == i) {
|
||||
return setAccessible(field);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Field getInstanceDeclaredField(@NotNull Class<?> clazz, final Class<?> type, int index) {
|
||||
int i = 0;
|
||||
for (final Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == type && !Modifier.isStatic(field.getModifiers())) {
|
||||
if (index == i) {
|
||||
return setAccessible(field);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Field> getDeclaredFields(final Class<?> clazz) {
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
fields.add(setAccessible(field));
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Field> getInstanceDeclaredFields(@NotNull Class<?> clazz) {
|
||||
List<Field> list = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
list.add(setAccessible(field));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Field> getDeclaredFields(@NotNull final Class<?> clazz, @NotNull final Class<?> type) {
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == type) {
|
||||
fields.add(setAccessible(field));
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Field> getInstanceDeclaredFields(@NotNull Class<?> clazz, @NotNull Class<?> type) {
|
||||
List<Field> list = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == type && !Modifier.isStatic(field.getModifiers())) {
|
||||
list.add(setAccessible(field));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getMethod(final Class<?> clazz, Class<?> returnType, final String[] possibleMethodNames, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (String name : possibleMethodNames) {
|
||||
if (name.equals(method.getName())) {
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getMethod(final Class<?> clazz, final String[] possibleMethodNames, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (String name : possibleMethodNames) {
|
||||
if (name.equals(method.getName())) return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getMethod(final Class<?> clazz, Class<?> returnType, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) return method;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getDeclaredMethod(final Class<?> clazz, Class<?> returnType, final String[] possibleMethodNames, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (String name : possibleMethodNames) {
|
||||
if (name.equals(method.getName())) {
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) {
|
||||
return setAccessible(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getDeclaredMethod(final Class<?> clazz, Class<?> returnType, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) return setAccessible(method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getMethod(final Class<?> clazz, Class<?> returnType, int index) {
|
||||
int i = 0;
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) {
|
||||
if (i == index) {
|
||||
return setAccessible(method);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getStaticMethod(final Class<?> clazz, Class<?> returnType, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (returnType.isAssignableFrom(method.getReturnType()))
|
||||
return setAccessible(method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getStaticMethod(final Class<?> clazz, Class<?> returnType, String[] possibleNames, final Class<?>... parameterTypes) {
|
||||
outer:
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getParameterCount() != parameterTypes.length) {
|
||||
continue;
|
||||
}
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (returnType.isAssignableFrom(method.getReturnType())) {
|
||||
for (String name : possibleNames) {
|
||||
if (name.equals(method.getName())) {
|
||||
return setAccessible(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Method getStaticMethod(final Class<?> clazz, int index) {
|
||||
int i = 0;
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (i == index) {
|
||||
return setAccessible(method);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getMethod(final Class<?> clazz, int index) {
|
||||
int i = 0;
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (i == index) {
|
||||
return setAccessible(method);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Method getMethodOrElseThrow(final Class<?> clazz, final String[] possibleMethodNames, final Class<?>[] parameterTypes) throws NoSuchMethodException {
|
||||
Method method = getMethod(clazz, possibleMethodNames, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException("No method found with possible names " + Arrays.toString(possibleMethodNames) + " with parameters " +
|
||||
Arrays.toString(parameterTypes) + " in class " + clazz.getName());
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<Method> getMethods(@NotNull Class<?> clazz, @NotNull Class<?> returnType, @NotNull Class<?>... parameterTypes) {
|
||||
List<Method> list = new ArrayList<>();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (!returnType.isAssignableFrom(method.getReturnType()) // check type
|
||||
|| method.getParameterCount() != parameterTypes.length // check length
|
||||
) continue;
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
outer: {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] != parameterTypes[i]) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
list.add(method);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T extends AccessibleObject> T setAccessible(@NotNull final T o) {
|
||||
o.setAccessible(true);
|
||||
return o;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... parameterTypes) {
|
||||
try {
|
||||
return clazz.getConstructor(parameterTypes);
|
||||
} catch (NoSuchMethodException | SecurityException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Constructor<?> getDeclaredConstructor(Class<?> clazz, Class<?>... parameterTypes) {
|
||||
try {
|
||||
return setAccessible(clazz.getDeclaredConstructor(parameterTypes));
|
||||
} catch (NoSuchMethodException | SecurityException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Constructor<?> getConstructor(Class<?> clazz, int index) {
|
||||
try {
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
if (index < 0 || index >= constructors.length) {
|
||||
throw new IndexOutOfBoundsException("Invalid constructor index: " + index);
|
||||
}
|
||||
return setAccessible(constructors[index]);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Constructor<?> getTheOnlyConstructor(Class<?> clazz) {
|
||||
Constructor<?>[] constructors = clazz.getConstructors();
|
||||
if (constructors.length != 1) {
|
||||
throw new RuntimeException("This class is expected to have only one constructor but it has " + constructors.length);
|
||||
}
|
||||
return constructors[0];
|
||||
}
|
||||
|
||||
public static MethodHandle unreflectGetter(Field field) throws IllegalAccessException {
|
||||
try {
|
||||
return LOOKUP.unreflectGetter(field);
|
||||
} catch (IllegalAccessException e) {
|
||||
field.setAccessible(true);
|
||||
return LOOKUP.unreflectGetter(field);
|
||||
}
|
||||
}
|
||||
|
||||
public static MethodHandle unreflectMethod(Method method) throws IllegalAccessException {
|
||||
try {
|
||||
return LOOKUP.unreflect(method);
|
||||
} catch (IllegalAccessException e) {
|
||||
method.setAccessible(true);
|
||||
return LOOKUP.unreflect(method);
|
||||
}
|
||||
}
|
||||
|
||||
public static VarHandle findVarHandle(Class<?> clazz, String name, Class<?> type) {
|
||||
try {
|
||||
return MethodHandles.privateLookupIn(clazz, LOOKUP)
|
||||
.findVarHandle(clazz, name, type);
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static VarHandle findVarHandle(Field field) {
|
||||
try {
|
||||
return MethodHandles.privateLookupIn(field.getDeclaringClass(), LOOKUP)
|
||||
.findVarHandle(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package net.momirealms.craftengine.mod.util;
|
||||
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||
import net.minecraft.core.DefaultedRegistry;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class Reflections {
|
||||
|
||||
public static final Method method$DefaultedRegistry$get = requireNonNull(
|
||||
ReflectionUtils.getMethod(
|
||||
DefaultedRegistry.class, Object.class, ResourceLocation.class
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$BlockBehaviour$Properties$id = ReflectionUtils.getDeclaredField(
|
||||
BlockBehaviour.Properties.class, ResourceKey.class, 0
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateParser$parseForBlock = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(
|
||||
BlockStateParser.class, BlockStateParser.BlockResult.class, new String[]{"parseForBlock"}, HolderLookup.class, String.class, boolean.class
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$Registry$asLookup = ReflectionUtils.getMethod(
|
||||
Registry.class, new String[]{"asLookup"}
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ include(":bukkit")
|
||||
include(":bukkit:legacy")
|
||||
include(":bukkit:compatibility")
|
||||
include(":bukkit:loader")
|
||||
include(":server-mod:v1_20_1")
|
||||
include(":server-mod:v1_20_5")
|
||||
include(":server-mod:v1_21_5")
|
||||
include(":client-mod")
|
||||
|
||||
Reference in New Issue
Block a user