classpublicfinalPriority 3
PortalSpawnFinder
com.hypixel.hytale.builtin.portals.ui.PortalSpawnFinder
1
Methods
1
Public Methods
0
Fields
1
Constructors
Constructors
public
PortalSpawnFinder()Methods
Public Methods (1)
publicstatic
Transform computeSpawnTransform(World world, PortalSpawn config)@Nullable
Related Classes
Source Code
package com.hypixel.hytale.builtin.portals.ui;
import com.hypixel.hytale.builtin.portals.utils.posqueries.generators.SearchCircular;
import com.hypixel.hytale.builtin.portals.utils.posqueries.predicates.FitsAPortal;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.protocol.BlockMaterial;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.portalworld.PortalSpawn;
import com.hypixel.hytale.server.core.modules.collision.WorldUtil;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class PortalSpawnFinder {
public PortalSpawnFinder() {
}
@Nullable
public static Transform computeSpawnTransform(World world, PortalSpawn config) {
Vector3d spawn = findSpawnByThrowingDarts(world, config);
if (spawn == null) {
spawn = findFallbackPositionOnGround(world, config);
HytaleLogger.getLogger().at(Level.INFO).log("Had to use fallback spawn for portal spawn");
}
if (spawn == null) {
HytaleLogger.getLogger().at(Level.INFO).log("Both dart and fallback spawn finder failed for portal spawn");
return null;
} else {
Vector3f direction = Vector3f.lookAt(spawn).scale(-1.0F);
direction.setPitch(0.0F);
direction.setRoll(0.0F);
return new Transform(spawn.clone().add(0.0, 0.5, 0.0), direction);
}
}
@Nullable
private static Vector3d findSpawnByThrowingDarts(World world, PortalSpawn config) {
Vector3d center = config.getCenter().toVector3d();
center.setY((double)config.getCheckSpawnY());
int halfwayThrows = config.getChunkDartThrows() / 2;
for (int chunkDart = 0; chunkDart < config.getChunkDartThrows(); chunkDart++) {
Vector3d pointd = new SearchCircular((double)config.getMinRadius(), (double)config.getMaxRadius(), 1).execute(world, center).orElse(null);
if (pointd != null) {
Vector3i point = pointd.toVector3i();
WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(point.x, point.z));
BlockType firstBlock = chunk.getBlockType(point.x, point.y, point.z);
if (firstBlock != null) {
BlockMaterial firstBlockMat = firstBlock.getMaterial();
if (firstBlockMat != BlockMaterial.Solid) {
boolean checkIfPortalFitsNice = chunkDart < halfwayThrows;
Vector3d spawn = findGroundWithinChunk(chunk, config, checkIfPortalFitsNice);
if (spawn != null) {
HytaleLogger.getLogger().at(Level.INFO).log("Found fragment spawn at " + spawn + " after " + (chunkDart + 1) + " chunk scan(s)");
return spawn;
}
}
}
}
}
return null;
}
@Nullable
private static Vector3d findGroundWithinChunk(WorldChunk chunk, PortalSpawn config, boolean checkIfPortalFitsNice) {
int chunkBlockX = ChunkUtil.minBlock(chunk.getX());
int chunkBlockZ = ChunkUtil.minBlock(chunk.getZ());
ThreadLocalRandom rand = ThreadLocalRandom.current();
for (int i = 0; i < config.getChecksPerChunk(); i++) {
int x = chunkBlockX + rand.nextInt(2, 14);
int z = chunkBlockZ + rand.nextInt(2, 14);
Vector3d point = findWithGroundBelow(chunk, x, config.getCheckSpawnY(), z, config.getScanHeight(), false);
if (point != null && (!checkIfPortalFitsNice || FitsAPortal.check(chunk.getWorld(), point))) {
return point;
}
}
return null;
}
@Nullable
private static Vector3d findWithGroundBelow(WorldChunk chunk, int x, int y, int z, int scanHeight, boolean fluidsAreAcceptable) {
World world = chunk.getWorld();
ChunkStore chunkStore = world.getChunkStore();
Ref<ChunkStore> chunkRef = chunk.getReference();
Store<ChunkStore> chunkStoreAccessor = chunkStore.getStore();
ChunkColumn chunkColumnComponent = chunkStoreAccessor.getComponent(chunkRef, ChunkColumn.getComponentType());
BlockChunk blockChunkComponent = chunkStoreAccessor.getComponent(chunkRef, BlockChunk.getComponentType());
for (int dy = 0; dy < scanHeight; dy++) {
PortalSpawnFinder.Material selfMat = getMaterial(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, (double)x, (double)(y - dy), (double)z);
PortalSpawnFinder.Material belowMat = getMaterial(
chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, (double)x, (double)(y - dy - 1), (double)z
);
boolean selfValid = selfMat == PortalSpawnFinder.Material.AIR || fluidsAreAcceptable && selfMat == PortalSpawnFinder.Material.FLUID;
if (!selfValid) {
break;
}
if (belowMat == PortalSpawnFinder.Material.SOLID) {
return new Vector3d((double)x, (double)(y - dy), (double)z);
}
}
return null;
}
private static PortalSpawnFinder.Material getMaterial(
@Nonnull ComponentAccessor<ChunkStore> chunkStore,
@Nonnull ChunkColumn chunkColumnComponent,
@Nonnull BlockChunk blockChunkComponent,
double x,
double y,
double z
) {
int blockX = (int)x;
int blockY = (int)y;
int blockZ = (int)z;
int fluidId = WorldUtil.getFluidIdAtPosition(chunkStore, chunkColumnComponent, blockX, blockY, blockZ);
if (fluidId != 0) {
return PortalSpawnFinder.Material.FLUID;
} else {
BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(blockY);
int blockId = blockSection.get(blockX, blockY, blockZ);
BlockType blockType = BlockType.getAssetMap().getAsset(blockId);
if (blockType == null) {
return PortalSpawnFinder.Material.UNKNOWN;
} else {
return switch (blockType.getMaterial()) {
case Solid -> PortalSpawnFinder.Material.SOLID;
case Empty -> PortalSpawnFinder.Material.AIR;
};
}
}
}
@Nullable
private static Vector3d findFallbackPositionOnGround(World world, PortalSpawn config) {
Vector3i center = config.getCenter();
WorldChunk centerChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(center.x, center.z));
return findWithGroundBelow(centerChunk, 0, 319, 0, 319, true);
}
private static enum Material {
SOLID,
FLUID,
AIR,
UNKNOWN;
private Material() {
}
}
}