diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt index b03dd7885..c7eba9b7b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlockEntityBlackHole.kt @@ -20,11 +20,13 @@ import net.minecraft.world.level.levelgen.structure.BoundingBox import net.minecraft.world.phys.AABB import net.minecraft.world.phys.Vec3 import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.BlockBlackHole import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue.Companion.queueForLevel import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.matter.MatterRegistry import ru.dbotthepony.mc.otm.set import kotlin.math.pow +import kotlin.math.roundToInt import kotlin.math.sqrt class BlockEntityBlackHole(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(Registry.BlockEntities.BLACK_HOLE, p_155229_, p_155230_) { @@ -245,14 +247,111 @@ class BlockEntityBlackHole(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn if (level.random.nextDouble() < 0.01 * 0.05 * (1 / gravitationStrength)) { this.mass += HAWKING_MASS_LOSE_STEP } + + if (gravitationStrength > 0.4f) { + val sphere = getSphericalShape((gravitationStrength * 6.0).roundToInt()) + + if (sphere.size != lastSphereSizeOuter) { + lastSphereSizeOuter = sphere.size + sphereIndexOuter = 0 + } + + var iterations = 0 + + while (iterations < ITERATIONS) { + iterations++ + + val pos = sphere[sphereIndexOuter] + blockPos + sphereIndexOuter = (sphereIndexOuter + 1) % lastSphereSizeOuter + + if (sphereIndexOuter == 0 && lastSphereSizeOuter <= ITERATIONS) + break + + val getBlock = level.getBlockState(pos) + + if (!getBlock.isAir && getBlock.block !is BlockBlackHole) { + val speed = getBlock.getDestroySpeed(level, pos) + + val eResist = try { + getBlock.getExplosionResistance(level, pos, null) + } catch (err: Throwable) { + getBlock.block.getExplosionResistance() + // Потому что возможно какой-либо мод не ожидает что Explosion == null + // особенно учитывая что интерфейс IForgeBlock не имеет @ParamsAreNonnullByDefault + // и аргумент не помечен как @Nullable + // тем самым имеет тип Explosion! который указывается как Explosion? .. Explosion!! + } + + var strengthLinear = sqrt(blockPos.distSqr(pos)) + + if (strengthLinear < gravitationStrength * 1.1) { + strengthLinear /= 4.0 + } + + if (speed >= 0f && (speed * 2f).coerceAtLeast(eResist / 3f) < gravitationStrength * (8.0 / strengthLinear)) { + Block.dropResources(getBlock, level, pos, level.getBlockEntity(pos)) + getBlock.block.destroy(level, pos, getBlock) + level.setBlock(pos, getBlock.fluidState.createLegacyBlock(), Block.UPDATE_ALL) + } + } + } + } } + private var lastSphereSizeOuter = 0 + private var sphereIndexOuter = 0 + init { mass = mass } companion object { + const val ITERATIONS = 30_000 val BASELINE_MASS = Fraction(1_000) val HAWKING_MASS_LOSE_STEP = Fraction("-0.1") + + private val blockShapeCache = HashMap>() + + private fun getSphericalShape(size: Int): Array { + return blockShapeCache.computeIfAbsent(size) { + val result = ArrayList((it * it * it * Math.PI * (4.0 / 3.0)).toInt() + 16) + + for (x in -it .. it) { + for (y in -it .. it) { + for (z in -it .. it) { + val dist = sqrt(x * x.toDouble() + y * y.toDouble() + z * z.toDouble()) + + if (dist <= size && dist != 0.0) { + result.add(BlockPos(x, y, z)) + } + } + } + } + + val arr = result.toTypedArray() + + arr.sortWith { a, b -> + val xa = a.x + val ya = a.y + val za = a.z + val distA = sqrt(xa * xa.toDouble() + ya * ya.toDouble() + za * za.toDouble()) + + val xb = b.x + val yb = b.y + val zb = b.z + val distB = sqrt(xb * xb.toDouble() + yb * yb.toDouble() + zb * zb.toDouble()) + + if (distA == distB) { + return@sortWith 0 + } else if (distA > distB) { + return@sortWith 1 + } else { + return@sortWith -1 + } + } + + return@computeIfAbsent arr + } + } } } \ No newline at end of file