mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 07:03:41 +01:00
Range indication for bells
- Stationary Haunted Bells now show particles at the perimeter of the scanned area, regardless of light level
This commit is contained in:
parent
efa2bc745f
commit
10b0bdbfcf
6 changed files with 148 additions and 33 deletions
|
@ -35,7 +35,9 @@ public enum AllParticleTypes {
|
|||
BASIN_FLUID(FluidParticleData::new),
|
||||
FLUID_DRIP(FluidParticleData::new),
|
||||
SOUL(SoulParticle.Data::new),
|
||||
SOUL_BASE(SoulBaseParticle.Data::new)
|
||||
SOUL_BASE(SoulBaseParticle.Data::new),
|
||||
SOUL_PERIMETER(SoulParticle.PerimeterData::new),
|
||||
SOUL_EXPANDING_PERIMETER(SoulParticle.ExpandingPerimeterData::new)
|
||||
;
|
||||
|
||||
private ParticleEntry<?> entry;
|
||||
|
|
|
@ -31,7 +31,7 @@ public class SoulBaseParticle extends CustomRotationParticle {
|
|||
selectSpriteLoopingWithAge(animatedSprite);
|
||||
|
||||
BlockPos pos = new BlockPos(posX, posY, posZ);
|
||||
if (age++ >= maxAge || !SoulPulseEffect.canSpawnSoulAt(world, pos))
|
||||
if (age++ >= maxAge || !SoulPulseEffect.canSpawnSoulAt(world, pos, false))
|
||||
setExpired();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package com.simibubi.create.content.curiosities.bell;
|
||||
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import com.simibubi.create.AllParticleTypes;
|
||||
|
||||
import net.minecraft.client.particle.IAnimatedSprite;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Quaternion;
|
||||
import net.minecraft.util.math.vector.Vector3f;
|
||||
|
||||
public class SoulParticle extends CustomRotationParticle {
|
||||
|
||||
|
@ -26,14 +29,18 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
protected int firstEndFrame = 33;
|
||||
protected int endFrames = 20;
|
||||
|
||||
protected int totalFrames = 53;
|
||||
|
||||
protected int ticksPerFrame = 2;
|
||||
|
||||
protected AnimationStage animationStage;
|
||||
|
||||
protected int totalFrames = 53;
|
||||
protected int ticksPerFrame = 2;
|
||||
|
||||
protected boolean isPerimeter = false;
|
||||
protected boolean isExpandingPerimeter = false;
|
||||
protected boolean isVisible = true;
|
||||
protected int perimeterFrames = 8;
|
||||
|
||||
public SoulParticle(ClientWorld worldIn, double x, double y, double z, double vx, double vy, double vz,
|
||||
IAnimatedSprite spriteSet) {
|
||||
IAnimatedSprite spriteSet, IParticleData data) {
|
||||
super(worldIn, x, y, z, spriteSet, 0);
|
||||
this.animatedSprite = spriteSet;
|
||||
this.particleScale = 0.5f;
|
||||
|
@ -42,24 +49,43 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
this.loopLength = loopFrames + (int) (this.rand.nextFloat() * 5f - 4f);
|
||||
this.startTicks = startFrames + (int) (this.rand.nextFloat() * 5f - 4f);
|
||||
this.endTicks = endFrames + (int) (this.rand.nextFloat() * 5f - 4f);
|
||||
this.numLoops = (int)(1f + this.rand.nextFloat() * 2f);
|
||||
this.numLoops = (int) (1f + this.rand.nextFloat() * 2f);
|
||||
|
||||
this.setFrame(0);
|
||||
this.field_21507 = true; // disable movement
|
||||
this.mirror = this.rand.nextBoolean();
|
||||
|
||||
this.animationStage = new StartAnimation(this);
|
||||
this.isPerimeter = data instanceof PerimeterData;
|
||||
this.isExpandingPerimeter = data instanceof ExpandingPerimeterData;
|
||||
this.animationStage = !isPerimeter ? new StartAnimation(this) : new PerimeterAnimation(this);
|
||||
if (isPerimeter) {
|
||||
prevPosY = posY -= .5f - 1 / 128f;
|
||||
totalFrames = perimeterFrames;
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
animationStage.tick();
|
||||
|
||||
animationStage = animationStage.getNext();
|
||||
|
||||
BlockPos pos = new BlockPos(posX, posY, posZ);
|
||||
if (animationStage == null || !SoulPulseEffect.canSpawnSoulAt(world, pos))
|
||||
if (animationStage == null)
|
||||
setExpired();
|
||||
if (!SoulPulseEffect.canSpawnSoulAt(world, pos, false)) {
|
||||
isVisible = true;
|
||||
if (!isPerimeter)
|
||||
setExpired();
|
||||
} else if (isPerimeter)
|
||||
isVisible = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildGeometry(IVertexBuilder builder, ActiveRenderInfo camera, float partialTicks) {
|
||||
if (!isVisible)
|
||||
return;
|
||||
super.buildGeometry(builder, camera, partialTicks);
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
|
@ -69,20 +95,44 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
|
||||
@Override
|
||||
public Quaternion getCustomRotation(ActiveRenderInfo camera, float partialTicks) {
|
||||
if (isPerimeter)
|
||||
return Vector3f.POSITIVE_X.getDegreesQuaternion(90);
|
||||
return new Quaternion(0, -camera.getYaw(), 0, true);
|
||||
}
|
||||
|
||||
public static class Data extends BasicParticleData<SoulParticle> {
|
||||
@Override
|
||||
public IBasicParticleFactory<SoulParticle> getBasicFactory() {
|
||||
return SoulParticle::new;
|
||||
return (worldIn, x, y, z, vx, vy, vz, spriteSet) -> new SoulParticle(worldIn, x, y, z, vx, vy, vz,
|
||||
spriteSet, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParticleType<?> getType() {
|
||||
return AllParticleTypes.SOUL.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static class PerimeterData extends BasicParticleData<SoulParticle> {
|
||||
@Override
|
||||
public IBasicParticleFactory<SoulParticle> getBasicFactory() {
|
||||
return (worldIn, x, y, z, vx, vy, vz, spriteSet) -> new SoulParticle(worldIn, x, y, z, vx, vy, vz,
|
||||
spriteSet, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParticleType<?> getType() {
|
||||
return AllParticleTypes.SOUL_PERIMETER.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExpandingPerimeterData extends PerimeterData {
|
||||
@Override
|
||||
public ParticleType<?> getType() {
|
||||
return AllParticleTypes.SOUL_EXPANDING_PERIMETER.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class AnimationStage {
|
||||
|
||||
protected final SoulParticle particle;
|
||||
|
@ -118,7 +168,8 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
particle.setFrame(particle.firstStartFrame + (int) (getAnimAge() / (float) particle.startTicks * particle.startFrames));
|
||||
particle.setFrame(
|
||||
particle.firstStartFrame + (int) (getAnimAge() / (float) particle.startTicks * particle.startFrames));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,9 +195,11 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
|
||||
int loopTick = getLoopTick();
|
||||
|
||||
if (loopTick == 0) loops++;
|
||||
if (loopTick == 0)
|
||||
loops++;
|
||||
|
||||
particle.setFrame(particle.firstLoopFrame + loopTick);//(int) (((float) loopTick / (float) particle.loopLength) * particle.loopFrames));
|
||||
particle.setFrame(particle.firstLoopFrame + loopTick);// (int) (((float) loopTick / (float)
|
||||
// particle.loopLength) * particle.loopFrames));
|
||||
|
||||
}
|
||||
|
||||
|
@ -173,7 +226,8 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
particle.setFrame(particle.firstEndFrame + (int) ((getAnimAge() / (float) particle.endTicks) * particle.endFrames));
|
||||
particle.setFrame(
|
||||
particle.firstEndFrame + (int) ((getAnimAge() / (float) particle.endTicks) * particle.endFrames));
|
||||
|
||||
}
|
||||
|
||||
|
@ -185,4 +239,26 @@ public class SoulParticle extends CustomRotationParticle {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PerimeterAnimation extends AnimationStage {
|
||||
|
||||
public PerimeterAnimation(SoulParticle particle) {
|
||||
super(particle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
particle.setFrame((int) getAnimAge() % particle.perimeterFrames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimationStage getNext() {
|
||||
if (animAge < (particle.isExpandingPerimeter ? 8
|
||||
: particle.startTicks + particle.endTicks + particle.numLoops * particle.loopLength))
|
||||
return this;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.simibubi.create.content.curiosities.bell.SoulParticle.ExpandingPerimeterData;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.entity.EntitySpawnPlacementRegistry;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
@ -17,7 +20,7 @@ import net.minecraft.world.spawner.WorldEntitySpawner;
|
|||
|
||||
public class SoulPulseEffect {
|
||||
|
||||
public static final int MAX_DISTANCE = 10;
|
||||
public static final int MAX_DISTANCE = 11;
|
||||
private static final List<List<BlockPos>> LAYERS = genLayers();
|
||||
|
||||
private static final int WAITING_TICKS = 100;
|
||||
|
@ -50,10 +53,10 @@ public class SoulPulseEffect {
|
|||
if (ticks < 0 || ticks % TICKS_PER_LAYER != 0)
|
||||
return null;
|
||||
|
||||
List<BlockPos> spawns = getSoulSpawns(world);
|
||||
List<BlockPos> spawns = getPotentialSoulSpawns(world);
|
||||
while (spawns.isEmpty() && ticks > 0) {
|
||||
ticks -= TICKS_PER_LAYER;
|
||||
spawns.addAll(getSoulSpawns(world));
|
||||
spawns.addAll(getPotentialSoulSpawns(world));
|
||||
}
|
||||
return spawns;
|
||||
}
|
||||
|
@ -62,28 +65,30 @@ public class SoulPulseEffect {
|
|||
return distance - ticks / TICKS_PER_LAYER - 1;
|
||||
}
|
||||
|
||||
public List<BlockPos> getSoulSpawns(World world) {
|
||||
public List<BlockPos> getPotentialSoulSpawns(World world) {
|
||||
if (world == null)
|
||||
return new ArrayList<>();
|
||||
|
||||
return getLayer(currentLayerIdx()).map(p -> p.add(pos))
|
||||
.filter(p -> canSpawnSoulAt(world, p))
|
||||
.collect(Collectors.toList());
|
||||
.filter(p -> canSpawnSoulAt(world, p, true))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static boolean canSpawnSoulAt(World world, BlockPos at) {
|
||||
public static boolean canSpawnSoulAt(World world, BlockPos at, boolean ignoreLight) {
|
||||
EntityType<?> dummy = EntityType.ZOMBIE;
|
||||
double dummyWidth = 0.2, dummyHeight = 0.75;
|
||||
double w2 = dummyWidth / 2;
|
||||
|
||||
return world != null
|
||||
&& WorldEntitySpawner.canCreatureTypeSpawnAtLocation(
|
||||
EntitySpawnPlacementRegistry.PlacementType.ON_GROUND, world, at, dummy)
|
||||
&& world.getLightLevel(LightType.BLOCK, at) < 8
|
||||
&& world.getBlockCollisions(null, new AxisAlignedBB(
|
||||
at.getX() + 0.5 - w2, at.getY(), at.getZ() + 0.5 - w2,
|
||||
at.getX() + 0.5 + w2, at.getY() + dummyHeight, at.getZ() + 0.5 + w2
|
||||
), (a,b) -> true).allMatch(VoxelShape::isEmpty);
|
||||
&& WorldEntitySpawner
|
||||
.canCreatureTypeSpawnAtLocation(EntitySpawnPlacementRegistry.PlacementType.ON_GROUND, world, at, dummy)
|
||||
&& (ignoreLight || world.getLightLevel(LightType.BLOCK, at) < 8)
|
||||
&& world
|
||||
.getBlockCollisions(null,
|
||||
new AxisAlignedBB(at.getX() + 0.5 - w2, at.getY(), at.getZ() + 0.5 - w2, at.getX() + 0.5 + w2,
|
||||
at.getY() + dummyHeight, at.getZ() + 0.5 + w2),
|
||||
(a, b) -> true)
|
||||
.allMatch(VoxelShape::isEmpty);
|
||||
}
|
||||
|
||||
public void spawnParticles(World world, BlockPos at) {
|
||||
|
@ -91,8 +96,15 @@ public class SoulPulseEffect {
|
|||
return;
|
||||
|
||||
Vector3d p = Vector3d.of(at);
|
||||
world.addOptionalParticle(new SoulParticle.Data(), p.x + 0.5, p.y + 0.5, p.z + 0.5, 0, 0, 0);
|
||||
world.addParticle(new SoulBaseParticle.Data(), p.x + 0.5, p.y + 0.01, p.z + 0.5, 0, 0, 0);
|
||||
if (canOverlap())
|
||||
world.addOptionalParticle(((int) Math.round(VecHelper.getCenterOf(pos)
|
||||
.distanceTo(VecHelper.getCenterOf(at)))) >= distance ? new SoulParticle.PerimeterData()
|
||||
: new ExpandingPerimeterData(),
|
||||
p.x + 0.5, p.y + 0.5, p.z + 0.5, 0, 0, 0);
|
||||
if (world.getLightLevel(LightType.BLOCK, at) < 8) {
|
||||
world.addOptionalParticle(new SoulParticle.Data(), p.x + 0.5, p.y + 0.5, p.z + 0.5, 0, 0, 0);
|
||||
world.addParticle(new SoulBaseParticle.Data(), p.x + 0.5, p.y + 0.01, p.z + 0.5, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<List<BlockPos>> genLayers() {
|
||||
|
@ -142,7 +154,8 @@ public class SoulPulseEffect {
|
|||
public static Stream<BlockPos> getLayer(int idx) {
|
||||
if (idx < 0 || idx >= MAX_DISTANCE)
|
||||
return Stream.empty();
|
||||
return LAYERS.get(idx).stream();
|
||||
return LAYERS.get(idx)
|
||||
.stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"textures": [
|
||||
"create:soul_base_0",
|
||||
"create:soul_base_1",
|
||||
"create:soul_base_2",
|
||||
"create:soul_base_3",
|
||||
"create:soul_base_2",
|
||||
"create:soul_base_1",
|
||||
"create:soul_base_0",
|
||||
"create:soul_base_0"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"textures": [
|
||||
"create:soul_base_0",
|
||||
"create:soul_base_1",
|
||||
"create:soul_base_2",
|
||||
"create:soul_base_3",
|
||||
"create:soul_base_4",
|
||||
"create:soul_base_5",
|
||||
"create:soul_base_6",
|
||||
"create:soul_base_7"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue