mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
添加1.21.5分支
This commit is contained in:
@@ -83,7 +83,7 @@ public class BlockItemBehavior extends ItemBehavior {
|
||||
|
||||
// todo adventure check
|
||||
if (player.isAdventureMode()) {
|
||||
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
int gameTicks = player.gameTicks();
|
||||
|
||||
@@ -67,8 +67,10 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
}
|
||||
|
||||
Player player = context.getPlayer();
|
||||
|
||||
// todo adventure check
|
||||
if (player.isAdventureMode()) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
int gameTicks = player.gameTicks();
|
||||
if (!player.updateLastSuccessfulInteractionTick(gameTicks)) {
|
||||
|
||||
@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.47.5
|
||||
project_version=0.0.47.6
|
||||
config_version=26
|
||||
lang_version=4
|
||||
project_group=net.momirealms
|
||||
|
||||
@@ -15,7 +15,7 @@ repositories {
|
||||
dependencies {
|
||||
implementation(project(":shared"))
|
||||
remapper("net.fabricmc:tiny-remapper:${rootProject.properties["tiny_remapper_version"]}:fat")
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:${rootProject.properties["latest_minecraft_version"]}-R0.1-SNAPSHOT")
|
||||
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.21.4-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"]}")
|
||||
@@ -44,7 +44,7 @@ artifacts {
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier = ""
|
||||
archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.20.5-1.21.5-mojmap.jar"
|
||||
archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.20.5-1.21.4-mojmap.jar"
|
||||
destinationDirectory.set(file("$rootDir/target"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package net.momirealms.craftengine.mod;
|
||||
|
||||
import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket;
|
||||
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.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");
|
||||
}
|
||||
}
|
||||
50
server-mod/v1_21_5/build.gradle.kts
Normal file
50
server-mod/v1_21_5/build.gradle.kts
Normal file
@@ -0,0 +1,50 @@
|
||||
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.21.5-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)
|
||||
}
|
||||
|
||||
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION
|
||||
|
||||
artifacts {
|
||||
archives(tasks.shadowJar)
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier = ""
|
||||
archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.21.5-mojmap.jar"
|
||||
destinationDirectory.set(file("$rootDir/target"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
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.LevelReader;
|
||||
import net.minecraft.world.level.ScheduledTickAccess;
|
||||
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;
|
||||
|
||||
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
|
||||
protected @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
|
||||
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 {
|
||||
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
|
||||
protected 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
|
||||
protected 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
|
||||
protected 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
|
||||
protected BlockState updateShape(@NotNull BlockState state,
|
||||
@NotNull LevelReader level,
|
||||
@NotNull ScheduledTickAccess scheduledTickAccess,
|
||||
@NotNull BlockPos pos,
|
||||
@NotNull Direction direction,
|
||||
@NotNull BlockPos neighborPos,
|
||||
@NotNull BlockState neighborState,
|
||||
@NotNull RandomSource random) {
|
||||
try {
|
||||
if (isNoteBlock && level instanceof ServerLevel serverLevel) {
|
||||
startNoteBlockChain(direction, serverLevel, pos);
|
||||
}
|
||||
return (BlockState) behaviorHolder.value().updateShape(this, new Object[]{state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random}, () -> super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// protected @NotNull FluidState getFluidState(@NotNull BlockState state) {
|
||||
// try {
|
||||
// return (FluidState) behaviorHolder.value().getFluidState(this, new Object[]{state}, () -> super.getFluidState(state));
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return super.getFluidState(state);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean isValidBonemealTarget(@NotNull LevelReader levelReader, @NotNull BlockPos blockPos, @NotNull BlockState blockState) {
|
||||
try {
|
||||
return behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{levelReader, blockPos, blockState});
|
||||
} 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,134 @@
|
||||
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 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;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomBlocks {
|
||||
|
||||
public static void register() {
|
||||
CraftEnginePlugin.setVanillaRegistrySize(Block.BLOCK_STATE_REGISTRY.size());
|
||||
ResourceLocation noteBlock = ResourceLocation.fromNamespaceAndPath("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);
|
||||
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());
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
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,41 @@
|
||||
package net.momirealms.craftengine.mod.item;
|
||||
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CustomStreamCodec implements StreamCodec<RegistryFriendlyByteBuf, ItemStack> {
|
||||
public static Function<ItemStack, ItemStack> clientBoundDataProcessor;
|
||||
public static Function<ItemStack, ItemStack> serverBoundDataProcessor;
|
||||
|
||||
private final StreamCodec<RegistryFriendlyByteBuf, ItemStack> original;
|
||||
|
||||
public CustomStreamCodec(StreamCodec<RegistryFriendlyByteBuf, ItemStack> original) {
|
||||
this.original = Objects.requireNonNull(original);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack decode(@NotNull RegistryFriendlyByteBuf buffer) {
|
||||
ItemStack itemStack = this.original.decode(buffer);
|
||||
if (!itemStack.isEmpty()) {
|
||||
if (serverBoundDataProcessor != null) {
|
||||
itemStack = serverBoundDataProcessor.apply(itemStack);
|
||||
}
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull RegistryFriendlyByteBuf buffer, @NotNull ItemStack value) {
|
||||
if (!value.isEmpty()) {
|
||||
if (clientBoundDataProcessor != null) {
|
||||
value = clientBoundDataProcessor.apply(value);
|
||||
}
|
||||
}
|
||||
this.original.encode(buffer, value);
|
||||
}
|
||||
}
|
||||
@@ -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,66 @@
|
||||
package net.momirealms.craftengine.mod.mixin;
|
||||
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.momirealms.craftengine.mod.item.CustomStreamCodec;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public abstract class ItemStackMixin {
|
||||
@Shadow(remap = false)
|
||||
@Mutable
|
||||
public static StreamCodec<RegistryFriendlyByteBuf, ItemStack> OPTIONAL_STREAM_CODEC;
|
||||
@Shadow(remap = false)
|
||||
@Mutable
|
||||
public static StreamCodec<RegistryFriendlyByteBuf, List<ItemStack>> OPTIONAL_LIST_STREAM_CODEC;
|
||||
@Shadow(remap = false)
|
||||
@Mutable
|
||||
public static StreamCodec<RegistryFriendlyByteBuf, ItemStack> OPTIONAL_UNTRUSTED_STREAM_CODEC;
|
||||
|
||||
private static StreamCodec<RegistryFriendlyByteBuf, ItemStack> ORIGINAL_OPTIONAL_STREAM_CODEC;
|
||||
private static StreamCodec<RegistryFriendlyByteBuf, ItemStack> ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC;
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target = "Lnet/minecraft/world/item/ItemStack;OPTIONAL_STREAM_CODEC:Lnet/minecraft/network/codec/StreamCodec;",
|
||||
opcode = Opcodes.PUTSTATIC,
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private static void captureOriginalAfterAssignment0(CallbackInfo ci) {
|
||||
ORIGINAL_OPTIONAL_STREAM_CODEC = OPTIONAL_STREAM_CODEC;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target = "Lnet/minecraft/world/item/ItemStack;OPTIONAL_UNTRUSTED_STREAM_CODEC:Lnet/minecraft/network/codec/StreamCodec;",
|
||||
opcode = Opcodes.PUTSTATIC,
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private static void captureOriginalAfterAssignment1(CallbackInfo ci) {
|
||||
ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC = OPTIONAL_UNTRUSTED_STREAM_CODEC;
|
||||
}
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("RETURN"))
|
||||
private static void replaceStreamCodec(CallbackInfo ci) {
|
||||
OPTIONAL_STREAM_CODEC = new CustomStreamCodec(ORIGINAL_OPTIONAL_STREAM_CODEC);
|
||||
OPTIONAL_UNTRUSTED_STREAM_CODEC = new CustomStreamCodec(ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC);
|
||||
OPTIONAL_LIST_STREAM_CODEC = OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs.collection(NonNullList::createWithCapacity));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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<>();
|
||||
}
|
||||
@@ -0,0 +1,489 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
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"}
|
||||
);
|
||||
}
|
||||
7
server-mod/v1_21_5/src/main/resources/ignite.mod.json
Normal file
7
server-mod/v1_21_5/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",
|
||||
"ItemStackMixin"
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,8 @@ include(":bukkit")
|
||||
include(":bukkit:legacy")
|
||||
include(":bukkit:compatibility")
|
||||
include(":bukkit:loader")
|
||||
include(":server-mod")
|
||||
include(":server-mod:v1_20_5")
|
||||
include(":server-mod:v1_21_5")
|
||||
include(":client-mod")
|
||||
pluginManagement {
|
||||
plugins {
|
||||
|
||||
Reference in New Issue
Block a user