diff --git a/src/main/java/eu/vodofrede/immersivexp/Events.java b/src/main/java/eu/vodofrede/immersivexp/Events.java new file mode 100644 index 0000000..aa38f7d --- /dev/null +++ b/src/main/java/eu/vodofrede/immersivexp/Events.java @@ -0,0 +1,46 @@ +package eu.vodofrede.immersivexp; + +import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.BlockState; +import net.minecraft.block.CropBlock; +import net.minecraft.block.MelonBlock; +import net.minecraft.block.SweetBerryBushBlock; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.tag.BlockTags; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class Events { + public static void init() { + PlayerBlockBreakEvents.AFTER.register((world, player, pos, state, entity) -> { + // TODO: Make experience amount configurable + if (world instanceof ServerWorld) { + if (state.getBlock() instanceof CropBlock || state.getBlock() instanceof MelonBlock) { + Util.spawnExp((ServerWorld) world, pos, 1, 1); + } + + if (state.isIn(BlockTags.LOGS)) { + boolean holdingAxe = player.isHolding(Registry.ITEM.get(new Identifier("minecraft:axe"))); + boolean isGrown = Util.isTreeNaturallyGrown(world, pos); + + if (holdingAxe && isGrown) { + Util.spawnExp((ServerWorld) world, pos, 1, 4); + } + } + } + }); + + UseBlockCallback.EVENT.register(((player, world, hand, hitResult) -> { + // TODO: Make experience amount configurable + BlockState state = world.getBlockState(hitResult.getBlockPos()); + + if (state.getBlock() instanceof SweetBerryBushBlock && world instanceof ServerWorld) { + Util.spawnExp((ServerWorld) world, hitResult.getBlockPos(), 1, 1); + } + + return ActionResult.PASS; + })); + } +} diff --git a/src/main/java/eu/vodofrede/immersivexp/ImmersiveXP.java b/src/main/java/eu/vodofrede/immersivexp/ImmersiveXP.java index 38838ce..d0b8897 100644 --- a/src/main/java/eu/vodofrede/immersivexp/ImmersiveXP.java +++ b/src/main/java/eu/vodofrede/immersivexp/ImmersiveXP.java @@ -1,21 +1,16 @@ package eu.vodofrede.immersivexp; -import net.fabricmc.api.ModInitializer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import net.fabricmc.api.ModInitializer; + public class ImmersiveXP implements ModInitializer { - // This logger is used to write text to the console and the log file. - // It is considered best practice to use your mod id as the logger's name. - // That way, it's clear which mod wrote info, warnings, and errors. public static final Logger LOGGER = LogManager.getLogger("immersivexp"); @Override public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - LOGGER.info("Hello Fabric world!"); + Events.init(); } + } diff --git a/src/main/java/eu/vodofrede/immersivexp/Util.java b/src/main/java/eu/vodofrede/immersivexp/Util.java new file mode 100644 index 0000000..bda3b68 --- /dev/null +++ b/src/main/java/eu/vodofrede/immersivexp/Util.java @@ -0,0 +1,42 @@ +package eu.vodofrede.immersivexp; + +import java.util.LinkedList; + +import net.minecraft.block.BlockState; +import net.minecraft.block.LeavesBlock; +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.tag.BlockTags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Util { + public static boolean isTreeNaturallyGrown(World world, BlockPos pos) { + LinkedList queue = new LinkedList(); + queue.push(pos.up()); + + while (!queue.isEmpty()) { + BlockPos nextPos = queue.pop(); + + BlockPos[] dirs = { nextPos.north(), nextPos.east(), nextPos.south(), nextPos.west(), nextPos.up() }; + for (BlockPos dir : dirs) { + BlockState state = world.getBlockState(dir); + if (state.getBlock() instanceof LeavesBlock && !state.get(LeavesBlock.PERSISTENT)) { + return true; + } + + if (world.getBlockState(dir).isIn(BlockTags.LOGS)) { + queue.push(dir); + } + } + } + + return false; + } + + public static void spawnExp(ServerWorld world, BlockPos pos, int min, int cap) { + Vec3d exp_pos = new Vec3d(pos.getX(), pos.getY(), pos.getZ()); + ExperienceOrbEntity.spawn(world, exp_pos, min + world.random.nextInt(cap)); + } +} diff --git a/src/main/java/eu/vodofrede/immersivexp/mixin/ImmersiveXPMixin.java b/src/main/java/eu/vodofrede/immersivexp/mixin/ImmersiveXPMixin.java index 386ea46..d2e3d67 100644 --- a/src/main/java/eu/vodofrede/immersivexp/mixin/ImmersiveXPMixin.java +++ b/src/main/java/eu/vodofrede/immersivexp/mixin/ImmersiveXPMixin.java @@ -1,16 +1,10 @@ package eu.vodofrede.immersivexp.mixin; -import net.minecraft.client.gui.screen.TitleScreen; 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; -import eu.vodofrede.immersivexp.ImmersiveXP; + +import net.minecraft.client.gui.screen.TitleScreen; @Mixin(TitleScreen.class) public class ImmersiveXPMixin { - @Inject(at = @At("HEAD"), method = "init()V") - private void init(CallbackInfo info) { - ImmersiveXP.LOGGER.info("This line is printed by an example mod mixin!"); - } + } diff --git a/src/main/resources/assets/immersivexp/icon.png b/src/main/resources/assets/immersivexp/icon.png index 047b91f..6beb338 100644 Binary files a/src/main/resources/assets/immersivexp/icon.png and b/src/main/resources/assets/immersivexp/icon.png differ diff --git a/src/main/resources/immersivexp.mixins.json b/src/main/resources/immersivexp.mixins.json index 233687a..ad0da08 100644 --- a/src/main/resources/immersivexp.mixins.json +++ b/src/main/resources/immersivexp.mixins.json @@ -3,7 +3,7 @@ "minVersion": "0.8", "package": "eu.vodofrede.immersivexp.mixin", "compatibilityLevel": "JAVA_16", - "mixins": [], + "mixins": ["ImmersiveXPMixin"], "client": ["ImmersiveXPMixin"], "injectors": { "defaultRequire": 1