mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-20 03:44:23 +01:00
Added fairies
This commit is contained in:
parent
6a84f5d8b6
commit
596e01cc24
8 changed files with 468 additions and 44 deletions
|
@ -20,6 +20,7 @@ import com.minelittlepony.unicopia.client.render.IcarusWingsFeatureRenderer;
|
||||||
import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer;
|
import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer;
|
||||||
import com.minelittlepony.unicopia.client.render.entity.ButterflyEntityRenderer;
|
import com.minelittlepony.unicopia.client.render.entity.ButterflyEntityRenderer;
|
||||||
import com.minelittlepony.unicopia.client.render.entity.CastSpellEntityRenderer;
|
import com.minelittlepony.unicopia.client.render.entity.CastSpellEntityRenderer;
|
||||||
|
import com.minelittlepony.unicopia.client.render.entity.FairyEntityRenderer;
|
||||||
import com.minelittlepony.unicopia.client.render.entity.SpellbookEntityRenderer;
|
import com.minelittlepony.unicopia.client.render.entity.SpellbookEntityRenderer;
|
||||||
import com.minelittlepony.unicopia.entity.UEntities;
|
import com.minelittlepony.unicopia.entity.UEntities;
|
||||||
import com.minelittlepony.unicopia.item.ChameleonItem;
|
import com.minelittlepony.unicopia.item.ChameleonItem;
|
||||||
|
@ -70,6 +71,7 @@ public interface URenderers {
|
||||||
EntityRendererRegistry.register(UEntities.BUTTERFLY, ButterflyEntityRenderer::new);
|
EntityRendererRegistry.register(UEntities.BUTTERFLY, ButterflyEntityRenderer::new);
|
||||||
EntityRendererRegistry.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new);
|
EntityRendererRegistry.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new);
|
||||||
EntityRendererRegistry.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new);
|
EntityRendererRegistry.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new);
|
||||||
|
EntityRendererRegistry.register(UEntities.FAIRY, FairyEntityRenderer::new);
|
||||||
EntityRendererRegistry.register(UEntities.SPELLBOOK, SpellbookEntityRenderer::new);
|
EntityRendererRegistry.register(UEntities.SPELLBOOK, SpellbookEntityRenderer::new);
|
||||||
|
|
||||||
ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET);
|
ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET);
|
||||||
|
|
|
@ -154,10 +154,7 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
|
|
||||||
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float lerpedRad, float tickDelta, int light) {
|
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float lerpedRad, float tickDelta, int light) {
|
||||||
float thickness = 0.05F;
|
float thickness = 0.05F;
|
||||||
|
|
||||||
matrices.push();
|
|
||||||
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad + thickness, 1, 1, 1, 0.8F);
|
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad + thickness, 1, 1, 1, 0.8F);
|
||||||
matrices.pop();
|
|
||||||
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad - thickness, 1, 1, 1, 1);
|
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad - thickness, 1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.client.render;
|
package com.minelittlepony.unicopia.client.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.client.render.VertexFormat;
|
import net.minecraft.client.render.VertexFormat;
|
||||||
import net.minecraft.client.render.VertexFormat.DrawMode;
|
import net.minecraft.client.render.VertexFormat.DrawMode;
|
||||||
|
@ -19,7 +21,27 @@ public final class RenderLayers extends RenderLayer {
|
||||||
.target(TRANSLUCENT_TARGET)
|
.target(TRANSLUCENT_TARGET)
|
||||||
.build(false));
|
.build(false));
|
||||||
|
|
||||||
|
private static final RenderLayer FAIRY = RenderLayer.of("fairy", VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL,
|
||||||
|
VertexFormat.DrawMode.QUADS, 256, true, true, RenderLayer.MultiPhaseParameters.builder()
|
||||||
|
.shader(COLOR_SHADER)
|
||||||
|
.transparency(TRANSLUCENT_TRANSPARENCY)
|
||||||
|
.target(TRANSLUCENT_TARGET)
|
||||||
|
.texturing(solid(120, 120, 0, 0.6F))
|
||||||
|
.build(false));
|
||||||
|
|
||||||
public static RenderLayer getMagicGlow() {
|
public static RenderLayer getMagicGlow() {
|
||||||
return MAGIC_GLOW;
|
return MAGIC_GLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RenderLayer getFairy() {
|
||||||
|
return FAIRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Texturing solid(float r, float g, float b, float a) {
|
||||||
|
return new Texturing("solid", () -> {
|
||||||
|
RenderSystem.setShaderColor(r, g, b, a);
|
||||||
|
}, () -> {
|
||||||
|
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.minelittlepony.unicopia.client.render.entity;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.client.particle.SphereModel;
|
||||||
|
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
||||||
|
import com.minelittlepony.unicopia.entity.FairyEntity;
|
||||||
|
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||||
|
import net.minecraft.client.render.entity.MobEntityRenderer;
|
||||||
|
import net.minecraft.client.render.entity.model.EntityModel;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.screen.PlayerScreenHandler;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
public class FairyEntityRenderer extends MobEntityRenderer<FairyEntity, FairyEntityRenderer.Model> {
|
||||||
|
public FairyEntityRenderer(EntityRendererFactory.Context context) {
|
||||||
|
super(context, new Model(), 0.25F);
|
||||||
|
shadowOpacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getTexture(FairyEntity entity) {
|
||||||
|
return PlayerScreenHandler.BLOCK_ATLAS_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Model extends EntityModel<FairyEntity> {
|
||||||
|
private float radius;
|
||||||
|
|
||||||
|
public Model() {
|
||||||
|
super(texture -> RenderLayers.getFairy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) {
|
||||||
|
float thickness = 0.05F;
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(0, 1.5, 0);
|
||||||
|
|
||||||
|
SphereModel.SPHERE.render(matrices, vertexConsumer, light, overlay, radius - thickness, red, green, blue, 0.5F);
|
||||||
|
SphereModel.SPHERE.render(matrices, vertexConsumer, light, overlay, radius, red, green, blue, 0.3F);
|
||||||
|
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAngles(FairyEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float headYaw, float headPitch) {
|
||||||
|
radius = 0.125F + (float)Math.sin(entity.age * 0.1F) / 100F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Affinity;
|
import com.minelittlepony.unicopia.Affinity;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
||||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||||
|
@ -24,21 +23,16 @@ import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.network.Packet;
|
import net.minecraft.network.Packet;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.text.TranslatableText;
|
import net.minecraft.text.TranslatableText;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
public class CastSpellEntity extends Entity implements Caster<LivingEntity>, LightEmittingEntity {
|
||||||
|
|
||||||
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||||
|
|
||||||
private static final TrackedData<Optional<UUID>> SPELL = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
private static final TrackedData<Optional<UUID>> SPELL = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
|
||||||
|
|
||||||
private static final LevelStore LEVELS = Levelled.fixed(0);
|
private static final LevelStore LEVELS = Levelled.fixed(0);
|
||||||
|
|
||||||
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, GRAVITY);
|
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, GRAVITY);
|
||||||
|
|
||||||
private final EntityReference<LivingEntity> owner = new EntityReference<>();
|
|
||||||
|
|
||||||
private final SpellContainer spell = new SpellContainer.Delegate() {
|
private final SpellContainer spell = new SpellContainer.Delegate() {
|
||||||
@Override
|
@Override
|
||||||
public SpellContainer delegate() {
|
public SpellContainer delegate() {
|
||||||
|
@ -52,7 +46,8 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private BlockPos lastPos;
|
private final EntityReference<LivingEntity> owner = new EntityReference<>();
|
||||||
|
private final LightEmitter<?> emitter = new LightEmitter<>(this);
|
||||||
|
|
||||||
private int orphanedTicks;
|
private int orphanedTicks;
|
||||||
|
|
||||||
|
@ -65,6 +60,11 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
getDataTracker().startTracking(SPELL, Optional.empty());
|
getDataTracker().startTracking(SPELL, Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightLevel() {
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Text getName() {
|
public Text getName() {
|
||||||
Entity master = getMaster();
|
Entity master = getMaster();
|
||||||
|
@ -74,7 +74,6 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
return super.getName();
|
return super.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
@ -83,23 +82,6 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (world.isClient) {
|
|
||||||
BlockPos currentPos = getBlockPos();
|
|
||||||
|
|
||||||
if (world.isChunkLoaded(currentPos)) {
|
|
||||||
try {
|
|
||||||
world.getLightingProvider().addLightSource(currentPos, 11);
|
|
||||||
|
|
||||||
if (lastPos != null && !currentPos.equals(lastPos)) {
|
|
||||||
world.getLightingProvider().checkBlock(lastPos);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Unicopia.LOGGER.error("Error updating lighting", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPos = currentPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LivingEntity master = getMaster();
|
LivingEntity master = getMaster();
|
||||||
|
|
||||||
if (master == null || master.isRemoved()) {
|
if (master == null || master.isRemoved()) {
|
||||||
|
@ -112,6 +94,8 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
|
|
||||||
orphanedTicks = 0;
|
orphanedTicks = 0;
|
||||||
|
|
||||||
|
emitter.tick();
|
||||||
|
|
||||||
if (!dataTracker.get(SPELL).filter(spellId -> {
|
if (!dataTracker.get(SPELL).filter(spellId -> {
|
||||||
return getSpellSlot().forEach(spell -> {
|
return getSpellSlot().forEach(spell -> {
|
||||||
return spell.getUuid().equals(spellId) ? Operation.ofBoolean(spell.tick(this, Situation.GROUND_ENTITY)) : Operation.SKIP;
|
return spell.getUuid().equals(spellId) ? Operation.ofBoolean(spell.tick(this, Situation.GROUND_ENTITY)) : Operation.SKIP;
|
||||||
|
@ -121,27 +105,19 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(RemovalReason reason) {
|
|
||||||
super.remove(reason);
|
|
||||||
if (world.isClient) {
|
|
||||||
world.getLightingProvider().checkBlock(getBlockPos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMaster(LivingEntity owner) {
|
public void setMaster(LivingEntity owner) {
|
||||||
this.owner.set(owner);
|
this.owner.set(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Entity getEntity() {
|
public LivingEntity getMaster() {
|
||||||
return this;
|
return owner.get(((Entity)this).world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LivingEntity getMaster() {
|
public Entity getEntity() {
|
||||||
return owner.get(world);
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,15 +158,14 @@ public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
|
||||||
if (tag.contains("owner")) {
|
if (tag.contains("owner")) {
|
||||||
owner.fromNBT(tag.getCompound("owner"));
|
owner.fromNBT(tag.getCompound("owner"));
|
||||||
}
|
}
|
||||||
|
orphanedTicks = 60;
|
||||||
if (tag.contains("spellId")) {
|
if (tag.contains("spellId")) {
|
||||||
dataTracker.set(SPELL, Optional.ofNullable(tag.getUuid("spellId")));
|
dataTracker.set(SPELL, Optional.ofNullable(tag.getUuid("spellId")));
|
||||||
}
|
}
|
||||||
orphanedTicks = 60;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Packet<?> createSpawnPacket() {
|
public Packet<?> createSpawnPacket() {
|
||||||
return Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
|
return Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.Owned;
|
||||||
|
import com.minelittlepony.unicopia.USounds;
|
||||||
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.entity.ai.FuzzyPositions;
|
||||||
|
import net.minecraft.entity.ai.goal.Goal;
|
||||||
|
import net.minecraft.entity.ai.goal.WanderAroundGoal;
|
||||||
|
import net.minecraft.entity.ai.pathing.BirdNavigation;
|
||||||
|
import net.minecraft.entity.ai.pathing.EntityNavigation;
|
||||||
|
import net.minecraft.entity.ai.pathing.PathNodeType;
|
||||||
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
|
import net.minecraft.entity.attribute.EntityAttributes;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.entity.mob.PathAwareEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.nbt.NbtHelper;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class FairyEntity extends PathAwareEntity implements LightEmittingEntity, Owned<LivingEntity> {
|
||||||
|
private final EntityReference<LivingEntity> owner = new EntityReference<>();
|
||||||
|
|
||||||
|
private final EntityReference<LivingEntity> assignment = new EntityReference<>();
|
||||||
|
|
||||||
|
private final LightEmitter<?> emitter = new LightEmitter<>(this);
|
||||||
|
|
||||||
|
private Optional<BlockPos> stayingPos = Optional.empty();
|
||||||
|
|
||||||
|
protected FairyEntity(EntityType<FairyEntity> type, World world) {
|
||||||
|
super(type, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EntityNavigation createNavigation(World world) {
|
||||||
|
BirdNavigation birdNavigation = new BirdNavigation(this, world);
|
||||||
|
birdNavigation.setCanPathThroughDoors(true);
|
||||||
|
birdNavigation.setCanSwim(true);
|
||||||
|
birdNavigation.setCanEnterOpenDoors(true);
|
||||||
|
return birdNavigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DefaultAttributeContainer.Builder createMobAttributes() {
|
||||||
|
return MobEntity.createMobAttributes()
|
||||||
|
.add(EntityAttributes.GENERIC_MAX_HEALTH, 3)
|
||||||
|
.add(EntityAttributes.GENERIC_FOLLOW_RANGE, 100)
|
||||||
|
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initDataTracker() {
|
||||||
|
super.initDataTracker();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initGoals() {
|
||||||
|
goalSelector.add(5, new StayGoal());
|
||||||
|
goalSelector.add(6, new FollowEntityGoal(2, 2, 30));
|
||||||
|
goalSelector.add(7, new WanderAroundGoal(this, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightLevel() {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaster(LivingEntity owner) {
|
||||||
|
this.owner.set(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LivingEntity getMaster() {
|
||||||
|
return owner.get(((Entity)this).world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void fall(double heightDifference, boolean onGround, BlockState landedState, BlockPos landedPosition) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClimbing() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStaying() {
|
||||||
|
return stayingPos.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStaying(BlockPos pos) {
|
||||||
|
stayingPos = Optional.ofNullable(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
this.onGround = true;
|
||||||
|
super.tick();
|
||||||
|
emitter.tick();
|
||||||
|
|
||||||
|
if (world.random.nextInt(20) == 3) {
|
||||||
|
world.addParticle(new MagicParticleEffect(0xFFFFFF), getParticleX(1), getY(), getParticleZ(1), 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (age % 60 == 0) {
|
||||||
|
playSound(USounds.ITEM_MAGIC_AURA, 0.1F, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void travel(Vec3d movementInput) {
|
||||||
|
if (isTouchingWater()) {
|
||||||
|
updateVelocity(0.02f, movementInput);
|
||||||
|
move(MovementType.SELF, getVelocity());
|
||||||
|
setVelocity(getVelocity().multiply(0.8f));
|
||||||
|
} else if (isInLava()) {
|
||||||
|
updateVelocity(0.02f, movementInput);
|
||||||
|
move(MovementType.SELF, getVelocity());
|
||||||
|
setVelocity(getVelocity().multiply(0.5));
|
||||||
|
} else {
|
||||||
|
float f = 0.91f;
|
||||||
|
if (onGround) {
|
||||||
|
f = world.getBlockState(getBlockPos().down()).getBlock().getSlipperiness() * 0.91f;
|
||||||
|
}
|
||||||
|
float g = 0.16277137f / (f * f * f);
|
||||||
|
f = 0.91f;
|
||||||
|
if (onGround) {
|
||||||
|
f = world.getBlockState(getBlockPos().down()).getBlock().getSlipperiness() * 0.91f;
|
||||||
|
}
|
||||||
|
updateVelocity(onGround ? 0.1f * g : 0.02f, movementInput);
|
||||||
|
move(MovementType.SELF, getVelocity());
|
||||||
|
setVelocity(getVelocity().multiply(f));
|
||||||
|
}
|
||||||
|
updateLimbs(this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ActionResult interactMob(PlayerEntity player, Hand hand) {
|
||||||
|
|
||||||
|
if (hand == Hand.MAIN_HAND && isStaying() && player == getMaster()) {
|
||||||
|
stayingPos = Optional.empty();
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemoved() {
|
||||||
|
super.onRemoved();
|
||||||
|
emitter.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeCustomDataToNbt(NbtCompound tag) {
|
||||||
|
super.writeCustomDataToNbt(tag);
|
||||||
|
tag.put("owner", owner.toNBT());
|
||||||
|
stayingPos.ifPresent(pos -> {
|
||||||
|
tag.put("stayingPos", NbtHelper.fromBlockPos(pos));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readCustomDataFromNbt(NbtCompound tag) {
|
||||||
|
super.readCustomDataFromNbt(tag);
|
||||||
|
if (tag.contains("owner")) {
|
||||||
|
owner.fromNBT(tag.getCompound("owner"));
|
||||||
|
}
|
||||||
|
stayingPos = tag.contains("stayingPos") ? Optional.of(NbtHelper.toBlockPos(tag.getCompound("stayingPos"))) : Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FollowEntityGoal extends Goal {
|
||||||
|
@Nullable
|
||||||
|
private LivingEntity target;
|
||||||
|
|
||||||
|
private final double speed;
|
||||||
|
private int updateCountdownTicks;
|
||||||
|
|
||||||
|
private final float minDistance;
|
||||||
|
private final float maxDistance;
|
||||||
|
private float oldWaterPathFindingPenalty;
|
||||||
|
|
||||||
|
public FollowEntityGoal(double speed, float minDistance, float maxDistance) {
|
||||||
|
this.speed = speed;
|
||||||
|
this.minDistance = minDistance;
|
||||||
|
this.maxDistance = maxDistance;
|
||||||
|
setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canStart() {
|
||||||
|
target = assignment.get(world);
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
target = getMaster();
|
||||||
|
}
|
||||||
|
if (target == null) {
|
||||||
|
target = world.getClosestPlayer(FairyEntity.this, maxDistance);
|
||||||
|
}
|
||||||
|
return target != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldContinue() {
|
||||||
|
return target != null && !isStaying() && !getNavigation().isIdle() && squaredDistanceTo(target) > minDistance * minDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
updateCountdownTicks = 0;
|
||||||
|
oldWaterPathFindingPenalty = getPathfindingPenalty(PathNodeType.WATER);
|
||||||
|
setPathfindingPenalty(PathNodeType.WATER, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
target = null;
|
||||||
|
getNavigation().stop();
|
||||||
|
setPathfindingPenalty(PathNodeType.WATER, oldWaterPathFindingPenalty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (target == null || isLeashed() || isStaying()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLookControl().lookAt(target, 10, getMaxLookPitchChange());
|
||||||
|
|
||||||
|
if (--updateCountdownTicks > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCountdownTicks = getTickCount(10);
|
||||||
|
|
||||||
|
if (getPos().squaredDistanceTo(target.getPos()) <= minDistance * minDistance) {
|
||||||
|
|
||||||
|
BlockPos pos = FuzzyPositions.localFuzz(FairyEntity.this.world.random, 5, 5);
|
||||||
|
if (pos != null) {
|
||||||
|
getNavigation().startMovingTo(pos.getX(), pos.getY(), pos.getZ(), speed);
|
||||||
|
} else {
|
||||||
|
getNavigation().stop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getNavigation().startMovingTo(target, speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StayGoal extends Goal {
|
||||||
|
private int updateCountdownTicks;
|
||||||
|
|
||||||
|
public StayGoal() {
|
||||||
|
setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canStart() {
|
||||||
|
return isStaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldContinue() {
|
||||||
|
return isStaying() && !getNavigation().isIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
updateCountdownTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
getNavigation().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (--updateCountdownTicks > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCountdownTicks = getTickCount(10);
|
||||||
|
|
||||||
|
stayingPos.ifPresent(pos -> {
|
||||||
|
if (pos.getSquaredDistance(getBlockPos()) <= 1) {
|
||||||
|
getNavigation().stop();
|
||||||
|
} else {
|
||||||
|
getNavigation().startMovingTo(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, speed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
public interface LightEmittingEntity {
|
||||||
|
|
||||||
|
int getLightLevel();
|
||||||
|
|
||||||
|
static class LightEmitter<T extends Entity & LightEmittingEntity> {
|
||||||
|
private BlockPos lastPos;
|
||||||
|
|
||||||
|
private final T entity;
|
||||||
|
|
||||||
|
public LightEmitter(T entity) {
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void tick() {
|
||||||
|
|
||||||
|
if (entity.isRemoved()) {
|
||||||
|
remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.world.isClient) {
|
||||||
|
int light = entity.getLightLevel();
|
||||||
|
|
||||||
|
if (light <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos currentPos = entity.getBlockPos();
|
||||||
|
|
||||||
|
if (entity.world.isChunkLoaded(currentPos)) {
|
||||||
|
try {
|
||||||
|
if (lastPos != null && !currentPos.equals(lastPos)) {
|
||||||
|
entity.world.getLightingProvider().checkBlock(lastPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.world.getLightingProvider().addLightSource(currentPos, light);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPos = currentPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove() {
|
||||||
|
if (entity.world.isClient) {
|
||||||
|
try {
|
||||||
|
entity.world.getLightingProvider().checkBlock(entity.getBlockPos());
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,10 @@ public interface UEntities {
|
||||||
.dimensions(EntityDimensions.fixed(1, 1)));
|
.dimensions(EntityDimensions.fixed(1, 1)));
|
||||||
EntityType<CastSpellEntity> CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new)
|
EntityType<CastSpellEntity> CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new)
|
||||||
.trackRangeBlocks(200)
|
.trackRangeBlocks(200)
|
||||||
.dimensions(EntityDimensions.fixed(1, 1)));
|
.dimensions(EntityDimensions.fixed(1, 0.4F)));
|
||||||
|
EntityType<FairyEntity> FAIRY = register("fairy", FabricEntityTypeBuilder.create(SpawnGroup.MISC, FairyEntity::new)
|
||||||
|
.trackRangeBlocks(200)
|
||||||
|
.dimensions(EntityDimensions.fixed(0.1F, 0.1F)));
|
||||||
EntityType<SpellbookEntity> SPELLBOOK = register("spellbook", FabricEntityTypeBuilder.create(SpawnGroup.MISC, SpellbookEntity::new)
|
EntityType<SpellbookEntity> SPELLBOOK = register("spellbook", FabricEntityTypeBuilder.create(SpawnGroup.MISC, SpellbookEntity::new)
|
||||||
.trackRangeBlocks(200)
|
.trackRangeBlocks(200)
|
||||||
.dimensions(EntityDimensions.fixed(0.9F, 0.25F)));
|
.dimensions(EntityDimensions.fixed(0.9F, 0.25F)));
|
||||||
|
@ -43,6 +46,7 @@ public interface UEntities {
|
||||||
static void bootstrap() {
|
static void bootstrap() {
|
||||||
FabricDefaultAttributeRegistry.register(BUTTERFLY, ButterflyEntity.createButterflyAttributes());
|
FabricDefaultAttributeRegistry.register(BUTTERFLY, ButterflyEntity.createButterflyAttributes());
|
||||||
FabricDefaultAttributeRegistry.register(SPELLBOOK, SpellbookEntity.createMobAttributes());
|
FabricDefaultAttributeRegistry.register(SPELLBOOK, SpellbookEntity.createMobAttributes());
|
||||||
|
FabricDefaultAttributeRegistry.register(FAIRY, FairyEntity.createMobAttributes());
|
||||||
|
|
||||||
final Predicate<BiomeSelectionContext> butterflySpawnable = BiomeSelectors.foundInOverworld()
|
final Predicate<BiomeSelectionContext> butterflySpawnable = BiomeSelectors.foundInOverworld()
|
||||||
.and(ctx -> ctx.getBiome().getPrecipitation() == Biome.Precipitation.RAIN);
|
.and(ctx -> ctx.getBiome().getPrecipitation() == Biome.Precipitation.RAIN);
|
||||||
|
|
Loading…
Reference in a new issue