hytale-server/com/hypixel/hytale/server/npc/util/PositionProbeBase.java

194 lines
6.7 KiB
Java

package com.hypixel.hytale.server.npc.util;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.shape.Box;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.modules.collision.BoxBlockIntersectionEvaluator;
import com.hypixel.hytale.server.core.modules.collision.CollisionFilter;
import com.hypixel.hytale.server.core.modules.collision.CollisionModule;
import com.hypixel.hytale.server.core.modules.collision.CollisionResult;
import com.hypixel.hytale.server.core.modules.collision.WorldUtil;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
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.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
public class PositionProbeBase {
private static final int lastWaterCheckDistanceMinSquared = 25;
protected boolean touchCeil;
protected boolean onGround;
protected boolean inWater;
protected boolean validPosition = true;
protected int groundLevel = -1;
protected int waterLevel = -1;
protected int heightOverGround = -1;
protected int heightOverWater = -1;
protected int heightOverSurface = -1;
protected int depthBelowSurface = -1;
private int lastWaterCheckX = Integer.MAX_VALUE;
private int lastWaterCheckZ = Integer.MAX_VALUE;
private int lastWaterCheckLevel = -2;
protected <T> boolean probePosition(
@Nonnull Ref<EntityStore> ref,
@Nonnull Box boundingBox,
@Nonnull Vector3d position,
@Nonnull CollisionResult collisionResult,
@Nonnull T t,
@Nonnull CollisionFilter<BoxBlockIntersectionEvaluator, T> blockTest,
int materialSet,
@Nonnull ComponentAccessor<EntityStore> componentAccessor
) {
World world = componentAccessor.getExternalData().getWorld();
TransformComponent transformComponent = componentAccessor.getComponent(ref, TransformComponent.getComponentType());
assert transformComponent != null;
ChunkStore chunkStore = world.getChunkStore();
long chunkIndex = ChunkUtil.indexChunkFromBlock(position.x, position.z);
Ref<ChunkStore> chunkRef = chunkStore.getChunkReference(chunkIndex);
this.reset();
if (chunkRef != null && chunkRef.isValid()) {
int x = MathUtil.floor(position.x);
int y = MathUtil.floor(position.y);
int z = MathUtil.floor(position.z);
this.validPosition = CollisionModule.get().validatePosition(world, boundingBox, position, materialSet, t, blockTest, collisionResult) != -1;
Store<ChunkStore> chunkStoreAccessor = chunkStore.getStore();
ChunkColumn chunkColumnComponent = chunkStoreAccessor.getComponent(chunkRef, ChunkColumn.getComponentType());
BlockChunk blockChunkComponent = chunkStoreAccessor.getComponent(chunkRef, BlockChunk.getComponentType());
if (chunkColumnComponent != null && blockChunkComponent != null) {
this.groundLevel = blockChunkComponent.getHeight(x, z);
this.waterLevel = this.updateWaterLevel(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, x, z);
} else {
this.groundLevel = -1;
this.waterLevel = -1;
this.lastWaterCheckLevel = -2;
}
this.heightOverGround = y - this.groundLevel;
if (this.waterLevel < this.groundLevel) {
this.heightOverSurface = this.heightOverGround;
} else if (y > this.waterLevel) {
this.heightOverSurface = y - this.waterLevel;
} else {
this.depthBelowSurface = this.waterLevel - y;
}
return this.validPosition;
} else {
this.waterLevel = -1;
this.groundLevel = -1;
this.lastWaterCheckLevel = -2;
return false;
}
}
protected int updateWaterLevel(
@Nonnull ComponentAccessor<ChunkStore> chunkStore, @Nonnull ChunkColumn chunkColumn, @Nonnull BlockChunk blockChunk, int x, int z
) {
if (this.lastWaterCheckLevel < -1 || this.movedFarEnough(x, z)) {
this.lastWaterCheckX = x;
this.lastWaterCheckZ = z;
this.lastWaterCheckLevel = WorldUtil.getWaterLevel(chunkStore, chunkColumn, blockChunk, x, z, this.groundLevel);
}
return this.lastWaterCheckLevel;
}
private boolean movedFarEnough(int x, int z) {
x -= this.lastWaterCheckX;
z -= this.lastWaterCheckZ;
return x * x + z * z > 25;
}
protected void reset() {
this.touchCeil = false;
this.onGround = false;
this.inWater = false;
this.validPosition = true;
this.heightOverGround = -1;
this.heightOverSurface = -1;
this.heightOverWater = -1;
this.depthBelowSurface = -1;
}
public boolean isValidPosition() {
return this.validPosition;
}
public boolean isTouchCeil() {
return this.touchCeil;
}
public boolean isOnGround() {
return this.onGround;
}
public boolean isInWater() {
return this.inWater;
}
public int getGroundLevel() {
return this.groundLevel;
}
public int getWaterLevel() {
return this.waterLevel;
}
public int getHeightOverGround() {
return this.heightOverGround;
}
public int getHeightOverSurface() {
return this.heightOverSurface;
}
public int getDepthBelowSurface() {
return this.depthBelowSurface;
}
public int getHeightOverWater() {
return this.heightOverWater;
}
@Nonnull
@Override
public String toString() {
return "PositionProbeBase{touchCeil="
+ this.touchCeil
+ ", onGround="
+ this.onGround
+ ", inWater="
+ this.inWater
+ ", validPosition="
+ this.validPosition
+ ", groundLevel="
+ this.groundLevel
+ ", waterLevel="
+ this.waterLevel
+ ", heightOverGround="
+ this.heightOverGround
+ ", heightOverSurface="
+ this.heightOverSurface
+ ", depthBelowSurface="
+ this.depthBelowSurface
+ ", heightOverWater="
+ this.heightOverWater
+ ", lastWaterCheckX="
+ this.lastWaterCheckX
+ ", lastWaterCheckZ="
+ this.lastWaterCheckZ
+ ", lastWaterCheckLevel="
+ this.lastWaterCheckLevel
+ "}";
}
}