Greatly enhance ender teleporter position validation

This commit is contained in:
DBotThePony 2022-10-13 15:43:58 +07:00
parent 254faa7a64
commit a76d07ecc2
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -12,15 +12,15 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.tags.BlockTags
import net.minecraft.world.level.ClipContext import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
import net.minecraft.world.level.material.Material
import net.minecraft.world.phys.HitResult import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.shapes.BooleanOp
import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraftforge.client.event.RenderLevelStageEvent import net.minecraftforge.client.event.RenderLevelStageEvent
import net.minecraftforge.event.entity.living.LivingDeathEvent import net.minecraftforge.event.entity.living.LivingDeathEvent
import org.lwjgl.opengl.GL11.GL_ALWAYS
import org.lwjgl.opengl.GL11.GL_LESS
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.ServerConfig
@ -29,7 +29,6 @@ import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.DynamicBufferSource import ru.dbotthepony.mc.otm.client.render.DynamicBufferSource
import ru.dbotthepony.mc.otm.client.render.ResearchIcons import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.client.render.element import ru.dbotthepony.mc.otm.client.render.element
@ -42,6 +41,7 @@ import ru.dbotthepony.mc.otm.core.component2
import ru.dbotthepony.mc.otm.core.component3 import ru.dbotthepony.mc.otm.core.component3
import ru.dbotthepony.mc.otm.core.formatPower import ru.dbotthepony.mc.otm.core.formatPower
import ru.dbotthepony.mc.otm.core.genericPositions import ru.dbotthepony.mc.otm.core.genericPositions
import ru.dbotthepony.mc.otm.core.minus
import ru.dbotthepony.mc.otm.core.plus import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.shortestDistanceBetween import ru.dbotthepony.mc.otm.core.shortestDistanceBetween
@ -74,23 +74,43 @@ class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiv
cooldown = nbt.getInt("cooldown") cooldown = nbt.getInt("cooldown")
} }
private fun isValidGround(blockPos: BlockPos): Boolean {
return canSupportPlayer(blockPos) && !isWall(blockPos)
}
private fun canSupportPlayer(blockPos: BlockPos): Boolean {
val state = ply.level.getBlockState(blockPos)
if (state.`is`(BlockTags.CLIMBABLE)) {
return true // ladders can always support player
}
val shape = state.getCollisionShape(ply.level, blockPos, CollisionContext.of(ply))
return Shapes.joinIsNotEmpty(shape, SHAPE_CHECK_SUPPORT_PLAYER, BooleanOp.AND)
}
private fun isWall(blockPos: BlockPos): Boolean {
val shape = ply.level.getBlockState(blockPos).getCollisionShape(ply.level, blockPos, CollisionContext.of(ply))
return Shapes.joinIsNotEmpty(shape, SHAPE_CHECK_NOT_FENCE, BooleanOp.AND)
}
private fun isAirGap(blockPos: BlockPos): Boolean {
val state = ply.level.getBlockState(blockPos)
if (state.isAir) {
return true
}
val shape = state.getCollisionShape(ply.level, blockPos, CollisionContext.of(ply))
return shape.isEmpty || !Shapes.joinIsNotEmpty(shape, SHAPE_CHECK_SUPPORT_PLAYER, BooleanOp.AND)
}
private fun isValidPosition(blockPos: BlockPos): Boolean { private fun isValidPosition(blockPos: BlockPos): Boolean {
if (!Block.canSupportCenter(ply.level, blockPos.below(), Direction.UP) && !Block.canSupportRigidBlock(ply.level, blockPos.below()) && ply.level.getBlockState(blockPos.below()).material != Material.LEAVES) { if (!canSupportPlayer(blockPos.below()) && !isWall(blockPos.below().below())) {
return false return false
} }
val a = ply.level.getBlockState(blockPos) return !isWall(blockPos.below()) && isAirGap(blockPos) && isAirGap(blockPos.above())
val b = ply.level.getBlockState(blockPos.above())
if (a.isAir && b.isAir) {
return true
}
if (a.getCollisionShape(ply.level, blockPos).isEmpty && b.getCollisionShape(ply.level, blockPos, CollisionContext.of(ply)).isEmpty) {
return true
}
return false
} }
private data class TraceResult(val pos: BlockPos? = null, val phasedBlocks: Collection<BlockPos> = listOf()) { private data class TraceResult(val pos: BlockPos? = null, val phasedBlocks: Collection<BlockPos> = listOf()) {
@ -115,22 +135,36 @@ class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiv
return TraceResult.EMPTY return TraceResult.EMPTY
} }
val testPositions = ply.genericPositions()
if ( if (
result.direction == Direction.UP && result.direction == Direction.UP &&
isValidPosition(result.blockPos.above()) && isValidPosition(result.blockPos.above()) &&
shortestDistanceBetween(ply.genericPositions(), result.blockPos.above().asVector()) <= ServerConfig.EnderTeleporter.MAX_DISTANCE shortestDistanceBetween(testPositions, result.blockPos.above().asVector()) <= ServerConfig.EnderTeleporter.MAX_DISTANCE
) { ) {
return TraceResult(result.blockPos.above()) return TraceResult(result.blockPos.above())
} }
for (y in 0 .. ServerConfig.EnderTeleporter.MAX_PHASE_DISTANCE) { for (y in (if (ply.level.getBlockState(result.blockPos).`is`(BlockTags.CLIMBABLE)) -1 else 0) .. ServerConfig.EnderTeleporter.MAX_PHASE_DISTANCE) {
val pos = result.blockPos + BlockPos(0, y + 1, 0) val pos = BlockPos(result.blockPos.x, result.blockPos.y + y + 1, result.blockPos.z)
if (isValidPosition(pos) && shortestDistanceBetween(ply.genericPositions(), pos.asVector()) <= ServerConfig.EnderTeleporter.MAX_DISTANCE) { if (isValidPosition(pos) && shortestDistanceBetween(testPositions, pos.asVector()) <= ServerConfig.EnderTeleporter.MAX_DISTANCE) {
return TraceResult(pos, if (y != 0) ImmutableList(y + 1) { result.blockPos + BlockPos(0, it, 0) } else listOf()) return TraceResult(pos, if (y != 0) ImmutableList(y + 1) { result.blockPos + BlockPos(0, it, 0) } else listOf())
} }
} }
// no valid positions...
if (isAirGap(result.blockPos)) {
// try to find ground below...
for (y in 0 downTo -ServerConfig.EnderTeleporter.MAX_PHASE_DISTANCE) {
val pos = BlockPos(result.blockPos.x, result.blockPos.y + y, result.blockPos.z)
if (isValidPosition(pos) && shortestDistanceBetween(testPositions, pos.asVector()) <= ServerConfig.EnderTeleporter.MAX_DISTANCE) {
return TraceResult(pos, if (y != 0) ImmutableList(-y + 1) { result.blockPos - BlockPos(0, it, 0) } else listOf())
}
}
}
return TraceResult.EMPTY return TraceResult.EMPTY
} }
@ -237,6 +271,9 @@ class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiv
DynamicBufferSource(maximalInitialBufferSize = 256) DynamicBufferSource(maximalInitialBufferSize = 256)
} }
private val SHAPE_CHECK_NOT_FENCE = Block.box(6.0, 17.0, 6.0, 10.0, 31.0, 10.0)
private val SHAPE_CHECK_SUPPORT_PLAYER = Block.box(6.0, 0.0, 6.0, 10.0, 16.0, 10.0)
val SPRITE = ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/item/black_hole.png").element(0f, 0f, 16f, 16f, 16f, 16f) val SPRITE = ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/item/black_hole.png").element(0f, 0f, 16f, 16f, 16f, 16f)
val POWER_COST_DESCRIPTION = val POWER_COST_DESCRIPTION =