From fd03dabdd67b84a5e90be4dc981c4a9221eb2919 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 25 Mar 2024 18:08:40 +0000 Subject: [PATCH] Added specter --- .../unicopia/client/URenderers.java | 7 +- .../client/particle/FootprintParticle.java | 74 +++++++++++ .../client/particle/RunesParticle.java | 123 ------------------ .../unicopia/entity/mob/SpecterEntity.java | 118 +++++++++++++++++ .../unicopia/entity/mob/UEntities.java | 12 +- .../particle/FootprintParticleEffect.java | 42 ++++++ .../unicopia/particle/UParticles.java | 4 +- .../resources/assets/unicopia/lang/en_us.json | 1 + .../assets/unicopia/particles/footprint.json | 5 + .../unicopia/textures/particle/footprint.png | Bin 0 -> 6935 bytes 10 files changed, 256 insertions(+), 130 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/particle/FootprintParticle.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java create mode 100644 src/main/java/com/minelittlepony/unicopia/particle/FootprintParticleEffect.java create mode 100644 src/main/resources/assets/unicopia/particles/footprint.json create mode 100644 src/main/resources/assets/unicopia/textures/particle/footprint.png diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 69d0ab9c..e5896bd6 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle; import com.minelittlepony.unicopia.client.particle.DiskParticle; import com.minelittlepony.unicopia.client.particle.DustCloudParticle; import com.minelittlepony.unicopia.client.particle.FloatingBubbleParticle; +import com.minelittlepony.unicopia.client.particle.FootprintParticle; import com.minelittlepony.unicopia.client.particle.GroundPoundParticle; import com.minelittlepony.unicopia.client.particle.HealthDrainParticle; import com.minelittlepony.unicopia.client.particle.LightningBoltParticle; @@ -19,7 +20,6 @@ import com.minelittlepony.unicopia.client.particle.MagicParticle; import com.minelittlepony.unicopia.client.particle.RainboomParticle; import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle; import com.minelittlepony.unicopia.client.particle.RaindropsParticle; -import com.minelittlepony.unicopia.client.particle.RunesParticle; import com.minelittlepony.unicopia.client.particle.ShockwaveParticle; import com.minelittlepony.unicopia.client.particle.SphereParticle; import com.minelittlepony.unicopia.client.render.*; @@ -54,6 +54,7 @@ import net.minecraft.client.particle.SpriteProvider; import net.minecraft.client.render.*; import net.minecraft.client.render.VertexConsumerProvider.Immediate; import net.minecraft.client.render.block.entity.BlockEntityRendererFactories; +import net.minecraft.client.render.entity.EmptyEntityRenderer; import net.minecraft.client.render.entity.FlyingItemEntityRenderer; import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.model.json.ModelTransformationMode; @@ -68,7 +69,6 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockRenderView; -@SuppressWarnings("deprecation") public interface URenderers { BlockEntity CHEST_RENDER_ENTITY = new CloudChestBlock.TileData(BlockPos.ORIGIN, UBlocks.CLOUD_CHEST.getDefaultState()); @@ -78,10 +78,10 @@ public interface URenderers { ParticleFactoryRegistry.getInstance().register(UParticles.BUBBLE, createFactory(FloatingBubbleParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create)); + ParticleFactoryRegistry.getInstance().register(UParticles.FOOTPRINT, createFactory(FootprintParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.SHOCKWAVE, ShockwaveParticle::new); - ParticleFactoryRegistry.getInstance().register(UParticles.MAGIC_RUNES, RunesParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.SPHERE, SphereParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.DISK, DiskParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.GROUND_POUND, GroundPoundParticle::new); @@ -111,6 +111,7 @@ public interface URenderers { EntityRendererRegistry.register(UEntities.LOOT_BUG, LootBugEntityRenderer::new); EntityRendererRegistry.register(UEntities.TENTACLE, TentacleEntityRenderer::new); EntityRendererRegistry.register(UEntities.IGNOMINIOUS_BULB, IgnominiousBulbEntityRenderer::new); + EntityRendererRegistry.register(UEntities.SPECTER, EmptyEntityRenderer::new); BlockEntityRendererFactories.register(UBlockEntities.WEATHER_VANE, WeatherVaneBlockEntityRenderer::new); BlockEntityRendererFactories.register(UBlockEntities.FANCY_BED, CloudBedBlockEntityRenderer::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/FootprintParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/FootprintParticle.java new file mode 100644 index 00000000..32075c5e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/FootprintParticle.java @@ -0,0 +1,74 @@ +package com.minelittlepony.unicopia.client.particle; + +import org.joml.Vector3f; + +import com.minelittlepony.unicopia.particle.FootprintParticleEffect; + +import net.minecraft.client.particle.ParticleTextureSheet; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.particle.SpriteProvider; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class FootprintParticle extends SpriteBillboardParticle { + // specter + + public FootprintParticle(FootprintParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double dx, double dy, double dz) { + super(world, x, y, z, 0, 0, 0); + setVelocity(0, 0, 0); + setSprite(provider.getSprite(world.random)); + this.angle = effect.yaw() * MathHelper.RADIANS_PER_DEGREE; + this.maxAge = 1000; + this.gravityStrength = 1; + } + + @Override + public ParticleTextureSheet getType() { + return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; + } + + @Override + public void tick() { + super.tick(); + } + + @Override + public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) { + Vec3d cam = camera.getPos(); + + float renderX = (float)(MathHelper.lerp(tickDelta, prevPosX, x) - cam.getX()); + float renderY = (float)(MathHelper.lerp(tickDelta, prevPosY, y) - cam.getY()); + float renderZ = (float)(MathHelper.lerp(tickDelta, prevPosZ, z) - cam.getZ()); + + Vector3f[] corners = new Vector3f[]{ + new Vector3f(-1, 0, -1), + new Vector3f(-1, 0, 1), + new Vector3f( 1, 0, 1), + new Vector3f( 1, 0, -1) + }; + for (int k = 0; k < 4; ++k) { + Vector3f corner = corners[k]; + corner.mul(0.2F); + corner.rotateAxis(angle, 0, 1, 0); + corner.add(renderX, renderY + 0.0001F, renderZ); + } + + float alpha = this.alpha * (1 - ((float)age / maxAge)); + int light = getBrightness(tickDelta); + + float minU = this.sprite.getMinU(); + float maxU = this.sprite.getMaxU(); + + float minV = this.sprite.getMinV(); + float maxV = this.sprite.getMaxV(); + + drawer.vertex(corners[0].x, corners[0].y, corners[0].z).texture(minU, minV).color(red, green, blue, alpha).light(light).next(); + drawer.vertex(corners[1].x, corners[1].y, corners[1].z).texture(maxU, minV).color(red, green, blue, alpha).light(light).next(); + drawer.vertex(corners[2].x, corners[2].y, corners[2].z).texture(maxU, maxV).color(red, green, blue, alpha).light(light).next(); + drawer.vertex(corners[3].x, corners[3].y, corners[3].z).texture(minU, maxV).color(red, green, blue, alpha).light(light).next(); + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java deleted file mode 100644 index 21294ca3..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.minelittlepony.unicopia.client.particle; - -import org.joml.Quaternionf; -import org.joml.Vector3f; - -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; -import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.*; - -@Deprecated -public class RunesParticle extends OrientedBillboardParticle { - - private static final Identifier[] TEXTURES = new Identifier[] { - Unicopia.id("textures/particles/runes_0.png"), - Unicopia.id("textures/particles/runes_1.png"), - Unicopia.id("textures/particles/runes_2.png"), - Unicopia.id("textures/particles/runes_3.png"), - Unicopia.id("textures/particles/runes_4.png"), - Unicopia.id("textures/particles/runes_5.png") - }; - - protected float targetSize = 3; - - protected float prevBaseSize = 0; - protected float baseSize = 0; - - private float prevRotationAngle; - private float rotationAngle; - - public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { - super(effect, world, x, y, z, velocityX, velocityY, velocityZ); - setMaxAge(70); - - red = world.random.nextFloat(); - green = world.random.nextFloat(); - blue = world.random.nextFloat(); - } - - @Override - public float getScale(float tickDelta) { - return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta); - } - - @Override - protected Identifier getTexture() { - return TEXTURES[0]; - } - - private float getAlphaScale() { - float transitionScale = age < maxAge / 2 ? 5 : 3; - return (float)Math.min(1, Math.sin(Math.PI * age / maxAge) * transitionScale); - } - - @Override - protected int getBrightness(float tint) { - return 0xF000F0; - } - - @Override - protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) { - - float alpha = this.alpha * getAlphaScale(); - - float angle = MathHelper.lerp(tickDelta, prevRotationAngle, rotationAngle); - - for (int i = 0; i < TEXTURES.length; i++) { - for (int dim = 0; dim < 3; dim++) { - RenderSystem.setShaderTexture(0, TEXTURES[i]); - RenderSystem.setShaderColor(red, green, blue, alpha / ((float)(dim * 3) + 1)); - - Vector3f[] corners = new Vector3f[]{ - new Vector3f(-1, -1, 0), - new Vector3f(-1, 1, 0), - new Vector3f( 1, 1, 0), - new Vector3f( 1, -1, 0) - }; - float scale = getScale(tickDelta); - - float ringSpeed = (i % 2 == 0 ? i : -1) * i; - - Quaternionf ringAngle = RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed); - Quaternionf ringFlip = RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim); - Quaternionf ringRoll = RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim); - - for(int k = 0; k < 4; ++k) { - Vector3f corner = corners[k]; - corner.rotate(ringAngle); - corner.rotate(ringFlip); - corner.rotate(ringRoll); - corner.rotate(rotation); - corner.mul(scale); - corner.add(x, y + 0.001F, z); - } - - renderQuad(te, buffer, corners, alpha, tickDelta); - } - } - - RenderSystem.setShaderColor(1, 1, 1, 1); - } - - @Override - public void tick() { - super.tick(); - - prevBaseSize = baseSize; - if (baseSize < targetSize) { - baseSize += 0.1F; - } - if (baseSize > targetSize) { - baseSize -= 0.1F; - } - - rotationAngle = (rotationAngle + 0.3F) % 360; - prevRotationAngle = rotationAngle - 0.3F; - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java new file mode 100644 index 00000000..91f9b407 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/SpecterEntity.java @@ -0,0 +1,118 @@ +package com.minelittlepony.unicopia.entity.mob; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.particle.FootprintParticleEffect; +import com.minelittlepony.unicopia.particle.ParticleUtils; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.ActiveTargetGoal; +import net.minecraft.entity.ai.goal.LookAroundGoal; +import net.minecraft.entity.ai.goal.LookAtEntityGoal; +import net.minecraft.entity.ai.goal.MeleeAttackGoal; +import net.minecraft.entity.ai.goal.RevengeGoal; +import net.minecraft.entity.ai.goal.SwimGoal; +import net.minecraft.entity.ai.goal.WanderAroundFarGoal; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameRules; +import net.minecraft.world.World; + +public class SpecterEntity extends HostileEntity { + public static DefaultAttributeContainer.Builder createAttributes() { + return HostileEntity.createHostileAttributes() + .add(EntityAttributes.GENERIC_MAX_HEALTH, 16F) + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.5F); + } + + private double stepDistance; + private double nextStepDistance; + private boolean wasLeft; + + public SpecterEntity(EntityType entityType, World world) { + super(entityType, world); + } + + @Override + protected void initGoals() { + this.goalSelector.add(1, new SwimGoal(this)); + this.goalSelector.add(4, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.add(5, new WanderAroundFarGoal(this, 0.8)); + this.goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 8.0f)); + this.goalSelector.add(6, new LookAroundGoal(this)); + this.targetSelector.add(1, new RevengeGoal(this)); + this.targetSelector.add(2, new TargetGoal<>(this, PlayerEntity.class)); + } + + @SuppressWarnings("deprecation") + @Override + public void tick() { + Vec3d prevPosition = getPos(); + super.tick(); + if (getBrightnessAtEyes() < 0.5F || getTarget() != null) { + ParticleUtils.spawnParticles(ParticleTypes.AMBIENT_ENTITY_EFFECT, this, 6); + + if (getWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) { + if (getWorld().getBlockState(getBlockPos()).isIn(BlockTags.REPLACEABLE_BY_TREES)) { + getWorld().breakBlock(getBlockPos(), true); + } + } + } + + if (!hasVehicle() && isOnGround()) { + stepDistance += getPos().subtract(prevPosition).horizontalLength() * 0.6F; + if (stepDistance >= nextStepDistance) { + nextStepDistance = stepDistance + 1; + wasLeft = !wasLeft; + float offset = 0.4F; + float yaw = getHeadYaw(); + Vec3d offsetVec = new Vec3d((wasLeft ? offset : -offset), 0, 0).rotateY(yaw); + getWorld().addParticle(new FootprintParticleEffect(yaw), true, getX() + offsetVec.getX(), getY(), getZ() + offsetVec.getZ(), 0, 0, 0); + ParticleUtils.spawnParticles(new BlockStateParticleEffect(ParticleTypes.BLOCK, getSteppingBlockState()), getWorld(), getPos(), 6); + playSound(getSteppingBlockState().getSoundGroup().getStepSound(), 0.5F, 1); + } + } + } + + @Override + public float getSoundPitch() { + return super.getSoundPitch() * 0.3F; + } + + @Override + @Nullable + protected SoundEvent getHurtSound(DamageSource source) { + return null; + } + + @Override + protected void playSwimSound(float volume) { + + } + + @Override + protected void onSwimmingStart() { + + } + + static class TargetGoal extends ActiveTargetGoal { + public TargetGoal(SpecterEntity specter, Class targetEntityClass) { + super(specter, targetEntityClass, true); + } + + @SuppressWarnings("deprecation") + @Override + public boolean canStart() { + return mob.getBrightnessAtEyes() < 0.5F && super.canStart(); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java index 924ca810..407710ef 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java @@ -7,7 +7,6 @@ import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour; import com.minelittlepony.unicopia.projectile.MagicBeamEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.PhysicsBodyProjectileEntity; - import net.fabricmc.fabric.api.biome.v1.BiomeModifications; import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext; import net.fabricmc.fabric.api.biome.v1.BiomeSelectors; @@ -17,10 +16,13 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityType; import net.minecraft.entity.SpawnGroup; +import net.minecraft.entity.SpawnRestriction.Location; import net.minecraft.entity.decoration.painting.PaintingVariant; import net.minecraft.entity.mob.FlyingEntity; +import net.minecraft.entity.mob.HostileEntity; import net.minecraft.registry.*; import net.minecraft.registry.tag.BiomeTags; +import net.minecraft.world.Heightmap.Type; public interface UEntities { EntityType BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.create(SpawnGroup.AMBIENT, ButterflyEntity::new) @@ -74,6 +76,11 @@ public interface UEntities { EntityType IGNOMINIOUS_BULB = register("ignominious_bulb", FabricEntityTypeBuilder.create(SpawnGroup.MISC, IgnominiousBulbEntity::new) .trackRangeChunks(8) .dimensions(EntityDimensions.fixed(3, 2))); + EntityType SPECTER = register("specter", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.MONSTER).entityFactory(SpecterEntity::new) + .spawnRestriction(Location.ON_GROUND, Type.WORLD_SURFACE, HostileEntity::canSpawnInDark) + .fireImmune() + .spawnableFarFromPlayer() + .dimensions(EntityDimensions.fixed(1, 2))); static EntityType register(String name, FabricEntityTypeBuilder builder) { EntityType type = builder.build(); @@ -89,6 +96,7 @@ public interface UEntities { FabricDefaultAttributeRegistry.register(FRIENDLY_CREEPER, FriendlyCreeperEntity.createCreeperAttributes()); FabricDefaultAttributeRegistry.register(LOOT_BUG, LootBugEntity.createSilverfishAttributes()); FabricDefaultAttributeRegistry.register(IGNOMINIOUS_BULB, IgnominiousBulbEntity.createMobAttributes()); + FabricDefaultAttributeRegistry.register(SPECTER, SpecterEntity.createAttributes()); if (!Unicopia.getConfig().disableButterflySpawning.get()) { final Predicate butterflySpawnable = BiomeSelectors.foundInOverworld() @@ -105,6 +113,8 @@ public interface UEntities { ), SpawnGroup.AMBIENT, BUTTERFLY, 7, 5, 19); } + BiomeModifications.addSpawn(BiomeSelectors.spawnsOneOf(EntityType.ZOMBIE), SpawnGroup.MONSTER, SPECTER, 2, 1, 2); + UTradeOffers.bootstrap(); EntityBehaviour.bootstrap(); UEntityAttributes.bootstrap(); diff --git a/src/main/java/com/minelittlepony/unicopia/particle/FootprintParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/FootprintParticleEffect.java new file mode 100644 index 00000000..69ef2300 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/particle/FootprintParticleEffect.java @@ -0,0 +1,42 @@ +package com.minelittlepony.unicopia.particle; + +import java.util.Locale; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleType; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.registry.Registries; + +public record FootprintParticleEffect ( + float yaw + ) implements ParticleEffect { + @SuppressWarnings("deprecation") + public static final ParticleEffect.Factory FACTORY = ParticleFactoryHelper.of(FootprintParticleEffect::new, FootprintParticleEffect::new); + + protected FootprintParticleEffect(ParticleType type, StringReader reader) throws CommandSyntaxException { + this(ParticleFactoryHelper.readFloat(reader)); + } + + protected FootprintParticleEffect(ParticleType particleType, PacketByteBuf buf) { + this(buf.readFloat()); + } + + @Override + public ParticleType getType() { + return UParticles.FOOTPRINT; + } + + @Override + public void write(PacketByteBuf buf) { + buf.writeFloat(yaw); + } + + @Override + public String asString() { + return String.format(Locale.ROOT, "%s %.2f", Registries.PARTICLE_TYPE.getId(getType()), yaw); + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java index 9bec2e5c..da302010 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java @@ -14,14 +14,12 @@ public interface UParticles { ParticleType UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.FACTORY)); DefaultParticleType CHANGELING_MAGIC = register("changeling_magic", FabricParticleTypes.simple()); DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple()); + ParticleType FOOTPRINT = register("footprint", FabricParticleTypes.complex(FootprintParticleEffect.FACTORY)); ParticleType DUST_CLOUD = register("dust_cloud", FabricParticleTypes.complex(BlockStateParticleEffect.PARAMETERS_FACTORY)); ParticleType RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); ParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.complex(TargetBoundParticleEffect.FACTORY)); - @Deprecated - ParticleType MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); - DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple()); ParticleType SPHERE = register("sphere", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY)); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index d9c8f395..01a3726f 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -355,6 +355,7 @@ "entity.unicopia.butterfly": "Butterfly", "entity.unicopia.twittermite": "Twittermite", + "entity.unicopia.specter": "Specter", "entity.unicopia.cast_spell": "Cast Spell", "entity.unicopia.cast_spell.by": "a spell cast by %s", "entity.unicopia.spellbook": "Spellbook", diff --git a/src/main/resources/assets/unicopia/particles/footprint.json b/src/main/resources/assets/unicopia/particles/footprint.json new file mode 100644 index 00000000..50c757f1 --- /dev/null +++ b/src/main/resources/assets/unicopia/particles/footprint.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "unicopia:footprint" + ] +} diff --git a/src/main/resources/assets/unicopia/textures/particle/footprint.png b/src/main/resources/assets/unicopia/textures/particle/footprint.png new file mode 100644 index 0000000000000000000000000000000000000000..a0ea4822b22157f122b708ac5ca0d3ab18ba4a0b GIT binary patch literal 6935 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 literal 0 HcmV?d00001