Add some flight balancing changes

This commit is contained in:
Sollace 2023-08-07 15:29:01 +01:00
parent 381d3bf3fa
commit f6857e2452
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 86 additions and 52 deletions

View file

@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.MeteorlogicalUtil;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
@ -16,9 +17,6 @@ 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;
@ -80,14 +78,6 @@ public class SunBlindnessStatusEffect extends StatusEffect {
return false;
}
return isPositionExposedToSun(entity.getWorld(), entity.getBlockPos());
}
public static boolean isPositionExposedToSun(World world, BlockPos pos) {
if (world.isClient) {
world.calculateAmbientDarkness();
}
return world.getDimension().hasSkyLight() && world.getLightLevel(LightType.SKY, pos) >= 12 && !world.isRaining() && !world.isThundering() && world.isDay();
return MeteorlogicalUtil.isPositionExposedToSun(entity.getWorld(), entity.getBlockPos());
}
}

View file

@ -2,7 +2,9 @@ package com.minelittlepony.unicopia.entity.player;
import net.minecraft.entity.Entity;
import net.minecraft.util.hit.HitResult.Type;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
public interface MeteorlogicalUtil {
@ -19,8 +21,8 @@ public interface MeteorlogicalUtil {
return false;
}
// we translate sun angle to a scale of 0-1 (0=sunrise, 1=sunset, >1 nighttime)
final float skyAngle = ((entity.getWorld().getSkyAngle(1) + 0.25F) % 1F) * 2;
final float skyAngle = getSkyAngle(entity.getWorld());
float playerYaw = MathHelper.wrapDegrees(entity.getHeadYaw());
float playerAngle = (-entity.getPitch(1) / 90F) / 2F;
@ -38,4 +40,40 @@ public interface MeteorlogicalUtil {
&& playerAngle > (skyAngle - 0.04F) && playerAngle < (skyAngle + 0.04F)
&& entity.raycast(100, 1, true).getType() == Type.MISS;
}
static float getSunIntensity(World world) {
float skyAngle = getSkyAngle(world);
if (skyAngle > 1) {
return 0;
}
// intensity (0-1) has a peak at 0.5 (midday)
float intensity = MathHelper.cos((skyAngle - 0.5F) * MathHelper.PI);
if (world.isRaining()) {
intensity *= 0.5;
}
if (world.isThundering()) {
intensity *= 0.5;
}
return intensity;
}
// we translate sun angle to a scale of 0-1 (0=sunrise, 1=sunset, >1 nighttime)
static float getSkyAngle(World world) {
return ((world.getSkyAngle(1) + 0.25F) % 1F) * 2;
}
static boolean isPositionExposedToSun(World world, BlockPos pos) {
if (world.isClient) {
world.calculateAmbientDarkness();
}
return world.getDimension().hasSkyLight()
&& world.getLightLevel(LightType.SKY, pos) >= 12
&& !world.isRaining()
&& !world.isThundering()
&& world.isDay();
}
}

View file

@ -553,7 +553,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
if (entity.getWorld().hasRain(entity.getBlockPos())) {
applyTurbulance(velocity);
} else {
descentRate -= WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F;
double updraft = WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F;
updraft *= 1 + motion;
velocity.y += updraft;
descentRate -= updraft;
}
descentRate += 0.001F;

View file

@ -327,7 +327,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
if (entity.getWorld() instanceof ServerWorld sw
&& getObservedSpecies() == Race.BAT
&& sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE
&& SunBlindnessStatusEffect.isPositionExposedToSun(sw, getOrigin())) {
&& MeteorlogicalUtil.isPositionExposedToSun(sw, getOrigin())) {
SpawnLocator.selectSpawnPosition(sw, entity);
}
ticksSunImmunity = INITIAL_SUN_IMMUNITY;

View file

