Spawn batponies in appropriate locations to avoid burning their eyes

This commit is contained in:
Sollace 2022-09-30 16:42:13 +02:00
parent d720a37cd9
commit ab97a7b6ef
5 changed files with 114 additions and 14 deletions

View file

@ -4,6 +4,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import net.minecraft.entity.Entity;
@ -14,7 +15,9 @@ import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffectCategory;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
public class SunBlindnessStatusEffect extends StatusEffect {
public static final int MAX_DURATION = 250;
@ -27,7 +30,7 @@ public class SunBlindnessStatusEffect extends StatusEffect {
public void applyUpdateEffect(LivingEntity entity, int amplifier) {
StatusEffectInstance state = entity.getStatusEffect(this);
if (state == null) {
if (state == null || isSunImmune(entity)) {
return;
}
@ -50,9 +53,15 @@ public class SunBlindnessStatusEffect extends StatusEffect {
return duration > 0;
}
public static boolean isSunImmune(LivingEntity entity) {
return entity.hasStatusEffect(StatusEffects.BLINDNESS)
|| entity.hasPortalCooldown()
|| Pony.of(entity).map(pony -> pony.isSunImmune()).orElse(false);
}
public static boolean hasSunExposure(LivingEntity entity) {
if (entity.hasPortalCooldown()) {
if (isSunImmune(entity)) {
return false;
}
@ -64,21 +73,21 @@ public class SunBlindnessStatusEffect extends StatusEffect {
return true;
}
if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.SHADES)) {
if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.SHADES)
|| TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.SHADES))
|| entity.isSubmergedInWater()) {
return false;
}
if (TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.SHADES))) {
return false;
return isPositionExposedToSun(entity.world, entity.getBlockPos());
}
if (entity.world.isClient) {
entity.world.calculateAmbientDarkness();
public static boolean isPositionExposedToSun(World world, BlockPos pos) {
if (world.isClient) {
world.calculateAmbientDarkness();
}
int light = entity.world.getLightLevel(LightType.SKY, entity.getBlockPos());
return !(entity.isSubmergedInWater() || light < 12 || entity.world.isRaining() || entity.world.isThundering() || !entity.world.isDay());
return world.getDimension().hasSkyLight() && world.getLightLevel(LightType.SKY, pos) >= 12 && !world.isRaining() && !world.isThundering() && world.isDay();
}
}

View file

@ -59,6 +59,7 @@ import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.Hand;
import net.minecraft.util.math.*;
import net.minecraft.world.GameMode;
public class Pony extends Living<PlayerEntity> implements Transmittable, Copieable<Pony>, UpdateCallback {
@ -107,6 +108,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
private int ticksInSun;
private boolean hasShades;
private int ticksSunImmunity = 20;
private Animation animation = Animation.NONE;
private int animationMaxDuration;
@ -221,6 +223,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
this.invisible = invisible;
}
public boolean isSunImmune() {
return ticksSunImmunity > 0;
}
@Override
public Affinity getAffinity() {
return getSpecies().getAffinity();
@ -270,6 +276,15 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
return interpolator;
}
public void onSpawn() {
if (entity.world instanceof ServerWorld sw
&& getSpecies() == Race.BAT
&& sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE
&& SunBlindnessStatusEffect.isPositionExposedToSun(sw, getOrigin())) {
SpawnLocator.selectSpawnPosition(sw, entity);
}
}
@Override
public boolean beforeUpdate() {
@ -355,6 +370,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
@Override
public void tick() {
if (ticksSunImmunity > 0) {
ticksSunImmunity--;
}
if (animationDuration >= 0 && --animationDuration <= 0) {
setAnimation(Animation.NONE);
}
@ -618,6 +637,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
mana.getXp().set(oldPlayer.getMagicalReserves().getXp().get());
advancementProgress.putAll(oldPlayer.getAdvancementProgress());
setDirty();
onSpawn();
}
@Override

View file

@ -0,0 +1,68 @@
package com.minelittlepony.unicopia.entity.player;
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.SpawnLocating;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
public class SpawnLocator extends SpawnLocating {
public static void selectSpawnPosition(ServerWorld world, PlayerEntity entity) {
BlockPos spawnPos = world.getSpawnPos();
int spawnRadius = Math.min(
MathHelper.floor(world.getWorldBorder().getDistanceInsideBorder(spawnPos.getX(), spawnPos.getZ())),
Math.max(0, world.getServer().getSpawnRadius(world))
);
long l = spawnRadius * 2 + 1;
long m = l * l;
int spawnArea = m > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)m;
int offsetMultiplier = spawnArea <= 16 ? spawnArea - 1 : 17;
int rng = Random.create().nextInt(spawnArea);
BlockPos.Mutable mutable = new BlockPos.Mutable();
for (int attempt = 0; attempt < spawnArea; attempt++) {
int tile = (rng + offsetMultiplier * attempt) % spawnArea;
int x = tile % (spawnRadius * 2 + 1);
int z = tile / (spawnRadius * 2 + 1);
BlockPos candidatePos = findOverworldSpawn(world,
spawnPos.getX() + x - spawnRadius,
spawnPos.getZ() + z - spawnRadius
);
if (candidatePos == null) {
continue;
}
mutable.set(candidatePos);
mutable.move(0, -1, 0);
while (!world.isAir(mutable) && mutable.getY() >= spawnPos.getY() - spawnRadius * 2 && !world.isOutOfHeightLimit(mutable)) {
mutable.move(0, -1, 0);
}
while (world.isAir(mutable) && mutable.getY() >= spawnPos.getY() - spawnRadius * 2 && !world.isOutOfHeightLimit(mutable)) {
mutable.move(0, -1, 0);
}
if (!world.isAir(mutable)) {
mutable.move(0, 1, 0);
}
if (!world.getFluidState(mutable).isEmpty()) {
continue;
}
entity.refreshPositionAndAngles(mutable, 0, 0);
if (!world.isSpaceEmpty(entity) || SunBlindnessStatusEffect.isPositionExposedToSun(world, mutable)) {
continue;
}
break;
}
}
}

View file

@ -9,7 +9,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.entity.duck.ServerPlayerEntityDuck;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.ScreenHandlerListener;
import net.minecraft.server.network.ServerPlayerEntity;

View file

@ -47,6 +47,10 @@ public class MsgRequestSpeciesChange implements Packet<ServerPlayerEntity> {
if (force || player.getActualSpecies().isDefault() || (player.getActualSpecies() == worldDefaultRace && !player.isSpeciesPersisted())) {
player.setSpecies(newRace.isPermitted(sender) ? newRace : worldDefaultRace);
if (force) {
player.onSpawn();
}
}
Channel.SERVER_PLAYER_CAPABILITIES.send(sender, new MsgPlayerCapabilities(true, player));