From f4b7a8f6b46274a7ff43111196d2552d29eea41d Mon Sep 17 00:00:00 2001 From: iceBear67 Date: Sun, 14 Jul 2024 14:29:57 +0800 Subject: [PATCH] add(feat): fertilize nearby sapling & crops by shifting continuously #8 --- .../io/ib67/sfcraft/SFCraftInitializer.java | 1 + .../io/ib67/sfcraft/callback/SFCallbacks.java | 6 ++ .../sfcraft/mixin/server/EntityMixin.java | 25 +++++++ .../sfcraft/module/FartFertilizerModule.java | 67 +++++++++++++++++++ .../sfcraft/module/chat/ChatPingModule.java | 2 +- .../java/io/ib67/sfcraft/util/Helper.java | 9 +++ src/main/resources/sfcraft.mixins.json | 1 + 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/ib67/sfcraft/mixin/server/EntityMixin.java create mode 100644 src/main/java/io/ib67/sfcraft/module/FartFertilizerModule.java diff --git a/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java b/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java index 6d7573b..86db8aa 100644 --- a/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java +++ b/src/main/java/io/ib67/sfcraft/SFCraftInitializer.java @@ -44,6 +44,7 @@ public class SFCraftInitializer extends GuiceModInitializer { registerFeature(BackModule.class); registerFeature(ManagementModule.class); registerFeature(AFKModule.class); + registerFeature(FartFertilizerModule.class); registerFeature(ChatPingModule.class); registerFeature(ChatSendLocModule.class); registerFeature(LongNightModule.class); diff --git a/src/main/java/io/ib67/sfcraft/callback/SFCallbacks.java b/src/main/java/io/ib67/sfcraft/callback/SFCallbacks.java index 5b3bdf7..816b402 100644 --- a/src/main/java/io/ib67/sfcraft/callback/SFCallbacks.java +++ b/src/main/java/io/ib67/sfcraft/callback/SFCallbacks.java @@ -31,6 +31,12 @@ public interface SFCallbacks { l -> (s, c) -> first(l, t -> t.onMotd(s, c))); Event PLAYER_IDLE = EventFactory.createArrayBacked(PlayerIdlingCallback.class, l -> (p, a) -> forEach(l, i -> i.onSwitchIdle(p, a))); + Event PLAYER_SNEAKING = EventFactory.createArrayBacked(PlayerSneakingCallback.class, + l -> (p, a) -> forEach(l, i -> i.onSneaking(p, a))); + + interface PlayerSneakingCallback { + void onSneaking(PlayerEntity player, boolean sneak); + } interface PlayerIdlingCallback { void onSwitchIdle(ServerPlayerEntity player, boolean afk); diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/EntityMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/EntityMixin.java new file mode 100644 index 0000000..f65750c --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/mixin/server/EntityMixin.java @@ -0,0 +1,25 @@ +package io.ib67.sfcraft.mixin.server; + +import io.ib67.sfcraft.callback.SFCallbacks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Entity.class) +public abstract class EntityMixin { + @Inject(method = "setSneaking", at = @At("HEAD")) + public void onSneaking(boolean sneaking, CallbackInfo ci) { + if ($this() instanceof PlayerEntity pe) { + SFCallbacks.PLAYER_SNEAKING.invoker().onSneaking(pe, sneaking); + } + } + + @Unique + private Entity $this() { + return (Entity) (Object) this; + } +} diff --git a/src/main/java/io/ib67/sfcraft/module/FartFertilizerModule.java b/src/main/java/io/ib67/sfcraft/module/FartFertilizerModule.java new file mode 100644 index 0000000..a065df9 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/module/FartFertilizerModule.java @@ -0,0 +1,67 @@ +package io.ib67.sfcraft.module; + +import io.ib67.sfcraft.ServerModule; +import io.ib67.sfcraft.callback.SFCallbacks; +import io.ib67.sfcraft.util.Helper; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import net.fabricmc.fabric.api.networking.v1.PlayerLookup; +import net.minecraft.block.Fertilizable; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; + +public class FartFertilizerModule extends ServerModule { + private final Object2LongMap lastSneaked = new Object2LongOpenHashMap<>(); + + @Override + public void onInitialize() { + SFCallbacks.PLAYER_SNEAKING.register(this::onSneaking); + } + + private void onSneaking(PlayerEntity player, boolean sneak) { + if (sneak) { + var lastSneak = lastSneaked.getOrDefault(player, 0); + var dlta = Math.min(System.currentTimeMillis() - lastSneak, 100); + if (player.getRandom().nextBetween(50, 150) > dlta) { + var playerPos = player.getBlockPos(); + var start = playerPos.add(-2, 0, -2); + var end = playerPos.add(2, 1, 2); + for (int dX = 0; dX < end.getX() - start.getX(); dX++) { + for (int dZ = 0; dZ < end.getZ() - start.getZ(); dZ++) { + for (int dY = 0; dY < end.getY() - start.getY(); dY++) { + var blockPos = start.add(dX, dY, dZ); + var state = player.getWorld().getBlockState(blockPos); + var block = state.getBlock(); + if (Helper.canFertilize(block)) { + var wld = (ServerWorld) player.getWorld(); + wld.spawnParticles( + ParticleTypes.COMPOSTER, + blockPos.getX(), blockPos.getY(), blockPos.getZ(), 5, + Math.max(0.5, Math.random()), Math.max(0.5, Math.random()), Math.max(0.5, Math.random()), + 0.4 + ); + for (ServerPlayerEntity serverPlayerEntity : PlayerLookup.around(wld, blockPos, 6f)) { + serverPlayerEntity.playSoundToPlayer( + SoundEvents.BLOCK_COMPOSTER_FILL, + SoundCategory.BLOCKS, + ((6 - serverPlayerEntity.distanceTo(player) + 1) / 6) * 50, + 3f + ); + } + if (player.getRandom().nextInt(10) < 3) { + ((Fertilizable) block).grow(wld, + wld.getRandom(), blockPos, state); + } + } + } + } + } + } + lastSneaked.put(player, System.currentTimeMillis()); + } + } +} diff --git a/src/main/java/io/ib67/sfcraft/module/chat/ChatPingModule.java b/src/main/java/io/ib67/sfcraft/module/chat/ChatPingModule.java index 864073e..4a6a320 100644 --- a/src/main/java/io/ib67/sfcraft/module/chat/ChatPingModule.java +++ b/src/main/java/io/ib67/sfcraft/module/chat/ChatPingModule.java @@ -55,7 +55,7 @@ public class ChatPingModule extends ServerModule implements MessageDecorator { foundPlayer.sendMessage(Text.literal(sender.getName().getLiteralString() + " 正在叫你。").withColor(Colors.LIGHT_GRAY)); } foundPlayer.playSoundToPlayer( - SoundEvent.of(SoundEvents.ENTITY_ITEM_PICKUP.getId()), + SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 0.8f, 0.5f diff --git a/src/main/java/io/ib67/sfcraft/util/Helper.java b/src/main/java/io/ib67/sfcraft/util/Helper.java index 622a9db..8950135 100644 --- a/src/main/java/io/ib67/sfcraft/util/Helper.java +++ b/src/main/java/io/ib67/sfcraft/util/Helper.java @@ -5,6 +5,10 @@ import io.ib67.sfcraft.SFCraft; import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.geoip.GeoIPService; import lombok.SneakyThrows; +import net.minecraft.block.Block; +import net.minecraft.block.CropBlock; +import net.minecraft.block.Fertilizable; +import net.minecraft.block.SaplingBlock; import net.minecraft.fluid.EmptyFluid; import net.minecraft.fluid.LavaFluid; import net.minecraft.fluid.WaterFluid; @@ -93,4 +97,9 @@ public class Helper { public static int fromRgb(int r, int g, int b) { return ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff); } + + public static boolean canFertilize(Block block) { + return block instanceof SaplingBlock + || block instanceof CropBlock; + } } diff --git a/src/main/resources/sfcraft.mixins.json b/src/main/resources/sfcraft.mixins.json index 5f3939b..a51fded 100644 --- a/src/main/resources/sfcraft.mixins.json +++ b/src/main/resources/sfcraft.mixins.json @@ -14,6 +14,7 @@ "server.ServerPlayNetworkHandlerMixin", "server.SleepManagerMixin", "server.ServerWorldMixin", + "server.EntityMixin", "server.AbstractFurnaceBlockMixin", "server.ServerHandshakeNetworkHandlerMixin", "server.LegacyQueryHandlerMixin",