diff --git a/src/main/java/dev/micle/firefly_bush_backport/block/FireflyBushBlock.java b/src/main/java/dev/micle/firefly_bush_backport/block/FireflyBushBlock.java index 0d05009..8a2cab3 100644 --- a/src/main/java/dev/micle/firefly_bush_backport/block/FireflyBushBlock.java +++ b/src/main/java/dev/micle/firefly_bush_backport/block/FireflyBushBlock.java @@ -1,5 +1,6 @@ package dev.micle.firefly_bush_backport.block; +import dev.micle.firefly_bush_backport.particle.ModParticles; import dev.micle.firefly_bush_backport.sound.ModSounds; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -36,6 +37,14 @@ public class FireflyBushBlock extends BushBlock implements BonemealableBlock { && level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, blockPos.getX(), blockPos.getZ()) <= blockPos.getY()) { level.playLocalSound(blockPos, ModSounds.FIREFLY_BUSH_IDLE.get(), SoundSource.AMBIENT, 1.0F, 1.0F, false); } + + if ((isMoonVisible(level) || level.getMaxLocalRawBrightness(blockPos) <= FIREFLY_SPAWN_MAX_BRIGHTNESS_LEVEL) && + randomSource.nextDouble() <= FIREFLY_CHANCE_PER_TICK) { + double d0 = blockPos.getX() + randomSource.nextDouble() * FIREFLY_HORIZONTAL_RANGE - FIREFLY_VERTICAL_RANGE; + double d1 = blockPos.getY() + randomSource.nextDouble() * FIREFLY_VERTICAL_RANGE; + double d2 = blockPos.getZ() + randomSource.nextDouble() * FIREFLY_HORIZONTAL_RANGE - FIREFLY_VERTICAL_RANGE; + level.addParticle(ModParticles.FIREFLY.get(), d0, d1, d2, 0.0, 0.0, 0.0); + } } public boolean isMoonVisible(Level level) { diff --git a/src/main/java/dev/micle/firefly_bush_backport/particle/FireflyParticle.java b/src/main/java/dev/micle/firefly_bush_backport/particle/FireflyParticle.java new file mode 100644 index 0000000..703326a --- /dev/null +++ b/src/main/java/dev/micle/firefly_bush_backport/particle/FireflyParticle.java @@ -0,0 +1,104 @@ +package dev.micle.firefly_bush_backport.particle; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.SimpleParticleType; +import net.minecraft.util.Mth; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; + +@OnlyIn(Dist.CLIENT) +public class FireflyParticle extends TextureSheetParticle { + private static final float PARTICLE_FADE_OUT_LIGHT_TIME = 0.3F; + private static final float PARTICLE_FADE_IN_LIGHT_TIME = 0.1F; + private static final float PARTICLE_FADE_OUT_ALPHA_TIME = 0.5F; + private static final float PARTICLE_FADE_IN_ALPHA_TIME = 0.3F; + private static final int PARTICLE_MIN_LIFETIME = 36; + private static final int PARTICLE_MAX_LIFETIME = 180; + + protected FireflyParticle(ClientLevel clientLevel, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { + super(clientLevel, x, y, z, xSpeed, ySpeed, zSpeed); + this.speedUpWhenYMotionIsBlocked = true; + this.friction = 0.96F; + this.quadSize *= 0.75F; + this.yd *= 0.8F; + this.xd *= 0.8F; + this.zd *= 0.8F; + } + + @Override + public @NotNull ParticleRenderType getRenderType() { + return ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT; + } + + @Override + public int getLightColor(float partialTick) { + return (int) (255.0F * getFadeAmount(this.getLifetimeProgress(this.age + partialTick), PARTICLE_FADE_IN_LIGHT_TIME, PARTICLE_FADE_OUT_LIGHT_TIME)); + } + + private static float getFadeAmount(float lifetimeProgress, float fadeIn, float fadeOut) { + if (lifetimeProgress >= 1.0F - fadeIn) { + return (1.0F - lifetimeProgress) / fadeIn; + } else { + return lifetimeProgress <= fadeOut ? lifetimeProgress / fadeOut : 1.0F; + } + } + + private float getLifetimeProgress(float age) { + return Mth.clamp(age / this.lifetime, 0.0F, 1.0F); + } + + @Override + public void tick() { + super.tick(); + if (!this.level.getBlockState(BlockPos.containing(this.x, this.y, this.z)).isAir()) { + this.remove(); + } else { + this.setAlpha(getFadeAmount(this.getLifetimeProgress(this.age), PARTICLE_FADE_IN_ALPHA_TIME, PARTICLE_FADE_OUT_ALPHA_TIME)); + if (Math.random() > 0.95 || this.age == 1) { + this.setParticleSpeed(-0.05F + 0.1F * Math.random(), -0.05F + 0.1F * Math.random(), -0.05F + 0.1F * Math.random()); + } + } + } + + @OnlyIn(Dist.CLIENT) + public static class FireflyProvider implements ParticleProvider { + private final SpriteSet sprite; + + public FireflyProvider(SpriteSet spriteSet) { + this.sprite = spriteSet; + } + + @ParametersAreNonnullByDefault + public Particle createParticle( + SimpleParticleType simpleParticleType, + ClientLevel clientLevel, + double x, + double y, + double z, + double xSpeed, + double ySpeed, + double zSpeed + ) { + FireflyParticle fireflyParticle = new FireflyParticle( + clientLevel, + x, + y, + z, + 0.5 - clientLevel.random.nextDouble(), + clientLevel.random.nextBoolean() ? ySpeed : -ySpeed, + 0.5 - clientLevel.random.nextDouble() + ); + fireflyParticle.setLifetime(clientLevel.random.nextIntBetweenInclusive(PARTICLE_MIN_LIFETIME, PARTICLE_MAX_LIFETIME)); + fireflyParticle.scale(1.5F); + fireflyParticle.pickSprite(this.sprite); + fireflyParticle.setAlpha(0.0F); + + return fireflyParticle; + } + } +} diff --git a/src/main/java/dev/micle/firefly_bush_backport/particle/ModParticles.java b/src/main/java/dev/micle/firefly_bush_backport/particle/ModParticles.java new file mode 100644 index 0000000..7f1114e --- /dev/null +++ b/src/main/java/dev/micle/firefly_bush_backport/particle/ModParticles.java @@ -0,0 +1,20 @@ +package dev.micle.firefly_bush_backport.particle; + +import dev.micle.firefly_bush_backport.FireflyBushBackport; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.particles.SimpleParticleType; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; + +public class ModParticles { + public static final DeferredRegister> PARTICLE_TYPES = DeferredRegister.create(ForgeRegistries.PARTICLE_TYPES, FireflyBushBackport.MOD_ID); + + public static final RegistryObject FIREFLY = PARTICLE_TYPES.register("firefly", + () -> new SimpleParticleType(false)); + + public static void register(IEventBus modEventBus) { + PARTICLE_TYPES.register(modEventBus); + } +} diff --git a/src/main/java/dev/micle/firefly_bush_backport/proxy/Proxy.java b/src/main/java/dev/micle/firefly_bush_backport/proxy/Proxy.java index af50851..720929d 100644 --- a/src/main/java/dev/micle/firefly_bush_backport/proxy/Proxy.java +++ b/src/main/java/dev/micle/firefly_bush_backport/proxy/Proxy.java @@ -5,6 +5,8 @@ import dev.micle.firefly_bush_backport.block.ModBlocks; import dev.micle.firefly_bush_backport.config.Config; import dev.micle.firefly_bush_backport.creative_mode_tab.ModCreativeModeTabs; import dev.micle.firefly_bush_backport.item.ModItems; +import dev.micle.firefly_bush_backport.particle.FireflyParticle; +import dev.micle.firefly_bush_backport.particle.ModParticles; import dev.micle.firefly_bush_backport.sound.ModSounds; import net.minecraft.client.Minecraft; import net.minecraft.server.MinecraftServer; @@ -12,6 +14,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.RegisterParticleProvidersEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.event.server.ServerStartedEvent; @@ -77,16 +80,24 @@ public class Proxy implements IProxy { // Client setup public static class Client extends Proxy { public Client() { - // Register mod event bus listeners IEventBus modEventBus = FireflyBushBackport.getFMLJavaModLoadingContext().getModEventBus(); + + ModParticles.register(modEventBus); + + // Register mod event bus listeners modEventBus.addListener(Client::setup); modEventBus.addListener(Client::postSetup); + modEventBus.addListener(Client::registerParticleFactories); } private static void setup(FMLClientSetupEvent event) {} private static void postSetup(FMLLoadCompleteEvent event) {} + private static void registerParticleFactories(RegisterParticleProvidersEvent event) { + event.registerSpriteSet(ModParticles.FIREFLY.get(), FireflyParticle.FireflyProvider::new); + } + @Override @OnlyIn(Dist.CLIENT) public Player getClientPlayer() { diff --git a/src/main/resources/assets/firefly_bush_backport/particles/firefly.json b/src/main/resources/assets/firefly_bush_backport/particles/firefly.json new file mode 100644 index 0000000..e786ab9 --- /dev/null +++ b/src/main/resources/assets/firefly_bush_backport/particles/firefly.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "firefly_bush_backport:firefly" + ] +} diff --git a/src/main/resources/assets/firefly_bush_backport/textures/particle/firefly.png b/src/main/resources/assets/firefly_bush_backport/textures/particle/firefly.png new file mode 100644 index 0000000..e4ef476 --- /dev/null +++ b/src/main/resources/assets/firefly_bush_backport/textures/particle/firefly.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e13ccf41823ca16b8abeed793b3c39e1936a4fb2f24349f888ea86de7ce0cfbb +size 73