From 5a767add80069c368d3bde424ba01bdd164d21ee Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 6 Jul 2024 15:25:38 -0700 Subject: [PATCH] Add basic BlockChangeNotifier & BlockChangeListener --- .../event/BlockChangeListener.java | 11 ++++ .../event/BlockChangeNotifier.java | 33 +++++++++++ .../structurelib/mixins/Mixins.java | 9 +-- .../blockChangeNotifier/MixinForgeHooks.java | 44 +++++++++++++++ .../early/blockChangeNotifier/MixinWorld.java | 55 +++++++++++++++++++ 5 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeListener.java create mode 100644 src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeNotifier.java create mode 100644 src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinForgeHooks.java create mode 100644 src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinWorld.java diff --git a/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeListener.java b/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeListener.java new file mode 100644 index 00000000..ae85adfa --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeListener.java @@ -0,0 +1,11 @@ +package com.gtnewhorizon.structurelib.event; + +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +public interface BlockChangeListener { + + void onBlockChange(World world, Chunk chunk, int x, int y, int z, Block oldBlock, Block newBlock, int oldMeta, + int newMeta); +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeNotifier.java b/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeNotifier.java new file mode 100644 index 00000000..1555a00c --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/event/BlockChangeNotifier.java @@ -0,0 +1,33 @@ +package com.gtnewhorizon.structurelib.event; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +@SuppressWarnings("ForLoopReplaceableByForEach") +public class BlockChangeNotifier { + + private static final List listeners = new ArrayList<>(); + + public static synchronized void addListener(BlockChangeListener listener) { + listeners.add(listener); + } + + public static void onBlockChange(World world, Chunk chunk, int x, int y, int z, Block oldBlock, Block newBlock, + int oldMeta, int newMeta) { + if (oldBlock == newBlock && oldMeta == newMeta) return; + + if (chunk == null) { + chunk = world.getChunkFromBlockCoords(x, z); + } + + final int numListeners = listeners.size(); + for (int i = 0; i < numListeners; i++) { + final BlockChangeListener listener = listeners.get(i); + listener.onBlockChange(world, chunk, x, y, z, oldBlock, newBlock, oldMeta, newMeta); + } + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/mixins/Mixins.java b/src/main/java/com/gtnewhorizon/structurelib/mixins/Mixins.java index 7f93fed8..e27b1610 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizon/structurelib/mixins/Mixins.java @@ -13,12 +13,9 @@ import cpw.mods.fml.relauncher.FMLLaunchHandler; public enum Mixins { - EMPTY(new Builder("Empty").setPhase(Phase.EARLY).addMixinClasses("com.gtnewhorizon.structurelib.mixins.EmptyMixin") - .addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH).setApplyIf(() -> false)); - // DISABLE_MODDED_CHUNK_POPULATION(new Builder("Disable all other mod chunk population (e.g. Natura clouds") - // .setPhase(Phase.EARLY).addMixinClasses("minecraft.MixinChunkProviderServer_DisableModGeneration") - // .addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH) - // .setApplyIf(() -> TweaksConfig.disableModdedChunkPopulation)); + BLOCK_CHANGE_NOTIFIER(new Builder("Block Change Notifier").setPhase(Phase.EARLY) + .addMixinClasses("blockChangeNotifier.MixinForgeHooks", "blockChangeNotifier.MixinWorld") + .addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH).setApplyIf(() -> true)); private final List mixinClasses; private final List targetedMods; diff --git a/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinForgeHooks.java b/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinForgeHooks.java new file mode 100644 index 00000000..78eaf9ae --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinForgeHooks.java @@ -0,0 +1,44 @@ +package com.gtnewhorizon.structurelib.mixins.early.blockChangeNotifier; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.util.BlockSnapshot; + +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.CallbackInfoReturnable; + +import com.gtnewhorizon.structurelib.event.BlockChangeNotifier; +import com.llamalad7.mixinextras.sugar.Local; + +@Mixin(ForgeHooks.class) +public class MixinForgeHooks { + + @Inject( + method = "onPlaceItemIntoWorld", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/World;markAndNotifyBlock(IIILnet/minecraft/world/chunk/Chunk;Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;I)V", + shift = At.Shift.AFTER), + remap = false) + private static void onBlockChange(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, + int side, float hitX, float hitY, float hitZ, CallbackInfoReturnable cir, + @Local(name = "blocksnapshot") BlockSnapshot blocksnapshot, @Local(name = "newBlock") Block newBlock, + @Local(name = "metadata") int newMetadata) { + BlockChangeNotifier.onBlockChange( + world, + null, + blocksnapshot.x, + blocksnapshot.y, + blocksnapshot.z, + blocksnapshot.replacedBlock, + newBlock, + blocksnapshot.meta, + newMetadata); + } + +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinWorld.java b/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinWorld.java new file mode 100644 index 00000000..f0a67261 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/mixins/early/blockChangeNotifier/MixinWorld.java @@ -0,0 +1,55 @@ +package com.gtnewhorizon.structurelib.mixins.early.blockChangeNotifier; + +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +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.CallbackInfoReturnable; + +import com.gtnewhorizon.structurelib.event.BlockChangeNotifier; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + +@Mixin(World.class) +public class MixinWorld { + + @Inject( + method = "Lnet/minecraft/world/World;setBlock(IIILnet/minecraft/block/Block;II)Z", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/World;markAndNotifyBlock(IIILnet/minecraft/world/chunk/Chunk;Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;I)V", + shift = At.Shift.AFTER, + remap = false)) + public void setBlockObserve(int x, int y, int z, Block newBlock, int newMeta, int flags, + CallbackInfoReturnable cir, @Local(name = "block1") Block originalBlock, + @Share("originalMeta") LocalIntRef originalMeta, @Share("chunk") LocalRef chunkLocalRef) { + BlockChangeNotifier.onBlockChange( + (World) ((Object) (this)), + chunkLocalRef.get(), + x, + y, + z, + originalBlock, + newBlock, + originalMeta.get(), + newMeta); + } + + @Inject( + method = "Lnet/minecraft/world/World;setBlock(IIILnet/minecraft/block/Block;II)Z", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/chunk/Chunk;func_150807_a(IIILnet/minecraft/block/Block;I)Z", + shift = At.Shift.BEFORE)) + public void captureChunkAndOriginalMetadata(int x, int y, int z, Block blockIn, int metadataIn, int flags, + CallbackInfoReturnable cir, @Local(name = "chunk") Chunk chunk, + @Share("originalMeta") LocalIntRef originalMeta, @Share("chunk") LocalRef chunkLocalRef) { + chunkLocalRef.set(chunk); + originalMeta.set(chunk.getBlockMetadata(x & 15, y, z & 15)); + } +}