From c04161eb9106463480400a47794e43748441c44a Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 19 Oct 2023 01:41:22 +0100 Subject: [PATCH] Added unstable clouds --- .../unicopia/block/UBlocks.java | 2 + .../block/cloud/UnstableCloudBlock.java | 73 ++++++++++++ .../particle/LightningBoltParticle.java | 110 +++++++++++++----- .../minelittlepony/unicopia/item/UItems.java | 1 + .../particle/LightningBoltParticleEffect.java | 25 +++- .../resources/assets/unicopia/lang/en_us.json | 1 + 6 files changed, 179 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java diff --git a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java index 4beeaa01..2f578642 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java +++ b/src/main/java/com/minelittlepony/unicopia/block/UBlocks.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.block.cloud.PoreousCloudBlock; import com.minelittlepony.unicopia.block.cloud.CloudBlock; import com.minelittlepony.unicopia.block.cloud.SoggyCloudBlock; import com.minelittlepony.unicopia.block.cloud.SoggyCloudSlabBlock; +import com.minelittlepony.unicopia.block.cloud.UnstableCloudBlock; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.group.ItemGroupRegistry; import com.minelittlepony.unicopia.server.world.UTreeGen; @@ -133,6 +134,7 @@ public interface UBlocks { Block CLOUD = register("cloud", new PoreousCloudBlock(Settings.create().mapColor(MapColor.OFF_WHITE).hardness(0.3F).resistance(0).sounds(BlockSoundGroup.WOOL), true, () -> UBlocks.SOGGY_CLOUD)); Block CLOUD_SLAB = register("cloud_slab", new CloudSlabBlock(Settings.copy(CLOUD), true, () -> UBlocks.SOGGY_CLOUD_SLAB)); + Block UNSTABLE_CLOUD = register("unstable_cloud", new UnstableCloudBlock(Settings.copy(CLOUD))); SoggyCloudBlock SOGGY_CLOUD = register("soggy_cloud", new SoggyCloudBlock(Settings.copy(CLOUD), () -> UBlocks.CLOUD)); SoggyCloudSlabBlock SOGGY_CLOUD_SLAB = register("soggy_cloud_slab", new SoggyCloudSlabBlock(Settings.copy(CLOUD), () -> UBlocks.CLOUD_SLAB)); Block DENSE_CLOUD = register("dense_cloud", new CloudBlock(Settings.create().mapColor(MapColor.GRAY).hardness(0.5F).resistance(0).sounds(BlockSoundGroup.WOOL), false)); diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java new file mode 100644 index 00000000..82e59309 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/UnstableCloudBlock.java @@ -0,0 +1,73 @@ +package com.minelittlepony.unicopia.block.cloud; + +import java.util.Optional; + +import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.IntProperty; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; + +public class UnstableCloudBlock extends CloudBlock { + private static final int MAX_CHARGE = 6; + private static final IntProperty CHARGE = IntProperty.of("charge", 0, MAX_CHARGE); + + public UnstableCloudBlock(Settings settings) { + super(settings, false); + setDefaultState(getDefaultState().with(CHARGE, 0)); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(CHARGE); + } + + @Override + public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { + int charge = state.get(CHARGE); + if (charge > 0) { + world.addParticle(new LightningBoltParticleEffect(true, 10, 1, 0.6F + (charge / (float)MAX_CHARGE) * 0.4F, Optional.empty()), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0, 0); + } + } + + @Override + public void onLandedUpon(World world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { + super.onLandedUpon(world, state, pos, entity, fallDistance); + + for (int i = 0; i < 9; i++) { + world.addParticle(ParticleTypes.CLOUD, pos.getX() + world.random.nextFloat(), pos.getY() + world.random.nextFloat(), pos.getZ() + world.random.nextFloat(), 0, 0, 0); + } + world.playSound(null, pos, SoundEvents.BLOCK_WOOL_HIT, SoundCategory.BLOCKS, 1, 1); + + if (state.get(CHARGE) < MAX_CHARGE) { + world.setBlockState(pos, state.cycle(CHARGE)); + } else { + world.setBlockState(pos, state.with(CHARGE, 0)); + BlockPos shockPosition = pos.add(world.random.nextInt(10) - 5, -world.random.nextInt(10), world.random.nextInt(10) - 5); + + world.addImportantParticle( + new LightningBoltParticleEffect(false, 10, 6, 0.3F, Optional.of(shockPosition.toCenterPos())), + true, + pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, + 0, 0, 0 + ); + world.getOtherEntities(null, new Box(shockPosition).expand(2)).forEach(e -> { + e.damage(entity.getDamageSources().lightningBolt(), 1); + }); + + if (world.isAir(shockPosition) && world.getBlockState(shockPosition.down()).isBurnable()) { + world.setBlockState(shockPosition, Blocks.FIRE.getDefaultState()); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/LightningBoltParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/LightningBoltParticle.java index 4fd11f79..745c1b55 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/LightningBoltParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/LightningBoltParticle.java @@ -21,7 +21,7 @@ import net.minecraft.util.math.Vec3d; public class LightningBoltParticle extends AbstractGeometryBasedParticle { - private final List> branches = new ArrayList<>(); + private final List branches = new ArrayList<>(); private final LightningBoltParticleEffect effect; @@ -37,42 +37,73 @@ public class LightningBoltParticle extends AbstractGeometryBasedParticle { return; } - if (age % effect.changeFrequency() == 0) { + if (effect.changeFrequency() > 0 && age % effect.changeFrequency() == 0) { branches.clear(); } - if (branches.isEmpty()) { - int totalBranches = 2 + world.random.nextInt(6); - while (branches.size() < totalBranches) { - branches.add(generateBranch()); - } + if (branches.isEmpty()) { + effect.pathEndPoint().ifPresentOrElse(endpoint -> { + branches.add(generateTrunk(endpoint.subtract(x, y, z).toVector3f())); + }, () -> { + int totalBranches = 2 + world.random.nextInt(effect.maxBranches()); + + while (branches.size() < totalBranches) { + branches.add(generateBranch()); + } + }); if (!effect.silent()) { world.playSound(x, y, z, USounds.Vanilla.ENTITY_LIGHTNING_BOLT_THUNDER, SoundCategory.WEATHER, 10000, 8, true); } } - world.setLightningTicksLeft(2); + if (effect.pathEndPoint().isEmpty() && !effect.silent()) { + world.setLightningTicksLeft(2); + } } - private List generateBranch() { + private Bolt generateTrunk(Vector3f end) { + Vector3f start = new Vector3f(0, 0, 0); + int kinks = 2 + world.random.nextInt(effect.maxBranches()); + + Vector3f segmentLength = end.sub(start, new Vector3f()).mul(1F/kinks); + float deviation = effect.maxDeviation(); + + List nodes = new ArrayList<>(); + nodes.add(start); + + for (int i = 0; i < kinks - 1; i++) { + start = start.add(segmentLength, new Vector3f()).add( + (float)world.random.nextTriangular(0, deviation), + 0, + (float)world.random.nextTriangular(0, deviation) + ); + nodes.add(start); + } + nodes.add(end); + + return new Bolt(true, nodes); + } + + private Bolt generateBranch() { Vector3f startPos = new Vector3f(0, 0, 0); - int intendedLength = 2 + world.random.nextInt(6); - + int intendedLength = 2 + world.random.nextInt(effect.maxBranches()); + float deviation = effect.maxDeviation(); List nodes = new ArrayList<>(); while (nodes.size() < intendedLength) { startPos = startPos.add( - (float)world.random.nextTriangular(0.1F, 3), - (float)world.random.nextTriangular(0.1F, 3), - (float)world.random.nextTriangular(0.1F, 3) + (float)world.random.nextTriangular(0F, deviation), + (float)world.random.nextTriangular(0F, deviation), + (float)world.random.nextTriangular(0F, deviation), + new Vector3f() ); nodes.add(startPos); } - return nodes; + return new Bolt(false, nodes); } @Override @@ -89,10 +120,15 @@ public class LightningBoltParticle extends AbstractGeometryBasedParticle { float z = (float)(MathHelper.lerp(tickDelta, prevPosZ, this.z) - cam.getZ()); Vector3f origin = new Vector3f(x, y, z); + Vector3f from = new Vector3f(); + Vector3f to = new Vector3f(); - for (List branch : branches) { - for (int i = 0; i < branch.size(); i++) { - renderBranch(buffer, i == 0 ? origin : new Vector3f(branch.get(i - 1).add(x, y, z)), new Vector3f(branch.get(i).add(x, y, z))); + for (Bolt branch : branches) { + for (int i = 0; i < branch.nodes().size(); i++) { + renderBranch(buffer, + branch.isTrunk() ? 0.05125F : world.random.nextFloat() / 30 + 0.01F, + i == 0 ? origin : branch.nodes().get(i - 1).add(x, y, z, from), branch.nodes().get(i).add(x, y, z, to) + ); } } @@ -101,14 +137,28 @@ public class LightningBoltParticle extends AbstractGeometryBasedParticle { RenderSystem.enableCull(); } - private void renderBranch(VertexConsumer buffer, Vector3f from, Vector3f to) { - float thickness = world.random.nextFloat() / 30 + 0.01F; - + private void renderBranch(VertexConsumer buffer, float thickness, Vector3f from, Vector3f to) { renderQuad(buffer, new Vector3f[]{ - new Vector3f(from.x - thickness, from.y, from.z), - new Vector3f(to.x - thickness, to.y, to.z), - new Vector3f(to.x + thickness, to.y, to.z), - new Vector3f(from.x + thickness, from.y, from.z), + new Vector3f(from.x - thickness, from.y, from.z + thickness), + new Vector3f(to.x - thickness, to.y, to.z + thickness), + new Vector3f(to.x + thickness, to.y, to.z + thickness), + new Vector3f(from.x + thickness, from.y, from.z + thickness), + + new Vector3f(from.x - thickness, from.y, from.z - thickness), + new Vector3f(to.x - thickness, to.y, to.z - thickness), + new Vector3f(to.x + thickness, to.y, to.z - thickness), + new Vector3f(from.x + thickness, from.y, from.z - thickness), + + new Vector3f(from.x - thickness, from.y, from.z - thickness), + new Vector3f(to.x - thickness, to.y, to.z - thickness), + new Vector3f(to.x - thickness, to.y, to.z + thickness), + new Vector3f(from.x - thickness, from.y, from.z + thickness), + + new Vector3f(from.x + thickness, from.y, from.z - thickness), + new Vector3f(to.x + thickness, to.y, to.z - thickness), + new Vector3f(to.x + thickness, to.y, to.z + thickness), + new Vector3f(from.x + thickness, from.y, from.z + thickness) + /*, new Vector3f(from.x - thickness, from.y - thickness * 2, from.z), new Vector3f(to.x - thickness, to.y - thickness * 2, to.z), @@ -118,12 +168,18 @@ public class LightningBoltParticle extends AbstractGeometryBasedParticle { new Vector3f(from.x, from.y - thickness, from.z + thickness), new Vector3f(to.x, to.y - thickness, to.z + thickness), new Vector3f(to.x, to.y + thickness, to.z + thickness), - new Vector3f(from.x, from.y + thickness, from.z + thickness), + new Vector3f(from.x, from.y + thickness, from.z + thickness) + + , new Vector3f(from.x - thickness * 2, from.y - thickness, from.z + thickness), new Vector3f(to.x - thickness * 2, to.y - thickness, to.z + thickness), new Vector3f(to.x - thickness * 2, to.y + thickness, to.z + thickness), - new Vector3f(from.x - thickness * 2, from.y + thickness, from.z + thickness) + new Vector3f(from.x - thickness * 2, from.y + thickness, from.z + thickness)*/ }, 0.3F, 1); } + + record Bolt(boolean isTrunk, List nodes) { + + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 954c20fd..e91f1db4 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -149,6 +149,7 @@ public interface UItems { Item DENSE_CLOUD = register("dense_cloud", new CloudBlockItem(UBlocks.DENSE_CLOUD, new Item.Settings()), ItemGroups.NATURAL); Item DENSE_CLOUD_SLAB = register("dense_cloud_slab", new CloudBlockItem(UBlocks.DENSE_CLOUD_SLAB, new Item.Settings()), ItemGroups.NATURAL); Item CLOUD_PILLAR = register("cloud_pillar", new CloudBlockItem(UBlocks.CLOUD_PILLAR, new Item.Settings()), ItemGroups.NATURAL); + Item UNSTABLE_CLOUD = register("unstable_cloud", new CloudBlockItem(UBlocks.UNSTABLE_CLOUD, new Item.Settings()), ItemGroups.NATURAL); AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new PegasusAmuletItem(new FabricItemSettings() .maxCount(1) diff --git a/src/main/java/com/minelittlepony/unicopia/particle/LightningBoltParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/LightningBoltParticleEffect.java index 85e54009..321b6114 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/LightningBoltParticleEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/LightningBoltParticleEffect.java @@ -1,27 +1,38 @@ package com.minelittlepony.unicopia.particle; +import java.util.Optional; + import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.network.PacketByteBuf; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleType; +import net.minecraft.util.math.Vec3d; public record LightningBoltParticleEffect ( boolean silent, int changeFrequency, - int maxBranchLength + int maxBranches, + float maxDeviation, + Optional pathEndPoint ) implements ParticleEffect { - public static final LightningBoltParticleEffect DEFAULT = new LightningBoltParticleEffect(false, 10, 6); + public static final LightningBoltParticleEffect DEFAULT = new LightningBoltParticleEffect(false, 10, 6, 3, Optional.empty()); @SuppressWarnings("deprecation") public static final ParticleEffect.Factory FACTORY = ParticleFactoryHelper.of(LightningBoltParticleEffect::new, LightningBoltParticleEffect::new); protected LightningBoltParticleEffect(ParticleType particleType, StringReader reader) throws CommandSyntaxException { - this(ParticleFactoryHelper.readBoolean(reader), ParticleFactoryHelper.readInt(reader), ParticleFactoryHelper.readInt(reader)); + this( + ParticleFactoryHelper.readBoolean(reader), + ParticleFactoryHelper.readInt(reader), + ParticleFactoryHelper.readInt(reader), + ParticleFactoryHelper.readFloat(reader), + ParticleFactoryHelper.readOptional(reader, ParticleFactoryHelper::readVector) + ); } protected LightningBoltParticleEffect(ParticleType particleType, PacketByteBuf buf) { - this(buf.readBoolean(), buf.readInt(), buf.readInt()); + this(buf.readBoolean(), buf.readInt(), buf.readInt(), buf.readFloat(), buf.readOptional(ParticleFactoryHelper::readVector)); } @Override @@ -33,12 +44,14 @@ public record LightningBoltParticleEffect ( public void write(PacketByteBuf buffer) { buffer.writeBoolean(silent); buffer.writeInt(changeFrequency); - buffer.writeInt(maxBranchLength); + buffer.writeInt(maxBranches); + buffer.writeFloat(maxDeviation); + buffer.writeOptional(pathEndPoint, ParticleFactoryHelper::writeVector); } @Override public String asString() { - return String.format("%s %s %s", silent, changeFrequency, maxBranchLength); + return String.format("%s %s %s %s", silent, changeFrequency, maxBranches, maxDeviation); } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index d3df60ba..bfcb75d1 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -221,6 +221,7 @@ "block.unicopia.cloud_slab": "Cloud Slab", "block.unicopia.soggy_cloud": "Soggy Cloud", "block.unicopia.soggy_cloud_slab": "Soggy Cloud Slab", + "block.unicopia.unstable_cloud": "Unstable Cloud", "block.unicopia.cloud_pillar": "Cloud Pillar", "block.unicopia.dense_cloud": "Dense Cloud", "block.unicopia.dense_cloud_slab": "Dense Cloud Slab",