mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 11:33:43 +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),
|
BASIN_FLUID(FluidParticleData::new),
|
||||||
FLUID_DRIP(FluidParticleData::new),
|
FLUID_DRIP(FluidParticleData::new),
|
||||||
SOUL(SoulParticle.Data::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;
|
private ParticleEntry<?> entry;
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class SoulBaseParticle extends CustomRotationParticle {
|
||||||
selectSpriteLoopingWithAge(animatedSprite);
|
selectSpriteLoopingWithAge(animatedSprite);
|
||||||
|
|
||||||
BlockPos pos = new BlockPos(posX, posY, posZ);
|
BlockPos pos = new BlockPos(posX, posY, posZ);
|
||||||
if (age++ >= maxAge || !SoulPulseEffect.canSpawnSoulAt(world, pos))
|
if (age++ >= maxAge || !SoulPulseEffect.canSpawnSoulAt(world, pos, false))
|
||||||
setExpired();
|
setExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package com.simibubi.create.content.curiosities.bell;
|
package com.simibubi.create.content.curiosities.bell;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
import com.simibubi.create.AllParticleTypes;
|
import com.simibubi.create.AllParticleTypes;
|
||||||
|
|
||||||
import net.minecraft.client.particle.IAnimatedSprite;
|
import net.minecraft.client.particle.IAnimatedSprite;
|
||||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
import net.minecraft.particles.IParticleData;
|
||||||
import net.minecraft.particles.ParticleType;
|
import net.minecraft.particles.ParticleType;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.vector.Quaternion;
|
import net.minecraft.util.math.vector.Quaternion;
|
||||||
|
import net.minecraft.util.math.vector.Vector3f;
|
||||||
|
|
||||||
public class SoulParticle extends CustomRotationParticle {
|
public class SoulParticle extends CustomRotationParticle {
|
||||||
|
|
||||||
|
@ -26,14 +29,18 @@ public class SoulParticle extends CustomRotationParticle {
|
||||||
protected int firstEndFrame = 33;
|
protected int firstEndFrame = 33;
|
||||||
protected int endFrames = 20;
|
protected int endFrames = 20;
|
||||||
|
|
||||||
protected int totalFrames = 53;
|
|
||||||
|
|
||||||
protected int ticksPerFrame = 2;
|
|
||||||
|
|
||||||
protected AnimationStage animationStage;
|
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,
|
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);
|
super(worldIn, x, y, z, spriteSet, 0);
|
||||||
this.animatedSprite = spriteSet;
|
this.animatedSprite = spriteSet;
|
||||||
this.particleScale = 0.5f;
|
this.particleScale = 0.5f;
|
||||||
|
@ -42,24 +49,43 @@ public class SoulParticle extends CustomRotationParticle {
|
||||||
this.loopLength = loopFrames + (int) (this.rand.nextFloat() * 5f - 4f);
|
this.loopLength = loopFrames + (int) (this.rand.nextFloat() * 5f - 4f);
|
||||||
this.startTicks = startFrames + (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.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.setFrame(0);
|
||||||
this.field_21507 = true; // disable movement
|
this.field_21507 = true; // disable movement
|
||||||
this.mirror = this.rand.nextBoolean();
|
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
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
animationStage.tick();
|
animationStage.tick();
|
||||||
|
|
||||||
animationStage = animationStage.getNext();
|
animationStage = animationStage.getNext();
|
||||||
|
|
||||||
BlockPos pos = new BlockPos(posX, posY, posZ);
|
BlockPos pos = new BlockPos(posX, posY, posZ);
|
||||||
if (animationStage == null || !SoulPulseEffect.canSpawnSoulAt(world, pos))
|
if (animationStage == null)
|
||||||
setExpired();
|
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) {
|
public void setFrame(int frame) {
|
||||||
|
@ -69,20 +95,44 @@ public class SoulParticle extends CustomRotationParticle {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Quaternion getCustomRotation(ActiveRenderInfo camera, float partialTicks) {
|
public Quaternion getCustomRotation(ActiveRenderInfo camera, float partialTicks) {
|
||||||
|
if (isPerimeter)
|
||||||
|
return Vector3f.POSITIVE_X.getDegreesQuaternion(90);
|
||||||
return new Quaternion(0, -camera.getYaw(), 0, true);
|
return new Quaternion(0, -camera.getYaw(), 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Data extends BasicParticleData<SoulParticle> {
|
public static class Data extends BasicParticleData<SoulParticle> {
|
||||||
@Override
|
@Override
|
||||||
public IBasicParticleFactory<SoulParticle> getBasicFactory() {
|
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
|
@Override
|
||||||
public ParticleType<?> getType() {
|
public ParticleType<?> getType() {
|
||||||
return AllParticleTypes.SOUL.get();
|
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 {
|
public static abstract class AnimationStage {
|
||||||
|
|
||||||
protected final SoulParticle particle;
|
protected final SoulParticle particle;
|
||||||
|
@ -118,7 +168,8 @@ public class SoulParticle extends CustomRotationParticle {
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.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
|
@Override
|
||||||
|
@ -144,9 +195,11 @@ public class SoulParticle extends CustomRotationParticle {
|
||||||
|
|
||||||
int loopTick = getLoopTick();
|
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() {
|
public void tick() {
|
||||||
super.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;
|
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.Collectors;
|
||||||
import java.util.stream.Stream;
|
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.EntitySpawnPlacementRegistry;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
@ -17,7 +20,7 @@ import net.minecraft.world.spawner.WorldEntitySpawner;
|
||||||
|
|
||||||
public class SoulPulseEffect {
|
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 List<List<BlockPos>> LAYERS = genLayers();
|
||||||
|
|
||||||
private static final int WAITING_TICKS = 100;
|
private static final int WAITING_TICKS = 100;
|
||||||
|
@ -50,10 +53,10 @@ public class SoulPulseEffect {
|
||||||
if (ticks < 0 || ticks % TICKS_PER_LAYER != 0)
|
if (ticks < 0 || ticks % TICKS_PER_LAYER != 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
List<BlockPos> spawns = getSoulSpawns(world);
|
List<BlockPos> spawns = getPotentialSoulSpawns(world);
|
||||||
while (spawns.isEmpty() && ticks > 0) {
|
while (spawns.isEmpty() && ticks > 0) {
|
||||||
ticks -= TICKS_PER_LAYER;
|
ticks -= TICKS_PER_LAYER;
|
||||||
spawns.addAll(getSoulSpawns(world));
|
spawns.addAll(getPotentialSoulSpawns(world));
|
||||||
}
|
}
|
||||||
return spawns;
|
return spawns;
|
||||||
}
|
}
|
||||||
|
@ -62,28 +65,30 @@ public class SoulPulseEffect {
|
||||||
return distance - ticks / TICKS_PER_LAYER - 1;
|
return distance - ticks / TICKS_PER_LAYER - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BlockPos> getSoulSpawns(World world) {
|
public List<BlockPos> getPotentialSoulSpawns(World world) {
|
||||||
if (world == null)
|
if (world == null)
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
|
||||||
return getLayer(currentLayerIdx()).map(p -> p.add(pos))
|
return getLayer(currentLayerIdx()).map(p -> p.add(pos))
|
||||||
.filter(p -> canSpawnSoulAt(world, p))
|
.filter(p -> canSpawnSoulAt(world, p, true))
|
||||||
.collect(Collectors.toList());
|
.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;
|
EntityType<?> dummy = EntityType.ZOMBIE;
|
||||||
double dummyWidth = 0.2, dummyHeight = 0.75;
|
double dummyWidth = 0.2, dummyHeight = 0.75;
|
||||||
double w2 = dummyWidth / 2;
|
double w2 = dummyWidth / 2;
|
||||||
|
|
||||||
return world != null
|
return world != null
|
||||||
&& WorldEntitySpawner.canCreatureTypeSpawnAtLocation(
|
&& WorldEntitySpawner
|
||||||
EntitySpawnPlacementRegistry.PlacementType.ON_GROUND, world, at, dummy)
|
.canCreatureTypeSpawnAtLocation(EntitySpawnPlacementRegistry.PlacementType.ON_GROUND, world, at, dummy)
|
||||||
&& world.getLightLevel(LightType.BLOCK, at) < 8
|
&& (ignoreLight || world.getLightLevel(LightType.BLOCK, at) < 8)
|
||||||
&& world.getBlockCollisions(null, new AxisAlignedBB(
|
&& world
|
||||||
at.getX() + 0.5 - w2, at.getY(), at.getZ() + 0.5 - w2,
|
.getBlockCollisions(null,
|
||||||
at.getX() + 0.5 + w2, at.getY() + dummyHeight, at.getZ() + 0.5 + w2
|
new AxisAlignedBB(at.getX() + 0.5 - w2, at.getY(), at.getZ() + 0.5 - w2, at.getX() + 0.5 + w2,
|
||||||
), (a,b) -> true).allMatch(VoxelShape::isEmpty);
|
at.getY() + dummyHeight, at.getZ() + 0.5 + w2),
|
||||||
|
(a, b) -> true)
|
||||||
|
.allMatch(VoxelShape::isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnParticles(World world, BlockPos at) {
|
public void spawnParticles(World world, BlockPos at) {
|
||||||
|
@ -91,8 +96,15 @@ public class SoulPulseEffect {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Vector3d p = Vector3d.of(at);
|
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);
|
if (canOverlap())
|
||||||
world.addParticle(new SoulBaseParticle.Data(), p.x + 0.5, p.y + 0.01, p.z + 0.5, 0, 0, 0);
|
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() {
|
private static List<List<BlockPos>> genLayers() {
|
||||||
|
@ -142,7 +154,8 @@ public class SoulPulseEffect {
|
||||||
public static Stream<BlockPos> getLayer(int idx) {
|
public static Stream<BlockPos> getLayer(int idx) {
|
||||||
if (idx < 0 || idx >= MAX_DISTANCE)
|
if (idx < 0 || idx >= MAX_DISTANCE)
|
||||||
return Stream.empty();
|
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