diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 318cb30f..1ea9520b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -45,10 +45,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl private final EntityReference owner = new EntityReference<>(); - @Nullable - private GoalSelector goals; - @Nullable - private GoalSelector targets; + private Optional goals = Optional.empty(); + private Optional targets = Optional.empty(); private int eatTimer; @Nullable @@ -59,14 +57,17 @@ public class Creature extends Living implements WeaklyOwned.Mutabl physics = new EntityPhysics<>(entity, GRAVITY); entity.getDataTracker().startTracking(MASTER, owner.toNBT()); entity.getDataTracker().startTracking(EATING, 0); + + addTicker(physics); + addTicker(this::updateConsumption); } @Override public void setMaster(LivingEntity owner) { this.owner.set(owner); entity.getDataTracker().set(MASTER, this.owner.toNBT()); - if (targets != null && owner != null) { - initMinionAi(); + if (owner != null) { + targets.ifPresent(this::initMinionAi); } } @@ -88,16 +89,16 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } public Optional getTargets() { - return Optional.ofNullable(targets); + return targets; } public Optional getGoals() { - return Optional.ofNullable(goals); + return goals; } public void initAi(GoalSelector goals, GoalSelector targets) { - this.goals = goals; - this.targets = targets; + this.goals = Optional.of(goals); + this.targets = Optional.of(targets); DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity); targets.add(1, targetter); @@ -111,7 +112,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (owner.isPresent(asWorld())) { - initMinionAi(); + initMinionAi(targets); } if (entity instanceof CreeperEntity mob) { @@ -122,7 +123,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } } - private void initMinionAi() { + private void initMinionAi(GoalSelector targets) { Predicate filter = TargetSelecter.notOwnerOrFriend(this, this).and(e -> { return Equine.of(e) .filter(eq -> eq instanceof Creature) @@ -147,11 +148,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl return false; } - @Override - public void tick() { - super.tick(); - physics.tick(); - + private void updateConsumption() { if (isClient()) { eatTimer = entity.getDataTracker().get(EATING); } else if (eatMuffinGoal != null) { @@ -240,8 +237,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); - if (owner.isPresent(asWorld()) && targets != null) { - initMinionAi(); + if (owner.isPresent(asWorld())) { + targets.ifPresent(this::initMinionAi); } } physics.fromNBT(compound); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java index 83a3a3dc..c5feebea 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java @@ -5,8 +5,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.util.Copyable; -import com.minelittlepony.unicopia.util.NbtSerialisable; +import com.minelittlepony.unicopia.util.*; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemConvertible; @@ -15,7 +14,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.Identifier; import net.minecraft.registry.Registries; -public class ItemTracker implements NbtSerialisable, Copyable { +public class ItemTracker implements NbtSerialisable, Copyable, Tickable { public static final long TICKS = 1; public static final long SECONDS = 20 * TICKS; public static final long HOURS = 1000 * TICKS; @@ -54,6 +53,17 @@ public class ItemTracker implements NbtSerialisable, Copyable { return ticks -> ticks <= maxTime; } + private final Living living; + + public ItemTracker(Living living) { + this.living = living; + } + + @Override + public void tick() { + update(living, living.getArmourStacks()); + } + public void update(Living living, Stream stacks) { final Set found = new HashSet<>(); final Set foundStacks = new HashSet<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index be9127cc..29a5ac3b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -1,14 +1,15 @@ package com.minelittlepony.unicopia.entity; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.jetbrains.annotations.Nullable; +import com.google.common.base.Preconditions; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellContainer; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; @@ -17,6 +18,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.block.data.DragonBreathStore; import com.minelittlepony.unicopia.entity.effect.UEffects; +import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.GlassesItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.network.datasync.EffectSync; @@ -24,8 +26,7 @@ import com.minelittlepony.unicopia.network.datasync.Transmittable; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; -import com.minelittlepony.unicopia.util.MagicalDamageSource; -import com.minelittlepony.unicopia.util.VecHelper; +import com.minelittlepony.unicopia.util.*; import net.minecraft.entity.*; import net.minecraft.entity.damage.DamageSource; @@ -62,9 +63,10 @@ public abstract class Living implements Equine, Caste private int invinsibilityTicks; - private final Enchantments enchants = new Enchantments(this); + private final List tickers = new ArrayList<>(); - private final ItemTracker armour = new ItemTracker(); + private final Enchantments enchants = addTicker(new Enchantments(this)); + private final ItemTracker armour = addTicker(new ItemTracker(this)); protected Living(T entity, TrackedData effect) { this.entity = entity; @@ -74,6 +76,11 @@ public abstract class Living implements Equine, Caste entity.getDataTracker().startTracking(CARRIER_ID, Optional.empty()); } + public Q addTicker(Q tickable) { + tickers.add(Preconditions.checkNotNull(tickable, "tickable")); + return tickable; + } + public boolean isInvisible() { return invisible && SpellPredicate.IS_DISGUISE.isOn(this); } @@ -135,7 +142,7 @@ public abstract class Living implements Equine, Caste @Override public void tick() { - armour.update(this, getArmourStacks()); + tickers.forEach(Tickable::tick); try { getSpellSlot().forEach(spell -> Operation.ofBoolean(spell.tick(this, Situation.BODY)), entity.world.isClient); @@ -157,11 +164,15 @@ public abstract class Living implements Equine, Caste updateVelocity(); } - enchants.tick(); + + + updateDragonBreath(); prevSneaking = entity.isSneaking(); prevLanded = entity.isOnGround(); + } + private void updateDragonBreath() { if (!entity.world.isClient && (entity instanceof PlayerEntity || entity.hasCustomName())) { Vec3d targetPos = entity.getRotationVector().multiply(2).add(entity.getEyePos()); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java index a85f3a13..84a5f9c3 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/SunBlindnessStatusEffect.java @@ -80,7 +80,6 @@ public class SunBlindnessStatusEffect extends StatusEffect { } return isPositionExposedToSun(entity.world, entity.getBlockPos()); - } public static boolean isPositionExposedToSun(World world, BlockPos pos) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/MeteorlogicalUtil.java b/src/main/java/com/minelittlepony/unicopia/entity/player/MeteorlogicalUtil.java new file mode 100644 index 00000000..f74e587d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/MeteorlogicalUtil.java @@ -0,0 +1,41 @@ +package com.minelittlepony.unicopia.entity.player; + +import net.minecraft.entity.Entity; +import net.minecraft.util.hit.HitResult.Type; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public interface MeteorlogicalUtil { + + static boolean isLookingIntoSun(World world, Entity entity) { + + // check first whether the world has a sun + if (!world.getDimension().hasSkyLight()) { + return false; + } + + // check if sun is obscured by clouds + if (world.hasRain(entity.getBlockPos()) || world.isThundering()) { + return false; + } + + // we translate sun angle to a scale of 0-1 (0=sunrise, 1=sunset, >1 nighttime) + final float skyAngle = ((entity.world.getSkyAngle(1) + 0.25F) % 1F) * 2; + float playerYaw = MathHelper.wrapDegrees(entity.getHeadYaw()); + float playerAngle = (-entity.getPitch(1) / 90F) / 2F; + + // player is facing the other way so flip the yaw to match sun angle + if (playerYaw > 0) { + playerAngle = 1 - playerAngle; + } + + playerYaw = Math.abs(playerYaw); + + // check if day, + // and player is looking towards the sun, and that there isn't a block obstructing their view + return skyAngle < 1 + && (playerYaw > 89 && playerYaw < 92 || (playerAngle > 0.45F && playerAngle < 0.55F)) + && playerAngle > (skyAngle - 0.04F) && playerAngle < (skyAngle + 0.04F) + && entity.raycast(100, 1, true).getType() == Type.MISS; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 25118d9b..1800cd12 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -11,8 +11,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.*; -import com.minelittlepony.unicopia.ability.AbilityDispatcher; -import com.minelittlepony.unicopia.ability.EarthPonyStompAbility; +import com.minelittlepony.unicopia.ability.*; import com.minelittlepony.unicopia.ability.magic.*; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; @@ -32,7 +31,6 @@ import com.minelittlepony.unicopia.network.MsgPlayerAnimationChange; import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback; import com.minelittlepony.common.util.animation.LinearInterpolator; -import com.google.common.collect.Lists; import com.google.common.collect.Streams; import com.minelittlepony.common.util.animation.Interpolator; import com.mojang.authlib.GameProfile; @@ -54,12 +52,10 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.Hand; -import net.minecraft.util.hit.HitResult.Type; import net.minecraft.util.math.*; import net.minecraft.world.GameMode; public class Pony extends Living implements Copyable, UpdateCallback { - private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); static final TrackedData ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); @@ -76,9 +72,8 @@ public class Pony extends Living implements Copyable, Update private static final TrackedData EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); private final AbilityDispatcher powers = new AbilityDispatcher(this); - private final PlayerPhysics gravity = new PlayerPhysics(this); + private final PlayerPhysics gravity = addTicker(new PlayerPhysics(this)); private final PlayerCharmTracker charms = new PlayerCharmTracker(this); - private final PlayerAttributes attributes = new PlayerAttributes(this); private final PlayerCamera camera = new PlayerCamera(this); private final TraitDiscovery discoveries = new TraitDiscovery(this); @@ -88,8 +83,6 @@ public class Pony extends Living implements Copyable, Update private final PlayerLevelStore levels; private final PlayerLevelStore corruption; - private final List tickers; - private final Interpolator interpolator = new LinearInterpolator(); private boolean dirty; @@ -99,9 +92,6 @@ public class Pony extends Living implements Copyable, Update private float magicExhaustion = 0; - @Nullable - private Race clientPreferredRace; - private int ticksInSun; private boolean hasShades; private int ticksSunImmunity = INITIAL_SUN_IMMUNITY; @@ -112,13 +102,17 @@ public class Pony extends Living implements Copyable, Update public Pony(PlayerEntity player) { super(player, EFFECT); - this.mana = new ManaContainer(this); + this.mana = addTicker(new ManaContainer(this)); this.levels = new PlayerLevelStore(this, LEVEL, true, SoundEvents.ENTITY_PLAYER_LEVELUP); this.corruption = new PlayerLevelStore(this, CORRUPTION, false, SoundEvents.PARTICLE_SOUL_ESCAPE); - this.tickers = Lists.newArrayList(gravity, mana, attributes); player.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); player.getDataTracker().startTracking(HANGING_POSITION, Optional.empty()); + + addTicker(this::updateAnimations); + addTicker(this::updateBatPonyAbilities); + addTicker(this::updateCorruptionDecay); + addTicker(new PlayerAttributes(this)); } public static void registerAttributes(DefaultAttributeContainer.Builder builder) { @@ -299,21 +293,24 @@ public class Pony extends Living implements Copyable, Update if (isClient()) { if (entity.hasVehicle() && entity.isSneaking()) { - Entity ridee = entity.getVehicle(); + Entity vehicle = entity.getVehicle(); - if (ridee instanceof Trap) { - if (((Trap)ridee).attemptDismount(entity)) { + if (vehicle instanceof Trap) { + if (((Trap)vehicle).attemptDismount(entity)) { entity.stopRiding(); + entity.refreshPositionAfterTeleport(vehicle.getPos()); + Living.transmitPassengers(vehicle); } else { entity.setSneaking(false); } } else { entity.stopRiding(); - Living.transmitPassengers(ridee); + entity.refreshPositionAfterTeleport(vehicle.getPos()); + Living.transmitPassengers(vehicle); } } } - + magicExhaustion = ManaConsumptionUtil.burnFood(entity, magicExhaustion); powers.tick(); @@ -355,15 +352,16 @@ public class Pony extends Living implements Copyable, Update return state.isSolidSurface(asWorld(), pos, entity, Direction.DOWN); } - @Override - public void tick() { - if (ticksSunImmunity > 0) { - ticksSunImmunity--; - } - + private void updateAnimations() { if (animationDuration >= 0 && --animationDuration <= 0) { setAnimation(Animation.NONE); } + } + + private void updateBatPonyAbilities() { + if (ticksSunImmunity > 0) { + ticksSunImmunity--; + } if (isHanging()) { ((LivingEntityDuck)entity).setLeaningPitch(0); @@ -381,30 +379,12 @@ public class Pony extends Living implements Copyable, Update } this.hasShades = hasShades; - if (!hasShades && ticksSunImmunity <= 0) { - float skyAngle = ((entity.world.getSkyAngle(1) + 0.25F) % 1F) * 2; - float playerAngle = (-entity.getPitch(1) / 90F) / 2F; - float playerYaw = MathHelper.wrapDegrees(entity.getHeadYaw()); - - if (playerYaw > 0) { - playerAngle = 1 - playerAngle; - } - - playerYaw = Math.abs(playerYaw); - - if (skyAngle < 1 - && (playerYaw > 89 && playerYaw < 92 || (playerAngle > 0.45F && playerAngle < 0.55F)) - && playerAngle > (skyAngle - 0.04F) && playerAngle < (skyAngle + 0.04F)) { - - if (entity.raycast(100, 1, true).getType() == Type.MISS) { - if (!isClient()) { - entity.addStatusEffect(new StatusEffectInstance(UEffects.SUN_BLINDNESS, SunBlindnessStatusEffect.MAX_DURATION, 2, true, false)); - UCriteria.LOOK_INTO_SUN.trigger(entity); - } else if (isClientPlayer()) { - InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_EARS_RINGING, entity.getId()); - } - - } + if (!hasShades && ticksSunImmunity <= 0 && MeteorlogicalUtil.isLookingIntoSun(asWorld(), entity)) { + if (!isClient()) { + entity.addStatusEffect(new StatusEffectInstance(UEffects.SUN_BLINDNESS, SunBlindnessStatusEffect.MAX_DURATION, 2, true, false)); + UCriteria.LOOK_INTO_SUN.trigger(entity); + } else if (isClientPlayer()) { + InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_EARS_RINGING, entity.getId()); } } @@ -424,7 +404,9 @@ public class Pony extends Living implements Copyable, Update ticksInSun--; } } + } + private void updateCorruptionDecay() { if (!isClient() && !UItems.ALICORN_AMULET.isApplicable(entity)) { if (entity.age % (10 * ItemTracker.SECONDS) == 0) { if (entity.world.random.nextInt(100) == 0) { @@ -443,11 +425,11 @@ public class Pony extends Living implements Copyable, Update setDirty(); } } + } - tickers.forEach(Tickable::tick); - + @Override + public void tick() { super.tick(); - sendCapabilities(); }