@ -2,8 +2,6 @@ package com.minelittlepony.unicopia.entity.player;
import java.util.Optional;
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
import net.minecraft.entity.ai.FuzzyPositions;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.SpawnLocating;
@ -84,7 +82,7 @@ public class SpawnLocator extends SpawnLocating {
entity.refreshPositionAndAngles(mutable, 0, 0);
if (!world.isSpaceEmpty(entity) || SunBlindnessStatusEffect.isPositionExposedToSun(world, mutable)) {
if (!world.isSpaceEmpty(entity) || MeteorlogicalUtil.isPositionExposedToSun(world, mutable)) {
continue;
}

View file

@ -1,12 +1,14 @@
package com.minelittlepony.unicopia.server.world;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.MeteorlogicalUtil;
import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.FluidTags;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
@ -15,23 +17,23 @@ import net.minecraft.world.PersistentState;
import net.minecraft.world.World;
public class WeatherConditions extends PersistentState implements Tickable {
public static final TwoDimensionalField HEIGHT_MAP_FIELD = (world, pos) -> {
return world.getTopY(Type.WORLD_SURFACE_WG, pos.getX(), pos.getZ());
};
public static final TwoDimensionalField THERMAL_FIELD = (world, pos) -> {
return world.getBiome(pos).value().getTemperature() + (float)getUpdraft(pos, world);
};
public static final TwoDimensionalField LOCAL_ALTITUDE_FIELD = (world, pos) -> {
public static final Plane HEIGHT_MAP_FIELD = (world, pos) -> world.getTopY(Type.WORLD_SURFACE_WG, pos.getX(), pos.getZ());
public static final Plane THERMAL_FIELD = (world, pos) -> (float)getUpdraft(pos, world);
public static final Plane LOCAL_ALTITUDE_FIELD = (world, pos) -> {
if (!world.isAir(pos)) {
return 0;
}
return pos.getY() - getSurfaceBelow(pos, world);
int y = pos.getY();
do {
pos.move(Direction.DOWN);
} while (world.isAir(pos) && world.isInBuildLimit(pos));
return y - pos.getY();
};
public static final double FIRE_UPDRAFT = 0.3;
public static final double SAND_UPDRAFT = 0.13;
public static final double SOUL_SAND_UPDRAFT = -0.13;
public static final double ICE_UPDRAFT = -0.10;
public static final double FIRE_UPDRAFT = 0.13;
public static final double SAND_UPDRAFT = 0.03;
public static final double SOUL_SAND_UPDRAFT = -0.03;
public static final double ICE_UPDRAFT = 0;
public static final double VOID_UPDRAFT = -0.23;
public static final float MAX_UPDRAFT_HEIGHT = 20;
@ -108,47 +110,57 @@ public class WeatherConditions extends PersistentState implements Tickable {
public static Vec3d getAirflow(BlockPos pos, World world) {
BlockPos.Mutable probedPosition = new BlockPos.Mutable();
final float localAltitude = LOCAL_ALTITUDE_FIELD.getValue(world, probedPosition.set(pos));
final float terrainFactor = Math.min(MAX_TERRAIN_HEIGHT, localAltitude) / MAX_TERRAIN_HEIGHT;
final float windFactor = Math.min(MAX_WIND_HEIGHT, localAltitude) / MAX_WIND_HEIGHT;
final float terrainFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_TERRAIN_HEIGHT);
final float windFactor = getScaledDistanceFromTerrain(probedPosition.set(pos), world, MAX_WIND_HEIGHT);
Vec3d terrainGradient = LOCAL_ALTITUDE_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor);
Vec3d thermalGradient = THERMAL_FIELD.computeAverage(world, pos, probedPosition).multiply(terrainFactor);
Vec3d wind = get(world).getWindDirection().multiply(1 - windFactor);
Vec3d thermalGradient = THERMAL_FIELD.computeAverage(world, pos, probedPosition).multiply(1 - terrainFactor);
Vec3d wind = get(world).getWindDirection().multiply(windFactor);
return terrainGradient
.add(thermalGradient)
.add(wind)
.normalize()
.add(0, getUpdraft(probedPosition.set(pos), world), 0)
.multiply(localAltitude / MAX_WIND_HEIGHT);
.multiply(windFactor);
}
public static double getUpdraft(BlockPos.Mutable pos, World world) {
final float ratio = 1 - Math.min(MAX_UPDRAFT_HEIGHT, pos.getY() - getSurfaceBelow(pos, world)) / MAX_UPDRAFT_HEIGHT;
double factor = 1 - getScaledDistanceFromTerrain(pos, world, MAX_UPDRAFT_HEIGHT);
return factor * getMaterialSurfaceTemperature(pos, world);
}
private static float getScaledDistanceFromTerrain(BlockPos.Mutable pos, World world, float maxDistance) {
return Math.min(maxDistance, LOCAL_ALTITUDE_FIELD.getValue(world, pos)) / maxDistance;
}
private static double getMaterialSurfaceTemperature(BlockPos.Mutable pos, World world) {
BlockState state = world.getBlockState(pos);
if (state.isAir()) {
return VOID_UPDRAFT * ratio;
return VOID_UPDRAFT;
}
if (state.isOf(Blocks.SOUL_SAND) || state.isOf(Blocks.SOUL_SOIL)) {
return SOUL_SAND_UPDRAFT * ratio;
return SOUL_SAND_UPDRAFT;
}
if (state.isOf(Blocks.LAVA) || state.isOf(Blocks.LAVA_CAULDRON)
|| state.isIn(BlockTags.FIRE)
|| state.isIn(BlockTags.CAMPFIRES)
|| state.isOf(Blocks.MAGMA_BLOCK)) {
return FIRE_UPDRAFT * ratio;
return FIRE_UPDRAFT;
}
if (state.isIn(BlockTags.SAND)) {
return SAND_UPDRAFT * ratio;
return SAND_UPDRAFT * MeteorlogicalUtil.getSunIntensity(world);
}
if (state.isIn(BlockTags.SNOW) || state.isIn(BlockTags.ICE)) {
return ICE_UPDRAFT * ratio;
return ICE_UPDRAFT * MeteorlogicalUtil.getSunIntensity(world);
}
if (state.getFluidState().isIn(FluidTags.WATER)) {
return MeteorlogicalUtil.getSunIntensity(world);
}
return 0;
@ -182,14 +194,7 @@ public class WeatherConditions extends PersistentState implements Tickable {
return Random.create(posLong + time);
}
private static int getSurfaceBelow(BlockPos.Mutable pos, World world) {
do {
pos.move(Direction.DOWN);
} while (world.isAir(pos) && world.isInBuildLimit(pos));
return pos.getY();
}
public interface TwoDimensionalField {
public interface Plane {
float getValue(World world, BlockPos.Mutable pos);
default Vec3d computedAverage(World world, BlockPos pos) {