From 08894c7c0ea20e5006a7a7e85d21edc0346d646d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 16 Apr 2025 02:21:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A01.21.5=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/behavior/BlockItemBehavior.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 4 +- gradle.properties | 2 +- server-mod/{ => v1_20_5}/build.gradle.kts | 4 +- .../craftengine/mod/CraftEnginePlugin.java | 104 ++++ .../mod/block/CraftEngineBlock.java | 0 .../craftengine/mod/block/CustomBlocks.java | 0 .../mod/block/StoneBlockShape.java | 0 .../mod/item/CustomStreamCodec.java | 0 .../craftengine/mod/mixin/BlocksMixin.java | 0 .../craftengine/mod/mixin/ItemStackMixin.java | 0 .../mod/util/BukkitReflectionUtils.java | 0 .../craftengine/mod/util/NoteBlockUtils.java | 0 .../craftengine/mod/util/ReflectionUtils.java | 0 .../craftengine/mod/util/Reflections.java | 0 .../src/main/resources/ignite.mod.json | 0 .../main/resources/mixins.craftengine.json | 0 server-mod/v1_21_5/build.gradle.kts | 50 ++ .../craftengine/mod/CraftEnginePlugin.java | 0 .../mod/block/CraftEngineBlock.java | 270 ++++++++++ .../craftengine/mod/block/CustomBlocks.java | 134 +++++ .../mod/block/StoneBlockShape.java | 20 + .../mod/item/CustomStreamCodec.java | 41 ++ .../craftengine/mod/mixin/BlocksMixin.java | 17 + .../craftengine/mod/mixin/ItemStackMixin.java | 66 +++ .../mod/util/BukkitReflectionUtils.java | 68 +++ .../craftengine/mod/util/NoteBlockUtils.java | 11 + .../craftengine/mod/util/ReflectionUtils.java | 489 ++++++++++++++++++ .../craftengine/mod/util/Reflections.java | 37 ++ .../src/main/resources/ignite.mod.json | 7 + .../main/resources/mixins.craftengine.json | 12 + settings.gradle.kts | 3 +- 32 files changed, 1335 insertions(+), 6 deletions(-) rename server-mod/{ => v1_20_5}/build.gradle.kts (88%) create mode 100644 server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java (100%) rename server-mod/{ => v1_20_5}/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java (100%) rename server-mod/{ => v1_20_5}/src/main/resources/ignite.mod.json (100%) rename server-mod/{ => v1_20_5}/src/main/resources/mixins.craftengine.json (100%) create mode 100644 server-mod/v1_21_5/build.gradle.kts rename server-mod/{ => v1_21_5}/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java (100%) create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java create mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java create mode 100644 server-mod/v1_21_5/src/main/resources/ignite.mod.json create mode 100644 server-mod/v1_21_5/src/main/resources/mixins.craftengine.json diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index dfcee504b..fd74c2a9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -83,7 +83,7 @@ public class BlockItemBehavior extends ItemBehavior { // todo adventure check if (player.isAdventureMode()) { - + return InteractionResult.FAIL; } int gameTicks = player.gameTicks(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index 6c3db214d..f4a2c324b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -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)) { diff --git a/gradle.properties b/gradle.properties index fc8249bc9..c5449ac87 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 diff --git a/server-mod/build.gradle.kts b/server-mod/v1_20_5/build.gradle.kts similarity index 88% rename from server-mod/build.gradle.kts rename to server-mod/v1_20_5/build.gradle.kts index e1a2d1fdf..272257de9 100644 --- a/server-mod/build.gradle.kts +++ b/server-mod/v1_20_5/build.gradle.kts @@ -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")) } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java new file mode 100644 index 000000000..db5a200de --- /dev/null +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java @@ -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 myTargets, + @NotNull Set otherTargets) { + } + + @Override + public @Nullable List 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"); + } +} diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java rename to server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java diff --git a/server-mod/src/main/resources/ignite.mod.json b/server-mod/v1_20_5/src/main/resources/ignite.mod.json similarity index 100% rename from server-mod/src/main/resources/ignite.mod.json rename to server-mod/v1_20_5/src/main/resources/ignite.mod.json diff --git a/server-mod/src/main/resources/mixins.craftengine.json b/server-mod/v1_20_5/src/main/resources/mixins.craftengine.json similarity index 100% rename from server-mod/src/main/resources/mixins.craftengine.json rename to server-mod/v1_20_5/src/main/resources/mixins.craftengine.json diff --git a/server-mod/v1_21_5/build.gradle.kts b/server-mod/v1_21_5/build.gradle.kts new file mode 100644 index 000000000..0be3a008a --- /dev/null +++ b/server-mod/v1_21_5/build.gradle.kts @@ -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 { + 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")) + } +} diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java similarity index 100% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java rename to server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java new file mode 100644 index 000000000..8b3039c7b --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -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 behaviorHolder; + public ObjectHolder 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 getBehaviorHolder() { + return behaviorHolder; + } + + @Override + public ObjectHolder 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); +// } +// } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java new file mode 100644 index 000000000..36af40eab --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CustomBlocks.java @@ -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 map = loadMappingsAndAdditionalBlocks(); + for (Map.Entry 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 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 loadMappingsAndAdditionalBlocks() { + Path mappingPath = CraftEnginePlugin.getCraftEngineMappingsPath(); + if (!Files.exists(mappingPath)) return Map.of(); + YamlConfiguration mappings = YamlConfiguration.loadConfiguration(mappingPath.toFile()); + Map blockStateMappings = loadBlockStateMappings(mappings); + validateBlockStateMappings(blockStateMappings); + Map blockTypeCounter = new LinkedHashMap<>(); + Map appearanceMapper = new HashMap<>(); + for (Map.Entry entry : blockStateMappings.entrySet()) { + processBlockStateMapping(entry, appearanceMapper, blockTypeCounter); + } + YamlConfiguration additionalYaml = YamlConfiguration.loadConfiguration(CraftEnginePlugin.getCraftEngineAdditionalBlocksPath().toFile()); + return buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml); + } + + private static Map loadBlockStateMappings(YamlConfiguration mappings) { + Map blockStateMappings = new LinkedHashMap<>(); + for (Map.Entry entry : mappings.getValues(false).entrySet()) { + if (entry.getValue() instanceof String afterValue) { + blockStateMappings.put(entry.getKey(), afterValue); + } + } + return blockStateMappings; + } + + private static void validateBlockStateMappings(Map blockStateMappings) { + Map temp = new HashMap<>(blockStateMappings); + for (Map.Entry entry : temp.entrySet()) { + String state = entry.getValue(); + blockStateMappings.remove(state); + } + } + + private static LinkedHashMap buildRegisteredRealBlockSlots(Map counter, YamlConfiguration additionalYaml) { + LinkedHashMap map = new LinkedHashMap<>(); + for (Map.Entry 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 entry, Map mapper, Map 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; + } + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java new file mode 100644 index 000000000..6ebc977a6 --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -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]); + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java new file mode 100644 index 000000000..2d1a47861 --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java @@ -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 { + public static Function clientBoundDataProcessor; + public static Function serverBoundDataProcessor; + + private final StreamCodec original; + + public CustomStreamCodec(StreamCodec 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); + } +} \ No newline at end of file diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java new file mode 100644 index 000000000..a14af758c --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/BlocksMixin.java @@ -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 = "", at = @At("RETURN")) + private static void onBlocksInit(CallbackInfo ci) { + CustomBlocks.register(); + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java new file mode 100644 index 000000000..88bc5d916 --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java @@ -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 OPTIONAL_STREAM_CODEC; + @Shadow(remap = false) + @Mutable + public static StreamCodec> OPTIONAL_LIST_STREAM_CODEC; + @Shadow(remap = false) + @Mutable + public static StreamCodec OPTIONAL_UNTRUSTED_STREAM_CODEC; + + private static StreamCodec ORIGINAL_OPTIONAL_STREAM_CODEC; + private static StreamCodec ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC; + + @Inject( + method = "", + 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 = "", + 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 = "", 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)); + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java new file mode 100644 index 000000000..5353b5e8d --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/BukkitReflectionUtils.java @@ -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; + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java new file mode 100644 index 000000000..8deebf538 --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/NoteBlockUtils.java @@ -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 CLIENT_SIDE_NOTE_BLOCKS = new HashSet<>(); +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java new file mode 100644 index 000000000..f76d59ebc --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/ReflectionUtils.java @@ -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 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 getDeclaredFields(final Class clazz) { + List fields = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + fields.add(setAccessible(field)); + } + return fields; + } + + @NotNull + public static List getInstanceDeclaredFields(@NotNull Class clazz) { + List list = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers())) { + list.add(setAccessible(field)); + } + } + return list; + } + + @NotNull + public static List getDeclaredFields(@NotNull final Class clazz, @NotNull final Class type) { + List fields = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + if (field.getType() == type) { + fields.add(setAccessible(field)); + } + } + return fields; + } + + @NotNull + public static List getInstanceDeclaredFields(@NotNull Class clazz, @NotNull Class type) { + List 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 getMethods(@NotNull Class clazz, @NotNull Class returnType, @NotNull Class... parameterTypes) { + List 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 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; + } + } +} diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java new file mode 100644 index 000000000..001f3a736 --- /dev/null +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/util/Reflections.java @@ -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"} + ); +} diff --git a/server-mod/v1_21_5/src/main/resources/ignite.mod.json b/server-mod/v1_21_5/src/main/resources/ignite.mod.json new file mode 100644 index 000000000..a353e9e4d --- /dev/null +++ b/server-mod/v1_21_5/src/main/resources/ignite.mod.json @@ -0,0 +1,7 @@ +{ + "id": "craftengine", + "version": "${project_version}", + "mixins": [ + "mixins.craftengine.json" + ] +} diff --git a/server-mod/v1_21_5/src/main/resources/mixins.craftengine.json b/server-mod/v1_21_5/src/main/resources/mixins.craftengine.json new file mode 100644 index 000000000..288b6501f --- /dev/null +++ b/server-mod/v1_21_5/src/main/resources/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" + ] +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e222e92cd..a06e0cb2c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -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 {