Added respawn logic to place seaponies in water

This commit is contained in:
Sollace 2023-11-09 15:07:56 +00:00
parent c656eb2309
commit 873297ca44
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
2 changed files with 66 additions and 28 deletions

View file

@ -54,6 +54,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.registry.tag.DamageTypeTags;
import net.minecraft.registry.tag.FluidTags;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
@ -340,11 +341,12 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
public void onSpawn() {
if (entity.getWorld() instanceof ServerWorld sw
&& getObservedSpecies() == Race.BAT
&& sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE
&& MeteorlogicalUtil.isPositionExposedToSun(sw, getOrigin())) {
SpawnLocator.selectSpawnPosition(sw, entity);
if (entity.getWorld() instanceof ServerWorld sw && sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE) {
boolean mustAvoidSun = getObservedSpecies() == Race.BAT && MeteorlogicalUtil.isPositionExposedToSun(sw, getOrigin());
boolean mustAvoidAir = getCompositeRace().includes(Race.SEAPONY) && !sw.getFluidState(getOrigin()).isIn(FluidTags.WATER);
if (mustAvoidSun || mustAvoidAir) {
SpawnLocator.selectSpawnPosition(sw, entity, mustAvoidAir, mustAvoidSun);
}
}
ticksSunImmunity = INITIAL_SUN_IMMUNITY;
}

View file

@ -1,37 +1,68 @@
package com.minelittlepony.unicopia.entity.player;
import java.util.Optional;
import com.minelittlepony.unicopia.util.MeteorlogicalUtil;
import net.minecraft.entity.ai.FuzzyPositions;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.registry.tag.FluidTags;
import net.minecraft.server.network.SpawnLocating;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.Heightmap;
import net.minecraft.world.chunk.WorldChunk;
public class SpawnLocator extends SpawnLocating {
public static BlockPos findSafeSpawnLocation(ServerWorld world, int x, int z) {
return SpawnLocating.findOverworldSpawn(world, x, z);
private static BlockPos findSafeSpawnLocation(ServerWorld world, int x, int z, boolean avoidAir) {
if (!avoidAir) {
return findOverworldSpawn(world, x, z);
}
public static Optional<BlockPos> fuzz(ServerWorld world, BlockPos pos, int horizontal, int vertical) {
for (int attempt = 0; attempt < 6; attempt++) {
BlockPos target = FuzzyPositions.localFuzz(world.random, horizontal, vertical);
target = findSafeSpawnLocation(world, target.getX(), target.getZ());
if (target != null) {
return Optional.of(target);
}
boolean hasCeiling = world.getDimension().hasCeiling();
WorldChunk chunk = world.getChunk(ChunkSectionPos.getSectionCoord(x), ChunkSectionPos.getSectionCoord(z));
int startHeight = hasCeiling
? world.getChunkManager().getChunkGenerator().getSpawnHeight(world)
: chunk.sampleHeightmap(Heightmap.Type.MOTION_BLOCKING, x & 0xF, z & 0xF);
if (startHeight < world.getBottomY()) {
return null;
}
return Optional.empty();
int terrainHeight = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, x & 0xF, z & 0xF);
if (terrainHeight <= startHeight && terrainHeight > chunk.sampleHeightmap(Heightmap.Type.OCEAN_FLOOR, x & 0xF, z & 0xF)) {
return null;
}
public static void selectSpawnPosition(ServerWorld world, PlayerEntity entity) {
BlockPos.Mutable mutable = new BlockPos.Mutable();
for (int y = startHeight + 1; y >= world.getBottomY(); --y) {
mutable.set(x, y, z);
BlockState state = world.getBlockState(mutable);
FluidState fluid = state.getFluidState();
if (fluid.isEmpty()) {
continue;
}
if (!fluid.isIn(FluidTags.WATER)) {
break;
}
if (!Block.isFaceFullSquare(state.getCollisionShape(world, mutable), Direction.UP)) {
continue;
}
return mutable.up().toImmutable();
}
return null;
}
private static boolean checkAtmosphere(ServerWorld world, BlockPos pos, boolean avoidAir) {
if (avoidAir) {
return world.getFluidState(pos).isIn(FluidTags.WATER);
}
return world.getFluidState(pos).isEmpty();
}
public static void selectSpawnPosition(ServerWorld world, PlayerEntity entity, boolean avoidAir, boolean avoidSun) {
BlockPos spawnPos = world.getSpawnPos();
int spawnRadius = Math.min(
MathHelper.floor(world.getWorldBorder().getDistanceInsideBorder(spawnPos.getX(), spawnPos.getZ())),
@ -53,7 +84,8 @@ public class SpawnLocator extends SpawnLocating {
BlockPos candidatePos = findSafeSpawnLocation(world,
spawnPos.getX() + x - spawnRadius,
spawnPos.getZ() + z - spawnRadius
spawnPos.getZ() + z - spawnRadius,
avoidAir
);
if (candidatePos == null) {
@ -70,7 +102,7 @@ public class SpawnLocator extends SpawnLocating {
mutable.move(0, -1, 0);
}
if (!world.getFluidState(mutable).isEmpty()) {
if (!checkAtmosphere(world, mutable, avoidAir)) {
continue;
}
@ -78,13 +110,17 @@ public class SpawnLocator extends SpawnLocating {
mutable.move(0, 1, 0);
}
if (!world.getFluidState(mutable).isEmpty()) {
if (!checkAtmosphere(world, mutable, avoidAir)) {
continue;
}
entity.refreshPositionAndAngles(mutable, 0, 0);
if (!world.isSpaceEmpty(entity) || MeteorlogicalUtil.isPositionExposedToSun(world, mutable)) {
if (!world.isSpaceEmpty(entity)) {
continue;
}
if (avoidSun && MeteorlogicalUtil.isPositionExposedToSun(world, mutable)) {
continue;
}